orion-sdr 0.0.21

DSP/SDR block library targeting HF-to-UHF, satellites, and Python bindings. Roadmap inside.
Documentation

use crate::modulate::{Ft4Mod, Ft4Frame};
use crate::modulate::ft4::{FT4_FRAME_LEN, FT4_TOTAL_SYMS, FT4_DATA_SYMS};

#[test]
fn ft4_frame_length() {
    let tx = Ft4Mod::new(12_000.0, 1_000.0, 0.0, 1.0);
    let iq = tx.modulate(&Ft4Frame::zeros());
    assert_eq!(iq.len(), FT4_FRAME_LEN, "FT4 frame length mismatch");
}

#[test]
fn ft4_symbol_sequence_count() {
    let seq = Ft4Mod::build_symbol_sequence(&Ft4Frame::zeros());
    assert_eq!(seq.len(), FT4_TOTAL_SYMS);
    let sync_pos: [(usize, usize); 4] = [(1, 5), (34, 38), (67, 71), (100, 104)];
    let mut is_reserved = [false; FT4_TOTAL_SYMS];
    is_reserved[0] = true;
    is_reserved[104] = true;
    for &(start, end) in &sync_pos { for p in start..end { is_reserved[p] = true; } }
    let data_count = is_reserved.iter().filter(|&&s| !s).count();
    assert_eq!(data_count, FT4_DATA_SYMS);
}

#[test]
fn ft4_costas_positions_correct() {
    let costas: [[u8; 4]; 4] = [[0,1,3,2],[1,0,2,3],[2,3,1,0],[3,2,0,1]];
    let sync_starts = [1usize, 34, 67, 100];
    let seq = Ft4Mod::build_symbol_sequence(&Ft4Frame::zeros());
    assert_eq!(seq[0], 0, "FT4 ramp at position 0 should be tone 0");
    assert_eq!(seq[104], 0, "FT4 ramp at position 104 should be tone 0");
    for (blk, &start) in sync_starts.iter().enumerate() {
        for i in 0..4 {
            assert_eq!(seq[start + i], costas[blk][i],
                "FT4 Costas mismatch blk {} sym {}: got {}, expected {}",
                blk, i, seq[start + i], costas[blk][i]);
        }
    }
}

#[test]
fn ft4_iq_power_unity() {
    let tx = Ft4Mod::new(12_000.0, 1_000.0, 0.0, 1.0);
    let iq = tx.modulate(&Ft4Frame::zeros());
    let power: f32 = iq.iter().map(|z| z.norm_sqr()).sum::<f32>() / (FT4_FRAME_LEN as f32);
    assert!((power - 1.0).abs() < 0.01, "FT4 IQ power deviates from 1.0: {}", power);
}