[fix](trx-ft8): align FT2 decoder thresholds and LLR scaling with reference

The FT2 decoder was failing to decode valid signals due to thresholds
and LLR parameters that were significantly stricter than the reference
implementation (Decodium/raptor ft2_triggered_decode).

Thresholds aligned with reference at depth>=3:
- Peak detection: 1.08 -> 1.03 (reference uses 0.50 on normalized spectrum)
- Scan sync: 0.60 -> 0.50 (reference at depth>=3)
- Decode sync: 0.80 -> 0.65 (reference at depth>=3)
- Sync quality min: 13 -> 10 (reference at depth>=3)

LLR parameters aligned:
- Scale factor: 2.83 -> 3.2 (matches reference scalefac)
- Normalization: sqrt(24/var) -> 1/sigma (matches reference normalizebmet)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
This commit is contained in:
2026-03-17 21:38:48 +01:00
parent 7844cb65c8
commit 8aa1884d2d
+10 -10
View File
@@ -368,7 +368,7 @@ static int ft2_find_frequency_peaks(
if (baseline[bin] <= 0.0f) if (baseline[bin] <= 0.0f)
continue; continue;
float value = smooth[bin] / baseline[bin]; float value = smooth[bin] / baseline[bin];
if (value < 1.08f) if (value < 1.03f)
continue; continue;
if (!(value >= (smooth[bin - 1] / fmaxf(baseline[bin - 1], 1e-9f)) && if (!(value >= (smooth[bin - 1] / fmaxf(baseline[bin - 1], 1e-9f)) &&
value >= (smooth[bin + 1] / fmaxf(baseline[bin + 1], 1e-9f)))) value >= (smooth[bin + 1] / fmaxf(baseline[bin + 1], 1e-9f))))
@@ -676,7 +676,7 @@ static int ft2_find_scan_hits(
} }
} }
} }
if (best_score < 0.60f) if (best_score < 0.50f)
continue; continue;
for (int idf = best_idf - 4; idf <= best_idf + 4; ++idf) for (int idf = best_idf - 4; idf <= best_idf + 4; ++idf)
@@ -694,7 +694,7 @@ static int ft2_find_scan_hits(
} }
} }
} }
if (best_score < 0.60f) if (best_score < 0.50f)
continue; continue;
out[count].freq_hz = peaks[peak].freq_hz; out[count].freq_hz = peaks[peak].freq_hz;
@@ -755,9 +755,9 @@ static void ft2_normalize_log174(float* log174)
if (variance <= 1.0e-12f) if (variance <= 1.0e-12f)
return; return;
float norm_factor = sqrtf(24.0f / variance); float sigma = sqrtf(variance);
for (int i = 0; i < FTX_LDPC_N; ++i) for (int i = 0; i < FTX_LDPC_N; ++i)
log174[i] *= norm_factor; log174[i] /= sigma;
} }
static bool ft2_extract_bitmetrics_raw(const float complex* signal, float bitmetrics[2 * FT2_FRAME_SYMBOLS][3]) static bool ft2_extract_bitmetrics_raw(const float complex* signal, float bitmetrics[2 * FT2_FRAME_SYMBOLS][3])
@@ -1286,7 +1286,7 @@ static bool ft2_decode_hit(
} }
} }
} }
if (best_score < 0.80f) if (best_score < 0.65f)
{ {
if (fail_stage) if (fail_stage)
*fail_stage = FT2_FAIL_REFINED_SYNC; *fail_stage = FT2_FAIL_REFINED_SYNC;
@@ -1338,7 +1338,7 @@ static bool ft2_decode_hit(
sync_qual += ((bitmetrics[132 + i][0] >= 0.0f) ? 1 : 0) == sync_bits_c[i]; sync_qual += ((bitmetrics[132 + i][0] >= 0.0f) ? 1 : 0) == sync_bits_c[i];
sync_qual += ((bitmetrics[198 + i][0] >= 0.0f) ? 1 : 0) == sync_bits_d[i]; sync_qual += ((bitmetrics[198 + i][0] >= 0.0f) ? 1 : 0) == sync_bits_d[i];
} }
if (sync_qual < 13) if (sync_qual < 10)
{ {
if (fail_stage) if (fail_stage)
*fail_stage = FT2_FAIL_SYNC_QUAL; *fail_stage = FT2_FAIL_SYNC_QUAL;
@@ -1362,9 +1362,9 @@ static bool ft2_decode_hit(
} }
for (int i = 0; i < FTX_LDPC_N; ++i) for (int i = 0; i < FTX_LDPC_N; ++i)
{ {
llr_passes[0][i] *= 2.83f; llr_passes[0][i] *= 3.2f;
llr_passes[1][i] *= 2.83f; llr_passes[1][i] *= 3.2f;
llr_passes[2][i] *= 2.83f; llr_passes[2][i] *= 3.2f;
float a = llr_passes[0][i]; float a = llr_passes[0][i];
float b = llr_passes[1][i]; float b = llr_passes[1][i];
float c = llr_passes[2][i]; float c = llr_passes[2][i];