Performance improvement to the FFT + code cleanup + Added an option to select the FFT window

pull/160/head
Ryzerth 2021-07-05 01:09:48 +02:00
rodzic 6db8251e46
commit ab376ea1aa
16 zmienionych plików z 91 dodań i 22 usunięć

Wyświetl plik

@ -118,6 +118,7 @@ int sdrpp_main(int argc, char *argv[]) {
defConfig["fastFFT"] = false;
defConfig["fftHeight"] = 300;
defConfig["fftSize"] = 65536;
defConfig["fftWindow"] = 0;
defConfig["frequency"] = 100000000.0;
defConfig["fullWaterfallUpdate"] = false;
defConfig["max"] = 0.0;

Wyświetl plik

@ -40,8 +40,8 @@ void MainWindow::init() {
gui::waterfall.init();
gui::waterfall.setRawFFTSize(fftSize);
tempFFT = new float[fftSize];
FFTdata = new float[fftSize];
appliedWindow = new float[fftSize];
generateFFTWindow(selectedWindow, fftSize);
credits::init();
@ -201,21 +201,23 @@ void MainWindow::fftHandler(dsp::complex_t* samples, int count, void* ctx) {
std::lock_guard<std::mutex> lck(_this->fft_mtx);
if (count != _this->fftSize) { return; }
memcpy(_this->fft_in, samples, count * sizeof(dsp::complex_t));
fftwf_execute(_this->fftwPlan);
int half = count / 2;
// Apply window
volk_32fc_32f_multiply_32fc((lv_32fc_t*)_this->fft_in, (lv_32fc_t*)samples, _this->appliedWindow, count);
// Execute FFT
fftwf_execute(_this->fftwPlan);
// Get the FFT buffer
float* fftBuf = gui::waterfall.getFFTBuffer();
if (fftBuf == NULL) {
gui::waterfall.pushFFT();
return;
}
volk_32fc_s32f_power_spectrum_32f(_this->tempFFT, (lv_32fc_t*)_this->fft_out, count, count);
memcpy(fftBuf, &_this->tempFFT[half], half * sizeof(float));
memcpy(&fftBuf[half], _this->tempFFT, half * sizeof(float));
// Take power of spectrum
volk_32fc_s32f_power_spectrum_32f(fftBuf, (lv_32fc_t*)_this->fft_out, count, count);
// Push back data
gui::waterfall.pushFFT();
}
@ -619,6 +621,30 @@ 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;
}
}
}
bool MainWindow::isPlaying() {

Wyświetl plik

@ -11,6 +11,12 @@
#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();
@ -18,6 +24,7 @@ public:
void setViewBandwidthSlider(float bandwidth);
bool sdrIsRunning();
void setFFTSize(int size);
void setFFTWindow(int win);
// TODO: Replace with it's own class
void setVFO(double freq);
@ -27,6 +34,7 @@ public:
bool lockWaterfallControls = false;
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);
@ -35,8 +43,7 @@ private:
std::mutex fft_mtx;
fftwf_complex *fft_in, *fft_out;
fftwf_plan fftwPlan;
float* tempFFT;
float* FFTdata;
float* appliedWindow;
// GUI Variables
bool firstMenuRender = true;
@ -56,6 +63,7 @@ private:
int tuningMode = tuner::TUNER_MODE_NORMAL;
dsp::stream<dsp::complex_t> dummyStream;
bool demoWindow = false;
int selectedWindow = 0;
EventHandler<VFOManager::VFO*> vfoCreatedHandler;

Wyświetl plik

@ -14,6 +14,7 @@ namespace displaymenu {
std::vector<std::string> colorMapNames;
std::string colorMapNamesTxt = "";
std::string colorMapAuthor = "";
int selectedWindow = 0;
const int FFTSizes[] = {
65536,
@ -70,6 +71,8 @@ namespace displaymenu {
}
gui::mainWindow.setFFTSize(FFTSizes[fftSizeId]);
selectedWindow = std::clamp<int>((int)core::configManager.conf["fftWindow"], 0, _FFT_WINDOW_COUNT-1);
gui::mainWindow.setFFTWindow(selectedWindow);
}
void draw(void* ctx) {
@ -99,13 +102,23 @@ namespace displaymenu {
ImGui::Text("FFT Size");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::Combo("##test_fft_size", &fftSizeId, FFTSizesStr)) {
if (ImGui::Combo("##sdrpp_fft_size", &fftSizeId, FFTSizesStr)) {
gui::mainWindow.setFFTSize(FFTSizes[fftSizeId]);
core::configManager.aquire();
core::configManager.conf["fftSize"] = FFTSizes[fftSizeId];
core::configManager.release(true);
}
ImGui::Text("FFT Window");
ImGui::SameLine();
ImGui::SetNextItemWidth(menuWidth - ImGui::GetCursorPosX());
if (ImGui::Combo("##sdrpp_fft_window", &selectedWindow, "Rectangular\0Blackman\0")) {
gui::mainWindow.setFFTWindow(selectedWindow);
core::configManager.aquire();
core::configManager.conf["fftWindow"] = selectedWindow;
core::configManager.release(true);
}
if (colorMapNames.size() > 0) {
ImGui::Text("Color Map");
ImGui::SameLine();

Wyświetl plik

@ -15,7 +15,7 @@
SDRPP_MOD_INFO {
/* Name: */ "frequency_manager",
/* Description: */ "Frequency manager module for SDR++",
/* Author: */ "Ryzerth;zimm",
/* Author: */ "Ryzerth;Zimm",
/* Version: */ 0, 3, 0,
/* Max instances */ 1
};
@ -125,8 +125,9 @@ private:
if (core::modComManager.interfaceExists(vfoName)) {
if (core::modComManager.getModuleName(vfoName) == "radio") {
int mode = bm.mode;
float bandwidth = bm.bandwidth;
core::modComManager.callInterface(vfoName, RADIO_IFACE_CMD_SET_MODE, &mode, NULL);
// TODO: Set bandwidth as well
core::modComManager.callInterface(vfoName, RADIO_IFACE_CMD_SET_BANDWIDTH, &bandwidth, NULL);
}
}
tuner::tune(tuner::TUNER_MODE_NORMAL, vfoName, bm.frequency);
@ -594,6 +595,9 @@ private:
}
ImGui::BeginTooltip();
ImGui::Text(hoveredBookmarkName.c_str());
ImGui::Separator();
ImGui::Text("Frequency: %s", freqToStr(hoveredBookmark.frequency).c_str());
ImGui::Text("Bandwidth: %s", freqToStr(hoveredBookmark.bandwidth).c_str());
ImGui::Text("Mode: %s", demodModeList[hoveredBookmark.mode]);
ImGui::EndTooltip();

Wyświetl plik

@ -162,8 +162,8 @@ public:
}
}
private:
void setBandwidth(float bandWidth, bool updateWaterfall = true) {
bandWidth = std::clamp<float>(bandWidth, bwMin, bwMax);
bw = bandWidth;
_vfo->setBandwidth(bw, updateWaterfall);
float audioBW = std::min<float>(audioSampRate / 2.0f, bw / 2.0f);
@ -173,6 +173,7 @@ private:
resamp.updateWindow(&win);
}
private:
void setSnapInterval(float snapInt) {
snapInterval = snapInt;
_vfo->setSnapInterval(snapInterval);

Wyświetl plik

@ -169,12 +169,13 @@ public:
}
}
private:
void setBandwidth(float bandWidth, bool updateWaterfall = true) {
bandWidth = std::clamp<float>(bandWidth, bwMin, bwMax);
bw = bandWidth;
_vfo->setBandwidth(bw, updateWaterfall);
}
private:
void setSnapInterval(float snapInt) {
snapInterval = snapInt;
_vfo->setSnapInterval(snapInterval);

Wyświetl plik

@ -162,12 +162,13 @@ public:
}
}
private:
void setBandwidth(float bandWidth, bool updateWaterfall = true) {
bandWidth = std::clamp<float>(bandWidth, bwMin, bwMax);
bw = bandWidth;
_vfo->setBandwidth(bw, updateWaterfall);
}
private:
void setSnapInterval(float snapInt) {
snapInterval = snapInt;
_vfo->setSnapInterval(snapInterval);

Wyświetl plik

@ -154,14 +154,15 @@ public:
}
}
private:
void setBandwidth(float bandWidth, bool updateWaterfall = true) {
bandWidth = std::clamp<float>(bandWidth, bwMin, bwMax);
bw = bandWidth;
_vfo->setBandwidth(bw, updateWaterfall);
demod.setDeviation(bw / 2.0f);
setAudioSampleRate(audioSampRate);
}
private:
void setSnapInterval(float snapInt) {
snapInterval = snapInt;
_vfo->setSnapInterval(snapInterval);

Wyświetl plik

@ -161,8 +161,8 @@ public:
}
}
private:
void setBandwidth(float bandWidth, bool updateWaterfall = true) {
bandWidth = std::clamp<float>(bandWidth, bwMin, bwMax);
bw = bandWidth;
_vfo->setBandwidth(bw, updateWaterfall);
demod.setBandWidth(bw);
@ -173,6 +173,7 @@ private:
resamp.updateWindow(&win);
}
private:
void setSnapInterval(float snapInt) {
snapInterval = snapInt;
_vfo->setSnapInterval(snapInterval);

Wyświetl plik

@ -174,6 +174,10 @@ private:
int* _in = (int*)in;
if (*_in != _this->demodId) { _this->selectDemodById(*_in); }
}
else if (code == RADIO_IFACE_CMD_SET_BANDWIDTH) {
float* _in = (float*)in;
_this->currentDemod->setBandwidth(*_in, true);
}
}
void selectDemod(Demodulator* demod) {

Wyświetl plik

@ -12,6 +12,7 @@ public:
virtual VFOManager::VFO* getVFO() = 0;
virtual void setAudioSampleRate(float sampleRate) = 0;
virtual float getAudioSampleRate() = 0;
virtual void setBandwidth(float bandWidth, bool updateWaterfall = true) = 0;
virtual dsp::stream<dsp::stereo_t>* getOutput() = 0;
virtual void showMenu() = 0;
};

Wyświetl plik

@ -116,6 +116,10 @@ public:
}
// TODO: Allow selection of the bandwidth
}
void setBandwidth(float bandWidth, bool updateWaterfall = true) {
// Do nothing
}
private:

Wyświetl plik

@ -161,8 +161,8 @@ public:
}
}
private:
void setBandwidth(float bandWidth, bool updateWaterfall = true) {
bandWidth = std::clamp<float>(bandWidth, bwMin, bwMax);
bw = bandWidth;
_vfo->setBandwidth(bw, updateWaterfall);
demod.setBandWidth(bw);
@ -173,6 +173,7 @@ private:
resamp.updateWindow(&win);
}
private:
void setSnapInterval(float snapInt) {
snapInterval = snapInt;
_vfo->setSnapInterval(snapInterval);

Wyświetl plik

@ -192,13 +192,15 @@ public:
_vfo->setSnapInterval(snapInterval);
}
private:
void setBandwidth(float bandWidth, bool updateWaterfall = true) {
bandWidth = std::clamp<float>(bandWidth, bwMin, bwMax);
bw = bandWidth;
_vfo->setBandwidth(bw, updateWaterfall);
demod.setDeviation(bw / 2.0f);
}
private:
const float bwMax = 250000;
const float bwMin = 50000;
const float bbSampRate = 250000;

Wyświetl plik

@ -1,6 +1,6 @@
# SDR++, The bloat-free SDR software
![Screenshot](https://i.imgur.com/EFOqwQQ.png)
![Screenshot](https://i.imgur.com/Ter2MQJ.png)
SDR++ is a cross-platform and open source SDR software with the aim of being bloat free and simple to use.
![Build](https://github.com/AlexandreRouma/SDRPlusPlus/workflows/Build%20Binaries/badge.svg)