[TSM.ID].[11031972] PXE : Platform X Ecosystem I [144 Module] +25 Missing Matrix Modules
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "xcu-noise-cancellation"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["TSM.ID <tsm@tsm.id>"]
|
||||
description = "[TSM.ID].[11031972] Spectral Subtraction Noise Reducer"
|
||||
|
||||
[dependencies]
|
||||
@@ -0,0 +1,57 @@
|
||||
#![deny(warnings)]
|
||||
#![allow(dead_code)]
|
||||
//! [TSM.ID].[11031972] -- Platform X Ecosystem
|
||||
//! xcu-noise-cancellation -- Spectral Subtraction Noise Reducer
|
||||
use std::f64::consts::PI;
|
||||
#[derive(Debug)] pub enum NoiseError { InvalidInput(String) }
|
||||
impl std::fmt::Display for NoiseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::InvalidInput(e) => write!(f, "{e}") } } }
|
||||
impl std::error::Error for NoiseError {}
|
||||
pub fn dft(signal: &[f64]) -> Vec<(f64, f64)> {
|
||||
let n = signal.len();
|
||||
(0..n).map(|k| {
|
||||
let (mut re, mut im) = (0.0, 0.0);
|
||||
for (t, &x) in signal.iter().enumerate() { let angle = 2.0 * PI * k as f64 * t as f64 / n as f64; re += x * angle.cos(); im -= x * angle.sin(); }
|
||||
(re, im)
|
||||
}).collect()
|
||||
}
|
||||
pub fn idft(spectrum: &[(f64, f64)]) -> Vec<f64> {
|
||||
let n = spectrum.len();
|
||||
(0..n).map(|t| {
|
||||
let mut sum = 0.0;
|
||||
for (k, &(re, im)) in spectrum.iter().enumerate() { let angle = 2.0 * PI * k as f64 * t as f64 / n as f64; sum += re * angle.cos() - im * angle.sin(); }
|
||||
sum / n as f64
|
||||
}).collect()
|
||||
}
|
||||
pub struct NoiseProfile { pub magnitude: Vec<f64> }
|
||||
impl NoiseProfile {
|
||||
pub fn estimate(noise_frames: &[Vec<f64>]) -> Result<Self, NoiseError> {
|
||||
if noise_frames.is_empty() { return Err(NoiseError::InvalidInput("Empty".into())); }
|
||||
let n = noise_frames[0].len();
|
||||
let mut avg_mag = vec![0.0; n];
|
||||
for frame in noise_frames {
|
||||
let spec = dft(frame);
|
||||
for (i, (re, im)) in spec.iter().enumerate() { avg_mag[i] += (re*re + im*im).sqrt(); }
|
||||
}
|
||||
for m in avg_mag.iter_mut() { *m /= noise_frames.len() as f64; }
|
||||
Ok(Self { magnitude: avg_mag })
|
||||
}
|
||||
}
|
||||
pub struct SpectralSubtractor { pub gain_floor: f64 }
|
||||
impl SpectralSubtractor {
|
||||
pub fn new(gain_floor: f64) -> Self { Self { gain_floor } }
|
||||
pub fn process(&self, signal: &[f64], noise: &NoiseProfile) -> Vec<f64> {
|
||||
let spec = dft(signal);
|
||||
let cleaned: Vec<(f64, f64)> = spec.iter().enumerate().map(|(i, &(re, im))| {
|
||||
let mag = (re*re + im*im).sqrt();
|
||||
let noise_mag = if i < noise.magnitude.len() { noise.magnitude[i] } else { 0.0 };
|
||||
let gain = if mag > noise_mag { (mag - noise_mag) / mag } else { self.gain_floor };
|
||||
(re * gain, im * gain)
|
||||
}).collect();
|
||||
idft(&cleaned)
|
||||
}
|
||||
}
|
||||
#[cfg(test)] mod tests {
|
||||
use super::*;
|
||||
#[test] fn test_dft_idft() { let sig = vec![1.0, 0.0, -1.0, 0.0]; let spec = dft(&sig); let rec = idft(&spec); for (a, b) in sig.iter().zip(rec.iter()) { assert!((a - b).abs() < 1e-10); } }
|
||||
#[test] fn test_noise_profile() { let frames = vec![vec![0.1, -0.1, 0.05, -0.05]]; let p = NoiseProfile::estimate(&frames).unwrap(); assert_eq!(p.magnitude.len(), 4); }
|
||||
}
|
||||
Reference in New Issue
Block a user