examples/a121/algo/distance/processor.py#
1# Copyright (c) Acconeer AB, 2022-2026
2# All rights reserved
3
4from __future__ import annotations
5
6import copy
7
8import numpy as np
9
10import pyqtgraph as pg
11
12import acconeer.exptool as et
13from acconeer.exptool import a121
14from acconeer.exptool.a121.algo.distance import (
15 Processor,
16 ProcessorConfig,
17 ProcessorContext,
18 ThresholdMethod,
19 calculate_bg_noise_std,
20)
21
22
23def main():
24 args = a121.ExampleArgumentParser().parse_args()
25 et.utils.config_logging(args)
26
27 client = a121.Client.open(**a121.get_client_args(args))
28
29 # Define sensor configuration.
30 sensor_config = a121.SensorConfig(
31 subsweeps=[
32 a121.SubsweepConfig(
33 start_point=50,
34 step_length=4,
35 num_points=50,
36 profile=a121.Profile.PROFILE_1,
37 hwaas=32,
38 phase_enhancement=True,
39 iq_imbalance_compensation=True,
40 )
41 ],
42 sweeps_per_frame=1,
43 )
44 session_config = a121.SessionConfig(sensor_config)
45
46 # Calibrate noise.
47 noise_sensor_config = copy.deepcopy(sensor_config)
48 for subsweep in noise_sensor_config.subsweeps:
49 # Disable Tx when measuring background noise.
50 subsweep.enable_tx = False
51
52 metadata = client.setup_session(noise_sensor_config)
53 client.start_session()
54 result = client.get_next()
55 client.stop_session()
56
57 stds = [
58 calculate_bg_noise_std(subframe, subsweep_config)
59 for (subframe, subsweep_config) in zip(result.subframes, noise_sensor_config.subsweeps)
60 ]
61
62 # Create processor for distance estimation.
63 distance_context = ProcessorContext(
64 bg_noise_std=stds,
65 )
66 distance_config = ProcessorConfig(
67 threshold_method=ThresholdMethod.CFAR,
68 threshold_sensitivity=0.8,
69 )
70 distance_processor = Processor(
71 session_config=session_config,
72 metadata=metadata,
73 processor_config=distance_config,
74 context=distance_context,
75 )
76
77 pg_updater = PGUpdater()
78 pg_process = et.PGProcess(pg_updater)
79 pg_process.start()
80
81 metadata = client.setup_session(sensor_config)
82 client.start_session()
83
84 interrupt_handler = et.utils.ExampleInterruptHandler()
85
86 while not interrupt_handler.got_signal:
87 extended_result = client.get_next()
88 processed_data = distance_processor.process(extended_result)
89 try:
90 pg_process.put_data(processed_data)
91 except et.PGProccessDiedException:
92 break
93
94 print("Disconnecting...")
95 pg_process.close()
96 client.close()
97
98
99class PGUpdater:
100 def __init__(self):
101 self.history = [np.nan] * 100
102
103 def setup(self, win):
104 self.sweep_plot = win.addPlot(row=0, col=0)
105 self.sweep_plot.setMenuEnabled(False)
106 self.sweep_plot.showGrid(x=True, y=True)
107 self.sweep_plot.addLegend()
108 self.sweep_plot.setLabel("left", "Amplitude")
109 self.sweep_plot.setLabel("bottom", "Distance(m)")
110 self.sweep_plot.addItem(pg.PlotDataItem())
111
112 legends = ["Sweep", "Threshold"]
113 self.curves = {}
114 for i, legend in enumerate(legends):
115 pen = et.utils.pg_pen_cycler(i)
116 brush = et.utils.pg_brush_cycler(i)
117 symbol_kw = dict(symbol="o", symbolSize=1, symbolBrush=brush, symbolPen="k")
118 feat_kw = dict(pen=pen, **symbol_kw)
119 self.curves[legend] = self.sweep_plot.plot(**feat_kw, name=legend)
120
121 self.smooth_max = et.utils.SmoothMax()
122
123 self.dist_history_plot = win.addPlot(row=1, col=0)
124 self.dist_history_plot.setMenuEnabled(False)
125 self.dist_history_plot.showGrid(x=True, y=True)
126 self.dist_history_plot.addLegend()
127 self.dist_history_plot.setLabel("left", "Estimated distance (m)")
128 self.dist_history_plot.setLabel("bottom", "History (frame)")
129 self.dist_history_plot.addItem(pg.PlotDataItem())
130 self.dist_history_plot.setXRange(0, len(self.history))
131
132 pen = et.utils.pg_pen_cycler(0)
133 brush = et.utils.pg_brush_cycler(0)
134 symbol_kw = dict(symbol="o", symbolSize=5, symbolBrush=brush, symbolPen="k")
135 feat_kw = dict(pen=pen, **symbol_kw)
136 self.dist_history_curve = self.dist_history_plot.plot(**feat_kw)
137
138 def update(self, d):
139 sweep = d.extra_result.abs_sweep
140 threshold = d.extra_result.used_threshold
141 distances = d.extra_result.distances_m
142
143 self.history.pop(0)
144 if len(d.estimated_distances) != 0:
145 self.history.append(d.estimated_distances[0])
146 else:
147 self.history.append(np.nan)
148
149 self.curves["Sweep"].setData(distances, sweep)
150 self.curves["Threshold"].setData(distances, threshold)
151 self.sweep_plot.setYRange(
152 0,
153 self.smooth_max.update(np.amax(np.concatenate((sweep, threshold)))),
154 )
155
156 if not np.all(np.isnan(self.history)):
157 self.dist_history_curve.setData(self.history)
158
159
160if __name__ == "__main__":
161 main()
View this example on GitHub: acconeer/acconeer-python-exploration