mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-12-24 01:48:28 +01:00
More DSP cleanup + Remove FastFFT option because it should never be used
This commit is contained in:
parent
8efd5cd01a
commit
575a941e24
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
1
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@ -11,6 +11,7 @@ FIRST: Before reporting any bug, make sure that the bug you are reporting has no
|
||||
|
||||
**Hardware**
|
||||
- CPU:
|
||||
- RAM:
|
||||
- GPU:
|
||||
- SDR: (Remote or local? If remote, what protocol?)
|
||||
|
||||
|
10
.github/workflows/build_all.yml
vendored
10
.github/workflows/build_all.yml
vendored
@ -95,18 +95,18 @@ jobs:
|
||||
- name: Install SDRplay API
|
||||
run: wget https://www.sdrplay.com/software/SDRplay_RSP_API-MacOSX-3.07.3.pkg && sudo installer -pkg SDRplay_RSP_API-MacOSX-3.07.3.pkg -target /
|
||||
|
||||
# - name: Install libiio
|
||||
# run: git clone https://github.com/analogdevicesinc/libiio && cd libiio && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
- name: Install libiio
|
||||
run: git clone https://github.com/analogdevicesinc/libiio && cd libiio && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
# - name: Install libad9361
|
||||
# run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
- name: Install libad9361
|
||||
run: git clone https://github.com/analogdevicesinc/libad9361-iio && cd libad9361-iio && mkdir build && cd build && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
- name: Install LimeSuite
|
||||
run: git clone https://github.com/myriadrf/LimeSuite && cd LimeSuite && mkdir builddir && cd builddir && cmake -DCMAKE_BUILD_TYPE=Release .. && make -j3 && sudo make install && cd ../../
|
||||
|
||||
- name: Prepare CMake
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=OFF -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||
run: cmake $GITHUB_WORKSPACE -DOPT_BUILD_PLUTOSDR_SOURCE=ON -DOPT_BUILD_SOAPY_SOURCE=OFF -DOPT_BUILD_BLADERF_SOURCE=ON -DOPT_BUILD_SDRPLAY_SOURCE=ON -DOPT_BUILD_LIMESDR_SOURCE=ON -DOPT_BUILD_AUDIO_SINK=OFF -DOPT_BUILD_PORTAUDIO_SINK=ON -DOPT_BUILD_NEW_PORTAUDIO_SINK=ON -DOPT_BUILD_M17_DECODER=ON -DUSE_BUNDLE_DEFAULTS=ON -DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
- name: Build
|
||||
working-directory: ${{runner.workspace}}/build
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "../processor.h"
|
||||
#include "../math/freq_to_omega.h"
|
||||
#include "../math/hz_to_rads.h"
|
||||
|
||||
namespace dsp::channel {
|
||||
class FrequencyXlator : public Processor<complex_t, complex_t> {
|
||||
@ -19,7 +19,7 @@ namespace dsp::channel {
|
||||
}
|
||||
|
||||
void init(stream<complex_t>* in, double offset, double samplerate) {
|
||||
init(in, math::freqToOmega(offset, samplerate));
|
||||
init(in, math::hzToRads(offset, samplerate));
|
||||
}
|
||||
|
||||
void setOffset(double offset) {
|
||||
@ -29,7 +29,7 @@ namespace dsp::channel {
|
||||
}
|
||||
|
||||
void setOffset(double offset, double samplerate) {
|
||||
setOffset(math::freqToOmega(offset, samplerate));
|
||||
setOffset(math::hzToRads(offset, samplerate));
|
||||
}
|
||||
|
||||
void reset() {
|
||||
|
@ -168,7 +168,7 @@ namespace dsp::clock_recovery {
|
||||
protected:
|
||||
void generateInterpTaps() {
|
||||
double bw = 0.5 / (double)_interpPhaseCount;
|
||||
dsp::tap<float> lp = dsp::taps::windowedSinc<float>(_interpPhaseCount * _interpTapCount, dsp::math::freqToOmega(bw, 1.0), dsp::window::nuttall, _interpPhaseCount);
|
||||
dsp::tap<float> lp = dsp::taps::windowedSinc<float>(_interpPhaseCount * _interpTapCount, dsp::math::hzToRads(bw, 1.0), dsp::window::nuttall, _interpPhaseCount);
|
||||
interpBank = dsp::multirate::buildPolyphaseBank<float>(_interpPhaseCount, lp);
|
||||
taps::free(lp);
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ namespace dsp::clock_recovery {
|
||||
protected:
|
||||
void generateInterpTaps() {
|
||||
double bw = 0.5 / (double)_interpPhaseCount;
|
||||
dsp::tap<float> lp = dsp::taps::windowedSinc<float>(_interpPhaseCount * _interpTapCount, dsp::math::freqToOmega(bw, 1.0), dsp::window::nuttall, _interpPhaseCount);
|
||||
dsp::tap<float> lp = dsp::taps::windowedSinc<float>(_interpPhaseCount * _interpTapCount, dsp::math::hzToRads(bw, 1.0), dsp::window::nuttall, _interpPhaseCount);
|
||||
interpBank = dsp::multirate::buildPolyphaseBank<float>(_interpPhaseCount, lp);
|
||||
taps::free(lp);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ namespace dsp::demod {
|
||||
pilotFirTaps = taps::bandPass<complex_t>(18750.0, 19250.0, 3000.0, _samplerate, true);
|
||||
pilotFir.init(NULL, pilotFirTaps);
|
||||
rtoc.init(NULL);
|
||||
pilotPLL.init(NULL, 25000.0 / _samplerate, 0.0, math::freqToOmega(19000.0, _samplerate), math::freqToOmega(18750.0, _samplerate), math::freqToOmega(19250.0, _samplerate));
|
||||
pilotPLL.init(NULL, 25000.0 / _samplerate, 0.0, math::hzToRads(19000.0, _samplerate), math::hzToRads(18750.0, _samplerate), math::hzToRads(19250.0, _samplerate));
|
||||
lprDelay.init(NULL, ((pilotFirTaps.size - 1) / 2) + 1);
|
||||
lmrDelay.init(NULL, ((pilotFirTaps.size - 1) / 2) + 1);
|
||||
audioFirTaps = taps::lowPass(15000.0, 4000.0, _samplerate);
|
||||
@ -82,8 +82,8 @@ namespace dsp::demod {
|
||||
pilotFirTaps = taps::bandPass<complex_t>(18750.0, 19250.0, 3000.0, samplerate, true);
|
||||
pilotFir.setTaps(pilotFirTaps);
|
||||
|
||||
pilotPLL.setFrequencyLimits(math::freqToOmega(18750.0, _samplerate), math::freqToOmega(19250.0, _samplerate));
|
||||
pilotPLL.setInitialFreq(math::freqToOmega(19000.0, _samplerate));
|
||||
pilotPLL.setFrequencyLimits(math::hzToRads(18750.0, _samplerate), math::hzToRads(19250.0, _samplerate));
|
||||
pilotPLL.setInitialFreq(math::hzToRads(19000.0, _samplerate));
|
||||
lprDelay.setDelay(((pilotFirTaps.size - 1) / 2) + 1);
|
||||
lmrDelay.setDelay(((pilotFirTaps.size - 1) / 2) + 1);
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
#include "../processor.h"
|
||||
#include "../math/fast_atan2.h"
|
||||
#include "../math/freq_to_omega.h"
|
||||
#include "../math/norm_phase_diff.h"
|
||||
#include "../math/hz_to_rads.h"
|
||||
#include "../math/normalize_phase.h"
|
||||
|
||||
namespace dsp::demod {
|
||||
class Quadrature : public Processor<complex_t, float> {
|
||||
@ -21,7 +21,7 @@ namespace dsp::demod {
|
||||
}
|
||||
|
||||
virtual void init(stream<complex_t>* in, double deviation, double samplerate) {
|
||||
init(in, math::freqToOmega(deviation, samplerate));
|
||||
init(in, math::hzToRads(deviation, samplerate));
|
||||
}
|
||||
|
||||
void setDeviation(double deviation) {
|
||||
@ -33,13 +33,13 @@ namespace dsp::demod {
|
||||
void setDeviation(double deviation, double samplerate) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
_invDeviation = 1.0 / math::freqToOmega(deviation, samplerate);
|
||||
_invDeviation = 1.0 / math::hzToRads(deviation, samplerate);
|
||||
}
|
||||
|
||||
inline int process(int count, complex_t* in, float* out) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
float cphase = in[i].phase();
|
||||
out[i] = math::normPhaseDiff(cphase - phase) * _invDeviation;
|
||||
out[i] = math::normalizePhase(cphase - phase) * _invDeviation;
|
||||
phase = cphase;
|
||||
}
|
||||
return count;
|
||||
|
@ -5,10 +5,16 @@ namespace dsp::loop {
|
||||
class CarrierTrackingPLL : public PLL {
|
||||
using base_type = PLL;
|
||||
public:
|
||||
CarrierTrackingPLL() {}
|
||||
|
||||
CarrierTrackingPLL(stream<complex_t>* in, double bandwidth, double initPhase = 0.0, double initFreq = 0.0, double minFreq = -FL_M_PI, double maxFreq = FL_M_PI) {
|
||||
base_type::init(in, bandwidth, initFreq, initPhase, minFreq, maxFreq);
|
||||
}
|
||||
|
||||
inline int process(int count, complex_t* in, complex_t* out) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
out[i] = in[i] * math::phasor(-pcl.phase);
|
||||
pcl.advance(math::normPhaseDiff(in[i].phase() - pcl.phase));
|
||||
pcl.advance(math::normalizePhase(in[i].phase() - pcl.phase));
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -8,6 +8,12 @@ namespace dsp::loop {
|
||||
static_assert(ORDER == 2 || ORDER == 4 || ORDER == 8, "Invalid costas order");
|
||||
using base_type = PLL;
|
||||
public:
|
||||
Costas() {}
|
||||
|
||||
Costas(stream<complex_t>* in, double bandwidth, double initPhase = 0.0, double initFreq = 0.0, double minFreq = -FL_M_PI, double maxFreq = FL_M_PI) {
|
||||
base_type::init(in, bandwidth, initFreq, initPhase, minFreq, maxFreq);
|
||||
}
|
||||
|
||||
inline int process(int count, complex_t* in, complex_t* out) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
out[i] = in[i] * math::phasor(-pcl.phase);
|
||||
|
@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "../processor.h"
|
||||
#include "../math/norm_phase_diff.h"
|
||||
#include "../math/normalize_phase.h"
|
||||
#include "../math/phasor.h"
|
||||
#include "phase_control_loop.h"
|
||||
|
||||
@ -64,7 +64,7 @@ namespace dsp::loop {
|
||||
virtual inline int process(int count, complex_t* in, complex_t* out) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
out[i] = math::phasor(pcl.phase);
|
||||
pcl.advance(math::normPhaseDiff(in[i].phase() - pcl.phase));
|
||||
pcl.advance(math::normalizePhase(in[i].phase() - pcl.phase));
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include "constants.h"
|
||||
|
||||
namespace dsp::math {
|
||||
inline double freqToOmega(double freq, double samplerate) {
|
||||
inline double hzToRads(double freq, double samplerate) {
|
||||
return 2.0 * DB_M_PI * (freq / samplerate);
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
namespace dsp::math {
|
||||
template<class T>
|
||||
T normPhaseDiff(T diff) {
|
||||
T normalizePhase(T diff) {
|
||||
if (diff > FL_M_PI) { diff -= 2.0f * FL_M_PI; }
|
||||
else if (diff <= -FL_M_PI) { diff += 2.0f * FL_M_PI; }
|
||||
return diff;
|
86
core/src/dsp/mod/gfsk.h
Normal file
86
core/src/dsp/mod/gfsk.h
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
#include "../multirate/rrc_interpolator.h"
|
||||
#include "quadrature.h"
|
||||
|
||||
namespace dsp::mod {
|
||||
class GFSK : public Processor<float, complex_t> {
|
||||
using base_type = Processor<float, complex_t>;
|
||||
public:
|
||||
GFSK() {}
|
||||
|
||||
GFSK(stream<float>* in, double symbolrate, double samplerate, double rrcBeta, int rrcTapCount, double deviation) {
|
||||
init(in, symbolrate, samplerate, rrcBeta, rrcTapCount, deviation);
|
||||
}
|
||||
|
||||
void init(stream<float>* in, double symbolrate, double samplerate, double rrcBeta, int rrcTapCount, double deviation) {
|
||||
_samplerate = samplerate;
|
||||
_deviation = deviation;
|
||||
|
||||
interp.init(NULL, symbolrate, _samplerate, rrcBeta, rrcTapCount);
|
||||
mod.init(NULL, _deviation, _samplerate);
|
||||
|
||||
base_type::init(in);
|
||||
}
|
||||
|
||||
void setRates(double symbolrate, double samplerate) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
base_type::tempStop();
|
||||
_samplerate = samplerate;
|
||||
interp.setRates(symbolrate, _samplerate);
|
||||
mod.setDeviation(_deviation, _samplerate);
|
||||
base_type::tempStart();
|
||||
}
|
||||
|
||||
void setRRCParams(double rrcBeta, int rrcTapCount) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
base_type::tempStop();
|
||||
interp.setRRCParam(rrcBeta, rrcTapCount);
|
||||
base_type::tempStart();
|
||||
}
|
||||
|
||||
void setDeviation(double deviation) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
_deviation = deviation;
|
||||
mod.setDeviation(_deviation, _samplerate);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
base_type::tempStop();
|
||||
interp.reset();
|
||||
mod.reset();
|
||||
base_type::tempStart();
|
||||
}
|
||||
|
||||
inline int process(int count, const float* in, complex_t* out) {
|
||||
count = interp.process(count, in, interp.out.writeBuf);
|
||||
mod.process(count, interp.out.writeBuf, out);
|
||||
return count;
|
||||
}
|
||||
|
||||
int run() {
|
||||
int count = base_type::_in->read();
|
||||
if (count < 0) { return -1; }
|
||||
|
||||
int outCount = process(count, base_type::_in->readBuf, base_type::out.writeBuf);
|
||||
|
||||
// Swap if some data was generated
|
||||
base_type::_in->flush();
|
||||
if (outCount) {
|
||||
if (!base_type::out.swap(outCount)) { return -1; }
|
||||
}
|
||||
return outCount;
|
||||
}
|
||||
|
||||
private:
|
||||
double _samplerate;
|
||||
double _deviation;
|
||||
|
||||
multirate::RRCInterpolator<float> interp;
|
||||
Quadrature mod;
|
||||
};
|
||||
}
|
6
core/src/dsp/mod/psk.h
Normal file
6
core/src/dsp/mod/psk.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include "../multirate/rrc_interpolator.h"
|
||||
|
||||
namespace dsp::mod {
|
||||
typedef multirate::RRCInterpolator<complex_t> PSK;
|
||||
}
|
67
core/src/dsp/mod/quadrature.h
Normal file
67
core/src/dsp/mod/quadrature.h
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
#include "../processor.h"
|
||||
#include "../math/phasor.h"
|
||||
#include "../math/normalize_phase.h"
|
||||
#include "../math/hz_to_rads.h"
|
||||
|
||||
namespace dsp::mod {
|
||||
class Quadrature : Processor<float, complex_t> {
|
||||
using base_type = Processor<float, complex_t>;
|
||||
public:
|
||||
Quadrature() {}
|
||||
|
||||
Quadrature(stream<float>* in, double deviation) { init(in, deviation); }
|
||||
|
||||
Quadrature(stream<float>* in, double deviation, double samplerate) { init(in, deviation, samplerate); }
|
||||
|
||||
void init(stream<float>* in, double deviation) {
|
||||
_deviation = deviation;
|
||||
base_type::init(in);
|
||||
}
|
||||
|
||||
void init(stream<float>* in, double deviation, double samplerate) {
|
||||
init(in, math::hzToRads(deviation, samplerate));
|
||||
}
|
||||
|
||||
void setDeviation(double deviation) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
_deviation = deviation;
|
||||
}
|
||||
|
||||
void setDeviation(double deviation, double samplerate) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
_deviation = math::hzToRads(deviation, samplerate);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
phase = 0.0f;
|
||||
}
|
||||
|
||||
inline int process(int count, const float* in, complex_t* out) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
phase = math::normalizePhase(phase + (_deviation * in[i]));
|
||||
out[i] = math::phasor(phase);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
virtual int run() {
|
||||
int count = base_type::_in->read();
|
||||
if (count < 0) { return -1; }
|
||||
|
||||
process(count, base_type::_in->readBuf, base_type::out.writeBuf);
|
||||
|
||||
base_type::_in->flush();
|
||||
if (!base_type::out.swap(count)) { return -1; }
|
||||
return count;
|
||||
}
|
||||
|
||||
private:
|
||||
float _deviation;
|
||||
float phase = 0.0f;
|
||||
};
|
||||
}
|
@ -69,6 +69,16 @@ namespace dsp::multirate {
|
||||
base_type::tempStart();
|
||||
}
|
||||
|
||||
void setRates(double inSamplerate, double outSamplerate) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
base_type::tempStop();
|
||||
_inSamplerate = inSamplerate;
|
||||
_outSamplerate = outSamplerate;
|
||||
reconfigure();
|
||||
base_type::tempStart();
|
||||
}
|
||||
|
||||
inline int process(int count, const T* in, T* out) {
|
||||
switch(mode) {
|
||||
case Mode::BOTH:
|
||||
|
103
core/src/dsp/multirate/rrc_interpolator.h
Normal file
103
core/src/dsp/multirate/rrc_interpolator.h
Normal file
@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
#include "../multirate/polyphase_resampler.h"
|
||||
#include "../taps/root_raised_cosine.h"
|
||||
#include <numeric>
|
||||
|
||||
namespace dsp::multirate {
|
||||
template <class T>
|
||||
class RRCInterpolator : public Processor<T, T> {
|
||||
using base_type = Processor<T, T>;
|
||||
public:
|
||||
RRCInterpolator() {}
|
||||
|
||||
RRCInterpolator(stream<T>* in, double symbolrate, double samplerate, double rrcBeta, int rrcTapCount) { init(in, symbolrate, samplerate, rrcBeta, rrcTapCount); }
|
||||
|
||||
void init(stream<T>* in, double symbolrate, double samplerate, double rrcBeta, int rrcTapCount) {
|
||||
_symbolrate = symbolrate;
|
||||
_samplerate = samplerate;
|
||||
_rrcTapCount = rrcTapCount;
|
||||
|
||||
rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount, rrcBeta, _symbolrate, _samplerate);
|
||||
resamp.init(NULL, 1, 1, rrcTaps);
|
||||
resamp.out.free();
|
||||
genTaps();
|
||||
|
||||
base_type::init(in);
|
||||
}
|
||||
|
||||
void setRates(double symbolrate, double samplerate) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
base_type::tempStop();
|
||||
_symbolrate = symbolrate;
|
||||
_samplerate = samplerate;
|
||||
genTaps();
|
||||
base_type::tempStart();
|
||||
}
|
||||
|
||||
void setRRCParam(double rrcBeta, int rrcTapCount) {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
base_type::tempStop();
|
||||
_rrcBeta = rrcBeta;
|
||||
_rrcTapCount = rrcTapCount;
|
||||
genTaps();
|
||||
base_type::tempStart();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
assert(base_type::_block_init);
|
||||
std::lock_guard<std::recursive_mutex> lck(base_type::ctrlMtx);
|
||||
base_type::tempStop();
|
||||
resamp.reset();
|
||||
base_type::tempStart();
|
||||
}
|
||||
|
||||
inline int process(int count, const T* in, T* out) {
|
||||
return resamp.process(count, in, out);
|
||||
}
|
||||
|
||||
int run() {
|
||||
int count = base_type::_in->read();
|
||||
if (count < 0) { return -1; }
|
||||
|
||||
int outCount = process(count, base_type::_in->readBuf, base_type::out.writeBuf);
|
||||
|
||||
// Swap if some data was generated
|
||||
base_type::_in->flush();
|
||||
if (outCount) {
|
||||
if (!base_type::out.swap(outCount)) { return -1; }
|
||||
}
|
||||
return outCount;
|
||||
}
|
||||
|
||||
private:
|
||||
void genTaps() {
|
||||
// Free current taps if they exist
|
||||
taps::free(rrcTaps);
|
||||
|
||||
// Calculate the rational samplerate ratio
|
||||
int InSR = round(_symbolrate);
|
||||
int OutSR = round(_samplerate);
|
||||
int gcd = std::gcd(InSR, OutSR);
|
||||
int interp = OutSR / gcd;
|
||||
int decim = InSR / gcd;
|
||||
|
||||
spdlog::warn("interp: {0}, decim: {1}", interp, decim);
|
||||
|
||||
// Configure resampler
|
||||
double tapSamplerate = _symbolrate * (double)interp;
|
||||
rrcTaps = taps::rootRaisedCosine<float>(_rrcTapCount * interp, _rrcBeta, _symbolrate, tapSamplerate);
|
||||
resamp.setRatio(interp, decim, rrcTaps);
|
||||
}
|
||||
|
||||
double _symbolrate;
|
||||
double _samplerate;
|
||||
double _rrcBeta;
|
||||
int _rrcTapCount;
|
||||
|
||||
tap<float> rrcTaps;
|
||||
multirate::PolyphaseResampler<T> resamp;
|
||||
|
||||
};
|
||||
}
|
@ -4,13 +4,13 @@
|
||||
#include "estimate_tap_count.h"
|
||||
#include "../window/nuttall.h"
|
||||
#include "../math/phasor.h"
|
||||
#include "../math/freq_to_omega.h"
|
||||
#include "../math/hz_to_rads.h"
|
||||
|
||||
namespace dsp::taps {
|
||||
template<class T>
|
||||
inline tap<T> bandPass(double bandStart, double bandStop, double transWidth, double sampleRate, bool oddTapCount = false) {
|
||||
assert(bandStop > bandStart);
|
||||
float offsetOmega = math::freqToOmega((bandStart + bandStop) / 2.0, sampleRate);
|
||||
float offsetOmega = math::hzToRads((bandStart + bandStop) / 2.0, sampleRate);
|
||||
int count = estimateTapCount(transWidth, sampleRate);
|
||||
if (oddTapCount && !(count % 2)) { count++; }
|
||||
return windowedSinc<T>(count, (bandStop - bandStart) / 2.0, sampleRate, [=](double n, double N) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "tap.h"
|
||||
#include "../math/sinc.h"
|
||||
#include "../math/freq_to_omega.h"
|
||||
#include "../math/hz_to_rads.h"
|
||||
#include "../window/nuttall.h"
|
||||
|
||||
namespace dsp::taps {
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include "tap.h"
|
||||
#include "../math/sinc.h"
|
||||
#include "../math/freq_to_omega.h"
|
||||
#include "../math/hz_to_rads.h"
|
||||
#include "../window/nuttall.h"
|
||||
|
||||
namespace dsp::taps {
|
||||
@ -30,6 +30,6 @@ namespace dsp::taps {
|
||||
|
||||
template<class T, typename Func>
|
||||
inline tap<T> windowedSinc(int count, double cutoff, double samplerate, Func window, double norm = 1.0) {
|
||||
return windowedSinc<T>(count, math::freqToOmega(cutoff, samplerate), window, norm);
|
||||
return windowedSinc<T>(count, math::hzToRads(cutoff, samplerate), window, norm);
|
||||
}
|
||||
}
|
@ -11,7 +11,6 @@
|
||||
|
||||
namespace displaymenu {
|
||||
bool showWaterfall;
|
||||
bool fastFFT = true;
|
||||
bool fullWaterfallUpdate = true;
|
||||
int colorMapId = 0;
|
||||
std::vector<std::string> colorMapNames;
|
||||
@ -81,9 +80,6 @@ namespace displaymenu {
|
||||
}
|
||||
}
|
||||
|
||||
fastFFT = core::configManager.conf["fastFFT"];
|
||||
gui::waterfall.setFastFFT(fastFFT);
|
||||
|
||||
fullWaterfallUpdate = core::configManager.conf["fullWaterfallUpdate"];
|
||||
gui::waterfall.setFullWaterfallUpdate(fullWaterfallUpdate);
|
||||
|
||||
@ -129,13 +125,6 @@ namespace displaymenu {
|
||||
core::configManager.release(true);
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Fast FFT##_sdrpp", &fastFFT)) {
|
||||
gui::waterfall.setFastFFT(fastFFT);
|
||||
core::configManager.acquire();
|
||||
core::configManager.conf["fastFFT"] = fastFFT;
|
||||
core::configManager.release(true);
|
||||
}
|
||||
|
||||
if (ImGui::Checkbox("Full Waterfall Update##_sdrpp", &fullWaterfallUpdate)) {
|
||||
gui::waterfall.setFullWaterfallUpdate(fullWaterfallUpdate);
|
||||
core::configManager.acquire();
|
||||
|
@ -570,11 +570,6 @@ namespace ImGui {
|
||||
return true;
|
||||
}
|
||||
|
||||
void WaterFall::setFastFFT(bool fastFFT) {
|
||||
std::lock_guard<std::recursive_mutex> lck(buf_mtx);
|
||||
_fastFFT = fastFFT;
|
||||
}
|
||||
|
||||
void WaterFall::updateWaterfallFb() {
|
||||
if (!waterfallVisible || rawFFTs == NULL) {
|
||||
return;
|
||||
@ -591,7 +586,7 @@ namespace ImGui {
|
||||
for (int i = 0; i < count; i++) {
|
||||
drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize;
|
||||
drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2);
|
||||
doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[((i + currentFFTLine) % waterfallHeight) * rawFFTSize], tempData, _fastFFT);
|
||||
doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[((i + currentFFTLine) % waterfallHeight) * rawFFTSize], tempData);
|
||||
for (int j = 0; j < dataWidth; j++) {
|
||||
pixel = (std::clamp<float>(tempData[j], waterfallMin, waterfallMax) - waterfallMin) / dataRange;
|
||||
waterfallFb[(i * dataWidth) + j] = waterfallPallet[(int)(pixel * (WATERFALL_RESOLUTION - 1))];
|
||||
@ -861,18 +856,8 @@ namespace ImGui {
|
||||
int drawDataSize = (viewBandwidth / wholeBandwidth) * rawFFTSize;
|
||||
int drawDataStart = (((double)rawFFTSize / 2.0) * (offsetRatio + 1)) - (drawDataSize / 2);
|
||||
|
||||
// If in fast mode, apply IIR filtering
|
||||
float* buf = &rawFFTs[currentFFTLine * rawFFTSize];
|
||||
if (_fastFFT) {
|
||||
float last = buf[0];
|
||||
for (int i = 0; i < rawFFTSize; i++) {
|
||||
last = (buf[i] * 0.1f) + (last * 0.9f);
|
||||
buf[i] = last;
|
||||
}
|
||||
}
|
||||
|
||||
if (waterfallVisible) {
|
||||
doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[currentFFTLine * rawFFTSize], latestFFT, _fastFFT);
|
||||
doZoom(drawDataStart, drawDataSize, dataWidth, &rawFFTs[currentFFTLine * rawFFTSize], latestFFT);
|
||||
memmove(&waterfallFb[dataWidth], waterfallFb, dataWidth * (waterfallHeight - 1) * sizeof(uint32_t));
|
||||
float pixel;
|
||||
float dataRange = waterfallMax - waterfallMin;
|
||||
@ -884,7 +869,7 @@ namespace ImGui {
|
||||
waterfallUpdate = true;
|
||||
}
|
||||
else {
|
||||
doZoom(drawDataStart, drawDataSize, dataWidth, rawFFTs, latestFFT, _fastFFT);
|
||||
doZoom(drawDataStart, drawDataSize, dataWidth, rawFFTs, latestFFT);
|
||||
fftLines = 1;
|
||||
}
|
||||
|
||||
|
@ -90,7 +90,7 @@ namespace ImGui {
|
||||
float* getFFTBuffer();
|
||||
void pushFFT();
|
||||
|
||||
inline void doZoom(int offset, int width, int outWidth, float* data, float* out, bool fast) {
|
||||
inline void doZoom(int offset, int width, int outWidth, float* data, float* out) {
|
||||
// NOTE: REMOVE THAT SHIT, IT'S JUST A HACKY FIX
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
@ -100,28 +100,20 @@ namespace ImGui {
|
||||
}
|
||||
|
||||
float factor = (float)width / (float)outWidth;
|
||||
|
||||
if (fast) {
|
||||
for (int i = 0; i < outWidth; i++) {
|
||||
out[i] = data[(int)(offset + ((float)i * factor))];
|
||||
}
|
||||
}
|
||||
else {
|
||||
float sFactor = ceilf(factor);
|
||||
float uFactor;
|
||||
float id = offset;
|
||||
float maxVal;
|
||||
int sId;
|
||||
for (int i = 0; i < outWidth; i++) {
|
||||
maxVal = -INFINITY;
|
||||
sId = (int)id;
|
||||
uFactor = (sId + sFactor > rawFFTSize) ? sFactor - ((sId + sFactor) - rawFFTSize) : sFactor;
|
||||
for (int j = 0; j < uFactor; j++) {
|
||||
if (data[sId + j] > maxVal) { maxVal = data[sId + j]; }
|
||||
}
|
||||
out[i] = maxVal;
|
||||
id += factor;
|
||||
float sFactor = ceilf(factor);
|
||||
float uFactor;
|
||||
float id = offset;
|
||||
float maxVal;
|
||||
int sId;
|
||||
for (int i = 0; i < outWidth; i++) {
|
||||
maxVal = -INFINITY;
|
||||
sId = (int)id;
|
||||
uFactor = (sId + sFactor > rawFFTSize) ? sFactor - ((sId + sFactor) - rawFFTSize) : sFactor;
|
||||
for (int j = 0; j < uFactor; j++) {
|
||||
if (data[sId + j] > maxVal) { maxVal = data[sId + j]; }
|
||||
}
|
||||
out[i] = maxVal;
|
||||
id += factor;
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,8 +162,6 @@ namespace ImGui {
|
||||
|
||||
void setRawFFTSize(int size);
|
||||
|
||||
void setFastFFT(bool fastFFT);
|
||||
|
||||
void setFullWaterfallUpdate(bool fullUpdate);
|
||||
|
||||
void setBandPlanPos(int pos);
|
||||
@ -328,7 +318,6 @@ namespace ImGui {
|
||||
bool waterfallVisible = true;
|
||||
bool bandplanVisible = false;
|
||||
|
||||
bool _fastFFT = true;
|
||||
bool _fullUpdate = true;
|
||||
|
||||
int bandPlanPos = BANDPLAN_POS_BOTTOM;
|
||||
|
@ -39,10 +39,10 @@ namespace dsp::loop {
|
||||
const float PHASE4 = -0.29067248091319986;
|
||||
|
||||
float phase = val.phase();
|
||||
float dp1 = math::normPhaseDiff(phase - PHASE1);
|
||||
float dp2 = math::normPhaseDiff(phase - PHASE2);
|
||||
float dp3 = math::normPhaseDiff(phase - PHASE3);
|
||||
float dp4 = math::normPhaseDiff(phase - PHASE4);
|
||||
float dp1 = math::normalizePhase(phase - PHASE1);
|
||||
float dp2 = math::normalizePhase(phase - PHASE2);
|
||||
float dp3 = math::normalizePhase(phase - PHASE3);
|
||||
float dp4 = math::normalizePhase(phase - PHASE4);
|
||||
float lowest = dp1;
|
||||
if (fabsf(dp2) < fabsf(lowest)) { lowest = dp2; }
|
||||
if (fabsf(dp3) < fabsf(lowest)) { lowest = dp3; }
|
||||
|
@ -112,6 +112,7 @@ public:
|
||||
}
|
||||
|
||||
~RadioModule() {
|
||||
core::modComManager.unregisterInterface(name);
|
||||
gui::menu.removeEntry(name);
|
||||
stream.stop();
|
||||
if (enabled) {
|
||||
|
Loading…
Reference in New Issue
Block a user