mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 01:55:48 -05:00
FT8 demod: make FFT engine
This commit is contained in:
parent
6adac5f45b
commit
22acbebab6
58
ft8/fft.cpp
58
ft8/fft.cpp
@ -20,39 +20,20 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "fft.h"
|
||||
#include <mutex>
|
||||
// #include <unistd.h>
|
||||
#include <assert.h>
|
||||
// #include <sys/file.h>
|
||||
// #include <sys/types.h>
|
||||
// #include <sys/stat.h>
|
||||
#include "util.h"
|
||||
|
||||
#define TIMING 0
|
||||
|
||||
namespace FT8 {
|
||||
|
||||
// MEASURE=0, ESTIMATE=64, PATIENT=32
|
||||
int fftw_type = FFTW_ESTIMATE;
|
||||
|
||||
static std::mutex plansmu;
|
||||
static std::mutex plansmu2;
|
||||
static Plan *plans[1000];
|
||||
static int nplans;
|
||||
// static int plan_master_pid = 0;
|
||||
|
||||
Plan *get_plan(int n, const char *why)
|
||||
FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why)
|
||||
{
|
||||
// cache fftw plans in the parent process,
|
||||
// so they will already be there for fork()ed children.
|
||||
|
||||
plansmu.lock();
|
||||
|
||||
// if (plan_master_pid == 0)
|
||||
// {
|
||||
// plan_master_pid = getpid();
|
||||
// }
|
||||
|
||||
for (int i = 0; i < nplans; i++)
|
||||
{
|
||||
if (plans[i]->n_ == n && plans[i]->type_ == fftw_type
|
||||
@ -73,16 +54,6 @@ Plan *get_plan(int n, const char *why)
|
||||
#endif
|
||||
|
||||
// fftw_make_planner_thread_safe();
|
||||
|
||||
// the fftw planner is not thread-safe.
|
||||
// can't rely on plansmu because both ft8.so
|
||||
// and snd.so may be using separate copies of fft.cc.
|
||||
// the lock file really should be per process.
|
||||
// int lockfd = creat("/tmp/fft-plan-lock", 0666);
|
||||
// assert(lockfd >= 0);
|
||||
// fchmod(lockfd, 0666);
|
||||
// int lockret = flock(lockfd, LOCK_EX);
|
||||
// assert(lockret == 0);
|
||||
plansmu2.lock();
|
||||
|
||||
fftwf_set_timelimit(5);
|
||||
@ -109,10 +80,6 @@ Plan *get_plan(int n, const char *why)
|
||||
// FFTW_PATIENT
|
||||
// FFTW_EXHAUSTIVE
|
||||
int type = fftw_type;
|
||||
// if (getpid() != plan_master_pid)
|
||||
// {
|
||||
// type = FFTW_ESTIMATE;
|
||||
// }
|
||||
p->type_ = type;
|
||||
p->fwd_ = fftwf_plan_dft_r2c_1d(n, p->r_, p->c_, type);
|
||||
assert(p->fwd_);
|
||||
@ -131,14 +98,11 @@ Plan *get_plan(int n, const char *why)
|
||||
p->crev_ = fftwf_plan_dft_1d(n, p->cc2_, p->cc1_, FFTW_BACKWARD, type);
|
||||
assert(p->crev_);
|
||||
|
||||
// flock(lockfd, LOCK_UN);
|
||||
// close(lockfd);
|
||||
plansmu2.unlock();
|
||||
|
||||
assert(nplans + 1 < 1000);
|
||||
|
||||
plans[nplans] = p;
|
||||
// __sync_synchronize();
|
||||
nplans += 1;
|
||||
|
||||
#if TIMING
|
||||
@ -160,12 +124,12 @@ Plan *get_plan(int n, const char *why)
|
||||
// real inputs, complex outputs.
|
||||
// output has (block / 2) + 1 points.
|
||||
//
|
||||
std::vector<std::complex<float>> one_fft(
|
||||
std::vector<std::complex<float>> FFTEngine::one_fft(
|
||||
const std::vector<float> &samples,
|
||||
int i0,
|
||||
int block,
|
||||
const char *why,
|
||||
Plan *p
|
||||
FFTEngine::Plan *p
|
||||
)
|
||||
{
|
||||
assert(i0 >= 0);
|
||||
@ -242,7 +206,7 @@ std::vector<std::complex<float>> one_fft(
|
||||
// do a full set of FFTs, one per symbol-time.
|
||||
// bins[time][frequency]
|
||||
//
|
||||
ffts_t ffts(const std::vector<float> &samples, int i0, int block, const char *why)
|
||||
FFTEngine::ffts_t FFTEngine::ffts(const std::vector<float> &samples, int i0, int block, const char *why)
|
||||
{
|
||||
assert(i0 >= 0);
|
||||
assert(block > 1 && (block % 2) == 0);
|
||||
@ -313,7 +277,7 @@ ffts_t ffts(const std::vector<float> &samples, int i0, int block, const char *wh
|
||||
// real inputs, complex outputs.
|
||||
// output has block points.
|
||||
//
|
||||
std::vector<std::complex<float>> one_fft_c(
|
||||
std::vector<std::complex<float>> FFTEngine::one_fft_c(
|
||||
const std::vector<float> &samples,
|
||||
int i0,
|
||||
int block,
|
||||
@ -373,7 +337,7 @@ std::vector<std::complex<float>> one_fft_c(
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::complex<float>> one_fft_cc(
|
||||
std::vector<std::complex<float>> FFTEngine::one_fft_cc(
|
||||
const std::vector<std::complex<float>> &samples,
|
||||
int i0,
|
||||
int block,
|
||||
@ -434,7 +398,7 @@ std::vector<std::complex<float>> one_fft_cc(
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<std::complex<float>> one_ifft_cc(
|
||||
std::vector<std::complex<float>> FFTEngine::one_ifft_cc(
|
||||
const std::vector<std::complex<float>> &bins,
|
||||
const char *why
|
||||
)
|
||||
@ -483,7 +447,7 @@ std::vector<std::complex<float>> one_ifft_cc(
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<float> one_ifft(const std::vector<std::complex<float>> &bins, const char *why)
|
||||
std::vector<float> FFTEngine::one_ifft(const std::vector<std::complex<float>> &bins, const char *why)
|
||||
{
|
||||
int nbins = bins.size();
|
||||
int block = (nbins - 1) * 2;
|
||||
@ -531,7 +495,7 @@ std::vector<float> one_ifft(const std::vector<std::complex<float>> &bins, const
|
||||
//
|
||||
// the return value is x + iy, where y is the hilbert transform of x.
|
||||
//
|
||||
std::vector<std::complex<float>> analytic(const std::vector<float> &x, const char *why)
|
||||
std::vector<std::complex<float>> FFTEngine::analytic(const std::vector<float> &x, const char *why)
|
||||
{
|
||||
ulong n = x.size();
|
||||
|
||||
@ -573,7 +537,7 @@ std::vector<std::complex<float>> analytic(const std::vector<float> &x, const cha
|
||||
//
|
||||
// like weakutil.py's freq_shift().
|
||||
//
|
||||
std::vector<float> hilbert_shift(const std::vector<float> &x, float hz0, float hz1, int rate)
|
||||
std::vector<float> FFTEngine::hilbert_shift(const std::vector<float> &x, float hz0, float hz1, int rate)
|
||||
{
|
||||
// y = scipy.signal.hilbert(x)
|
||||
std::vector<std::complex<float>> y = analytic(x, "hilbert_shift");
|
||||
@ -595,7 +559,7 @@ std::vector<float> hilbert_shift(const std::vector<float> &x, float hz0, float h
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fft_stats()
|
||||
void FFTEngine::fft_stats()
|
||||
{
|
||||
for (int i = 0; i < nplans; i++)
|
||||
{
|
||||
|
91
ft8/fft.h
91
ft8/fft.h
@ -22,56 +22,73 @@
|
||||
#ifndef FFT_H
|
||||
#define FFT_H
|
||||
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <complex>
|
||||
#include <fftw3.h>
|
||||
|
||||
namespace FT8
|
||||
{
|
||||
// a cached fftw plan, for both of:
|
||||
// fftwf_plan_dft_r2c_1d(n, m_in, m_out, FFTW_ESTIMATE);
|
||||
// fftwf_plan_dft_c2r_1d(n, m_in, m_out, FFTW_ESTIMATE);
|
||||
class Plan
|
||||
class FFTEngine
|
||||
{
|
||||
public:
|
||||
int n_;
|
||||
int type_;
|
||||
// a cached fftw plan, for both of:
|
||||
// fftwf_plan_dft_r2c_1d(n, m_in, m_out, FFTW_ESTIMATE);
|
||||
// fftwf_plan_dft_c2r_1d(n, m_in, m_out, FFTW_ESTIMATE);
|
||||
class Plan
|
||||
{
|
||||
public:
|
||||
int n_;
|
||||
int type_;
|
||||
|
||||
//
|
||||
// real -> complex
|
||||
//
|
||||
fftwf_complex *c_; // (n_ / 2) + 1 of these
|
||||
float *r_; // n_ of these
|
||||
fftwf_plan fwd_; // forward plan
|
||||
fftwf_plan rev_; // reverse plan
|
||||
//
|
||||
// real -> complex
|
||||
//
|
||||
fftwf_complex *c_; // (n_ / 2) + 1 of these
|
||||
float *r_; // n_ of these
|
||||
fftwf_plan fwd_; // forward plan
|
||||
fftwf_plan rev_; // reverse plan
|
||||
|
||||
//
|
||||
// complex -> complex
|
||||
//
|
||||
fftwf_complex *cc1_; // n
|
||||
fftwf_complex *cc2_; // n
|
||||
fftwf_plan cfwd_; // forward plan
|
||||
fftwf_plan crev_; // reverse plan
|
||||
//
|
||||
// complex -> complex
|
||||
//
|
||||
fftwf_complex *cc1_; // n
|
||||
fftwf_complex *cc2_; // n
|
||||
fftwf_plan cfwd_; // forward plan
|
||||
fftwf_plan crev_; // reverse plan
|
||||
|
||||
// how much CPU time spent in FFTs that use this plan.
|
||||
#if TIMING
|
||||
double time_;
|
||||
#endif
|
||||
const char *why_;
|
||||
int uses_;
|
||||
};
|
||||
// how much CPU time spent in FFTs that use this plan.
|
||||
#if TIMING
|
||||
double time_;
|
||||
#endif
|
||||
const char *why_;
|
||||
int uses_;
|
||||
}; // Plan
|
||||
|
||||
Plan *get_plan(int n, const char *why);
|
||||
FFTEngine() : nplans(0)
|
||||
{}
|
||||
|
||||
std::vector<std::complex<float>> one_fft(const std::vector<float> &samples, int i0, int block, const char *why, Plan *p);
|
||||
std::vector<float> one_ifft(const std::vector<std::complex<float>> &bins, const char *why);
|
||||
typedef std::vector<std::vector<std::complex<float>>> ffts_t;
|
||||
ffts_t ffts(const std::vector<float> &samples, int i0, int block, const char *why);
|
||||
std::vector<std::complex<float>> one_fft_c(const std::vector<float> &samples, int i0, int block, const char *why);
|
||||
std::vector<std::complex<float>> one_fft_cc(const std::vector<std::complex<float>> &samples, int i0, int block, const char *why);
|
||||
std::vector<std::complex<float>> one_ifft_cc(const std::vector<std::complex<float>> &bins, const char *why);
|
||||
std::vector<std::complex<float>> analytic(const std::vector<float> &x, const char *why);
|
||||
std::vector<float> hilbert_shift(const std::vector<float> &x, float hz0, float hz1, int rate);
|
||||
Plan *get_plan(int n, const char *why);
|
||||
|
||||
std::vector<std::complex<float>> one_fft(const std::vector<float> &samples, int i0, int block, const char *why, Plan *p);
|
||||
std::vector<float> one_ifft(const std::vector<std::complex<float>> &bins, const char *why);
|
||||
typedef std::vector<std::vector<std::complex<float>>> ffts_t;
|
||||
ffts_t ffts(const std::vector<float> &samples, int i0, int block, const char *why);
|
||||
std::vector<std::complex<float>> one_fft_c(const std::vector<float> &samples, int i0, int block, const char *why);
|
||||
std::vector<std::complex<float>> one_fft_cc(const std::vector<std::complex<float>> &samples, int i0, int block, const char *why);
|
||||
std::vector<std::complex<float>> one_ifft_cc(const std::vector<std::complex<float>> &bins, const char *why);
|
||||
std::vector<std::complex<float>> analytic(const std::vector<float> &x, const char *why);
|
||||
std::vector<float> hilbert_shift(const std::vector<float> &x, float hz0, float hz1, int rate);
|
||||
|
||||
private:
|
||||
void fft_stats();
|
||||
std::mutex plansmu;
|
||||
std::mutex plansmu2;
|
||||
Plan *plans[1000];
|
||||
int nplans;
|
||||
// MEASURE=0, ESTIMATE=64, PATIENT=32
|
||||
static const int fftw_type = FFTW_ESTIMATE;
|
||||
}; // FFTEngine
|
||||
|
||||
} // namespace FT8
|
||||
|
||||
|
85
ft8/ft8.cpp
85
ft8/ft8.cpp
@ -326,7 +326,8 @@ FT8::FT8(
|
||||
double deadline,
|
||||
double final_deadline,
|
||||
CallbackInterface *cb,
|
||||
std::vector<cdecode> prevdecs
|
||||
std::vector<cdecode> prevdecs,
|
||||
FFTEngine *fftEngine
|
||||
)
|
||||
{
|
||||
samples_ = samples;
|
||||
@ -349,11 +350,12 @@ FT8::FT8(
|
||||
}
|
||||
|
||||
hack_size_ = -1;
|
||||
hack_data_ = 0;
|
||||
hack_data_ = nullptr;
|
||||
hack_off_ = -1;
|
||||
hack_len_ = -1;
|
||||
|
||||
plan32_ = 0;
|
||||
plan32_ = nullptr;
|
||||
fftEngine_ = fftEngine;
|
||||
}
|
||||
|
||||
FT8::~FT8()
|
||||
@ -362,7 +364,7 @@ FT8::~FT8()
|
||||
|
||||
// strength of costas block of signal with tone 0 at bi0,
|
||||
// and symbol zero at si0.
|
||||
float FT8::one_coarse_strength(const ffts_t &bins, int bi0, int si0)
|
||||
float FT8::one_coarse_strength(const FFTEngine::ffts_t &bins, int bi0, int si0)
|
||||
{
|
||||
int costas[] = {3, 1, 4, 0, 6, 5, 2};
|
||||
|
||||
@ -491,7 +493,7 @@ int FT8::blocksize(int rate)
|
||||
// look for potential signals by searching FFT bins for Costas symbol
|
||||
// blocks. returns a vector of candidate positions.
|
||||
//
|
||||
std::vector<Strength> FT8::coarse(const ffts_t &bins, int si0, int si1)
|
||||
std::vector<Strength> FT8::coarse(const FFTEngine::ffts_t &bins, int si0, int si1)
|
||||
{
|
||||
int block = blocksize(rate_);
|
||||
int nbins = bins[0].size();
|
||||
@ -579,8 +581,8 @@ std::vector<float> FT8::reduce_rate(
|
||||
}
|
||||
|
||||
int alen = a.size();
|
||||
std::vector<std::complex<float>> bins1 = one_fft(a, 0, alen,
|
||||
"reduce_rate1", 0);
|
||||
std::vector<std::complex<float>> bins1 = fftEngine_->one_fft(
|
||||
a, 0, alen, "reduce_rate1", 0);
|
||||
int nbins1 = bins1.size();
|
||||
float bin_hz = arate / (float)alen;
|
||||
|
||||
@ -630,7 +632,7 @@ std::vector<float> FT8::reduce_rate(
|
||||
}
|
||||
|
||||
// use ifft to reduce the rate.
|
||||
std::vector<float> vvv = one_ifft(bbins, "reduce_rate2");
|
||||
std::vector<float> vvv = fftEngine_->one_ifft(bbins, "reduce_rate2");
|
||||
|
||||
delta_hz = delta * bin_hz;
|
||||
|
||||
@ -640,7 +642,7 @@ std::vector<float> FT8::reduce_rate(
|
||||
void FT8::go(int npasses)
|
||||
{
|
||||
// cache to avoid cost of fftw planner mutex.
|
||||
plan32_ = get_plan(32, "cache32");
|
||||
plan32_ = fftEngine_->get_plan(32, "cache32");
|
||||
|
||||
if (0)
|
||||
{
|
||||
@ -831,8 +833,8 @@ void FT8::go(int npasses)
|
||||
|
||||
// just do this once, re-use for every fractional fft_shift
|
||||
// and down_v7_f() to 200 sps.
|
||||
std::vector<std::complex<float>> bins = one_fft(samples_, 0, samples_.size(),
|
||||
"go1", 0);
|
||||
std::vector<std::complex<float>> bins = fftEngine_->one_fft(
|
||||
samples_, 0, samples_.size(), "go1", 0);
|
||||
|
||||
for (int hz_frac_i = 0; hz_frac_i < params.coarse_hz_n; hz_frac_i++)
|
||||
{
|
||||
@ -851,7 +853,7 @@ void FT8::go(int npasses)
|
||||
for (int off_frac_i = 0; off_frac_i < params.coarse_off_n; off_frac_i++)
|
||||
{
|
||||
int off_frac = off_frac_i * (block / params.coarse_off_n);
|
||||
ffts_t bins = ffts(samples1, off_frac, block, "go2");
|
||||
FFTEngine::ffts_t bins = fftEngine_->ffts(samples1, off_frac, block, "go2");
|
||||
std::vector<Strength> oo = coarse(bins, si0, si1);
|
||||
for (int i = 0; i < (int)oo.size(); i++)
|
||||
{
|
||||
@ -927,7 +929,7 @@ float FT8::one_strength(const std::vector<float> &samples200, float hz, int off)
|
||||
int start = starts[which];
|
||||
for (int si = 0; si < 7; si++)
|
||||
{
|
||||
auto fft = one_fft(samples200, off + (si + start) * 32, 32, "one_strength", plan32_);
|
||||
auto fft = fftEngine_->one_fft(samples200, off + (si + start) * 32, 32, "one_strength", plan32_);
|
||||
for (int bi = 0; bi < 8; bi++)
|
||||
{
|
||||
float x = std::abs(fft[bin0 + bi]);
|
||||
@ -1004,7 +1006,8 @@ float FT8::one_strength_known(
|
||||
|
||||
for (int si = 0; si < 79; si += params.known_sparse)
|
||||
{
|
||||
auto fft = one_fft(samples, off + si * block, block, "one_strength_known", 0);
|
||||
auto fft = fftEngine_->one_fft(samples, off + si * block, block, "one_strength_known", 0);
|
||||
|
||||
if (params.known_strength_how == 7)
|
||||
{
|
||||
std::complex<float> c = fft[bin0 + syms[si]];
|
||||
@ -1226,7 +1229,7 @@ void FT8::search_both_known(
|
||||
int best_off = 0;
|
||||
float best_strength = 0;
|
||||
|
||||
std::vector<std::complex<float>> bins = one_fft(samples, 0, samples.size(), "stfk", 0);
|
||||
std::vector<std::complex<float>> bins = fftEngine_->one_fft(samples, 0, samples.size(), "stfk", 0);
|
||||
|
||||
float hz_start, hz_inc, hz_end;
|
||||
if (params.third_hz_n > 1)
|
||||
@ -1290,7 +1293,7 @@ std::vector<float> FT8::fft_shift(
|
||||
}
|
||||
else
|
||||
{
|
||||
bins = one_fft(samples, off, len, "fft_shift", 0);
|
||||
bins = fftEngine_->one_fft(samples, off, len, "fft_shift", 0);
|
||||
hack_bins_ = bins;
|
||||
hack_size_ = samples.size();
|
||||
hack_off_ = off;
|
||||
@ -1331,7 +1334,7 @@ std::vector<float> FT8::fft_shift_f(
|
||||
bins1[i] = 0;
|
||||
}
|
||||
}
|
||||
std::vector<float> out = one_ifft(bins1, "fft_shift");
|
||||
std::vector<float> out = fftEngine_->one_ifft(bins1, "fft_shift");
|
||||
return out;
|
||||
}
|
||||
|
||||
@ -1356,12 +1359,12 @@ std::vector<float> FT8::shift200(
|
||||
}
|
||||
|
||||
// returns a mini-FFT of 79 8-tone symbols.
|
||||
ffts_t FT8::extract(const std::vector<float> &samples200, float, int off)
|
||||
FFTEngine::ffts_t FT8::extract(const std::vector<float> &samples200, float, int off)
|
||||
{
|
||||
|
||||
ffts_t bins3 = ffts(samples200, off, 32, "extract");
|
||||
FFTEngine::ffts_t bins3 = fftEngine_->ffts(samples200, off, 32, "extract");
|
||||
FFTEngine::ffts_t m79(79);
|
||||
|
||||
ffts_t m79(79);
|
||||
for (int si = 0; si < 79; si++)
|
||||
{
|
||||
m79[si].resize(8);
|
||||
@ -1388,9 +1391,9 @@ ffts_t FT8::extract(const std::vector<float> &samples200, float, int off)
|
||||
//
|
||||
// m79 is a 79x8 array of complex.
|
||||
//
|
||||
ffts_t FT8::un_gray_code_c(const ffts_t &m79)
|
||||
FFTEngine::ffts_t FT8::un_gray_code_c(const FFTEngine::ffts_t &m79)
|
||||
{
|
||||
ffts_t m79a(79);
|
||||
FFTEngine::ffts_t m79a(79);
|
||||
|
||||
int map[] = {0, 1, 3, 2, 6, 4, 5, 7};
|
||||
for (int si = 0; si < 79; si++)
|
||||
@ -1687,7 +1690,7 @@ void FT8::make_stats(
|
||||
// number of cycles and thus preserves phase from one symbol to the
|
||||
// next.
|
||||
//
|
||||
std::vector<std::vector<float>> FT8::soft_c2m(const ffts_t &c79)
|
||||
std::vector<std::vector<float>> FT8::soft_c2m(const FFTEngine::ffts_t &c79)
|
||||
{
|
||||
std::vector<std::vector<float>> m79(79);
|
||||
std::vector<float> raw_phases(79); // of strongest tone in each symbol time
|
||||
@ -1859,7 +1862,7 @@ float FT8::bayes(
|
||||
//
|
||||
// c79 is 79x8 complex tones, before un-gray-coding.
|
||||
//
|
||||
void FT8::soft_decode(const ffts_t &c79, float ll174[])
|
||||
void FT8::soft_decode(const FFTEngine::ffts_t &c79, float ll174[])
|
||||
{
|
||||
std::vector<std::vector<float>> m79(79);
|
||||
|
||||
@ -1974,9 +1977,9 @@ void FT8::soft_decode(const ffts_t &c79, float ll174[])
|
||||
//
|
||||
// c79 is 79x8 complex tones, before un-gray-coding.
|
||||
//
|
||||
void FT8::c_soft_decode(const ffts_t &c79x, float ll174[])
|
||||
void FT8::c_soft_decode(const FFTEngine::ffts_t &c79x, float ll174[])
|
||||
{
|
||||
ffts_t c79 = c_convert_to_snr(c79x);
|
||||
FFTEngine::ffts_t c79 = c_convert_to_snr(c79x);
|
||||
|
||||
int costas[] = {3, 1, 4, 0, 6, 5, 2};
|
||||
std::complex<float> maxes[79];
|
||||
@ -2185,11 +2188,11 @@ std::vector<float> FT8::extract_bits(const std::vector<int> &syms, const std::ve
|
||||
// that they have the same phase, by summing the complex
|
||||
// correlations for each possible pair and using the max.
|
||||
void FT8::soft_decode_pairs(
|
||||
const ffts_t &m79x,
|
||||
const FFTEngine::ffts_t &m79x,
|
||||
float ll174[]
|
||||
)
|
||||
{
|
||||
ffts_t m79 = c_convert_to_snr(m79x);
|
||||
FFTEngine::ffts_t m79 = c_convert_to_snr(m79x);
|
||||
|
||||
struct BitInfo
|
||||
{
|
||||
@ -2319,11 +2322,11 @@ void FT8::soft_decode_pairs(
|
||||
}
|
||||
|
||||
void FT8::soft_decode_triples(
|
||||
const ffts_t &m79x,
|
||||
const FFTEngine::ffts_t &m79x,
|
||||
float ll174[]
|
||||
)
|
||||
{
|
||||
ffts_t m79 = c_convert_to_snr(m79x);
|
||||
FFTEngine::ffts_t m79 = c_convert_to_snr(m79x);
|
||||
|
||||
struct BitInfo
|
||||
{
|
||||
@ -2610,7 +2613,7 @@ std::vector<std::complex<float>> FT8::fbandpass(
|
||||
std::vector<float> FT8::down_v7(const std::vector<float> &samples, float hz)
|
||||
{
|
||||
int len = samples.size();
|
||||
std::vector<std::complex<float>> bins = one_fft(samples, 0, len, "down_v7a", 0);
|
||||
std::vector<std::complex<float>> bins = fftEngine_->one_fft(samples, 0, len, "down_v7a", 0);
|
||||
|
||||
return down_v7_f(bins, len, hz);
|
||||
}
|
||||
@ -2655,7 +2658,7 @@ std::vector<float> FT8::down_v7_f(const std::vector<std::complex<float>> &bins,
|
||||
std::vector<std::complex<float>> bbins(blen / 2 + 1);
|
||||
for (int i = 0; i < (int)bbins.size(); i++)
|
||||
bbins[i] = bins1[i];
|
||||
std::vector<float> out = one_ifft(bbins, "down_v7b");
|
||||
std::vector<float> out = fftEngine_->one_ifft(bbins, "down_v7b");
|
||||
|
||||
return out;
|
||||
}
|
||||
@ -2731,7 +2734,7 @@ int FT8::one_iter(const std::vector<float> &samples200, int best_off, float hz_f
|
||||
// estimate SNR, yielding numbers vaguely similar to WSJT-X.
|
||||
// m79 is a 79x8 complex FFT output.
|
||||
//
|
||||
float FT8::guess_snr(const ffts_t &m79)
|
||||
float FT8::guess_snr(const FFTEngine::ffts_t &m79)
|
||||
{
|
||||
int costas[] = {3, 1, 4, 0, 6, 5, 2};
|
||||
float noises = 0;
|
||||
@ -2798,7 +2801,7 @@ float FT8::guess_snr(const ffts_t &m79)
|
||||
// adj_off is the amount to change the offset, in samples.
|
||||
// should be subtracted from offset.
|
||||
//
|
||||
void FT8::fine(const ffts_t &m79, int, float &adj_hz, float &adj_off)
|
||||
void FT8::fine(const FFTEngine::ffts_t &m79, int, float &adj_hz, float &adj_off)
|
||||
{
|
||||
adj_hz = 0.0;
|
||||
adj_off = 0.0;
|
||||
@ -2991,7 +2994,7 @@ int FT8::one_iter1(
|
||||
best_hz);
|
||||
|
||||
// mini 79x8 FFT.
|
||||
ffts_t m79 = extract(samples200, 25, best_off);
|
||||
FFTEngine::ffts_t m79 = extract(samples200, 25, best_off);
|
||||
|
||||
// look at symbol-to-symbol phase change to try
|
||||
// to improve best_hz and best_off.
|
||||
@ -3157,9 +3160,9 @@ void FT8::subtract(
|
||||
// move nsamples so that signal is centered in bin0.
|
||||
float diff0 = (bin0 * bin_hz) - hz0;
|
||||
float diff1 = (bin0 * bin_hz) - hz1;
|
||||
std::vector<float> moved = hilbert_shift(nsamples_, diff0, diff1, rate_);
|
||||
std::vector<float> moved = fftEngine_->hilbert_shift(nsamples_, diff0, diff1, rate_);
|
||||
|
||||
ffts_t bins = ffts(moved, off0, block, "subtract");
|
||||
FFTEngine::ffts_t bins = fftEngine_->ffts(moved, off0, block, "subtract");
|
||||
|
||||
if (bin0 + 8 > (int)bins[0].size())
|
||||
return;
|
||||
@ -3291,7 +3294,7 @@ void FT8::subtract(
|
||||
}
|
||||
}
|
||||
|
||||
nsamples_ = hilbert_shift(moved, -diff0, -diff1, rate_);
|
||||
nsamples_ = fftEngine_->hilbert_shift(moved, -diff0, -diff1, rate_);
|
||||
}
|
||||
|
||||
//
|
||||
@ -3311,7 +3314,7 @@ int FT8::try_decode(
|
||||
float,
|
||||
int use_osd,
|
||||
const char *comment1,
|
||||
const ffts_t &m79
|
||||
const FFTEngine::ffts_t &m79
|
||||
)
|
||||
{
|
||||
int a174[174];
|
||||
@ -3467,6 +3470,7 @@ void FT8Decoder::entry(
|
||||
double t0 = now();
|
||||
double deadline = t0 + time_left;
|
||||
double final_deadline = t0 + total_time_left;
|
||||
FFTEngine fftEngine;
|
||||
|
||||
// decodes from previous runs, for subtraction.
|
||||
std::vector<cdecode> prevdecs;
|
||||
@ -3520,7 +3524,8 @@ void FT8Decoder::entry(
|
||||
deadline,
|
||||
final_deadline,
|
||||
cb,
|
||||
prevdecs
|
||||
prevdecs,
|
||||
&fftEngine
|
||||
);
|
||||
ft8->getParams() = getParams(); // transfer parameters
|
||||
|
||||
|
30
ft8/ft8.h
30
ft8/ft8.h
@ -292,7 +292,7 @@ public:
|
||||
std::vector<std::complex<float>> hack_bins_;
|
||||
std::vector<cdecode> prevdecs_;
|
||||
|
||||
Plan *plan32_;
|
||||
FFTEngine::Plan *plan32_;
|
||||
|
||||
FT8(
|
||||
const std::vector<float> &samples,
|
||||
@ -305,12 +305,13 @@ public:
|
||||
double deadline,
|
||||
double final_deadline,
|
||||
CallbackInterface *cb,
|
||||
std::vector<cdecode> prevdecs
|
||||
std::vector<cdecode> prevdecs,
|
||||
FFTEngine *fftEngine
|
||||
);
|
||||
~FT8();
|
||||
// strength of costas block of signal with tone 0 at bi0,
|
||||
// and symbol zero at si0.
|
||||
float one_coarse_strength(const ffts_t &bins, int bi0, int 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.
|
||||
@ -319,7 +320,7 @@ public:
|
||||
// look for potential signals by searching FFT bins for Costas symbol
|
||||
// blocks. returns a vector of candidate positions.
|
||||
//
|
||||
std::vector<Strength> coarse(const ffts_t &bins, int si0, int si1);
|
||||
std::vector<Strength> coarse(const FFTEngine::ffts_t &bins, int si0, int si1);
|
||||
//
|
||||
// reduce the sample rate from arate to brate.
|
||||
// center hz0..hz1 in the new nyquist range.
|
||||
@ -425,11 +426,11 @@ public:
|
||||
float hz
|
||||
);
|
||||
// returns a mini-FFT of 79 8-tone symbols.
|
||||
ffts_t extract(const std::vector<float> &samples200, float, int off);
|
||||
FFTEngine::ffts_t extract(const std::vector<float> &samples200, float, int off);
|
||||
//
|
||||
// m79 is a 79x8 array of complex.
|
||||
//
|
||||
ffts_t un_gray_code_c(const ffts_t &m79);
|
||||
FFTEngine::ffts_t un_gray_code_c(const FFTEngine::ffts_t &m79);
|
||||
//
|
||||
// m79 is a 79x8 array of float.
|
||||
//
|
||||
@ -468,7 +469,7 @@ public:
|
||||
// number of cycles and thus preserves phase from one symbol to the
|
||||
// next.
|
||||
//
|
||||
std::vector<std::vector<float>> soft_c2m(const ffts_t &c79);
|
||||
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
|
||||
@ -486,11 +487,11 @@ public:
|
||||
//
|
||||
// c79 is 79x8 complex tones, before un-gray-coding.
|
||||
//
|
||||
void soft_decode(const ffts_t &c79, float ll174[]);
|
||||
void soft_decode(const FFTEngine::ffts_t &c79, float ll174[]);
|
||||
//
|
||||
// c79 is 79x8 complex tones, before un-gray-coding.
|
||||
//
|
||||
void c_soft_decode(const ffts_t &c79x, float ll174[]);
|
||||
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,
|
||||
@ -506,11 +507,11 @@ public:
|
||||
// that they have the same phase, by summing the complex
|
||||
// correlations for each possible pair and using the max.
|
||||
void soft_decode_pairs(
|
||||
const ffts_t &m79x,
|
||||
const FFTEngine::ffts_t &m79x,
|
||||
float ll174[]
|
||||
);
|
||||
void soft_decode_triples(
|
||||
const ffts_t &m79x,
|
||||
const FFTEngine::ffts_t &m79x,
|
||||
float ll174[]
|
||||
);
|
||||
//
|
||||
@ -563,7 +564,7 @@ public:
|
||||
// estimate SNR, yielding numbers vaguely similar to WSJT-X.
|
||||
// m79 is a 79x8 complex FFT output.
|
||||
//
|
||||
float guess_snr(const ffts_t &m79);
|
||||
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.
|
||||
@ -584,7 +585,7 @@ public:
|
||||
// adj_off is the amount to change the offset, in samples.
|
||||
// should be subtracted from offset.
|
||||
//
|
||||
void fine(const ffts_t &m79, int, float &adj_hz, float &adj_off);
|
||||
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,
|
||||
@ -615,7 +616,7 @@ public:
|
||||
float,
|
||||
int use_osd,
|
||||
const char *comment1,
|
||||
const ffts_t &m79
|
||||
const FFTEngine::ffts_t &m79
|
||||
);
|
||||
//
|
||||
// given 174 bits corrected by LDPC, work
|
||||
@ -644,6 +645,7 @@ public:
|
||||
FT8Params& getParams() { return params; }
|
||||
private:
|
||||
FT8Params params;
|
||||
FFTEngine *fftEngine_;
|
||||
static const double apriori174[];
|
||||
}; // class FT8
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user