Files
mpsk_rx_gui/Source/Receiver.hpp
T
2022-07-13 19:31:21 +02:00

457 lines
10 KiB
C++

#ifndef _RECEIVER_H_
#define _RECEIVER_H_
#include <cstdint>
#include <radio/symbol.h>
#include <radio/synchronization.h>
#include <radio/interpolation.h>
#include <radio/statistics.h>
#include <radio/agc.h>
#include <JuceHeader.h>
#include "LogComponent.h"
#include "FrameReceiver.hpp"
#include "TimingGeneratorGardner.hpp"
#include <cpp/radio/Vector.hpp>
#include <cpp/radio/FirComplex.hpp>
#include <cpp/radio/Equalizer.hpp>
#include <cpp/radio/interpolation/Farrow.hpp>
#include <cpp/radio/interpolation/DownSampler.hpp>
#include <cpp/radio/interpolation/PolyPhase.hpp>
#include <cpp/radio/metrics/Tracker.hpp>
#include <cpp/radio/Nco.hpp>
#include <noise/noise.h>
#ifdef _WINDOWS
#include <float.h>
#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;
radio_float_t awgn_dB;
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 &params) = 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 test() = 0;
virtual void statisticsReset() = 0;
virtual void agcReset() = 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;
};
class Receiver : public ReceiverInterface, public Timer
{
public:
Receiver(LogHandler *pLogHandler);
~Receiver(void);
void init();
void free();
void processBaseband(radio_float_t *pI, radio_float_t *pQ, size_t len);
void processPassband(RVec const &rf, size_t len);
void setBufSize(size_t size);
Processor::Buffer<sym_err_t>& getSoftSyms();
void initDefaultParams();
void addStatusListener(ReceiverStatusListener *pListener);
void addDataListener(ReceiverDataListener *pListener);
private:
ListenerList<ReceiverStatusListener> 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;
Processor::Buffer<sym_err_t> m_buf_symerr;
Processor::Buffer<symbol_t> m_buf_sym;
uint32_t m_bufsize;
bool m_ReceiverEnable;
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;
ComplexScalar m_dfe_off_e;
// 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<ComplexScalar> m_buffer_agc;
Processor::Buffer<ComplexScalar> m_buffer_ip;
// Noise
noise_gen_t m_noise;
// Slow timer
size_t m_slow_timer_counter;
void slowTimerCallback();
void timerCallback();
void processBaseband(CVec const &iq, size_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 &params) override;
params_t& getParams() override;
status_t& getStatus() override;
void reset() override;
void test() override;
void agcReset() 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;
const CVec& getWeightsCMA() override
{
return m_cma2.getWeights();
}
const CVec& getWeightsDFE() override
{
return m_dfe_off2.getWeights();
}
size_t m_is_slip;
bool is_slip()
{
bool result = m_is_slip;
if (m_is_slip)
{
m_is_slip--;
}
return result;
}
};
#endif // _RECEIVER_H_