spacexerq 1 hafta önce
ebeveyn
işleme
672aaa0263
2 değiştirilmiş dosya ile 48 ekleme ve 47 silme
  1. 31 43
      apps/gui/src/tabs/seq_interp_tab.py
  2. 17 4
      services/seq-interp/api.py

+ 31 - 43
apps/gui/src/tabs/seq_interp_tab.py

@@ -238,23 +238,7 @@ class SeqInterpTab(QWidget):
             f.setFixedWidth(2)
             return f
 
-        # -- Per-channel ADC dynamic range ------------------------------------
-        _range_lbl = QLabel("Каналы АЦП:")
-        _range_lbl.setToolTip("Динамический диапазон АЦП по каналам (iadc.channel_ranges)")
-        lay.addWidget(_range_lbl)
-
-        self._ch_range_container = QWidget()
-        self._ch_range_layout    = QHBoxLayout(self._ch_range_container)
-        self._ch_range_layout.setContentsMargins(0, 0, 0, 0)
-        self._ch_range_layout.setSpacing(4)
-        self._ch_range_combos: list[QComboBox] = []
-        lay.addWidget(self._ch_range_container)
-
-        _default_ranges = self._read_hw_config_channel_ranges()
-        self._rebuild_ch_range_combos(_default_ranges)
-
         # -- Averaging --------------------------------------------------------
-        lay.addWidget(sep())
         self._avg_check = QCheckBox("Усреднение")
         self._avg_check.setToolTip(
             "Включить усреднение (iadc.averaging).\nВыключено = 1."
@@ -347,17 +331,21 @@ class SeqInterpTab(QWidget):
         self._controls = DelayControlsPanel()
         lay.addWidget(self._controls)
 
-        self._warn_grp = TrGroupBox("grp_warnings")
-        warn_lay = QVBoxLayout(self._warn_grp)
-        self._warn_list = QListWidget()
-        self._warn_list.setFont(QFont("Arial", 9))
-        self._warn_list.setMaximumHeight(110)
-        self._warn_list.setStyleSheet(
-            "QListWidget { color: #ddddff; background: #16162a; border: 1px solid #2a2a4a; } "
-            "QListWidget::item { padding: 2px; }"
-        )
-        warn_lay.addWidget(self._warn_list)
-        lay.addWidget(self._warn_grp)
+        # Warnings are shown in PreviewPanel (right panel) — no separate widget needed here
+        self._warn_list = QListWidget()   # kept for _refresh_warnings compatibility
+
+        # -- Per-channel ADC range (lives here, not in the toolbar) -----------
+        self._ch_range_grp = TrGroupBox("grp_adc_ranges")
+        self._ch_range_grp.setTitle("АЦП диапазоны")
+        self._ch_range_form = QFormLayout(self._ch_range_grp)
+        self._ch_range_form.setFieldGrowthPolicy(QFormLayout.AllNonFixedFieldsGrow)
+        self._ch_range_form.setLabelAlignment(Qt.AlignRight | Qt.AlignVCenter)
+        self._ch_range_combos: list[QComboBox] = []
+        lay.addWidget(self._ch_range_grp)
+
+        # Initialise with hw_config defaults
+        _default_ranges = self._read_hw_config_channel_ranges()
+        self._rebuild_ch_range_combos(_default_ranges)
 
         lay.addStretch()
 
@@ -659,7 +647,6 @@ class SeqInterpTab(QWidget):
     def _make_ch_combo(self, code: int) -> QComboBox:
         """Create a single channel range combo preset to `code`."""
         cb = QComboBox()
-        cb.setFixedWidth(72)
         for c, label in _ADC_RANGES:
             cb.addItem(label, userData=c)
         idx = next((i for i, (c, _) in enumerate(_ADC_RANGES) if c == code), 0)
@@ -668,26 +655,16 @@ class SeqInterpTab(QWidget):
         return cb
 
     def _rebuild_ch_range_combos(self, ranges: list[int]) -> None:
-        """Recreate per-channel combo widgets to match `ranges`."""
-        # Remove old widgets
-        for cb in self._ch_range_combos:
-            self._ch_range_layout.removeWidget(cb)
-            cb.deleteLater()
+        """Recreate per-channel combo widgets in the left-panel form layout."""
+        # Clear existing form rows
+        while self._ch_range_form.rowCount() > 0:
+            self._ch_range_form.removeRow(0)
         self._ch_range_combos.clear()
 
-        # Remove old channel labels
-        while self._ch_range_layout.count():
-            item = self._ch_range_layout.takeAt(0)
-            if item.widget():
-                item.widget().deleteLater()
-
         for idx, code in enumerate(ranges):
-            lbl = QLabel(f"Ch{idx}")
-            lbl.setToolTip(f"Канал {idx}")
-            self._ch_range_layout.addWidget(lbl)
             cb = self._make_ch_combo(code)
             cb.setToolTip(f"Динамический диапазон канала {idx}")
-            self._ch_range_layout.addWidget(cb)
+            self._ch_range_form.addRow(str(idx), cb)
             self._ch_range_combos.append(cb)
 
     def _selected_adc_ranges(self) -> list[int]:
@@ -731,6 +708,7 @@ class SeqInterpTab(QWidget):
     def _on_adc_range_changed(self) -> None:
         if self._post_info:
             self._patch_adc_range(self._post_info)
+            self._refresh_post_json_preview()
 
     # -- Averaging helpers --------------------------------------------------
 
@@ -748,10 +726,20 @@ class SeqInterpTab(QWidget):
         self._avg_spin.setEnabled(checked)
         if self._post_info:
             self._patch_averaging(self._post_info)
+            self._refresh_post_json_preview()
 
     def _on_avg_value_changed(self) -> None:
         if self._avg_check.isChecked() and self._post_info:
             self._patch_averaging(self._post_info)
+            self._refresh_post_json_preview()
+
+    def _refresh_post_json_preview(self) -> None:
+        """Push current _post_info into the preview panel POST JSON tab."""
+        if self._post_info:
+            import json as _j
+            self._preview.set_post_json_text(
+                _j.dumps({"info": self._post_info}, indent=2, ensure_ascii=False)
+            )
 
     def _on_post_json_edited(self, data: dict) -> None:
         """

+ 17 - 4
services/seq-interp/api.py

@@ -94,18 +94,31 @@ def _downsample(arr, max_pts: int) -> list:
 
 def _extract_waveforms(seq_data: dict, sync_data: dict) -> dict:
     """Extract waveform arrays from seq_data for GUI display."""
+    try:
+        import numpy as _np
+    except ImportError:
+        _np = None
+
     waveforms: dict[str, list] = {}
+
+    # Gradients
     for key in ("gx", "gy", "gz", "t_gx", "t_gy", "t_gz"):
         if key in seq_data:
             waveforms[key] = _downsample(seq_data[key], _MAX_WAVEFORM_POINTS)
-    # RF
-    for key in ("rf_amp", "rf_phase", "t_rf"):
-        if key in seq_data:
-            waveforms[key] = _downsample(seq_data[key], _MAX_WAVEFORM_POINTS)
+
+    # RF — seq_data stores a complex array under "rf" / "t_rf".
+    # Split into amplitude and phase for JSON transport (complex is not serialisable).
+    if "rf" in seq_data and "t_rf" in seq_data and _np is not None:
+        rf = _np.asarray(seq_data["rf"])
+        waveforms["rf_amp"]   = _downsample(_np.abs(rf),    _MAX_WAVEFORM_POINTS)
+        waveforms["rf_phase"] = _downsample(_np.angle(rf),  _MAX_WAVEFORM_POINTS)
+        waveforms["t_rf"]     = _downsample(seq_data["t_rf"], _MAX_WAVEFORM_POINTS)
+
     # Sync gate arrays
     for key in ("gate_adc", "gate_rf", "gate_tr_switch", "blocks_duration"):
         if key in sync_data:
             waveforms[key] = _downsample(sync_data[key], _MAX_WAVEFORM_POINTS)
+
     return waveforms