diff --git a/src/main.rs b/src/main.rs index 73be544..efbdf95 100644 --- a/src/main.rs +++ b/src/main.rs @@ -108,71 +108,51 @@ impl SampleSender for WavSampleSender { } struct FSKReceiver { - pos_correllator: FIRFilter, - neg_correllator: FIRFilter, eye_sender: Sender>, - matched_lowpass: FIRFilter, + phase_lowpass: FIRFilter, elg: ELGate, - dc_block: DCBlocker, last_byte: u8, frame_constructor: FrameConstructor, bit_count: Option, + last_sample: Complex32, } impl FSKReceiver { fn new(eye_sender: Sender>) -> Self { let samples_per_symbol = (SAMPLE_RATE as f32) / (BAUD_RATE as f32); - let correllator_length = samples_per_symbol as usize; - let mut pos_nco = Nco::new(hz_to_rad_per_sample(DEVIATION, SAMPLE_RATE as f32)); - let mut neg_nco = Nco::new(hz_to_rad_per_sample(-DEVIATION, SAMPLE_RATE as f32)); - let pos_ir = (0..correllator_length).map(|i| { - pos_nco.step(); - pos_nco.cexp() * windows::blackmann(i as f32 / correllator_length as f32) - }); - let neg_ir = (0..correllator_length).map(|i| { - neg_nco.step(); - neg_nco.cexp() * windows::blackmann(i as f32 / correllator_length as f32) - }); - let mut pos_correllator = FIRFilter::new(&pos_ir.collect::>()); - let mut neg_correllator = FIRFilter::new(&neg_ir.collect::>()); - pos_correllator.normalize_freq(hz_to_rad_per_sample(DEVIATION, SAMPLE_RATE as f32)); - neg_correllator.normalize_freq(hz_to_rad_per_sample(-DEVIATION, SAMPLE_RATE as f32)); - - let mut matched_lowpass = FIRFilter::new(&vec![ + let mut phase_lowpass = FIRFilter::new(&vec![ Complex32::new(1., 0.); samples_per_symbol as usize / 2 ]); - matched_lowpass.normalize_freq(hz_to_rad_per_sample(DEVIATION, SAMPLE_RATE as f32)); + phase_lowpass.normalize_dc(); //let mut dc_block = DCBlocker::new(0.999); - let mut dc_block = DCBlocker::new(1.); + //let mut dc_block = DCBlocker::new(1.); let loop_i = 0.03; let loop_p = 0.1; let mut loop_ir = vec![Complex32::new(loop_i, 0.); samples_per_symbol as usize / 2]; loop_ir.push(Complex32::new(loop_p, 0.)); - let mut elg = ELGate::new(samples_per_symbol, FIRFilter::new(&loop_ir)); + let elg = ELGate::new(samples_per_symbol, FIRFilter::new(&loop_ir)); Self { //iq_sampler: IQSampler::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32)), - pos_correllator, - neg_correllator, - matched_lowpass, - dc_block, + phase_lowpass, elg, last_byte: 0x00u8, frame_constructor: FrameConstructor::new(), bit_count: None, eye_sender, + last_sample: Complex32::new(1., 0.), } } async fn receive(&mut self, iq: Complex32) -> Result, FrameConstructionError> { // Frame reconstruction - let matched = - self.matched_lowpass.next_real(self.dc_block.next_real( - self.pos_correllator.next(iq).mag() - self.neg_correllator.next(iq).mag(), - )); - if let Some((bit_sample, eye)) = self.elg.next_eye(matched) { + let dphi = self + .phase_lowpass + .next_real((self.last_sample.conj() * iq).arg()); + self.last_sample = iq; + if let Some((bit_sample, eye)) = self.elg.next_eye(dphi) { let _ = self.eye_sender.send(eye).await; self.last_byte >>= 1; self.last_byte |= ((bit_sample > 0.) as u8) << 7; @@ -321,19 +301,47 @@ impl Transceiver { pub async fn transmit(frame: Frame, samples_sender: &mut Sender>) { let bytes = frame.bytes(); - let mut bit_stream = bytes.iter().flat_map(|x| byte_to_bits(*x)); - let modulator = BFSKMod::new( - (SAMPLE_RATE as f32 / BAUD_RATE as f32).round() as u32, - hz_to_rad_per_sample(DEVIATION, SAMPLE_RATE as f32), - &mut bit_stream, - ); + let data = bytes + .iter() + .flat_map(|x| byte_to_bits(*x)) + .collect::>(); - let up_lo = Nco::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32)); - let mut samples = vec![]; - for (m, up) in modulator.zip(up_lo) { - let sample = m * up; - samples.push(sample.re); + let sample_per_symbols = SAMPLE_RATE / BAUD_RATE; + let bitstream = (0..(bytes.len() * 8 * sample_per_symbols as usize)).map(|i| { + if data[i / sample_per_symbols as usize] { + 1. + } else { + -1. + } + }); + + // Synthesise impulse response + let mut impulse_response = + vec![Complex32::zero(); sample_per_symbols as usize].into_boxed_slice(); + for (i, x) in impulse_response.iter_mut().enumerate() { + *x = Complex32::new( + windows::gaussian(0.3, i as f32 / sample_per_symbols as f32), + 0., + ); } + + let mut gaussian_filter = FIRFilter::new(&impulse_response); + gaussian_filter.normalize_dc(); + let filtered_bitstream = bitstream.map(|x| gaussian_filter.next_real(x)); + + let mut nco = Nco::new(0.); + let mut lo = Nco::new(hz_to_rad_per_sample(CENTER_FREQ, SAMPLE_RATE as f32)); + + // Generate passband + let samples = filtered_bitstream + .map(|f| { + nco.set_frequency(hz_to_rad_per_sample(f * DEVIATION, SAMPLE_RATE as f32)); + nco.step_n(1); + lo.step_n(1); + (nco.cexp() * lo.cexp()).re + }) + .collect::>(); + let len = samples.len(); samples_sender.send(samples).await.unwrap(); tokio::time::sleep(Duration::from_secs_f32(len as f32 / SAMPLE_RATE as f32)).await; diff --git a/src/windows.rs b/src/windows.rs index f0309e9..0d18945 100644 --- a/src/windows.rs +++ b/src/windows.rs @@ -10,18 +10,20 @@ pub fn bartlett(t: f32) -> f32 { if t < 0.5 { 2. * t } else { 2. - 2. * t } } -pub fn hann(t: f32) -> f32 -{ +pub fn hann(t: f32) -> f32 { 0.5 - 0.5 * (2. * PI * t).cos() } -pub fn hamming(t: f32) -> f32 -{ +pub fn hamming(t: f32) -> f32 { 0.54 - 0.46 * (2. * PI * t).cos() } -pub fn blackmann(t: f32) -> f32 -{ +pub fn blackmann(t: f32) -> f32 { let x = 2. * PI * t; 0.45 - 0.5 * x.cos() + 0.08 * (2. * x).cos() } + +pub fn gaussian(sigma: f32, t: f32) -> f32 { + let sq = (t - 0.5) / sigma; + (-sq * sq).exp() +}