From 6fcb45c931c85825fd25894361df05ce50c8ca7f Mon Sep 17 00:00:00 2001 From: Bastian Bloessl Date: Mon, 6 Jun 2022 21:45:13 +0200 Subject: [PATCH] fm receiver wip --- examples/fm-receiver/Cargo.toml | 1 + examples/fm-receiver/config.toml | 1 + examples/fm-receiver/src/main.rs | 55 ++++++++++++++++++++++---------- futuredsp/src/fir.rs | 1 + src/blocks/fir.rs | 5 +++ 5 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 examples/fm-receiver/config.toml diff --git a/examples/fm-receiver/Cargo.toml b/examples/fm-receiver/Cargo.toml index b8759ced..c92f02ed 100644 --- a/examples/fm-receiver/Cargo.toml +++ b/examples/fm-receiver/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +clap = { version = "3.0.13", features = ["derive"] } futuresdr = { path = "../..", features=["soapy", "audio"] } futuredsp = { path = "../../futuredsp", version = "0.0.3" } diff --git a/examples/fm-receiver/config.toml b/examples/fm-receiver/config.toml new file mode 100644 index 00000000..35de72c9 --- /dev/null +++ b/examples/fm-receiver/config.toml @@ -0,0 +1 @@ +buffer_size = 262144 diff --git a/examples/fm-receiver/src/main.rs b/examples/fm-receiver/src/main.rs index 43543664..4afb7a2f 100644 --- a/examples/fm-receiver/src/main.rs +++ b/examples/fm-receiver/src/main.rs @@ -9,6 +9,7 @@ //! be periodically asked to enter a new frequency that the SDR will be tuned to. //! **Watch out** though: Some frequencies (very high or very low) might be unsupported //! by your SDR and may cause a crash. +use clap::Parser; use futuredsp::firdes; use futuresdr::async_io; @@ -21,23 +22,43 @@ use futuresdr::runtime::Flowgraph; use futuresdr::runtime::Pmt; use futuresdr::runtime::Runtime; +#[derive(Parser, Debug)] +struct Args { + /// Gain to apply to the soapy source + #[clap(short, long, default_value_t = 30.0)] + gain: f64, + + /// Center frequency + #[clap(short, long, default_value_t = 100_000_000.0)] + frequency: f64, + + /// Sample rate + #[clap(short, long, default_value_t = 1000000.0)] + rate: f64, + + /// Soapy source to use as a source + #[clap(long, default_value = "")] + soapy: String, +} + fn main() -> ! { - let freq_mhz = 100.0; - let sample_rate = 1_920_000.0; + let args = Args::parse(); + + let sample_rate = args.rate as u32; + let audio_rate = AudioSink::default_sample_rate().unwrap(); - println!( - "Default Frequency is {} MHz. Sample rate set to {}", - freq_mhz, sample_rate - ); + println!("Configuration {:?}", args); + println!("Audio Rate {:?}", audio_rate); // Create the `Flowgraph` where the `Block`s will be added later on let mut fg = Flowgraph::new(); // Create a new SoapySDR block with the given parameters let src = SoapySourceBuilder::new() - .freq(freq_mhz * 1e6) - .sample_rate(sample_rate) - .gain(34.0) + .filter(args.soapy) + .freq(args.frequency) + .sample_rate(args.rate) + .gain(args.gain) .build(); // Store the `freq` port ID for later use @@ -46,8 +67,10 @@ fn main() -> ! { .expect("No freq port found!"); // Downsample before demodulation - let resamp1 = FirBuilder::new_resampling::(1, 8); - let sample_rate = sample_rate / 8.0; + let interp = (audio_rate * 5) as usize; + let decim = sample_rate as usize; + println!("interp {} decim {}", interp, decim); + let resamp1 = FirBuilder::new_resampling::(interp, decim); // Demodulation block using the conjugate delay method // See https://en.wikipedia.org/wiki/Detector_(radio)#Quadrature_detector @@ -60,14 +83,14 @@ fn main() -> ! { // Design filter for the audio and decimate by 5. // Ideally, this should be a FM de-emphasis filter, but the following works. - let audio_filter_taps = - firdes::kaiser::lowpass::(2_000.0 / sample_rate, 10_000.0 / sample_rate, 0.1); + let cutoff = 2_000.0 / (audio_rate * 5) as f64; + let transition = 10_000.0 / (audio_rate * 5) as f64; + println!("cutoff {} transition {}", cutoff, transition); + let audio_filter_taps = firdes::kaiser::lowpass::(cutoff, transition, 0.1); let resamp2 = FirBuilder::new_resampling_with_taps::(1, 5, audio_filter_taps); - let sample_rate = sample_rate / 5.0; // Single-channel `AudioSink` with the downsampled rate (sample_rate / (8*5) = 48_000) - let snk = AudioSink::new(sample_rate as u32, 1); - + let snk = AudioSink::new(audio_rate, 1); // Add all the blocks to the `Flowgraph`... let src = fg.add_block(src); let resamp1 = fg.add_block(resamp1); diff --git a/futuredsp/src/fir.rs b/futuredsp/src/fir.rs index 2f5c5408..1a8e494c 100644 --- a/futuredsp/src/fir.rs +++ b/futuredsp/src/fir.rs @@ -227,6 +227,7 @@ where SampleType: Copy, TapsType::TapType: Copy, { + info!("interp {} decim {} tap len {}", interp, decim, taps.num_taps()); // Assume same number of taps in all filters let num_taps = taps.num_taps() / interp; let num_producable_samples = diff --git a/src/blocks/fir.rs b/src/blocks/fir.rs index 3df91385..ded97e9d 100644 --- a/src/blocks/fir.rs +++ b/src/blocks/fir.rs @@ -76,6 +76,8 @@ where let (consumed, produced, status) = self.core.work(i, o); + println!("i.len {} o.len {} consumed {} produced {} status {:?}", i.len(), o.len(), consumed, produced, status); + sio.input(0).consume(consumed); sio.output(0).produce(produced); @@ -171,6 +173,9 @@ impl FirBuilder { Taps: 'static + TapsAccessor, PolyphaseResamplingFirKernel: UnaryKernel, { + let gcd = num_integer::gcd(interp, decim); + let interp = interp / gcd; + let decim = decim / gcd; Fir::>::new( PolyphaseResamplingFirKernel::new(interp, decim, taps), )