Go to the documentation of this file.
18 #define B_STATIC_LENGTH (3U)
19 #define A_STATIC_LENGTH (2U)
20 #define B_ANGLE_LENGTH (5U)
21 #define A_ANGLE_LENGTH (4U)
108 if (
config->presence_config == NULL)
114 config->time_series_length_s = 20U;
115 config->lowest_breathing_rate = 6U;
116 config->highest_breathing_rate = 60U;
117 config->num_dists_to_analyze = 3U;
118 config->use_presence_processor =
true;
119 config->distance_determination_duration_s = 5U;
147 if (
config->presence_config != NULL)
185 handle->lowest_freq = (float)
config->lowest_breathing_rate / 60.0f;
186 handle->highest_freq = (
float)
config->highest_breathing_rate / 60.0f;
187 handle->use_presence_processor =
config->use_presence_processor;
188 handle->time_series_length_s =
config->time_series_length_s;
189 handle->distance_determination_count =
config->distance_determination_duration_s *
handle->frame_rate;
190 handle->num_points_to_analyze_half_width =
config->num_dists_to_analyze / 2U;
191 handle->num_points_to_analyze =
config->use_presence_processor ?
handle->num_points_to_analyze_half_width * 2U + 1U :
handle->num_points;
194 handle->padded_time_series_length_shift = 0U;
195 handle->padded_time_series_length = 1U <<
handle->padded_time_series_length_shift;
197 while (
handle->padded_time_series_length <
handle->time_series_length)
199 handle->padded_time_series_length_shift++;
200 handle->padded_time_series_length = 1U <<
handle->padded_time_series_length_shift;
203 handle->rfft_output_length = (
handle->padded_time_series_length / 2U) + 1U;
204 handle->distance_determination_counter = 0U;
205 handle->presence_init =
false;
206 handle->presence_distance = 0.0f;
207 handle->base_presence_dist =
false;
208 handle->base_presence_distance = 0.0f;
213 handle->initialized =
false;
228 handle->filt_sparse_iq_buffer =
236 handle->breathing_motion_buffer =
239 handle->windowed_breathing_motion_buffer =
244 bool status =
handle->mean_sweep != NULL &&
handle->filt_sparse_iq != NULL &&
handle->sparse_iq_buffer != NULL &&
245 handle->filt_sparse_iq_buffer != NULL &&
handle->angle != NULL &&
handle->prev_angle != NULL &&
handle->lp_filt_ampl != NULL &&
246 handle->unwrapped_angle != NULL &&
handle->angle_buffer != NULL &&
handle->filt_angle_buffer != NULL &&
247 handle->breathing_motion_buffer != NULL &&
handle->hamming_window != NULL &&
handle->windowed_breathing_motion_buffer != NULL &&
248 handle->rfft_output != NULL &&
handle->weighted_psd != NULL;
274 if (
handle->mean_sweep != NULL)
279 if (
handle->filt_sparse_iq != NULL)
284 if (
handle->sparse_iq_buffer != NULL)
289 if (
handle->filt_sparse_iq_buffer != NULL)
294 if (
handle->angle != NULL)
299 if (
handle->prev_angle != NULL)
304 if (
handle->lp_filt_ampl != NULL)
309 if (
handle->unwrapped_angle != NULL)
314 if (
handle->angle_buffer != NULL)
319 if (
handle->filt_angle_buffer != NULL)
324 if (
handle->breathing_motion_buffer != NULL)
329 if (
handle->hamming_window != NULL)
334 if (
handle->windowed_breathing_motion_buffer != NULL)
339 if (
handle->rfft_output != NULL)
344 if (
handle->weighted_psd != NULL)
376 handle->base_presence_dist =
false;
377 handle->base_presence_distance = 0.0f;
405 if (frame_rate == 0.0f)
407 printf(
"Frame rate must be set, i.e. > 0.0\n");
411 if (
config->lowest_breathing_rate >=
config->highest_breathing_rate)
413 printf(
"Lowest breathing rate must be lower than highest breathing rate\n");
417 if (
config->num_dists_to_analyze < 1U)
419 printf(
"Number of distances to analyze must be higher than 1");
436 else if (!
handle->base_presence_dist &&
handle->use_presence_processor)
440 else if (!
handle->use_presence_processor ||
handle->distance_determination_count <=
handle->distance_determination_counter)
452 if (!
handle->presence_init)
454 handle->presence_init =
true;
460 if (
handle->base_presence_dist &&
handle->presence_distance_threshold < fabsf(
handle->base_presence_distance -
handle->presence_distance))
462 handle->base_presence_dist =
false;
463 handle->base_presence_distance = 0.0f;
469 handle->start_point = start_point;
470 handle->end_point = end_point;
471 handle->num_points_to_analyze = end_point - start_point;
476 handle->initialized =
false;
480 memset(
handle->prev_angle, 0,
handle->num_points_to_analyze *
sizeof(*
handle->prev_angle));
481 memset(
handle->lp_filt_ampl, 0,
handle->num_points_to_analyze *
sizeof(*
handle->lp_filt_ampl));
482 memset(
handle->unwrapped_angle, 0,
handle->num_points_to_analyze *
sizeof(*
handle->unwrapped_angle));
485 memset(
handle->breathing_motion_buffer, 0,
handle->time_series_length *
handle->num_points_to_analyze *
sizeof(*
handle->breathing_motion_buffer));
494 result->result_ready =
false;
496 switch (
handle->app_state)
504 handle->base_presence_dist =
false;
505 handle->base_presence_distance = 0.0f;
510 handle->distance_determination_counter = 0U;
514 handle->distance_determination_counter++;
515 handle->base_presence_dist =
true;
516 handle->base_presence_distance =
handle->presence_distance;
526 if (
handle->use_presence_processor)
528 uint16_t center_idx = (uint16_t)(((
handle->base_presence_distance -
handle->start_m) /
handle->step_length_m) + 0.5f);
529 start_p = center_idx >=
handle->num_points_to_analyze_half_width
530 ? (uint16_t)(center_idx -
handle->num_points_to_analyze_half_width)
532 end_p = (center_idx +
handle->num_points_to_analyze_half_width + 1U) <=
handle->num_points
533 ? (center_idx +
handle->num_points_to_analyze_half_width + 1U)
539 end_p =
handle->num_points;
561 handle->num_points_to_analyze,
566 handle->filt_sparse_iq_buffer,
568 handle->num_points_to_analyze,
572 handle->num_points_to_analyze,
574 handle->num_points_to_analyze);
578 handle->num_points_to_analyze,
582 for (uint16_t i = 0U; i <
handle->num_points_to_analyze; i++)
590 for (uint16_t i = 0U; i <
handle->num_points_to_analyze; i++)
599 for (uint16_t i = 0U; i <
handle->num_points_to_analyze; i++)
604 for (uint16_t i = 0U; i <
handle->num_points_to_analyze; i++)
606 float angle_diff =
handle->angle[i] -
handle->prev_angle[i];
609 if ((
float)
M_PI < angle_diff)
611 angle_diff -= 2.0f * (float)
M_PI;
613 else if (angle_diff < -(
float)
M_PI)
615 angle_diff += 2.0f * (float)
M_PI;
618 handle->unwrapped_angle[i] += angle_diff;
624 handle->filt_angle_buffer,
626 handle->num_points_to_analyze,
630 handle->num_points_to_analyze,
632 handle->num_points_to_analyze);
637 handle->time_series_length,
638 handle->num_points_to_analyze,
644 handle->initialized =
true;
657 float lp_filt_ampl_sum = 0U;
659 for (uint16_t r = 0U; r <
handle->time_series_length; r++)
661 for (uint16_t c = 0U; c <
handle->num_points_to_analyze; c++)
663 handle->windowed_breathing_motion_buffer[r *
handle->num_points_to_analyze + c] =
664 handle->breathing_motion_buffer[r *
handle->num_points_to_analyze + c] *
handle->hamming_window[r];
665 lp_filt_ampl_sum +=
handle->lp_filt_ampl[c];
670 handle->time_series_length,
671 handle->num_points_to_analyze,
672 handle->padded_time_series_length_shift,
676 for (uint16_t r = 0U; r <
handle->rfft_output_length; r++)
680 for (uint16_t c = 0U; c <
handle->num_points_to_analyze; c++)
682 sum_psd += cabsf(
handle->rfft_output[r *
handle->num_points_to_analyze + c]) *
handle->lp_filt_ampl[c];
685 handle->weighted_psd[r] = sum_psd / lp_filt_ampl_sum;
693 result->result_ready =
true;
694 result->breathing_rate = freq * 60.0f;
@ REF_APP_BREATHING_APP_STATE_ESTIMATE_BREATHING_RATE
void * acc_integration_mem_calloc(size_t nmemb, size_t size)
Allocate dynamic memory.
void acc_algorithm_apply_filter_f32(const float *a, const float *filt_data, uint16_t filt_rows, uint16_t filt_cols, const float *b, const float *data, uint16_t data_rows, uint16_t data_cols, float *output, uint16_t output_length)
Apply filter coefficients to filtered data matrix and data matrix.
void acc_detector_presence_config_sweeps_per_frame_set(acc_detector_presence_config_t *presence_config, uint16_t sweeps_per_frame)
Set the number of sweeps per frame.
float acc_algorithm_exp_smoothing_coefficient(float fs, float tc)
Calculate exponential smoothing coefficient.
static bool process_breathing(ref_app_breathing_handle_t *handle, acc_int16_complex_t *frame, ref_app_breathing_result_t *result)
@ REF_APP_BREATHING_APP_STATE_INIT
void acc_detector_presence_destroy(acc_detector_presence_handle_t *presence_handle)
Destroy a presence detector identified with the provided handle.
void acc_detector_presence_config_hwaas_set(acc_detector_presence_config_t *presence_config, uint16_t hwaas)
Set the hardware accelerated average samples (HWAAS)
static bool reinit_breathing(ref_app_breathing_handle_t *handle, uint16_t start_point, uint16_t end_point)
acc_cal_result_t sensor_cal_result
float complex * filt_sparse_iq_buffer
ref_app_breathing_app_state_t app_state
ref_app_breathing_config_t * ref_app_breathing_config_create(void)
Create a configuration for the ref app breathing.
void acc_detector_presence_config_auto_profile_set(acc_detector_presence_config_t *presence_config, bool enable)
Enable automatic selection of profile based on start point of measurement.
static float presence_distance
Data type for interger-based representation of complex numbers.
uint16_t padded_time_series_length
float acc_algorithm_interpolate_peaks_equidistant(const float *y, float x_start, float x_delta, uint16_t peak_idx)
Interpolate equidistant peaks.
void acc_algorithm_roll_and_push_matrix_f32(float *data, uint16_t rows, uint16_t cols, const float *column, bool pos_shift)
Roll row elements and push a new column.
The result from a completed calibration.
void acc_detector_presence_config_frame_rate_set(acc_detector_presence_config_t *presence_config, float frame_rate)
Set the frame rate.
static void update_presence_distance(ref_app_breathing_handle_t *handle, float presence_distance)
Breathing application results container.
float * windowed_breathing_motion_buffer
float complex * sparse_iq_buffer
acc_detector_presence_handle_t * presence_handle
bool ref_app_breathing_prepare(ref_app_breathing_handle_t *handle, ref_app_breathing_config_t *config, acc_sensor_t *sensor, const acc_cal_result_t *sensor_cal_result, void *buffer, uint32_t buffer_size)
Prepare the application to do a measurement.
uint16_t distance_determination_count
bool acc_detector_presence_get_buffer_size(const acc_detector_presence_handle_t *presence_handle, uint32_t *buffer_size)
Get the buffer size needed for the provided presence detector handle.
uint16_t rfft_output_length
float intra_detection_threshold
float presence_distance_threshold
@ REF_APP_BREATHING_APP_STATE_INTRA_PRESENCE
uint16_t distance_determination_counter
void acc_detector_presence_config_intra_detection_threshold_set(acc_detector_presence_config_t *presence_config, float intra_detection_threshold)
Set the detection threshold for the intra-frame presence detection.
static void determine_state(ref_app_breathing_handle_t *handle, acc_detector_presence_result_t *presence_result)
void * acc_integration_mem_alloc(size_t size)
Allocate dynamic memory.
uint16_t time_series_length
uint16_t sweeps_per_frame
Presence detector results container.
void acc_detector_presence_config_inter_frame_presence_timeout_set(acc_detector_presence_config_t *presence_config, uint16_t inter_frame_presence_timeout)
Set the inter-frame presence timeout in seconds.
void acc_algorithm_butter_lowpass(float freq, float fs, float *b, float *a)
Design a 2nd order digital Butterworth lowpass filter.
float * breathing_motion_buffer
uint16_t acc_algorithm_argmax(const float *data, uint16_t data_length)
Find index of largest element in the array.
float * filt_angle_buffer
uint16_t time_series_length_s
void acc_detector_presence_config_destroy(acc_detector_presence_config_t *presence_config)
Destroy a presence detector configuration.
float complex * rfft_output
void acc_algorithm_rfft_matrix(const float *data, uint16_t rows, uint16_t cols, uint16_t length_shift, float complex *output, uint16_t axis)
1D Fast Fourier Transform for real input matrix
void acc_detector_presence_config_end_set(acc_detector_presence_config_t *presence_config, float end)
Set the end point of measurement interval in meters.
void acc_detector_presence_config_intra_output_time_const_set(acc_detector_presence_config_t *presence_config, float intra_output_time_const)
Set the time constant for the output in the intra-frame part.
float base_presence_distance
float intra_presence_score
static bool validate_config(ref_app_breathing_config_t *config)
@ REF_APP_BREATHING_APP_STATE_NO_PRESENCE
bool acc_detector_presence_process(acc_detector_presence_handle_t *presence_handle, void *buffer, acc_detector_presence_result_t *result)
Process the data according to the configuration used in acc_detector_presence_config_create.
void acc_detector_presence_config_inter_output_time_const_set(acc_detector_presence_config_t *presence_config, float inter_output_time_const)
Set the time constant for the output in the inter-frame part.
bool ref_app_breathing_get_buffer_size(ref_app_breathing_handle_t *handle, uint32_t *buffer_size)
Get the buffer size needed for the provided ref app breathing handle.
acc_detector_presence_handle_t * presence_handle
void acc_algorithm_mean_sweep(const acc_int16_complex_t *frame, uint16_t num_points, uint16_t sweeps_per_frame, uint16_t start_point, uint16_t end_point, float complex *sweep)
Calculate mean sweep of a frame from start_point to end_point.
bool acc_detector_presence_prepare(const acc_detector_presence_handle_t *presence_handle, acc_detector_presence_config_t *presence_config, acc_sensor_t *sensor, const acc_cal_result_t *cal_result, void *buffer, uint32_t buffer_size)
Prepare the detector to do a measurement.
float complex * mean_sweep
float acc_algorithm_fftfreq_delta(uint16_t n, float d)
Calculate delta between frequency bins in rfft.
void ref_app_breathing_destroy(ref_app_breathing_handle_t *handle)
Destroy a handle for the ref app breathing.
static bool perform_action_based_on_state(ref_app_breathing_handle_t *handle, acc_int16_complex_t *frame, ref_app_breathing_result_t *result)
struct acc_detector_presence_config acc_detector_presence_config_t
uint16_t acc_detector_presence_config_sweeps_per_frame_get(const acc_detector_presence_config_t *presence_config)
Get the number of sweeps per frame.
@ REF_APP_BREATHING_APP_STATE_DETERMINE_DISTANCE
uint16_t num_points_to_analyze_half_width
ref_app_breathing_app_state_t prev_app_state
float acc_detector_presence_config_frame_rate_get(const acc_detector_presence_config_t *presence_config)
Get the frame rate.
void acc_detector_presence_config_profile_set(acc_detector_presence_config_t *presence_config, acc_config_profile_t profile)
Set a profile.
void acc_algorithm_roll_and_push_matrix_f32_complex(float complex *data, uint16_t rows, uint16_t cols, const float complex *column, bool pos_shift)
Roll row elements and push a new column.
float acc_algorithm_get_fwhm(acc_config_profile_t profile)
Get the envelope Full Width Half Maximum in meters given a profile.
void acc_integration_mem_free(void *ptr)
Free dynamic memory.
void ref_app_breathing_config_destroy(ref_app_breathing_config_t *config)
Destory a configuration for the ref app breathing.
ref_app_breathing_handle_t * ref_app_breathing_create(ref_app_breathing_config_t *config)
Create a handle for the ref app breathing.
uint16_t num_points_to_analyze
acc_detector_presence_handle_t * acc_detector_presence_create(acc_detector_presence_config_t *presence_config, acc_detector_presence_metadata_t *metadata)
Create a presence detector with the provided configuration.
float acc_detector_presence_config_intra_detection_threshold_get(const acc_detector_presence_config_t *presence_config)
Get the detection threshold for the intra-frame presence detection.
acc_config_profile_t acc_detector_presence_config_profile_get(const acc_detector_presence_config_t *presence_config)
Get the currently set profile.
void acc_algorithm_butter_bandpass(float min_freq, float max_freq, float fs, float *b, float *a)
Design a 2nd order digital Butterworth bandpass filter.
struct acc_detector_presence_handle acc_detector_presence_handle_t
acc_detector_presence_config_t * acc_detector_presence_config_create(void)
Create a configuration for a presence detector.
Breathing application config container.
uint16_t use_presence_processor
bool ref_app_breathing_process(ref_app_breathing_handle_t *handle, void *buffer, ref_app_breathing_result_t *result)
Process the data.
void acc_detector_presence_config_start_set(acc_detector_presence_config_t *presence_config, float start)
Set the start point of measurement interval in meters.
uint16_t padded_time_series_length_shift
float complex * filt_sparse_iq
void acc_algorithm_apply_filter_f32_complex(const float *a, const float complex *filt_data, uint16_t filt_rows, uint16_t filt_cols, const float *b, const float complex *data, uint16_t data_rows, uint16_t data_cols, float complex *output, uint16_t output_length)
Apply filter coefficients to filtered data matrix and data matrix.
void acc_detector_presence_config_auto_step_length_set(acc_detector_presence_config_t *presence_config, bool enable)
Enable automatic selection of step length based on the profile.
void acc_algorithm_hamming(uint16_t n, float *window)
Calculate hamming window for a specified number of points.
struct acc_sensor acc_sensor_t
void acc_detector_presence_config_step_length_set(acc_detector_presence_config_t *presence_config, uint16_t step_length)
Set the step length in points.
void acc_detector_presence_config_automatic_subsweeps_set(acc_detector_presence_config_t *presence_config, bool automatic_subsweeps)
Set if automatic subsweeps should be used.
ref_app_breathing_app_state_t
State of the application.
void acc_detector_presence_config_inter_frame_fast_cutoff_set(acc_detector_presence_config_t *presence_config, float inter_frame_fast_cutoff)
Set the cutoff frequency of the low pass filter for the fast filtered absolute sweep mean.