#ifndef _RECEIVER_H_ #define _RECEIVER_H_ #include #include #include #include #include #include #include #include #include "LogComponent.h" #include #include #include #include #include #include #include #include #ifdef _WINDOWS #include #define isnan _isnan #define isinf(x) (!_finite(x)) #endif using namespace Radio; // --------------------------------------------------- #define NUM_PASSBAND_SAMPLES_PER_SYM 4 #define NUM_BASEBAND_SAMPLES_PER_SYM 2 #define MODE_PROCESS_PASSBAND 0 #define MODE_PROCESS_BASEBAND 1 #define RCF_TYPE_POLYPHASE_DISCRETE 0 #define RCF_TYPE_POLYPHASE_FARROW 1 #define EQ_ENABLE 1 #define MODULATION_TYPE MAP_MODE_QAM #define RCF_TYPE RCF_TYPE_POLYPHASE_FARROW #define MAX_NUMBITS_PERSYM 16 // --------------------------------------------------- enum eq_mode { eq_mode_disabled, eq_mode_cma, eq_mode_dfe }; enum cma_type { cma_type_cma = 0, cma_type_mma, cma_type_smma }; enum cma_mode { cma_mode_training_disabled = 0, cma_mode_training_enabled }; enum dfe_mode { dfe_mode_training_disabled = 0, dfe_mode_training_enabled }; enum agc_mode { agc_mode_disabled = 0, agc_mode_enabled }; enum agc_state { agc_state_acquisition = 0, agc_state_track }; enum cpr_mode { cpr_mode_disabled = 0, cpr_mode_enabled }; enum cpr_state { cpr_state_acquisition = 0, cpr_state_track }; enum str_mode { str_mode_disabled = 0, str_mode_enabled }; enum str_state { str_state_acquisition = 0, str_state_track }; typedef struct _minmax_t { radio_float_t min, max; } minmax_t; typedef struct _cpx_minmax_t { cpx_t min, max; radio_float_t magMin, magMax; radio_float_t phiAtMinI; radio_float_t phiAtMaxI; radio_float_t phiAtMinQ; radio_float_t phiAtMaxQ; } cpx_minmax_t; typedef struct _statistics_t { sl_var_t RF; sl_var_t I_DDC; sl_var_t Q_DDC; sl_var_t I_MF; sl_var_t Q_MF; sl_var_t I_CPR; sl_var_t Q_CPR; sl_var_t I_AGC; sl_var_t Q_AGC; sl_var_t I_EQ; sl_var_t Q_EQ; sl_var_t I_decision; sl_var_t Q_decision; sl_var_t MagDecision; sl_var_t PhiDecision; sl_var_t sym_err_mag; sl_var_t sym_err_phi; sl_var_t noise; sl_var_t noise_cma; sl_var_t noise_str; sl_var_t noise_cpr; sl_var_t noise_dfe_on; sl_var_t noise_dfe_off; sl_minmax_t sl_min_I; sl_minmax_t sl_max_I; sl_minmax_t sl_min_Q; sl_minmax_t sl_max_Q; sl_minmax_t sl_min_mag; sl_minmax_t sl_max_mag; cpx_minmax_t ddcMinMax; } statistics_t; typedef struct _params_t { uint32_t numBitsPerSymbol; radio_float_t symbolrate; radio_float_t samplerate; radio_float_t ddc_freq; radio_float_t CPR_phase; bool dfeAutoUpdateEnable; bool strAutoControlEnable; bool cprAutoControlEnable; bool agcAutoControlEnable; enum str_mode str_mode; enum cpr_mode cpr_mode; enum agc_mode agc_mode; enum eq_mode eq_mode; enum cma_type cmaType; enum cma_mode cmaMode; enum dfe_mode dfeMode; lead_lag_coeff_t str_loopfilter_coeff[2]; uint32_t str_loopfilter_coeff_index; lead_lag_coeff_t cpr_loopfilter_coeff[2]; uint32_t cpr_loopfilter_coeff_index; radio_float_t eqMuCma; radio_float_t eqMuDfe; radio_float_t agcMu[2]; uint32_t agcMu_index; enum str_state strState; enum cpr_state cprState; enum agc_state agc_state; } params_t; typedef struct _status_t { uint32 numSymbolsReceived; frame_statistics_t frameStatRx; radio_float_t noiseStr; radio_float_t noiseCpr; radio_float_t EB_N0; radio_float_t powerRF_dB; radio_float_t powerDDC_dB; radio_float_t powerMF_dB; radio_float_t powerCPR_dB; radio_float_t powerAGC_dB; radio_float_t powerEQ_dB; radio_float_t powerDecison_dB; radio_float_t powerMagDecision_dB; radio_float_t powerPhiDecision_dB; radio_float_t snrCurrent_dB; radio_float_t snrCma_dB; radio_float_t snrDfeOn_dB; radio_float_t snrDfeOff_dB; radio_float_t snrSymbolMagnitude_dB; radio_float_t snrSymbolPhase_dB; radio_float_t deltaFrequencyCPR; radio_float_t deltaFrequencySTR; radio_float_t agcGain[2]; minmax_t rfMinMax; cpx_minmax_t ddcMinMax; } status_t; class Receiver; // --------------------------------------------------- class ReceiverInterface { public: ReceiverInterface() {} virtual ~ReceiverInterface() {} virtual void setSamplerate(radio_float_t samplerate_hz) = 0; virtual void setParams(const params_t ¶ms) = 0; virtual const params_t& getParams() = 0; virtual const status_t& getStatus() = 0; virtual cpx_t getTracker(uint32 index) = 0; virtual void reset() = 0; virtual void statisticsReset() = 0; virtual void strReset() = 0; virtual void cprReset() = 0; virtual void cmaReset() = 0; virtual void dfeReset() = 0; virtual void dfeOffUpdateFromCma() = 0; virtual void dfeOnUpdateFromDfeOff() = 0; virtual const CVec& getWeightsCMA() = 0; virtual const CVec& getWeightsDFE() = 0; }; class ReceiverStatusListener { public: ReceiverStatusListener() {} virtual ~ReceiverStatusListener() {} virtual void receiverStatusChanged(ReceiverInterface *pReceiver) = 0; }; class ReceiverDataListener { public: ReceiverDataListener() {} virtual ~ReceiverDataListener() {} virtual void receiverDataChanged(Receiver *pObj) = 0; }; // Symbol timing recovery class TimingGeneratorGardner : public Interpolation::TimingGenerator { // Loop-Filter lead_lag_filter_t *filter; lead_lag_coeff_t *coeff; // Gardner Symbol Timing Recovery str_t m_SymbolTimingRevovery; bool is_time; radio_float_t m_omega; public: TimingGeneratorGardner() : Interpolation::TimingGenerator() , filter(nullptr) , coeff(nullptr) { STRGardnerInit(&m_SymbolTimingRevovery); is_time = true; } virtual ~TimingGeneratorGardner() = default; void reset() { LeadLagInit(filter, 0.00); } void loopFilterSetup(lead_lag_filter_t *pFilter, lead_lag_coeff_t *pCoeff) { filter = pFilter; coeff = pCoeff; } bool process(ComplexScalar const &iq) { // @2 x symbolrate // Symbol timing recovery radio_float_t vd = STRGardnerProcess(&m_SymbolTimingRevovery, toCpx(iq)); if (is_time) { // @1 x symbolrate m_omega = LeadLagProcess(filter, coeff, vd); } is_time = not is_time; update(m_omega); return not is_time; } }; class Receiver : public ReceiverInterface, public IDeFormatter, public Timer { public: Receiver(LogHandler *pLogHandler); ~Receiver(void); void init(); void free(); void processBaseband(radio_float_t *pI, radio_float_t *pQ, uint32_t len); void processPassband(RVec const &rf, uint32_t len); void setBufSize(uint32 size); uint32 getNumSoftSym(); sym_err_t getSoftSym(uint32 index); sym_err_t* getSoftSyms(); void initDefaultParams(); void addStatusListener(ReceiverStatusListener *pListener); void addDataListener(ReceiverDataListener *pListener); private: ListenerList m_statusListeners; LogComponent m_log; ReceiverDataListener *m_pDataListener; CriticalSection m_lock; cpx_t *m_pPassbandBuffer; cpx_t *m_pBasebandBuffer; CVec m_passbandBuffer; CVec m_basebandBuffer; sym_err_t *m_pSymbolBuffer; uint32_t m_numSymsInBuffer; uint32_t m_bufsize; bool m_ReceiverEnable; sample_clock_t m_symClock; pfd_t m_pfdCpr; // Filter Interpolation::DownSampler m_firArmDown; // Gardner Symbol Timing Recovery TimingGeneratorGardner m_timingGenerator; // Interpolators Interpolation::PolyPhase m_polyPhase; Interpolation::Farrow m_farrow; // NCOs Nco m_nco_ddc, m_nco_cpr; radio_float_t m_dOmega_vco; // Loop-Filter lead_lag_filter_t m_loop_filter_str; lead_lag_filter_t m_loop_filter_cpr; // AGC // Blind agc_t agcBlind; // Equalizer // Decision directed EQ Equalizer::Dfe m_dfe_on2; Equalizer::Dfe m_dfe_off2; cpx_t m_dfe_e_cpx; // Blind EQ Equalizer::Cma m_cma2; // Symbol demapper sym_map_t *m_pSymMapper; // Staticstics sym_stat_t m_sym_stat; statistics_t m_statistics; // Metrics Metrics::Tracker m_tracker; FrameReceiver m_frameReceiver; params_t m_params; // Processor Buffers Processor::Buffer m_buffer_agc; Processor::Buffer m_buffer_ip; void timerCallback(); void processBaseband(CVec const &iq, uint32_t len); void minMaxInit(minmax_t *pObj, radio_float_t min_initial, radio_float_t max_initial) { pObj->min = min_initial; pObj->max = max_initial; } void minMaxInit(cpx_minmax_t *pObj, cpx_t min_initial, cpx_t max_initial) { pObj->min = min_initial; pObj->max = max_initial; pObj->magMin = 1000; pObj->magMax = -1000; } void minMaxProcess(minmax_t *pObj, radio_float_t x) { pObj->min = dmin(pObj->min, x); pObj->max = dmax(pObj->max, x); } void minMaxProcess(cpx_minmax_t *pObj, cpx_t x) { if (CpxMagS(x) >= pObj->magMax) { if (x.real > 0 && x.imag > 0) pObj->phiAtMaxI = CpxPhiS(x); if (x.real > 0 && x.imag < 0) pObj->phiAtMaxQ = CpxPhiS(x); if (x.real < 0 && x.imag < 0) pObj->phiAtMinQ = CpxPhiS(x); if (x.real < 0 && x.imag > 0) pObj->phiAtMinI = CpxPhiS(x); } pObj->min.real = SlidingMinMaxProcess(&m_statistics.sl_min_I, x.real); pObj->max.real = SlidingMinMaxProcess(&m_statistics.sl_max_I, x.real); pObj->min.imag = SlidingMinMaxProcess(&m_statistics.sl_min_Q, x.imag); pObj->max.imag = SlidingMinMaxProcess(&m_statistics.sl_max_Q, x.imag); pObj->magMin = SlidingMinMaxProcess(&m_statistics.sl_min_mag, CpxMagS(x)); pObj->magMax = SlidingMinMaxProcess(&m_statistics.sl_max_mag, CpxMagS(x)); } void initFilterArm(); void initFilterRcf(); void initSymbolMapper(); void initSTR(); void initCPR(); void initDDC(); // Interface void setSamplerate(radio_float_t samplerate_hz) override; void setParams(const params_t ¶ms) override; params_t& getParams() override; status_t& getStatus() override; void reset() override; void strReset() override; void cprReset() override; void dfeReset() override; void cmaReset() override; void statisticsReset() override; void dfeOffUpdateFromCma() override; void dfeOnUpdateFromDfeOff() override; cpx_t getTracker(uint32 index) override; void onData(void *pData, uint32_t size) override { // Received raw data (void)pData; (void)size; } const CVec& getWeightsCMA() override { return m_cma2.getWeights(); } const CVec& getWeightsDFE() override { return m_dfe_off2.getWeights(); } trace_t m_trace; }; #endif // _RECEIVER_H_