Adds pulse shaping, work stealing

This commit is contained in:
2026-04-09 16:33:42 +02:00
parent 4d548a7973
commit 54f26a0dd2
32 changed files with 1305 additions and 340 deletions

View File

@ -6,6 +6,7 @@ use oxydsp_dsp::blocks::filtering::fir::FirFilter;
use oxydsp_dsp::blocks::math::basic::Multiplier;
use oxydsp_dsp::blocks::synthesis::Nco;
use oxydsp_dsp::blocks::synthesis::OscillatorSource;
use oxydsp_dsp::blocks::utilities::adapters::FlatMap;
use oxydsp_dsp::blocks::utilities::adapters::Map;
use oxydsp_dsp::blocks::utilities::adapters::Repeat;
use oxydsp_dsp::blocks::utilities::adapters::Scan;

View File

@ -33,6 +33,7 @@ use oxydsp_dsp::filtering::fir::Fir;
use oxydsp_dsp::units::DigitalFrequency;
use oxydsp_flowgraph::block::BlockResult;
use oxydsp_flowgraph::flowgraph;
use oxydsp_flowgraph::io::AnonymousIn;
use oxydsp_flowgraph::tag::Tags;
use rand::random;

View File

@ -0,0 +1,16 @@
[package]
name = "qpsk-modem"
version = "0.1.0"
edition = "2024"
[dependencies]
oxydsp-flowgraph = {path = "../../oxydsp-flowgraph/"}
oxydsp-dsp = {path = "../../oxydsp-dsp/"}
egui = "0.33.3"
egui_plot = "0.34.1"
eframe = { version = "0.33.3", features = ["default_fonts", "wayland"] }
num = "0.4.3"
hound = "3.5.1"
rand = "0.10.0"
cpal = "0.17.3"
rand_distr = "0.6.0"

View File

@ -0,0 +1,85 @@
use std::time::Instant;
use num::Complex;
use oxydsp_dsp::blocks::filtering::fir::FirFilter;
use oxydsp_dsp::blocks::filtering::pulse_shaping::PulseShaper;
use oxydsp_dsp::blocks::iq::zero_if::ZeroIf;
use oxydsp_dsp::blocks::math::basic::Multiplier;
use oxydsp_dsp::blocks::synthesis::OscillatorSource;
use oxydsp_dsp::blocks::utilities::adapters::{Map, NullSink, Scan};
use oxydsp_dsp::blocks::utilities::iter::IterSource;
use oxydsp_dsp::filtering::fir::Fir;
use oxydsp_dsp::units::DigitalFrequency;
use oxydsp_flowgraph::flowgraph;
use rand::{RngExt, SeedableRng, random};
const CARRRIER_FREQ: f64 = 1000.;
const SAMPLE_RATE: usize = 48_000;
fn main()
{
let bits = (0..1024).map(|_| [random::<bool>(), random::<bool>()]);
let (iter_source, bits) = IterSource::new(bits.cycle());
let (iq_map, iq) = Map::new(bits, |x| match x
{
[true, true] => Complex::new(1., 1.),
[true, false] => Complex::new(1., -1.),
[false, true] => Complex::new(-1., 1.),
[false, false] => Complex::new(-1., -1.),
});
let (pulse_shaper, iq) = PulseShaper::new(iq, Fir::square(200), 200);
let (lo, carrier) = OscillatorSource::new(DigitalFrequency::from_time_frequency(CARRRIER_FREQ, SAMPLE_RATE as f64).into());
let (mixer, passband) = Multiplier::new(iq, carrier);
let (channel, passband) = Scan::new(passband, rand::rngs::SmallRng::seed_from_u64(0), |state, x|
{
x.re + state.sample::<f32, _>(rand_distr::StandardNormal)
});
let (zero_if, iq) = ZeroIf::new(passband, DigitalFrequency::from_time_frequency(CARRRIER_FREQ, SAMPLE_RATE as f64).into());
let (matched_filter, iq) = FirFilter::new(iq, Fir::<f32>::square(200));
let (inspect, iq) = Scan::new(iq, (Instant::now(), 0), |(last, counter), x|
{
*counter += 1;
if *counter >= 1_000_000
{
let time = Instant::now() - *last;
println!("{:.2} Ms/s", 1. / time.as_secs_f32());
*last = Instant::now();
*counter = 0;
}
x
});
let null_sink = NullSink::new(iq);
let graph = flowgraph![iter_source, iq_map, pulse_shaper, lo, mixer, channel, zero_if, matched_filter, inspect, null_sink];
graph.run(6).join();
}
pub fn to_bits(n: u8) -> [bool; 8]
{
[
(n & 1) == 1,
(n >> 1) & 1 == 1,
(n >> 2) & 1 == 1,
(n >> 3) & 1 == 1,
(n >> 4) & 1 == 1,
(n >> 5) & 1 == 1,
(n >> 6) & 1 == 1,
(n >> 7) & 1 == 1,
]
}
pub fn from_bits(n: [bool; 8]) -> u8
{
(n[0] as u8)
| ((n[1] as u8) << 1)
| ((n[2] as u8) << 2)
| ((n[3] as u8) << 3)
| ((n[4] as u8) << 4)
| ((n[5] as u8) << 5)
| ((n[6] as u8) << 6)
| ((n[7] as u8) << 7)
}