Surface Velocity#

This example uses the A121 to measure the surface velocity of a water flow. Both direction and velocity are estimated.


The sensor needs to be positioned at an angle. The sensor angle, sensor_angle, is defined as the angle from the water surface, thus 0 degrees is defined as the sensor facing straight down to the surface. The angle needs to be big enough to get a good velocity estimate and small enough to get enough reflected radar signal back to the sensor. It was found that the optimal angle is between 35 and 45 degrees. The optimal range to be measured is calculated based on the sensor angle, the perpendicular distance from the sensor to the surface, surface_distance, the number of points to be measured, and the step length. Based on the measured range, the optimal profile is automatically chosen.

The direction of the flow is seen as either positive or negative. Water flowing towards the sensor will be seen as negative flow, while water flowing away from the sensor will be seen as positive flow.


Time series#

Based on the set sweep rate and the sensor angle, the maximum velocity that can be measured is decided. The resolution is determined by the number of samples in the time series, set by the time_series_length. By default, continuous sweep mode and double buffering are enabled. With continuous sweep mode, the interval between the last sweep in one frame and the first sweep in the following frame is the same as the interval between the sweeps in the frames, see Continuous sweep mode (CSM). This makes it possible to create a time series that is longer than the number of sweeps per frame, giving good resolution with a high sweep rate. If the continuous sweep mode is not used, the time series length will be set to the number of sweeps per frame.

To estimate the velocity, the power spectral density (PSD) is calculated for all measured distances and the PSD with the most energy is used for the velocity estimate. The PSD is low pass filtered in time and the filter coefficient is set by the psd_lp_coeff. If a small sensor angle is used, the PSD can get a high peak around 0 Hz. Due to this, a slow zone is defined, slow_zone. The slow zone is neglected when choosing PSD based on energy. Furthermore, peaks in the PSD outside the slow zone are prioritized.

Peak finding#

The threshold method used to find peaks in the PSD is based on a one-sided constant false alarm rate (CFAR) threshold. The parameters for this threshold are the window from which the neighboring frequency bins are averaged, cfar_win, and the guard or gap around the frequency bin of interest, which is omitted, cfar_guard. Finally, there is a sensitivity parameter, between zero and one, adjusting the threshold, cfar_sensitivity.

Because of the chaotic nature of water flow, the peaks in the PSD are not constantly present. With lower velocities, the time between peaks is larger. To have a steady estimate of the velocity, an interval is set and during this time the velocity estimate does not change if the new estimate is a decrease larger than 20%. The maximum interval time is controlled by the max_peak_interval_s.

Peaks in the PSD that are closer together than 0.1 m/s will be regarded as the same. If the estimated velocity is based on a merged peak, it will be seen as a colored area around the velocity estimate in the GUI.

As a final step, the estimated velocity from the PSD is low pass filtered with a filter coefficient that is controlled by the velocity_lp_coeff.


The top plot in the GUI shows a timeline of the estimated velocity. It also displays the distance that was used for the estimate. In the second plot, the PSD together with the CFAR threshold is shown. The frequencies have been converted to velocities and the colored middle section in the PSD represents the slow zone.


Configuration parameters#

class acconeer.exptool.a121.algo.surface_velocity._example_app.ExampleAppConfig(*, surface_distance: float = 1, sensor_angle: float = 45, num_points: int = 4, step_length: int = 12, profile: Profile | None = None, frame_rate: float | None = None, sweep_rate: float = 3000, sweeps_per_frame: int = 128, hwaas: int = 16, double_buffering: bool = True, continuous_sweep_mode: bool = True, inter_frame_idle_state: IdleState = IdleState.READY, inter_sweep_idle_state: IdleState = IdleState.READY, time_series_length: int = 512, psd_lp_coeff: float = 0.75, cfar_sensitivity: float = 0.15, cfar_guard: int = 6, cfar_win: int = 6, slow_zone: int = 3, velocity_lp_coeff: float = 0.98, max_peak_interval_s: float = 4)#
surface_distance: float#

Perpendicular distance from the water surface to the sensor in meters.

sensor_angle: float#

Sensor angle in degrees. 0 degrees is defined as the sensor facing straight down to the surface.

num_points: int#

Number of data points in the measurement.

step_length: int#

Step length in points.

profile: Profile | None#

Sets the profile. If no argument is provided, the highest possible profile without interference of direct leakage is used to maximize SNR.

frame_rate: float | None#

Frame rate in Hz.

sweep_rate: float#

Sweep rate in Hz.

sweeps_per_frame: int#

Number of sweeps per frame.

hwaas: int#

Number of HWAAS.

double_buffering: bool#

Enables double buffering.

continuous_sweep_mode: bool#

Enables continuous sweep mode.

inter_frame_idle_state: IdleState#

Sets the inter frame idle state.

inter_sweep_idle_state: IdleState#

Sets the inter sweep idle state.

time_series_length: int#

Number of sweeps in the time series.

psd_lp_coeff: float#

Filter coefficient for the exponential filter of PSD over time.

cfar_sensitivity: float#

Sensitivity of the CFAR threshold. Low sensitivity will set a high threshold.

cfar_guard: int#

Number of frequency bins around the point of interest that is omitted when calculating the CFAR threshold.

cfar_win: int#

Number of frequency bins next to the CFAR guard from which the threshold level will be calculated.

slow_zone: int#

Half size of the number of frequency bins that are regarded as the slow zone.

velocity_lp_coeff: float#

Filter coefficient for the exponential filter of the velocity estimate.

max_peak_interval_s: float#

Maximal number of seconds that is tolerated between peaks before the estimated velocity starts decreasing.

Detector result#

class acconeer.exptool.a121.algo.surface_velocity._example_app.ExampleAppResult(*, velocity: float, distance_m: float, processor_extra_result: ProcessorExtraResult, service_result: Result)#
velocity: float#

Estimated velocity.

distance_m: float#

Distance in meters used for the current velocity estimate.