Skip to content

Commit

Permalink
fm receiver wip
Browse files Browse the repository at this point in the history
  • Loading branch information
bastibl committed Jun 6, 2022
1 parent 8da5cea commit 6fcb45c
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 16 deletions.
1 change: 1 addition & 0 deletions examples/fm-receiver/Cargo.toml
Expand Up @@ -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" }
1 change: 1 addition & 0 deletions examples/fm-receiver/config.toml
@@ -0,0 +1 @@
buffer_size = 262144
55 changes: 39 additions & 16 deletions examples/fm-receiver/src/main.rs
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -46,8 +67,10 @@ fn main() -> ! {
.expect("No freq port found!");

// Downsample before demodulation
let resamp1 = FirBuilder::new_resampling::<Complex32>(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::<Complex32>(interp, decim);

// Demodulation block using the conjugate delay method
// See https://en.wikipedia.org/wiki/Detector_(radio)#Quadrature_detector
Expand All @@ -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::<f32>(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::<f32>(cutoff, transition, 0.1);
let resamp2 = FirBuilder::new_resampling_with_taps::<f32, f32, _>(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);
Expand Down
1 change: 1 addition & 0 deletions futuredsp/src/fir.rs
Expand Up @@ -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 =
Expand Down
5 changes: 5 additions & 0 deletions src/blocks/fir.rs
Expand Up @@ -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);

Expand Down Expand Up @@ -171,6 +173,9 @@ impl FirBuilder {
Taps: 'static + TapsAccessor,
PolyphaseResamplingFirKernel<SampleType, Taps>: UnaryKernel<SampleType>,
{
let gcd = num_integer::gcd(interp, decim);
let interp = interp / gcd;
let decim = decim / gcd;
Fir::<SampleType, TapType, PolyphaseResamplingFirKernel<SampleType, Taps>>::new(
PolyphaseResamplingFirKernel::new(interp, decim, taps),
)
Expand Down

0 comments on commit 6fcb45c

Please sign in to comment.