Correlation bfsk fir design
This commit is contained in:
236
src/main.rs
236
src/main.rs
@ -3,6 +3,7 @@
|
||||
use std::{
|
||||
f32::consts::PI,
|
||||
fs::File,
|
||||
i16,
|
||||
io::{Read, Write},
|
||||
ops::{Add, Div, Mul, Sub},
|
||||
};
|
||||
@ -21,33 +22,22 @@ use complex::Complex;
|
||||
use complex::Complex32;
|
||||
use fft::DFTAlgorithm;
|
||||
use nco::Nco;
|
||||
use plotters::prelude::*;
|
||||
|
||||
use eframe::egui::{self, Color32, debug_text::print};
|
||||
use egui_plot::{self, Bar, BarChart, Legend, Line, LineStyle, Plot, PlotPoints};
|
||||
use plotters::style::Color;
|
||||
|
||||
use crate::{
|
||||
bfsk::BFSKDem,
|
||||
fft::{
|
||||
FFT, FFTDirection, create_fft,
|
||||
dft::NaiveDFT,
|
||||
mixed_radix::MixedRadixFFT,
|
||||
prime_factors,
|
||||
rader::{RaderFFT, compute_prime_primitive_root, exp_mod},
|
||||
rader2::{Rader2FFT, next_pow2},
|
||||
radix2::Radix2FFT,
|
||||
windows,
|
||||
fft::{FFT, dft::NaiveDFT},
|
||||
filtering::{
|
||||
fir::FIRFilter,
|
||||
impulse_response::design::{self, frequency_response, ir_from_transfer_function},
|
||||
},
|
||||
iq::IQSampler,
|
||||
units::frequency::{self, hz_to_rad_per_sample},
|
||||
};
|
||||
|
||||
struct QuickLCG(i32);
|
||||
impl QuickLCG {
|
||||
pub fn seed(val: i32) -> QuickLCG {
|
||||
QuickLCG(val % 10)
|
||||
}
|
||||
pub fn next(&mut self) -> i32 {
|
||||
self.0 = self.0.overflowing_mul(9321).0.overflowing_add(5672).0 % 10;
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
// Utilities
|
||||
fn map<T>(input: T, in_min: T, in_max: T, out_min: T, out_max: T) -> T
|
||||
where
|
||||
@ -58,17 +48,185 @@ where
|
||||
|
||||
fn main() {
|
||||
modulate();
|
||||
//œtest();
|
||||
println!("Demodulating");
|
||||
//demodulate();
|
||||
let native_options = eframe::NativeOptions::default();
|
||||
let _ = eframe::run_native("Egui", native_options, Box::new(|cc| Ok(Box::new(EguiApp::new(cc)))));
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct EguiApp {
|
||||
samples: Vec<f32>,
|
||||
|
||||
iq: Vec<Complex32>,
|
||||
dem: Vec<f32>,
|
||||
}
|
||||
const BAUD_RATE: u32 = 1000;
|
||||
|
||||
impl EguiApp {
|
||||
fn new(cc: &eframe::CreationContext<'_>) -> Self {
|
||||
let mut reader = hound::WavReader::open("audio/modulated.wav").unwrap();
|
||||
let samples = reader.samples::<i16>();
|
||||
let input_test = samples
|
||||
.take(10_000)
|
||||
.map(|x| x.unwrap() as f32 / i16::MAX as f32)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// Modulation parameters
|
||||
let frequency = 1700.;
|
||||
let deviation = 500.;
|
||||
|
||||
// Data parameters
|
||||
let sample_rate = 48000;
|
||||
let baud_rate = BAUD_RATE;
|
||||
|
||||
let mut iq_sampler = IQSampler::new(hz_to_rad_per_sample(frequency, sample_rate as f32));
|
||||
let iq = input_test
|
||||
.iter()
|
||||
.map(|x| iq_sampler.sample(*x))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut dem = BFSKDem::new(
|
||||
sample_rate / baud_rate,
|
||||
hz_to_rad_per_sample(deviation, sample_rate as f32),
|
||||
);
|
||||
let mut demodulated = vec![];
|
||||
|
||||
for x in iq.chunks((sample_rate / baud_rate) as usize) {
|
||||
let samples = x
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(std::iter::repeat(Complex32::zero()))
|
||||
.take((sample_rate / baud_rate) as usize)
|
||||
.collect::<Vec<_>>();
|
||||
demodulated.push(dem.demod(&samples));
|
||||
}
|
||||
|
||||
Self {
|
||||
samples: input_test.clone(),
|
||||
iq,
|
||||
dem: demodulated
|
||||
.iter()
|
||||
.map(|b| if *b { 1. } else { 0. })
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl eframe::App for EguiApp {
|
||||
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.heading("Hello World!");
|
||||
Plot::new("Fourrier transform")
|
||||
.legend(Legend::default())
|
||||
.show(ui, |plot_ui| {
|
||||
plot_ui.line(
|
||||
Line::new(
|
||||
"Transfer function",
|
||||
self.samples
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, x)| [i as f64 / self.samples.len() as f64, *x as f64])
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.width(2.),
|
||||
);
|
||||
|
||||
plot_ui.line(
|
||||
Line::new(
|
||||
"RE",
|
||||
self.iq
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, x)| [i as f64 / self.iq.len() as f64, x.re as f64])
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.width(2.),
|
||||
);
|
||||
|
||||
plot_ui.line(
|
||||
Line::new(
|
||||
"IM",
|
||||
self.iq
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, x)| [i as f64 / self.iq.len() as f64, x.im as f64])
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.width(2.),
|
||||
);
|
||||
|
||||
plot_ui.line(
|
||||
Line::new(
|
||||
"Bits",
|
||||
self.iq
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, x)| {
|
||||
[
|
||||
i as f64 / self.iq.len() as f64,
|
||||
self.dem[(self.dem.len() as f32 * i as f32
|
||||
/ self.iq.len() as f32)
|
||||
.floor()
|
||||
as usize]
|
||||
as f64,
|
||||
]
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.width(2.),
|
||||
);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn demodulate() {
|
||||
let mut reader = hound::WavReader::open("audio/modulated.wav").unwrap();
|
||||
let samples = reader.samples::<i16>();
|
||||
|
||||
// Modulation parameters
|
||||
let frequency = 1700.;
|
||||
let deviation = 500.;
|
||||
|
||||
// Data parameter
|
||||
let sample_rate = 48000;
|
||||
let baud_rate = BAUD_RATE;
|
||||
|
||||
let mut iq_sampler = IQSampler::new(hz_to_rad_per_sample(frequency, sample_rate as f32));
|
||||
let iq_samples = samples
|
||||
.map(|x| iq_sampler.sample(x.unwrap() as f32 / i16::MAX as f32))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut dem = BFSKDem::new(
|
||||
sample_rate / baud_rate,
|
||||
hz_to_rad_per_sample(deviation, sample_rate as f32),
|
||||
);
|
||||
let mut bits = vec![];
|
||||
|
||||
for x in iq_samples.chunks((sample_rate / baud_rate) as usize) {
|
||||
// Zero pad
|
||||
//let zero_padded = x.iter().copied().chain(std::iter::repeat(Complex32::zero())).take(sample_rate as usize / baud_rate as usize).collect::<Vec<_>>();
|
||||
//bits.push(dem.demod(&zero_padded));
|
||||
bits.push(dem.demod(x));
|
||||
}
|
||||
|
||||
assert!(bits.len() % 8 == 0);
|
||||
|
||||
let mut out_file = File::create("out.txt").unwrap();
|
||||
for x in bits.chunks(8) {
|
||||
out_file.write_all(&[!bits_to_byte(x)]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn modulate() {
|
||||
// Modulation parameters
|
||||
let frequency = 2000.;
|
||||
let frequency = 1700.;
|
||||
let deviation = 500.;
|
||||
|
||||
// Data parameters
|
||||
let sample_rate = 44100;
|
||||
let baud_rate = 400;
|
||||
// Data parameter
|
||||
let sample_rate = 48000;
|
||||
let baud_rate = BAUD_RATE;
|
||||
|
||||
// File to modulate
|
||||
let f = File::open("s.txt").unwrap();
|
||||
@ -92,7 +250,7 @@ fn modulate() {
|
||||
sample_format: hound::SampleFormat::Int,
|
||||
};
|
||||
|
||||
let mut writer = hound::WavWriter::create("sine.wav", spec).unwrap();
|
||||
let mut writer = hound::WavWriter::create("audio/modulated.wav", spec).unwrap();
|
||||
for (s, up) in modulator.zip(lo) {
|
||||
let sample = (s * up).re; // Project to I coords
|
||||
let amplitude = i16::MAX as f32;
|
||||
@ -113,3 +271,27 @@ fn byte_to_bits(byte: u8) -> Vec<bool> {
|
||||
(byte >> 7) & 1 == 1,
|
||||
]
|
||||
}
|
||||
|
||||
/*
|
||||
fn bits_to_byte(bits: &[bool]) -> u8 {
|
||||
bits[7] as u8 |
|
||||
bits[6] as u8 >> 1 |
|
||||
bits[5] as u8 >> 2 |
|
||||
bits[4] as u8 >> 3 |
|
||||
bits[3] as u8 >> 4 |
|
||||
bits[2] as u8 >> 5 |
|
||||
bits[1] as u8 >> 6 |
|
||||
bits[0] as u8 >> 7
|
||||
}
|
||||
*/
|
||||
|
||||
fn bits_to_byte(bits: &[bool]) -> u8 {
|
||||
bits[0] as u8
|
||||
| (bits[1] as u8) << 1
|
||||
| (bits[2] as u8) << 2
|
||||
| (bits[3] as u8) << 3
|
||||
| (bits[4] as u8) << 4
|
||||
| (bits[5] as u8) << 5
|
||||
| (bits[6] as u8) << 6
|
||||
| (bits[7] as u8) << 7
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user