feat: 波长偏移修正 + 项目架构文档

- BandMathCalculator 支持 wavelength_offset 参数,公式波长统一加减偏移后匹配传感器波段
- WaterQualityIndexCalculator 全链传递偏移量 (band_math → calculate_one → calculate_many)
- WaterIndexCsvProcessor / Step7Handler / DataPreparationStep 传播偏移参数
- Step7/Step10 面板新增 QDoubleSpinBox 波长偏移控件 (±200nm, 默认0)
- 偏移控件去除单位后缀,避免编辑时需手动移动光标
- 新增 ARCHITECTURE.md 完整项目架构文档
This commit is contained in:
duxin
2026-06-30 13:13:38 +08:00
parent 8ff5b08190
commit 9e433395f4
8 changed files with 537 additions and 15 deletions

View File

@ -26,7 +26,7 @@ from PyQt5.QtWidgets import (
QGroupBox, QLabel, QLineEdit, QComboBox, QCheckBox, QPushButton,
QFileDialog, QMessageBox, QListWidget, QListWidgetItem,
QAbstractItemView, QProgressBar, QTextEdit, QFrame,
QScrollArea, QSizePolicy,
QScrollArea, QSizePolicy, QDoubleSpinBox,
)
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt, QThread, pyqtSignal
@ -72,6 +72,7 @@ class WaterIndexWorker(QThread):
selected_formulas: List[str],
waterindex_csv: str,
work_dir: Optional[str] = None,
wavelength_offset: float = 0.0,
):
super().__init__()
self.sampling_csv_path = sampling_csv_path
@ -79,6 +80,7 @@ class WaterIndexWorker(QThread):
self.selected_formulas = selected_formulas
self.waterindex_csv = waterindex_csv
self.work_dir = work_dir
self.wavelength_offset = float(wavelength_offset)
def run(self):
try:
@ -96,6 +98,7 @@ class WaterIndexWorker(QThread):
output_dir=self.output_dir,
selected_formulas=self.selected_formulas or None,
progress_callback=lambda m, p: self.progress.emit(m, p),
wavelength_offset=self.wavelength_offset,
)
self.progress.emit(
@ -166,7 +169,23 @@ class Step10WatercolorPanel(QWidget):
self.sampling_csv_file.label.setMinimumWidth(100)
input_layout.addWidget(self.sampling_csv_file)
# 注意:彻底去掉了 self.meta_label 及其相关的布局代码
# ── 波长偏移修正 ──
offset_layout = QHBoxLayout()
offset_label = QLabel("波长偏移 (nm):")
offset_label.setMinimumWidth(120)
self.wavelength_offset_spin = QDoubleSpinBox()
self.wavelength_offset_spin.setRange(-200.0, 200.0)
self.wavelength_offset_spin.setValue(0.0)
self.wavelength_offset_spin.setDecimals(1)
self.wavelength_offset_spin.setSuffix("")
self.wavelength_offset_spin.setToolTip(
"传感器波长系统偏移修正量。正数=公式波长加偏移(如+100则w450→找≈w550的波段);"
"负数=公式波长减偏移。默认0表示不做修正。"
)
offset_layout.addWidget(offset_label)
offset_layout.addWidget(self.wavelength_offset_spin)
offset_layout.addStretch()
input_layout.addLayout(offset_layout)
input_group.setLayout(input_layout)
layout.addWidget(input_group)
@ -653,6 +672,7 @@ class Step10WatercolorPanel(QWidget):
selected_formulas=selected,
waterindex_csv=self._waterindex_csv,
work_dir=work_dir,
wavelength_offset=self.wavelength_offset_spin.value(),
)
self._worker.progress.connect(self._on_progress)
self._worker.finished_ok.connect(self._on_finished)

View File

@ -14,6 +14,7 @@ from PyQt5.QtWidgets import (
QVBoxLayout, QHBoxLayout, QGroupBox, QFormLayout,
QLabel, QPushButton, QMessageBox, QListWidget,
QListWidgetItem, QSizePolicy, QWidget, QComboBox,
QDoubleSpinBox,
)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QColor
@ -238,6 +239,30 @@ class Step7InversionPanel(QWidget):
params_group.setLayout(params_layout)
main_layout.addWidget(params_group)
# ==========================================
# 波长偏移修正
# ==========================================
offset_group = QGroupBox("🔧 波长偏移修正")
offset_layout = QHBoxLayout()
offset_layout.setContentsMargins(20, 16, 20, 16)
offset_label = QLabel("统一偏移量 (nm):")
offset_label.setMinimumWidth(120)
self.wavelength_offset_spin = QDoubleSpinBox()
self.wavelength_offset_spin.setRange(-200.0, 200.0)
self.wavelength_offset_spin.setValue(0.0)
self.wavelength_offset_spin.setDecimals(1)
self.wavelength_offset_spin.setSuffix("")
self.wavelength_offset_spin.setToolTip(
"传感器波长系统偏移修正。公式中的目标波长统一加上此值后再匹配传感器波段。\n"
"例如:偏移 +100 意味着公式中的 w450 实际去找传感器 ~550nm 的波段。\n"
"默认 0 不做修正。适用于传感器标定漂移或不同传感器间的波段对齐。"
)
offset_layout.addWidget(offset_label)
offset_layout.addWidget(self.wavelength_offset_spin)
offset_layout.addStretch()
offset_group.setLayout(offset_layout)
main_layout.addWidget(offset_group)
# ==========================================
# 卡片 3:输出与执行
# ==========================================
@ -309,7 +334,8 @@ class Step7InversionPanel(QWidget):
'training_csv_path': self.training_data_widget.get_path(),
'formula_csv_file': self.formula_file.get_path(),
'formula_names': selected_names,
'enabled': True
'enabled': True,
'wavelength_offset': self.wavelength_offset_spin.value(),
}
output_path = self.output_file.get_path()
if output_path:
@ -337,6 +363,12 @@ class Step7InversionPanel(QWidget):
if 'output_path' in config:
self.output_file.set_path(config['output_path'])
if 'wavelength_offset' in config:
try:
self.wavelength_offset_spin.setValue(float(config['wavelength_offset']))
except (ValueError, TypeError):
pass
def _load_formulas_from_csv(self):
"""解析公式 CSV 文件并填充列表框"""
csv_path = self.formula_file.get_path()