JS8Call-Improved master
Loading...
Searching...
No Matches
ldpc_feedback.h
1#pragma once
2
3#include <QDebug>
4#include <QLoggingCategory>
5#include <QtGlobal>
6
7#include <algorithm>
8#include <array>
9#include <cmath>
10#include <cstdint>
11#include <cstdlib>
12#include <optional>
13
14Q_DECLARE_LOGGING_CATEGORY(decoder_js8);
15
16namespace js8 {
25constexpr float LLR_ERASURE_THRESHOLD_DEFAULT = 0.25f;
26constexpr float LLR_FEEDBACK_CONFIDENT_MIN = 3.0f;
27constexpr float LLR_FEEDBACK_UNCERTAIN_MAX = 1.0f;
28constexpr float LLR_FEEDBACK_CONFIDENT_BOOST = 1.2f;
29constexpr float LLR_FEEDBACK_UNCERTAIN_SHRINK = 0.5f;
30constexpr float LLR_FEEDBACK_MAX_MAG = 6.0f;
31constexpr int LDPC_FEEDBACK_MAX_PASSES_DEFAULT = 8;
32
33inline float llrErasureThreshold() {
34 float threshold = LLR_ERASURE_THRESHOLD_DEFAULT;
35
36 if (auto const env = std::getenv("JS8_LLR_ERASURE_THRESH"); env) {
37 char *end = nullptr;
38 float val = std::strtof(env, &end);
39
40 if (end != env && std::isfinite(val)) {
41 threshold = val;
42 }
43 }
44
45 if (threshold <= 0.0f || !std::isfinite(threshold) ||
46 std::getenv("JS8_DISABLE_ERASURE_THRESHOLDING")) {
47 return 0.0f;
48 }
49
50 return threshold;
51}
52
53inline bool ldpcFeedbackEnabled() {
54 bool ok = false;
55 int value = qEnvironmentVariableIntValue("JS8_LDPC_FEEDBACK", &ok);
56 return ok ? value != 0 : true;
57}
58
59inline int ldpcFeedbackMaxPasses() {
60 bool ok = false;
61 int value = qEnvironmentVariableIntValue("JS8_LDPC_MAX_PASSES", &ok);
62
63 if (!ok)
64 return LDPC_FEEDBACK_MAX_PASSES_DEFAULT;
65
66 return std::clamp(value, 1, LDPC_FEEDBACK_MAX_PASSES_DEFAULT);
67}
68
69template <std::size_t N>
70void refineLlrsWithLdpcFeedback(std::array<float, N> const &llrIn,
71 std::array<int8_t, N> const &cw,
72 float erasureThreshold,
73 std::array<float, N> &llrOut,
74 int &confidentCount, int &uncertainCount) {
75 llrOut = llrIn;
76 confidentCount = 0;
77 uncertainCount = 0;
78
79 for (std::size_t i = 0; i < llrOut.size(); ++i) {
80 float &value = llrOut[i];
81
82 if (!std::isfinite(value)) {
83 value = 0.0f;
84 ++uncertainCount;
85 continue;
86 }
87
88 bool const bitOne = cw[i] != 0;
89 float const mag = std::abs(value);
90 bool const signMatch = (value >= 0.0f) == bitOne;
91
92 if (signMatch && mag >= LLR_FEEDBACK_CONFIDENT_MIN) {
93 ++confidentCount;
94 float boosted = mag * LLR_FEEDBACK_CONFIDENT_BOOST;
95 boosted = std::clamp(boosted, 0.0f, LLR_FEEDBACK_MAX_MAG);
96 value = bitOne ? boosted : -boosted;
97 } else if (!signMatch || mag <= LLR_FEEDBACK_UNCERTAIN_MAX) {
98 ++uncertainCount;
99 float shrunk = mag * LLR_FEEDBACK_UNCERTAIN_SHRINK;
100
101 if (erasureThreshold > 0.0f && shrunk < erasureThreshold) {
102 value = 0.0f;
103 } else {
104 value = bitOne ? shrunk : -shrunk;
105 }
106 }
107 }
108}
109} // namespace js8
JS8 namespace for Kalman filter-based trackers.
Definition FrequencyTracker.cpp:14
constexpr float LLR_ERASURE_THRESHOLD_DEFAULT
LDPC erasure threshold config and feedback refinement helpers.
Definition ldpc_feedback.h:25