Go to the documentation of this file.
24 #define MODULE "example_vibration"
32 #define RADIANS_TO_DISPLACEMENT_FACTOR (394.32604621792916f)
34 #define NUM_POINTS (1U)
35 #define CFAR_WINDOW_LENGTH (10U)
36 #define CFAR_HALF_GUARD_LENGTH (5U)
37 #define CFAR_MARGIN (CFAR_WINDOW_LENGTH + CFAR_HALF_GUARD_LENGTH)
39 #define IS_POWER_OF_TWO(x) (((x) & ((x) - 1)) == 0)
40 #define BOOL_TO_STR(b) (b ? "true" : "false")
117 bool status =
config != NULL;
128 config->measured_point = 80U;
129 config->time_series_length = 1024U;
132 config->amplitude_threshold = 100.0f;
134 config->low_frequency_enhancement =
true;
136 config->frame_rate = 0.0f;
137 config->sweep_rate = 200.0f;
140 config->double_buffering =
true;
141 config->continuous_sweep_mode =
true;
146 config->measured_point = 80U;
147 config->time_series_length = 1024U;
150 config->amplitude_threshold = 100.0f;
152 config->low_frequency_enhancement =
false;
154 config->frame_rate = 0.0f;
155 config->sweep_rate = 10000.0f;
158 config->double_buffering =
false;
159 config->continuous_sweep_mode =
false;
178 switch (
config->reported_displacement_mode)
200 switch (
config->inter_frame_idle_state)
216 switch (
config->inter_sweep_idle_state)
235 uint16_t sweeps_per_frame = 0U;
236 float sweep_rate = 0.0f;
240 bool status =
config != NULL;
255 handle->low_frequency_enhancement_enabled =
config->low_frequency_enhancement;
257 sweep_rate =
config->sweep_rate;
263 handle->subframe_length = sweeps_per_frame;
264 handle->rfft_output_length = (
handle->padded_time_series_length / 2U) + 1U;
265 handle->rfft_read_offset = 1U;
268 handle->continuous_data_acquisition =
config->continuous_sweep_mode;
270 handle->psd_to_radians_conversion_factor =
271 2.0f / (
handle->continuous_data_acquisition ? (float)
config->time_series_length : (
float)sweeps_per_frame);
277 handle->displacement_conversion_factor *= 2.0f;
284 status =
handle->sensor_config != NULL;
295 handle->time_series.write_idx = 0U;
296 handle->time_series.capacity =
config->time_series_length;
298 status =
handle->time_series.buffer != NULL;
304 status =
handle->frequencies != NULL;
315 status =
handle->double_buffer_filter_buffer != NULL;
321 status =
handle->zero_mean_time_series != NULL;
327 status =
handle->rfft_output != NULL;
333 status =
handle->lp_displacements != NULL;
339 status =
handle->threshold != NULL;
347 return status ?
handle : NULL;
352 return handle->sensor_config;
357 float *history_p = NULL;
358 bool status =
handle != NULL;
362 history_p =
handle->lp_displacements;
363 *num_elem =
handle->data_length;
366 return status ? history_p : NULL;
371 bool status =
handle != NULL;
375 *continuous_data_acquisition =
handle->continuous_data_acquisition;
385 if (
handle->sensor_config != NULL)
388 handle->sensor_config = NULL;
391 if (
handle->time_series.buffer != NULL)
394 handle->time_series.buffer = NULL;
397 if (
handle->frequencies != NULL)
400 handle->frequencies = NULL;
403 if (
handle->lp_displacements != NULL)
406 handle->lp_displacements = NULL;
409 if (
handle->double_buffer_filter_buffer != NULL)
412 handle->double_buffer_filter_buffer = NULL;
415 if (
handle->zero_mean_time_series != NULL)
418 handle->zero_mean_time_series = NULL;
421 if (
handle->rfft_output != NULL)
424 handle->rfft_output = NULL;
427 if (
handle->threshold != NULL)
444 result->max_sweep_amplitude = 0.0f;
445 result->max_displacement = FLT_MAX;
446 result->max_displacement_freq = FLT_MAX;
447 result->time_series_std = FLT_MAX;
454 for (uint16_t i = 0; i <
handle->subframe_length; i++)
458 if (
handle->low_frequency_enhancement_enabled)
468 result->max_sweep_amplitude = fmaxf(
result->max_sweep_amplitude, cabsf(point.
real + (point.
imag * I)));
471 if (
result->max_sweep_amplitude <
config->amplitude_threshold)
478 if (
handle->low_frequency_enhancement_enabled)
481 for (uint16_t frame_idx = 0U; frame_idx <
handle->subframe_length; frame_idx++)
483 uint16_t measure_src_idx = 2U * frame_idx;
484 uint16_t loopback_src_idx = (2U * frame_idx) + 1U;
485 uint16_t dst_idx = frame_idx;
490 complex
float measure_cf = (float)
measure.real + ((
float)
measure.imag * I);
491 complex
float loopback_cf = (float)loopback.
real + ((
float)loopback.
imag * I);
493 complex
float lb_norm = loopback_cf / cabsf(loopback_cf);
494 complex
float compensated = measure_cf * conjf(lb_norm);
496 proc_result->
frame[dst_idx].
real = (int16_t)(crealf(compensated) + 0.5f);
497 proc_result->
frame[dst_idx].
imag = (int16_t)(cimagf(compensated) + 0.5f);
506 if (
handle->continuous_data_acquisition)
511 for (uint16_t i = 0; i <
handle->subframe_length; i++)
514 float new_element = cargf(point.
real + (point.
imag * I));
527 for (uint16_t i = 0; i <
handle->data_length; i++)
529 float z_abs = cabsf(
handle->rfft_output[i +
handle->rfft_read_offset]);
530 float displacement = z_abs *
handle->displacement_conversion_factor;
534 handle->lp_displacements[i] =
handle->lp_displacements[i] *
config->lp_coeff + displacement * (1.0f -
config->lp_coeff);
538 handle->lp_displacements[i] = displacement;
544 for (uint16_t i = 0U; i <
config->time_series_length; i++)
561 float unwrapped = new_element;
577 return cb->
buffer[buffer_idx];
586 ACC_LOG_WARNING(
"**************************** [Warning] *********************************");
587 ACC_LOG_WARNING(
"** time_series_length should be power of 2 for efficient usage of FFT **");
588 ACC_LOG_WARNING(
"************************************************************************");
591 if (
config->time_series_length < 2U)
597 if (
config->sweep_rate == 0.0f)
603 if (
config->continuous_sweep_mode && !
config->double_buffering)
605 ACC_LOG_ERROR(
"double buffering needs to be activated to achieve sufficient sweep rate when using continuous sweep mode");
614 bool status =
config != NULL;
645 if (
config->low_frequency_enhancement)
671 float sample_spacing = 1.0f / sweep_rate;
685 float max_displacement = 0.0f;
686 uint16_t max_displacement_idx = 0;
688 result->max_displacement = 0.0f;
690 for (uint16_t i = 1U; i <
handle->data_length; i++)
694 max_displacement =
result->max_displacement;
696 result->max_displacement = fmaxf(
result->max_displacement,
handle->lp_displacements[i]);
698 if (
result->max_displacement > max_displacement)
700 max_displacement_idx = i;
705 if (max_displacement_idx > 0)
707 result->max_displacement_freq =
handle->frequencies[max_displacement_idx +
handle->rfft_read_offset];
711 result->max_displacement = FLT_MAX;
719 for (uint16_t i = 0; i <
handle->time_series.capacity; i++)
721 mean +=
handle->time_series.buffer[i];
724 mean /= (float)
handle->time_series.capacity;
726 for (uint16_t i = 0; i <
handle->time_series.capacity; i++)
731 return handle->zero_mean_time_series;
736 for (uint16_t i = 0; i <
handle->data_length; i++)
752 const float head_slope_multiplier = 2.0f;
753 const uint16_t head_slope_calculation_width = 2U;
754 const uint16_t tail_mean_calculation_width = 10U;
755 const uint16_t tail_mean_calculation_start =
handle->data_length -
CFAR_MARGIN - tail_mean_calculation_width;
764 float head_mean_slope = 0.0f;
766 for (uint16_t i = 0; i < head_slope_calculation_width; i++)
769 head_mean_slope +=
handle->threshold[pos + 1U] -
handle->threshold[pos];
772 head_mean_slope /= (float)head_slope_calculation_width;
773 head_mean_slope *= head_slope_multiplier;
779 float tail_mean = 0.0f;
781 for (int16_t i = 0; i < tail_mean_calculation_width; i++)
783 tail_mean +=
handle->threshold[tail_mean_calculation_start + i];
786 tail_mean /= (float)tail_mean_calculation_width;
794 handle->threshold[i] = ((float)i -
CFAR_MARGIN) * head_mean_slope + head_base_offset;
795 handle->threshold[tail_offset + i] = tail_mean;
801 const uint16_t N =
config->time_series_length;
804 uint16_t length = 1U;
815 handle->padded_time_series_length = length;
816 handle->rfft_length_shift = shift;
void * acc_integration_mem_calloc(size_t nmemb, size_t size)
Allocate dynamic memory.
void acc_config_inter_frame_idle_state_set(acc_config_t *config, acc_config_idle_state_t idle_state)
Set inter frame idle state.
void acc_algorithm_rfft(const float *data, uint16_t data_length, uint16_t length_shift, float complex *output)
1D Fast Fourier Transform for real input
acc_config_t * sensor_config
#define ACC_LOG_WARNING(...)
static bool measure(acc_surface_velocity_handle_t *handle)
Result provided by the processing module.
void acc_algorithm_unwrap(float *data, uint16_t data_length)
Unwraps a signal by changing elements which have an absolute difference from their predecessor of mor...
#define ACC_LOG_INFO(...)
#define CFAR_WINDOW_LENGTH
float acc_algorithm_stddev_f32(const float *data, uint16_t length)
Calculate standard deviation.
static void setup_sample_frequencies(acc_vibration_handle_t *handle, float sweep_rate)
Data type for interger-based representation of complex numbers.
void acc_algorithm_double_buffering_frame_filter(acc_int16_complex_t *frame, const uint16_t sweeps_per_frame, const uint16_t num_points, int32_t *work_buffer)
Double buffering frame filter.
static bool validate_config(const acc_vibration_config_t *config)
bool continuous_data_acquisition
void acc_config_sweeps_per_frame_set(acc_config_t *config, uint16_t sweeps)
Set sweeps per frame.
void acc_config_destroy(acc_config_t *config)
Destroy a configuration freeing any resources allocated.
uint16_t rfft_read_offset
static float * get_zero_mean_time_series(acc_vibration_handle_t *handle)
@ ACC_CONFIG_IDLE_STATE_DEEP_SLEEP
void acc_config_inter_sweep_idle_state_set(acc_config_t *config, acc_config_idle_state_t idle_state)
Set inter sweep idle state.
Vibration config container.
acc_config_t * acc_config_create(void)
Create a configuration.
void acc_vibration_config_log(const acc_vibration_config_t *config)
#define ACC_LOG_ERROR(...)
acc_vibration_handle_t * acc_vibration_handle_create(const acc_vibration_config_t *config)
void acc_config_subsweep_phase_enhancement_set(acc_config_t *config, bool enable, uint8_t index)
Set the phase enhancement enabled configuration.
void acc_config_frame_rate_set(acc_config_t *config, float frame_rate)
Set the frame rate.
void * acc_integration_mem_alloc(size_t size)
Allocate dynamic memory.
uint16_t sweeps_per_frame
uint16_t rfft_output_length
void acc_algorithm_rfftfreq(uint16_t n, float d, float *freqs)
Calculate the real Fast Fourier Transform sample frequencies.
void acc_config_double_buffering_set(acc_config_t *config, bool enable)
Enable or disable double buffering.
acc_config_prf_t
Pulse Repetition Frequency.
float psd_to_radians_conversion_factor
uint16_t rfft_length_shift
bool low_frequency_enhancement_enabled
@ ACC_CONFIG_IDLE_STATE_READY
struct acc_config acc_config_t
@ ACC_VIBRATION_PRESET_LOW_FREQUENCY
circular_float_buffer_t time_series
@ ACC_VIBRATION_REPORT_DISPLACEMENT_AS_PEAK2PEAK
@ ACC_VIBRATION_REPORT_DISPLACEMENT_AS_AMPLITUDE
void acc_config_num_subsweeps_set(acc_config_t *config, uint8_t num_subsweeps)
Set the number of subsweeps to use.
void acc_vibration_handle_destroy(acc_vibration_handle_t *handle)
void acc_config_subsweep_start_point_set(acc_config_t *config, int32_t start_point, uint8_t index)
Set the starting point of the sweep.
void acc_config_sweep_rate_set(acc_config_t *config, float sweep_rate)
Set the sweep rate.
void acc_config_subsweep_profile_set(acc_config_t *config, acc_config_profile_t profile, uint8_t index)
Set a profile.
const float * acc_vibration_handle_displacement_history_get(acc_vibration_handle_t *handle, uint16_t *num_elem)
#define ACC_APPROX_BASE_STEP_LENGTH_M
Approximate minimum step length for a sensor measurement in meters.
Vibration processing result.
acc_config_prf_t acc_algorithm_select_prf(int16_t breakpoint, acc_config_profile_t profile, float base_step_length)
Select a suitable PRF given a breakpoint and profile.
acc_int16_complex_t * frame
static bool translate_config(const acc_vibration_config_t *config, acc_config_t *sensor_config)
void acc_vibration_process(acc_processing_result_t *proc_result, acc_vibration_handle_t *handle, acc_vibration_config_t *config, acc_vibration_result_t *result)
static void circular_float_buffer_write_angle(circular_float_buffer_t *cb, float new_element)
Write an angle (in rads) to the circular buffer. The angle will be "unwrapped" before write.
const acc_config_t * acc_vibration_handle_sensor_config_get(acc_vibration_handle_t *handle)
static float circular_float_buffer_get(const circular_float_buffer_t *cb, uint16_t chronological_idx)
Get an element of the circular buffer given its "age". A chronological index of 0 returns the oldest ...
int32_t * double_buffer_filter_buffer
#define ACC_LOG_FLOAT_TO_INTEGER(a)
bool acc_vibration_handle_continuous_data_acquisition_get(acc_vibration_handle_t *handle, bool *continuous_data_acquisition)
static void calculate_threshold(acc_vibration_handle_t *handle, acc_vibration_config_t *config)
void acc_vibration_preset_set(acc_vibration_config_t *config, acc_vibration_preset_t preset)
float acc_algorithm_calculate_cfar(const float *data, uint16_t data_length, uint16_t window_length, uint16_t half_guard_length, float sensitivity, uint16_t idx)
Calculate CFAR threshold.
void acc_config_continuous_sweep_mode_set(acc_config_t *config, bool enabled)
Set continuous sweep mode.
acc_vibration_preset_t
Vibration presets.
static void update_vibration_result(acc_vibration_handle_t *handle, acc_vibration_config_t *config, acc_vibration_result_t *result)
void acc_config_subsweep_receiver_gain_set(acc_config_t *config, uint8_t gain, uint8_t index)
Set receiver gain setting.
complex float * rfft_output
@ ACC_VIBRATION_PRESET_HIGH_FREQUENCY
void acc_integration_mem_free(void *ptr)
Free dynamic memory.
float displacement_conversion_factor
void acc_config_subsweep_enable_loopback_set(acc_config_t *config, bool enable, uint8_t index)
Set the loopback enabled configuration.
void acc_config_subsweep_hwaas_set(acc_config_t *config, uint16_t hwaas, uint8_t index)
Set the hardware accelerated average samples (HWAAS)
void acc_config_subsweep_step_length_set(acc_config_t *config, uint16_t step_length, uint8_t index)
Set the step length in a sweep.
@ ACC_CONFIG_IDLE_STATE_SLEEP
float * zero_mean_time_series
void acc_config_subsweep_num_points_set(acc_config_t *config, uint16_t num_points, uint8_t index)
Set the number of data points to measure.
#define CFAR_HALF_GUARD_LENGTH
uint16_t padded_time_series_length
#define PRIfloat
Specifier for printing float type using integers.
void acc_config_subsweep_enable_tx_set(acc_config_t *config, bool enable, uint8_t index)
Enable or disable the transmitter.
static void setup_rfft_bounds(acc_vibration_handle_t *handle, const acc_vibration_config_t *config)
float threshold_sensitivity
#define IS_POWER_OF_TWO(x)
void acc_config_subsweep_prf_set(acc_config_t *config, acc_config_prf_t prf, uint8_t index)
Set Pulse Repetition Frequency.
#define RADIANS_TO_DISPLACEMENT_FACTOR