mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-03-18 14:09:37 -04:00
FT8 demod: fix duplicated code (1)
This commit is contained in:
parent
71d6208fe9
commit
81f7d2ff99
90
ft8/ft4.cpp
90
ft8/ft4.cpp
@ -1547,88 +1547,6 @@ std::vector<std::vector<float>> FT4::soft_c2m(const FFTEngine::ffts_t &c103)
|
||||
return m103;
|
||||
}
|
||||
|
||||
//
|
||||
// guess the probability that a bit is zero vs one,
|
||||
// based on strengths of strongest tones that would
|
||||
// give it those values. for soft LDPC decoding.
|
||||
//
|
||||
// returns log-likelihood, zero is positive, one is negative.
|
||||
//
|
||||
float FT4::bayes(
|
||||
FT4Params& params,
|
||||
float best_zero,
|
||||
float best_one,
|
||||
int lli,
|
||||
Stats &bests,
|
||||
Stats &all
|
||||
)
|
||||
{
|
||||
float maxlog = 4.97;
|
||||
float ll = 0;
|
||||
float pzero = 0.5;
|
||||
float pone = 0.5;
|
||||
|
||||
if (params.use_apriori)
|
||||
{
|
||||
pzero = 1.0 - apriori174[lli];
|
||||
pone = apriori174[lli];
|
||||
}
|
||||
|
||||
//
|
||||
// Bayes combining rule normalization from:
|
||||
// http://cs.wellesley.edu/~anderson/writing/naive-bayes.pdf
|
||||
//
|
||||
// a = P(zero)P(e0|zero)P(e1|zero)
|
||||
// b = P(one)P(e0|one)P(e1|one)
|
||||
// p = a / (a + b)
|
||||
//
|
||||
// also see Mark Owen's book Practical Signal Processing,
|
||||
// Chapter 6.
|
||||
//
|
||||
|
||||
// zero
|
||||
float a = pzero * bests.problt(best_zero) * (1.0 - all.problt(best_one));
|
||||
// printf("FT8::bayes: a: %f bp: %f ap: %f \n", a, bests.problt(best_zero), all.problt(best_one));
|
||||
|
||||
if (params.bayes_how == 1) {
|
||||
a *= all.problt(all.mean() + (best_zero - best_one));
|
||||
}
|
||||
|
||||
// one
|
||||
float b = pone * bests.problt(best_one) * (1.0 - all.problt(best_zero));
|
||||
// printf("FT8::bayes: b: %f bp: %f ap: %f \n", b, bests.problt(best_one), all.problt(best_zero));
|
||||
|
||||
if (params.bayes_how == 1) {
|
||||
b *= all.problt(all.mean() + (best_one - best_zero));
|
||||
}
|
||||
|
||||
float p;
|
||||
|
||||
if (a + b == 0) {
|
||||
p = 0.5;
|
||||
} else {
|
||||
p = a / (a + b);
|
||||
}
|
||||
|
||||
// printf("FT8::bayes: all.mean: %f a: %f b: %f p: %f\n", all.mean(), a, b, p);
|
||||
|
||||
if (1 - p == 0.0) {
|
||||
ll = maxlog;
|
||||
} else {
|
||||
ll = log(p / (1 - p));
|
||||
}
|
||||
|
||||
if (ll > maxlog) {
|
||||
ll = maxlog;
|
||||
}
|
||||
|
||||
if (ll < -maxlog) {
|
||||
ll = -maxlog;
|
||||
}
|
||||
|
||||
return ll;
|
||||
}
|
||||
|
||||
//
|
||||
// c103 is 103x4 complex tones, before un-gray-coding.
|
||||
//
|
||||
@ -1720,7 +1638,7 @@ void FT4::soft_decode(const FFTEngine::ffts_t &c103, float ll174[])
|
||||
}
|
||||
}
|
||||
|
||||
float ll = bayes(params, best_zero, best_one, lli, bests, all);
|
||||
float ll = FT8::bayes(params, best_zero, best_one, lli, bests, all);
|
||||
ll174[lli++] = ll;
|
||||
}
|
||||
}
|
||||
@ -1909,7 +1827,7 @@ void FT4::c_soft_decode(const FFTEngine::ffts_t &c103x, float ll174[])
|
||||
}
|
||||
}
|
||||
|
||||
float ll = bayes(params, best_zero, best_one, lli, bests, all);
|
||||
float ll = FT8::bayes(params, best_zero, best_one, lli, bests, all);
|
||||
ll174[lli++] = ll;
|
||||
}
|
||||
}
|
||||
@ -2084,7 +2002,7 @@ void FT4::soft_decode_pairs(
|
||||
float best_zero = bitinfo[si * 2 + i].zero;
|
||||
float best_one = bitinfo[si * 2 + i].one;
|
||||
// ll174[lli++] = best_zero > best_one ? 4.99 : -4.99;
|
||||
float ll = bayes(params, best_zero, best_one, lli, bests, all);
|
||||
float ll = FT8::bayes(params, best_zero, best_one, lli, bests, all);
|
||||
ll174[lli++] = ll;
|
||||
}
|
||||
}
|
||||
@ -2262,7 +2180,7 @@ void FT4::soft_decode_triples(
|
||||
float best_zero = bitinfo[si * 2 + i].zero;
|
||||
float best_one = bitinfo[si * 2 + i].one;
|
||||
// ll174[lli++] = best_zero > best_one ? 4.99 : -4.99;
|
||||
float ll = bayes(params, best_zero, best_one, lli, bests, all);
|
||||
float ll = FT8::bayes(params, best_zero, best_one, lli, bests, all);
|
||||
ll174[lli++] = ll;
|
||||
}
|
||||
}
|
||||
|
||||
177
ft8/ft4.h
177
ft8/ft4.h
@ -17,162 +17,23 @@ class QThread;
|
||||
|
||||
namespace FT8 {
|
||||
|
||||
// 1920-point FFT at 12000 samples/second
|
||||
// 6.25 Hz spacing, 0.16 seconds/symbol
|
||||
// FT4 characteristics:
|
||||
// 576-point FFT at 12000 samples/second
|
||||
// 23.4 Hz spacing, 0.048 seconds/symbol
|
||||
// encode chain:
|
||||
// 77 bits
|
||||
// append 14 bits CRC (for 91 bits)
|
||||
// LDPC(174,91) yields 174 bits
|
||||
// that's 58 3-bit FSK-8 symbols
|
||||
// gray code each 3 bits
|
||||
// insert three 7-symbol Costas sync arrays
|
||||
// at symbol #s 0, 36, 72 of final signal
|
||||
// thus: 79 FSK-8 symbols
|
||||
// total transmission time is 12.64 seconds
|
||||
// that's 87 2-bit FSK-4 symbols
|
||||
// gray code each 2 bits
|
||||
// insert four 4-symbol Costas sync arrays
|
||||
// at positions: 0-3, 33-36, 66-69, 99-102
|
||||
// thus: 103 FSK-4 symbols
|
||||
// add 2 ramp symbols at start and end to make 105 symbols
|
||||
// total transmission time is 5.04 seconds
|
||||
|
||||
// tunable parameters
|
||||
class FT8_API FT4Params
|
||||
{
|
||||
public:
|
||||
int nthreads; // number of parallel threads, for multi-core
|
||||
int npasses_one; // number of spectral subtraction passes
|
||||
int npasses_two; // number of spectral subtraction passes
|
||||
int ldpc_iters; // how hard LDPC decoding should work
|
||||
int snr_win; // averaging window, in symbols, for SNR conversion
|
||||
int snr_how; // technique to measure "N" for SNR. 0 means median of the 8 tones.
|
||||
float shoulder200; // for 200 sps bandpass filter
|
||||
float shoulder200_extra; // for bandpass filter
|
||||
float second_hz_win; // +/- hz
|
||||
int second_hz_n; // divide total window into this many pieces
|
||||
float second_off_win; // +/- search window in symbol-times
|
||||
int second_off_n;
|
||||
int third_hz_n;
|
||||
float third_hz_win;
|
||||
int third_off_n;
|
||||
float third_off_win;
|
||||
float log_tail;
|
||||
float log_rate;
|
||||
int problt_how_noise;
|
||||
int problt_how_sig;
|
||||
int use_apriori;
|
||||
int use_hints; // 1 means use all hints, 2 means just CQ hints
|
||||
int win_type;
|
||||
int use_osd;
|
||||
int osd_depth; // 6; // don't increase beyond 6, produces too much garbage
|
||||
int osd_ldpc_thresh; // demand this many correct LDPC parity bits before OSD
|
||||
int ncoarse; // number of offsets per hz produced by coarse()
|
||||
int ncoarse_blocks;
|
||||
float tminus; // start looking at 0.5 - tminus seconds
|
||||
float tplus;
|
||||
int coarse_off_n;
|
||||
int coarse_hz_n;
|
||||
float already_hz;
|
||||
float overlap;
|
||||
int overlap_edges;
|
||||
float nyquist;
|
||||
int oddrate;
|
||||
float pass0_frac;
|
||||
int reduce_how;
|
||||
float go_extra;
|
||||
int do_reduce;
|
||||
int pass_threshold;
|
||||
int strength_how;
|
||||
int known_strength_how;
|
||||
int coarse_strength_how;
|
||||
float reduce_shoulder;
|
||||
float reduce_factor;
|
||||
float reduce_extra;
|
||||
float coarse_all;
|
||||
int second_count;
|
||||
int soft_phase_win;
|
||||
float subtract_ramp;
|
||||
int subtract_edge_symbols; // model one extra tapered symbol at frame start/end during subtraction (does not yield significant improvement)
|
||||
int soft_ones;
|
||||
int soft_pairs;
|
||||
int soft_triples;
|
||||
int do_second;
|
||||
int do_fine_hz;
|
||||
int do_fine_off;
|
||||
int do_third;
|
||||
float fine_thresh;
|
||||
int fine_max_off;
|
||||
int fine_max_tone;
|
||||
int known_sparse;
|
||||
float c_soft_weight;
|
||||
int c_soft_win;
|
||||
int bayes_how;
|
||||
|
||||
FT4Params()
|
||||
{
|
||||
nthreads = 8; // number of parallel threads, for multi-core
|
||||
npasses_one = 3; // number of spectral subtraction passes
|
||||
npasses_two = 3; // number of spectral subtraction passes
|
||||
ldpc_iters = 25; // how hard LDPC decoding should work
|
||||
snr_win = 7; // averaging window, in symbols, for SNR conversion
|
||||
snr_how = 3; // technique to measure "N" for SNR. 0 means median of the 8 tones.
|
||||
shoulder200 = 10; // for 200 sps bandpass filter
|
||||
shoulder200_extra = 0.0; // for bandpass filter
|
||||
second_hz_win = 3.5; // +/- hz
|
||||
second_hz_n = 8; // divide total window into this many pieces
|
||||
second_off_win = 0.5; // +/- search window in symbol-times
|
||||
second_off_n = 10;
|
||||
third_hz_n = 3;
|
||||
third_hz_win = 0.25;
|
||||
third_off_n = 4;
|
||||
third_off_win = 0.075;
|
||||
log_tail = 0.1;
|
||||
log_rate = 8.0;
|
||||
problt_how_noise = 0; // Gaussian
|
||||
problt_how_sig = 0; // Gaussian
|
||||
use_apriori = 1;
|
||||
use_hints = 2; // 1 means use all hints, 2 means just CQ hints
|
||||
win_type = 1;
|
||||
use_osd = 1;
|
||||
osd_depth = 0; // 6; // don't increase beyond 6, produces too much garbage
|
||||
osd_ldpc_thresh = 70; // demand this many correct LDPC parity bits before OSD
|
||||
ncoarse = 1; // number of offsets per hz produced by coarse()
|
||||
ncoarse_blocks = 1;
|
||||
tminus = 2.2; // start looking at 0.5 - tminus seconds
|
||||
tplus = 2.4;
|
||||
coarse_off_n = 4;
|
||||
coarse_hz_n = 4;
|
||||
already_hz = 27;
|
||||
overlap = 20;
|
||||
overlap_edges = 0;
|
||||
nyquist = 0.925;
|
||||
oddrate = 1;
|
||||
pass0_frac = 1.0;
|
||||
reduce_how = 2;
|
||||
go_extra = 3.5;
|
||||
do_reduce = 1;
|
||||
pass_threshold = 1;
|
||||
strength_how = 4;
|
||||
known_strength_how = 7;
|
||||
coarse_strength_how = 6;
|
||||
reduce_shoulder = -1;
|
||||
reduce_factor = 0.25;
|
||||
reduce_extra = 0;
|
||||
coarse_all = -1;
|
||||
second_count = 3;
|
||||
soft_phase_win = 2;
|
||||
subtract_ramp = 0.11;
|
||||
subtract_edge_symbols = 0;
|
||||
soft_ones = 2;
|
||||
soft_pairs = 1;
|
||||
soft_triples = 1;
|
||||
do_second = 1;
|
||||
do_fine_hz = 1;
|
||||
do_fine_off = 1;
|
||||
do_third = 2;
|
||||
fine_thresh = 0.19;
|
||||
fine_max_off = 2;
|
||||
fine_max_tone = 4;
|
||||
known_sparse = 1;
|
||||
c_soft_weight = 7;
|
||||
c_soft_win = 2;
|
||||
bayes_how = 1;
|
||||
}
|
||||
}; // class FT4Params
|
||||
using FT4Params = FT8Params;
|
||||
|
||||
class FT8_API FT4ParamsLight
|
||||
{
|
||||
@ -393,22 +254,6 @@ private:
|
||||
// next.
|
||||
//
|
||||
std::vector<std::vector<float>> soft_c2m(const FFTEngine::ffts_t &c79);
|
||||
//
|
||||
// guess the probability that a bit is zero vs one,
|
||||
// based on strengths of strongest tones that would
|
||||
// give it those values. for soft LDPC decoding.
|
||||
//
|
||||
// returns log-likelihood, zero is positive, one is negative.
|
||||
//
|
||||
static float bayes(
|
||||
FT4Params& params,
|
||||
float best_zero,
|
||||
float best_one,
|
||||
int lli,
|
||||
Stats &bests,
|
||||
Stats &all
|
||||
);
|
||||
//
|
||||
// c79 is 79x8 complex tones, before un-gray-coding.
|
||||
//
|
||||
void soft_decode(const FFTEngine::ffts_t &c79, float ll174[]);
|
||||
|
||||
131
ft8/ft8.cpp
131
ft8/ft8.cpp
@ -47,6 +47,71 @@
|
||||
|
||||
namespace FT8 {
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename ParamsT>
|
||||
float bayesImpl(
|
||||
const double apriori174[],
|
||||
ParamsT& params,
|
||||
float best_zero,
|
||||
float best_one,
|
||||
int lli,
|
||||
Stats &bests,
|
||||
Stats &all
|
||||
)
|
||||
{
|
||||
float maxlog = 4.97;
|
||||
float ll = 0;
|
||||
float pzero = 0.5;
|
||||
float pone = 0.5;
|
||||
|
||||
if (params.use_apriori)
|
||||
{
|
||||
pzero = 1.0 - apriori174[lli];
|
||||
pone = apriori174[lli];
|
||||
}
|
||||
|
||||
// zero
|
||||
float a = pzero * bests.problt(best_zero) * (1.0 - all.problt(best_one));
|
||||
|
||||
if (params.bayes_how == 1) {
|
||||
a *= all.problt(all.mean() + (best_zero - best_one));
|
||||
}
|
||||
|
||||
// one
|
||||
float b = pone * bests.problt(best_one) * (1.0 - all.problt(best_zero));
|
||||
|
||||
if (params.bayes_how == 1) {
|
||||
b *= all.problt(all.mean() + (best_one - best_zero));
|
||||
}
|
||||
|
||||
float p;
|
||||
|
||||
if (a + b == 0) {
|
||||
p = 0.5;
|
||||
} else {
|
||||
p = a / (a + b);
|
||||
}
|
||||
|
||||
if (1 - p == 0.0) {
|
||||
ll = maxlog;
|
||||
} else {
|
||||
ll = log(p / (1 - p));
|
||||
}
|
||||
|
||||
if (ll > maxlog) {
|
||||
ll = maxlog;
|
||||
}
|
||||
|
||||
if (ll < -maxlog) {
|
||||
ll = -maxlog;
|
||||
}
|
||||
|
||||
return ll;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// a-priori probability of each of the 174 LDPC codeword
|
||||
// bits being one. measured from reconstructed correct
|
||||
// codewords, into ft8bits, then python bprob.py.
|
||||
@ -1675,72 +1740,10 @@ float FT8::bayes(
|
||||
Stats &all
|
||||
)
|
||||
{
|
||||
float maxlog = 4.97;
|
||||
float ll = 0;
|
||||
float pzero = 0.5;
|
||||
float pone = 0.5;
|
||||
|
||||
if (params.use_apriori)
|
||||
{
|
||||
pzero = 1.0 - apriori174[lli];
|
||||
pone = apriori174[lli];
|
||||
}
|
||||
|
||||
//
|
||||
// Bayes combining rule normalization from:
|
||||
// http://cs.wellesley.edu/~anderson/writing/naive-bayes.pdf
|
||||
//
|
||||
// a = P(zero)P(e0|zero)P(e1|zero)
|
||||
// b = P(one)P(e0|one)P(e1|one)
|
||||
// p = a / (a + b)
|
||||
//
|
||||
// also see Mark Owen's book Practical Signal Processing,
|
||||
// Chapter 6.
|
||||
//
|
||||
|
||||
// zero
|
||||
float a = pzero * bests.problt(best_zero) * (1.0 - all.problt(best_one));
|
||||
// printf("FT8::bayes: a: %f bp: %f ap: %f \n", a, bests.problt(best_zero), all.problt(best_one));
|
||||
|
||||
if (params.bayes_how == 1) {
|
||||
a *= all.problt(all.mean() + (best_zero - best_one));
|
||||
}
|
||||
|
||||
// one
|
||||
float b = pone * bests.problt(best_one) * (1.0 - all.problt(best_zero));
|
||||
// printf("FT8::bayes: b: %f bp: %f ap: %f \n", b, bests.problt(best_one), all.problt(best_zero));
|
||||
|
||||
if (params.bayes_how == 1) {
|
||||
b *= all.problt(all.mean() + (best_one - best_zero));
|
||||
}
|
||||
|
||||
float p;
|
||||
|
||||
if (a + b == 0) {
|
||||
p = 0.5;
|
||||
} else {
|
||||
p = a / (a + b);
|
||||
}
|
||||
|
||||
// printf("FT8::bayes: all.mean: %f a: %f b: %f p: %f\n", all.mean(), a, b, p);
|
||||
|
||||
if (1 - p == 0.0) {
|
||||
ll = maxlog;
|
||||
} else {
|
||||
ll = log(p / (1 - p));
|
||||
}
|
||||
|
||||
if (ll > maxlog) {
|
||||
ll = maxlog;
|
||||
}
|
||||
|
||||
if (ll < -maxlog) {
|
||||
ll = -maxlog;
|
||||
}
|
||||
|
||||
return ll;
|
||||
return bayesImpl(apriori174, params, best_zero, best_one, lli, bests, all);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// c79 is 79x8 complex tones, before un-gray-coding.
|
||||
//
|
||||
|
||||
37
ft8/ft8.h
37
ft8/ft8.h
@ -36,6 +36,21 @@
|
||||
class QThread;
|
||||
|
||||
namespace FT8 {
|
||||
|
||||
// FT8 characteristics:
|
||||
// 1920-point FFT at 12000 samples/second
|
||||
// 6.25 Hz spacing, 0.16 seconds/symbol
|
||||
// encode chain:
|
||||
// 77 bits
|
||||
// append 14 bits CRC (for 91 bits)
|
||||
// LDPC(174,91) yields 174 bits
|
||||
// that's 58 3-bit FSK-8 symbols
|
||||
// gray code each 3 bits
|
||||
// insert three 7-symbol Costas sync arrays
|
||||
// at symbol #s 0, 36, 72 of final signal
|
||||
// thus: 79 FSK-8 symbols
|
||||
// total transmission time is 12.64 seconds
|
||||
|
||||
// Callback interface to get the results
|
||||
class FT8_API CallbackInterface
|
||||
{
|
||||
@ -52,7 +67,6 @@ public:
|
||||
virtual QString get_name() = 0;
|
||||
};
|
||||
|
||||
|
||||
class FT8_API Strength
|
||||
{
|
||||
public:
|
||||
@ -71,20 +85,7 @@ struct FT8_API cdecode
|
||||
int *bits; // 174
|
||||
};
|
||||
|
||||
// 1920-point FFT at 12000 samples/second
|
||||
// 6.25 Hz spacing, 0.16 seconds/symbol
|
||||
// encode chain:
|
||||
// 77 bits
|
||||
// append 14 bits CRC (for 91 bits)
|
||||
// LDPC(174,91) yields 174 bits
|
||||
// that's 58 3-bit FSK-8 symbols
|
||||
// gray code each 3 bits
|
||||
// insert three 7-symbol Costas sync arrays
|
||||
// at symbol #s 0, 36, 72 of final signal
|
||||
// thus: 79 FSK-8 symbols
|
||||
// total transmission time is 12.64 seconds
|
||||
|
||||
// tunable parameters
|
||||
// tunable parameters for all FT decoders
|
||||
class FT8_API FT8Params
|
||||
{
|
||||
public:
|
||||
@ -140,6 +141,7 @@ public:
|
||||
int second_count;
|
||||
int soft_phase_win;
|
||||
float subtract_ramp;
|
||||
int subtract_edge_symbols; // model one extra tapered symbol at frame start/end during subtraction
|
||||
int soft_ones;
|
||||
int soft_pairs;
|
||||
int soft_triples;
|
||||
@ -209,6 +211,7 @@ public:
|
||||
second_count = 3;
|
||||
soft_phase_win = 2;
|
||||
subtract_ramp = 0.11;
|
||||
subtract_edge_symbols = 0;
|
||||
soft_ones = 2;
|
||||
soft_pairs = 1;
|
||||
soft_triples = 1;
|
||||
@ -230,6 +233,8 @@ public:
|
||||
class FT8_API FT8 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class FT4;
|
||||
|
||||
public:
|
||||
FT8(
|
||||
const std::vector<float> &samples,
|
||||
@ -457,6 +462,7 @@ private:
|
||||
// next.
|
||||
//
|
||||
std::vector<std::vector<float>> soft_c2m(const FFTEngine::ffts_t &c79);
|
||||
public:
|
||||
//
|
||||
// guess the probability that a bit is zero vs one,
|
||||
// based on strengths of strongest tones that would
|
||||
@ -472,6 +478,7 @@ private:
|
||||
Stats &bests,
|
||||
Stats &all
|
||||
);
|
||||
private:
|
||||
//
|
||||
// c79 is 79x8 complex tones, before un-gray-coding.
|
||||
//
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user