From 5591e80c53fc58ebd87faaf3297df4c95b34437c Mon Sep 17 00:00:00 2001 From: awe Date: Tue, 5 May 2026 09:29:29 +0300 Subject: [PATCH] fix carry --- rfg_adc_plotter/gui/pyqtgraph_backend.py | 83 ++++++++++++++++++------ tests/test_processing.py | 13 ++++ 2 files changed, 75 insertions(+), 21 deletions(-) diff --git a/rfg_adc_plotter/gui/pyqtgraph_backend.py b/rfg_adc_plotter/gui/pyqtgraph_backend.py index cc25e6f..7c9fa64 100644 --- a/rfg_adc_plotter/gui/pyqtgraph_backend.py +++ b/rfg_adc_plotter/gui/pyqtgraph_backend.py @@ -102,6 +102,32 @@ def display_distance_axis( return (float(zero_at_m) - axis_arr).astype(np.float64, copy=False) +def display_distance_transform_enabled(mode: str | None) -> bool: + """Only the exact positive-only IFFT mode uses the shifted/reversed display axis.""" + return str(mode or "").strip().lower() == "positive_only_exact" + + +def display_distance_value_for_mode(distance_m: float, mode: str | None) -> float: + if display_distance_transform_enabled(mode): + return display_distance_value(distance_m) + try: + distance_val = float(distance_m) + except Exception: + return float("nan") + return distance_val if np.isfinite(distance_val) else float("nan") + + +def display_distance_axis_for_mode(distance_axis: Optional[np.ndarray], mode: str | None) -> np.ndarray: + if display_distance_transform_enabled(mode): + return display_distance_axis(distance_axis) + if distance_axis is None: + return np.zeros((0,), dtype=np.float64) + axis_arr = np.asarray(distance_axis, dtype=np.float64).reshape(-1) + if axis_arr.size <= 0: + return np.zeros((0,), dtype=np.float64) + return axis_arr + + def sanitize_curve_data_for_display( xs: Optional[np.ndarray], ys: Optional[np.ndarray], @@ -1022,7 +1048,7 @@ def run_pyqtgraph(args) -> None: fft_bg_line.setVisible(False) fft_left_line.setVisible(False) fft_right_line.setVisible(False) - p_fft.setLabel("bottom", "Расстояние, м (0 = 9 м)") + p_fft.setLabel("bottom", "Расстояние, м") p_fft.setLabel("left", "Амплитуда" if complex_sweep_mode else "дБ") if complex_sweep_mode: try: @@ -1043,7 +1069,7 @@ def run_pyqtgraph(args) -> None: p_spec.getAxis("bottom").setStyle(showValues=False) except Exception: pass - p_spec.setLabel("left", "Расстояние, м (0 = 9 м)") + p_spec.setLabel("left", "Расстояние, м") img_fft = pg.ImageItem() p_spec.addItem(img_fft) spec_left_line = pg.InfiniteLine(angle=0, movable=False, pen=peak_pen) @@ -1441,6 +1467,18 @@ def run_pyqtgraph(args) -> None: set_item_visible_if_changed("spec_left_line", spec_left_line, visible) set_item_visible_if_changed("spec_right_line", spec_right_line, visible) + def refresh_distance_axis_labels() -> None: + distance_label = ( + "Расстояние, м (0 = 9 м)" + if display_distance_transform_enabled(fft_mode) + else "Расстояние, м" + ) + try: + p_fft.setLabel("bottom", distance_label) + p_spec.setLabel("left", distance_label) + except Exception: + pass + fixed_ylim: Optional[Tuple[float, float]] = None if args.ylim: try: @@ -1498,7 +1536,7 @@ def run_pyqtgraph(args) -> None: text = f"{fft_low_cut_percent:.1f}%" cut_start = _active_distance_cut_start() if cut_start is not None and np.isfinite(cut_start): - text = f"{text} (~{display_distance_value(cut_start):.4g} м)" + text = f"{text} (~{display_distance_value_for_mode(cut_start, fft_mode):.4g} м)" if text == last_fft_low_cut_label_text: return try: @@ -1527,7 +1565,7 @@ def run_pyqtgraph(args) -> None: distance_bounds = resolve_axis_bounds(runtime.ring.distance_axis) if distance_bounds is not None: - display_axis_full = display_distance_axis(runtime.ring.distance_axis) + display_axis_full = display_distance_axis_for_mode(runtime.ring.distance_axis, fft_mode) display_bounds = resolve_axis_bounds(display_axis_full) if display_bounds is not None: d_min_display, d_max_display = display_bounds @@ -1549,7 +1587,7 @@ def run_pyqtgraph(args) -> None: d_cut = _active_distance_cut_start() fft_axis_physical, _fft_keep = apply_distance_cut_to_axis(runtime.ring.distance_axis, d_cut) - fft_display_bounds = resolve_axis_bounds(display_distance_axis(fft_axis_physical)) + fft_display_bounds = resolve_axis_bounds(display_distance_axis_for_mode(fft_axis_physical, fft_mode)) if fft_display_bounds is not None: set_x_range_if_changed("fft_x", p_fft, fft_display_bounds[0], fft_display_bounds[1], padding=0) refresh_fft_low_cut_label() @@ -2398,6 +2436,7 @@ def run_pyqtgraph(args) -> None: "positive_only": "IFFT: нули [-max,+min]", "positive_only_exact": "IFFT: нули [-max,+min] точный", }.get(fft_mode, f"IFFT: {fft_mode}") + refresh_distance_axis_labels() set_status_note(mode_label) update_physical_axes() runtime.mark_dirty() @@ -2457,7 +2496,7 @@ def run_pyqtgraph(args) -> None: if idx < len(peaks): peak = peaks[idx] lines.append(f"peak {idx + 1}:") - lines.append(f" X: {display_distance_value(peak['x']):.4g} m") + lines.append(f" X: {display_distance_value_for_mode(peak['x'], fft_mode):.4g} m") lines.append(f" H: {peak['height']:.4g} dB") lines.append(f" W: {peak['width']:.4g} m") else: @@ -3186,7 +3225,7 @@ def run_pyqtgraph(args) -> None: fft_complex_plot = fft_complex_plot[fft_keep_mask] elif fft_complex_plot is not None: fft_complex_plot = None - xs_fft_display = display_distance_axis(xs_fft) + xs_fft_display = display_distance_axis_for_mode(xs_fft, fft_mode) fft_x_bounds = resolve_axis_bounds(xs_fft_display) if fft_x_bounds is not None: set_x_range_if_changed("fft_x", p_fft, fft_x_bounds[0], fft_x_bounds[1], padding=0) @@ -3244,11 +3283,12 @@ def run_pyqtgraph(args) -> None: set_curve_data( f"fft_peak_box_{idx}", box, - display_distance_axis( + display_distance_axis_for_mode( np.asarray( [peak["left"], peak["left"], peak["right"], peak["right"], peak["left"]], dtype=np.float64, - ) + ), + fft_mode, ), y_box, ) @@ -3270,10 +3310,10 @@ def run_pyqtgraph(args) -> None: markers = find_peak_width_markers(xs_fft, fft_vals_db) if markers is not None: fft_bg_line.setValue(float(_db_to_linear_amplitude(np.asarray([markers["background"]]))[0])) - fft_left_line.setValue(display_distance_value(markers["left"])) - fft_right_line.setValue(display_distance_value(markers["right"])) - spec_left_line.setValue(display_distance_value(markers["left"])) - spec_right_line.setValue(display_distance_value(markers["right"])) + fft_left_line.setValue(display_distance_value_for_mode(markers["left"], fft_mode)) + fft_right_line.setValue(display_distance_value_for_mode(markers["right"], fft_mode)) + spec_left_line.setValue(display_distance_value_for_mode(markers["left"], fft_mode)) + spec_right_line.setValue(display_distance_value_for_mode(markers["right"], fft_mode)) set_peak_marker_visibility(True) runtime.current_peak_width = markers["width"] runtime.current_peak_amplitude = markers["amplitude"] @@ -3314,11 +3354,12 @@ def run_pyqtgraph(args) -> None: set_curve_data( f"fft_peak_box_{idx}", box, - display_distance_axis( + display_distance_axis_for_mode( np.asarray( [peak["left"], peak["left"], peak["right"], peak["right"], peak["left"]], dtype=np.float64, - ) + ), + fft_mode, ), [peak["ref"], peak["peak_y"], peak["peak_y"], peak["ref"], peak["ref"]], ) @@ -3349,10 +3390,10 @@ def run_pyqtgraph(args) -> None: markers = find_peak_width_markers(xs_fft, fft_vals_db) if markers is not None: fft_bg_line.setValue(markers["background"]) - fft_left_line.setValue(display_distance_value(markers["left"])) - fft_right_line.setValue(display_distance_value(markers["right"])) - spec_left_line.setValue(display_distance_value(markers["left"])) - spec_right_line.setValue(display_distance_value(markers["right"])) + fft_left_line.setValue(display_distance_value_for_mode(markers["left"], fft_mode)) + fft_right_line.setValue(display_distance_value_for_mode(markers["right"], fft_mode)) + spec_left_line.setValue(display_distance_value_for_mode(markers["left"], fft_mode)) + spec_right_line.setValue(display_distance_value_for_mode(markers["right"], fft_mode)) set_peak_marker_visibility(True) runtime.current_peak_width = markers["width"] runtime.current_peak_amplitude = markers["amplitude"] @@ -3540,8 +3581,8 @@ def run_pyqtgraph(args) -> None: and runtime.ring.y_min_fft != runtime.ring.y_max_fft ): levels = (runtime.ring.y_min_fft, runtime.ring.y_max_fft) - disp_fft_display_axis = display_distance_axis(disp_fft_axis) - if disp_fft_display_axis.size == disp_fft.shape[0]: + disp_fft_display_axis = display_distance_axis_for_mode(disp_fft_axis, fft_mode) + if display_distance_transform_enabled(fft_mode) and disp_fft_display_axis.size == disp_fft.shape[0]: disp_fft = disp_fft[::-1, :] disp_fft_display_axis = disp_fft_display_axis[::-1] distance_bounds = resolve_axis_bounds(disp_fft_display_axis) diff --git a/tests/test_processing.py b/tests/test_processing.py index b3063ef..6bf77d1 100644 --- a/tests/test_processing.py +++ b/tests/test_processing.py @@ -21,7 +21,9 @@ from rfg_adc_plotter.gui.pyqtgraph_backend import ( decimate_bscan_rows_for_display, decimate_curve_for_display, display_distance_axis, + display_distance_axis_for_mode, display_distance_value, + display_distance_value_for_mode, fft_bscan_image_to_db, is_short_sweep, resolve_axis_bounds, @@ -555,6 +557,17 @@ class ProcessingTests(unittest.TestCase): np.testing.assert_allclose(display_axis, np.asarray([9.0, 4.5, 0.0], dtype=np.float64)) self.assertAlmostEqual(display_distance_value(9.0), 0.0, places=12) + def test_display_distance_axis_transform_only_for_positive_only_exact_mode(self): + axis = np.asarray([0.0, 4.5, 9.0], dtype=np.float64) + + np.testing.assert_allclose(display_distance_axis_for_mode(axis, "symmetric"), axis) + np.testing.assert_allclose( + display_distance_axis_for_mode(axis, "positive_only_exact"), + np.asarray([9.0, 4.5, 0.0], dtype=np.float64), + ) + self.assertAlmostEqual(display_distance_value_for_mode(9.0, "symmetric"), 9.0, places=12) + self.assertAlmostEqual(display_distance_value_for_mode(9.0, "positive_only_exact"), 0.0, places=12) + def test_resolve_initial_window_size_stays_within_small_screen(self): width, height = resolve_initial_window_size(800, 480)