From: Thomas Karpiniec Date: Wed, 8 Jan 2025 09:35:44 +0000 (+1100) Subject: Convolutional encoding X-Git-Url: https://code.octet-stream.net/m17rt/commitdiff_plain/f9af623dd10c967733af7bfb5efa20fbc7033072 Convolutional encoding --- diff --git a/.gitignore b/.gitignore index eb5a316..54e04cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ target +*.kate-swp diff --git a/demod/src/main.rs b/demod/src/main.rs index 563b721..d0e562d 100755 --- a/demod/src/main.rs +++ b/demod/src/main.rs @@ -4,9 +4,9 @@ use m17codec2::Codec2Adapter; use std::path::PathBuf; pub fn m17app_test() { - //let path = PathBuf::from("../../Data/test_vk7xt.rrc"); - //let source = InputRrcFile::new(path); - let source = InputSoundcard::new(); + let path = PathBuf::from("../../Data/test_vk7xt.rrc"); + let source = InputRrcFile::new(path); + //let source = InputSoundcard::new(); let soundmodem = Soundmodem::new_with_input(source); let app = M17App::new(soundmodem); app.add_stream_adapter(Codec2Adapter::new()); diff --git a/m17core/src/decode.rs b/m17core/src/decode.rs index ba21a27..de13124 100755 --- a/m17core/src/decode.rs +++ b/m17core/src/decode.rs @@ -88,6 +88,7 @@ pub(crate) fn frame_initial_decode(frame: &[f32] /* length 192 */) -> [u8; 46] { pub(crate) fn parse_lsf(frame: &[f32] /* length 192 */) -> Option { let deinterleaved = frame_initial_decode(frame); + debug!("deinterleaved: {:?}", deinterleaved); let lsf = match fec::decode(&deinterleaved, 240, p_1) { Some(lsf) => LsfFrame(lsf), None => return None, diff --git a/m17core/src/encode.rs b/m17core/src/encode.rs new file mode 100644 index 0000000..70fe012 --- /dev/null +++ b/m17core/src/encode.rs @@ -0,0 +1,3 @@ +use crate::protocol::LsfFrame; + +pub(crate) fn encode_lsf(frame: &LsfFrame) {} diff --git a/m17core/src/fec.rs b/m17core/src/fec.rs index 0716be0..5a49f87 100755 --- a/m17core/src/fec.rs +++ b/m17core/src/fec.rs @@ -269,3 +269,91 @@ pub(crate) fn decode( Some(out) } } + +/// Perform convolutional encoding on payload. +/// +/// Four flush bits will be appended automatically. +/// +/// Parameters: +/// * `type1`: Type 1 bits, maximum length 30 bytes +/// * `input_len`: Number of type 1 bits, up to 240 +/// * `puncture`: Puncturing scheme - `p_1`, `p_2` or `p_3` +/// +/// Returns up to 368 type 3 bits. Caller is responsible for knowing the number of +/// filled bits in the returned array, which is known statically by the type of +/// payload and puncturing scheme in use. +pub(crate) fn encode( + type1: &[u8], + input_len: usize, + puncture: fn(usize) -> (bool, bool), +) -> [u8; 46] { + let mut out = [0u8; 46]; + let bits = Bits::new(type1); + let mut out_idx = 0; + let mut out_bits = BitsMut::new(&mut out); + let mut state: u8 = 0; + for (t1_idx, b) in bits + .iter() + .take(input_len) + .chain(core::iter::repeat_n(0, 4)) + .enumerate() + { + let (use_g1, use_g2) = puncture(t1_idx); + if use_g1 { + let g1 = (b + ((state & 0x02) >> 1) + (state & 0x01)) & 0x01; + out_bits.set_bit(out_idx, g1); + out_idx += 1; + } + if use_g2 { + let g2 = (b + ((state & 0x08) >> 3) + ((state & 0x04) >> 2) + (state & 0x01)) & 0x01; + out_bits.set_bit(out_idx, g2); + out_idx += 1; + } + state = (state >> 1) | (b << 3); + } + out +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn lsf_fec_round_trip() { + let lsf = [ + 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 131, 53, + ]; + let expected_encoded = [ + 222, 73, 36, 146, 73, 37, 182, 219, 109, 76, 0, 0, 0, 5, 191, 47, 25, 186, 30, 214, + 237, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 153, 208, + 119, + ]; + let encoded = encode(&lsf, 240, p_1); + assert_eq!(encoded, expected_encoded); + let decoded = decode(&encoded, 240, p_1); + assert_eq!(decoded, Some(lsf)); + } + + #[test] + fn fec_damage() { + let lsf = [ + 255, 255, 255, 255, 255, 255, 0, 0, 0, 159, 221, 81, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 131, 53, + ]; + let mut encoded = encode(&lsf, 240, p_1); + + // progressively flip more bits + for idx in [50, 90, 51, 200, 15, 7, 100] { + let mut bits = BitsMut::new(&mut encoded); + let bit = bits.get_bit(idx); + bits.set_bit(idx, if bit == 1 { 0 } else { 1 }); + let decoded = decode(&encoded, 240, p_1); + if idx == 100 { + assert_eq!(decoded, None); // 7 bits is too much damage + } else { + assert_eq!(decoded, Some(lsf)); // recovered from errors + } + } + } +} diff --git a/m17core/src/lib.rs b/m17core/src/lib.rs index b10427b..eb4a457 100755 --- a/m17core/src/lib.rs +++ b/m17core/src/lib.rs @@ -10,6 +10,7 @@ pub mod tnc; mod bits; mod decode; +mod encode; mod fec; mod interleave; mod random;