Skip to main content

LmsInstanceF32

Struct LmsInstanceF32 

Source
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: f32

Implementations§

Source§

impl<'a> LmsInstanceF32<'a>

Source

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Az for T

Source§

fn az<Dst>(self) -> Dst
where T: Cast<Dst>,

Casts the value.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<Src, Dst> CastFrom<Src> for Dst
where Src: Cast<Dst>,

Source§

fn cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CheckedAs for T

Source§

fn checked_as<Dst>(self) -> Option<Dst>
where T: CheckedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> CheckedCastFrom<Src> for Dst
where Src: CheckedCast<Dst>,

Source§

fn checked_cast_from(src: Src) -> Option<Dst>

Casts the value.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<Src, Dst> LosslessTryInto<Dst> for Src
where Dst: LosslessTryFrom<Src>,

Source§

fn lossless_try_into(self) -> Option<Dst>

Performs the conversion.
Source§

impl<Src, Dst> LossyInto<Dst> for Src
where Dst: LossyFrom<Src>,

Source§

fn lossy_into(self) -> Dst

Performs the conversion.
Source§

impl<T> OverflowingAs for T

Source§

fn overflowing_as<Dst>(self) -> (Dst, bool)
where T: OverflowingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> OverflowingCastFrom<Src> for Dst
where Src: OverflowingCast<Dst>,

Source§

fn overflowing_cast_from(src: Src) -> (Dst, bool)

Casts the value.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> SaturatingAs for T

Source§

fn saturating_as<Dst>(self) -> Dst
where T: SaturatingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> SaturatingCastFrom<Src> for Dst
where Src: SaturatingCast<Dst>,

Source§

fn saturating_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> StrictAs for T

Source§

fn strict_as<Dst>(self) -> Dst
where T: StrictCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> StrictCastFrom<Src> for Dst
where Src: StrictCast<Dst>,

Source§

fn strict_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

Source§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
Source§

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

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
Source§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> UnwrappedAs for T

Source§

fn unwrapped_as<Dst>(self) -> Dst
where T: UnwrappedCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> UnwrappedCastFrom<Src> for Dst
where Src: UnwrappedCast<Dst>,

Source§

fn unwrapped_cast_from(src: Src) -> Dst

Casts the value.
Source§

impl<T> WrappingAs for T

Source§

fn wrapping_as<Dst>(self) -> Dst
where T: WrappingCast<Dst>,

Casts the value.
Source§

impl<Src, Dst> WrappingCastFrom<Src> for Dst
where Src: WrappingCast<Dst>,

Source§

fn wrapping_cast_from(src: Src) -> Dst

Casts the value.