mirror of
				https://github.com/AlexandreRouma/SDRPlusPlus.git
				synced 2025-10-31 17:08:13 +01:00 
			
		
		
		
	Added decimation
This commit is contained in:
		| @@ -47,13 +47,15 @@ namespace core { | ||||
|     GLFWwindow* window; | ||||
|  | ||||
|     void setInputSampleRate(double samplerate) { | ||||
|         sigpath::signalPath.sourceSampleRate = samplerate; | ||||
|         double effectiveSr = samplerate / ((double)(1 << sigpath::signalPath.decimation)); | ||||
|         // NOTE: Zoom controls won't work | ||||
|         spdlog::info("New DSP samplerate: {0}", samplerate); | ||||
|         gui::waterfall.setBandwidth(samplerate); | ||||
|         spdlog::info("New DSP samplerate: {0} (source samplerate is {1})", effectiveSr, samplerate); | ||||
|         gui::waterfall.setBandwidth(effectiveSr); | ||||
|         gui::waterfall.setViewOffset(0); | ||||
|         gui::waterfall.setViewBandwidth(samplerate); | ||||
|         sigpath::signalPath.setSampleRate(samplerate); | ||||
|         gui::mainWindow.setViewBandwidthSlider(samplerate); | ||||
|         gui::waterfall.setViewBandwidth(effectiveSr); | ||||
|         sigpath::signalPath.setSampleRate(effectiveSr); | ||||
|         gui::mainWindow.setViewBandwidthSlider(effectiveSr); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| @@ -202,6 +204,7 @@ int sdrpp_main(int argc, char *argv[]) { | ||||
|     defConfig["showMenu"] = true; | ||||
|     defConfig["showWaterfall"] = true; | ||||
|     defConfig["source"] = ""; | ||||
|     defConfig["decimationPower"] = 0; | ||||
|  | ||||
|     defConfig["streams"]["Radio"]["muted"] = false; | ||||
|     defConfig["streams"]["Radio"]["sink"] = "Audio"; | ||||
|   | ||||
							
								
								
									
										108
									
								
								core/src/dsp/decimation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								core/src/dsp/decimation.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| #pragma once | ||||
| #include <dsp/block.h> | ||||
| #include <dsp/stream.h> | ||||
| #include <dsp/types.h> | ||||
| #include <dsp/window.h> | ||||
|  | ||||
| namespace dsp { | ||||
|     template <class T> | ||||
|     class HalfDecimator : public generic_block<HalfDecimator<T>> { | ||||
|     public: | ||||
|         HalfDecimator() {} | ||||
|  | ||||
|         HalfDecimator(stream<T>* in, dsp::filter_window::generic_window* window) { init(in, window); } | ||||
|  | ||||
|         ~HalfDecimator() { | ||||
|             if (!generic_block<HalfDecimator<T>>::_block_init) { return; } | ||||
|             generic_block<HalfDecimator<T>>::stop(); | ||||
|             volk_free(buffer); | ||||
|             volk_free(taps); | ||||
|             generic_block<HalfDecimator<T>>::_block_init = false; | ||||
|         } | ||||
|  | ||||
|         void init(stream<T>* in, dsp::filter_window::generic_window* window) { | ||||
|             _in = in; | ||||
|  | ||||
|             tapCount = window->getTapCount(); | ||||
|             taps = (float*)volk_malloc(tapCount * sizeof(float), volk_get_alignment()); | ||||
|             window->createTaps(taps, tapCount); | ||||
|  | ||||
|             buffer = (T*)volk_malloc(STREAM_BUFFER_SIZE * sizeof(T) * 2, volk_get_alignment()); | ||||
|             bufStart = &buffer[tapCount]; | ||||
|             generic_block<HalfDecimator<T>>::registerInput(_in); | ||||
|             generic_block<HalfDecimator<T>>::registerOutput(&out); | ||||
|             generic_block<HalfDecimator<T>>::_block_init = true; | ||||
|         } | ||||
|  | ||||
|         void setInput(stream<T>* in) { | ||||
|             assert(generic_block<HalfDecimator<T>>::_block_init); | ||||
|             std::lock_guard<std::mutex> lck(generic_block<HalfDecimator<T>>::ctrlMtx); | ||||
|             generic_block<HalfDecimator<T>>::tempStop(); | ||||
|             generic_block<HalfDecimator<T>>::unregisterInput(_in); | ||||
|             _in = in; | ||||
|             generic_block<HalfDecimator<T>>::registerInput(_in); | ||||
|             generic_block<HalfDecimator<T>>::tempStart(); | ||||
|         } | ||||
|  | ||||
|         void updateWindow(dsp::filter_window::generic_window* window) { | ||||
|             assert(generic_block<HalfDecimator<T>>::_block_init); | ||||
|             std::lock_guard<std::mutex> lck(generic_block<HalfDecimator<T>>::ctrlMtx); | ||||
|             _window = window; | ||||
|             volk_free(taps); | ||||
|             tapCount = window->getTapCount(); | ||||
|             taps = (float*)volk_malloc(tapCount * sizeof(float), volk_get_alignment()); | ||||
|             bufStart = &buffer[tapCount]; | ||||
|             window->createTaps(taps, tapCount); | ||||
|         } | ||||
|  | ||||
|         int run() { | ||||
|             int count = _in->read(); | ||||
|             if (count < 0) { return -1; } | ||||
|  | ||||
|             generic_block<HalfDecimator<T>>::ctrlMtx.lock(); | ||||
|  | ||||
|             memcpy(bufStart, _in->readBuf, count * sizeof(T)); | ||||
|             _in->flush(); | ||||
|  | ||||
|             int inIndex = _inIndex; | ||||
|             int outIndex = 0; | ||||
|             if constexpr (std::is_same_v<T, float>) { | ||||
|                 while (inIndex < count) { | ||||
|                     volk_32f_x2_dot_prod_32f((float*)&out.writeBuf[outIndex], (float*)&buffer[inIndex+1], taps, tapCount); | ||||
|                     inIndex += 2; | ||||
|                     outIndex++; | ||||
|                 } | ||||
|             } | ||||
|             if constexpr (std::is_same_v<T, complex_t>) { | ||||
|                 while (inIndex < count) { | ||||
|                     volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&out.writeBuf[outIndex], (lv_32fc_t*)&buffer[inIndex+1], taps, tapCount); | ||||
|                     inIndex += 2; | ||||
|                     outIndex++; | ||||
|                 } | ||||
|             } | ||||
|             _inIndex = inIndex - count; | ||||
|  | ||||
|             if (!out.swap(outIndex)) { return -1; } | ||||
|  | ||||
|             memmove(buffer, &buffer[count], tapCount * sizeof(T)); | ||||
|  | ||||
|             generic_block<HalfDecimator<T>>::ctrlMtx.unlock(); | ||||
|  | ||||
|             return count; | ||||
|         } | ||||
|  | ||||
|         stream<T> out; | ||||
|  | ||||
|     private: | ||||
|         stream<T>* _in; | ||||
|  | ||||
|         dsp::filter_window::generic_window* _window; | ||||
|  | ||||
|         T* bufStart; | ||||
|         T* buffer; | ||||
|         int tapCount; | ||||
|         float* taps; | ||||
|         int _inIndex = 0; | ||||
|  | ||||
|     }; | ||||
| } | ||||
| @@ -11,6 +11,7 @@ namespace sourecmenu { | ||||
|     int sourceId = 0; | ||||
|     double customOffset = 0.0; | ||||
|     double effectiveOffset = 0.0; | ||||
|     int decimationPower = 0; | ||||
|  | ||||
|     EventHandler<std::string> sourceRegisteredHandler; | ||||
|     EventHandler<std::string> sourceUnregisterHandler; | ||||
| @@ -39,6 +40,14 @@ namespace sourecmenu { | ||||
|                                 "Ku LNB (9750MHz)\0" | ||||
|                                 "Ku LNB (10700MHz)\0"; | ||||
|  | ||||
|     const char* decimationStages = "None\0" | ||||
|                                 "2\0" | ||||
|                                 "4\0" | ||||
|                                 "8\0" | ||||
|                                 "16\0" | ||||
|                                 "32\0" | ||||
|                                 "64\0"; | ||||
|  | ||||
|     void updateOffset() { | ||||
|         if (offsetMode == OFFSET_MODE_CUSTOM) {         effectiveOffset = customOffset; } | ||||
|         else if (offsetMode == OFFSET_MODE_SPYVERTER) { effectiveOffset = 120000000; }          // 120MHz Up-conversion | ||||
| @@ -113,10 +122,12 @@ namespace sourecmenu { | ||||
|         std::string selected = core::configManager.conf["source"]; | ||||
|         customOffset = core::configManager.conf["offset"]; | ||||
|         offsetMode = core::configManager.conf["offsetMode"]; | ||||
|         decimationPower = core::configManager.conf["decimationPower"]; | ||||
|         updateOffset(); | ||||
|  | ||||
|         refreshSources(); | ||||
|         selectSource(selected); | ||||
|         sigpath::signalPath.setDecimation(decimationPower); | ||||
|  | ||||
|         sourceRegisteredHandler.handler = onSourceRegistered; | ||||
|         sourceUnregisterHandler.handler = onSourceUnregister; | ||||
| @@ -130,8 +141,9 @@ namespace sourecmenu { | ||||
|  | ||||
|     void draw(void* ctx) { | ||||
|         float itemWidth = ImGui::GetContentRegionAvailWidth(); | ||||
|         bool running = gui::mainWindow.sdrIsRunning(); | ||||
|  | ||||
|         if (gui::mainWindow.sdrIsRunning()) { style::beginDisabled(); } | ||||
|         if (running) { style::beginDisabled(); } | ||||
|  | ||||
|         ImGui::SetNextItemWidth(itemWidth); | ||||
|         if (ImGui::Combo("##source", &sourceId, sourceNamesTxt.c_str())) { | ||||
| @@ -141,7 +153,7 @@ namespace sourecmenu { | ||||
|             core::configManager.release(true); | ||||
|         } | ||||
|  | ||||
|         if (gui::mainWindow.sdrIsRunning()) { style::endDisabled(); } | ||||
|         if (running) { style::endDisabled(); } | ||||
|  | ||||
|         sigpath::sourceManager.showSelectedMenu(); | ||||
|  | ||||
| @@ -171,5 +183,17 @@ namespace sourecmenu { | ||||
|             ImGui::InputDouble("##freq_offset", &effectiveOffset, 1.0, 100.0); | ||||
|             style::endDisabled(); | ||||
|         } | ||||
|  | ||||
|         if (running) { style::beginDisabled(); } | ||||
|         ImGui::Text("Decimation"); | ||||
|         ImGui::SameLine(); | ||||
|         ImGui::SetNextItemWidth(itemWidth - ImGui::GetCursorPosX()); | ||||
|         if (ImGui::Combo("##source_decim", &decimationPower, decimationStages)) { | ||||
|             sigpath::signalPath.setDecimation(decimationPower); | ||||
|             core::configManager.acquire(); | ||||
|             core::configManager.conf["decimationPower"] = decimationPower; | ||||
|             core::configManager.release(true); | ||||
|         } | ||||
|         if (running) { style::endDisabled(); } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| #include <signal_path/dsp.h> | ||||
| #include <core.h> | ||||
|  | ||||
| SignalPath::SignalPath() { | ||||
|      | ||||
| @@ -6,10 +7,13 @@ SignalPath::SignalPath() { | ||||
|  | ||||
| void SignalPath::init(uint64_t sampleRate, int fftRate, int fftSize, dsp::stream<dsp::complex_t>* input, dsp::complex_t* fftBuffer, void fftHandler(dsp::complex_t*,int,void*), void* fftHandlerCtx) { | ||||
|     this->sampleRate = sampleRate; | ||||
|     this->sourceSampleRate = sampleRate; | ||||
|     this->fftRate = fftRate; | ||||
|     this->fftSize = fftSize; | ||||
|     inputBlockSize = sampleRate / 200.0f; | ||||
|  | ||||
|     halfBandWindow.init(1000000, 200000, 4000000); | ||||
|  | ||||
|     // split.init(input); | ||||
|     inputBuffer.init(input); | ||||
|     split.init(&inputBuffer.out); | ||||
| @@ -47,17 +51,25 @@ double SignalPath::getSampleRate() { | ||||
| } | ||||
|  | ||||
| void SignalPath::start() { | ||||
|     for (auto& decimator : decimators) { | ||||
|         decimator->start(); | ||||
|     } | ||||
|     inputBuffer.start(); | ||||
|     split.start(); | ||||
|     reshape.start(); | ||||
|     fftHandlerSink.start(); | ||||
|     running = true; | ||||
| } | ||||
|  | ||||
| void SignalPath::stop() { | ||||
|     for (auto& decimator : decimators) { | ||||
|         decimator->stop(); | ||||
|     } | ||||
|     inputBuffer.stop(); | ||||
|     split.stop(); | ||||
|     reshape.stop(); | ||||
|     fftHandlerSink.stop(); | ||||
|     running = false; | ||||
| } | ||||
|  | ||||
| dsp::VFO* SignalPath::addVFO(std::string name, double outSampleRate, double bandwidth, double offset) { | ||||
| @@ -87,7 +99,6 @@ void SignalPath::removeVFO(std::string name) { | ||||
| } | ||||
|  | ||||
| void SignalPath::setInput(dsp::stream<dsp::complex_t>* input) { | ||||
|     // split.setInput(input); | ||||
|     inputBuffer.setInput(input); | ||||
| } | ||||
|  | ||||
| @@ -120,4 +131,38 @@ void SignalPath::stopFFT() { | ||||
|  | ||||
| void SignalPath::setBuffering(bool enabled) { | ||||
|     inputBuffer.bypass = !enabled; | ||||
| } | ||||
|  | ||||
| void SignalPath::setDecimation(int dec) { | ||||
|     decimation = dec; | ||||
|  | ||||
|     // Stop existing decimators | ||||
|     if (!decimators.empty()) { | ||||
|         for (auto& decimator : decimators) { | ||||
|             decimator->stop(); | ||||
|             delete decimator; | ||||
|         } | ||||
|     } | ||||
|     decimators.clear(); | ||||
|  | ||||
|     // If no decimation, reconnect | ||||
|     if (!dec) { | ||||
|         split.setInput(&inputBuffer.out); | ||||
|         core::setInputSampleRate(sourceSampleRate); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|     // Create new decimators | ||||
|     if (running) { split.stop(); } | ||||
|     for (int i = 0; i < dec; i++) { | ||||
|         dsp::HalfDecimator<dsp::complex_t>* decimator = new dsp::HalfDecimator<dsp::complex_t>((i == 0) ? &inputBuffer.out : &decimators[i-1]->out, &halfBandWindow); | ||||
|         if (running) { decimator->start(); } | ||||
|         // TODO: ONLY start if running | ||||
|         decimators.push_back(decimator); | ||||
|     } | ||||
|     split.setInput(&decimators[decimators.size()-1]->out); | ||||
|     if (running) { split.start(); } | ||||
|  | ||||
|     // Update the DSP sample rate | ||||
|     core::setInputSampleRate(sourceSampleRate); | ||||
| } | ||||
| @@ -3,6 +3,7 @@ | ||||
| #include <dsp/vfo.h> | ||||
| #include <map> | ||||
| #include <dsp/sink.h> | ||||
| #include <dsp/decimation.h> | ||||
|  | ||||
| class SignalPath { | ||||
| public: | ||||
| @@ -21,8 +22,11 @@ public: | ||||
|     void startFFT(); | ||||
|     void stopFFT(); | ||||
|     void setBuffering(bool enabled); | ||||
|     void setDecimation(int dec); | ||||
|  | ||||
|     dsp::SampleFrameBuffer<dsp::complex_t> inputBuffer; | ||||
|     double sourceSampleRate = 0; | ||||
|     int decimation = 0; | ||||
|  | ||||
| private: | ||||
|     struct VFO_t { | ||||
| @@ -39,10 +43,13 @@ private: | ||||
|  | ||||
|     // VFO | ||||
|     std::map<std::string, VFO_t> vfos; | ||||
|     std::vector<dsp::HalfDecimator<dsp::complex_t>*> decimators; | ||||
|     dsp::filter_window::BlackmanWindow halfBandWindow; | ||||
|  | ||||
|     double sampleRate; | ||||
|     double fftRate; | ||||
|     int fftSize; | ||||
|     int inputBlockSize; | ||||
|     bool bufferingEnabled = false; | ||||
|     bool running = false; | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user