mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-12-23 10:05:46 -05:00
FT8 demod: adapted to QThread
This commit is contained in:
parent
aaab8b5351
commit
6ecd110d14
@ -780,10 +780,7 @@ add_subdirectory(devices)
|
||||
add_subdirectory(sdrbench)
|
||||
|
||||
add_subdirectory(modemm17)
|
||||
|
||||
if (LINUX)
|
||||
add_subdirectory(ft8)
|
||||
endif()
|
||||
add_subdirectory(ft8)
|
||||
|
||||
if (BUILD_GUI)
|
||||
add_subdirectory(sdrgui)
|
||||
|
68
ft8/ft8.cpp
68
ft8/ft8.cpp
@ -33,15 +33,13 @@
|
||||
#include <math.h>
|
||||
#include <complex>
|
||||
#include <fftw3.h>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <complex>
|
||||
#include <random>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <thread>
|
||||
// #include <QDebug>
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#include "util.h"
|
||||
#include "ft8.h"
|
||||
@ -356,14 +354,21 @@ FT8::FT8(
|
||||
|
||||
plan32_ = nullptr;
|
||||
fftEngine_ = fftEngine;
|
||||
npasses_ = 1;
|
||||
}
|
||||
|
||||
FT8::~FT8()
|
||||
{
|
||||
}
|
||||
|
||||
// strength of costas block of signal with tone 0 at bi0,
|
||||
// and symbol zero at si0.
|
||||
void FT8::start_work()
|
||||
{
|
||||
go(npasses_);
|
||||
emit finished();
|
||||
}
|
||||
|
||||
// strength of costas block of signal with tone 0 at bi0,
|
||||
// and symbol zero at si0.
|
||||
float FT8::one_coarse_strength(const FFTEngine::ffts_t &bins, int bi0, int si0)
|
||||
{
|
||||
int costas[] = {3, 1, 4, 0, 6, 5, 2};
|
||||
@ -3448,8 +3453,13 @@ std::vector<int> FT8::recode(int a174[])
|
||||
return out79;
|
||||
}
|
||||
|
||||
FT8Decoder::~FT8Decoder()
|
||||
{
|
||||
forceQuit(); // stop all remaining running threads if any
|
||||
}
|
||||
|
||||
//
|
||||
// Python calls these.
|
||||
// Launch decoding
|
||||
//
|
||||
void FT8Decoder::entry(
|
||||
float xsamples[],
|
||||
@ -3470,7 +3480,6 @@ 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;
|
||||
@ -3494,7 +3503,6 @@ void FT8Decoder::entry(
|
||||
}
|
||||
|
||||
float per = (max_hz - min_hz) / params.nthreads;
|
||||
std::vector<std::pair<FT8*, std::thread*>> thv;
|
||||
|
||||
for (int i = 0; i < params.nthreads; i++)
|
||||
{
|
||||
@ -3530,15 +3538,45 @@ void FT8Decoder::entry(
|
||||
ft8->getParams() = getParams(); // transfer parameters
|
||||
|
||||
int npasses = nprevdecs > 0 ? params.npasses_two : params.npasses_one;
|
||||
std::thread *th = new std::thread([ft8, npasses] () { ft8->go(npasses); });
|
||||
thv.push_back(std::pair<FT8*, std::thread*>(ft8, th));
|
||||
ft8->set_npasses(npasses);
|
||||
QThread *th = new QThread();
|
||||
threads.push_back(th);
|
||||
// std::thread *th = new std::thread([ft8, npasses] () { ft8->go(npasses); });
|
||||
// thv.push_back(std::pair<FT8*, std::thread*>(ft8, th));
|
||||
ft8->moveToThread(th);
|
||||
QObject::connect(th, &QThread::started, ft8, &FT8::start_work);
|
||||
QObject::connect(ft8, &FT8::finished, th, &QThread::quit, Qt::DirectConnection);
|
||||
QObject::connect(th, &QThread::finished, ft8, &QObject::deleteLater);
|
||||
QObject::connect(th, &QThread::finished, th, &QThread::deleteLater);
|
||||
th->start();
|
||||
}
|
||||
}
|
||||
|
||||
void FT8Decoder::wait(double time_left)
|
||||
{
|
||||
unsigned long thread_timeout = time_left * 1000;
|
||||
|
||||
while (threads.size() != 0)
|
||||
{
|
||||
bool success = threads.front()->wait(thread_timeout);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
qDebug("FT8::FT8Decoder::wait: thread timed out");
|
||||
thread_timeout = 50; // only 50ms for the rest
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)thv.size(); i++)
|
||||
threads.erase(threads.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void FT8Decoder::forceQuit()
|
||||
{
|
||||
while (threads.size() != 0)
|
||||
{
|
||||
thv[i].second->join();
|
||||
delete thv[i].second;
|
||||
delete thv[i].first;
|
||||
threads.front()->quit();
|
||||
threads.front()->wait();
|
||||
threads.erase(threads.begin());
|
||||
}
|
||||
}
|
||||
|
||||
|
27
ft8/ft8.h
27
ft8/ft8.h
@ -21,11 +21,16 @@
|
||||
#ifndef ft8_h
|
||||
#define ft8_h
|
||||
|
||||
#include <QMutex>
|
||||
#include "fft.h"
|
||||
#include <vector>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMutex>
|
||||
|
||||
#include "fft.h"
|
||||
#include "export.h"
|
||||
|
||||
class QThread;
|
||||
|
||||
namespace FT8 {
|
||||
// Callback interface to get the results
|
||||
class FT8_API CallbackInterface
|
||||
@ -261,8 +266,9 @@ struct FT8_API FT8Params
|
||||
}; // class FT8Params
|
||||
|
||||
// The FT8 worker
|
||||
class FT8_API FT8
|
||||
class FT8_API FT8 : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
float min_hz_;
|
||||
float max_hz_;
|
||||
@ -308,6 +314,10 @@ public:
|
||||
FFTEngine *fftEngine
|
||||
);
|
||||
~FT8();
|
||||
// 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);
|
||||
@ -642,14 +652,19 @@ public:
|
||||
);
|
||||
|
||||
FT8Params& getParams() { return params; }
|
||||
signals:
|
||||
void finished();
|
||||
private:
|
||||
FT8Params params;
|
||||
FFTEngine *fftEngine_;
|
||||
int npasses_;
|
||||
static const double apriori174[];
|
||||
}; // class FT8
|
||||
|
||||
class FT8_API FT8Decoder {
|
||||
class FT8_API FT8Decoder : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
~FT8Decoder();
|
||||
void entry(
|
||||
float xsamples[],
|
||||
int nsamples,
|
||||
@ -665,9 +680,13 @@ public:
|
||||
int,
|
||||
struct cdecode *
|
||||
);
|
||||
void wait(double time_left); //!< wait for all threads to finish
|
||||
void forceQuit(); //!< force quit all threads
|
||||
FT8Params& getParams() { return params; }
|
||||
private:
|
||||
FFTEngine fftEngine;
|
||||
FT8Params params;
|
||||
std::vector<QThread*> threads;
|
||||
}; // FT8Decoder
|
||||
|
||||
} // namespace FT8
|
||||
|
@ -47,7 +47,8 @@ void MainBench::run()
|
||||
<< " nsamples: " << m_parser.getNbSamples()
|
||||
<< " repet: " << m_parser.getRepetition()
|
||||
<< " log2f: " << m_parser.getLog2Factor()
|
||||
<< " file: " << m_parser.getFileName();
|
||||
<< " file: " << m_parser.getFileName()
|
||||
<< " args: " << m_parser.getArgsStr();
|
||||
|
||||
if (m_parser.getTestType() == ParserBench::TestDecimatorsII) {
|
||||
testDecimateII();
|
||||
@ -64,7 +65,7 @@ void MainBench::run()
|
||||
} else if (m_parser.getTestType() == ParserBench::TestGolay2312) {
|
||||
testGolay2312();
|
||||
} else if (m_parser.getTestType() == ParserBench::TestFT8) {
|
||||
testFT8(m_parser.getFileName());
|
||||
testFT8(m_parser.getFileName(), m_parser.getArgsStr());
|
||||
} else {
|
||||
qDebug() << "MainBench::run: unknown test type: " << m_parser.getTestType();
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ private:
|
||||
void testDecimateFI();
|
||||
void testDecimateFF();
|
||||
void testGolay2312();
|
||||
void testFT8(const QString& wavFile); //!< use with sdrbench/samples/ft8/230105_091630.wav in -f option
|
||||
void testFT8(const QString& wavFile, const QString& argsStr); //!< use with sdrbench/samples/ft8/230105_091630.wav in -f option
|
||||
void decimateII(const qint16 *buf, int len);
|
||||
void decimateInfII(const qint16 *buf, int len);
|
||||
void decimateSupII(const qint16 *buf, int len);
|
||||
|
@ -42,6 +42,10 @@ ParserBench::ParserBench() :
|
||||
m_fileOption(QStringList() << "f" << "file",
|
||||
"File to be used for the test.",
|
||||
"file",
|
||||
""),
|
||||
m_argsOption(QStringList() << "a" << "args",
|
||||
"Custom arguments string to be used for the test.",
|
||||
"args",
|
||||
"")
|
||||
{
|
||||
m_testStr = "decimateii";
|
||||
@ -58,6 +62,7 @@ ParserBench::ParserBench() :
|
||||
m_parser.addOption(m_repetitionOption);
|
||||
m_parser.addOption(m_log2FactorOption);
|
||||
m_parser.addOption(m_fileOption);
|
||||
m_parser.addOption(m_argsOption);
|
||||
}
|
||||
|
||||
ParserBench::~ParserBench()
|
||||
@ -120,6 +125,10 @@ void ParserBench::parse(const QCoreApplication& app)
|
||||
// file
|
||||
|
||||
m_fileName = m_parser.value(m_fileOption);
|
||||
|
||||
// custom args
|
||||
|
||||
m_argsStr = m_parser.value(m_argsOption);
|
||||
}
|
||||
|
||||
ParserBench::TestType ParserBench::getTestType() const
|
||||
|
@ -50,6 +50,7 @@ public:
|
||||
uint32_t getRepetition() const { return m_repetition; }
|
||||
uint32_t getLog2Factor() const { return m_log2Factor; }
|
||||
const QString& getFileName() const { return m_fileName; }
|
||||
const QString& getArgsStr() const { return m_argsStr; }
|
||||
|
||||
private:
|
||||
QString m_testStr;
|
||||
@ -57,6 +58,7 @@ private:
|
||||
uint32_t m_repetition;
|
||||
uint32_t m_log2Factor;
|
||||
QString m_fileName;
|
||||
QString m_argsStr;
|
||||
|
||||
QCommandLineParser m_parser;
|
||||
QCommandLineOption m_testOption;
|
||||
@ -64,6 +66,7 @@ private:
|
||||
QCommandLineOption m_repetitionOption;
|
||||
QCommandLineOption m_log2FactorOption;
|
||||
QCommandLineOption m_fileOption;
|
||||
QCommandLineOption m_argsOption;
|
||||
};
|
||||
|
||||
|
||||
|
@ -102,11 +102,40 @@ int TestFT8Callback::hcb(
|
||||
return 2; // 2 => new decode, do subtract.
|
||||
}
|
||||
|
||||
void MainBench::testFT8(const QString& wavFile)
|
||||
void MainBench::testFT8(const QString& wavFile, const QString& argsStr)
|
||||
{
|
||||
qDebug("MainBench::testFT8: start");
|
||||
int nthreads = 8; // number of threads (default)
|
||||
double budget = 2.5; // compute for this many seconds per cycle (default)
|
||||
// 3,0.5 combinaion may be enough
|
||||
|
||||
QStringList argElements = argsStr.split(','); // comma separated list of arguments
|
||||
|
||||
for (int i = 0; i < argElements.size(); i++)
|
||||
{
|
||||
const QString& argStr = argElements.at(i);
|
||||
bool ok;
|
||||
|
||||
if (i == 0) // first is the number of threads (integer)
|
||||
{
|
||||
int nthreads_x = argStr.toInt(&ok);
|
||||
|
||||
if (ok) {
|
||||
nthreads = nthreads_x;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == 1) // second is the time budget in seconds (double)
|
||||
{
|
||||
double budget_x = argStr.toDouble(&ok);
|
||||
|
||||
if (ok) {
|
||||
budget = budget_x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qDebug("MainBench::testFT8: start nthreads: %d budget: %fs", nthreads, budget);
|
||||
int hints[2] = { 2, 0 }; // CQ
|
||||
double budget = 2.5; // compute for this many seconds per cycle
|
||||
TestFT8Callback testft8Callback;
|
||||
|
||||
std::ifstream wfile;
|
||||
@ -169,6 +198,7 @@ void MainBench::testFT8(const QString& wavFile)
|
||||
wfile.close();
|
||||
|
||||
FT8::FT8Decoder decoder;
|
||||
decoder.getParams().nthreads = nthreads;
|
||||
|
||||
decoder.entry(
|
||||
samples.data(),
|
||||
@ -185,8 +215,10 @@ void MainBench::testFT8(const QString& wavFile)
|
||||
0,
|
||||
(struct FT8::cdecode *) nullptr
|
||||
);
|
||||
qDebug("MainBench::testFT8: done");
|
||||
|
||||
decoder.wait(budget + 1.0); // add one second to budget to force quit threads
|
||||
const std::map<std::string, bool>& msgMap = testft8Callback.getMsgMap();
|
||||
qDebug("MainBench::testFT8: done %lu decodes", msgMap.size());
|
||||
|
||||
if (msgMap.size() != 15)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user