spectral_radar_transforms/
spectral_radar_transforms.rs1use embedded_dsp::*;
17
18fn main() {
19 println!("===============================================================================");
20 println!(" embedded-dsp Spectral Analysis, Multirate & Transform Pipeline ");
21 println!("===============================================================================");
22 println!();
23
24 const FS: f32 = 48000.0; const N_SAMPLES: usize = 512;
26
27 println!("--- 1. Multitone RF Signal Simulation with Interfering Jammer ---");
31 let mut clean_signal = [0.0f32; N_SAMPLES];
32 let mut jammer_signal = [0.0f32; N_SAMPLES];
33 let mut received_signal = [0.0f32; N_SAMPLES];
34
35 let target_f1 = 3000.0f32; let target_f2 = 7500.0f32; let jammer_freq = 1200.0f32; for i in 0..N_SAMPLES {
40 let t = i as f32 / FS;
41 clean_signal[i] = 0.6 * (2.0 * core::f32::consts::PI * target_f1 * t).sin()
43 + 0.4 * (2.0 * core::f32::consts::PI * target_f2 * t).sin();
44 jammer_signal[i] = 1.8 * (2.0 * core::f32::consts::PI * jammer_freq * t).sin();
46 let prng =
48 ((i as u64).wrapping_mul(1664525).wrapping_add(1013904223) % 10000) as f32 / 10000.0;
49 let noise = 0.1 * (prng - 0.5);
50
51 received_signal[i] = clean_signal[i] + jammer_signal[i] + noise;
52 }
53
54 let mut raw_rms = 0.0f32;
55 rms_f32(&received_signal, &mut raw_rms);
56 println!(
57 " Generated {} samples. Total Received RMS: {:.4} (Jammer-dominated)",
58 N_SAMPLES, raw_rms
59 );
60
61 println!("\n--- 2. Multirate DSP: CIC Decimation / Interpolation & Linear Resampling ---");
65 let mut cic_decimator = CicDecimator::<3>::new(4);
67 let mut cic_interpolator = CicInterpolator::<3>::new(4);
68
69 let mut decimated_stream = [0i32; 128];
70 let mut dec_count = 0;
71
72 for &sample in &received_signal {
73 let sample_i32 = (sample * 1000.0) as i32;
74 if let Some(dec_val) = cic_decimator.process_sample(sample_i32) {
75 if dec_count < decimated_stream.len() {
76 decimated_stream[dec_count] = dec_val;
77 dec_count += 1;
78 }
79 }
80 }
81 println!(
82 " CIC Decimator (R=4, 3 stages): Decimated 512 samples -> {} samples",
83 dec_count
84 );
85
86 let mut upsample_chunk = [0i32; 4];
88 cic_interpolator.process_sample(decimated_stream[0], &mut upsample_chunk);
89 println!(
90 " CIC Interpolator: 1 input sample -> 4 upsampled samples: {:?}",
91 upsample_chunk
92 );
93
94 let mut resampled_out = [0.0f32; 341];
96 resample_linear_f32(&received_signal, &mut resampled_out, 32000.0 / 48000.0);
97 println!(
98 " Fractional Resampler (48kHz -> 32kHz): Resampled {} -> {} samples",
99 received_signal.len(),
100 resampled_out.len()
101 );
102
103 println!("\n--- 3. Adaptive Noise Cancellation (LMS & Normalized LMS) ---");
107 const LMS_TAPS: usize = 32;
109 let mut lms_coeffs = [0.0f32; LMS_TAPS];
110 let mut lms_state = [0.0f32; LMS_TAPS];
111 let mut lms_filter =
112 LmsInstanceF32::init(LMS_TAPS as u16, &mut lms_coeffs, &mut lms_state, 0.005);
113
114 let mut lms_cancelled_out = [0.0f32; N_SAMPLES];
115 let mut lms_error = [0.0f32; N_SAMPLES];
116
117 lms_f32(
120 &mut lms_filter,
121 &jammer_signal,
122 &received_signal,
123 &mut lms_cancelled_out,
124 &mut lms_error,
125 );
126
127 let mut err_rms_initial = 0.0f32;
128 let mut err_rms_converged = 0.0f32;
129 rms_f32(&lms_error[..64], &mut err_rms_initial);
130 rms_f32(&lms_error[N_SAMPLES - 64..], &mut err_rms_converged);
131
132 println!(" LMS Adaptive Filter (32 taps, mu=0.005):");
133 println!(" • Initial Error RMS : {:.4}", err_rms_initial);
134 println!(
135 " • Converged Error RMS : {:.4} (Interference cancelled, target recovered!)",
136 err_rms_converged
137 );
138
139 println!("\n--- 4. Windowing Comparison: Mainlobe & Sidelobe Properties ---");
143 const WIN_LEN: usize = 64;
144 let win_rect = [1.0f32; WIN_LEN];
145 let mut win_hanning = [0.0f32; WIN_LEN];
146 let mut win_hamming = [0.0f32; WIN_LEN];
147 let mut win_blackman_harris = [0.0f32; WIN_LEN];
148 let mut win_flat_top = [0.0f32; WIN_LEN];
149
150 hanning_f32(&mut win_hanning);
151 hamming_f32(&mut win_hamming);
152 blackman_harris_f32(&mut win_blackman_harris);
153 flattop_f32(&mut win_flat_top);
154
155 println!(" Sample Window Values at Midpoint (n=32):");
156 println!(" • Rectangular : {:.4}", win_rect[32]);
157 println!(" • Hanning : {:.4}", win_hanning[32]);
158 println!(" • Hamming : {:.4}", win_hamming[32]);
159 println!(" • Blackman-Harris: {:.4}", win_blackman_harris[32]);
160 println!(" • Flat-Top : {:.4}", win_flat_top[32]);
161
162 println!("\n--- 5. Spectral Analysis: In-Place Complex FFT & Welch's PSD ---");
166 const FFT_SIZE: usize = 256;
168 let mut fft_buffer = [0.0f32; 2 * FFT_SIZE];
169 for i in 0..FFT_SIZE {
170 fft_buffer[2 * i] = lms_error[N_SAMPLES - FFT_SIZE + i] * win_hamming[i % WIN_LEN];
171 fft_buffer[2 * i + 1] = 0.0;
172 }
173
174 cfft_f32(&mut fft_buffer, FFT_SIZE, 0, 1);
175
176 let mut peak1_mag = 0.0f32;
178 let mut peak1_bin = 0usize;
179 let mut peak2_mag = 0.0f32;
180 let mut peak2_bin = 0usize;
181
182 for k in 1..FFT_SIZE / 2 {
183 let re = fft_buffer[2 * k];
184 let im = fft_buffer[2 * k + 1];
185 let mag = (re * re + im * im).sqrt();
186 if mag > peak1_mag {
187 peak2_mag = peak1_mag;
188 peak2_bin = peak1_bin;
189 peak1_mag = mag;
190 peak1_bin = k;
191 } else if mag > peak2_mag {
192 peak2_mag = mag;
193 peak2_bin = k;
194 }
195 }
196
197 let bin_to_hz = FS / FFT_SIZE as f32;
198 println!(" 256-Point FFT Detected Spectral Peaks:");
199 println!(
200 " • Peak 1: Bin {:>3} ({:>6.1} Hz) -> Magnitude: {:>7.2}",
201 peak1_bin,
202 peak1_bin as f32 * bin_to_hz,
203 peak1_mag
204 );
205 println!(
206 " • Peak 2: Bin {:>3} ({:>6.1} Hz) -> Magnitude: {:>7.2}",
207 peak2_bin,
208 peak2_bin as f32 * bin_to_hz,
209 peak2_mag
210 );
211
212 let mut psd_out = [0.0f32; 64];
214 welch_psd_f32(
215 &received_signal,
216 &mut psd_out,
217 128, 64, FS, WelchWindow::BlackmanHarris,
221 true, );
223 println!(" Welch's PSD (Averaged Periodogram in dB/Hz):");
224 println!(" • PSD[Bin 4] (375 Hz) : {:>6.1} dB/Hz", psd_out[4]);
225 println!(
226 " • PSD[Bin 13] (1200 Hz): {:>6.1} dB/Hz (Jammer peak)",
227 psd_out[13]
228 );
229 println!(
230 " • PSD[Bin 32] (3000 Hz): {:>6.1} dB/Hz (Target 1 peak)",
231 psd_out[32]
232 );
233
234 println!("\n--- 6. Advanced DSP Transforms: FWHT, DCT-IV, Hartley & Wavelets ---");
238
239 let mut walsh_data = [1.0f32, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0];
241 let fwht_status = fwht_f32(&mut walsh_data);
242 println!(
243 " Fast Walsh-Hadamard Transform (8-point): Status={:?}, Out={:?}",
244 fwht_status, walsh_data
245 );
246 ifwht_f32(&mut walsh_data);
247 println!(
248 " Inverse FWHT (reconstructed exact signal): {:?}",
249 walsh_data
250 );
251
252 let dct_in = [1.0f32, 2.0, 3.0, 4.0];
254 let mut dct_out = [0.0f32; 4];
255 dct4_f32(&dct_in, &mut dct_out, 4);
256 println!(" DCT-IV (4-point): In={:?} -> Out={:?}", dct_in, dct_out);
257
258 let mut hartley_buf = [1.0f32, 2.0, 3.0, 4.0];
260 let h_status = hartley_transform_f32(&mut hartley_buf);
261 println!(
262 " Hartley Transform: Status={:?}, F_H={:?}",
263 h_status, hartley_buf
264 );
265 hartley_transform_f32(&mut hartley_buf);
267 println!(" Hartley Roundtrip (Self-Inverse): {:?}", hartley_buf);
268
269 let mut wavelet_signal = [0.0f32; 16];
271 wavelet_signal[7] = 10.0; let orig_wavelet = wavelet_signal;
273
274 let dwt_status = wavelet_transform_f32(&mut wavelet_signal, &DAUBECHIES_4);
275 println!(" Daubechies-4 DWT (16-point Pyramid Decomposition):");
276 println!(" • DWT Status : {:?}", dwt_status);
277 println!(
278 " • Detail/Scaling Coefficients: {:?}",
279 &wavelet_signal[..8]
280 );
281
282 let idwt_status = inverse_wavelet_transform_f32(&mut wavelet_signal, &DAUBECHIES_4);
283 let mut diff = 0.0f32;
284 for i in 0..16 {
285 diff += (wavelet_signal[i] - orig_wavelet[i]).abs();
286 }
287 println!(
288 " • Inverse DWT Status: {:?}, Reconstruction Error: {:.2e}",
289 idwt_status, diff
290 );
291
292 println!();
293 println!("===============================================================================");
294 println!(" Spectral & Transforms Pipeline Execution Complete! ");
295 println!("===============================================================================");
296}