kopia lustrzana https://github.com/AlexandreRouma/SDRPlusPlus
Fixed waterfall at very low samplerates
rodzic
c13eb950b2
commit
ee5b89c4aa
|
@ -38,9 +38,6 @@ void MainWindow::init() {
|
|||
gui::waterfall.init();
|
||||
gui::waterfall.setRawFFTSize(fftSize);
|
||||
|
||||
appliedWindow = new float[fftSize];
|
||||
generateFFTWindow(selectedWindow, fftSize);
|
||||
|
||||
credits::init();
|
||||
|
||||
core::configManager.acquire();
|
||||
|
@ -215,10 +212,14 @@ void MainWindow::init() {
|
|||
void MainWindow::fftHandler(dsp::complex_t* samples, int count, void* ctx) {
|
||||
MainWindow* _this = (MainWindow*)ctx;
|
||||
std::lock_guard<std::mutex> lck(_this->fft_mtx);
|
||||
if (count != _this->fftSize) { return; }
|
||||
|
||||
// Apply window
|
||||
volk_32fc_32f_multiply_32fc((lv_32fc_t*)_this->fft_in, (lv_32fc_t*)samples, _this->appliedWindow, count);
|
||||
volk_32fc_32f_multiply_32fc((lv_32fc_t*)_this->fft_in, (lv_32fc_t*)samples, sigpath::signalPath.fftTaps, count);
|
||||
|
||||
// Zero out the rest of the samples
|
||||
if (count < _this->fftSize) {
|
||||
memset(&_this->fft_in[count], 0, (_this->fftSize-count) * sizeof(dsp::complex_t));
|
||||
}
|
||||
|
||||
// Execute FFT
|
||||
fftwf_execute(_this->fftwPlan);
|
||||
|
@ -231,7 +232,7 @@ void MainWindow::fftHandler(dsp::complex_t* samples, int count, void* ctx) {
|
|||
}
|
||||
|
||||
// Take power of spectrum
|
||||
volk_32fc_s32f_power_spectrum_32f(fftBuf, (lv_32fc_t*)_this->fft_out, count, count);
|
||||
volk_32fc_s32f_power_spectrum_32f(fftBuf, (lv_32fc_t*)_this->fft_out, _this->fftSize, _this->fftSize);
|
||||
|
||||
// Push back data
|
||||
gui::waterfall.pushFFT();
|
||||
|
@ -663,30 +664,11 @@ void MainWindow::setFFTSize(int size) {
|
|||
fft_in = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||
fft_out = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fftSize);
|
||||
fftwPlan = fftwf_plan_dft_1d(fftSize, fft_in, fft_out, FFTW_FORWARD, FFTW_ESTIMATE);
|
||||
|
||||
delete appliedWindow;
|
||||
|
||||
appliedWindow = new float[fftSize];
|
||||
generateFFTWindow(selectedWindow, fftSize);
|
||||
}
|
||||
|
||||
void MainWindow::setFFTWindow(int win) {
|
||||
std::lock_guard<std::mutex> lck(fft_mtx);
|
||||
selectedWindow = win;
|
||||
generateFFTWindow(selectedWindow, fftSize);
|
||||
}
|
||||
|
||||
void MainWindow::generateFFTWindow(int win, int size) {
|
||||
if (win == FFT_WINDOW_RECTANGULAR) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
appliedWindow[i] = (i%2) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
else if (win == FFT_WINDOW_BLACKMAN) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
appliedWindow[i] = ((i%2) ? dsp::window_function::blackman(i, size) : -dsp::window_function::blackman(i, size))*2;
|
||||
}
|
||||
}
|
||||
sigpath::signalPath.setFFTWindow(win);
|
||||
}
|
||||
|
||||
bool MainWindow::isPlaying() {
|
||||
|
|
|
@ -11,12 +11,6 @@
|
|||
|
||||
#define WINDOW_FLAGS ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoBackground
|
||||
|
||||
enum {
|
||||
FFT_WINDOW_RECTANGULAR,
|
||||
FFT_WINDOW_BLACKMAN,
|
||||
_FFT_WINDOW_COUNT
|
||||
};
|
||||
|
||||
class MainWindow {
|
||||
public:
|
||||
void init();
|
||||
|
@ -37,7 +31,6 @@ public:
|
|||
Event<bool> onPlayStateChange;
|
||||
|
||||
private:
|
||||
void generateFFTWindow(int win, int size);
|
||||
static void fftHandler(dsp::complex_t* samples, int count, void* ctx);
|
||||
static void vfoAddedHandler(VFOManager::VFO* vfo, void* ctx);
|
||||
|
||||
|
@ -46,7 +39,6 @@ private:
|
|||
std::mutex fft_mtx;
|
||||
fftwf_complex *fft_in, *fft_out;
|
||||
fftwf_plan fftwPlan;
|
||||
float* appliedWindow;
|
||||
|
||||
// GUI Variables
|
||||
bool firstMenuRender = true;
|
||||
|
|
|
@ -14,12 +14,22 @@ void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream
|
|||
|
||||
halfBandWindow.init(1000000, 200000, 4000000);
|
||||
|
||||
// split.init(input);
|
||||
inputBuffer.init(input);
|
||||
corrector.init(&inputBuffer.out, 50.0f / sampleRate);
|
||||
split.init(&inputBuffer.out);
|
||||
|
||||
reshape.init(&fftStream, fftSize, (sampleRate / fftRate) - fftSize);
|
||||
// Allocate the fft taps
|
||||
fftTaps = new float[fftSize];
|
||||
|
||||
// Calculate the parameters for the reshaper
|
||||
int fftInterval = sampleRate / fftRate;
|
||||
fftOutputSampleCount = std::min<int>(fftInterval, fftSize);
|
||||
int fftSkip = fftInterval - fftOutputSampleCount;
|
||||
|
||||
// Generate FFT Windows
|
||||
generateFFTWindow(fftWindow, fftTaps, fftOutputSampleCount);
|
||||
|
||||
reshape.init(&fftStream, fftSize, fftSkip);
|
||||
split.bindStream(&fftStream);
|
||||
fftHandlerSink.init(&reshape.out, fftHandler, fftHandlerCtx);
|
||||
}
|
||||
|
@ -27,26 +37,29 @@ void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream
|
|||
void SignalPath::setSampleRate(double sampleRate) {
|
||||
this->sampleRate = sampleRate;
|
||||
|
||||
// Stop the splitter
|
||||
split.stop();
|
||||
reshape.stop();
|
||||
|
||||
// Stop all VFOs
|
||||
for (auto const& [name, vfo] : vfos) {
|
||||
vfo.vfo->stop();
|
||||
}
|
||||
|
||||
// Claculate skip to maintain a constant fft rate
|
||||
int skip = (sampleRate / fftRate) - fftSize;
|
||||
reshape.setSkip(skip);
|
||||
|
||||
// TODO: Tell modules that the block size has changed (maybe?)
|
||||
updateFFTDSP();
|
||||
|
||||
// Update the sample rate for all VFOs and start them up
|
||||
for (auto const& [name, vfo] : vfos) {
|
||||
vfo.vfo->setInSampleRate(sampleRate);
|
||||
vfo.vfo->start();
|
||||
}
|
||||
|
||||
// Update correction rate on the IQ corrector
|
||||
corrector.setCorrectionRate(50.0f / sampleRate);
|
||||
|
||||
// Start the splitter
|
||||
split.start();
|
||||
reshape.start();
|
||||
}
|
||||
|
||||
double SignalPath::getSampleRate() {
|
||||
|
@ -117,19 +130,15 @@ void SignalPath::unbindIQStream(dsp::stream<dsp::complex_t>* stream) {
|
|||
|
||||
void SignalPath::setFFTSize(int size) {
|
||||
fftSize = size;
|
||||
int skip = (sampleRate / fftRate) - fftSize;
|
||||
reshape.stop();
|
||||
reshape.setSkip(skip);
|
||||
reshape.setKeep(fftSize);
|
||||
updateFFTDSP();
|
||||
reshape.start();
|
||||
}
|
||||
|
||||
void SignalPath::setFFTRate(double rate) {
|
||||
fftRate = rate;
|
||||
int skip = (sampleRate / fftRate) - fftSize;
|
||||
reshape.stop();
|
||||
reshape.setSkip(skip);
|
||||
reshape.setKeep(fftSize);
|
||||
updateFFTDSP();
|
||||
reshape.start();
|
||||
}
|
||||
|
||||
|
@ -226,4 +235,45 @@ void SignalPath::setIQCorrection(bool enabled) {
|
|||
corrector.offset.re = 0;
|
||||
corrector.offset.im = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SignalPath::setFFTWindow(int win) {
|
||||
fftWindow = win;
|
||||
reshape.stop();
|
||||
updateFFTDSP();
|
||||
reshape.start();
|
||||
}
|
||||
|
||||
void SignalPath::generateFFTWindow(int win, float* taps, int size) {
|
||||
if (win == FFT_WINDOW_RECTANGULAR) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
taps[i] = (i%2) ? 1 : -1;
|
||||
}
|
||||
}
|
||||
else if (win == FFT_WINDOW_BLACKMAN) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
taps[i] = ((i%2) ? dsp::window_function::blackman(i, size) : -dsp::window_function::blackman(i, size))*2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SignalPath::updateFFTDSP() {
|
||||
|
||||
// Allocate the fft taps
|
||||
if (fftTaps != NULL) { delete[] fftTaps; }
|
||||
fftTaps = new float[fftSize];
|
||||
|
||||
// Calculate the parameters for the reshaper
|
||||
int fftInterval = sampleRate / fftRate;
|
||||
fftOutputSampleCount = std::min<int>(fftInterval, fftSize);
|
||||
int fftSkip = fftInterval - fftOutputSampleCount;
|
||||
|
||||
// Generate FFT Windows
|
||||
generateFFTWindow(fftWindow, fftTaps, fftOutputSampleCount);
|
||||
|
||||
// Update parameters of the reshaper
|
||||
reshape.setKeep(fftOutputSampleCount);
|
||||
reshape.setSkip(fftSkip);
|
||||
|
||||
spdlog::info("Updating FFT DSP settings: Keep: {0}, Skip: {1}", fftOutputSampleCount, fftSkip);
|
||||
}
|
|
@ -6,6 +6,12 @@
|
|||
#include <dsp/decimation.h>
|
||||
#include <dsp/correction.h>
|
||||
|
||||
enum {
|
||||
FFT_WINDOW_RECTANGULAR,
|
||||
FFT_WINDOW_BLACKMAN,
|
||||
_FFT_WINDOW_COUNT
|
||||
};
|
||||
|
||||
class SignalPath {
|
||||
public:
|
||||
SignalPath();
|
||||
|
@ -26,12 +32,18 @@ public:
|
|||
void setBuffering(bool enabled);
|
||||
void setDecimation(int dec);
|
||||
void setIQCorrection(bool enabled);
|
||||
void setFFTWindow(int win);
|
||||
|
||||
dsp::SampleFrameBuffer<dsp::complex_t> inputBuffer;
|
||||
double sourceSampleRate = 0;
|
||||
int decimation = 0;
|
||||
|
||||
float* fftTaps = NULL;
|
||||
|
||||
private:
|
||||
void generateFFTWindow(int win, float* taps, int size);
|
||||
void updateFFTDSP();
|
||||
|
||||
struct VFO_t {
|
||||
dsp::stream<dsp::complex_t>* inputStream;
|
||||
dsp::VFO* vfo;
|
||||
|
@ -50,10 +62,12 @@ private:
|
|||
std::vector<dsp::HalfDecimator<dsp::complex_t>*> decimators;
|
||||
dsp::filter_window::BlackmanWindow halfBandWindow;
|
||||
|
||||
int fftOutputSampleCount = 0;
|
||||
double sampleRate;
|
||||
double fftRate;
|
||||
int fftSize;
|
||||
int inputBlockSize;
|
||||
int fftWindow = FFT_WINDOW_RECTANGULAR;
|
||||
bool bufferingEnabled = false;
|
||||
bool running = false;
|
||||
bool iqCorrection = false;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#define VERSION_STR "1.0.0_rc4"
|
||||
#define VERSION_STR "1.0.0_rc5"
|
Ładowanie…
Reference in New Issue