From d2bc12d5fd5775c555b4f9cd8b908bbf79246b4b Mon Sep 17 00:00:00 2001 From: zeefaad Date: Mon, 15 Jun 2026 12:50:30 +0200 Subject: [PATCH] chunk to sample process --- src/agc.rs | 60 ++++++++++++++++++++++-------------------------- src/fir.rs | 47 +++++++++++++++++++------------------ src/fm_demod.rs | 13 ++++------- src/iq_reader.rs | 42 ++++++++++++++++----------------- src/main.rs | 6 ++--- src/pipeline.rs | 6 ++--- 6 files changed, 83 insertions(+), 91 deletions(-) diff --git a/src/agc.rs b/src/agc.rs index 2cfda3b..fb9debb 100644 --- a/src/agc.rs +++ b/src/agc.rs @@ -1,4 +1,3 @@ -use crate::iq_reader::IqChunk; use crate::iq_reader::IqSample; // Automatic Gain Control @@ -51,56 +50,51 @@ impl Agc { } } - pub fn process_chunk(&mut self, chunk: &mut IqChunk) { - for z in chunk.samples.iter_mut() { - let i = z.re; - let q = z.im; + pub fn process_sample(&mut self, sample: IqSample) -> IqSample { + let i = sample.re; + let q = sample.im; - // Instant Power - let inst_power = i * i + q * q; + // Instant Power + let inst_power = i * i + q * q; - let alpha = if inst_power > self.power_estimate { - self.alpha_attack - } else { - self.alpha_release - }; + let alpha = if inst_power > self.power_estimate { + self.alpha_attack + } else { + self.alpha_release + }; - // IIR filter - let power_estimate = alpha * inst_power + (1.0 - alpha) * self.power_estimate; + // IIR filter + let power_estimate = alpha * inst_power + (1.0 - alpha) * self.power_estimate; - // Update Power - self.power_estimate = power_estimate.max(1e-10); + // Update Power + self.power_estimate = power_estimate.max(1e-10); - let raw_gain = (self.target_power / self.power_estimate).sqrt(); + let raw_gain = (self.target_power / self.power_estimate).sqrt(); - // Gain in [min_gain ; max_gain] - let raw_gain = match raw_gain { - g if g < self.min_gain => self.min_gain, - g if g > self.max_gain => self.max_gain, - _ => raw_gain, - }; + // Gain in [min_gain ; max_gain] + let raw_gain = match raw_gain { + g if g < self.min_gain => self.min_gain, + g if g > self.max_gain => self.max_gain, + _ => raw_gain, + }; - let final_gain = self.beta * self.current_gain + (1.0 - self.beta) * raw_gain; + let final_gain = self.beta * self.current_gain + (1.0 - self.beta) * raw_gain; - self.current_gain = final_gain; + self.current_gain = final_gain; - *z = IqSample::new(i * final_gain, q * final_gain); - } + IqSample::new(i * final_gain, q * final_gain) } } impl Iterator for Agc where - I: Iterator>, + I: Iterator>, { - type Item = Result; + type Item = Result; fn next(&mut self) -> Option { match self.inner.next()? { - Ok(mut chunk) => { - self.process_chunk(&mut chunk); - Some(Ok(chunk)) - } + Ok(mut sample) => Some(Ok(self.process_sample(sample))), Err(e) => Some(Err(e)), } } diff --git a/src/fir.rs b/src/fir.rs index f965558..c930149 100644 --- a/src/fir.rs +++ b/src/fir.rs @@ -1,5 +1,5 @@ // Finite Impulse response + Decimation -use crate::{iq_reader::IqChunk, iq_reader::IqSample, utils::ring_buffer::RingBuffer}; +use crate::{iq_reader::IqSample, utils::ring_buffer::RingBuffer}; pub struct Fir { inner: I, @@ -27,40 +27,43 @@ impl Fir { } } - pub fn process_chunk(&mut self, chunk: &IqChunk) -> IqChunk { - let mut chunk_out = IqChunk::new(); + // None if not emited + pub fn process_sample(&mut self, sample: IqSample) -> Option { + self.history.push(sample); - for iq in chunk.samples.iter() { - self.history.push(*iq); + self.decimation_index += 1; - // Decimation - if self.decimation_index.is_multiple_of(self.decimation_factor) { - let mut y_n = IqSample::default(); - for k in 0..N { - if let Some(sample) = self.history.read_at(k) { - y_n += *sample * self.taps[k]; - } + // Decimation + if self.decimation_index.is_multiple_of(self.decimation_factor) { + let mut y_n = IqSample::default(); + for k in 0..N { + if let Some(s) = self.history.read_at(k) { + y_n += *s * self.taps[k]; } - - chunk_out.samples.push(y_n); } - - self.decimation_index += 1; + Some(y_n) + } else { + None } - chunk_out } } impl Iterator for Fir where - I: Iterator>, + I: Iterator>, { - type Item = Result; + type Item = Result; fn next(&mut self) -> Option { - match self.inner.next()? { - Ok(chunk) => Some(Ok(self.process_chunk(&chunk))), - Err(e) => Some(Err(e)), + loop { + match self.inner.next()? { + Ok(sample) => { + if let Some(y_n) = self.process_sample(sample) { + return Some(Ok(y_n)); + } + } + Err(e) => return Some(Err(e)), + } } } } diff --git a/src/fm_demod.rs b/src/fm_demod.rs index c2f5f9f..9a030af 100644 --- a/src/fm_demod.rs +++ b/src/fm_demod.rs @@ -1,5 +1,3 @@ -use std::{os::unix::process, slice::Chunks}; - use crate::iq_reader::{IqChunk, IqSample}; pub struct FmDemod { @@ -15,7 +13,7 @@ impl FmDemod { } } - pub fn process_chunk(&mut self, chunk: &mut IqChunk) { + pub fn process_sample(&mut self, sample: IqSample) -> IqSample { // TODO: FM Demodulation todo!(); } @@ -23,16 +21,13 @@ impl FmDemod { impl Iterator for FmDemod where - I: Iterator>, + I: Iterator>, { - type Item = Result; + type Item = Result; fn next(&mut self) -> Option { match self.inner.next()? { - Ok(mut chunk) => { - self.process_chunk(&mut chunk); - Some(Ok(chunk)) - } + Ok(sample) => Some(Ok(self.process_sample(sample))), Err(e) => Some(Err(e)), } } diff --git a/src/iq_reader.rs b/src/iq_reader.rs index 2e9cbdd..f370bf5 100644 --- a/src/iq_reader.rs +++ b/src/iq_reader.rs @@ -26,6 +26,8 @@ pub struct FileSource { pub raw_buffer: Vec, // Size of a sample chunk pub chunk_samples_size: usize, + // raw_buffer position (in samples) + pub cursor: usize, } impl FileSource { @@ -42,40 +44,38 @@ impl FileSource { reader, raw_buffer: raw_reader, chunk_samples_size, + cursor: chunk_samples_size, }) } } impl Iterator for FileSource { - type Item = Result>; + type Item = Result>; fn next(&mut self) -> Option { - // Buffer read - match self.reader.read_exact(&mut self.raw_buffer) { - Ok(_) => {} + if self.cursor >= self.chunk_samples_size { + // Buffer read chunk + match self.reader.read_exact(&mut self.raw_buffer) { + Ok(_) => {} - // EOF - Err(e) if e.kind() == ErrorKind::UnexpectedEof => { - return None; - } + // EOF + Err(e) if e.kind() == ErrorKind::UnexpectedEof => { + return None; + } - Err(e) => { - return Some(Err(e.into())); + Err(e) => { + return Some(Err(e.into())); + } } + self.cursor = 0; } - // Output samples - let mut samples = Vec::with_capacity(self.chunk_samples_size); + // Buffer read sample + let i = (self.raw_buffer[self.cursor * 2] as i8) as f32 / 128.0; + let q = (self.raw_buffer[self.cursor * 2 + 1] as i8) as f32 / 128.0; - // Buffer read - for iq in self.raw_buffer.chunks(2) { - let i = iq[0] as i8; - let q = iq[1] as i8; - let i_f32 = (i as f32) / 128.0; - let q_f32 = (q as f32) / 128.0; - samples.push(Complex::new(i_f32, q_f32)); - } + self.cursor += 1; - Some(Ok(IqChunk { samples })) + Some(Ok(IqSample::new(i, q))) } } diff --git a/src/main.rs b/src/main.rs index fdc9380..9cf43ee 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,9 +19,9 @@ fn main() -> Result<(), Box> { .agc(20_000_000.0, 1.0, 0.001, 100.0) .fir::<64>(taps, 4); - for chunk_r in pipeline { - let chunk = chunk_r?; - println!("size : {}", chunk.samples.len()); + for sample_r in pipeline { + let sample = sample_r?; + println!("sample : {} + i{}", sample.re, sample.im); } Ok(()) diff --git a/src/pipeline.rs b/src/pipeline.rs index b762b07..56bae3e 100644 --- a/src/pipeline.rs +++ b/src/pipeline.rs @@ -1,8 +1,8 @@ use crate::agc::Agc; use crate::fir::Fir; -use crate::iq_reader::IqChunk; +use crate::iq_reader::IqSample; -pub trait DspPipelineExt: Iterator> + Sized { +pub trait DspPipelineExt: Iterator> + Sized { fn agc(self, sample_rate: f32, target_power: f32, min_gain: f32, max_gain: f32) -> Agc { Agc::new(self, sample_rate, target_power, min_gain, max_gain) } @@ -12,4 +12,4 @@ pub trait DspPipelineExt: Iterator> + Sized { } } -impl DspPipelineExt for I where I: Iterator> {} +impl DspPipelineExt for I where I: Iterator> {}