From 445403fdc61f4e65736dc65a959f119fc096f4c0 Mon Sep 17 00:00:00 2001 From: Christian Kolset Date: Wed, 22 Apr 2026 13:05:05 -0600 Subject: Removed calibration feature in signal processing > pipeline. --- .../__pycache__/signals_window.cpython-312.pyc | Bin 51384 -> 42907 bytes ui/windows/signals_window.py | 128 ++------------------- 2 files changed, 11 insertions(+), 117 deletions(-) (limited to 'ui/windows') diff --git a/ui/windows/__pycache__/signals_window.cpython-312.pyc b/ui/windows/__pycache__/signals_window.cpython-312.pyc index 1f6a3db..f057963 100644 Binary files a/ui/windows/__pycache__/signals_window.cpython-312.pyc and b/ui/windows/__pycache__/signals_window.cpython-312.pyc differ diff --git a/ui/windows/signals_window.py b/ui/windows/signals_window.py index eb7730a..68cceda 100644 --- a/ui/windows/signals_window.py +++ b/ui/windows/signals_window.py @@ -4,14 +4,10 @@ ui/windows/signals_window.py SIGNALS window — toolbar section 3. Tabs: - Pipeline — per-channel filter stack (filters, calibration, scale/offset) + Pipeline — per-channel filter stack (filters, scale/offset) Derived — create virtual channels from physical ones Channels — visibility & color management for all channels -CALIBRATION: A dedicated calibration section inside Pipeline lets the operator -enter known input→output pairs and fits a linear (or polynomial) cal curve, -which is applied as a ScaleOffset filter. - DERIVED includes: - displacement from pot voltage (calibrated) - velocity from displacement (backward difference) @@ -22,15 +18,13 @@ DERIVED includes: """ from __future__ import annotations -import math -from typing import List, Optional, Tuple +from typing import List, Optional from PyQt6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QScrollArea, QFrame, QTabWidget, QComboBox, QLineEdit, QDoubleSpinBox, QSpinBox, QCheckBox, QTextEdit, QGroupBox, - QToolButton, QSizePolicy, QTableWidget, QTableWidgetItem, - QHeaderView, QAbstractItemView, QFormLayout, QMessageBox, + QToolButton, QSizePolicy, QFormLayout, QMessageBox, ) from PyQt6.QtCore import Qt, pyqtSignal from PyQt6.QtGui import QColor, QFont, QCloseEvent @@ -39,7 +33,7 @@ from devices.device_registry import DeviceRegistry from core.signal_processor import ( SignalProcessor, ChannelPipeline, DerivedChannel, FilterBase, MovingAverageFilter, MedianFilter, LowPassFilter, - HighPassFilter, ScaleOffsetFilter, DerivativeFilter, IntegralFilter, + HighPassFilter, DerivativeFilter, IntegralFilter, FILTER_CLASSES, ) @@ -128,92 +122,6 @@ def _also(self, fn): fn(self); return self _QLabel.also = _also -# ══════════════════════════════════════════════════════════════════════════════ -# Calibration widget -# ══════════════════════════════════════════════════════════════════════════════ - -class CalibrationWidget(QGroupBox): - """ - Linear calibration: enter N (raw, engineering) point pairs, - fit y = scale*x + offset, apply as ScaleOffsetFilter. - """ - cal_applied = pyqtSignal(float, float) # scale, offset - - def __init__(self, parent=None): - super().__init__("Calibration", parent) - self._points: List[Tuple[float,float]] = [] - self._build() - - def _build(self): - lay = QVBoxLayout(self); lay.setSpacing(4) - - # Table of raw→engineering pairs - self._tbl = QTableWidget(0, 2) - self._tbl.setHorizontalHeaderLabels(["Raw (sensor)", "Engineering"]) - self._tbl.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) - self._tbl.setMaximumHeight(130) - self._tbl.setObjectName("channelTable") - lay.addWidget(self._tbl) - - btn_row = QHBoxLayout() - add_pt = QPushButton("+ Point"); add_pt.setObjectName("addTraceBtn") - add_pt.clicked.connect(self._add_row) - rm_pt = QPushButton("✕ Remove"); rm_pt.setObjectName("configButton") - rm_pt.clicked.connect(self._rm_row) - btn_row.addWidget(add_pt); btn_row.addWidget(rm_pt); btn_row.addStretch() - lay.addLayout(btn_row) - - # Result - self._result_lbl = QLabel("") - self._result_lbl.setObjectName("traceSource"); lay.addWidget(self._result_lbl) - - fit_btn = QPushButton("Fit & Apply"); fit_btn.setObjectName("applyButton") - fit_btn.clicked.connect(self._fit); lay.addWidget(fit_btn) - - def _add_row(self): - r = self._tbl.rowCount(); self._tbl.insertRow(r) - self._tbl.setItem(r, 0, QTableWidgetItem("0.0")) - self._tbl.setItem(r, 1, QTableWidgetItem("0.0")) - - def _rm_row(self): - rows = {i.row() for i in self._tbl.selectedItems()} - for r in sorted(rows, reverse=True): - self._tbl.removeRow(r) - - def _fit(self): - pts = [] - for r in range(self._tbl.rowCount()): - try: - x = float(self._tbl.item(r,0).text()) - y = float(self._tbl.item(r,1).text()) - pts.append((x,y)) - except Exception: - pass - if len(pts) < 2: - self._result_lbl.setText("⚠ Need ≥2 points"); return - xs = [p[0] for p in pts]; ys = [p[1] for p in pts] - n = len(pts) - sx = sum(xs); sy = sum(ys) - sxx = sum(x*x for x in xs); sxy = sum(x*y for x,y in pts) - denom = n*sxx - sx*sx - if abs(denom) < 1e-12: - self._result_lbl.setText("⚠ Singular — all raw values identical"); return - scale = (n*sxy - sx*sy) / denom - offset = (sy - scale*sx) / n - self._result_lbl.setText( - f"y = {scale:.5g} × x + {offset:.5g} (R²≈{self._r2(xs,ys,scale,offset):.4f})" - ) - self._result_lbl.setStyleSheet("color:#22c55e;") - self.cal_applied.emit(scale, offset) - - @staticmethod - def _r2(xs, ys, scale, offset): - y_mean = sum(ys)/len(ys) - ss_tot = sum((y-y_mean)**2 for y in ys) - ss_res = sum((y - (scale*x+offset))**2 for x,y in zip(xs,ys)) - return 1 - ss_res/ss_tot if ss_tot else 1.0 - - # ══════════════════════════════════════════════════════════════════════════════ # Pipeline Tab — filter stack + calibration for one channel # ══════════════════════════════════════════════════════════════════════════════ @@ -272,10 +180,13 @@ class PipelineTab(QWidget): add_bar.addWidget(add_btn) self._inner.addLayout(add_bar) - # Calibration - self._cal_widget = CalibrationWidget() - self._cal_widget.cal_applied.connect(self._apply_calibration) - self._inner.addWidget(self._cal_widget) + # Apply button + ap_row = QHBoxLayout() + ap_row.addStretch() + ap_btn = QPushButton("✓ Apply Pipeline"); ap_btn.setObjectName("applyButton") + ap_btn.clicked.connect(self._push) + ap_row.addWidget(ap_btn) + self._inner.addLayout(ap_row) self._inner.addStretch() scroll.setWidget(self._cont) @@ -327,23 +238,6 @@ class PipelineTab(QWidget): if self._cur_pipeline: self._cur_pipeline.enabled = v; self._push() - def _apply_calibration(self, scale: float, offset: float): - """Insert/replace a scale_offset filter at the END of the pipeline.""" - if self._cur_pipeline is None: return - # Remove existing scale_offset - self._cur_pipeline.filters = [ - f for f in self._cur_pipeline.filters if f.name != "scale_offset" - ] - cal_filt = ScaleOffsetFilter(scale=scale, offset=offset) - self._cur_pipeline.filters.append(cal_filt) - # Refresh rows - for r in self._rows: - self._filter_lay.removeWidget(r); r.deleteLater() - self._rows.clear() - for f in self._cur_pipeline.filters: - self._add_filter_row(f) - self._push() - def _push(self): if self._cur_pipeline: self.processor.set_pipeline(self._cur_pipeline) -- cgit v1.2.3