pub struct LmsInstanceF32<'a> {
pub num_taps: u16,
pub coeffs: &'a mut [f32],
pub state: &'a mut [f32],
pub mu: f32,
}Expand description
Instance structure for the floating-point LMS adaptive filter.
Fields§
§num_taps: u16§coeffs: &'a mut [f32]§state: &'a mut [f32]§mu: f32Implementations§
Source§impl<'a> LmsInstanceF32<'a>
impl<'a> LmsInstanceF32<'a>
Sourcepub fn init(
num_taps: u16,
coeffs: &'a mut [f32],
state: &'a mut [f32],
mu: f32,
) -> Self
pub fn init( num_taps: u16, coeffs: &'a mut [f32], state: &'a mut [f32], mu: f32, ) -> Self
Examples found in repository?
examples/spectral_radar_transforms.rs (line 112)
18fn main() {
19 println!("===============================================================================");
20 println!(" embedded-dsp Spectral Analysis, Multirate & Transform Pipeline ");
21 println!("===============================================================================");
22 println!();
23
24 const FS: f32 = 48000.0; // 48 kHz IF / baseband sampling rate
25 const N_SAMPLES: usize = 512;
26
27 // -----------------------------------------------------------------------------------------
28 // 1. Multitone RF / Radar Signal Synthesis with Strong Jammer
29 // -----------------------------------------------------------------------------------------
30 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; // 3 kHz target tone
36 let target_f2 = 7500.0f32; // 7.5 kHz target tone
37 let jammer_freq = 1200.0f32; // 1.2 kHz strong interfering tone
38
39 for i in 0..N_SAMPLES {
40 let t = i as f32 / FS;
41 // Clean signal: Target radar return
42 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 // High-power narrowband interference (Jammer)
45 jammer_signal[i] = 1.8 * (2.0 * core::f32::consts::PI * jammer_freq * t).sin();
46 // Receiver noise
47 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 // -----------------------------------------------------------------------------------------
62 // 2. Multirate DSP: Cascaded Integrator-Comb (CIC) & Resampling
63 // -----------------------------------------------------------------------------------------
64 println!("\n--- 2. Multirate DSP: CIC Decimation / Interpolation & Linear Resampling ---");
65 // CIC Decimator: 3 stages, Decimation factor R = 4 (e.g. 48 kHz -> 12 kHz)
66 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 // CIC Interpolator: Upsample by 4 back to original rate
87 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 // Fractional Linear Resampling (e.g., 48 kHz to 32 kHz -> ratio = 32/48 = 0.6667)
95 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 // -----------------------------------------------------------------------------------------
104 // 3. Adaptive Noise Cancellation (LMS & NLMS Filters)
105 // -----------------------------------------------------------------------------------------
106 println!("\n--- 3. Adaptive Noise Cancellation (LMS & Normalized LMS) ---");
107 // Use jammer reference signal to cancel interference from received signal
108 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 // Reference signal x = jammer reference, Desired d = received signal (target + jammer + noise)
118 // Error output e = d - y = target + noise (jammer cancelled!)
119 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 // -----------------------------------------------------------------------------------------
140 // 4. Windowing Comparison (Spectral Leakage Suppression)
141 // -----------------------------------------------------------------------------------------
142 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 // -----------------------------------------------------------------------------------------
163 // 5. High-Resolution Spectral Analysis (FFT & Welch PSD)
164 // -----------------------------------------------------------------------------------------
165 println!("\n--- 5. Spectral Analysis: In-Place Complex FFT & Welch's PSD ---");
166 // 256-point Complex FFT on Converged LMS Cleaned Signal
167 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 // Find top 2 spectral peaks
177 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 // Welch's Method Power Spectral Density (PSD)
213 let mut psd_out = [0.0f32; 64];
214 welch_psd_f32(
215 &received_signal,
216 &mut psd_out,
217 128, // Segment length
218 64, // Overlap
219 FS, // Sampling rate
220 WelchWindow::BlackmanHarris,
221 true, // Return in dB/Hz
222 );
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 // -----------------------------------------------------------------------------------------
235 // 6. Advanced DSP Transforms (FWHT, DCT-IV, Hartley, Wavelets)
236 // -----------------------------------------------------------------------------------------
237 println!("\n--- 6. Advanced DSP Transforms: FWHT, DCT-IV, Hartley & Wavelets ---");
238
239 // A. Fast Walsh-Hadamard Transform (FWHT) for CDMA / Walsh codes
240 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 // B. Discrete Cosine Transform IV (DCT-IV)
253 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 // C. Hartley Transform (Real-in, Real-out, Self-Inverse Transform)
259 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 // Applying Hartley twice recovers the original scaled signal
266 hartley_transform_f32(&mut hartley_buf);
267 println!(" Hartley Roundtrip (Self-Inverse): {:?}", hartley_buf);
268
269 // D. Multi-Resolution Daubechies-4 Discrete Wavelet Transform (DWT)
270 let mut wavelet_signal = [0.0f32; 16];
271 wavelet_signal[7] = 10.0; // High-frequency transient spike in middle of frame
272 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}Auto Trait Implementations§
impl<'a> !UnwindSafe for LmsInstanceF32<'a>
impl<'a> Freeze for LmsInstanceF32<'a>
impl<'a> RefUnwindSafe for LmsInstanceF32<'a>
impl<'a> Send for LmsInstanceF32<'a>
impl<'a> Sync for LmsInstanceF32<'a>
impl<'a> Unpin for LmsInstanceF32<'a>
impl<'a> UnsafeUnpin for LmsInstanceF32<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CheckedAs for T
impl<T> CheckedAs for T
Source§fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
fn checked_as<Dst>(self) -> Option<Dst>where
T: CheckedCast<Dst>,
Casts the value.
Source§impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
impl<Src, Dst> CheckedCastFrom<Src> for Dstwhere
Src: CheckedCast<Dst>,
Source§fn checked_cast_from(src: Src) -> Option<Dst>
fn checked_cast_from(src: Src) -> Option<Dst>
Casts the value.
Source§impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere
Dst: LosslessTryFrom<Src>,
impl<Src, Dst> LosslessTryInto<Dst> for Srcwhere
Dst: LosslessTryFrom<Src>,
Source§fn lossless_try_into(self) -> Option<Dst>
fn lossless_try_into(self) -> Option<Dst>
Performs the conversion.
Source§impl<Src, Dst> LossyInto<Dst> for Srcwhere
Dst: LossyFrom<Src>,
impl<Src, Dst> LossyInto<Dst> for Srcwhere
Dst: LossyFrom<Src>,
Source§fn lossy_into(self) -> Dst
fn lossy_into(self) -> Dst
Performs the conversion.
Source§impl<T> OverflowingAs for T
impl<T> OverflowingAs for T
Source§fn overflowing_as<Dst>(self) -> (Dst, bool)where
T: OverflowingCast<Dst>,
fn overflowing_as<Dst>(self) -> (Dst, bool)where
T: OverflowingCast<Dst>,
Casts the value.
Source§impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere
Src: OverflowingCast<Dst>,
impl<Src, Dst> OverflowingCastFrom<Src> for Dstwhere
Src: OverflowingCast<Dst>,
Source§fn overflowing_cast_from(src: Src) -> (Dst, bool)
fn overflowing_cast_from(src: Src) -> (Dst, bool)
Casts the value.
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
Source§impl<T> SaturatingAs for T
impl<T> SaturatingAs for T
Source§fn saturating_as<Dst>(self) -> Dstwhere
T: SaturatingCast<Dst>,
fn saturating_as<Dst>(self) -> Dstwhere
T: SaturatingCast<Dst>,
Casts the value.
Source§impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere
Src: SaturatingCast<Dst>,
impl<Src, Dst> SaturatingCastFrom<Src> for Dstwhere
Src: SaturatingCast<Dst>,
Source§fn saturating_cast_from(src: Src) -> Dst
fn saturating_cast_from(src: Src) -> Dst
Casts the value.
Source§impl<T> StrictAs for T
impl<T> StrictAs for T
Source§fn strict_as<Dst>(self) -> Dstwhere
T: StrictCast<Dst>,
fn strict_as<Dst>(self) -> Dstwhere
T: StrictCast<Dst>,
Casts the value.
Source§impl<Src, Dst> StrictCastFrom<Src> for Dstwhere
Src: StrictCast<Dst>,
impl<Src, Dst> StrictCastFrom<Src> for Dstwhere
Src: StrictCast<Dst>,
Source§fn strict_cast_from(src: Src) -> Dst
fn strict_cast_from(src: Src) -> Dst
Casts the value.
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
The inverse inclusion map: attempts to construct
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
Checks if
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
Use with care! Same as
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
The inclusion map: converts
self to the equivalent element of its superset.Source§impl<T> UnwrappedAs for T
impl<T> UnwrappedAs for T
Source§fn unwrapped_as<Dst>(self) -> Dstwhere
T: UnwrappedCast<Dst>,
fn unwrapped_as<Dst>(self) -> Dstwhere
T: UnwrappedCast<Dst>,
Casts the value.
Source§impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere
Src: UnwrappedCast<Dst>,
impl<Src, Dst> UnwrappedCastFrom<Src> for Dstwhere
Src: UnwrappedCast<Dst>,
Source§fn unwrapped_cast_from(src: Src) -> Dst
fn unwrapped_cast_from(src: Src) -> Dst
Casts the value.
Source§impl<T> WrappingAs for T
impl<T> WrappingAs for T
Source§fn wrapping_as<Dst>(self) -> Dstwhere
T: WrappingCast<Dst>,
fn wrapping_as<Dst>(self) -> Dstwhere
T: WrappingCast<Dst>,
Casts the value.
Source§impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere
Src: WrappingCast<Dst>,
impl<Src, Dst> WrappingCastFrom<Src> for Dstwhere
Src: WrappingCast<Dst>,
Source§fn wrapping_cast_from(src: Src) -> Dst
fn wrapping_cast_from(src: Src) -> Dst
Casts the value.