new kamil adc
This commit is contained in:
@@ -21,6 +21,10 @@ class AppWindowTracePlotMixin:
|
||||
"""Return whether phase curves should be rendered."""
|
||||
return self._show_phase_checkbox.isChecked()
|
||||
|
||||
def _unwrap_phase_enabled(self) -> bool:
|
||||
"""Return whether the phase trace should be unwrapped (cumulative)."""
|
||||
return self._unwrap_phase_checkbox.isChecked()
|
||||
|
||||
def _pass_through_fixed_y_range(self) -> tuple[bool, float, float]:
|
||||
"""Return normalized magnitude Y-range override for pass-through mode."""
|
||||
y_min = float(self._pass_through_y_min_db.value())
|
||||
@@ -48,13 +52,29 @@ class AppWindowTracePlotMixin:
|
||||
return None
|
||||
|
||||
def _configure_pass_through_magnitude_axis(self, plot: pg.PlotWidget) -> None:
|
||||
"""Apply pass-through magnitude-axis autorange or fixed Y window."""
|
||||
"""Apply the magnitude Y-axis: a fixed window or autorange.
|
||||
|
||||
The X axis is set explicitly from the data band by the caller, so this
|
||||
never re-enables X autorange (which would scan all curves every frame).
|
||||
"""
|
||||
fixed_y_enabled, y_min, y_max = self._pass_through_fixed_y_range()
|
||||
view_box = plot.getViewBox()
|
||||
view_box.invertY(False)
|
||||
view_box.enableAutoRange(x=True, y=not fixed_y_enabled)
|
||||
if fixed_y_enabled:
|
||||
view_box.enableAutoRange(y=False)
|
||||
plot.setYRange(y_min, y_max, padding=0.0)
|
||||
else:
|
||||
view_box.enableAutoRange(y=True)
|
||||
|
||||
def _configure_pass_through_phase_axis(self, plot: pg.PlotWidget) -> None:
|
||||
"""Apply the phase Y-axis: fixed ±180° when wrapped, autorange when unwrapped."""
|
||||
view_box = plot.getViewBox()
|
||||
view_box.invertY(False)
|
||||
if self._unwrap_phase_enabled():
|
||||
view_box.enableAutoRange(y=True)
|
||||
else:
|
||||
view_box.enableAutoRange(y=False)
|
||||
plot.setYRange(-180.0, 180.0, padding=0.02)
|
||||
|
||||
def _on_trace_visibility_changed(self, *_args) -> None:
|
||||
"""Redraw pass-through traces when magnitude/phase toggles changed."""
|
||||
@@ -116,7 +136,6 @@ class AppWindowTracePlotMixin:
|
||||
|
||||
if show_magnitude:
|
||||
mag_item = magnitude_plot.getPlotItem()
|
||||
self._configure_pass_through_magnitude_axis(magnitude_plot)
|
||||
mag_item.showAxis("left", show=True)
|
||||
mag_item.showAxis("bottom", show=not show_phase)
|
||||
magnitude_plot.setLabel("left", "Magnitude", units="dB")
|
||||
@@ -126,8 +145,6 @@ class AppWindowTracePlotMixin:
|
||||
|
||||
if show_phase:
|
||||
phase_item = phase_plot.getPlotItem()
|
||||
phase_plot.getViewBox().invertY(False)
|
||||
phase_plot.getViewBox().enableAutoRange(x=True, y=False)
|
||||
phase_item.showAxis("left", show=True)
|
||||
phase_item.showAxis("bottom", show=True)
|
||||
phase_plot.setLabel("left", "Phase", units="deg")
|
||||
@@ -179,16 +196,18 @@ class AppWindowTracePlotMixin:
|
||||
x_max = max(x_max, local_x_max)
|
||||
|
||||
if show_magnitude:
|
||||
magnitude_values = 20.0 * np.log10(np.maximum(np.abs(payload.trace), 1e-12))
|
||||
mag_x, magnitude_values = self._magnitude_display_arrays(
|
||||
payload.frequency_hz, payload.trace
|
||||
)
|
||||
active_magnitude_keys.add(curve_key)
|
||||
magnitude_curve = self._trace_magnitude_curves.get(curve_key)
|
||||
if magnitude_curve is None:
|
||||
magnitude_curve = pg.PlotCurveItem(pen=pg.mkPen(color, width=1.4))
|
||||
magnitude_curve = pg.PlotCurveItem(pen=pg.mkPen(color, width=1.4), antialias=False)
|
||||
self._trace_magnitude_curves[curve_key] = magnitude_curve
|
||||
magnitude_plot.addItem(magnitude_curve)
|
||||
else:
|
||||
magnitude_curve.setPen(pg.mkPen(color, width=1.4))
|
||||
magnitude_curve.setData(payload.frequency_hz, magnitude_values)
|
||||
magnitude_curve.setData(mag_x, magnitude_values)
|
||||
legend_source_magnitude.setdefault(combo_key, magnitude_curve)
|
||||
has_data = True
|
||||
|
||||
@@ -196,7 +215,7 @@ class AppWindowTracePlotMixin:
|
||||
active_phase_keys.add(curve_key)
|
||||
phase_curve = self._trace_phase_curves.get(curve_key)
|
||||
if phase_curve is None:
|
||||
phase_curve = pg.PlotCurveItem(pen=pg.mkPen(color, width=1.2))
|
||||
phase_curve = pg.PlotCurveItem(pen=pg.mkPen(color, width=1.2), antialias=False)
|
||||
self._trace_phase_curves[curve_key] = phase_curve
|
||||
phase_plot.addItem(phase_curve)
|
||||
else:
|
||||
@@ -231,16 +250,17 @@ class AppWindowTracePlotMixin:
|
||||
phase_sources=legend_source_phase,
|
||||
)
|
||||
|
||||
if has_data:
|
||||
if np.isfinite(x_min) and np.isfinite(x_max):
|
||||
if show_magnitude:
|
||||
magnitude_plot.setXRange(x_min, x_max, padding=0.02)
|
||||
if show_phase:
|
||||
phase_plot.setXRange(x_min, x_max, padding=0.02)
|
||||
if show_phase:
|
||||
phase_plot.setYRange(-180.0, 180.0, padding=0.02)
|
||||
# X is the (constant) frequency band: set it explicitly rather than
|
||||
# autoranging every frame. Y is configured once per draw.
|
||||
if has_data and np.isfinite(x_min) and np.isfinite(x_max):
|
||||
if show_magnitude:
|
||||
self._configure_pass_through_magnitude_axis(magnitude_plot)
|
||||
magnitude_plot.setXRange(x_min, x_max, padding=0.02)
|
||||
if show_phase:
|
||||
phase_plot.setXRange(x_min, x_max, padding=0.02)
|
||||
if show_magnitude:
|
||||
self._configure_pass_through_magnitude_axis(magnitude_plot)
|
||||
if show_phase:
|
||||
self._configure_pass_through_phase_axis(phase_plot)
|
||||
return has_data
|
||||
|
||||
@staticmethod
|
||||
@@ -268,15 +288,40 @@ class AppWindowTracePlotMixin:
|
||||
plot.removeItem(curve)
|
||||
cache.clear()
|
||||
|
||||
def _phase_display_arrays(self, frequency_hz: np.ndarray, trace: np.ndarray) -> tuple[np.ndarray, np.ndarray]:
|
||||
"""Return phase display arrays with decimation for faster rendering."""
|
||||
max_points = int(getattr(self, "_trace_phase_render_max_points", 1200))
|
||||
if max_points > 0 and trace.size > max_points:
|
||||
step = max(1, int(np.ceil(trace.size / max_points)))
|
||||
frequency_hz = frequency_hz[::step]
|
||||
trace = trace[::step]
|
||||
phase_values = np.arctan2(trace.imag, trace.real) * (180.0 / np.pi)
|
||||
return frequency_hz, phase_values
|
||||
def _render_decimation_step(self, size: int) -> int:
|
||||
"""Stride that caps a rendered trace at the configured maximum point count.
|
||||
|
||||
Beyond ~1 point per screen pixel there is no visual gain, so decimating
|
||||
keeps the line plots responsive even with many combos on screen.
|
||||
"""
|
||||
max_points = int(getattr(self, "_trace_render_max_points", 800))
|
||||
if max_points > 0 and size > max_points:
|
||||
return max(1, int(np.ceil(size / max_points)))
|
||||
return 1
|
||||
|
||||
def _magnitude_display_arrays(
|
||||
self, frequency_hz: np.ndarray, trace: np.ndarray
|
||||
) -> tuple[np.ndarray, np.ndarray]:
|
||||
"""Return decimated (frequency, magnitude-dB) arrays for fast rendering."""
|
||||
step = self._render_decimation_step(int(trace.size))
|
||||
frequency_hz = frequency_hz[::step]
|
||||
magnitude_db = 20.0 * np.log10(np.maximum(np.abs(trace[::step]), 1e-12))
|
||||
return frequency_hz, magnitude_db
|
||||
|
||||
def _phase_display_arrays(
|
||||
self, frequency_hz: np.ndarray, trace: np.ndarray
|
||||
) -> tuple[np.ndarray, np.ndarray]:
|
||||
"""Return decimated (frequency, phase-deg) arrays, unwrapped when enabled.
|
||||
|
||||
Unwrapping runs at full resolution (before decimation) so the cumulative
|
||||
phase is correct, then both arrays are decimated together for rendering.
|
||||
"""
|
||||
phase = np.angle(trace)
|
||||
if self._unwrap_phase_enabled():
|
||||
phase = np.unwrap(phase)
|
||||
phase_deg = np.degrees(phase)
|
||||
step = self._render_decimation_step(int(trace.size))
|
||||
return frequency_hz[::step], phase_deg[::step]
|
||||
|
||||
def _sync_trace_legends(
|
||||
self,
|
||||
@@ -363,26 +408,24 @@ class AppWindowTracePlotMixin:
|
||||
return
|
||||
|
||||
if show_magnitude:
|
||||
self._configure_pass_through_magnitude_axis(magnitude_plot)
|
||||
magnitude_plot.getPlotItem().showAxis("bottom", show=not show_phase)
|
||||
magnitude_plot.setLabel("left", "Magnitude", units="dB")
|
||||
magnitude_plot.setTitle(title)
|
||||
if not show_phase:
|
||||
magnitude_plot.setLabel("bottom", "Frequency", units="Hz")
|
||||
if show_phase:
|
||||
phase_plot.getViewBox().invertY(False)
|
||||
phase_plot.getViewBox().enableAutoRange(x=True, y=False)
|
||||
phase_plot.getPlotItem().showAxis("bottom", show=True)
|
||||
phase_plot.setLabel("left", "Phase", units="deg")
|
||||
phase_plot.setLabel("bottom", "Frequency", units="Hz")
|
||||
phase_plot.setTitle(title)
|
||||
|
||||
if show_magnitude:
|
||||
magnitude_db = 20.0 * np.log10(np.maximum(np.abs(samples), 1e-12))
|
||||
mag_x, magnitude_db = self._magnitude_display_arrays(trace.frequency_hz, samples)
|
||||
magnitude_curve = pg.PlotCurveItem(
|
||||
trace.frequency_hz,
|
||||
mag_x,
|
||||
magnitude_db,
|
||||
pen=pg.mkPen("#ffd166", width=1.8),
|
||||
antialias=False,
|
||||
)
|
||||
magnitude_plot.addItem(magnitude_curve)
|
||||
self._trace_magnitude_curves[
|
||||
@@ -390,23 +433,26 @@ class AppWindowTracePlotMixin:
|
||||
] = magnitude_curve
|
||||
|
||||
if show_phase:
|
||||
phase_values = np.degrees(np.angle(samples))
|
||||
phase_x, phase_values = self._phase_display_arrays(trace.frequency_hz, samples)
|
||||
phase_curve = pg.PlotCurveItem(
|
||||
trace.frequency_hz,
|
||||
phase_x,
|
||||
phase_values,
|
||||
pen=pg.mkPen("#80ed99", width=1.4, style=Qt.PenStyle.DashLine),
|
||||
antialias=False,
|
||||
)
|
||||
phase_plot.addItem(phase_curve)
|
||||
self._trace_phase_curves[
|
||||
(int(trace.combo.input), int(trace.combo.output), 0, "__single_trace__")
|
||||
] = phase_curve
|
||||
phase_plot.setYRange(-180.0, 180.0, padding=0.02)
|
||||
|
||||
if np.size(trace.frequency_hz) > 1:
|
||||
x_min = float(np.min(trace.frequency_hz))
|
||||
x_max = float(np.max(trace.frequency_hz))
|
||||
if show_magnitude:
|
||||
magnitude_plot.setXRange(x_min, x_max, padding=0.02)
|
||||
self._configure_pass_through_magnitude_axis(magnitude_plot)
|
||||
if show_phase:
|
||||
phase_plot.setXRange(x_min, x_max, padding=0.02)
|
||||
if show_magnitude:
|
||||
self._configure_pass_through_magnitude_axis(magnitude_plot)
|
||||
if show_phase:
|
||||
self._configure_pass_through_phase_axis(phase_plot)
|
||||
|
||||
Reference in New Issue
Block a user