mirror of
				https://github.com/AlexandreRouma/SDRPlusPlus.git
				synced 2025-11-04 10:49:11 +01:00 
			
		
		
		
	More DSP cleanup + Remove FastFFT option because it should never be used
This commit is contained in:
		
							
								
								
									
										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) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user