1
0
Fork 0
mirror of https://github.com/alemidev/scope-tui.git synced 2024-11-23 14:14:48 +01:00

feat: implemented hann window on spectroscope input

totally not got the hann window function from github
This commit is contained in:
əlemi 2023-09-21 03:28:15 +02:00
parent e99c9a4a3d
commit 349bee0943
Signed by: alemi
GPG key ID: A4895B84D311642C

View file

@ -15,19 +15,34 @@ pub struct Spectroscope {
pub buffer_size: u32, pub buffer_size: u32,
pub average: u32, pub average: u32,
pub buf: Vec<VecDeque<Vec<f64>>>, pub buf: Vec<VecDeque<Vec<f64>>>,
pub window: bool,
} }
fn complex_to_magnitude(c: Complex<f64>) -> f64 { fn magnitude(c: Complex<f64>) -> f64 {
let squared = (c.re * c.re) + (c.im * c.im); let squared = (c.re * c.re) + (c.im * c.im);
squared.sqrt() squared.sqrt()
} }
// got this from https://github.com/phip1611/spectrum-analyzer/blob/3c079ec2785b031d304bb381ff5f5fe04e6bcf71/src/windows.rs#L40
pub fn hann_window(samples: &[f64]) -> Vec<f64> {
let mut windowed_samples = Vec::with_capacity(samples.len());
let samples_len = samples.len() as f64;
for (i, sample) in samples.iter().enumerate() {
let two_pi_i = 2.0 * std::f64::consts::PI * i as f64;
let idontknowthename = (two_pi_i / samples_len).cos();
let multiplier = 0.5 * (1.0 - idontknowthename);
windowed_samples.push(sample * multiplier)
}
windowed_samples
}
impl DisplayMode for Spectroscope { impl DisplayMode for Spectroscope {
fn from_args(args: &crate::ScopeArgs) -> Self { fn from_args(args: &crate::ScopeArgs) -> Self {
Spectroscope { Spectroscope {
sampling_rate: args.sample_rate, sampling_rate: args.sample_rate,
buffer_size: args.buffer / (2 * args.channels as u32), buffer_size: args.buffer / (2 * args.channels as u32),
average: 1, buf: Vec::new(), average: 1, buf: Vec::new(),
window: true,
} }
} }
@ -44,14 +59,16 @@ impl DisplayMode for Spectroscope {
} }
fn header(&self, _: &GraphConfig) -> String { fn header(&self, _: &GraphConfig) -> String {
let window_marker = if self.window { "-|-" } else { "---" };
if self.average <= 1 { if self.average <= 1 {
format!("live -- {:.3}Hz buckets", self.sampling_rate as f64 / self.buffer_size as f64) format!("live {} {:.3}Hz bins", window_marker, self.sampling_rate as f64 / self.buffer_size as f64)
} else { } else {
format!( format!(
"{}x average ({:.1}s) -- {:.3}Hz buckets", "{}x avg ({:.1}s) {} {:.3}Hz bins",
self.average, self.average,
(self.average * self.buffer_size) as f64 / self.sampling_rate as f64, (self.average * self.buffer_size) as f64 / self.sampling_rate as f64,
self.sampling_rate as f64 / (self.buffer_size * self.average) as f64 window_marker,
self.sampling_rate as f64 / (self.buffer_size * self.average) as f64,
) )
} }
} }
@ -87,13 +104,16 @@ impl DisplayMode for Spectroscope {
let fft = planner.plan_fft_forward(sample_len as usize); let fft = planner.plan_fft_forward(sample_len as usize);
for (n, chan_queue) in self.buf.iter().enumerate().rev() { for (n, chan_queue) in self.buf.iter().enumerate().rev() {
let chunk = chan_queue.iter().flatten().collect::<Vec<&f64>>(); let mut chunk = chan_queue.iter().flatten().copied().collect::<Vec<f64>>();
if self.window {
chunk = hann_window(chunk.as_slice());
}
let max_val = chunk.iter().max_by(|a, b| a.total_cmp(b)).expect("empty dataset?"); let max_val = chunk.iter().max_by(|a, b| a.total_cmp(b)).expect("empty dataset?");
let mut tmp : Vec<Complex<f64>> = chunk.iter().map(|x| Complex { re: *x / *max_val, im: 0.0 }).collect(); let mut tmp : Vec<Complex<f64>> = chunk.iter().map(|x| Complex { re: *x / *max_val, im: 0.0 }).collect();
fft.process(tmp.as_mut_slice()); fft.process(tmp.as_mut_slice());
out.push(DataSet::new( out.push(DataSet::new(
self.channel_name(n), self.channel_name(n),
tmp[..=tmp.len() / 2].iter().enumerate().map(|(i,x)| ((i as f64 * resolution).ln(), complex_to_magnitude(*x))).collect(), tmp[..=tmp.len() / 2].iter().enumerate().map(|(i,x)| ((i as f64 * resolution).ln(), magnitude(*x))).collect(),
cfg.marker_type, cfg.marker_type,
if cfg.scatter { GraphType::Scatter } else { GraphType::Line }, if cfg.scatter { GraphType::Scatter } else { GraphType::Line },
cfg.palette(n), cfg.palette(n),
@ -108,6 +128,7 @@ impl DisplayMode for Spectroscope {
match key.code { match key.code {
KeyCode::PageUp => update_value_i(&mut self.average, true, 1, 1., 1..65535), KeyCode::PageUp => update_value_i(&mut self.average, true, 1, 1., 1..65535),
KeyCode::PageDown => update_value_i(&mut self.average, false, 1, 1., 1..65535), KeyCode::PageDown => update_value_i(&mut self.average, false, 1, 1., 1..65535),
KeyCode::Char('w') => self.window = !self.window,
_ => {} _ => {}
} }
} }