Browse Source

feat: 数据修正系数支持正负值分组配置

master
liujiangyong 1 week ago
parent
commit
c187fd9fd3
  1. 61
      CHANGELOGS/V1.2.4.md
  2. 2
      package.json
  3. 87
      src/renderer/src/components/SystemSettings/SystemSettings.jsx
  4. 26
      src/renderer/src/components/SystemSettings/SystemSettings.module.css
  5. 19
      src/renderer/src/stores/deviceStore.js
  6. 158
      src/renderer/src/utils/deflectionCorrection.js

61
CHANGELOGS/V1.2.4.md

@ -0,0 +1,61 @@
# V1.2.4 更新日志
- **更新日期**: 2026年06月17日
- **版本号**: 1.2.4
## 新增功能
### 1. 数据修正系数支持正负值分组配置
- **新增正负值双组修正系数**:每个距离配置下,分别维护“正值配置”和“负值配置”两套 `xK/xB/yK/yB`
- **按原始值符号自动应用**:当原始采集值大于等于 `0` 时使用正值配置,小于 `0` 时使用负值配置
- **X/Y 独立判断**:`xReal` 和 `yReal` 分别按各自原始值符号选择对应修正系数,不共享判断结果
- **保持历史冻结语义**:修正系数变更后仅影响后续新采集数据,已进入历史链路的数据保持采集当时的修正结果
### 2. 修正系数配置界面升级
- **卡片内新增正负值配置区**:每张距离配置卡片内新增“正值配置”和“负值配置”两个分组
- **支持 8 项参数编辑**:每个距离可分别编辑正值组和负值组的 `xK/xB/yK/yB`
- **保留多距离管理能力**:继续支持距离配置的新增、编辑、删除和当前应用项切换
- **保留控制台调试输出**:修正计算时继续输出原始值、命中的正负组、K、B 和修正后值,便于排查数据口径
## 技术细节
### 本地存储结构
```json
{
"profiles": [
{
"distance": 10,
"positive": { "xK": 1, "xB": 0, "yK": 1, "yB": 0 },
"negative": { "xK": 1, "xB": 0, "yK": 1, "yB": 0 }
}
],
"activeDistance": 10
}
```
### 数据处理策略
- `0` 归入正值配置
- 正负值判断基于传感器原始值,而不是修正后的结果
- 空值、缺失值或不可转数字的原始值不参与修正计算,保持“无数据”语义
- 页面曲线、实时数据显示、报警判断、实时 CSV、报警 CSV 继续共享冻结后的 `correctedX/correctedY`
## 影响范围
- 系统设置中的数据修正系数配置区域
- 多距离修正系数本地持久化结构
- 挠度采集页 X/Y 曲线与右侧实时数据
- 报警判断逻辑
- 实时数据 CSV 导出
- 报警数据 CSV 导出
## 依赖更新
- 无依赖包更新
## 注意事项
1. 本版本不兼容 V1.2.3 的单组修正系数本地结构,读取到旧结构或异常结构时会重建为新的默认 `10 米` 正负值双组配置。
2. 距离仍仅作为上位机修正系数配置的管理维度,不会根据设备状态或测点距离自动切换。
3. 当前应用项切换后,仅影响后续新采集数据;历史数据仍保持采集当时的修正结果。
4. 设备侧“测点设置”中的“计算系数”仍为独立参数,与本地正负值数据修正系数不互相替代。
---
**完整更新内容请查看项目 Git 提交记录**

2
package.json

@ -1,6 +1,6 @@
{
"name": "FlexometerSetup",
"version": "1.2.3",
"version": "1.2.4",
"description": "An Electron application with React",
"main": "./out/main/index.js",
"author": "cles",

87
src/renderer/src/components/SystemSettings/SystemSettings.jsx

@ -798,8 +798,21 @@ function SystemSettings() {
return
}
const [groupKey, factorKey] = field.split('.')
if (!groupKey || !factorKey) {
return
}
const nextProfiles = correctionProfiles.map((profile) =>
profile.distance === distance ? { ...profile, [field]: Number(value) } : profile
profile.distance === distance
? {
...profile,
[groupKey]: {
...profile[groupKey],
[factorKey]: Number(value)
}
}
: profile
)
const nextConfig = persistCorrectionConfig(nextProfiles, activeCorrectionDistance)
@ -1198,13 +1211,17 @@ function SystemSettings() {
</div>
<div className={styles.correctionFactorGrid}>
<div className={styles.correctionFactorGroup}>
<div className={styles.correctionFactorGroupTitle}>正值配置</div>
<div className={styles.correctionFactorGroupHint}>原始值大于等于 0 时使用</div>
<div className={styles.correctionFactorSubGrid}>
<div className={styles.correctionField}>
<span className={styles.correctionFieldLabel}>xK</span>
<InputNumber
precision={6}
value={profile.xK}
value={profile.positive.xK}
onChange={(nextValue) =>
handleCorrectionProfileChange(profile.distance, 'xK', nextValue)
handleCorrectionProfileChange(profile.distance, 'positive.xK', nextValue)
}
className={styles.correctionFieldInput}
/>
@ -1213,9 +1230,9 @@ function SystemSettings() {
<span className={styles.correctionFieldLabel}>xB</span>
<InputNumber
precision={6}
value={profile.xB}
value={profile.positive.xB}
onChange={(nextValue) =>
handleCorrectionProfileChange(profile.distance, 'xB', nextValue)
handleCorrectionProfileChange(profile.distance, 'positive.xB', nextValue)
}
className={styles.correctionFieldInput}
/>
@ -1224,9 +1241,9 @@ function SystemSettings() {
<span className={styles.correctionFieldLabel}>yK</span>
<InputNumber
precision={6}
value={profile.yK}
value={profile.positive.yK}
onChange={(nextValue) =>
handleCorrectionProfileChange(profile.distance, 'yK', nextValue)
handleCorrectionProfileChange(profile.distance, 'positive.yK', nextValue)
}
className={styles.correctionFieldInput}
/>
@ -1235,15 +1252,67 @@ function SystemSettings() {
<span className={styles.correctionFieldLabel}>yB</span>
<InputNumber
precision={6}
value={profile.yB}
value={profile.positive.yB}
onChange={(nextValue) =>
handleCorrectionProfileChange(profile.distance, 'yB', nextValue)
handleCorrectionProfileChange(profile.distance, 'positive.yB', nextValue)
}
className={styles.correctionFieldInput}
/>
</div>
</div>
</div>
<div className={styles.correctionFactorGroup}>
<div className={styles.correctionFactorGroupTitle}>负值配置</div>
<div className={styles.correctionFactorGroupHint}>原始值小于 0 时使用</div>
<div className={styles.correctionFactorSubGrid}>
<div className={styles.correctionField}>
<span className={styles.correctionFieldLabel}>xK</span>
<InputNumber
precision={6}
value={profile.negative.xK}
onChange={(nextValue) =>
handleCorrectionProfileChange(profile.distance, 'negative.xK', nextValue)
}
className={styles.correctionFieldInput}
/>
</div>
<div className={styles.correctionField}>
<span className={styles.correctionFieldLabel}>xB</span>
<InputNumber
precision={6}
value={profile.negative.xB}
onChange={(nextValue) =>
handleCorrectionProfileChange(profile.distance, 'negative.xB', nextValue)
}
className={styles.correctionFieldInput}
/>
</div>
<div className={styles.correctionField}>
<span className={styles.correctionFieldLabel}>yK</span>
<InputNumber
precision={6}
value={profile.negative.yK}
onChange={(nextValue) =>
handleCorrectionProfileChange(profile.distance, 'negative.yK', nextValue)
}
className={styles.correctionFieldInput}
/>
</div>
<div className={styles.correctionField}>
<span className={styles.correctionFieldLabel}>yB</span>
<InputNumber
precision={6}
value={profile.negative.yB}
onChange={(nextValue) =>
handleCorrectionProfileChange(profile.distance, 'negative.yB', nextValue)
}
className={styles.correctionFieldInput}
/>
</div>
</div>
</div>
</div>
</div>
)
})}
</div>

26
src/renderer/src/components/SystemSettings/SystemSettings.module.css

@ -198,6 +198,32 @@
}
.correctionFactorGrid {
display: grid;
grid-template-columns: 1fr;
gap: 10px;
}
.correctionFactorGroup {
border: 1px solid #e5e7eb;
border-radius: 6px;
padding: 10px;
background: #fff;
}
.correctionFactorGroupTitle {
font-size: 13px;
font-weight: 600;
color: #222;
}
.correctionFactorGroupHint {
margin-top: 2px;
margin-bottom: 8px;
font-size: 12px;
color: #666;
}
.correctionFactorSubGrid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px 8px;

19
src/renderer/src/stores/deviceStore.js

@ -1,6 +1,8 @@
import {
createDefaultCorrectionConfig,
createDefaultDualCorrectionFactors,
getActiveCorrectionFactors,
sanitizeDualCorrectionFactors,
sanitizeCorrectionProfiles
} from '../utils/deflectionCorrection'
@ -64,12 +66,11 @@ const useDeviceStore = create((set) => ({
// 数据修正系数管理
setCorrectionFactors: (factors) =>
set((state) => ({
correctionFactors: {
...state.correctionFactors,
...factors
}
})),
set({
correctionFactors: factors
? sanitizeDualCorrectionFactors(factors) ?? createDefaultDualCorrectionFactors()
: createDefaultDualCorrectionFactors()
}),
setCorrectionProfiles: (profiles) =>
set({
correctionProfiles: sanitizeCorrectionProfiles(profiles)
@ -89,10 +90,8 @@ const useDeviceStore = create((set) => ({
return {
activeCorrectionDistance: distance,
correctionFactors: {
xK: activeProfile.xK,
xB: activeProfile.xB,
yK: activeProfile.yK,
yB: activeProfile.yB
positive: { ...activeProfile.positive },
negative: { ...activeProfile.negative }
}
}
}),

158
src/renderer/src/utils/deflectionCorrection.js

@ -9,9 +9,18 @@ export const DEFAULT_CORRECTION_FACTORS = {
export const DEFAULT_CORRECTION_DISTANCE = 10
export const createDefaultFactorGroup = () => ({
...DEFAULT_CORRECTION_FACTORS
})
export const createDefaultDualCorrectionFactors = () => ({
positive: createDefaultFactorGroup(),
negative: createDefaultFactorGroup()
})
export const createDefaultCorrectionProfile = (distance = DEFAULT_CORRECTION_DISTANCE) => ({
distance,
...DEFAULT_CORRECTION_FACTORS
...createDefaultDualCorrectionFactors()
})
export const createDefaultCorrectionConfig = () => ({
@ -44,6 +53,21 @@ export const sanitizeCorrectionFactors = (value) => {
}
}
export const sanitizeDualCorrectionFactors = (value) => {
const next = value && typeof value === 'object' ? value : {}
const hasPositiveGroup = next.positive && typeof next.positive === 'object'
const hasNegativeGroup = next.negative && typeof next.negative === 'object'
if (!hasPositiveGroup || !hasNegativeGroup) {
return null
}
return {
positive: sanitizeCorrectionFactors(next.positive),
negative: sanitizeCorrectionFactors(next.negative)
}
}
export const sanitizeCorrectionProfile = (value) => {
const next = value && typeof value === 'object' ? value : {}
const distance = toPositiveInteger(next.distance)
@ -52,9 +76,14 @@ export const sanitizeCorrectionProfile = (value) => {
return null
}
const normalizedGroups = sanitizeDualCorrectionFactors(next)
if (!normalizedGroups) {
return null
}
return {
distance,
...sanitizeCorrectionFactors(next)
...normalizedGroups
}
}
@ -110,24 +139,8 @@ export const getActiveCorrectionFactors = (config) => {
)
return activeProfile
? sanitizeCorrectionFactors(activeProfile)
: { ...DEFAULT_CORRECTION_FACTORS }
}
export const ensureDefaultDistanceProfile = (profiles) => {
const normalizedProfiles = sanitizeCorrectionProfiles(profiles)
const hasDefaultDistance = normalizedProfiles.some(
(profile) => profile.distance === DEFAULT_CORRECTION_DISTANCE
)
if (hasDefaultDistance) {
return normalizedProfiles
}
return [
...normalizedProfiles,
createDefaultCorrectionProfile(DEFAULT_CORRECTION_DISTANCE)
]
? sanitizeDualCorrectionFactors(activeProfile) ?? createDefaultDualCorrectionFactors()
: createDefaultDualCorrectionFactors()
}
export const removeCorrectionProfileWithFallback = (profiles, activeDistance, distanceToDelete) => {
@ -162,7 +175,7 @@ export const removeCorrectionProfileWithFallback = (profiles, activeDistance, di
}
}
export const correctAxisValue = (originalValue, k, b) => {
const getFactorGroupNameByValue = (originalValue) => {
if (originalValue === null || originalValue === undefined || originalValue === '') {
return null
}
@ -172,7 +185,72 @@ export const correctAxisValue = (originalValue, k, b) => {
return null
}
return k * numericOriginal + b
return numericOriginal < 0 ? 'negative' : 'positive'
}
export const correctAxisValue = (originalValue, factors) => {
if (originalValue === null || originalValue === undefined || originalValue === '') {
return { correctedValue: null, appliedGroup: null, appliedFactors: null }
}
const numericOriginal = Number(originalValue)
if (!Number.isFinite(numericOriginal)) {
return { correctedValue: null, appliedGroup: null, appliedFactors: null }
}
const normalizedGroups = sanitizeDualCorrectionFactors(factors)
if (!normalizedGroups) {
return { correctedValue: null, appliedGroup: null, appliedFactors: null }
}
const appliedGroup = getFactorGroupNameByValue(numericOriginal)
const appliedFactors = appliedGroup ? normalizedGroups[appliedGroup] : null
if (!appliedFactors) {
return { correctedValue: null, appliedGroup: null, appliedFactors: null }
}
return {
correctedValue: appliedFactors.xK * numericOriginal + appliedFactors.xB,
appliedGroup,
appliedFactors: {
xK: appliedFactors.xK,
xB: appliedFactors.xB
}
}
}
const correctAxisWithKeys = (originalValue, factors, axis) => {
if (originalValue === null || originalValue === undefined || originalValue === '') {
return { correctedValue: null, appliedGroup: null, appliedFactors: null }
}
const numericOriginal = Number(originalValue)
if (!Number.isFinite(numericOriginal)) {
return { correctedValue: null, appliedGroup: null, appliedFactors: null }
}
const normalizedGroups = sanitizeDualCorrectionFactors(factors)
if (!normalizedGroups) {
return { correctedValue: null, appliedGroup: null, appliedFactors: null }
}
const appliedGroup = getFactorGroupNameByValue(numericOriginal)
const appliedFactors = appliedGroup ? normalizedGroups[appliedGroup] : null
if (!appliedFactors) {
return { correctedValue: null, appliedGroup: null, appliedFactors: null }
}
const kKey = `${axis}K`
const bKey = `${axis}B`
return {
correctedValue: appliedFactors[kKey] * numericOriginal + appliedFactors[bKey],
appliedGroup,
appliedFactors: {
[kKey]: appliedFactors[kKey],
[bKey]: appliedFactors[bKey]
}
}
}
export const applyCorrectionToSensor = (sensor, correctionFactors) => {
@ -180,32 +258,44 @@ export const applyCorrectionToSensor = (sensor, correctionFactors) => {
return sensor
}
const normalizedFactors = sanitizeCorrectionFactors(correctionFactors)
const correctedX = correctAxisValue(sensor.xReal, normalizedFactors.xK, normalizedFactors.xB)
const correctedY = correctAxisValue(sensor.yReal, normalizedFactors.yK, normalizedFactors.yB)
const normalizedFactors =
sanitizeDualCorrectionFactors(correctionFactors) ?? createDefaultDualCorrectionFactors()
const xResult = correctAxisWithKeys(sensor.xReal, normalizedFactors, 'x')
const yResult = correctAxisWithKeys(sensor.yReal, normalizedFactors, 'y')
console.log('[DeflectionCorrection]', {
pos: sensor.pos ?? null,
des: sensor.des ?? '',
x: {
originalValue: sensor.xReal ?? null,
k: normalizedFactors.xK,
b: normalizedFactors.xB,
correctedValue: correctedX
appliedGroup: xResult.appliedGroup,
k: xResult.appliedFactors?.xK ?? null,
b: xResult.appliedFactors?.xB ?? null,
correctedValue: xResult.correctedValue
},
y: {
originalValue: sensor.yReal ?? null,
k: normalizedFactors.yK,
b: normalizedFactors.yB,
correctedValue: correctedY
appliedGroup: yResult.appliedGroup,
k: yResult.appliedFactors?.yK ?? null,
b: yResult.appliedFactors?.yB ?? null,
correctedValue: yResult.correctedValue
}
})
return {
...sensor,
appliedCorrectionFactors: normalizedFactors,
correctedX,
correctedY
appliedCorrectionFactors: {
x: {
group: xResult.appliedGroup,
factors: xResult.appliedFactors
},
y: {
group: yResult.appliedGroup,
factors: yResult.appliedFactors
}
},
correctedX: xResult.correctedValue,
correctedY: yResult.correctedValue
}
}

Loading…
Cancel
Save