- Use C++ Equalizer DFE and CMA
git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@91 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
+15
-15
@@ -122,8 +122,6 @@ void GraphComponent::mouseDown (const MouseEvent& e)
|
|||||||
void GraphComponent::receiverStatusChanged(ReceiverInterface *pReceiver)
|
void GraphComponent::receiverStatusChanged(ReceiverInterface *pReceiver)
|
||||||
{
|
{
|
||||||
uint32_t i, j;
|
uint32_t i, j;
|
||||||
uint32_t N;
|
|
||||||
const cpx_t *pW;
|
|
||||||
|
|
||||||
float minX = 1000;
|
float minX = 1000;
|
||||||
float maxX = -1000;
|
float maxX = -1000;
|
||||||
@@ -131,12 +129,12 @@ void GraphComponent::receiverStatusChanged(ReceiverInterface *pReceiver)
|
|||||||
float maxY = -1000;
|
float maxY = -1000;
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
N = pReceiver->getNumWeightsCMA();
|
{
|
||||||
pW = pReceiver->getWeightsCMA();
|
const CVec &w = pReceiver->getWeightsCMA();
|
||||||
for (i=0; i < N; i++)
|
for (i=0; i < w.size(); i++)
|
||||||
{
|
{
|
||||||
m_pCurves[j].m_pPointArray[i].x = (float)i;
|
m_pCurves[j].m_pPointArray[i].x = (float)i;
|
||||||
m_pCurves[j].m_pPointArray[i].y = CpxMagS(pW[i]);
|
m_pCurves[j].m_pPointArray[i].y = abs(w(i));
|
||||||
|
|
||||||
if (m_pCurves[j].m_pPointArray[i].y < minY)
|
if (m_pCurves[j].m_pPointArray[i].y < minY)
|
||||||
{
|
{
|
||||||
@@ -147,16 +145,17 @@ void GraphComponent::receiverStatusChanged(ReceiverInterface *pReceiver)
|
|||||||
maxY = m_pCurves[j].m_pPointArray[i].y;
|
maxY = m_pCurves[j].m_pPointArray[i].y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_pCurves[j].m_numPoints = N;
|
m_pCurves[j].m_numPoints = w.size();
|
||||||
maxX = (float)(N-1);
|
maxX = (float)(w.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
j = 1;
|
j = 1;
|
||||||
N = pReceiver->getNumWeightsDFE();
|
{
|
||||||
pW = pReceiver->getWeightsDFE();
|
const CVec &w = pReceiver->getWeightsDFE();
|
||||||
for (i=0; i < N; i++)
|
for (i=0; i < w.size(); i++)
|
||||||
{
|
{
|
||||||
m_pCurves[j].m_pPointArray[i].x = (float)i;
|
m_pCurves[j].m_pPointArray[i].x = (float)i;
|
||||||
m_pCurves[j].m_pPointArray[i].y = CpxMagS(pW[i]);
|
m_pCurves[j].m_pPointArray[i].y = abs(w(i));
|
||||||
|
|
||||||
if (m_pCurves[j].m_pPointArray[i].y < minY)
|
if (m_pCurves[j].m_pPointArray[i].y < minY)
|
||||||
{
|
{
|
||||||
@@ -167,14 +166,15 @@ void GraphComponent::receiverStatusChanged(ReceiverInterface *pReceiver)
|
|||||||
maxY = m_pCurves[j].m_pPointArray[i].y;
|
maxY = m_pCurves[j].m_pPointArray[i].y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_pCurves[j].m_numPoints = N;
|
m_pCurves[j].m_numPoints = w.size();
|
||||||
|
|
||||||
minY = 0;
|
minY = 0;
|
||||||
minX = 0;
|
minX = 0;
|
||||||
maxY = ceil(maxY);
|
maxY = ceil(maxY);
|
||||||
if (N > maxX)
|
if (w.size() > maxX)
|
||||||
{
|
{
|
||||||
maxX = (float)(N-1);
|
maxX = (float)(w.size()-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setGraphBounds(minX, maxX, minY, maxY);
|
setGraphBounds(minX, maxX, minY, maxY);
|
||||||
|
|||||||
+55
-53
@@ -55,6 +55,7 @@ Receiver::Receiver(LogHandler *pLogHandler)
|
|||||||
, m_pPolyphaseInterpolator(0)
|
, m_pPolyphaseInterpolator(0)
|
||||||
, m_pLagrangeInterpolator(0)
|
, m_pLagrangeInterpolator(0)
|
||||||
, m_pFarrowInterpolator(0)
|
, m_pFarrowInterpolator(0)
|
||||||
|
|
||||||
{
|
{
|
||||||
m_stateArm_I = nullptr;
|
m_stateArm_I = nullptr;
|
||||||
m_stateArm_Q = nullptr;
|
m_stateArm_Q = nullptr;
|
||||||
@@ -165,10 +166,10 @@ void Receiver::initDefaultParams()
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
void UpdateWeigths(ComplexVector &x, ComplexVector &e, ComplexVector &w, ComplexVector &w_conj, radio_float_t mu)
|
void UpdateWeigths(CVec &x, CVec &e, CVec &w, CVec &w_conj, radio_float_t mu)
|
||||||
{
|
{
|
||||||
|
|
||||||
e *= ComplexVector(mu, 0);
|
e *= CVec(mu, 0);
|
||||||
e.print("e * mu");
|
e.print("e * mu");
|
||||||
|
|
||||||
w += x * e.conj();
|
w += x * e.conj();
|
||||||
@@ -219,9 +220,10 @@ void Receiver::init()
|
|||||||
AGC_Init(&agcBlind, EQ_UPD_INTERVAL, AGC_INITIAL_VALUE);
|
AGC_Init(&agcBlind, EQ_UPD_INTERVAL, AGC_INITIAL_VALUE);
|
||||||
|
|
||||||
// Channel estimation filter
|
// Channel estimation filter
|
||||||
DFEComplexInit(&m_dfe_off, EQ_DFE_K);
|
m_cma2.init(2*EQ_DFE_K+1);
|
||||||
DFEComplexInit(&m_dfe_on, EQ_DFE_K);
|
m_dfe_off2.init(EQ_DFE_K);
|
||||||
CMAInit(&m_cma, 2*EQ_DFE_K+1);
|
m_dfe_on2.init(EQ_DFE_K);
|
||||||
|
|
||||||
m_dfe_e_cpx.real = m_dfe_e_cpx.imag = 0.f;
|
m_dfe_e_cpx.real = m_dfe_e_cpx.imag = 0.f;
|
||||||
|
|
||||||
cmaReset();
|
cmaReset();
|
||||||
@@ -372,20 +374,20 @@ void Receiver::init()
|
|||||||
//---------------------------
|
//---------------------------
|
||||||
// ComplexVector
|
// ComplexVector
|
||||||
//---------------------------
|
//---------------------------
|
||||||
ComplexVector cv1(4);
|
CVec cv1(4);
|
||||||
ComplexVector cv2(4);
|
CVec cv2(4);
|
||||||
ComplexVector cv3(4);
|
CVec cv3(4);
|
||||||
|
|
||||||
cv1.at(0) = ComplexVector(1,2);
|
cv1.at(0) = CVec(1,2);
|
||||||
cv1.at(1) = ComplexVector(3,4);
|
cv1.at(1) = CVec(3,4);
|
||||||
cv1.at(2) = ComplexVector(5,6);
|
cv1.at(2) = CVec(5,6);
|
||||||
cv1.at(3) = ComplexVector(7,8);
|
cv1.at(3) = CVec(7,8);
|
||||||
cv2.at(0) = ComplexVector(11,12);
|
cv2.at(0) = CVec(11,12);
|
||||||
cv2.at(1) = ComplexVector(13,14);
|
cv2.at(1) = CVec(13,14);
|
||||||
cv2.at(2) = ComplexVector(15,16);
|
cv2.at(2) = CVec(15,16);
|
||||||
cv2.at(3) = ComplexVector(17,18);
|
cv2.at(3) = CVec(17,18);
|
||||||
|
|
||||||
const ComplexVector &c = -cv1;
|
const CVec &c = -cv1;
|
||||||
cv3 = c;
|
cv3 = c;
|
||||||
|
|
||||||
//---------------------------
|
//---------------------------
|
||||||
@@ -711,18 +713,18 @@ void Receiver::init()
|
|||||||
//---------------------------
|
//---------------------------
|
||||||
// Test
|
// Test
|
||||||
//---------------------------
|
//---------------------------
|
||||||
ComplexVector w(32);
|
CVec w(32);
|
||||||
ComplexVector w_conj(32);
|
CVec w_conj(32);
|
||||||
ComplexVector e(32);
|
CVec e(32);
|
||||||
ComplexVector x(32);
|
CVec x(32);
|
||||||
|
|
||||||
w = ComplexVector(1, 1);
|
w = CVec(1, 1);
|
||||||
w_conj = ComplexVector(0.f, 0.f);
|
w_conj = CVec(0.f, 0.f);
|
||||||
e = ComplexVector (0.5f, 0.4f);
|
e = CVec (0.5f, 0.4f);
|
||||||
x = ComplexVector(2.f, 2.f);
|
x = CVec(2.f, 2.f);
|
||||||
x *= ComplexVector(10.f, 0);
|
x *= CVec(10.f, 0);
|
||||||
x += ComplexVector(0.5f, 0);
|
x += CVec(0.5f, 0);
|
||||||
x -= ComplexVector(5.f, 0);
|
x -= CVec(5.f, 0);
|
||||||
x += w + w_conj;
|
x += w + w_conj;
|
||||||
|
|
||||||
w.print("w");
|
w.print("w");
|
||||||
@@ -733,14 +735,14 @@ void Receiver::init()
|
|||||||
//---------------------------
|
//---------------------------
|
||||||
// RealVector
|
// RealVector
|
||||||
//---------------------------
|
//---------------------------
|
||||||
RealVector rv1(4, 0);
|
RVec rv1(4, 0);
|
||||||
RealVector rv2(4, 0);
|
RVec rv2(4, 0);
|
||||||
RealVector rv3(4, 0);
|
RVec rv3(4, 0);
|
||||||
|
|
||||||
rv1 = 10.f;
|
rv1 = 10.f;
|
||||||
rv2 = 20.f;
|
rv2 = 20.f;
|
||||||
|
|
||||||
const RealVector &r = -rv1;
|
const RVec &r = -rv1;
|
||||||
rv3 = r;
|
rv3 = r;
|
||||||
rv3 = -rv1;
|
rv3 = -rv1;
|
||||||
rv3 = -rv1 * rv2 * rv2;
|
rv3 = -rv1 * rv2 * rv2;
|
||||||
@@ -947,11 +949,6 @@ void Receiver::free()
|
|||||||
// AGC
|
// AGC
|
||||||
AGC_Free(&agcBlind);
|
AGC_Free(&agcBlind);
|
||||||
|
|
||||||
// Channel estimation filter
|
|
||||||
DFEComplexFree(&m_dfe_off);
|
|
||||||
DFEComplexFree(&m_dfe_on);
|
|
||||||
CMAFree(&m_cma);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Receiver Controller
|
// The Receiver Controller
|
||||||
@@ -1160,8 +1157,11 @@ void Receiver::processBaseband(cpx_t *pIF, uint32_t len)
|
|||||||
// Equalizer Process samples
|
// Equalizer Process samples
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
SlidingVarGet(&m_statistics.I_CPR);
|
SlidingVarGet(&m_statistics.I_CPR);
|
||||||
IQ_cma = CMAProcess(&m_cma, IQ_cpr);
|
ComplexScalar __IQ_cma = m_cma2.process(toComplexScalar(IQ_cpr));
|
||||||
IQ_dfeOn = DFEComplexProcess(&m_dfe_on, IQ_cpr, IQ_hard_last);
|
IQ_cma = toCpx(__IQ_cma);
|
||||||
|
|
||||||
|
ComplexScalar __IQ_dfeOn = m_dfe_on2.process(toComplexScalar(IQ_cpr), toComplexScalar(IQ_hard_last));
|
||||||
|
IQ_dfeOn = toCpx(__IQ_dfeOn);
|
||||||
|
|
||||||
IQ_eq = IQ_cpr;
|
IQ_eq = IQ_cpr;
|
||||||
if (m_params.eq_mode == eq_mode_cma)
|
if (m_params.eq_mode == eq_mode_cma)
|
||||||
@@ -1206,32 +1206,34 @@ void Receiver::processBaseband(cpx_t *pIF, uint32_t len)
|
|||||||
if (m_params.cmaType == cma_type_cma)
|
if (m_params.cmaType == cma_type_cma)
|
||||||
{
|
{
|
||||||
// CMA: Train
|
// CMA: Train
|
||||||
CMATrainGodard(&m_cma, IQ_cma, CpxMagS(sym_cma.rect), m_pSymMapper->R2_cma, m_params.eqMuCma);
|
m_cma2.trainGodard(__IQ_cma, CpxMagS(sym_cma.rect), m_pSymMapper->R2_cma, m_params.eqMuCma);
|
||||||
}
|
}
|
||||||
if (m_params.cmaType == cma_type_mma)
|
if (m_params.cmaType == cma_type_mma)
|
||||||
{
|
{
|
||||||
// MMA: Train
|
// MMA: Train
|
||||||
MMATrain(&m_cma, IQ_cma, m_pSymMapper->R_mma, m_params.eqMuCma);
|
m_cma2.trainMma(__IQ_cma, toComplexScalar(m_pSymMapper->R_mma), m_params.eqMuCma);
|
||||||
}
|
}
|
||||||
if (m_params.cmaType == cma_type_smma)
|
if (m_params.cmaType == cma_type_smma)
|
||||||
{
|
{
|
||||||
// S-MMA: Train
|
// S-MMA: Train
|
||||||
SMMATrain(&m_cma, IQ_cma, CpxMagS(sym_cma.rect), m_pSymMapper->R_smma, m_params.eqMuCma);
|
m_cma2.trainSmma(__IQ_cma, CpxMagS(sym_cma.rect), toComplexScalar(m_pSymMapper->R_smma), m_params.eqMuCma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_params.dfeMode == dfe_mode_training_enabled)
|
if (m_params.dfeMode == dfe_mode_training_enabled)
|
||||||
{
|
{
|
||||||
// DFE: LMS Update coefficients
|
// DFE: LMS Update coefficients
|
||||||
DFEAdaptLMS(&m_dfe_off, m_dfe_e_cpx, m_params.eqMuDfe); // last dfe_e_cpx
|
m_dfe_off2.train(toComplexScalar(m_dfe_e_cpx), m_params.eqMuDfe);
|
||||||
|
|
||||||
// DFE: Calc offline response
|
// DFE: Calc offline response
|
||||||
IQ_dfeOff = DFEComplexProcess(&m_dfe_off, IQ_cpr, sym_dfe_off.rect);
|
ComplexScalar __IQ_dfeOff = m_dfe_off2.process(toComplexScalar(IQ_cpr), toComplexScalar(sym_dfe_off.rect));
|
||||||
|
IQ_dfeOff = toCpx(__IQ_dfeOff);
|
||||||
|
|
||||||
sym_dfe_off = SymMapGetSymbolInfo(m_pSymMapper, SymMapDemap(m_pSymMapper, IQ_soft));
|
sym_dfe_off = SymMapGetSymbolInfo(m_pSymMapper, SymMapDemap(m_pSymMapper, IQ_soft));
|
||||||
|
|
||||||
// DFE: Calculate current error
|
// DFE: Calculate current error
|
||||||
m_dfe_e_cpx = CpxSubS(sym_dfe_off.rect, IQ_dfeOff);
|
ComplexScalar __dfe_e_cpx = toComplexScalar(sym_dfe_off.rect) - __IQ_dfeOff;
|
||||||
|
m_dfe_e_cpx = toCpx(__dfe_e_cpx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate current error
|
// Calculate current error
|
||||||
@@ -1576,6 +1578,9 @@ status_t& Receiver::getStatus()
|
|||||||
radio_float_t powerSoft_dB;
|
radio_float_t powerSoft_dB;
|
||||||
radio_float_t powerHard_dB;
|
radio_float_t powerHard_dB;
|
||||||
|
|
||||||
|
if (!m_pSymMapper)
|
||||||
|
return status;
|
||||||
|
|
||||||
status.frameStatRx = m_frameReceiver.getStats();
|
status.frameStatRx = m_frameReceiver.getStats();
|
||||||
status.numSymbolsReceived = m_sym_stat.sym_cnt;
|
status.numSymbolsReceived = m_sym_stat.sym_cnt;
|
||||||
status.noiseStr = powerDB(SlidingVarGet(&m_statistics.noise_str), 1.0f);
|
status.noiseStr = powerDB(SlidingVarGet(&m_statistics.noise_str), 1.0f);
|
||||||
@@ -1639,28 +1644,25 @@ void Receiver::cprReset()
|
|||||||
|
|
||||||
void Receiver::dfeReset()
|
void Receiver::dfeReset()
|
||||||
{
|
{
|
||||||
CoeffComplexUnitAt(m_dfe_off.eq.pW, m_dfe_off.N, EQ_GROUP_DELAY);
|
m_dfe_on2.setUnit(EQ_GROUP_DELAY);
|
||||||
CoeffComplexUnitAt(m_dfe_on.eq.pW, m_dfe_on.N, EQ_GROUP_DELAY);
|
m_dfe_off2.setUnit(EQ_GROUP_DELAY);
|
||||||
CoeffComplexUnitAt(m_dfe_off.eq.pW_conj, m_dfe_off.N, EQ_GROUP_DELAY);
|
|
||||||
CoeffComplexUnitAt(m_dfe_on.eq.pW_conj, m_dfe_on.N, EQ_GROUP_DELAY);
|
|
||||||
m_statusListeners.call(&ReceiverStatusListener::receiverStatusChanged, this);
|
m_statusListeners.call(&ReceiverStatusListener::receiverStatusChanged, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Receiver::cmaReset()
|
void Receiver::cmaReset()
|
||||||
{
|
{
|
||||||
CoeffComplexUnitAt(m_cma.eq.pW, m_cma.N, EQ_GROUP_DELAY);
|
m_cma2.setUnit(EQ_GROUP_DELAY);
|
||||||
m_statusListeners.call(&ReceiverStatusListener::receiverStatusChanged, this);
|
m_statusListeners.call(&ReceiverStatusListener::receiverStatusChanged, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Receiver::dfeOffUpdateFromCma()
|
void Receiver::dfeOffUpdateFromCma()
|
||||||
{
|
{
|
||||||
memcpy(m_dfe_off.eq.pW, m_cma.eq.pW, m_cma.N*sizeof(cpx_t));
|
(Equalizer::AEqualizer &)m_dfe_off2 = (Equalizer::AEqualizer const &)m_cma2;
|
||||||
m_statusListeners.call(&ReceiverStatusListener::receiverStatusChanged, this);
|
m_statusListeners.call(&ReceiverStatusListener::receiverStatusChanged, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Receiver::dfeOnUpdateFromDfeOff()
|
void Receiver::dfeOnUpdateFromDfeOff()
|
||||||
{
|
{
|
||||||
memcpy(m_dfe_on.eq.pW, m_dfe_off.eq.pW, m_dfe_on.eq.N*sizeof(cpx_t));
|
m_dfe_on2 = m_dfe_off2;
|
||||||
memcpy(m_dfe_on.eq.pW_conj, m_dfe_off.eq.pW_conj, m_dfe_on.eq.N*sizeof(cpx_t));
|
|
||||||
m_statusListeners.call(&ReceiverStatusListener::receiverStatusChanged, this);
|
m_statusListeners.call(&ReceiverStatusListener::receiverStatusChanged, this);
|
||||||
}
|
}
|
||||||
|
|||||||
+16
-22
@@ -14,6 +14,11 @@
|
|||||||
#include "JuceHeader.h"
|
#include "JuceHeader.h"
|
||||||
#include "LogComponent.h"
|
#include "LogComponent.h"
|
||||||
|
|
||||||
|
#include <radio/FirComplex.hpp>
|
||||||
|
#include <radio/Equalizer.hpp>
|
||||||
|
|
||||||
|
using namespace Radio;
|
||||||
|
|
||||||
// ---------------------------------------------------
|
// ---------------------------------------------------
|
||||||
#define NUM_PASSBAND_SAMPLES_PER_SYM 4
|
#define NUM_PASSBAND_SAMPLES_PER_SYM 4
|
||||||
#define NUM_BASEBAND_SAMPLES_PER_SYM 2
|
#define NUM_BASEBAND_SAMPLES_PER_SYM 2
|
||||||
@@ -241,10 +246,8 @@ public:
|
|||||||
virtual void dfeReset() = 0;
|
virtual void dfeReset() = 0;
|
||||||
virtual void dfeOffUpdateFromCma() = 0;
|
virtual void dfeOffUpdateFromCma() = 0;
|
||||||
virtual void dfeOnUpdateFromDfeOff() = 0;
|
virtual void dfeOnUpdateFromDfeOff() = 0;
|
||||||
virtual const uint32_t getNumWeightsCMA() = 0;
|
virtual const CVec& getWeightsCMA() = 0;
|
||||||
virtual const cpx_t* getWeightsCMA() = 0;
|
virtual const CVec& getWeightsDFE() = 0;
|
||||||
virtual const uint32_t getNumWeightsDFE() = 0;
|
|
||||||
virtual const cpx_t* getWeightsDFE() = 0;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -334,12 +337,14 @@ private:
|
|||||||
|
|
||||||
// Equalizer
|
// Equalizer
|
||||||
// Decision directed EQ
|
// Decision directed EQ
|
||||||
dfe_cpx_t m_dfe_on;
|
Equalizer::Dfe m_dfe_on2;
|
||||||
dfe_cpx_t m_dfe_off;
|
Equalizer::Dfe m_dfe_off2;
|
||||||
|
|
||||||
cpx_t m_dfe_e_cpx;
|
cpx_t m_dfe_e_cpx;
|
||||||
|
|
||||||
// Blind EQ
|
// Blind EQ
|
||||||
cma_t m_cma;
|
Equalizer::Cma m_cma2;
|
||||||
|
|
||||||
|
|
||||||
// Symbol demapper
|
// Symbol demapper
|
||||||
sym_map_t *m_pSymMapper;
|
sym_map_t *m_pSymMapper;
|
||||||
@@ -423,27 +428,16 @@ private:
|
|||||||
(void)size;
|
(void)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t getNumWeightsCMA() override
|
const CVec& getWeightsCMA() override
|
||||||
{
|
{
|
||||||
return m_cma.eq.N;
|
return m_cma2.getWeights();
|
||||||
}
|
}
|
||||||
|
|
||||||
const cpx_t* getWeightsCMA() override
|
const CVec& getWeightsDFE() override
|
||||||
{
|
{
|
||||||
return m_cma.eq.pW;
|
return m_dfe_off2.getWeights();
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t getNumWeightsDFE() override
|
|
||||||
{
|
|
||||||
return m_dfe_off.eq.N;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cpx_t* getWeightsDFE() override
|
|
||||||
{
|
|
||||||
return m_dfe_off.eq.pW;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
trace_t m_trace;
|
trace_t m_trace;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user