example_waste_level.c
Go to the documentation of this file.
1 // Copyright (c) Acconeer AB, 2024-2025
2 // All rights reserved
3 // This file is subject to the terms and conditions defined in the file
4 // 'LICENSES/license_acconeer.txt', (BSD 3-Clause License) which is part
5 // of this source code package.
6 
7 #include <complex.h>
8 #include <inttypes.h>
9 #include <math.h>
10 #include <stdbool.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include "acc_algorithm.h"
17 #include "acc_config.h"
18 #include "acc_config_subsweep.h"
19 #include "acc_definitions_common.h"
20 #include "acc_integration.h"
21 #include "acc_integration_log.h"
22 #include "acc_processing.h"
23 #include "example_waste_level.h"
24 
25 #define MODULE "example_waste_level"
26 
28 {
29  /** State. Affects output between frames */
30  struct
31  {
32  /** Ring buffer for distance estimations. Has capacity processing_config.median_filter_len */
34 
35  /** How many valid elements there are in distance_history_points (starting at 0) */
37 
38  /** Write index for the distance_history_points */
40  } state;
41 
42  /** Float scratch. Has length == max(sweeps_per_frame, median_filter_len) */
43  float *scratch;
44 };
45 
46 /**
47  * @brief Validate an app_config (processing & sensor config).
48  *
49  * @param[in] app_config The app config
50  * @return True if config was valid, false otherwise.
51  */
52 static bool validate_app_config(const waste_level_app_config_t *app_config);
53 
54 /**
55  * @brief Helper function for validation
56  *
57  * @param[in] sensor_config The sensor config
58  * @return True if all subsweeps' start_points are strictly increasing, false otherwise
59  */
60 static bool subsweep_start_points_strictly_increases(const acc_config_t *sensor_config);
61 
62 /**
63  * @brief Helper function for validation
64  *
65  * @param[in] sensor_config The sensor config
66  * @param[out] offending_subsweep The subsweep index of a subsweep that overlaps into
67  * the subsweep after it
68  * @return True if sensor config has overlapping (in distance) subsweeps, false otherwise
69  */
70 static bool has_overlapping_subsweeps(const acc_config_t *sensor_config, uint8_t *offending_subsweep);
71 
72 /**
73  * @brief Helper function for validation
74  *
75  * @param[in] sensor_config The sensor config
76  * @return True if start_point for subsweep 0 is invalid
77  */
78 static bool is_invalid_start_point(const acc_config_t *sensor_config);
79 
80 /**
81  * @brief Helper function for validation
82  *
83  * @param[in] sensor_config The sensor config
84  * @param[in] distance_m The distance to check
85  * @return True if distance_m is outside the interval measured by sensor_config, false otherwise
86  */
87 static bool is_outside_measuring_interval(const acc_config_t *sensor_config, float distance_m);
88 
89 /**
90  * @brief Helper function for validation
91  *
92  * @param[in] sensor_config The sensor config
93  * @param[in] subsweep_idx The distance to check
94  * @return The approximate distance to the first point measured in subsweep with index subsweep_idx
95  */
96 static float subsweep_approx_start_m(const acc_config_t *sensor_config, uint8_t subsweep_idx);
97 
98 /**
99  * @brief Helper function for validation
100  *
101  * @param[in] sensor_config The sensor config
102  * @param[in] subsweep_idx The distance to check
103  * @return The approximate distance to the last point measured in subsweep with index subsweep_idx
104  */
105 static float subsweep_approx_end_m(const acc_config_t *sensor_config, uint8_t subsweep_idx);
106 
107 /**
108  * @brief Calculate a point's corresponding distance in meters
109  *
110  * @param[in] sensor_config The sensor config
111  * @param[in] metadata The processing metadata
112  * @param[in] point_idx The index in a sweep of the point to get distance for
113  * @return The distance of point at point_idx
114  */
115 static float point_in_sweep_to_distance_m(const acc_config_t *sensor_config, const acc_processing_metadata_t *metadata, uint16_t point_idx);
116 
117 /**
118  * @brief Write next value into a ring buffer
119  *
120  * @param[in, out] buffer The circular buffer
121  * @param[in] capacity The allocated number of elements of buffer
122  * @param[in, out] length The buffer length (number of valid elements)
123  * @param[in, out] write_idx The next index in buffer to write to
124  * @param[in] elem The new element to write
125  */
126 static void write_to_ring_buffer(float *buffer, uint16_t capacity, uint16_t *length, uint16_t *write_idx, float elem);
127 
128 /**
129  * @brief Copy non-NaN floats between buffers
130  *
131  * @param[in] in Source buffer of floats which can contain NaNs
132  * @param[out] out The destination buffer. Will not contain NaNs
133  * @param[in] length The allocated size of in & out
134  * @return The number of elements written to out
135  */
136 static uint16_t copy_non_nan_floats(const float *in, float *out, uint16_t length);
137 
138 /**
139  * @brief Populate a waste level result with its human-readable entries
140  *
141  * @param[in] filtered_distance The median filtered distance
142  * @param[in] processing_config The waste processing config
143  * @param[out] result The waste result
144  */
145 static void set_level_numbers(float filtered_distance, const waste_level_processing_config_t *processing_config, waste_level_result_t *result);
146 
148 {
149  waste_level_app_config_t *app_config = acc_integration_mem_alloc(sizeof(*app_config));
150  bool status = app_config != NULL;
151 
152  if (status)
153  {
154  app_config->sensor_config = acc_config_create();
155  status = app_config->sensor_config != NULL;
156  }
157 
158  if (status)
159  {
161  }
162 
163  return app_config;
164 }
165 
167 {
168  if (app_config != NULL)
169  {
170  if (app_config->sensor_config != NULL)
171  {
172  acc_config_destroy(app_config->sensor_config);
173  }
174 
175  acc_integration_mem_free(app_config);
176  }
177 }
178 
180 {
181  bool status = app_config != NULL;
182 
183  if (status)
184  {
185  switch (preset)
186  {
188  app_config->processing_config.bin_start_m = 0.15f;
189  app_config->processing_config.bin_end_m = 1.00f;
190  app_config->processing_config.threshold = 0.30f;
191  app_config->processing_config.distance_sequence_len = 4U;
192  app_config->processing_config.median_filter_len = 5U;
193 
194  acc_config_frame_rate_set(app_config->sensor_config, 5.0f);
197 
202  acc_config_subsweep_hwaas_set(app_config->sensor_config, 4U, 0U);
203 
204  acc_config_subsweep_start_point_set(app_config->sensor_config, 150U, 1U);
208  acc_config_subsweep_hwaas_set(app_config->sensor_config, 8U, 1U);
209  break;
210  default:
212  break;
213  }
214  }
215 }
216 
218 {
219  uint16_t sweeps_per_frame = 0U;
220  uint16_t median_filter_len = 0U;
222 
223  bool status = validate_app_config(app_config);
224 
225  if (status)
226  {
228  status = handle != NULL;
229  }
230 
231  if (status)
232  {
233  sweeps_per_frame = acc_config_sweeps_per_frame_get(app_config->sensor_config);
234  median_filter_len = app_config->processing_config.median_filter_len;
235 
236  handle->state.distance_history_len = 0U;
237  handle->state.distance_history_write_idx = 0U;
238  }
239 
240  if (status)
241  {
242  uint16_t num_elem = sweeps_per_frame > median_filter_len ? sweeps_per_frame : median_filter_len;
243  handle->scratch = (float *)acc_integration_mem_alloc(num_elem * sizeof(*handle->scratch));
244  status = handle->scratch != NULL;
245  }
246 
247  if (status)
248  {
249  handle->state.distance_history_points =
250  (float *)acc_integration_mem_alloc(median_filter_len * sizeof(*handle->state.distance_history_points));
251  status = handle->state.distance_history_points != NULL;
252  }
253 
254  return handle;
255 }
256 
258 {
259  if (handle != NULL)
260  {
261  if (handle->state.distance_history_points != NULL)
262  {
263  acc_integration_mem_free(handle->state.distance_history_points);
264  }
265 
266  if (handle->scratch != NULL)
267  {
269  }
270 
272  }
273 }
274 
276  const waste_level_app_config_t *app_config,
277  const acc_processing_metadata_t *metadata,
278  const acc_int16_complex_t *frame,
279  waste_level_result_t *waste_level_result)
280 {
281  if (handle != NULL && app_config != NULL && metadata != NULL && frame != NULL && waste_level_result != NULL)
282  {
283  uint16_t sweep_length = metadata->sweep_data_length;
284  uint16_t sweeps_per_frame = acc_config_sweeps_per_frame_get(app_config->sensor_config);
285  uint16_t distance_seq_len = app_config->processing_config.distance_sequence_len;
286  uint16_t median_filter_len = app_config->processing_config.median_filter_len;
287  float threshold_squared = app_config->processing_config.threshold * app_config->processing_config.threshold;
288 
289  uint16_t phase_vars_under_threshold = 0U;
290 
291  bool point_of_waste_found = false;
292  uint16_t point_of_waste = 0U;
293 
294  for (uint16_t point_idx = 0U; point_idx < sweep_length; point_idx++)
295  {
296  float complex column_sum;
297 
298  acc_algorithm_sum_sweep(frame, sweep_length, sweeps_per_frame, point_idx, point_idx + 1U, &column_sum);
299 
300  acc_algorithm_conj_f32(&column_sum, 1U);
301 
302  for (uint16_t sweep_idx = 0U; sweep_idx < sweeps_per_frame; sweep_idx++)
303  {
304  uint16_t frame_idx = sweep_idx * sweep_length + point_idx;
305  acc_int16_complex_t point = frame[frame_idx];
306  float complex float_point = (float)point.real + (float)point.imag * I;
307 
308  handle->scratch[sweep_idx] = cargf(float_point * column_sum);
309  }
310 
311  float point_phase_variance = acc_algorithm_variance_f32(handle->scratch, sweeps_per_frame);
312 
313  if (point_phase_variance < threshold_squared)
314  {
315  phase_vars_under_threshold++;
316  }
317  else
318  {
319  phase_vars_under_threshold = 0U;
320  }
321 
322  if (phase_vars_under_threshold >= distance_seq_len)
323  {
324  point_of_waste = point_idx - (phase_vars_under_threshold - 1U);
325  point_of_waste_found = true;
326  break;
327  }
328  }
329 
330  float new_distance = !point_of_waste_found ? NAN : point_in_sweep_to_distance_m(app_config->sensor_config, metadata, point_of_waste);
331 
332  write_to_ring_buffer(handle->state.distance_history_points,
333  median_filter_len,
334  &handle->state.distance_history_len,
335  &handle->state.distance_history_write_idx,
336  new_distance);
337 
338  // copy non-NaN distance history points as median sorts inplace
339  uint16_t num_normal = copy_non_nan_floats(handle->state.distance_history_points, handle->scratch, handle->state.distance_history_len);
340  if (num_normal > 0U)
341  {
342  waste_level_result->level_found = true;
343 
344  float median_distance = acc_algorithm_median_f32(handle->scratch, num_normal);
345  set_level_numbers(median_distance, &app_config->processing_config, waste_level_result);
346  }
347  else
348  {
349  waste_level_result->level_found = false;
350  }
351  }
352 }
353 
355 {
356  printf("Waste level config:\n");
357  printf("bin_start_m: %" PRIfloat "\n", ACC_LOG_FLOAT_TO_INTEGER(config->bin_start_m));
358  printf("bin_end_m: %" PRIfloat "\n", ACC_LOG_FLOAT_TO_INTEGER(config->bin_end_m));
359  printf("threshold: %" PRIfloat "\n", ACC_LOG_FLOAT_TO_INTEGER(config->threshold));
360  printf("distance_sequence_len: %" PRIu16 "\n", config->distance_sequence_len);
361  printf("median_filter_len: %" PRIu16 "\n", config->median_filter_len);
362 }
363 
364 static bool validate_app_config(const waste_level_app_config_t *app_config)
365 {
366  const waste_level_processing_config_t *processing_config;
367  const acc_config_t *sensor_config;
368 
369  bool status = app_config != NULL;
370 
371  if (status)
372  {
373  sensor_config = app_config->sensor_config;
374  processing_config = &app_config->processing_config;
375  status = sensor_config != NULL && processing_config != NULL;
376  }
377 
378  if (status && processing_config->bin_start_m < 0.08f)
379  {
380  fprintf(stderr, "Bin start needs to be greater or equal than 0.08m\n");
381  status = false;
382  }
383 
384  if (status && processing_config->bin_end_m < processing_config->bin_start_m)
385  {
386  fprintf(stderr, "Bin end needs to be greater than bin start\n");
387  status = false;
388  }
389 
390  if (status && (processing_config->threshold < 0.0f || processing_config->threshold > 4.0f))
391  {
392  fprintf(stderr, "Threshold shoud be in the range [0.0, 4.0], was %" PRIfloat "\n", ACC_LOG_FLOAT_TO_INTEGER(processing_config->threshold));
393  status = false;
394  }
395 
396  if (status && (processing_config->distance_sequence_len > 10U || processing_config->distance_sequence_len < 1U))
397  {
398  fprintf(stderr, "Distance sequence length shoud be in the range [1, 10], was %" PRIu16 "\n", processing_config->distance_sequence_len);
399  status = false;
400  }
401 
402  if (status && (processing_config->median_filter_len > 10U || processing_config->median_filter_len < 1U))
403  {
404  fprintf(stderr, "Median filter length shoud be in the range [1, 10], was %" PRIu16 "\n", processing_config->median_filter_len);
405  status = false;
406  }
407 
408  if (status && !subsweep_start_points_strictly_increases(sensor_config))
409  {
410  fprintf(stderr, "Subsweeps with higher indexes should measure farther away than those with lower indexes\n");
411  status = false;
412  }
413 
414  if (status)
415  {
416  uint8_t subsweep_idx;
417 
418  if (has_overlapping_subsweeps(sensor_config, &subsweep_idx))
419  {
420  fprintf(stderr, "Disallowed range overlap between susweeps %" PRIu16 " and %" PRIu16 "\n", subsweep_idx, subsweep_idx + 1U);
421  status = false;
422  }
423  }
424 
425  if (status && is_invalid_start_point(sensor_config))
426  {
427  fprintf(stderr, "Start point must be greater or equal than 32\n");
428  status = false;
429  }
430 
431  if (status && is_outside_measuring_interval(sensor_config, processing_config->bin_start_m))
432  {
433  fprintf(stderr, "Bin start is outside measuring interval\n");
434  status = false;
435  }
436 
437  if (status && is_outside_measuring_interval(sensor_config, processing_config->bin_end_m))
438  {
439  fprintf(stderr, "Bin end is outside measuring interval\n");
440  status = false;
441  }
442 
443  if (status && acc_config_sweeps_per_frame_get(sensor_config) <= 3)
444  {
445  fprintf(stderr, "Sweeps per frame needs to be greater than 3\n");
446  status = false;
447  }
448 
449  return status;
450 }
451 
453 {
454  bool increasing = true;
455 
456  uint8_t num_subsweeps = acc_config_num_subsweeps_get(sensor_config);
457 
458  for (uint8_t subsweep_idx = 1U; subsweep_idx < num_subsweeps; subsweep_idx++)
459  {
460  int32_t prev_start = acc_config_subsweep_start_point_get(sensor_config, subsweep_idx - 1U);
461  int32_t curr_start = acc_config_subsweep_start_point_get(sensor_config, subsweep_idx);
462 
463  if (curr_start <= prev_start)
464  {
465  increasing = false;
466  break;
467  }
468  }
469 
470  return increasing;
471 }
472 
473 static bool has_overlapping_subsweeps(const acc_config_t *sensor_config, uint8_t *offending_subsweep)
474 {
475  bool overlap_found = false;
476  uint8_t num_subsweeps = acc_config_num_subsweeps_get(sensor_config);
477 
478  for (uint8_t subsweep_idx = 0U; subsweep_idx < num_subsweeps - 1U; subsweep_idx++)
479  {
480  float curr_end = subsweep_approx_end_m(sensor_config, subsweep_idx);
481  float next_start = subsweep_approx_start_m(sensor_config, subsweep_idx + 1U);
482 
483  if (curr_end >= next_start)
484  {
485  *offending_subsweep = subsweep_idx;
486  overlap_found = true;
487  break;
488  }
489  }
490 
491  return overlap_found;
492 }
493 
494 static bool is_invalid_start_point(const acc_config_t *sensor_config)
495 {
496  const int32_t minimum_allowed_start_point = 32;
497 
498  int32_t min_start_point = acc_config_subsweep_start_point_get(sensor_config, 0U);
499 
500  return min_start_point < minimum_allowed_start_point;
501 }
502 
503 static bool is_outside_measuring_interval(const acc_config_t *sensor_config, float distance_m)
504 {
505  float min_measured_point_m = 1000.0f;
506  float max_measured_point_m = -1000.0f;
507 
508  uint8_t num_subsweeps = acc_config_num_subsweeps_get(sensor_config);
509 
510  for (uint8_t subsweep_idx = 0U; subsweep_idx < num_subsweeps; subsweep_idx++)
511  {
512  float current_begin_m = subsweep_approx_start_m(sensor_config, subsweep_idx);
513  float current_end_m = subsweep_approx_end_m(sensor_config, subsweep_idx);
514 
515  if (current_begin_m < min_measured_point_m)
516  {
517  min_measured_point_m = current_begin_m;
518  }
519 
520  if (current_end_m > max_measured_point_m)
521  {
522  max_measured_point_m = current_end_m;
523  }
524  }
525 
526  return distance_m < min_measured_point_m || distance_m > max_measured_point_m;
527 }
528 
529 static float subsweep_approx_start_m(const acc_config_t *sensor_config, uint8_t subsweep_idx)
530 {
531  return acc_algorithm_get_distance_m(acc_config_subsweep_step_length_get(sensor_config, subsweep_idx),
532  acc_config_subsweep_start_point_get(sensor_config, subsweep_idx),
534  0U);
535 }
536 
537 static float subsweep_approx_end_m(const acc_config_t *sensor_config, uint8_t subsweep_idx)
538 {
539  return acc_algorithm_get_distance_m(acc_config_subsweep_step_length_get(sensor_config, subsweep_idx),
540  acc_config_subsweep_start_point_get(sensor_config, subsweep_idx),
542  acc_config_subsweep_num_points_get(sensor_config, subsweep_idx) - 1U);
543 }
544 
545 static float point_in_sweep_to_distance_m(const acc_config_t *sensor_config, const acc_processing_metadata_t *metadata, uint16_t point_idx)
546 {
547  uint8_t num_subsweeps = acc_config_num_subsweeps_get(sensor_config);
548  float distance_m = 0.0f;
549 
550  for (uint8_t subsweep_idx = 0U; subsweep_idx < num_subsweeps; subsweep_idx++)
551  {
552  uint16_t start = metadata->subsweep_data_offset[subsweep_idx];
553  uint16_t end = start + metadata->subsweep_data_length[subsweep_idx];
554 
555  if (point_idx >= start && point_idx < end)
556  {
557  distance_m = acc_algorithm_get_distance_m(acc_config_subsweep_step_length_get(sensor_config, subsweep_idx),
558  acc_config_subsweep_start_point_get(sensor_config, subsweep_idx),
560  point_idx - start);
561  break;
562  }
563  }
564 
565  return distance_m;
566 }
567 
568 static void write_to_ring_buffer(float *buffer, uint16_t capacity, uint16_t *length, uint16_t *write_idx, float elem)
569 {
570  buffer[*write_idx] = elem;
571 
572  *write_idx = (*write_idx + 1U) % capacity;
573 
574  if (*length < capacity)
575  {
576  *length = *length + 1U;
577  }
578 }
579 
580 static uint16_t copy_non_nan_floats(const float *in, float *out, uint16_t length)
581 {
582  uint16_t num_normal = 0U;
583 
584  for (uint16_t i = 0U; i < length; i++)
585  {
586  if (fpclassify(in[i]) != FP_NAN)
587  {
588  out[num_normal] = in[i];
589  num_normal++;
590  }
591  }
592 
593  return num_normal;
594 }
595 
596 static void set_level_numbers(float filtered_distance, const waste_level_processing_config_t *processing_config, waste_level_result_t *result)
597 {
598  float bin_end_m = processing_config->bin_end_m;
599  float bin_start_m = processing_config->bin_start_m;
600 
601  float fill_level_m = bin_end_m - filtered_distance;
602  float fill_level_percent_f = acc_algorithm_clip_f32(100.0f * fill_level_m / (bin_end_m - bin_start_m), 0.0f, 100.0f);
603 
604  fill_level_percent_f += 0.5f; // for rounding
605  uint8_t fill_level_percent = (uint8_t)fill_level_percent_f;
606 
607  result->level_m = fill_level_m;
608  result->level_percent = fill_level_percent;
609 }
waste_level_processing_config_t::distance_sequence_len
uint16_t distance_sequence_len
Definition: example_waste_level.h:36
waste_level_app_config_destroy
void waste_level_app_config_destroy(waste_level_app_config_t *app_config)
Destroy a waste level app config.
Definition: example_waste_level.c:166
waste_level_handle::distance_history_write_idx
uint16_t distance_history_write_idx
Definition: example_waste_level.c:39
waste_level_preset_t
waste_level_preset_t
Waste level preset.
Definition: example_waste_level.h:54
acc_processing_metadata_t::subsweep_data_offset
uint16_t subsweep_data_offset[(4U)]
Definition: acc_processing.h:43
waste_level_handle::distance_history_len
uint16_t distance_history_len
Definition: example_waste_level.c:36
acc_config_subsweep_num_points_get
uint16_t acc_config_subsweep_num_points_get(const acc_config_t *config, uint8_t index)
Get the number of data points to measure.
has_overlapping_subsweeps
static bool has_overlapping_subsweeps(const acc_config_t *sensor_config, uint8_t *offending_subsweep)
Helper function for validation.
Definition: example_waste_level.c:473
buffer
void * buffer
Definition: i2c_example_cargo.c:40
waste_level_app_config_set_preset
void waste_level_app_config_set_preset(waste_level_preset_t preset, waste_level_app_config_t *app_config)
Apply a preset to an app config.
Definition: example_waste_level.c:179
acc_config_num_subsweeps_get
uint8_t acc_config_num_subsweeps_get(const acc_config_t *config)
Get the number of subsweeps to use.
acc_algorithm_get_distance_m
float acc_algorithm_get_distance_m(uint16_t step_length, uint16_t start_point, float base_step_length_m, uint16_t idx)
Calculate distance for a point at an index.
Definition: acc_algorithm.c:1118
waste_level_handle
Definition: example_waste_level.c:27
acc_int16_complex_t
Data type for interger-based representation of complex numbers.
Definition: acc_definitions_common.h:40
waste_level_process
void waste_level_process(waste_level_handle_t *handle, const waste_level_app_config_t *app_config, const acc_processing_metadata_t *metadata, const acc_int16_complex_t *frame, waste_level_result_t *waste_level_result)
Process Sparse IQ data.
Definition: example_waste_level.c:275
acc_config_sweeps_per_frame_set
void acc_config_sweeps_per_frame_set(acc_config_t *config, uint16_t sweeps)
Set sweeps per frame.
acc_config_destroy
void acc_config_destroy(acc_config_t *config)
Destroy a configuration freeing any resources allocated.
waste_level_handle::state
struct waste_level_handle::@7 state
waste_level_result_t
Result type.
Definition: example_waste_level.h:63
acc_config_subsweep.h
is_invalid_start_point
static bool is_invalid_start_point(const acc_config_t *sensor_config)
Helper function for validation.
Definition: example_waste_level.c:494
cargo_result_t::level_m
float level_m
Definition: example_cargo.h:123
acc_config_create
acc_config_t * acc_config_create(void)
Create a configuration.
waste_level_processing_config_t::median_filter_len
uint16_t median_filter_len
Definition: example_waste_level.h:39
copy_non_nan_floats
static uint16_t copy_non_nan_floats(const float *in, float *out, uint16_t length)
Copy non-NaN floats between buffers.
Definition: example_waste_level.c:580
acc_integration.h
config
cargo_config_t config
Definition: i2c_example_cargo.c:34
subsweep_approx_end_m
static float subsweep_approx_end_m(const acc_config_t *sensor_config, uint8_t subsweep_idx)
Helper function for validation.
Definition: example_waste_level.c:537
acc_config_frame_rate_set
void acc_config_frame_rate_set(acc_config_t *config, float frame_rate)
Set the frame rate.
cargo_result_t::level_percent
float level_percent
Definition: example_cargo.h:128
acc_integration_mem_alloc
void * acc_integration_mem_alloc(size_t size)
Allocate dynamic memory.
Definition: acc_integration_stm32.c:592
acc_processing_metadata_t
Metadata that will be populated by the processing module during creation.
Definition: acc_processing.h:36
waste_level_app_config_t
Definition: example_waste_level.h:42
is_outside_measuring_interval
static bool is_outside_measuring_interval(const acc_config_t *sensor_config, float distance_m)
Helper function for validation.
Definition: example_waste_level.c:503
subsweep_approx_start_m
static float subsweep_approx_start_m(const acc_config_t *sensor_config, uint8_t subsweep_idx)
Helper function for validation.
Definition: example_waste_level.c:529
acc_config_sweeps_per_frame_get
uint16_t acc_config_sweeps_per_frame_get(const acc_config_t *config)
Get the number of sweeps per frame.
acc_processing_metadata_t::sweep_data_length
uint16_t sweep_data_length
Definition: acc_processing.h:41
waste_level_processing_config_t::bin_start_m
float bin_start_m
Definition: example_waste_level.h:27
set_level_numbers
static void set_level_numbers(float filtered_distance, const waste_level_processing_config_t *processing_config, waste_level_result_t *result)
Populate a waste level result with its human-readable entries.
Definition: example_waste_level.c:596
handle
cargo_handle_t * handle
Definition: i2c_example_cargo.c:35
result
cargo_result_t result
Definition: i2c_example_cargo.c:43
acc_int16_complex_t::real
int16_t real
Definition: acc_definitions_common.h:42
acc_config_t
struct acc_config acc_config_t
Definition: acc_config.h:24
printf
#define printf
Definition: printf.h:60
acc_config_subsweep_step_length_get
uint16_t acc_config_subsweep_step_length_get(const acc_config_t *config, uint8_t index)
Get the step length in a sweep.
acc_processing_points_to_meter
float acc_processing_points_to_meter(int32_t points)
Convert a distance or step length in points to meter.
write_to_ring_buffer
static void write_to_ring_buffer(float *buffer, uint16_t capacity, uint16_t *length, uint16_t *write_idx, float elem)
Write next value into a ring buffer.
Definition: example_waste_level.c:568
WASTE_LEVEL_PRESET_PLASTIC_WASTE_BIN
@ WASTE_LEVEL_PRESET_PLASTIC_WASTE_BIN
Definition: example_waste_level.h:57
acc_config_num_subsweeps_set
void acc_config_num_subsweeps_set(acc_config_t *config, uint8_t num_subsweeps)
Set the number of subsweeps to use.
acc_config_subsweep_start_point_set
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.
WASTE_LEVEL_PRESET_NONE
@ WASTE_LEVEL_PRESET_NONE
Definition: example_waste_level.h:56
waste_level_processing_config_t::threshold
float threshold
Definition: example_waste_level.h:33
waste_level_app_config_t::sensor_config
acc_config_t * sensor_config
Definition: example_waste_level.h:48
acc_config_subsweep_profile_set
void acc_config_subsweep_profile_set(acc_config_t *config, acc_config_profile_t profile, uint8_t index)
Set a profile.
subsweep_start_points_strictly_increases
static bool subsweep_start_points_strictly_increases(const acc_config_t *sensor_config)
Helper function for validation.
Definition: example_waste_level.c:452
ACC_APPROX_BASE_STEP_LENGTH_M
#define ACC_APPROX_BASE_STEP_LENGTH_M
Approximate minimum step length for a sensor measurement in meters.
Definition: acc_algorithm.h:19
waste_level_handle_destroy
void waste_level_handle_destroy(waste_level_handle_t *handle)
Destroy a waste level handle.
Definition: example_waste_level.c:257
acc_algorithm_conj_f32
void acc_algorithm_conj_f32(float complex *data, uint16_t data_length)
Inline calculate conjugate of all elements in an array.
Definition: acc_algorithm.c:576
waste_level_app_config_create
waste_level_app_config_t * waste_level_app_config_create(void)
Create a waste level app config (includes an acc_config_t)
Definition: example_waste_level.c:147
waste_level_handle_create
waste_level_handle_t * waste_level_handle_create(const waste_level_app_config_t *app_config)
Create a waste level handle.
Definition: example_waste_level.c:217
acc_algorithm_clip_f32
float acc_algorithm_clip_f32(float value, float min, float max)
Clip passed value into the interval [min, max].
Definition: acc_algorithm.c:1431
acc_integration_log.h
waste_level_processing_config_log
void waste_level_processing_config_log(const waste_level_processing_config_t *config)
Log a waste level config.
Definition: example_waste_level.c:354
waste_level_result_t::level_found
bool level_found
Definition: example_waste_level.h:68
ACC_LOG_FLOAT_TO_INTEGER
#define ACC_LOG_FLOAT_TO_INTEGER(a)
Definition: acc_integration_log.h:26
waste_level_handle::scratch
float * scratch
Definition: example_waste_level.c:43
acc_algorithm_median_f32
float acc_algorithm_median_f32(float *data, uint16_t length)
Calculate median of input data.
Definition: acc_algorithm.c:1342
acc_algorithm.h
acc_algorithm_variance_f32
float acc_algorithm_variance_f32(const float *data, uint16_t length)
Calculate variance.
Definition: acc_algorithm.c:1399
acc_integration_mem_free
void acc_integration_mem_free(void *ptr)
Free dynamic memory.
Definition: acc_integration_stm32.c:602
example_waste_level.h
acc_int16_complex_t::imag
int16_t imag
Definition: acc_definitions_common.h:43
acc_definitions_common.h
acc_config_subsweep_hwaas_set
void acc_config_subsweep_hwaas_set(acc_config_t *config, uint16_t hwaas, uint8_t index)
Set the hardware accelerated average samples (HWAAS)
acc_config_subsweep_step_length_set
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.h
waste_level_processing_config_t
Configuration for waste_level.
Definition: example_waste_level.h:24
validate_app_config
static bool validate_app_config(const waste_level_app_config_t *app_config)
Validate an app_config (processing & sensor config).
Definition: example_waste_level.c:364
acc_config_subsweep_num_points_set
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.
PRIfloat
#define PRIfloat
Specifier for printing float type using integers.
Definition: acc_integration_log.h:31
ACC_CONFIG_PROFILE_1
@ ACC_CONFIG_PROFILE_1
Definition: acc_definitions_a121.h:52
waste_level_handle::distance_history_points
float * distance_history_points
Definition: example_waste_level.c:33
cargo_handle::state
struct cargo_handle::@6 state
acc_config_subsweep_start_point_get
int32_t acc_config_subsweep_start_point_get(const acc_config_t *config, uint8_t index)
Get the starting point of the sweep.
waste_level_processing_config_t::bin_end_m
float bin_end_m
Definition: example_waste_level.h:30
acc_algorithm_sum_sweep
void acc_algorithm_sum_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 *sum_sweep)
Calculate the sum of all sweeps in a frame, from start_point to end_point.
Definition: acc_algorithm.c:536
point_in_sweep_to_distance_m
static float point_in_sweep_to_distance_m(const acc_config_t *sensor_config, const acc_processing_metadata_t *metadata, uint16_t point_idx)
Calculate a point's corresponding distance in meters.
Definition: example_waste_level.c:545
acc_processing.h
ACC_CONFIG_PROFILE_3
@ ACC_CONFIG_PROFILE_3
Definition: acc_definitions_a121.h:54
acc_processing_metadata_t::subsweep_data_length
uint16_t subsweep_data_length[(4U)]
Definition: acc_processing.h:45
waste_level_app_config_t::processing_config
waste_level_processing_config_t processing_config
Definition: example_waste_level.h:45