| Crates.io | orion-sdr |
| lib.rs | orion-sdr |
| version | 0.0.11 |
| created_at | 2025-08-12 17:08:45.591954+00 |
| updated_at | 2025-09-03 17:28:39.534391+00 |
| description | DSP/SDR block library targeting HF-to-UHF, satellites, and Python bindings. Roadmap inside. |
| homepage | |
| repository | https://github.com/skynavga/orion-sdr |
| max_upload_size | |
| id | 1792242 |
| size | 231,932 |
A composable SDR/DSP library in Rust with Python bindings.
The following results were obtained using cargo test --release --features throughput -- --nocapture on Apple M2 Pro Silicon (sans SIMD):
| Mode | Throughput (Msps) | Runtime (s) |
|---|---|---|
| AM-AbsApprox | 156.89 | 0.013 |
| AM-PowerSqrt | 152.34 | 0.013 |
| SSB-USB | 124.71 | 0.011 |
| CW | 100.74 | 0.020 |
| PM | 31.04 | 0.063 |
| FM | 27.23 | 0.072 |
Below are usage patterns and examples for all demodulators currently available in orion-sdr: CW, AM, SSB, FM, PM.
All examples assume you have IQ samples as Vec<num_complex::Complex32> and show a minimal chain using IqToAudioChain. Adjust sample rates, bandwidths, and gains to your setup.
Extract a CW tone at a chosen audio pitch (e.g., 600–800 Hz) from complex baseband IQ.
use orion_sdr::{
core::IqToAudioChain,
demodulate::CwEnvelopeDemod,
dsp::{FirDecimator, AgcRms},
};
use num_complex::Complex32 as C32;
// IQ sample rate
let fs = 48_000.0;
// CW audio pitch & bandwidth
let pitch_hz = 700.0;
let audio_bw_hz = 300.0;
let mut chain = IqToAudioChain::new(CwEnvelopeDemod::new(fs, pitch_hz, audio_bw_hz));
// Optional: decimate IQ before demod to save CPU (design passband/transition for post-decim BW)
let m = 2; // decimate by 2
let cutoff = (fs / m as f32) * 0.45;
let trans = (fs / m as f32) * 0.10;
chain.push_iq(FirDecimator::new(fs, m, cutoff, trans));
// Optional: audio AGC
chain.push_audio(AgcRms::new(fs, 0.2, 5.0, 200.0));
// Run
let iq: Vec<C32> = get_iq_block(); // your source of IQ samples
let audio: Vec<f32> = chain.process(iq);
Simple envelope detector with post low-pass and DC removal.
use orion_sdr::{
core::IqToAudioChain,
demodulate::AmEnvelopeDemod,
dsp::AgcRms,
};
use num_complex::Complex32 as C32;
let fs = 48_000.0;
let audio_bw_hz = 5_000.0; // narrow AM voice; raise for wider audio
let mut chain = IqToAudioChain::new(AmEnvelopeDemod::new(fs, audio_bw_hz));
chain.push_audio(AgcRms::new(fs, 0.2, 10.0, 300.0));
let iq: Vec<C32> = get_iq_block();
let audio = chain.process(iq);
Product detector with BFO; set BFO frequency and audio bandwidth to taste.
use orion_sdr::{
core::IqToAudioChain,
demodulate::SsbProductDemod,
dsp::{FirDecimator, AgcRms},
};
use num_complex::Complex32 as C32;
let fs = 48_000.0;
let bfo_hz = 0.0; // 0 = audio centered; use +/- offset to choose LSB/USB by tuning
let audio_bw_hz = 2_800.0; // typical SSB audio bandwidth
let mut chain = IqToAudioChain::new(SsbProductDemod::new(fs, bfo_hz, audio_bw_hz));
// Optional: decimate IQ first
let m = 2;
let cutoff = (fs / m as f32) * 0.45;
let trans = (fs / m as f32) * 0.10;
chain.push_iq(FirDecimator::new(fs, m, cutoff, trans));
// Optional: audio AGC
chain.push_audio(AgcRms::new(fs, 0.2, 5.0, 200.0));
let iq: Vec<C32> = get_iq_block();
let audio = chain.process(iq);
Phase-difference quadrature discriminator. Optional limiter and de-emphasis. Audio is scaled so roughly ±deviation → ±1.0.
use orion_sdr::{
core::IqToAudioChain,
demodulate::FmQuadratureDemod,
dsp::AgcRms,
};
use num_complex::Complex32 as C32;
let fs = 48_000.0; // IQ sample rate
let dev_hz = 2_500.0; // peak deviation (e.g., 2.5k or 5k for NBFM)
let audio_bw_hz = 5_000.0; // post-demod audio low-pass
let mut chain = IqToAudioChain::new(FmQuadratureDemod::new(fs, dev_hz, audio_bw_hz));
// Optional: enable de-emphasis (try 300–750 µs for NBFM voice; 75 µs US WBFM, 50 µs EU WBFM)
// chain.demod_mut().set_deemph_tau_us(300.0);
// Optional: post audio AGC
chain.push_audio(AgcRms::new(fs, 0.2, 5.0, 200.0));
let iq: Vec<C32> = get_iq_block();
let audio = chain.process(iq);
Instantaneous phase (with unwrap). Set pm_sense_rad so that your expected phase deviation maps to ~±1.0 audio.
use orion_sdr::{
core::IqToAudioChain,
demodulate::PmQuadratureDemod,
};
use num_complex::Complex32 as C32;
let fs = 48_000.0;
let pm_sense_rad = 0.8; // radians peak phase deviation → ~±1.0 audio
let audio_bw_hz = 5_000.0;
let mut chain = IqToAudioChain::new(PmQuadratureDemod::new(pm_sense_rad, audio_bw_hz, fs));
// Optional: disable amplitude limiter on the demod if desired
// chain.demod_mut().set_limiter(false);
let iq: Vec<C32> = get_iq_block();
let audio = chain.process(iq);
FirDecimator cutoff/transition relative to the post-decim rate).