Starting fsk demod
This commit is contained in:
BIN
example/mod.wav
BIN
example/mod.wav
Binary file not shown.
@ -8,14 +8,16 @@ Repeat_2 [label="{ {<i0> input}| Repeat |{<o0> output} }"];
|
||||
Nco_3 [label="{ {<i0> frequency}| Nco |{<o0> output} }"];
|
||||
OscillatorSource_4 [label="{ OscillatorSource |{<o0> output} }"];
|
||||
Multiplier_5 [label="{ {<i0> input_a|<i1> input_b}| Multiplier |{<o0> output} }"];
|
||||
TxSink_6 [label="{ {<i0> input}| TxSink }"];
|
||||
MapResultTagged_6 [label="{ {<i0> input}| MapResultTagged |{<o0> output} }"];
|
||||
NullSink_7 [label="{ {<i0> input}| NullSink }"];
|
||||
|
||||
IterSource_0:o0 -> Map_1:i0 [label="bool"];
|
||||
Map_1:o0 -> Repeat_2:i0 [label="oxydsp_dsp::units::DigitalFrequency"];
|
||||
Repeat_2:o0 -> Nco_3:i0 [label="oxydsp_dsp::units::DigitalFrequency"];
|
||||
Nco_3:o0 -> Multiplier_5:i0 [label="num_complex::Complex<f32>"];
|
||||
OscillatorSource_4:o0 -> Multiplier_5:i1 [label="num_complex::Complex<f32>"];
|
||||
Multiplier_5:o0 -> TxSink_6:i0 [label="num_complex::Complex<f32>"];
|
||||
Multiplier_5:o0 -> MapResultTagged_6:i0 [label="num_complex::Complex<f32>"];
|
||||
MapResultTagged_6:o0 -> NullSink_7:i0 [label="num_complex::Complex<f32>"];
|
||||
|
||||
}
|
||||
|
||||
@ -4,17 +4,30 @@ use std::io::Write;
|
||||
use std::sync::mpsc;
|
||||
|
||||
use eframe::NativeOptions;
|
||||
use egui::Color32;
|
||||
use egui_plot::Line;
|
||||
use egui_plot::MarkerShape;
|
||||
use egui_plot::PlotPoints;
|
||||
use egui_plot::Points;
|
||||
use egui_plot::Polygon;
|
||||
use egui_plot::VLine;
|
||||
use num::Complex;
|
||||
use num::Zero;
|
||||
use oxydsp_dsp::blocks::filtering::fir::FirFilter;
|
||||
use oxydsp_dsp::blocks::math::basic::Adder;
|
||||
use oxydsp_dsp::blocks::math::basic::Multiplier;
|
||||
use oxydsp_dsp::blocks::synthesis::Nco;
|
||||
use oxydsp_dsp::blocks::synthesis::OscillatorSource;
|
||||
use oxydsp_dsp::blocks::ted::early_late::EarlyLateGate;
|
||||
use oxydsp_dsp::blocks::utilities::adapters::Map;
|
||||
use oxydsp_dsp::blocks::utilities::adapters::MapResult;
|
||||
use oxydsp_dsp::blocks::utilities::adapters::MapResultTagged;
|
||||
use oxydsp_dsp::blocks::utilities::adapters::NullSink;
|
||||
use oxydsp_dsp::blocks::utilities::adapters::Repeat;
|
||||
use oxydsp_dsp::blocks::utilities::adapters::Scan;
|
||||
use oxydsp_dsp::blocks::utilities::channels::TxSink;
|
||||
use oxydsp_dsp::blocks::utilities::iter::IterSource;
|
||||
use oxydsp_dsp::filtering::fir::Fir;
|
||||
use oxydsp_dsp::units::DigitalFrequency;
|
||||
use oxydsp_flowgraph::BlockIO;
|
||||
use oxydsp_flowgraph::block::Block;
|
||||
@ -170,6 +183,11 @@ impl<T: 'static + Display> Printer<T>
|
||||
}
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
main_demod()
|
||||
}
|
||||
|
||||
fn main_tst()
|
||||
{
|
||||
let (sourcea, a) = SourceTag::new("valuea".to_string());
|
||||
@ -181,22 +199,140 @@ fn main_tst()
|
||||
let _ = fg.run().join();
|
||||
}
|
||||
|
||||
fn main()
|
||||
{
|
||||
let sample_rate = 48_000;
|
||||
let sample_per_symbol = 96;
|
||||
let deviation = DigitalFrequency::from_time_frequency(500., sample_rate as f64);
|
||||
let carrier = DigitalFrequency::from_time_frequency(1000., sample_rate as f64);
|
||||
const SAMPLE_RATE: usize = 48_000;
|
||||
const SAMPLE_PER_SYMBOL: usize = 96;
|
||||
const DEVIATION: f64 = 500.;
|
||||
const CARRIER: f64 = 1000.;
|
||||
|
||||
fn main_demod()
|
||||
{
|
||||
let carrier = DigitalFrequency::from_time_frequency(CARRIER, SAMPLE_RATE as f64);
|
||||
|
||||
let mut reader = hound::WavReader::open("mod.wav").unwrap();
|
||||
let sqr_sum = reader
|
||||
.samples::<i16>()
|
||||
.map(|sample| (sample.unwrap() as f32) / (i16::MAX as f32))
|
||||
.collect::<Vec<_>>();
|
||||
let (iter_source, signal) = IterSource::new(sqr_sum.into_iter());
|
||||
|
||||
// Make an iq sampler
|
||||
let (lo, lo_signal) = OscillatorSource::new(carrier.into());
|
||||
let (mixer, iq) = Multiplier::new(signal, lo_signal);
|
||||
let (iq_bandpass, iq) = FirFilter::<Complex<f32>, Complex<f32>, Complex<f32>>::new(
|
||||
iq,
|
||||
Fir::lowpass(carrier, 100).normalized(),
|
||||
);
|
||||
let (arg_extract, arg) = Scan::new(iq, Complex::zero(), |state, sample| {
|
||||
let angle = *state / sample;
|
||||
*state = sample;
|
||||
angle.arg()
|
||||
});
|
||||
let (sig_lowpass, arg) =
|
||||
FirFilter::<f32, f32, f32>::new(arg, Fir(vec![1.; SAMPLE_PER_SYMBOL]).normalized());
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
||||
let elg_loop = Fir(vec![1.0f32; 10]);
|
||||
let mut elg_loop = elg_loop.normalized();
|
||||
elg_loop.0[0] = 0.5;
|
||||
let (elg, arg) = EarlyLateGate::new(arg, elg_loop, SAMPLE_PER_SYMBOL);
|
||||
let (sender, arg) = MapResultTagged::new(arg, move |x| {
|
||||
let _ = tx.send((
|
||||
x.0,
|
||||
x.1.as_ref()
|
||||
.is_some_and(|t| t.retrieve("elg_symbol").is_some()),
|
||||
));
|
||||
if x.1
|
||||
.is_some_and(|t| t.retrieve("itersource_finished").is_some())
|
||||
{
|
||||
println!("FINISHED !");
|
||||
(x.0.into(), BlockResult::Exit)
|
||||
}
|
||||
else
|
||||
{
|
||||
(x.0.into(), BlockResult::Ok)
|
||||
}
|
||||
});
|
||||
let null_sink = NullSink::new(arg);
|
||||
|
||||
let graph = flowgraph![
|
||||
iter_source,
|
||||
lo,
|
||||
mixer,
|
||||
iq_bandpass,
|
||||
arg_extract,
|
||||
sig_lowpass,
|
||||
elg,
|
||||
sender,
|
||||
null_sink
|
||||
];
|
||||
let j = graph.run();
|
||||
|
||||
let mut output = vec![];
|
||||
while let Ok(x) = rx.recv()
|
||||
{
|
||||
output.push(x);
|
||||
}
|
||||
let _ = j.join();
|
||||
|
||||
eframe::run_simple_native("Plot", NativeOptions::default(), move |ctx, _frame| {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
egui_plot::Plot::new("hello").show(ui, |plot_ui| {
|
||||
plot_ui.line(Line::new(
|
||||
"samples",
|
||||
output
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, s)| [i as f64, s.0 as f64])
|
||||
.collect::<PlotPoints>(),
|
||||
));
|
||||
|
||||
plot_ui.points(
|
||||
Points::new(
|
||||
"symbols",
|
||||
output
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, (_, x))| *x)
|
||||
.map(|(i, (s, _))| [i as f64, *s as f64])
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.id("symbols")
|
||||
.radius(5.)
|
||||
.shape(MarkerShape::Diamond),
|
||||
);
|
||||
});
|
||||
ctx.request_repaint();
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn main_mod()
|
||||
{
|
||||
let carrier = DigitalFrequency::from_time_frequency(CARRIER, SAMPLE_RATE as f64);
|
||||
let deviation = DigitalFrequency::from_time_frequency(DEVIATION, SAMPLE_RATE as f64);
|
||||
let data = (0..255u8).flat_map(to_bits).collect::<Vec<_>>();
|
||||
let (bit_stream, bits) = IterSource::new(data.into_iter());
|
||||
let (to_freq, freq) = Map::new(bits, move |x| [-deviation, deviation][x as usize]);
|
||||
let (repeat, freq) = Repeat::new(freq, sample_per_symbol);
|
||||
let (repeat, freq) = Repeat::new(freq, SAMPLE_PER_SYMBOL);
|
||||
let (base_oscillator, baseband) = Nco::<f32>::new(freq);
|
||||
let (local_oscillator, lo) = OscillatorSource::<f32>::new(carrier.into());
|
||||
let (frontend, passband) = Multiplier::new(baseband, lo);
|
||||
let (tx, rx) = mpsc::channel::<Complex<f32>>();
|
||||
let sink = TxSink::new(passband, tx);
|
||||
let (sender, passband) = MapResultTagged::new(passband, move |x| {
|
||||
let _ = tx.send(x.0);
|
||||
if x.1
|
||||
.is_some_and(|t| t.retrieve("itersource_finished").is_some())
|
||||
{
|
||||
println!("FINISHED !");
|
||||
(x.0.into(), BlockResult::Exit)
|
||||
}
|
||||
else
|
||||
{
|
||||
(x.0.into(), BlockResult::Ok)
|
||||
}
|
||||
});
|
||||
let null_sink = NullSink::new(passband);
|
||||
|
||||
let graph = flowgraph![
|
||||
bit_stream,
|
||||
@ -205,7 +341,8 @@ fn main()
|
||||
base_oscillator,
|
||||
local_oscillator,
|
||||
frontend,
|
||||
sink,
|
||||
sender,
|
||||
null_sink,
|
||||
];
|
||||
File::create("out.dot")
|
||||
.unwrap()
|
||||
@ -222,7 +359,7 @@ fn main()
|
||||
// Write signal
|
||||
let spec = hound::WavSpec {
|
||||
channels: 1,
|
||||
sample_rate,
|
||||
sample_rate: SAMPLE_RATE as u32,
|
||||
bits_per_sample: 16,
|
||||
sample_format: hound::SampleFormat::Int,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user