mirror of
https://github.com/f4exb/sdrangel.git
synced 2026-03-18 05:59:37 -04:00
FT4 demod: copy original FT8 worker to FT4. Isolate AI generated classes
This commit is contained in:
parent
724a9a0f83
commit
fbfa04a06d
3720
ft8/ft4.cpp
3720
ft8/ft4.cpp
File diff suppressed because it is too large
Load Diff
632
ft8/ft4.h
632
ft8/ft4.h
@ -17,8 +17,163 @@ class QThread;
|
||||
|
||||
namespace FT8 {
|
||||
|
||||
// 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
|
||||
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 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;
|
||||
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
|
||||
|
||||
class FT8_API FT4ParamsLight
|
||||
{
|
||||
public:
|
||||
int nthreads;
|
||||
int ldpc_iters;
|
||||
@ -27,7 +182,7 @@ public:
|
||||
int osd_ldpc_thresh;
|
||||
int max_candidates;
|
||||
|
||||
FT4Params() :
|
||||
FT4ParamsLight() :
|
||||
nthreads(8),
|
||||
ldpc_iters(25),
|
||||
use_osd(1),
|
||||
@ -37,9 +192,473 @@ public:
|
||||
{}
|
||||
};
|
||||
|
||||
class FT8_API FT4Decoder : public QObject
|
||||
// The FT8 worker
|
||||
class FT8_API FT4 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
FT4(
|
||||
const std::vector<float> &samples,
|
||||
float min_hz,
|
||||
float max_hz,
|
||||
int start,
|
||||
int rate,
|
||||
int hints1[],
|
||||
int hints2[],
|
||||
double deadline,
|
||||
double final_deadline,
|
||||
CallbackInterface *cb,
|
||||
std::vector<cdecode> prevdecs,
|
||||
FFTEngine *fftEngine
|
||||
);
|
||||
~FT4();
|
||||
// Number of passes
|
||||
void set_npasses(int npasses) { npasses_ = npasses; }
|
||||
// Start the worker
|
||||
void start_work();
|
||||
// strength of costas block of signal with tone 0 at bi0,
|
||||
// and symbol zero at si0.
|
||||
float one_coarse_strength(const FFTEngine::ffts_t &bins, int bi0, int si0);
|
||||
// return symbol length in samples at the given rate.
|
||||
// insist on integer symbol lengths so that we can
|
||||
// use whole FFT bins.
|
||||
int blocksize(int rate);
|
||||
//
|
||||
// look for potential signals by searching FFT bins for Costas symbol
|
||||
// blocks. returns a vector of candidate positions.
|
||||
//
|
||||
std::vector<Strength> coarse(const FFTEngine::ffts_t &bins, int si0, int si1);
|
||||
|
||||
FT4Params& getParams() { return params; }
|
||||
//
|
||||
// given log likelihood for each bit, try LDPC and OSD decoders.
|
||||
// on success, puts corrected 174 bits into a174[].
|
||||
//
|
||||
static int decode(const float ll174[], int a174[], FT4Params& params, int use_osd, std::string &comment);
|
||||
// encode a 77 bit message into a 174 bit payload
|
||||
// adds the 14 bit CRC to obtain 91 bits
|
||||
// apply (174, 91) generator mastrix to obtain the 83 parity bits
|
||||
// append the 83 bits to the 91 bits message e+ crc to obtain the 174 bit payload
|
||||
static void encode(int a174[], const int s77[]);
|
||||
|
||||
//
|
||||
// set ones and zero symbol indexes
|
||||
//
|
||||
static void set_ones_zeroes(int ones[], int zeroes[], int nbBits, int bitIndex);
|
||||
|
||||
//
|
||||
// mags is the vector of 2^nbSymbolBits vector of magnitudes at each symbol time
|
||||
// ll174 is the resulting 174 soft bits of payload
|
||||
// used in FT-chirp modulation scheme - generalized to any number of symbol bits
|
||||
//
|
||||
static void soft_decode_mags(FT4Params& params, const std::vector<std::vector<float>>& mags, int nbSymbolBits, float ll174[]);
|
||||
|
||||
//
|
||||
// Generic Gray decoding for magnitudes (floats)
|
||||
//
|
||||
static std::vector<std::vector<float>> un_gray_code_r_gen(const std::vector<std::vector<float>> &mags);
|
||||
|
||||
private:
|
||||
//
|
||||
// reduce the sample rate from arate to brate.
|
||||
// center hz0..hz1 in the new nyquist range.
|
||||
// but first filter to that range.
|
||||
// sets delta_hz to hz moved down.
|
||||
//
|
||||
std::vector<float> reduce_rate(
|
||||
const std::vector<float> &a,
|
||||
float hz0,
|
||||
float hz1,
|
||||
int arate,
|
||||
int brate,
|
||||
float &delta_hz
|
||||
);
|
||||
// The actual main process
|
||||
void go(int npasses);
|
||||
//
|
||||
// what's the strength of the Costas sync blocks of
|
||||
// the signal starting at hz and off?
|
||||
//
|
||||
float one_strength(const std::vector<float> &samples200, float hz, int off);
|
||||
//
|
||||
// given a complete known signal's symbols in syms,
|
||||
// how strong is it? used to look for the best
|
||||
// offset and frequency at which to subtract a
|
||||
// decoded signal.
|
||||
//
|
||||
float one_strength_known(
|
||||
const std::vector<float> &samples,
|
||||
int rate,
|
||||
const std::vector<int> &syms,
|
||||
float hz,
|
||||
int off
|
||||
);
|
||||
int search_time_fine(
|
||||
const std::vector<float> &samples200,
|
||||
int off0,
|
||||
int offN,
|
||||
float hz,
|
||||
int gran,
|
||||
float &str
|
||||
);
|
||||
int search_time_fine_known(
|
||||
const std::vector<std::complex<float>> &bins,
|
||||
int rate,
|
||||
const std::vector<int> &syms,
|
||||
int off0,
|
||||
int offN,
|
||||
float hz,
|
||||
int gran,
|
||||
float &str
|
||||
);
|
||||
//
|
||||
// search for costas blocks in an MxN time/frequency grid.
|
||||
// hz0 +/- hz_win in hz_inc increments. hz0 should be near 25.
|
||||
// off0 +/- off_win in off_inc incremenents.
|
||||
//
|
||||
std::vector<Strength> search_both(
|
||||
const std::vector<float> &samples200,
|
||||
float hz0,
|
||||
int hz_n,
|
||||
float hz_win,
|
||||
int off0,
|
||||
int off_n,
|
||||
int off_win
|
||||
);
|
||||
void search_both_known(
|
||||
const std::vector<float> &samples,
|
||||
int rate,
|
||||
const std::vector<int> &syms,
|
||||
float hz0,
|
||||
float off_secs0, // seconds
|
||||
float &hz_out,
|
||||
float &off_out
|
||||
);
|
||||
//
|
||||
// shift frequency by shifting the bins of one giant FFT.
|
||||
// so no problem with phase mismatch &c at block boundaries.
|
||||
// surprisingly fast at 200 samples/second.
|
||||
// shifts *down* by hz.
|
||||
//
|
||||
std::vector<float> fft_shift(
|
||||
const std::vector<float> &samples,
|
||||
int off,
|
||||
int len,
|
||||
int rate,
|
||||
float hz
|
||||
);
|
||||
//
|
||||
// shift down by hz.
|
||||
//
|
||||
std::vector<float> fft_shift_f(
|
||||
const std::vector<std::complex<float>> &bins,
|
||||
int rate,
|
||||
float hz
|
||||
);
|
||||
// shift the frequency by a fraction of 6.25,
|
||||
// to center hz on bin 4 (25 hz).
|
||||
std::vector<float> shift200(
|
||||
const std::vector<float> &samples200,
|
||||
int off,
|
||||
int len,
|
||||
float hz
|
||||
);
|
||||
// returns a mini-FFT of 79 8-tone symbols.
|
||||
FFTEngine::ffts_t extract(const std::vector<float> &samples200, float, int off);
|
||||
//
|
||||
// m79 is a 79x8 array of complex.
|
||||
//
|
||||
FFTEngine::ffts_t un_gray_code_c(const FFTEngine::ffts_t &m79);
|
||||
//
|
||||
// m79 is a 79x8 array of float.
|
||||
//
|
||||
std::vector<std::vector<float>> un_gray_code_r(const std::vector<std::vector<float>> &m79);
|
||||
//
|
||||
// normalize levels by windowed median.
|
||||
// this helps, but why?
|
||||
//
|
||||
std::vector<std::vector<float>> convert_to_snr(const std::vector<std::vector<float>> &m79);
|
||||
//
|
||||
// normalize levels by windowed median.
|
||||
// this helps, but why?
|
||||
//
|
||||
static std::vector<std::vector<float>> convert_to_snr_gen(const FT4Params& params, int nbSymbolBits, const std::vector<std::vector<float>> &mags);
|
||||
//
|
||||
// normalize levels by windowed median.
|
||||
// this helps, but why?
|
||||
//
|
||||
std::vector<std::vector<std::complex<float>>> c_convert_to_snr(
|
||||
const std::vector<std::vector<std::complex<float>>> &m79
|
||||
);
|
||||
//
|
||||
// statistics to decide soft probabilities,
|
||||
// to drive LDPC decoder.
|
||||
// distribution of strongest tones, and
|
||||
// distribution of noise.
|
||||
//
|
||||
static void make_stats(
|
||||
const std::vector<std::vector<float>> &m79,
|
||||
Stats &bests,
|
||||
Stats &all
|
||||
);
|
||||
//
|
||||
// generalized version of the above for any number of symbols and no Costas
|
||||
// used by FT-chirp decoder
|
||||
//
|
||||
static void make_stats_gen(
|
||||
const std::vector<std::vector<float>> &mags,
|
||||
int nbSymbolBits,
|
||||
Stats &bests,
|
||||
Stats &all
|
||||
);
|
||||
//
|
||||
// convert 79x8 complex FFT bins to magnitudes.
|
||||
//
|
||||
// exploits local phase coherence by decreasing magnitudes of bins
|
||||
// whose phase is far from the phases of nearby strongest tones.
|
||||
//
|
||||
// relies on each tone being reasonably well centered in its FFT bin
|
||||
// (in time and frequency) so that each tone completes an integer
|
||||
// number of cycles and thus preserves phase from one symbol to the
|
||||
// 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[]);
|
||||
//
|
||||
// c79 is 79x8 complex tones, before un-gray-coding.
|
||||
//
|
||||
void c_soft_decode(const FFTEngine::ffts_t &c79x, float ll174[]);
|
||||
//
|
||||
// turn 79 symbol numbers into 174 bits.
|
||||
// strip out the three Costas sync blocks,
|
||||
// leaving 58 symbol numbers.
|
||||
// each represents three bits.
|
||||
// (all post-un-gray-code).
|
||||
// str is per-symbol strength; must be positive.
|
||||
// each returned element is < 0 for 1, > 0 for zero,
|
||||
// scaled by str.
|
||||
//
|
||||
std::vector<float> extract_bits(const std::vector<int> &syms, const std::vector<float> str);
|
||||
// decode successive pairs of symbols. exploits the likelihood
|
||||
// that they have the same phase, by summing the complex
|
||||
// correlations for each possible pair and using the max.
|
||||
void soft_decode_pairs(
|
||||
const FFTEngine::ffts_t &m79x,
|
||||
float ll174[]
|
||||
);
|
||||
void soft_decode_triples(
|
||||
const FFTEngine::ffts_t &m79x,
|
||||
float ll174[]
|
||||
);
|
||||
//
|
||||
// bandpass filter some FFT bins.
|
||||
// smooth transition from stop-band to pass-band,
|
||||
// so that it's not a brick-wall filter, so that it
|
||||
// doesn't ring.
|
||||
//
|
||||
std::vector<std::complex<float>> fbandpass(
|
||||
const std::vector<std::complex<float>> &bins0,
|
||||
float bin_hz,
|
||||
float low_outer, // start of transition
|
||||
float low_inner, // start of flat area
|
||||
float high_inner, // end of flat area
|
||||
float high_outer // end of transition
|
||||
);
|
||||
//
|
||||
// move hz down to 25, filter+convert to 200 samples/second.
|
||||
//
|
||||
// like fft_shift(). one big FFT, move bins down and
|
||||
// zero out those outside the band, then IFFT,
|
||||
// then re-sample.
|
||||
//
|
||||
// XXX maybe merge w/ fft_shift() / shift200().
|
||||
//
|
||||
std::vector<float> down_v7(const std::vector<float> &samples, float hz);
|
||||
std::vector<float> down_v7_f(const std::vector<std::complex<float>> &bins, int len, float hz);
|
||||
//
|
||||
// putative start of signal is at hz and symbol si0.
|
||||
//
|
||||
// return 2 if it decodes to a brand-new message.
|
||||
// return 1 if it decodes but we've already seen it,
|
||||
// perhaps in a different pass.
|
||||
// return 0 if we could not decode.
|
||||
//
|
||||
// XXX merge with one_iter().
|
||||
//
|
||||
int one_merge(const std::vector<std::complex<float>> &bins, int len, float hz, int off);
|
||||
// return 2 if it decodes to a brand-new message.
|
||||
// return 1 if it decodes but we've already seen it,
|
||||
// perhaps in a different pass.
|
||||
// return 0 if we could not decode.
|
||||
int one_iter(const std::vector<float> &samples200, int best_off, float hz_for_cb);
|
||||
//
|
||||
// estimate SNR, yielding numbers vaguely similar to WSJT-X.
|
||||
// m79 is a 79x8 complex FFT output.
|
||||
//
|
||||
float guess_snr(const FFTEngine::ffts_t &m79);
|
||||
//
|
||||
// compare phases of successive symbols to guess whether
|
||||
// the starting offset is a little too high or low.
|
||||
// we expect each symbol to have the same phase.
|
||||
// an error in causes the phase to advance at a steady rate.
|
||||
// so if hz is wrong, we expect the phase to advance
|
||||
// or retard at a steady pace.
|
||||
// an error in offset causes each symbol to start at
|
||||
// a phase that depends on the symbol's frequency;
|
||||
// a particular offset error causes a phase error
|
||||
// that depends on frequency.
|
||||
// hz0 is actual FFT bin number of m79[...][0] (always 4).
|
||||
//
|
||||
// the output adj_hz is relative to the FFT bin center;
|
||||
// a positive number means the real signal seems to be
|
||||
// a bit higher in frequency that the bin center.
|
||||
//
|
||||
// adj_off is the amount to change the offset, in samples.
|
||||
// should be subtracted from offset.
|
||||
//
|
||||
void fine(const FFTEngine::ffts_t &m79, int, float &adj_hz, float &adj_off);
|
||||
//
|
||||
// subtract a corrected decoded signal from nsamples_,
|
||||
// perhaps revealing a weaker signal underneath,
|
||||
// to be decoded in a subsequent pass.
|
||||
//
|
||||
// re79[] holds the error-corrected symbol numbers.
|
||||
//
|
||||
void subtract(
|
||||
const std::vector<int> re79,
|
||||
float hz0,
|
||||
float hz1,
|
||||
float off_sec
|
||||
);
|
||||
//
|
||||
// decode, give to callback, and subtract.
|
||||
//
|
||||
// return 2 if it decodes to a brand-new message.
|
||||
// return 1 if it decodes but we've already seen it,
|
||||
// perhaps in a different pass.
|
||||
// return 0 if we could not decode.
|
||||
//
|
||||
int try_decode(
|
||||
const std::vector<float> &samples200,
|
||||
float ll174[174],
|
||||
float best_hz,
|
||||
int best_off_samples,
|
||||
float hz0_for_cb,
|
||||
float,
|
||||
int use_osd,
|
||||
const char *comment1,
|
||||
const FFTEngine::ffts_t &m79
|
||||
);
|
||||
//
|
||||
// given 174 bits corrected by LDPC, work
|
||||
// backwards to the symbols that must have
|
||||
// been sent.
|
||||
// used to help ensure that subtraction subtracts
|
||||
// at the right place.
|
||||
//
|
||||
std::vector<int> recode(int a174[]);
|
||||
//
|
||||
// the signal is at roughly 25 hz in samples200.
|
||||
//
|
||||
// return 2 if it decodes to a brand-new message.
|
||||
// return 1 if it decodes but we've already seen it,
|
||||
// perhaps in a different pass.
|
||||
// return 0 if we could not decode.
|
||||
//
|
||||
int one_iter1(
|
||||
const std::vector<float> &samples200x,
|
||||
int best_off,
|
||||
float best_hz,
|
||||
float hz0_for_cb,
|
||||
float hz1_for_cb
|
||||
);
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
private:
|
||||
FT4Params params;
|
||||
FFTEngine *fftEngine_;
|
||||
int npasses_;
|
||||
static const double apriori174[];
|
||||
|
||||
float min_hz_;
|
||||
float max_hz_;
|
||||
std::vector<float> samples_; // input to each pass
|
||||
std::vector<float> nsamples_; // subtract from here
|
||||
|
||||
int start_; // sample number of 0.5 seconds into samples[]
|
||||
int rate_; // samples/second
|
||||
double deadline_; // start time + budget
|
||||
double final_deadline_; // keep going this long if no decodes
|
||||
std::vector<int> hints1_;
|
||||
std::vector<int> hints2_;
|
||||
int pass_;
|
||||
float down_hz_;
|
||||
|
||||
QMutex cb_mu_;
|
||||
CallbackInterface *cb_; // call-back interface
|
||||
|
||||
QMutex hack_mu_;
|
||||
int hack_size_;
|
||||
int hack_off_;
|
||||
int hack_len_;
|
||||
float hack_0_;
|
||||
float hack_1_;
|
||||
const float *hack_data_;
|
||||
std::vector<std::complex<float>> hack_bins_;
|
||||
std::vector<cdecode> prevdecs_;
|
||||
}; // class FT4
|
||||
|
||||
|
||||
class FT8_API FT4DecoderLight : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~FT4DecoderLight();
|
||||
void entry(
|
||||
float xsamples[],
|
||||
int nsamples,
|
||||
int start,
|
||||
int rate,
|
||||
float min_hz,
|
||||
float max_hz,
|
||||
int hints1[],
|
||||
int hints2[],
|
||||
double time_left,
|
||||
double total_time_left,
|
||||
CallbackInterface *cb,
|
||||
int,
|
||||
struct cdecode *
|
||||
);
|
||||
void wait(double time_left);
|
||||
void forceQuit();
|
||||
FT4ParamsLight& getParams() { return params; }
|
||||
|
||||
private:
|
||||
FT4ParamsLight params;
|
||||
std::vector<QThread*> threads;
|
||||
};
|
||||
|
||||
class FT8_API FT4Decoder : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
~FT4Decoder();
|
||||
void entry(
|
||||
@ -57,14 +676,15 @@ public:
|
||||
int,
|
||||
struct cdecode *
|
||||
);
|
||||
void wait(double time_left);
|
||||
void forceQuit();
|
||||
void wait(double time_left); //!< wait for all threads to finish
|
||||
void forceQuit(); //!< force quit all threads
|
||||
FT4Params& getParams() { return params; }
|
||||
|
||||
private:
|
||||
FT4Params params;
|
||||
std::vector<QThread*> threads;
|
||||
};
|
||||
std::vector<FFTEngine*> fftEngines;
|
||||
}; // FT4Decoder
|
||||
|
||||
|
||||
} // namespace FT8
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ FT4Worker::FT4Worker(
|
||||
int start,
|
||||
int rate,
|
||||
CallbackInterface *cb,
|
||||
const FT4Params& params
|
||||
const FT4ParamsLight& params
|
||||
) :
|
||||
m_samples(samples),
|
||||
m_minHz(minHz),
|
||||
@ -369,6 +369,7 @@ void FT4Worker::decode()
|
||||
|
||||
int plain[174];
|
||||
int ldpcOk = 0;
|
||||
int correct_bits = 0;
|
||||
LDPC::ldpc_decode(llr.data(), m_params.ldpc_iters, plain, &ldpcOk);
|
||||
|
||||
if (ldpcOk < ldpcThreshold)
|
||||
@ -378,8 +379,15 @@ void FT4Worker::decode()
|
||||
|
||||
int a174[174];
|
||||
|
||||
for (int i = 0; i < 174; i++) {
|
||||
for (int i = 0; i < 174; i++)
|
||||
{
|
||||
a174[i] = plain[i];
|
||||
|
||||
if (llr.data()[i] < 0 && a174[i] == 1) {
|
||||
correct_bits += 1;
|
||||
} else if (llr.data()[i] > 0 && a174[i] == 0) {
|
||||
correct_bits += 1;
|
||||
}
|
||||
}
|
||||
|
||||
bool crcOk = OSD::check_crc(a174);
|
||||
@ -420,7 +428,7 @@ void FT4Worker::decode()
|
||||
}
|
||||
|
||||
const float off = static_cast<float>(m_start) / m_rate + static_cast<float>(candidate.start) / m_rate;
|
||||
m_cb->hcb(a91, tone0, off, "FT4-EXP", snr, 0, ldpcOk);
|
||||
m_cb->hcb(a91, tone0, off, "FT4-EXP", snr, 0, correct_bits);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -40,7 +40,7 @@ public:
|
||||
int start,
|
||||
int rate,
|
||||
CallbackInterface *cb,
|
||||
const FT4Params& params
|
||||
const FT4ParamsLight& params
|
||||
);
|
||||
|
||||
void start_work();
|
||||
@ -59,7 +59,7 @@ private:
|
||||
int m_start;
|
||||
int m_rate;
|
||||
CallbackInterface *m_cb;
|
||||
FT4Params m_params;
|
||||
FT4ParamsLight m_params;
|
||||
FFTEngine m_fftEngine;
|
||||
};
|
||||
|
||||
|
||||
72
ft8/ft8.cpp
72
ft8/ft8.cpp
@ -47,78 +47,6 @@
|
||||
|
||||
namespace FT8 {
|
||||
|
||||
//
|
||||
// return a Hamming window of length n.
|
||||
//
|
||||
std::vector<float> hamming(int n)
|
||||
{
|
||||
std::vector<float> h(n);
|
||||
|
||||
for (int k = 0; k < n; k++) {
|
||||
h[k] = 0.54 - 0.46 * cos(2 * M_PI * k / (n - 1.0));
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//
|
||||
// blackman window
|
||||
//
|
||||
std::vector<float> blackman(int n)
|
||||
{
|
||||
std::vector<float> h(n);
|
||||
|
||||
for (int k = 0; k < n; k++) {
|
||||
h[k] = 0.42 - 0.5 * cos(2 * M_PI * k / n) + 0.08 * cos(4 * M_PI * k / n);
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//
|
||||
// symmetric blackman window
|
||||
//
|
||||
std::vector<float> sym_blackman(int n)
|
||||
{
|
||||
std::vector<float> h(n);
|
||||
|
||||
for (int k = 0; k < (n / 2) + 1; k++) {
|
||||
h[k] = 0.42 - 0.5 * cos(2 * M_PI * k / n) + 0.08 * cos(4 * M_PI * k / n);
|
||||
}
|
||||
|
||||
for (int k = n - 1; k >= (n / 2) + 1; --k) {
|
||||
h[k] = h[(n - 1) - k];
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//
|
||||
// blackman-harris window
|
||||
//
|
||||
std::vector<float> blackmanharris(int n)
|
||||
{
|
||||
float a0 = 0.35875;
|
||||
float a1 = 0.48829;
|
||||
float a2 = 0.14128;
|
||||
float a3 = 0.01168;
|
||||
std::vector<float> h(n);
|
||||
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
// symmetric
|
||||
h[k] = a0 - a1 * cos(2 * M_PI * k / (n - 1)) + a2 * cos(4 * M_PI * k / (n - 1)) - a3 * cos(6 * M_PI * k / (n - 1));
|
||||
// periodic
|
||||
// h[k] =
|
||||
// a0
|
||||
// - a1 * cos(2 * M_PI * k / n)
|
||||
// + a2 * cos(4 * M_PI * k / n)
|
||||
// - a3 * cos(6 * M_PI * k / n);
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
// a-priori probability of each of the 174 LDPC codeword
|
||||
// bits being one. measured from reconstructed correct
|
||||
// codewords, into ft8bits, then python bprob.py.
|
||||
|
||||
72
ft8/util.cpp
72
ft8/util.cpp
@ -338,4 +338,76 @@ std::string trim(const std::string &s) {
|
||||
return rtrim(ltrim(s));
|
||||
}
|
||||
|
||||
//
|
||||
// return a Hamming window of length n.
|
||||
//
|
||||
std::vector<float> hamming(int n)
|
||||
{
|
||||
std::vector<float> h(n);
|
||||
|
||||
for (int k = 0; k < n; k++) {
|
||||
h[k] = 0.54 - 0.46 * cos(2 * M_PI * k / (n - 1.0));
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//
|
||||
// blackman window
|
||||
//
|
||||
std::vector<float> blackman(int n)
|
||||
{
|
||||
std::vector<float> h(n);
|
||||
|
||||
for (int k = 0; k < n; k++) {
|
||||
h[k] = 0.42 - 0.5 * cos(2 * M_PI * k / n) + 0.08 * cos(4 * M_PI * k / n);
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//
|
||||
// symmetric blackman window
|
||||
//
|
||||
std::vector<float> sym_blackman(int n)
|
||||
{
|
||||
std::vector<float> h(n);
|
||||
|
||||
for (int k = 0; k < (n / 2) + 1; k++) {
|
||||
h[k] = 0.42 - 0.5 * cos(2 * M_PI * k / n) + 0.08 * cos(4 * M_PI * k / n);
|
||||
}
|
||||
|
||||
for (int k = n - 1; k >= (n / 2) + 1; --k) {
|
||||
h[k] = h[(n - 1) - k];
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
//
|
||||
// blackman-harris window
|
||||
//
|
||||
std::vector<float> blackmanharris(int n)
|
||||
{
|
||||
float a0 = 0.35875;
|
||||
float a1 = 0.48829;
|
||||
float a2 = 0.14128;
|
||||
float a3 = 0.01168;
|
||||
std::vector<float> h(n);
|
||||
|
||||
for (int k = 0; k < n; k++)
|
||||
{
|
||||
// symmetric
|
||||
h[k] = a0 - a1 * cos(2 * M_PI * k / (n - 1)) + a2 * cos(4 * M_PI * k / (n - 1)) - a3 * cos(6 * M_PI * k / (n - 1));
|
||||
// periodic
|
||||
// h[k] =
|
||||
// a0
|
||||
// - a1 * cos(2 * M_PI * k / n)
|
||||
// + a2 * cos(4 * M_PI * k / n)
|
||||
// - a3 * cos(6 * M_PI * k / n);
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
} // namespace FT8
|
||||
|
||||
@ -50,6 +50,11 @@ std::vector<float> gfsk_r(
|
||||
std::vector<float> gfsk_window(int samples_per_symbol, float b);
|
||||
std::string trim(const std::string &s);
|
||||
|
||||
std::vector<float> hamming(int n); // return a Hamming window of length n.
|
||||
std::vector<float> blackman(int n); // blackman window
|
||||
std::vector<float> sym_blackman(int n); // symmetric blackman window
|
||||
std::vector<float> blackmanharris(int n); // blackman-harris window
|
||||
|
||||
typedef unsigned long ulong;
|
||||
typedef unsigned int uint;
|
||||
|
||||
|
||||
@ -112,7 +112,7 @@ private:
|
||||
bool m_invalidSequence;
|
||||
qint64 m_baseFrequency;
|
||||
FT8::FT8Decoder m_ft8Decoder;
|
||||
FT8::FT4Decoder m_ft4Decoder;
|
||||
FT8::FT4DecoderLight m_ft4Decoder;
|
||||
FT8::Packing m_packing;
|
||||
MessageQueue *m_guiReportingMessageQueue;
|
||||
MessageQueue *m_pskReportingMessageQueue;
|
||||
|
||||
@ -216,7 +216,7 @@ void MainBench::testFT4(const QString& wavFile, const QString& argsStr)
|
||||
|
||||
wfile.close();
|
||||
|
||||
FT8::FT4Decoder decoder;
|
||||
FT8::FT4DecoderLight decoder;
|
||||
decoder.getParams().nthreads = nthreads;
|
||||
decoder.getParams().use_osd = 1;
|
||||
decoder.getParams().osd_depth = 6;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user