diff --git a/src/decoders/trx-ftx/src/common/decode.rs b/src/decoders/trx-ftx/src/common/decode.rs index 640f131..560a3ad 100644 --- a/src/decoders/trx-ftx/src/common/decode.rs +++ b/src/decoders/trx-ftx/src/common/decode.rs @@ -49,16 +49,7 @@ pub(crate) fn get_cand_offset(wf: &Waterfall, cand: &Candidate) -> usize { offset.max(0) as usize } -pub(crate) fn wf_mag_at(wf: &Waterfall, base: usize, idx: isize) -> &WfElem { - let i = (base as isize + idx).max(0) as usize; - if i < wf.mag.len() { - &wf.mag[i] - } else { - &DEFAULT_WF_ELEM - } -} - -// Leaked reference for out-of-bounds default +// Default element for out-of-bounds waterfall access pub(crate) static DEFAULT_WF_ELEM: WfElem = WfElem { mag: -120.0, phase: 0.0, @@ -256,8 +247,8 @@ pub fn pack_bits(bit_array: &[u8], num_bits: usize, packed: &mut [u8]) { } let mut mask: u8 = 0x80; let mut byte_idx = 0; - for i in 0..num_bits { - if bit_array[i] != 0 { + for &bit in bit_array.iter().take(num_bits) { + if bit != 0 { packed[byte_idx] |= mask; } mask >>= 1; @@ -312,19 +303,19 @@ pub fn ftx_post_decode_snr(wf: &Waterfall, cand: &Candidate, message: &FtxMessag let mut sum_snr = 0.0f32; let mut n_valid = 0; - for sym in 0..nn { + for (sym, &tone) in tones.iter().enumerate().take(nn) { let block_abs = cand.time_offset as i32 + sym as i32; if block_abs < 0 || block_abs >= wf.num_blocks as i32 { continue; } let p_offset = base + sym * wf.block_stride; - let sig_db = wf_mag_safe(wf, p_offset + tones[sym] as usize).mag; + let sig_db = wf_mag_safe(wf, p_offset + tone as usize).mag; let mut noise_min = 0.0f32; let mut found_noise = false; for t in 0..num_tones { - if t == tones[sym] as usize { + if t == tone as usize { continue; } let db = wf_mag_safe(wf, p_offset + t).mag; diff --git a/src/decoders/trx-ftx/src/common/encode.rs b/src/decoders/trx-ftx/src/common/encode.rs index dee0f9f..c33adfa 100644 --- a/src/decoders/trx-ftx/src/common/encode.rs +++ b/src/decoders/trx-ftx/src/common/encode.rs @@ -33,10 +33,10 @@ pub(crate) fn encode174(message: &[u8], codeword: &mut [u8]) { let mut col_idx: usize = FTX_LDPC_K_BYTES - 1; // Compute the LDPC checksum bits and store them in codeword - for i in 0..FTX_LDPC_M { + for gen_row in FTX_LDPC_GENERATOR.iter().take(FTX_LDPC_M) { let mut nsum: u8 = 0; for j in 0..FTX_LDPC_K_BYTES { - nsum ^= parity8(message[j] & FTX_LDPC_GENERATOR[i][j]); + nsum ^= parity8(message[j] & gen_row[j]); } if !nsum.is_multiple_of(2) { @@ -55,7 +55,7 @@ pub(crate) fn encode174(message: &[u8], codeword: &mut [u8]) { /// /// Each element of the returned array is 0 or 1. /// Uses the same (174, 91) LDPC generator as `encode174`. -#[allow(dead_code)] +#[cfg(test)] pub(crate) fn encode174_to_bits(a91: &[u8; FTX_LDPC_K_BYTES]) -> [u8; super::protocol::FTX_LDPC_N] { use super::protocol::FTX_LDPC_N; let mut codeword_packed = [0u8; FTX_LDPC_N_BYTES]; diff --git a/src/decoders/trx-ftx/src/common/message.rs b/src/decoders/trx-ftx/src/common/message.rs index 45d2412..9ca0441 100644 --- a/src/decoders/trx-ftx/src/common/message.rs +++ b/src/decoders/trx-ftx/src/common/message.rs @@ -247,8 +247,7 @@ fn parse_cq_modifier(s: &str) -> Option { let mut nlet = 0; let mut m: i32 = 0; - for i in 3..8.min(bytes.len()) { - let c = bytes[i]; + for &c in &bytes[3..8.min(bytes.len())] { if c == b' ' || c == 0 { break; } else if c.is_ascii_digit() { @@ -511,16 +510,14 @@ fn pack58(hash_table: Option<&mut CallsignHashTable>, callsign: &str) -> Option< let mut result: u64 = 0; let mut c11 = String::with_capacity(12); - let mut length = 0; - for ch in src.chars() { + for (length, ch) in src.chars().enumerate() { if ch == '<' || length >= 11 { break; } c11.push(ch); let j = nchar(ch, CharTable::AlphanumSpaceSlash)?; result = result * 38 + j as u64; - length += 1; } save_callsign(hash_table, &c11)?; @@ -1156,9 +1153,9 @@ pub fn ftx_message_decode_free(msg: &FtxMessage) -> String { for idx in (0..13).rev() { // Divide the long integer in b71 by 42 let mut rem: u16 = 0; - for i in 0..9 { - rem = (rem << 8) | b71[i] as u16; - b71[i] = (rem / 42) as u8; + for b in &mut b71 { + rem = (rem << 8) | *b as u16; + *b = (rem / 42) as u8; rem %= 42; } c14[idx] = charn(rem as i32, CharTable::Full) as u8; @@ -1183,9 +1180,9 @@ pub fn ftx_message_decode_telemetry_hex(msg: &FtxMessage) -> String { pub fn ftx_message_decode_telemetry(msg: &FtxMessage) -> [u8; 9] { let mut telemetry = [0u8; 9]; let mut carry: u8 = 0; - for i in 0..9 { - telemetry[i] = (carry << 7) | (msg.payload[i] >> 1); - carry = msg.payload[i] & 0x01; + for (t, &p) in telemetry.iter_mut().zip(msg.payload.iter()) { + *t = (carry << 7) | (p >> 1); + carry = p & 0x01; } telemetry } diff --git a/src/decoders/trx-ftx/src/common/mod.rs b/src/decoders/trx-ftx/src/common/mod.rs index afddaef..e157918 100644 --- a/src/decoders/trx-ftx/src/common/mod.rs +++ b/src/decoders/trx-ftx/src/common/mod.rs @@ -7,17 +7,11 @@ pub mod callsign_hash; pub mod constants; pub mod crc; -#[allow(dead_code, clippy::needless_range_loop)] pub mod decode; -#[allow(clippy::needless_range_loop)] pub mod encode; -#[allow(clippy::needless_range_loop)] pub mod ldpc; -#[allow(clippy::explicit_counter_loop, clippy::needless_range_loop)] pub mod message; -#[allow(dead_code)] pub mod monitor; -#[allow(dead_code, clippy::needless_range_loop, clippy::too_many_arguments)] pub mod osd; pub mod protocol; pub mod text; diff --git a/src/decoders/trx-ftx/src/common/monitor.rs b/src/decoders/trx-ftx/src/common/monitor.rs index 225678c..e324567 100644 --- a/src/decoders/trx-ftx/src/common/monitor.rs +++ b/src/decoders/trx-ftx/src/common/monitor.rs @@ -8,7 +8,6 @@ use num_complex::Complex32; use realfft::RealFftPlanner; -use rustfft::FftPlanner; use super::protocol::FtxProtocol; @@ -94,10 +93,6 @@ pub struct Monitor { fft_output: Vec, fft_input: Vec, real_fft: std::sync::Arc>, - // iFFT for resynthesis - nifft: usize, - ifft: std::sync::Arc>, - ifft_scratch: Vec, } fn hann_i(i: usize, n: usize) -> f32 { @@ -137,11 +132,6 @@ impl Monitor { let fft_output = real_fft.make_output_vec(); let fft_input = real_fft.make_input_vec(); - let nifft = 64; - let mut fft_planner = FftPlanner::::new(); - let ifft = fft_planner.plan_fft_inverse(nifft); - let ifft_scratch = vec![Complex32::new(0.0, 0.0); ifft.get_inplace_scratch_len()]; - Self { symbol_period, min_bin, @@ -158,9 +148,6 @@ impl Monitor { fft_output, fft_input, real_fft, - nifft, - ifft, - ifft_scratch, } } diff --git a/src/decoders/trx-ftx/src/common/osd.rs b/src/decoders/trx-ftx/src/common/osd.rs index 23a28e6..6f9393d 100644 --- a/src/decoders/trx-ftx/src/common/osd.rs +++ b/src/decoders/trx-ftx/src/common/osd.rs @@ -76,14 +76,6 @@ fn encode174_91_nocrc_bits(message91: &[u8], codeword: &mut [u8; FTX_LDPC_N]) { } } -/// XOR two byte slices. -fn xor_rows(dst: &mut [u8], src: &[u8], len: usize) { - dst[..len] - .iter_mut() - .zip(&src[..len]) - .for_each(|(d, s)| *d ^= s); -} - /// Matrix-vector multiply for re-encoding in OSD. fn mrbencode91(me: &[u8], codeword: &mut [u8], g2: &[u8], n: usize, k: usize) { codeword[..n].fill(0); @@ -114,24 +106,20 @@ fn nextpat91(mi: &mut [u8], k: usize, iorder: usize, iflag: &mut i32) { // Build new pattern in-place: zero out after ind, set the swap, pack remaining 1s at end let ind_u = ind as usize; - for i in (ind_u + 1)..k { - mi[i] = 0; - } + mi[(ind_u + 1)..k].fill(0); mi[ind_u] = 1; let mut nz = iorder as i32; - for i in 0..k { - nz -= mi[i] as i32; + for &v in mi.iter().take(k) { + nz -= v as i32; } if nz > 0 { - for i in (k - nz as usize)..k { - mi[i] = 1; - } + mi[(k - nz as usize)..k].fill(1); } *iflag = -1; - for i in 0..k { - if mi[i] == 1 { + for (i, &v) in mi.iter().enumerate().take(k) { + if v == 1 { *iflag = i as i32; break; } @@ -145,7 +133,6 @@ struct OsdBox { pairs: Vec<[i32; 2]>, capacity: usize, count: usize, - size: usize, last_pattern: i32, next_index: i32, } @@ -160,7 +147,6 @@ impl OsdBox { pairs: vec![[-1, -1]; capacity], capacity, count: 0, - size, last_pattern: -1, next_index: -1, }) @@ -214,8 +200,8 @@ impl OsdBox { /// Compute hash of a bit pattern for OSD-2 lookup. fn pattern_hash(e2: &[u8], ntau: usize) -> usize { let mut ipat = 0usize; - for i in 0..ntau { - if e2[i] != 0 { + for (i, &v) in e2.iter().enumerate().take(ntau) { + if v != 0 { ipat |= 1 << (ntau - i - 1); } } @@ -232,6 +218,7 @@ fn pattern_hash(e2: &[u8], ntau: usize) -> usize { /// `cw`: output 174-bit codeword. /// `nhardmin`: output minimum hard errors. /// `dmin`: output minimum distance. +#[allow(clippy::too_many_arguments)] pub fn osd174_91( llr: &mut [f32; FTX_LDPC_N], k: usize, @@ -372,9 +359,7 @@ pub fn osd174_91( // OSD-1: exhaustive search over bit patterns of increasing order for iorder in 1..=nord { misub.iter_mut().for_each(|v| *v = 0); - for i in (k - iorder)..k { - misub[i] = 1; - } + misub[(k - iorder)..k].fill(1); let mut iflag = (k - iorder) as i32; while iflag >= 0 { @@ -408,8 +393,8 @@ pub fn osd174_91( e2[i] = e2sub[i]; } let mut nd1kpt = 1; - for i in 0..nt.min(n - k) { - nd1kpt += e2sub[i] as i32; + for &v in e2sub.iter().take(nt.min(n - k)) { + nd1kpt += v as i32; } d1 = 0.0; for i in 0..k { @@ -438,8 +423,8 @@ pub fn osd174_91( e2[i] = e2sub[i] ^ g2[(k + i) * k + n1 as usize]; } let mut nd1kpt = 2; - for i in 0..nt.min(n - k) { - nd1kpt += e2[i] as i32; + for &v in e2.iter().take(nt.min(n - k)) { + nd1kpt += v as i32; } if nd1kpt <= ntheta { mrbencode91(&me, &mut ce, &g2, n, k); @@ -486,9 +471,7 @@ pub fn osd174_91( // Search using base patterns misub.iter_mut().for_each(|v| *v = 0); - for i in (k - nord)..k { - misub[i] = 1; - } + misub[(k - nord)..k].fill(1); let mut iflag = (k - nord) as i32; while iflag >= 0 { @@ -594,9 +577,7 @@ fn generator_matrix() -> &'static [[u8; FTX_LDPC_N]; FTX_LDPC_K] { let mut msg = [0u8; FTX_LDPC_K]; msg[i] = 1; if i < 77 { - for j in 77..FTX_LDPC_K { - msg[j] = 0; - } + msg[77..FTX_LDPC_K].fill(0); } encode174_91_nocrc_bits(&msg, &mut gen[i]); } @@ -620,6 +601,7 @@ fn generator_matrix() -> &'static [[u8; FTX_LDPC_N]; FTX_LDPC_K] { /// `ntype`: output decode type (0=fail, 1=BP, 2=OSD). /// `nharderror`: output number of hard errors. /// `dmin`: output minimum distance. +#[allow(clippy::too_many_arguments)] pub fn ft2_decode174_91_osd( llr: &mut [f32; FTX_LDPC_N], keff: usize, @@ -732,8 +714,8 @@ pub fn ft2_decode174_91_osd( for i in 0..num_rows.min(7) { tanhtoc[i] = (-toc[m][i] / 2.0).tanh(); } - for j in 0..num_rows { - let n = FTX_LDPC_NM[m][j] as usize - 1; + for &nm_val in FTX_LDPC_NM[m].iter().take(num_rows) { + let n = nm_val as usize - 1; if n >= FTX_LDPC_N { continue; } diff --git a/src/decoders/trx-ftx/src/ft2/bitmetrics.rs b/src/decoders/trx-ftx/src/ft2/bitmetrics.rs index f9d5ac9..779ae08 100644 --- a/src/decoders/trx-ftx/src/ft2/bitmetrics.rs +++ b/src/decoders/trx-ftx/src/ft2/bitmetrics.rs @@ -78,9 +78,9 @@ impl BitMetricsWorkspace { // Sync quality check: verify Costas patterns are detectable let mut sync_ok = 0; - for group in 0..4 { + for (group, costas_group) in FT4_COSTAS_PATTERN.iter().enumerate() { let base = group * 33; - for i in 0..4 { + for (i, &costas_tone) in costas_group.iter().enumerate() { if base + i >= FT2_FRAME_SYMBOLS { continue; } @@ -90,7 +90,7 @@ impl BitMetricsWorkspace { best = tone; } } - if best == FT4_COSTAS_PATTERN[group][i] as usize { + if best == costas_tone as usize { sync_ok += 1; } } diff --git a/src/decoders/trx-ftx/src/ft2/decode.rs b/src/decoders/trx-ftx/src/ft2/decode.rs index 2c98f1e..15d396f 100644 --- a/src/decoders/trx-ftx/src/ft2/decode.rs +++ b/src/decoders/trx-ftx/src/ft2/decode.rs @@ -17,10 +17,10 @@ pub(crate) fn ft2_sync_score(wf: &Waterfall, cand: &Candidate) -> i32 { let mut score_f: f32 = 0.0; let mut groups = 0; - for m in 0..FT2_NUM_SYNC { + for (m, costas_group) in FT4_COSTAS_PATTERN.iter().enumerate().take(FT2_NUM_SYNC) { let mut sum = Complex32::new(0.0, 0.0); let mut complete = true; - for k in 0..FT2_LENGTH_SYNC { + for (k, &costas_tone) in costas_group.iter().enumerate().take(FT2_LENGTH_SYNC) { let block = 1 + FT2_SYNC_OFFSET * m + k; let block_abs = cand.time_offset as i32 + block as i32; if block_abs < 0 || block_abs >= wf.num_blocks as i32 { @@ -28,7 +28,7 @@ pub(crate) fn ft2_sync_score(wf: &Waterfall, cand: &Candidate) -> i32 { break; } let sym_offset = base + block * wf.block_stride; - let tone = FT4_COSTAS_PATTERN[m][k] as usize; + let tone = costas_tone as usize; let elem = *wf_mag_safe(wf, sym_offset + tone); sum += wf_elem_to_complex(elem); } @@ -63,9 +63,9 @@ pub(crate) fn ft2_extract_likelihood( continue; } let sym_offset = base + sym_idx * wf.block_stride; - for tone in 0..4 { + for (tone, symbol_row) in symbols.iter_mut().enumerate().take(4) { let elem = *wf_mag_safe(wf, sym_offset + tone); - symbols[tone][frame_sym] = wf_elem_to_complex(elem); + symbol_row[frame_sym] = wf_elem_to_complex(elem); } } diff --git a/src/decoders/trx-ftx/src/ft2/downsample.rs b/src/decoders/trx-ftx/src/ft2/downsample.rs index e92a528..2a8b9f4 100644 --- a/src/decoders/trx-ftx/src/ft2/downsample.rs +++ b/src/decoders/trx-ftx/src/ft2/downsample.rs @@ -190,8 +190,8 @@ impl DownsampleContext { } // Apply spectral window - for i in 0..self.nfft2 { - band[i] *= self.window[i]; + for (b, &w) in band.iter_mut().zip(self.window.iter()) { + *b *= w; } // Inverse FFT (in-place) @@ -221,19 +221,27 @@ fn build_spectral_window(nfft2: usize, df: f32) -> Vec { } // Raised-cosine leading edge - for i in 0..iwt.min(nfft2) { - window[i] = 0.5 * (1.0 + (std::f32::consts::PI * (iwt - 1 - i) as f32 / iwt as f32).cos()); + for (i, w) in window.iter_mut().enumerate().take(iwt.min(nfft2)) { + *w = 0.5 * (1.0 + (std::f32::consts::PI * (iwt - 1 - i) as f32 / iwt as f32).cos()); } // Flat passband - for i in iwt..(iwt + iwf).min(nfft2) { - window[i] = 1.0; + for w in window + .iter_mut() + .skip(iwt) + .take((iwt + iwf).min(nfft2) - iwt) + { + *w = 1.0; } // Raised-cosine trailing edge - for i in (iwt + iwf)..(2 * iwt + iwf).min(nfft2) { - window[i] = - 0.5 * (1.0 + (std::f32::consts::PI * (i - (iwt + iwf)) as f32 / iwt as f32).cos()); + for (i, w) in window + .iter_mut() + .enumerate() + .take((2 * iwt + iwf).min(nfft2)) + .skip(iwt + iwf) + { + *w = 0.5 * (1.0 + (std::f32::consts::PI * (i - (iwt + iwf)) as f32 / iwt as f32).cos()); } // Circular shift by iws bins diff --git a/src/decoders/trx-ftx/src/ft2/mod.rs b/src/decoders/trx-ftx/src/ft2/mod.rs index 73f565b..19c7ade 100644 --- a/src/decoders/trx-ftx/src/ft2/mod.rs +++ b/src/decoders/trx-ftx/src/ft2/mod.rs @@ -8,12 +8,9 @@ //! peaks in the averaged spectrum, downsample each candidate, compute 2D sync //! scores, extract bit metrics, and run multi-pass LDPC + OSD decode. -#[allow(clippy::needless_range_loop)] pub mod bitmetrics; pub(crate) mod decode; -#[allow(clippy::needless_range_loop)] pub mod downsample; -#[allow(clippy::needless_range_loop)] pub mod sync; pub(crate) use self::decode::{ft2_extract_likelihood, ft2_sync_score}; @@ -50,6 +47,13 @@ pub fn ft2_frequency_offset_hz() -> f32 { -1.5 / FT2_SYMBOL_PERIOD_F } +/// Generate FT2 tone sequence from payload data. +/// +/// FT2 uses the FT4 framing with a doubled symbol rate. +pub fn ft2_encode(payload: &[u8], tones: &mut [u8]) { + crate::ft4::ft4_encode(payload, tones); +} + /// Raw frequency peak candidate from the averaged power spectrum. #[derive(Clone, Copy, Default)] pub struct RawCandidate { @@ -315,8 +319,8 @@ impl Ft2Pipeline { } let inv_n_frames = 1.0 / n_frames as f32; - for bin in 1..FT2_NH1 { - avg[bin] *= inv_n_frames; + for v in avg.iter_mut().take(FT2_NH1).skip(1) { + *v *= inv_n_frames; } // Smooth with 15-point moving average @@ -620,17 +624,24 @@ impl Ft2Pipeline { } // Scale and derive combined passes - for i in 0..FTX_LDPC_N { - llr_passes[0][i] *= 2.83; - llr_passes[1][i] *= 2.83; - llr_passes[2][i] *= 2.83; - - let a = llr_passes[0][i]; - let b = llr_passes[1][i]; - let c = llr_passes[2][i]; - + let [ref mut pass0, ref mut pass1, ref mut pass2, ref mut pass3, ref mut pass4] = + llr_passes; + for v in pass0.iter_mut() { + *v *= 2.83; + } + for v in pass1.iter_mut() { + *v *= 2.83; + } + for v in pass2.iter_mut() { + *v *= 2.83; + } + for ((&a, &b), (&c, (p3, p4))) in pass0 + .iter() + .zip(pass1.iter()) + .zip(pass2.iter().zip(pass3.iter_mut().zip(pass4.iter_mut()))) + { // Pass 3: max-abs metric - llr_passes[3][i] = if a.abs() >= b.abs() && a.abs() >= c.abs() { + *p3 = if a.abs() >= b.abs() && a.abs() >= c.abs() { a } else if b.abs() >= c.abs() { b @@ -639,7 +650,7 @@ impl Ft2Pipeline { }; // Pass 4: average - llr_passes[4][i] = (a + b + c) / 3.0; + *p4 = (a + b + c) / 3.0; } // Multi-pass LDPC decode using full BP+OSD decoder @@ -647,11 +658,11 @@ impl Ft2Pipeline { let mut message = FtxMessage::default(); let mut apmask = [0u8; FTX_LDPC_N]; - for pass in 0..5 { + for llr_pass in &llr_passes { if ok { break; } - let mut log174 = llr_passes[pass]; + let mut log174 = *llr_pass; let mut message91 = [0u8; FTX_LDPC_K]; let mut cw = [0u8; FTX_LDPC_N]; @@ -822,4 +833,14 @@ mod tests { assert_eq!(b, 0); } } + + #[test] + fn ft2_encode_matches_ft4() { + let payload = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x20]; + let mut tones_ft4 = [0u8; FT4_NN]; + let mut tones_ft2 = [0u8; FT4_NN]; + crate::ft4::ft4_encode(&payload, &mut tones_ft4); + ft2_encode(&payload, &mut tones_ft2); + assert_eq!(tones_ft4, tones_ft2); + } } diff --git a/src/decoders/trx-ftx/src/ft2/sync.rs b/src/decoders/trx-ftx/src/ft2/sync.rs index 447d99d..407f15d 100644 --- a/src/decoders/trx-ftx/src/ft2/sync.rs +++ b/src/decoders/trx-ftx/src/ft2/sync.rs @@ -50,8 +50,8 @@ pub fn prepare_sync_waveforms() -> SyncWaveforms { for group in 0..4 { let mut idx = 0usize; let mut phase = 0.0f32; - for tone_idx in 0..4 { - let tone = FT4_COSTAS_PATTERN[group][tone_idx] as f32; + for &costas_tone in FT4_COSTAS_PATTERN[group].iter() { + let tone = costas_tone as f32; let dphase = 4.0 * std::f32::consts::PI * tone / nss; let half_nss = (nss / 2.0) as usize; for _step in 0..half_nss { @@ -68,9 +68,9 @@ pub fn prepare_sync_waveforms() -> SyncWaveforms { // Build frequency tweak phasors for idf in FT2_SYNC_TWEAK_MIN..=FT2_SYNC_TWEAK_MAX { let tw_idx = (idf - FT2_SYNC_TWEAK_MIN) as usize; - for n in 0..64 { + for (n, tw) in tweak_wave[tw_idx].iter_mut().enumerate() { let phase = 4.0 * std::f32::consts::PI * idf as f32 * n as f32 / fs_down; - tweak_wave[tw_idx][n] = Complex32::new(phase.cos(), phase.sin()); + *tw = Complex32::new(phase.cos(), phase.sin()); } } @@ -89,11 +89,10 @@ fn sync_reference_bank() -> &'static SyncReferenceBank { let waveforms = prepare_sync_waveforms(); let mut refs = [[[Complex32::new(0.0, 0.0); SYNC_SAMPLES]; SYNC_GROUP_COUNT]; NUM_TWEAKS]; - for tw_idx in 0..NUM_TWEAKS { - for group in 0..SYNC_GROUP_COUNT { - for i in 0..SYNC_SAMPLES { - refs[tw_idx][group][i] = - (waveforms.sync_wave[group][i] * waveforms.tweak_wave[tw_idx][i]).conj(); + for (tw_idx, refs_tw) in refs.iter_mut().enumerate() { + for (group, refs_group) in refs_tw.iter_mut().enumerate() { + for (i, r) in refs_group.iter_mut().enumerate() { + *r = (waveforms.sync_wave[group][i] * waveforms.tweak_wave[tw_idx][i]).conj(); } } } @@ -132,14 +131,13 @@ fn correlate_group_clipped( let mut usable = 0usize; let n_samples = samples.len() as i32; - for i in 0..SYNC_SAMPLES { + for (i, &reference) in refs.iter().enumerate() { let sample_idx = pos + i as i32 * SAMPLE_STRIDE as i32; if sample_idx < 0 || sample_idx >= n_samples { continue; } let sample = samples[sample_idx as usize]; - let reference = refs[i]; sum_re += sample.re * reference.re - sample.im * reference.im; sum_im += sample.re * reference.im + sample.im * reference.re; usable += 1; diff --git a/src/decoders/trx-ftx/src/ft4/mod.rs b/src/decoders/trx-ftx/src/ft4/mod.rs index 1ce0f9c..9ef5139 100644 --- a/src/decoders/trx-ftx/src/ft4/mod.rs +++ b/src/decoders/trx-ftx/src/ft4/mod.rs @@ -17,8 +17,8 @@ pub(crate) fn ft4_sync_score(wf: &Waterfall, cand: &Candidate) -> i32 { let mut score: i32 = 0; let mut num_average: i32 = 0; - for m in 0..FT4_NUM_SYNC { - for k in 0..FT4_LENGTH_SYNC { + for (m, costas_group) in FT4_COSTAS_PATTERN.iter().enumerate().take(FT4_NUM_SYNC) { + for (k, &sm_val) in costas_group.iter().enumerate().take(FT4_LENGTH_SYNC) { let block = 1 + FT4_SYNC_OFFSET * m + k; let block_abs = cand.time_offset as i32 + block as i32; if block_abs < 0 { @@ -29,7 +29,7 @@ pub(crate) fn ft4_sync_score(wf: &Waterfall, cand: &Candidate) -> i32 { } let p_offset = base + block * wf.block_stride; - let sm = FT4_COSTAS_PATTERN[m][k] as usize; + let sm = sm_val as usize; if sm > 0 { let a = wf_mag_safe(wf, p_offset + sm).mag_int(); @@ -174,13 +174,6 @@ pub fn ft4_encode(payload: &[u8], tones: &mut [u8]) { } } -/// Generate FT2 tone sequence from payload data. -/// -/// FT2 uses the FT4 framing with a doubled symbol rate. -pub fn ft2_encode(payload: &[u8], tones: &mut [u8]) { - ft4_encode(payload, tones); -} - #[cfg(test)] mod tests { use super::*; @@ -244,14 +237,4 @@ mod tests { ft4_encode(&payload, &mut tones2); assert_eq!(tones1, tones2); } - - #[test] - fn ft2_encode_matches_ft4() { - let payload = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x20]; - let mut tones_ft4 = [0u8; FT4_NN]; - let mut tones_ft2 = [0u8; FT4_NN]; - ft4_encode(&payload, &mut tones_ft4); - ft2_encode(&payload, &mut tones_ft2); - assert_eq!(tones_ft4, tones_ft2); - } } diff --git a/src/decoders/trx-ftx/src/ft8/mod.rs b/src/decoders/trx-ftx/src/ft8/mod.rs index e923c6f..ce792a4 100644 --- a/src/decoders/trx-ftx/src/ft8/mod.rs +++ b/src/decoders/trx-ftx/src/ft8/mod.rs @@ -18,7 +18,7 @@ pub(crate) fn ft8_sync_score(wf: &Waterfall, cand: &Candidate) -> i32 { let mut num_average: i32 = 0; for m in 0..FT8_NUM_SYNC { - for k in 0..FT8_LENGTH_SYNC { + for (k, &sm_val) in FT8_COSTAS_PATTERN.iter().enumerate().take(FT8_LENGTH_SYNC) { let block = FT8_SYNC_OFFSET * m + k; let block_abs = cand.time_offset as i32 + block as i32; if block_abs < 0 { @@ -29,7 +29,7 @@ pub(crate) fn ft8_sync_score(wf: &Waterfall, cand: &Candidate) -> i32 { } let p_offset = base + block * wf.block_stride; - let sm = FT8_COSTAS_PATTERN[k] as usize; + let sm = sm_val as usize; if sm > 0 { let a = wf_mag_safe(wf, p_offset + sm).mag_int(); diff --git a/src/decoders/trx-ftx/src/lib.rs b/src/decoders/trx-ftx/src/lib.rs index 2d3d17c..0e2b488 100644 --- a/src/decoders/trx-ftx/src/lib.rs +++ b/src/decoders/trx-ftx/src/lib.rs @@ -4,11 +4,8 @@ pub mod common; mod decoder; -#[allow(clippy::needless_range_loop)] pub mod ft2; -#[allow(clippy::needless_range_loop)] pub mod ft4; -#[allow(clippy::needless_range_loop)] pub mod ft8; pub use decoder::{Ft8DecodeResult, Ft8Decoder};