mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 10:05:46 -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 "fft.h"
|
||||||
#include <mutex>
|
|
||||||
// #include <unistd.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
// #include <sys/file.h>
|
|
||||||
// #include <sys/types.h>
|
|
||||||
// #include <sys/stat.h>
|
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
#define TIMING 0
|
#define TIMING 0
|
||||||
|
|
||||||
namespace FT8 {
|
namespace FT8 {
|
||||||
|
|
||||||
// MEASURE=0, ESTIMATE=64, PATIENT=32
|
FFTEngine::Plan *FFTEngine::get_plan(int n, const char *why)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
// cache fftw plans in the parent process,
|
// cache fftw plans in the parent process,
|
||||||
// so they will already be there for fork()ed children.
|
// so they will already be there for fork()ed children.
|
||||||
|
|
||||||
plansmu.lock();
|
plansmu.lock();
|
||||||
|
|
||||||
// if (plan_master_pid == 0)
|
|
||||||
// {
|
|
||||||
// plan_master_pid = getpid();
|
|
||||||
// }
|
|
||||||
|
|
||||||
for (int i = 0; i < nplans; i++)
|
for (int i = 0; i < nplans; i++)
|
||||||
{
|
{
|
||||||
if (plans[i]->n_ == n && plans[i]->type_ == fftw_type
|
if (plans[i]->n_ == n && plans[i]->type_ == fftw_type
|
||||||
@ -73,16 +54,6 @@ Plan *get_plan(int n, const char *why)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// fftw_make_planner_thread_safe();
|
// 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();
|
plansmu2.lock();
|
||||||
|
|
||||||
fftwf_set_timelimit(5);
|
fftwf_set_timelimit(5);
|
||||||
@ -109,10 +80,6 @@ Plan *get_plan(int n, const char *why)
|
|||||||
// FFTW_PATIENT
|
// FFTW_PATIENT
|
||||||
// FFTW_EXHAUSTIVE
|
// FFTW_EXHAUSTIVE
|
||||||
int type = fftw_type;
|
int type = fftw_type;
|
||||||
// if (getpid() != plan_master_pid)
|
|
||||||
// {
|
|
||||||
// type = FFTW_ESTIMATE;
|
|
||||||
// }
|
|
||||||
p->type_ = type;
|
p->type_ = type;
|
||||||
p->fwd_ = fftwf_plan_dft_r2c_1d(n, p->r_, p->c_, type);
|
p->fwd_ = fftwf_plan_dft_r2c_1d(n, p->r_, p->c_, type);
|
||||||
assert(p->fwd_);
|
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);
|
p->crev_ = fftwf_plan_dft_1d(n, p->cc2_, p->cc1_, FFTW_BACKWARD, type);
|
||||||
assert(p->crev_);
|
assert(p->crev_);
|
||||||
|
|
||||||
// flock(lockfd, LOCK_UN);
|
|
||||||
// close(lockfd);
|
|
||||||
plansmu2.unlock();
|
plansmu2.unlock();
|
||||||
|
|
||||||
assert(nplans + 1 < 1000);
|
assert(nplans + 1 < 1000);
|
||||||
|
|
||||||
plans[nplans] = p;
|
plans[nplans] = p;
|
||||||
// __sync_synchronize();
|
|
||||||
nplans += 1;
|
nplans += 1;
|
||||||
|
|
||||||
#if TIMING
|
#if TIMING
|
||||||
@ -160,12 +124,12 @@ Plan *get_plan(int n, const char *why)
|
|||||||
// real inputs, complex outputs.
|
// real inputs, complex outputs.
|
||||||
// output has (block / 2) + 1 points.
|
// 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,
|
const std::vector<float> &samples,
|
||||||
int i0,
|
int i0,
|
||||||
int block,
|
int block,
|
||||||
const char *why,
|
const char *why,
|
||||||
Plan *p
|
FFTEngine::Plan *p
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
assert(i0 >= 0);
|
assert(i0 >= 0);
|
||||||
@ -242,7 +206,7 @@ std::vector<std::complex<float>> one_fft(
|
|||||||
// do a full set of FFTs, one per symbol-time.
|
// do a full set of FFTs, one per symbol-time.
|
||||||
// bins[time][frequency]
|
// 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(i0 >= 0);
|
||||||
assert(block > 1 && (block % 2) == 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.
|
// real inputs, complex outputs.
|
||||||
// output has block points.
|
// 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,
|
const std::vector<float> &samples,
|
||||||
int i0,
|
int i0,
|
||||||
int block,
|
int block,
|
||||||
@ -373,7 +337,7 @@ std::vector<std::complex<float>> one_fft_c(
|
|||||||
return out;
|
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,
|
const std::vector<std::complex<float>> &samples,
|
||||||
int i0,
|
int i0,
|
||||||
int block,
|
int block,
|
||||||
@ -434,7 +398,7 @@ std::vector<std::complex<float>> one_fft_cc(
|
|||||||
return out;
|
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 std::vector<std::complex<float>> &bins,
|
||||||
const char *why
|
const char *why
|
||||||
)
|
)
|
||||||
@ -483,7 +447,7 @@ std::vector<std::complex<float>> one_ifft_cc(
|
|||||||
return out;
|
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 nbins = bins.size();
|
||||||
int block = (nbins - 1) * 2;
|
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.
|
// 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();
|
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().
|
// 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)
|
// y = scipy.signal.hilbert(x)
|
||||||
std::vector<std::complex<float>> y = analytic(x, "hilbert_shift");
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fft_stats()
|
void FFTEngine::fft_stats()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < nplans; i++)
|
for (int i = 0; i < nplans; i++)
|
||||||
{
|
{
|
||||||
|
91
ft8/fft.h
91
ft8/fft.h
@ -22,56 +22,73 @@
|
|||||||
#ifndef FFT_H
|
#ifndef FFT_H
|
||||||
#define FFT_H
|
#define FFT_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <complex>
|
#include <complex>
|
||||||
#include <fftw3.h>
|
#include <fftw3.h>
|
||||||
|
|
||||||
namespace FT8
|
namespace FT8
|
||||||
{
|
{
|
||||||
// a cached fftw plan, for both of:
|
class FFTEngine
|
||||||
// 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:
|
public:
|
||||||
int n_;
|
// a cached fftw plan, for both of:
|
||||||
int type_;
|
// 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
|
// real -> complex
|
||||||
//
|
//
|
||||||
fftwf_complex *c_; // (n_ / 2) + 1 of these
|
fftwf_complex *c_; // (n_ / 2) + 1 of these
|
||||||
float *r_; // n_ of these
|
float *r_; // n_ of these
|
||||||
fftwf_plan fwd_; // forward plan
|
fftwf_plan fwd_; // forward plan
|
||||||
fftwf_plan rev_; // reverse plan
|
fftwf_plan rev_; // reverse plan
|
||||||
|
|
||||||
//
|
//
|
||||||
// complex -> complex
|
// complex -> complex
|
||||||
//
|
//
|
||||||
fftwf_complex *cc1_; // n
|
fftwf_complex *cc1_; // n
|
||||||
fftwf_complex *cc2_; // n
|
fftwf_complex *cc2_; // n
|
||||||
fftwf_plan cfwd_; // forward plan
|
fftwf_plan cfwd_; // forward plan
|
||||||
fftwf_plan crev_; // reverse plan
|
fftwf_plan crev_; // reverse plan
|
||||||
|
|
||||||
// how much CPU time spent in FFTs that use this plan.
|
// how much CPU time spent in FFTs that use this plan.
|
||||||
#if TIMING
|
#if TIMING
|
||||||
double time_;
|
double time_;
|
||||||
#endif
|
#endif
|
||||||
const char *why_;
|
const char *why_;
|
||||||
int uses_;
|
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);
|
Plan *get_plan(int n, const char *why);
|
||||||
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;
|
std::vector<std::complex<float>> one_fft(const std::vector<float> &samples, int i0, int block, const char *why, Plan *p);
|
||||||
ffts_t ffts(const std::vector<float> &samples, int i0, int block, const char *why);
|
std::vector<float> one_ifft(const std::vector<std::complex<float>> &bins, const char *why);
|
||||||
std::vector<std::complex<float>> one_fft_c(const std::vector<float> &samples, int i0, int block, const char *why);
|
typedef std::vector<std::vector<std::complex<float>>> ffts_t;
|
||||||
std::vector<std::complex<float>> one_fft_cc(const std::vector<std::complex<float>> &samples, int i0, int block, const char *why);
|
ffts_t ffts(const std::vector<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>> one_fft_c(const std::vector<float> &samples, int i0, int block, const char *why);
|
||||||
std::vector<std::complex<float>> analytic(const std::vector<float> &x, 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<float> hilbert_shift(const std::vector<float> &x, float hz0, float hz1, int rate);
|
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
|
} // namespace FT8
|
||||||
|
|
||||||
|
85
ft8/ft8.cpp
85
ft8/ft8.cpp
@ -326,7 +326,8 @@ FT8::FT8(
|
|||||||
double deadline,
|
double deadline,
|
||||||
double final_deadline,
|
double final_deadline,
|
||||||
CallbackInterface *cb,
|
CallbackInterface *cb,
|
||||||
std::vector<cdecode> prevdecs
|
std::vector<cdecode> prevdecs,
|
||||||
|
FFTEngine *fftEngine
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
samples_ = samples;
|
samples_ = samples;
|
||||||
@ -349,11 +350,12 @@ FT8::FT8(
|
|||||||
}
|
}
|
||||||
|
|
||||||
hack_size_ = -1;
|
hack_size_ = -1;
|
||||||
hack_data_ = 0;
|
hack_data_ = nullptr;
|
||||||
hack_off_ = -1;
|
hack_off_ = -1;
|
||||||
hack_len_ = -1;
|
hack_len_ = -1;
|
||||||
|
|
||||||
plan32_ = 0;
|
plan32_ = nullptr;
|
||||||
|
fftEngine_ = fftEngine;
|
||||||
}
|
}
|
||||||
|
|
||||||
FT8::~FT8()
|
FT8::~FT8()
|
||||||
@ -362,7 +364,7 @@ FT8::~FT8()
|
|||||||
|
|
||||||
// strength of costas block of signal with tone 0 at bi0,
|
// strength of costas block of signal with tone 0 at bi0,
|
||||||
// and symbol zero at si0.
|
// 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};
|
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
|
// look for potential signals by searching FFT bins for Costas symbol
|
||||||
// blocks. returns a vector of candidate positions.
|
// 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 block = blocksize(rate_);
|
||||||
int nbins = bins[0].size();
|
int nbins = bins[0].size();
|
||||||
@ -579,8 +581,8 @@ std::vector<float> FT8::reduce_rate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
int alen = a.size();
|
int alen = a.size();
|
||||||
std::vector<std::complex<float>> bins1 = one_fft(a, 0, alen,
|
std::vector<std::complex<float>> bins1 = fftEngine_->one_fft(
|
||||||
"reduce_rate1", 0);
|
a, 0, alen, "reduce_rate1", 0);
|
||||||
int nbins1 = bins1.size();
|
int nbins1 = bins1.size();
|
||||||
float bin_hz = arate / (float)alen;
|
float bin_hz = arate / (float)alen;
|
||||||
|
|
||||||
@ -630,7 +632,7 @@ std::vector<float> FT8::reduce_rate(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// use ifft to reduce the 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;
|
delta_hz = delta * bin_hz;
|
||||||
|
|
||||||
@ -640,7 +642,7 @@ std::vector<float> FT8::reduce_rate(
|
|||||||
void FT8::go(int npasses)
|
void FT8::go(int npasses)
|
||||||
{
|
{
|
||||||
// cache to avoid cost of fftw planner mutex.
|
// cache to avoid cost of fftw planner mutex.
|
||||||
plan32_ = get_plan(32, "cache32");
|
plan32_ = fftEngine_->get_plan(32, "cache32");
|
||||||
|
|
||||||
if (0)
|
if (0)
|
||||||
{
|
{
|
||||||
@ -831,8 +833,8 @@ void FT8::go(int npasses)
|
|||||||
|
|
||||||
// just do this once, re-use for every fractional fft_shift
|
// just do this once, re-use for every fractional fft_shift
|
||||||
// and down_v7_f() to 200 sps.
|
// and down_v7_f() to 200 sps.
|
||||||
std::vector<std::complex<float>> bins = one_fft(samples_, 0, samples_.size(),
|
std::vector<std::complex<float>> bins = fftEngine_->one_fft(
|
||||||
"go1", 0);
|
samples_, 0, samples_.size(), "go1", 0);
|
||||||
|
|
||||||
for (int hz_frac_i = 0; hz_frac_i < params.coarse_hz_n; hz_frac_i++)
|
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++)
|
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);
|
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);
|
std::vector<Strength> oo = coarse(bins, si0, si1);
|
||||||
for (int i = 0; i < (int)oo.size(); i++)
|
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];
|
int start = starts[which];
|
||||||
for (int si = 0; si < 7; si++)
|
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++)
|
for (int bi = 0; bi < 8; bi++)
|
||||||
{
|
{
|
||||||
float x = std::abs(fft[bin0 + 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)
|
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)
|
if (params.known_strength_how == 7)
|
||||||
{
|
{
|
||||||
std::complex<float> c = fft[bin0 + syms[si]];
|
std::complex<float> c = fft[bin0 + syms[si]];
|
||||||
@ -1226,7 +1229,7 @@ void FT8::search_both_known(
|
|||||||
int best_off = 0;
|
int best_off = 0;
|
||||||
float best_strength = 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;
|
float hz_start, hz_inc, hz_end;
|
||||||
if (params.third_hz_n > 1)
|
if (params.third_hz_n > 1)
|
||||||
@ -1290,7 +1293,7 @@ std::vector<float> FT8::fft_shift(
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bins = one_fft(samples, off, len, "fft_shift", 0);
|
bins = fftEngine_->one_fft(samples, off, len, "fft_shift", 0);
|
||||||
hack_bins_ = bins;
|
hack_bins_ = bins;
|
||||||
hack_size_ = samples.size();
|
hack_size_ = samples.size();
|
||||||
hack_off_ = off;
|
hack_off_ = off;
|
||||||
@ -1331,7 +1334,7 @@ std::vector<float> FT8::fft_shift_f(
|
|||||||
bins1[i] = 0;
|
bins1[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::vector<float> out = one_ifft(bins1, "fft_shift");
|
std::vector<float> out = fftEngine_->one_ifft(bins1, "fft_shift");
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1356,12 +1359,12 @@ std::vector<float> FT8::shift200(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns a mini-FFT of 79 8-tone symbols.
|
// 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++)
|
for (int si = 0; si < 79; si++)
|
||||||
{
|
{
|
||||||
m79[si].resize(8);
|
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.
|
// 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};
|
int map[] = {0, 1, 3, 2, 6, 4, 5, 7};
|
||||||
for (int si = 0; si < 79; si++)
|
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
|
// number of cycles and thus preserves phase from one symbol to the
|
||||||
// next.
|
// 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<std::vector<float>> m79(79);
|
||||||
std::vector<float> raw_phases(79); // of strongest tone in each symbol time
|
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.
|
// 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);
|
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.
|
// 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};
|
int costas[] = {3, 1, 4, 0, 6, 5, 2};
|
||||||
std::complex<float> maxes[79];
|
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
|
// that they have the same phase, by summing the complex
|
||||||
// correlations for each possible pair and using the max.
|
// correlations for each possible pair and using the max.
|
||||||
void FT8::soft_decode_pairs(
|
void FT8::soft_decode_pairs(
|
||||||
const ffts_t &m79x,
|
const FFTEngine::ffts_t &m79x,
|
||||||
float ll174[]
|
float ll174[]
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ffts_t m79 = c_convert_to_snr(m79x);
|
FFTEngine::ffts_t m79 = c_convert_to_snr(m79x);
|
||||||
|
|
||||||
struct BitInfo
|
struct BitInfo
|
||||||
{
|
{
|
||||||
@ -2319,11 +2322,11 @@ void FT8::soft_decode_pairs(
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FT8::soft_decode_triples(
|
void FT8::soft_decode_triples(
|
||||||
const ffts_t &m79x,
|
const FFTEngine::ffts_t &m79x,
|
||||||
float ll174[]
|
float ll174[]
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
ffts_t m79 = c_convert_to_snr(m79x);
|
FFTEngine::ffts_t m79 = c_convert_to_snr(m79x);
|
||||||
|
|
||||||
struct BitInfo
|
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)
|
std::vector<float> FT8::down_v7(const std::vector<float> &samples, float hz)
|
||||||
{
|
{
|
||||||
int len = samples.size();
|
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);
|
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);
|
std::vector<std::complex<float>> bbins(blen / 2 + 1);
|
||||||
for (int i = 0; i < (int)bbins.size(); i++)
|
for (int i = 0; i < (int)bbins.size(); i++)
|
||||||
bbins[i] = bins1[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;
|
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.
|
// estimate SNR, yielding numbers vaguely similar to WSJT-X.
|
||||||
// m79 is a 79x8 complex FFT output.
|
// 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};
|
int costas[] = {3, 1, 4, 0, 6, 5, 2};
|
||||||
float noises = 0;
|
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.
|
// adj_off is the amount to change the offset, in samples.
|
||||||
// should be subtracted from offset.
|
// 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_hz = 0.0;
|
||||||
adj_off = 0.0;
|
adj_off = 0.0;
|
||||||
@ -2991,7 +2994,7 @@ int FT8::one_iter1(
|
|||||||
best_hz);
|
best_hz);
|
||||||
|
|
||||||
// mini 79x8 FFT.
|
// 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
|
// look at symbol-to-symbol phase change to try
|
||||||
// to improve best_hz and best_off.
|
// to improve best_hz and best_off.
|
||||||
@ -3157,9 +3160,9 @@ void FT8::subtract(
|
|||||||
// move nsamples so that signal is centered in bin0.
|
// move nsamples so that signal is centered in bin0.
|
||||||
float diff0 = (bin0 * bin_hz) - hz0;
|
float diff0 = (bin0 * bin_hz) - hz0;
|
||||||
float diff1 = (bin0 * bin_hz) - hz1;
|
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())
|
if (bin0 + 8 > (int)bins[0].size())
|
||||||
return;
|
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,
|
float,
|
||||||
int use_osd,
|
int use_osd,
|
||||||
const char *comment1,
|
const char *comment1,
|
||||||
const ffts_t &m79
|
const FFTEngine::ffts_t &m79
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
int a174[174];
|
int a174[174];
|
||||||
@ -3467,6 +3470,7 @@ void FT8Decoder::entry(
|
|||||||
double t0 = now();
|
double t0 = now();
|
||||||
double deadline = t0 + time_left;
|
double deadline = t0 + time_left;
|
||||||
double final_deadline = t0 + total_time_left;
|
double final_deadline = t0 + total_time_left;
|
||||||
|
FFTEngine fftEngine;
|
||||||
|
|
||||||
// decodes from previous runs, for subtraction.
|
// decodes from previous runs, for subtraction.
|
||||||
std::vector<cdecode> prevdecs;
|
std::vector<cdecode> prevdecs;
|
||||||
@ -3520,7 +3524,8 @@ void FT8Decoder::entry(
|
|||||||
deadline,
|
deadline,
|
||||||
final_deadline,
|
final_deadline,
|
||||||
cb,
|
cb,
|
||||||
prevdecs
|
prevdecs,
|
||||||
|
&fftEngine
|
||||||
);
|
);
|
||||||
ft8->getParams() = getParams(); // transfer parameters
|
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<std::complex<float>> hack_bins_;
|
||||||
std::vector<cdecode> prevdecs_;
|
std::vector<cdecode> prevdecs_;
|
||||||
|
|
||||||
Plan *plan32_;
|
FFTEngine::Plan *plan32_;
|
||||||
|
|
||||||
FT8(
|
FT8(
|
||||||
const std::vector<float> &samples,
|
const std::vector<float> &samples,
|
||||||
@ -305,12 +305,13 @@ public:
|
|||||||
double deadline,
|
double deadline,
|
||||||
double final_deadline,
|
double final_deadline,
|
||||||
CallbackInterface *cb,
|
CallbackInterface *cb,
|
||||||
std::vector<cdecode> prevdecs
|
std::vector<cdecode> prevdecs,
|
||||||
|
FFTEngine *fftEngine
|
||||||
);
|
);
|
||||||
~FT8();
|
~FT8();
|
||||||
// strength of costas block of signal with tone 0 at bi0,
|
// strength of costas block of signal with tone 0 at bi0,
|
||||||
// and symbol zero at si0.
|
// 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.
|
// return symbol length in samples at the given rate.
|
||||||
// insist on integer symbol lengths so that we can
|
// insist on integer symbol lengths so that we can
|
||||||
// use whole FFT bins.
|
// use whole FFT bins.
|
||||||
@ -319,7 +320,7 @@ public:
|
|||||||
// look for potential signals by searching FFT bins for Costas symbol
|
// look for potential signals by searching FFT bins for Costas symbol
|
||||||
// blocks. returns a vector of candidate positions.
|
// 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.
|
// reduce the sample rate from arate to brate.
|
||||||
// center hz0..hz1 in the new nyquist range.
|
// center hz0..hz1 in the new nyquist range.
|
||||||
@ -425,11 +426,11 @@ public:
|
|||||||
float hz
|
float hz
|
||||||
);
|
);
|
||||||
// returns a mini-FFT of 79 8-tone symbols.
|
// 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.
|
// 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.
|
// m79 is a 79x8 array of float.
|
||||||
//
|
//
|
||||||
@ -468,7 +469,7 @@ public:
|
|||||||
// number of cycles and thus preserves phase from one symbol to the
|
// number of cycles and thus preserves phase from one symbol to the
|
||||||
// next.
|
// 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,
|
// guess the probability that a bit is zero vs one,
|
||||||
// based on strengths of strongest tones that would
|
// based on strengths of strongest tones that would
|
||||||
@ -486,11 +487,11 @@ public:
|
|||||||
//
|
//
|
||||||
// c79 is 79x8 complex tones, before un-gray-coding.
|
// 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.
|
// 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.
|
// turn 79 symbol numbers into 174 bits.
|
||||||
// strip out the three Costas sync blocks,
|
// strip out the three Costas sync blocks,
|
||||||
@ -506,11 +507,11 @@ public:
|
|||||||
// that they have the same phase, by summing the complex
|
// that they have the same phase, by summing the complex
|
||||||
// correlations for each possible pair and using the max.
|
// correlations for each possible pair and using the max.
|
||||||
void soft_decode_pairs(
|
void soft_decode_pairs(
|
||||||
const ffts_t &m79x,
|
const FFTEngine::ffts_t &m79x,
|
||||||
float ll174[]
|
float ll174[]
|
||||||
);
|
);
|
||||||
void soft_decode_triples(
|
void soft_decode_triples(
|
||||||
const ffts_t &m79x,
|
const FFTEngine::ffts_t &m79x,
|
||||||
float ll174[]
|
float ll174[]
|
||||||
);
|
);
|
||||||
//
|
//
|
||||||
@ -563,7 +564,7 @@ public:
|
|||||||
// estimate SNR, yielding numbers vaguely similar to WSJT-X.
|
// estimate SNR, yielding numbers vaguely similar to WSJT-X.
|
||||||
// m79 is a 79x8 complex FFT output.
|
// 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
|
// compare phases of successive symbols to guess whether
|
||||||
// the starting offset is a little too high or low.
|
// 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.
|
// adj_off is the amount to change the offset, in samples.
|
||||||
// should be subtracted from offset.
|
// 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_,
|
// subtract a corrected decoded signal from nsamples_,
|
||||||
// perhaps revealing a weaker signal underneath,
|
// perhaps revealing a weaker signal underneath,
|
||||||
@ -615,7 +616,7 @@ public:
|
|||||||
float,
|
float,
|
||||||
int use_osd,
|
int use_osd,
|
||||||
const char *comment1,
|
const char *comment1,
|
||||||
const ffts_t &m79
|
const FFTEngine::ffts_t &m79
|
||||||
);
|
);
|
||||||
//
|
//
|
||||||
// given 174 bits corrected by LDPC, work
|
// given 174 bits corrected by LDPC, work
|
||||||
@ -644,6 +645,7 @@ public:
|
|||||||
FT8Params& getParams() { return params; }
|
FT8Params& getParams() { return params; }
|
||||||
private:
|
private:
|
||||||
FT8Params params;
|
FT8Params params;
|
||||||
|
FFTEngine *fftEngine_;
|
||||||
static const double apriori174[];
|
static const double apriori174[];
|
||||||
}; // class FT8
|
}; // class FT8
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user