embedded_dsp/
beamforming.rs1#[allow(unused_imports)]
6use crate::math::FloatMath;
7use crate::transform::cfft_f32;
8use crate::types::Status;
9
10#[derive(Debug, Clone)]
14pub struct DelayAndSumBeamformer<const MICS: usize, const MAX_DELAY: usize> {
15 delays_samples: [f32; MICS],
16 weights: [f32; MICS],
17 delay_lines: [[f32; MAX_DELAY]; MICS],
18 write_ptrs: [usize; MICS],
19}
20
21impl<const MICS: usize, const MAX_DELAY: usize> DelayAndSumBeamformer<MICS, MAX_DELAY> {
22 pub fn new() -> Self {
24 let uniform_w = 1.0 / MICS as f32;
25 Self {
26 delays_samples: [0.0; MICS],
27 weights: [uniform_w; MICS],
28 delay_lines: [[0.0; MAX_DELAY]; MICS],
29 write_ptrs: [0; MICS],
30 }
31 }
32
33 pub fn set_delays(&mut self, delays: &[f32; MICS]) {
35 for (i, &d) in delays.iter().enumerate() {
36 self.delays_samples[i] = d.clamp(0.0, (MAX_DELAY - 2) as f32);
37 }
38 }
39
40 pub fn set_weights(&mut self, weights: &[f32; MICS]) {
42 self.weights.copy_from_slice(weights);
43 }
44
45 pub fn process_sample(&mut self, mic_inputs: &[f32; MICS]) -> f32 {
47 let mut output = 0.0f32;
48
49 for m in 0..MICS {
50 let w_ptr = self.write_ptrs[m];
52 self.delay_lines[m][w_ptr] = mic_inputs[m];
53 self.write_ptrs[m] = (w_ptr + 1) % MAX_DELAY;
54
55 let delay = self.delays_samples[m];
57 let int_delay = delay as usize;
58 let frac_delay = delay - int_delay as f32;
59
60 let idx0 = (w_ptr + MAX_DELAY - int_delay) % MAX_DELAY;
62 let idx1 = (idx0 + MAX_DELAY - 1) % MAX_DELAY;
63
64 let s0 = self.delay_lines[m][idx0];
65 let s1 = self.delay_lines[m][idx1];
66 let delayed_sample = s0 + frac_delay * (s1 - s0);
67
68 output += delayed_sample * self.weights[m];
69 }
70
71 output
72 }
73
74 pub fn reset(&mut self) {
76 for m in 0..MICS {
77 self.delay_lines[m].fill(0.0);
78 self.write_ptrs[m] = 0;
79 }
80 }
81}
82
83impl<const MICS: usize, const MAX_DELAY: usize> Default for DelayAndSumBeamformer<MICS, MAX_DELAY> {
84 fn default() -> Self {
85 Self::new()
86 }
87}
88
89pub fn gcc_phat_tdoa_f32(sig_a: &[f32], sig_b: &[f32], max_delay: usize) -> Result<f32, Status> {
98 let n = sig_a.len();
99 if n != sig_b.len() || n < 4 || (n & (n - 1)) != 0 || n > 512 {
100 return Err(Status::ArgumentError);
101 }
102 if max_delay >= n / 2 {
103 return Err(Status::ArgumentError);
104 }
105
106 let mut buf_a = [0.0f32; 1024];
107 let mut buf_b = [0.0f32; 1024];
108
109 for i in 0..n {
110 buf_a[2 * i] = sig_a[i];
111 buf_a[2 * i + 1] = 0.0;
112 buf_b[2 * i] = sig_b[i];
113 buf_b[2 * i + 1] = 0.0;
114 }
115
116 cfft_f32(&mut buf_a[..2 * n], n, 0, 1);
118 cfft_f32(&mut buf_b[..2 * n], n, 0, 1);
119
120 let mut xcorr_spec = [0.0f32; 1024];
122 for k in 0..n {
123 let a_re = buf_a[2 * k];
124 let a_im = buf_a[2 * k + 1];
125 let b_re = buf_b[2 * k];
126 let b_im = -buf_b[2 * k + 1]; let c_re = a_re * b_re - a_im * b_im;
129 let c_im = a_re * b_im + a_im * b_re;
130
131 let mag = (c_re * c_re + c_im * c_im).sqrt().max(1e-12);
132 xcorr_spec[2 * k] = c_re / mag;
133 xcorr_spec[2 * k + 1] = c_im / mag;
134 }
135
136 cfft_f32(&mut xcorr_spec[..2 * n], n, 1, 1);
138
139 let mut gcc = [0.0f32; 512];
141 for i in 0..n {
142 let target_idx = (i + n / 2) % n;
143 gcc[target_idx] = xcorr_spec[2 * i];
144 }
145
146 let center = n / 2;
148 let start_idx = center - max_delay;
149 let end_idx = center + max_delay;
150
151 let mut peak_val = f32::MIN;
152 let mut peak_idx = center;
153
154 for i in start_idx..=end_idx {
155 if gcc[i] > peak_val {
156 peak_val = gcc[i];
157 peak_idx = i;
158 }
159 }
160
161 let mut frac_offset = 0.0f32;
163 if peak_idx > start_idx && peak_idx < end_idx {
164 let alpha = gcc[peak_idx - 1];
165 let beta = gcc[peak_idx];
166 let gamma = gcc[peak_idx + 1];
167 let denom = 2.0 * (2.0 * beta - alpha - gamma);
168 if denom.abs() > 1e-12 {
169 frac_offset = (alpha - gamma) / denom;
170 }
171 }
172
173 let delay_samples = (peak_idx as f32 + frac_offset) - center as f32;
174 Ok(delay_samples)
175}