From eac2efdb353a1f04fd1e210807c0c15dca633f6c Mon Sep 17 00:00:00 2001 From: Stan Grams Date: Sun, 15 Mar 2026 08:06:19 +0100 Subject: [PATCH] [fix](trx-ft8): increase FT2 LDPC iterations and improve OSD fallback Increase BP/SP iteration count from 30 to 50 to match WSJT-X reference and give belief propagation more opportunities to converge near-threshold candidates. Replace the parity-based OSD-1/OSD-2 fallback (which required LDPC to have nearly converged) with ft2_osd_lite_decode applied to all five LLR combination passes. The CRC-based decoder works directly from raw LLRs without depending on LDPC convergence, searching the 24 least-reliable systematic bits for up to three bit errors via OSD-3. Also increase max_candidates in ft2_osd_lite_decode from 12 to 24 for broader coverage of likely error positions. Co-Authored-By: Claude Sonnet 4.6 Signed-off-by: Stan Grams --- src/decoders/trx-ft8/src/ft8_wrapper.c | 33 +++++++++++--------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/decoders/trx-ft8/src/ft8_wrapper.c b/src/decoders/trx-ft8/src/ft8_wrapper.c index adbd31c..32a5117 100644 --- a/src/decoders/trx-ft8/src/ft8_wrapper.c +++ b/src/decoders/trx-ft8/src/ft8_wrapper.c @@ -1074,7 +1074,7 @@ static bool ft2_osd_lite_decode(const float log174[FTX_LDPC_N], ftx_message_t* m } qsort(reliabilities, FTX_LDPC_K, sizeof(reliabilities[0]), ft2_cmp_reliability_asc); - const int max_candidates = 12; + const int max_candidates = 24; const int n = (FTX_LDPC_K < max_candidates) ? FTX_LDPC_K : max_candidates; uint8_t trial_a91[FTX_LDPC_K_BYTES]; uint8_t best_codeword[FTX_LDPC_N]; @@ -1393,8 +1393,6 @@ static bool ft2_decode_hit( bool ok = false; uint8_t cw[FTX_LDPC_N] = { 0 }; - int global_best_errors = FTX_LDPC_M; - int global_best_pass = 0; for (int pass = 0; pass < 5 && !ok; ++pass) { float log174[FTX_LDPC_N]; @@ -1406,7 +1404,7 @@ static bool ft2_decode_hit( uint8_t bp_plain[FTX_LDPC_N]; int bp_errors = FTX_LDPC_M; - bp_decode(log174, 30, bp_plain, &bp_errors); + bp_decode(log174, 50, bp_plain, &bp_errors); if (bp_errors < nharderror) { nharderror = bp_errors; @@ -1425,7 +1423,7 @@ static bool ft2_decode_hit( { uint8_t sp_plain[FTX_LDPC_N]; int sp_errors = FTX_LDPC_M; - ldpc_decode(log174, 30, sp_plain, &sp_errors); + ldpc_decode(log174, 50, sp_plain, &sp_errors); if (sp_errors < nharderror) { nharderror = sp_errors; @@ -1441,12 +1439,6 @@ static bool ft2_decode_hit( } } - if (nharderror < global_best_errors) - { - global_best_errors = nharderror; - global_best_pass = pass; - } - if (pass_diag) { pass_diag->ntype[pass] = ntype; @@ -1455,15 +1447,18 @@ static bool ft2_decode_hit( } } - // OSD-1 / OSD-2: when BP/SP leave only a few parity errors, try flipping - // the least-reliable bits to bridge the gap. - if (!ok && global_best_errors <= 8) + // CRC-based OSD: try flipping 1/2/3 of the least-reliable systematic bits. + // Works directly from LLRs without depending on LDPC convergence. + if (!ok) { - float osd_log174[FTX_LDPC_N]; - memcpy(osd_log174, llr_passes[global_best_pass], sizeof(osd_log174)); - ft2_normalize_log174(osd_log174); - if (ft2_osd_decode(cw, osd_log174, global_best_errors) && ft2_unpack_message(cw, message)) - ok = true; + for (int pass = 0; pass < 5 && !ok; ++pass) + { + float osd_log174[FTX_LDPC_N]; + memcpy(osd_log174, llr_passes[pass], sizeof(osd_log174)); + ft2_normalize_log174(osd_log174); + if (ft2_osd_lite_decode(osd_log174, message)) + ok = true; + } } if (!ok && fail_stage)