#pragma once #include #include #include #include #include #include #include #include #include #define FAST_ATAN2_COEF1 FL_M_PI / 4.0f #define FAST_ATAN2_COEF2 3.0f * FAST_ATAN2_COEF1 inline float fast_arctan2(float y, float x) { float abs_y = fabsf(y); float r, angle; if (x == 0.0f && y == 0.0f) { return 0.0f; } if (x>=0.0f) { r = (x - abs_y) / (x + abs_y); angle = FAST_ATAN2_COEF1 - FAST_ATAN2_COEF1 * r; } else { r = (x + abs_y) / (abs_y - x); angle = FAST_ATAN2_COEF2 - FAST_ATAN2_COEF1 * r; } if (y < 0.0f) { return -angle; } return angle; } namespace dsp { class FloatFMDemod : public generic_block { public: FloatFMDemod() {} FloatFMDemod(stream* in, float sampleRate, float deviation) { init(in, sampleRate, deviation); } void init(stream* in, float sampleRate, float deviation) { _in = in; _sampleRate = sampleRate; _deviation = deviation; phasorSpeed = (2 * FL_M_PI) / (_sampleRate / _deviation); generic_block::registerInput(_in); generic_block::registerOutput(&out); } void setInput(stream* in) { std::lock_guard lck(generic_block::ctrlMtx); generic_block::tempStop(); generic_block::unregisterInput(_in); _in = in; generic_block::registerInput(_in); generic_block::tempStart(); } void setSampleRate(float sampleRate) { std::lock_guard lck(generic_block::ctrlMtx); generic_block::tempStop(); _sampleRate = sampleRate; phasorSpeed = (2 * FL_M_PI) / (_sampleRate / _deviation); generic_block::tempStart(); } float getSampleRate() { return _sampleRate; } void setDeviation(float deviation) { std::lock_guard lck(generic_block::ctrlMtx); generic_block::tempStop(); _deviation = deviation; phasorSpeed = (2 * FL_M_PI) / (_sampleRate / _deviation); generic_block::tempStart(); } float getDeviation() { return _deviation; } int run() { int count = _in->read(); if (count < 0) { return -1; } // This is somehow faster than volk... float diff, currentPhase; for (int i = 0; i < count; i++) { currentPhase = fast_arctan2(_in->readBuf[i].im, _in->readBuf[i].re); diff = currentPhase - phase; if (diff > 3.1415926535f) { diff -= 2 * 3.1415926535f; } else if (diff <= -3.1415926535f) { diff += 2 * 3.1415926535f; } out.writeBuf[i] = diff / phasorSpeed; phase = currentPhase; } _in->flush(); if (!out.swap(count)) { return -1; } return count; } stream out; private: float phase = 0; float phasorSpeed, _sampleRate, _deviation; stream* _in; }; class FMDemod : public generic_block { public: FMDemod() {} FMDemod(stream* in, float sampleRate, float deviation) { init(in, sampleRate, deviation); } void init(stream* in, float sampleRate, float deviation) { _in = in; _sampleRate = sampleRate; _deviation = deviation; phasorSpeed = (2 * FL_M_PI) / (_sampleRate / _deviation); generic_block::registerInput(_in); generic_block::registerOutput(&out); } void setInput(stream* in) { std::lock_guard lck(generic_block::ctrlMtx); generic_block::tempStop(); generic_block::unregisterInput(_in); _in = in; generic_block::registerInput(_in); generic_block::tempStart(); } void setSampleRate(float sampleRate) { std::lock_guard lck(generic_block::ctrlMtx); generic_block::tempStop(); _sampleRate = sampleRate; phasorSpeed = (2 * FL_M_PI) / (_sampleRate / _deviation); generic_block::tempStart(); } float getSampleRate() { return _sampleRate; } void setDeviation(float deviation) { _deviation = deviation; phasorSpeed = (2 * FL_M_PI) / (_sampleRate / _deviation); } float getDeviation() { return _deviation; } int run() { int count = _in->read(); if (count < 0) { return -1; } // This is somehow faster than volk... float diff, currentPhase; for (int i = 0; i < count; i++) { currentPhase = fast_arctan2(_in->readBuf[i].im, _in->readBuf[i].re); diff = currentPhase - phase; if (diff > 3.1415926535f) { diff -= 2 * 3.1415926535f; } else if (diff <= -3.1415926535f) { diff += 2 * 3.1415926535f; } out.writeBuf[i].l = diff / phasorSpeed; out.writeBuf[i].r = diff / phasorSpeed; phase = currentPhase; } _in->flush(); if (!out.swap(count)) { return -1; } return count; } stream out; private: float phase = 0; float phasorSpeed, _sampleRate, _deviation; stream* _in; }; class AMDemod : public generic_block { public: AMDemod() {} AMDemod(stream* in) { init(in); } void init(stream* in) { _in = in; generic_block::registerInput(_in); generic_block::registerOutput(&out); } void setInput(stream* in) { std::lock_guard lck(generic_block::ctrlMtx); generic_block::tempStop(); generic_block::unregisterInput(_in); _in = in; generic_block::registerInput(_in); generic_block::tempStart(); } int run() { int count = _in->read(); if (count < 0) { return -1; } volk_32fc_magnitude_32f(out.writeBuf, (lv_32fc_t*)_in->readBuf, count); _in->flush(); float avg; volk_32f_accumulator_s32f(&avg, out.writeBuf, count); avg /= (float)count; for (int i = 0; i < count; i++) { out.writeBuf[i] -= avg; } if (!out.swap(count)) { return -1; } return count; } stream out; private: stream* _in; }; class SSBDemod : public generic_block { public: SSBDemod() {} SSBDemod(stream* in, float sampleRate, float bandWidth, int mode) { init(in, sampleRate, bandWidth, mode); } ~SSBDemod() { generic_block::stop(); delete[] buffer; } enum { MODE_USB, MODE_LSB, MODE_DSB }; void init(stream* in, float sampleRate, float bandWidth, int mode) { _in = in; _sampleRate = sampleRate; _bandWidth = bandWidth; _mode = mode; phase = lv_cmake(1.0f, 0.0f); switch (_mode) { case MODE_USB: phaseDelta = lv_cmake(std::cos((_bandWidth / _sampleRate) * FL_M_PI), std::sin((_bandWidth / _sampleRate) * FL_M_PI)); break; case MODE_LSB: phaseDelta = lv_cmake(std::cos(-(_bandWidth / _sampleRate) * FL_M_PI), std::sin(-(_bandWidth / _sampleRate) * FL_M_PI)); break; case MODE_DSB: phaseDelta = lv_cmake(1.0f, 0.0f); break; } buffer = new lv_32fc_t[STREAM_BUFFER_SIZE]; generic_block::registerInput(_in); generic_block::registerOutput(&out); } void setInput(stream* in) { std::lock_guard lck(generic_block::ctrlMtx); generic_block::tempStop(); generic_block::unregisterInput(_in); _in = in; generic_block::registerInput(_in); generic_block::tempStart(); } void setSampleRate(float sampleRate) { // No need to restart _sampleRate = sampleRate; switch (_mode) { case MODE_USB: phaseDelta = lv_cmake(std::cos((_bandWidth / _sampleRate) * FL_M_PI), std::sin((_bandWidth / _sampleRate) * FL_M_PI)); break; case MODE_LSB: phaseDelta = lv_cmake(std::cos(-(_bandWidth / _sampleRate) * FL_M_PI), std::sin(-(_bandWidth / _sampleRate) * FL_M_PI)); break; case MODE_DSB: phaseDelta = lv_cmake(1.0f, 0.0f); break; } } void setBandWidth(float bandWidth) { // No need to restart _bandWidth = bandWidth; switch (_mode) { case MODE_USB: phaseDelta = lv_cmake(std::cos((_bandWidth / _sampleRate) * FL_M_PI), std::sin((_bandWidth / _sampleRate) * FL_M_PI)); break; case MODE_LSB: phaseDelta = lv_cmake(std::cos(-(_bandWidth / _sampleRate) * FL_M_PI), std::sin(-(_bandWidth / _sampleRate) * FL_M_PI)); break; case MODE_DSB: phaseDelta = lv_cmake(1.0f, 0.0f); break; } } void setMode(int mode) { _mode = mode; switch (_mode) { case MODE_USB: phaseDelta = lv_cmake(std::cos((_bandWidth / _sampleRate) * FL_M_PI), std::sin((_bandWidth / _sampleRate) * FL_M_PI)); break; case MODE_LSB: phaseDelta = lv_cmake(std::cos(-(_bandWidth / _sampleRate) * FL_M_PI), std::sin(-(_bandWidth / _sampleRate) * FL_M_PI)); break; case MODE_DSB: phaseDelta = lv_cmake(1.0f, 0.0f); break; } } int run() { int count = _in->read(); if (count < 0) { return -1; } volk_32fc_s32fc_x2_rotator_32fc(buffer, (lv_32fc_t*)_in->readBuf, phaseDelta, &phase, count); volk_32fc_deinterleave_real_32f(out.writeBuf, buffer, count); _in->flush(); if (!out.swap(count)) { return -1; } return count; } stream out; private: int _mode; float _sampleRate, _bandWidth; stream* _in; lv_32fc_t* buffer; lv_32fc_t phase; lv_32fc_t phaseDelta; }; class MSKDemod : public generic_hier_block { public: MSKDemod() {} MSKDemod(stream* input, float sampleRate, float deviation, float baudRate, float omegaGain = (0.01*0.01) / 4, float muGain = 0.01f, float omegaRelLimit = 0.005f) { init(input, sampleRate, deviation, baudRate, omegaGain, muGain, omegaRelLimit); } void init(stream* input, float sampleRate, float deviation, float baudRate, float omegaGain = (0.01*0.01) / 4, float muGain = 0.01f, float omegaRelLimit = 0.005f) { _sampleRate = sampleRate; _deviation = deviation; _baudRate = baudRate; _omegaGain = omegaGain; _muGain = muGain; _omegaRelLimit = omegaRelLimit; demod.init(input, _sampleRate, _deviation); recov.init(&demod.out, _sampleRate / _baudRate, _omegaGain, _muGain, _omegaRelLimit); out = &recov.out; generic_hier_block::registerBlock(&demod); generic_hier_block::registerBlock(&recov); } void setSampleRate(float sampleRate) { generic_hier_block::tempStop(); _sampleRate = sampleRate; demod.setSampleRate(_sampleRate); recov.setOmega(_sampleRate / _baudRate, _omegaRelLimit); generic_hier_block::tempStart(); } void setDeviation(float deviation) { _deviation = deviation; demod.setDeviation(deviation); } void setBaudRate(float baudRate, float omegaRelLimit) { _baudRate = baudRate; _omegaRelLimit = omegaRelLimit; recov.setOmega(_sampleRate / _baudRate, _omegaRelLimit); } void setMMGains(float omegaGain, float myGain) { _omegaGain = omegaGain; _muGain = myGain; recov.setGains(_omegaGain, _muGain); } void setOmegaRelLimit(float omegaRelLimit) { _omegaRelLimit = omegaRelLimit; recov.setOmegaRelLimit(_omegaRelLimit); } stream* out = NULL; private: FloatFMDemod demod; MMClockRecovery recov; float _sampleRate; float _deviation; float _baudRate; float _omegaGain; float _muGain; float _omegaRelLimit; }; template class PSKDemod : public generic_hier_block> { public: PSKDemod() {} PSKDemod(stream* input, float sampleRate, float baudRate, int RRCTapCount = 31, float RRCAlpha = 0.32f, float agcRate = 10e-4, float costasLoopBw = 0.004f, float omegaGain = (0.01*0.01) / 4, float muGain = 0.01f, float omegaRelLimit = 0.005f) { init(input, sampleRate, baudRate, RRCTapCount, RRCAlpha, agcRate, costasLoopBw, omegaGain, muGain, omegaRelLimit); } void init(stream* input, float sampleRate, float baudRate, int RRCTapCount = 31, float RRCAlpha = 0.32f, float agcRate = 10e-4, float costasLoopBw = 0.004f, float omegaGain = (0.01*0.01) / 4, float muGain = 0.01f, float omegaRelLimit = 0.005f) { _RRCTapCount = RRCTapCount; _RRCAlpha = RRCAlpha; _sampleRate = sampleRate; _agcRate = agcRate; _costasLoopBw = costasLoopBw; _baudRate = baudRate; _omegaGain = omegaGain; _muGain = muGain; _omegaRelLimit = omegaRelLimit; agc.init(input, 1.0f, 65535, _agcRate); taps.init(_RRCTapCount, _sampleRate, _baudRate, _RRCAlpha); rrc.init(&agc.out, &taps); demod.init(&rrc.out, _costasLoopBw); generic_hier_block>::registerBlock(&agc); generic_hier_block>::registerBlock(&rrc); generic_hier_block>::registerBlock(&demod); if constexpr (OFFSET) { delay.init(&demod.out); recov.init(&delay.out, _sampleRate / _baudRate, _omegaGain, _muGain, _omegaRelLimit); generic_hier_block>::registerBlock(&delay); } else { recov.init(&demod.out, _sampleRate / _baudRate, _omegaGain, _muGain, _omegaRelLimit); } generic_hier_block>::registerBlock(&recov); out = &recov.out; } void setInput(stream* input) { agc.setInput(input); } void setSampleRate(float sampleRate) { _sampleRate = sampleRate; rrc.tempStop(); recov.tempStop(); taps.setSampleRate(_sampleRate); rrc.updateWindow(&taps); recov.setOmega(_sampleRate / _baudRate, _omegaRelLimit); rrc.tempStart(); recov.tempStart(); } void setBaudRate(float baudRate) { _baudRate = baudRate; rrc.tempStop(); recov.tempStop(); taps.setBaudRate(_baudRate); rrc.updateWindow(&taps); recov.setOmega(_sampleRate / _baudRate, _omegaRelLimit); rrc.tempStart(); recov.tempStart(); } void setRRCParams(int RRCTapCount, float RRCAlpha) { _RRCTapCount = RRCTapCount; _RRCAlpha = RRCAlpha; taps.setTapCount(_RRCTapCount); taps.setAlpha(RRCAlpha); rrc.updateWindow(&taps); } void setAgcRate(float agcRate) { _agcRate = agcRate; agc.setRate(_agcRate); } void setCostasLoopBw(float costasLoopBw) { _costasLoopBw = costasLoopBw; demod.setLoopBandwidth(_costasLoopBw); } void setMMGains(float omegaGain, float myGain) { _omegaGain = omegaGain; _muGain = myGain; recov.setGains(_omegaGain, _muGain); } void setOmegaRelLimit(float omegaRelLimit) { _omegaRelLimit = omegaRelLimit; recov.setOmegaRelLimit(_omegaRelLimit); } stream* out = NULL; private: dsp::ComplexAGC agc; dsp::RRCTaps taps; dsp::FIR rrc; CostasLoop demod; DelayImag delay; MMClockRecovery recov; int _RRCTapCount; float _RRCAlpha; float _sampleRate; float _agcRate; float _baudRate; float _costasLoopBw; float _omegaGain; float _muGain; float _omegaRelLimit; }; class PMDemod : public generic_hier_block { public: PMDemod() {} PMDemod(stream* input, float sampleRate, float baudRate, float agcRate = 0.02e-3f, float pllLoopBandwidth = (0.06f*0.06f) / 4.0f, int rrcTapCount = 31, float rrcAlpha = 0.6f, float omegaGain = (0.01*0.01) / 4, float muGain = 0.01f, float omegaRelLimit = 0.005f) { init(input, sampleRate, baudRate, agcRate, pllLoopBandwidth, rrcTapCount, rrcAlpha, omegaGain, muGain, omegaRelLimit); } void init(stream* input, float sampleRate, float baudRate, float agcRate = 0.02e-3f, float pllLoopBandwidth = (0.06f*0.06f) / 4.0f, int rrcTapCount = 31, float rrcAlpha = 0.6f, float omegaGain = (0.01*0.01) / 4, float muGain = 0.01f, float omegaRelLimit = 0.005f) { _sampleRate = sampleRate; _baudRate = baudRate; _agcRate = agcRate; _pllLoopBandwidth = pllLoopBandwidth; _rrcTapCount = rrcTapCount; _rrcAlpha = rrcAlpha; _omegaGain = omegaGain; _muGain = muGain; _omegaRelLimit = omegaRelLimit; agc.init(input, 1.0f, 65535, _agcRate); pll.init(&agc.out, _pllLoopBandwidth); rrcwin.init(_rrcTapCount, _sampleRate, _baudRate, _rrcAlpha); rrc.init(&pll.out, &rrcwin); recov.init(&rrc.out, _sampleRate / _baudRate, _omegaGain, _muGain, _omegaRelLimit); out = &recov.out; generic_hier_block::registerBlock(&agc); generic_hier_block::registerBlock(&pll); generic_hier_block::registerBlock(&rrc); generic_hier_block::registerBlock(&recov); } void setInput(stream* input) { agc.setInput(input); } void setAgcRate(float agcRate) { _agcRate = agcRate; agc.setRate(_agcRate); } void setPllLoopBandwidth(float pllLoopBandwidth) { _pllLoopBandwidth = pllLoopBandwidth; pll.setLoopBandwidth(_pllLoopBandwidth); } void setRRCParams(int rrcTapCount, float rrcAlpha) { _rrcTapCount = rrcTapCount; _rrcAlpha = rrcAlpha; rrcwin.setTapCount(_rrcTapCount); rrcwin.setAlpha(_rrcAlpha); rrc.updateWindow(&rrcwin); } void setMMGains(float omegaGain, float muGain) { _omegaGain = omegaGain; _muGain = muGain; recov.setGains(_omegaGain, _muGain); } void setOmegaRelLimit(float omegaRelLimit) { _omegaRelLimit = omegaRelLimit; recov.setOmegaRelLimit(_omegaRelLimit); } stream* out = NULL; private: dsp::ComplexAGC agc; dsp::CarrierTrackingPLL pll; dsp::RRCTaps rrcwin; dsp::FIR rrc; dsp::MMClockRecovery recov; float _sampleRate; float _baudRate; float _agcRate; float _pllLoopBandwidth; int _rrcTapCount; float _rrcAlpha; float _omegaGain; float _muGain; float _omegaRelLimit; }; }