Files
radio/old/radio.c.old
T
2022-07-08 14:39:31 +02:00

2661 lines
54 KiB
Plaintext
Executable File

// --------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include <fir/fir2.h>
#include <crc/crc.h>
#include "radio.h"
// --------------------------------------------------------------
// Real Functions
// --------------------------------------------------------------
radio_float_t dabs(radio_float_t x)
{
if (x < 0)
return -x;
return x;
}
radio_float_t dsign(radio_float_t x)
{
if (x < 0)
return -1.0;
return 1.0;
}
radio_float_t dmod(radio_float_t x, radio_float_t y)
{
int xy;
if (y == 0)
return x;
xy = (int)floor(x/y);
return dsign(y)*(radio_float_t)fabs(x - y*(radio_float_t)xy);
}
radio_float_t dmax(radio_float_t x, radio_float_t y)
{
if (x > y)
return x;
return y;
}
radio_float_t dmin(radio_float_t x, radio_float_t y)
{
if (x < y)
return x;
return y;
}
radio_float_t dclamp(radio_float_t x, radio_float_t limit_low, radio_float_t limit_high)
{
return dmin(dmax(x, limit_low), limit_high);
}
radio_float_t powerDB(radio_float_t v1, radio_float_t preScale)
{
return (radio_float_t)(10*log10(RADIO_POWER_EPS + v1*preScale));
}
float fsum(float *pSrc, int len)
{
float sum = 0;
while(len--)
sum += *(pSrc++);
return sum;
}
float fmean(float *pSrc, int len)
{
return fsum(pSrc, len)/len;
}
radio_float_t dsum(radio_float_t *pSrc, int len)
{
radio_float_t sum = 0;
while(len--)
sum += *(pSrc++);
return sum;
}
radio_float_t dmean(radio_float_t *pSrc, int len)
{
return dsum(pSrc, len)/len;
}
// --------------------------------------------------------------
// Complex Functions
// --------------------------------------------------------------
cpx_t CpxConjS(cpx_t v1)
{
register cpx_t temp;
temp.real = v1.real;
temp.imag = -v1.imag;
return temp;
}
cpx_t CpxAddS(cpx_t v1, cpx_t v2)
{
register cpx_t temp;
temp.real = v1.real + v2.real;
temp.imag = v1.imag + v2.imag;
return temp;
}
cpx_t CpxSubS(cpx_t v1, cpx_t v2)
{
register cpx_t temp;
temp.real = v1.real - v2.real;
temp.imag = v1.imag - v2.imag;
return temp;
}
cpx_t CpxMulS(cpx_t v1, cpx_t v2)
{
register cpx_t temp;
temp.real = v1.real*v2.real - v1.imag*v2.imag;
temp.imag = v1.real*v2.imag + v1.imag*v2.real;
return temp;
}
cpx_t CpxScaleRealS(cpx_t v1, radio_float_t v2)
{
register cpx_t temp;
temp.real = v1.real*v2;
temp.imag = v1.imag*v2;
return temp;
}
cpx_t CpxScaleComplexS(cpx_t x, cpx_t gain)
{
register cpx_t temp;
temp.real = x.real*gain.real;
temp.imag = x.imag*gain.imag;
return temp;
}
cpx_t CpxFromReal(radio_float_t v1)
{
cpx_t res = {v1, v1};
return res;
}
cpx_t Cpx(radio_float_t real, radio_float_t imag)
{
cpx_t res = {real, imag};
return res;
}
radio_float_t CpxMagS(cpx_t v1)
{
radio_float_t mag;
mag = (radio_float_t)sqrt(v1.real*v1.real + v1.imag*v1.imag);
return mag;
}
radio_float_t CpxPhiS(cpx_t v1)
{
return (radio_float_t)atan2(v1.real, v1.imag);
}
cpx_t CpxMinS(cpx_t x1, cpx_t x2)
{
return Cpx(dmin(x1.real, x2.real), dmin(x1.imag, x2.imag));
}
cpx_t CpxMaxS(cpx_t x1, cpx_t x2)
{
return Cpx(dmax(x1.real, x2.real), dmax(x1.imag, x2.imag));
}
radio_float_t cpxPowerDB(cpx_t v1, radio_float_t preScale)
{
return powerDB(CpxMagS(v1), preScale);
}
void CpxCopy(cpx_t *pSrc, cpx_t *pDst, uint32_t len)
{
memcpy(pDst, pSrc, len*sizeof(cpx_t));
}
void CpxConj(cpx_t *pSrcDst, uint32_t len)
{
uint32_t i;
for(i=0; i < len; i++)
pSrcDst[i] = CpxConjS(pSrcDst[i]);
}
void CpxAdd(cpx_t *pSrc, cpx_t *pSrcDst, uint32_t len)
{
uint32_t i;
for(i=0; i < len; i++)
pSrcDst[i] = CpxAddS(pSrc[i], pSrcDst[i]);
}
void CpxSub(cpx_t *pSrc, cpx_t *pSrcDst, uint32_t len)
{
uint32_t i;
for(i=0; i < len; i++)
pSrcDst[i] = CpxSubS(pSrc[i], pSrcDst[i]);
}
void CpxMul(cpx_t *pSrc, cpx_t *pSrcDst, uint32_t len)
{
uint32_t i;
for(i=0; i < len; i++)
pSrcDst[i] = CpxMulS(pSrc[i], pSrcDst[i]);
}
cpx_t csum(cpx_t *pSrc, int len)
{
cpx_t sum = {0};
while(len--)
{
sum.real += (*(pSrc)).real;
sum.imag += (*(pSrc++)).imag;
}
return sum;
}
cpx_t cmean(cpx_t *pSrc, int len)
{
cpx_t y;
y = csum(pSrc, len);
y.real /= len;
y.imag /= len;
return y;
}
// --------------------------------------------------------------
// NCO
// --------------------------------------------------------------
void NCO_Init(nco_t *pObj, radio_float_t omega, radio_float_t phi, uint32_t tbl_size)
{
uint32_t i;
radio_float_t dphi_tbl, phi_tbl;
pObj->dOmega = 0.0;
pObj->dPhi = 0.0;
pObj->omega = omega;
pObj->phi = phi;
pObj->tbl_index = 0;
pObj->tbl_size = tbl_size;
pObj->pTbl = NULL;
memset(&pObj->state,0,sizeof(cpx_t));
if (tbl_size > 0)
{
dphi_tbl = (radio_float_t)(2.0*PI/tbl_size);
pObj->pTbl = (cpx_t*)malloc(tbl_size*sizeof(cpx_t));
phi_tbl = 0;
for (i=0; i < tbl_size; i++)
{
pObj->pTbl[i].real = (radio_float_t)cos(phi_tbl);
pObj->pTbl[i].imag = (radio_float_t)sin(phi_tbl);
phi_tbl += dphi_tbl;
}
}
}
void NCO_Free(nco_t *pObj)
{
if (pObj->pTbl)
free(pObj->pTbl);
}
void NCO_ModPhi(nco_t *pObj, radio_float_t dPhi)
{
pObj->dPhi += dPhi;
pObj->phi += dPhi;
if (pObj->phi < -(radio_float_t)0.5) pObj->phi += (radio_float_t)1.0;
if (pObj->phi >= +(radio_float_t)0.5) pObj->phi -= (radio_float_t)1.0;
}
void NCO_ModOmega(nco_t *pObj, radio_float_t dOmega)
{
pObj->dOmega = dOmega;
}
radio_float_t NCO_GetOmega(nco_t *pObj)
{
return pObj->omega + pObj->dOmega;
}
void NCO_Process(nco_t *pObj)
{
uint32_t i;
pObj->phi += (pObj->omega + pObj->dOmega);
if (pObj->phi < -(radio_float_t)0.5) pObj->phi += (radio_float_t)1.0;
if (pObj->phi >= +(radio_float_t)0.5) pObj->phi -= (radio_float_t)1.0;
if (pObj->pTbl == NULL)
{
pObj->state.real = +(radio_float_t)cos(2.0*PI*pObj->phi);
pObj->state.imag = -(radio_float_t)sin(2.0*PI*pObj->phi);
}
else
{
i = (int)(0.5 + pObj->phi*pObj->tbl_size)%pObj->tbl_size;
pObj->state.real = +pObj->pTbl[i].real;
pObj->state.imag = -pObj->pTbl[i].imag;
}
}
// --------------------------------------------------------------
// Mixer
// Scalar version
// --------------------------------------------------------------
cpx_t NCO_MixComplexS(nco_t *pObj, cpx_t *pSrc, cpx_t gain)
{
return CpxMulS(pObj->state, CpxScaleComplexS(*pSrc, gain));
}
cpx_t NCO_MixRealS(nco_t *pObj, radio_float_t src, radio_float_t gain)
{
cpx_t dst;
dst.real = gain*src;
dst.imag = 0;
return CpxMulS(pObj->state, dst);
}
radio_float_t NCO_MixComplexRealS(nco_t *pObj, cpx_t *pSrc, cpx_t gain)
{
return gain.real*pSrc->real*pObj->state.real + gain.imag*pSrc->imag*pObj->state.imag;
}
// --------------------------------------------------------------
// Mixer
// Vector version
// --------------------------------------------------------------
void NCO_MixComplexV(nco_t *pObj, cpx_t *pSrc, cpx_t *pDst, cpx_t gain, uint32_t len)
{
while (len--)
{
*pDst++ = NCO_MixComplexS(pObj, pSrc++, gain);
// NCO update
NCO_Process(pObj);
}
}
void NCO_MixRealV(nco_t *pObj, radio_float_t *pSrc, cpx_t *pDst, radio_float_t gain, uint32_t len)
{
while (len--)
{
*pDst++ = NCO_MixRealS(pObj, *pSrc++, gain);
// NCO update
NCO_Process(pObj);
}
}
void NCO_MixComplexRealV(nco_t *pObj, cpx_t *pSrc, radio_float_t *pDst, cpx_t gain, uint32_t len)
{
while (len--)
{
*pDst++ = NCO_MixComplexRealS(pObj, pSrc++, gain);
// NCO update
NCO_Process(pObj);
}
}
// --------------------------------------------------------------
// Synchronization
// --------------------------------------------------------------
#if 0
void SamplerInit(sampler_t *pObj, int divide)
{
pObj->reload = divide;
pObj->count = divide -1;;
}
int SamplerIsSample(sampler_t *pObj)
{
return (pObj->count == 0);
}
void SamplerUpdate(sampler_t *pObj)
{
if (pObj->count == 0)
pObj->count = pObj->reload -1;
else
pObj->count--;
}
// --------------------------------------------------------------
// Phase detector for QPSK
// --------------------------------------------------------------
radio_float_t PhaseErrQPSK(cpx_t x)
{
radio_float_t perr;
perr = x.imag*dsign(x.real) - x.real*dsign(x.imag);
return perr;
}
radio_float_t PhaseErr(cpx_t x, radio_float_t pstep, radio_float_t poffset)
{
radio_float_t perr, phi, m;
phi = (radio_float_t)CpxPhiS(x) + poffset;
m = dmod(phi/(radio_float_t)PI,(radio_float_t)2.0/pstep);
perr = (radio_float_t)1.0/pstep - m;
return (radio_float_t)(PI*perr);
}
// --------------------------------------------------------------
// Clock generator
// --------------------------------------------------------------
void Clkgen_Init(clkgen_t *pObj)
{
pObj->lastPhi = 0;
}
int Clkgen_GetPulse(clkgen_t *pObj, nco_t *pNCO)
{
int pulse = 0;
radio_float_t tmp1, tmp2;
tmp1 = (radio_float_t)fmod(pNCO->phi, (radio_float_t)PI);
tmp2 = (radio_float_t)fmod(pObj->lastPhi, (radio_float_t)PI);
// if ((pObj->pNCO->phi <= 0) && (pObj->lastPhi > 0)/* && (pObj->pNCO->phi <= 0)*/)
// pulse = 1;
pulse = tmp1 < tmp2;
pObj->lastPhi = pNCO->phi;
return pulse;
}
void LeadLagInit(lead_lag_filter_t *pObj, radio_float_t lead_gain, radio_float_t lag_gain, radio_float_t ic_lag)
{
pObj->term_lag = ic_lag;
pObj->term_lead = 0;
pObj->gain_lag = lag_gain;
pObj->gain_lead = lead_gain;
};
void LeadLagSetGainLead(lead_lag_filter_t *pObj, radio_float_t gain)
{
pObj->gain_lead = gain;
}
void LeadLagSetGainLag(lead_lag_filter_t *pObj, radio_float_t gain)
{
pObj->gain_lag = gain;
}
radio_float_t LeadLagProcess(lead_lag_filter_t *pObj, radio_float_t x)
{
radio_float_t y;
pObj->term_lag += x * pObj->gain_lag;
pObj->term_lead = x * pObj->gain_lead;
y = pObj->term_lag + pObj->term_lead;
return y;
}
// --------------------------------------------------------------
// Gardner Timing Error Detector
// --------------------------------------------------------------
void STRGardnerInit(str_t *pObj)
{
memset(pObj->d, 0, sizeof(pObj->d));
}
radio_float_t STRGardnerProcess(str_t *pObj, cpx_t x)
{
radio_float_t Vd;
cpx_t t, *pD;
pD = pObj->d;
t.real = (pD[1].real - x.real) * pD[0].real;
t.imag = (pD[1].imag - x.imag) * pD[0].imag;
Vd = (t.real + t.imag);
// Adjust delay line
pD[1] = pD[0];
pD[0] = x;
return Vd;
}
#endif
// --------------------------------------------------------------
// Sliding Statistics
// --------------------------------------------------------------
void SlidingMeanInit(sl_mean_t *pObj, int N)
{
RBufInit(&pObj->buf, N);
pObj->Nr = (radio_float_t)1.0/N;
pObj->mean = 0.0;
pObj->sum = 0.0;
pObj->normalize_count = N;
}
void SlidingMeanFree(sl_mean_t *pObj)
{
RBufFree(&pObj->buf);
}
radio_float_t SlidingMeanProcess(sl_mean_t *pObj, radio_float_t x)
{
uint32_t i;
radio_float_t last;
last = RBufGetAfter(&pObj->buf, pObj->buf.size-1);
RBufPut(&pObj->buf, x);
pObj->sum += (x - last);
pObj->mean = pObj->sum*pObj->Nr;
if (--pObj->normalize_count == 0)
{
pObj->normalize_count = pObj->buf.size;
pObj->sum = 0;
for (i=0; i < pObj->buf.size; i++)
{
pObj->sum += pObj->buf.pData[i];
}
}
return pObj->mean;
}
void SlidingMeanProcessV(sl_mean_t *pObj, radio_float_t *pX, uint32_t len)
{
uint32_t i;
for (i=0; i < len; i++)
SlidingMeanProcess(pObj, *(pX++));
}
radio_float_t SlidingMeanGet(sl_mean_t *pObj)
{
return pObj->mean;
}
void SlidingVarInit(sl_var_t *pObj, int Npwr, int Nmean)
{
RBufInit(&pObj->buf, Npwr);
SlidingMeanInit(&pObj->sl_mean, Nmean);
pObj->Nr = (radio_float_t)1.0/Npwr;
pObj->var = 0.0;
pObj->sum = 0.0;
pObj->normalize_count = Npwr;
}
void SlidingVarFree(sl_var_t *pObj)
{
RBufFree(&pObj->buf);
SlidingMeanFree(&pObj->sl_mean);
}
radio_float_t SlidingVarProcess(sl_var_t *pObj, radio_float_t x)
{
uint32_t i;
radio_float_t last, xm, mean, var;
last = RBufGetAfter(&pObj->buf, pObj->buf.size-1);
mean = SlidingMeanProcess(&pObj->sl_mean, x);
xm = x - mean;
xm *= xm;
RBufPut(&pObj->buf, xm);
pObj->sum += (xm - last);
var = pObj->sum*pObj->Nr;
if (var >= 0)
pObj->var = var;
if (--pObj->normalize_count == 0)
{
pObj->normalize_count = pObj->buf.size;
pObj->sum = 0;
for (i=0; i < pObj->buf.size; i++)
{
pObj->sum += pObj->buf.pData[i];
}
}
return pObj->var;
}
void SlidingVarProcessV(sl_var_t *pObj, radio_float_t *pX, uint32_t len)
{
uint32_t i;
for (i=0; i < len; i++)
SlidingVarProcess(pObj, *(pX++));
}
radio_float_t SlidingVarGet(sl_var_t *pObj)
{
return pObj->var;
}
radio_float_t SlidingVarGetPowerDB(sl_var_t *pObj, radio_float_t preScale)
{
return powerDB(pObj->var, preScale);
}
void SlidingMinMaxInit(sl_minmax_t *pObj, uint32_t L, radio_float_t P, radio_float_t mode)
{
pObj->L = L;
pObj->P = P;
pObj->N = 0;
pObj->max = 0;
pObj->mode = mode;
pObj->pP = (uint32_t*)malloc(L*sizeof(uint32_t));
pObj->pU = (radio_float_t*)malloc(L*sizeof(radio_float_t));
pObj->pP_last = (uint32_t*)malloc(L*sizeof(uint32_t));
pObj->pU_last = (radio_float_t*)malloc(L*sizeof(radio_float_t));
memset(pObj->pP, 0, L*sizeof(uint32_t));
memset(pObj->pU, 0, L*sizeof(radio_float_t));
memset(pObj->pP_last, 0, L*sizeof(uint32_t));
memset(pObj->pU_last, 0, L*sizeof(radio_float_t));
pObj->pU_last[1] = P;
}
void SlidingMinMaxFree(sl_minmax_t *pObj)
{
if (pObj->pP)
free(pObj->pP);
if (pObj->pU)
free(pObj->pU);
if (pObj->pP_last)
free(pObj->pP_last);
if (pObj->pU_last)
free(pObj->pU_last);
pObj->pP = (uint32_t*)0;
pObj->pU = (radio_float_t*)0;
pObj->pP_last = (uint32_t*)0;
pObj->pU_last = (radio_float_t*)0;
}
// Sliding Min/Max based on MAXLIST-Algorithm
// "AN EFFICIENT ALGORITHM FOR RUNNING MAX MIN CALCULATION", 1996, S.C. Douglas, University of Utah
// Dependeding on 'mode' this algorithm calculates either minimum (mode = -1) or maximum (mode = +1)
radio_float_t SlidingMinMaxProcess(sl_minmax_t *pObj, radio_float_t x)
{
uint32_t m;
uint32_t i;
uint32_t j;
x *= pObj->mode;
m = 1;
if (pObj->pP_last[pObj->N] == pObj->L)
{
m = 0;
pObj->pU_last[pObj->N] = pObj->P;
}
i = 0;
while (x >= pObj->pU_last[i+1])
{
i++;
}
pObj->N = pObj->N - i + m;
for (j=1; j < pObj->N; j++)
{
pObj->pU[j+1] = pObj->pU_last[j+i];
pObj->pP[j+1] = pObj->pP_last[j+i] + 1;
}
pObj->pU[pObj->N+1] = pObj->P;
pObj->pU[1] = x;
pObj->pP[1] = 1;
pObj->max = pObj->pU[pObj->N];
i=0;
while(pObj->pU[i] != pObj->P)
{
pObj->pU_last[i] = pObj->pU[i];
pObj->pP_last[i] = pObj->pP[i];
i++;
}
pObj->pU_last[i] = pObj->pU[i];
pObj->pP_last[i] = pObj->pP[i];
return pObj->mode*pObj->max;
}
radio_float_t SlidingMinMaxGet(sl_minmax_t *pObj)
{
return pObj->mode*pObj->max;
}
void SlidingMinMaxProcessV(sl_minmax_t *pObj, radio_float_t *pX, uint32_t len)
{
uint32_t i;
for (i=0; i < len; i++)
{
SlidingMinMaxProcess(pObj, pX[i]);
}
}
// --------------------------------------------------------------
// RingBuffer and Fifo
// --------------------------------------------------------------
void RBufInit(rbuf_t *pObj, int size)
{
pObj->ir = 0;
pObj->iw = 0;
pObj->dist = 0;
pObj->size = size;
pObj->pData = (radio_float_t*)malloc(size*sizeof(radio_float_t));
memset(pObj->pData, 0, size*sizeof(radio_float_t));
}
void RBufFree(rbuf_t *pObj)
{
if (pObj->pData)
free(pObj->pData);
pObj->pData = NULL;
pObj->size = 0;
}
void RBufPut(rbuf_t *pObj, radio_float_t x)
{
(pObj->iw)++;
if (pObj->iw >= pObj->size)
pObj->iw = 0;
pObj->pData[pObj->iw] = x;
pObj->dist++;
}
radio_float_t RBufGet(rbuf_t *pObj)
{
radio_float_t y;
y = pObj->pData[(pObj->ir)++];
if (pObj->ir >= pObj->size)
pObj->ir = 0;
pObj->dist--;
return y;
}
radio_float_t RBufGetAfter(rbuf_t *pObj, int delay)
{
pObj->ir = (pObj->iw-delay)%pObj->size;
if (pObj->ir < 0)
pObj->ir += pObj->size;
pObj->dist = delay;
return pObj->pData[pObj->ir];
}
radio_float_t RBufGetAt(rbuf_t *pObj, int index)
{
if (index < 0)
index = 0;
pObj->ir = (index)%pObj->size;
pObj->dist = pObj->iw-pObj->ir;
if (pObj->dist < 0)
pObj->dist += pObj->size;
return pObj->pData[pObj->ir];
}
void FifoInit(fifo_t *pObj, uint32_t max_size)
{
pObj->size_max = max_size;
pObj->size = 0;
pObj->iw = (uint32_t)0;
pObj->ir = (uint32_t)0;
pObj->pData = (uint32_t*)malloc(max_size*sizeof(uint32_t));
memset(pObj->pData, 0, max_size*sizeof(uint32_t));
}
void FifoFree(fifo_t *pObj)
{
if (pObj->pData)
free(pObj->pData);
pObj->pData = NULL;
pObj->size_max = 0;
pObj->size = 0;
}
uint32_t FifoSize(fifo_t *pObj)
{
return pObj->size;
}
uint32_t FifoSizeMax(fifo_t *pObj)
{
return pObj->size_max;
}
uint32_t FifoFront(fifo_t *pObj)
{
return pObj->pData[pObj->ir];
}
uint32_t FifoBack(fifo_t *pObj)
{
return pObj->pData[pObj->iw];
}
void FifoPushBack(fifo_t *pObj, uint32_t item)
{
pObj->pData[pObj->iw++] = item;
if (pObj->iw >= pObj->size_max)
pObj->iw = 0;
if (pObj->size < pObj->size_max)
{
pObj->size++;
}
else
{
if (++pObj->ir >= pObj->size_max)
pObj->ir = 0;
}
}
void FifoPushFront(fifo_t *pObj, uint32_t item)
{
pObj->ir--;
if (pObj->ir >= pObj->size_max)
pObj->ir = 0;
pObj->pData[pObj->ir] = item;
if (pObj->size < pObj->size_max)
{
pObj->size++;
}
else
{
if (--pObj->iw >= pObj->size_max)
pObj->iw = 0;
}
}
void FifoPopBack(fifo_t *pObj)
{
pObj->iw--;
if (pObj->iw >= pObj->size_max)
pObj->iw = 0;
if (pObj->size > 0)
pObj->size--;
}
void FifoPopFront(fifo_t *pObj)
{
pObj->ir++;
if (pObj->ir >= pObj->size_max)
pObj->ir = 0;
if (pObj->size > 0)
pObj->size--;
}
// --------------------------------------------------------------
// Interpolation
// --------------------------------------------------------------
#if 0
void FDly_Init(fdly_t *pObj, int order)
{
pObj->Nf = order + 1;
pObj->hf = (radio_float_t*)malloc(pObj->Nf*sizeof(radio_float_t));
pObj->statef = (radio_float_t*)malloc(pObj->Nf*sizeof(radio_float_t));
memset(pObj->hf, 0, pObj->Nf*sizeof(radio_float_t));
memset(pObj->statef, 0, pObj->Nf*sizeof(radio_float_t));
}
void FDly_Free(fdly_t *pObj)
{
if (pObj->hf)
free(pObj->hf);
pObj->hf = NULL;
if (pObj->statef)
free(pObj->statef);
pObj->statef = NULL;
}
radio_float_t FDly_Process(fdly_t *pObj, radio_float_t x)
{
radio_float_t y;
FIR(pObj->hf, pObj->statef, pObj->Nf, &x, &y, 1);
return y;
}
void FDly_CalcCoeff(fdly_t *pObj, radio_float_t delay)
{
int n, k;
radio_float_t hn;
for (n=0; n < pObj->Nf; n++)
{
hn = 1.0;
for (k=0; k < pObj->Nf; k++)
{
if (k == n)
continue;
hn *= ((delay - (radio_float_t)k) / (radio_float_t)(n-k));
}
pObj->hf[n] = hn;
}
}
void LGIpInit(lgip_t *pObj, int order, int bufsize)
{
pObj->N = order + 1;
pObj->bufsize = bufsize;
RBufInit(&pObj->rbuf, bufsize);
}
void LGIpFree(lgip_t *pObj)
{
RBufFree(&pObj->rbuf);
pObj->N = 0;
}
radio_float_t LGIpProcess(lgip_t *pObj, radio_float_t x, int m, radio_float_t mu)
{
int n, k;
radio_float_t hn, y, delay;
RBufPut(&pObj->rbuf, x);
y = 0;
delay = 1-mu;
for (n=0; n < pObj->N; n++)
{
hn = 1.0;
for (k=0; k < pObj->N; k++)
{
if (k == n)
continue;
hn *= ((delay - (radio_float_t)k) / (radio_float_t)(n-k));
}
y += hn*RBufGetAt(&pObj->rbuf, pObj->bufsize/2 + m-n);
}
return y;
}
void LGCpxIpInit(lgip_cpx_t *pObj, int order)
{
// FIFO
pObj->N = order + 1;
pObj->w = 0;
pObj->r = 0;
pObj->L = 64*pObj->N; // Influences STR-Loop delay
pObj->pFifo = (cpx_t*)malloc(pObj->L*sizeof(cpx_t));
memset(pObj->pFifo, 0, pObj->L*sizeof(cpx_t));
}
void LGCpxIpFree(lgip_cpx_t *pObj)
{
free(pObj->pFifo);
pObj->pFifo = NULL;
pObj->N = 0;
}
cpx_t LGCpxIpProcess(lgip_cpx_t *pObj, cpx_t x, int m, radio_float_t mu)
{
uint32_t i, j, k, N, L, r;
radio_float_t h;
cpx_t y;
L = pObj->L;
N = pObj->N;
pObj->pFifo[pObj->w++] = x;
if (pObj->w == L)
pObj->w = 0;
r = (m-N) % L;
k = 0;
y.real = 0.0;
y.imag = 0.0;
for (i=0; i < pObj->N; i++)
{
h = 1.0;
for (j=0; j < pObj->N; j++)
{
if (i == j)
continue;
h *= (((radio_float_t)pObj->N/2 + mu - (radio_float_t)j - (radio_float_t)0.5) / (radio_float_t)(i-j));
}
y.real += pObj->pFifo[r].real * h;
y.imag += pObj->pFifo[r].imag * h;
r = (r+1) % L;
}
return y;
}
radio_float_t PolyPhaseSRRCInit(fir_pp_t *pObj, radio_float_t fa, radio_float_t tsym, radio_float_t alpha, uint32_t N, uint32_t M)
{
uint32_t i, j;
fir_float_t *pCoeff;
radio_float_t k;
pCoeff = (fir_float_t*)malloc((N+1)*M*sizeof(fir_float_t));
memset(pCoeff, 0, M*(N+1)*sizeof(fir_float_t));
k = CalcFirSRRC(pCoeff, M*fa, tsym, alpha, M*N);
pObj->ppCoeff = (fir_float_t**)malloc(M*sizeof(fir_float_t*));
for(i=0; i < M; i++)
{
pObj->ppCoeff[i] = (fir_float_t*)malloc(N*sizeof(fir_float_t));
memset(pObj->ppCoeff[i], 0, N*sizeof(fir_float_t));
}
pObj->pState = (fir_float_t*)malloc(N*sizeof(fir_float_t));
memset(pObj->pState, 0, N*sizeof(fir_float_t));
for(i=0; i < M; i++)
{
for(j=0; j < N; j++)
{
pObj->ppCoeff[i][j] = M*pCoeff[M*j+M/2+i];
}
}
pObj->M = M;
pObj->N = N;
free(pCoeff);
return k/M;
}
void PolyPhaseSRRCFree(fir_pp_t *pObj)
{
uint32_t i;
for(i=0; i < pObj->M; i++)
{
free(pObj->ppCoeff[i]);
}
free(pObj->ppCoeff);
pObj->ppCoeff = NULL;
free(pObj->pState);
pObj->pState = NULL;
}
uint32_t PolyPhaseSRRCProcess(fir_pp_t *pObj, radio_float_t mu, radio_float_t *pX, radio_float_t *pY, uint32_t len)
{
uint32_t m;
// m = (pObj->M/2 + (int)(mu * pObj->M/2)) % pObj->M;
m = (int)dmod(mu*pObj->M, (radio_float_t)pObj->M);
FIR(pObj->ppCoeff[m], pObj->pState, pObj->N, pX, pY, len);
return len;
}
// --------------------------------------------------------------
radio_float_t PolyPhaseIpInit(ppip_t *pObj, radio_float_t fa, radio_float_t tsym, radio_float_t alpha, uint32_t N, uint32_t M)
{
uint32_t i, j;
fir_float_t *pCoeff;
radio_float_t k;
pCoeff = (fir_float_t*)malloc((N+1)*M*sizeof(fir_float_t));
memset(pCoeff, 0, (N+1)*M*sizeof(fir_float_t));
k = CalcFirSRRC(pCoeff, M*fa, tsym, alpha, N*M);
pObj->ppCoeff = (fir_float_t**)malloc(M*sizeof(fir_float_t*));
for(i=0; i < M; i++)
{
pObj->ppCoeff[i] = (fir_float_t*)malloc(N*sizeof(fir_float_t));
memset(pObj->ppCoeff[i], 0, N*sizeof(fir_float_t));
}
for(i=0; i < M; i++)
{
for(j=0; j < N; j++)
{
pObj->ppCoeff[i][j] = M*pCoeff[M*j+M/2+i];
}
}
pObj->pState = (fir_float_t*)malloc(N*sizeof(fir_float_t));
memset(pObj->pState, 0, N*sizeof(fir_float_t));
pObj->M = M;
pObj->N = N;
RBufInit(&pObj->rbuf, 2*N); // Influences STR-Loop delay
free(pCoeff);
return k/M;
}
void PolyPhaseIpFree(ppip_t *pObj)
{
uint32_t i;
for(i=0; i < pObj->M; i++)
{
free(pObj->ppCoeff[i]);
}
free(pObj->ppCoeff);
pObj->ppCoeff = NULL;
free(pObj->pState);
pObj->pState = NULL;
RBufFree(&pObj->rbuf);
}
radio_float_t PolyPhaseIpProcess(ppip_t *pObj, radio_float_t x, int m, radio_float_t mu)
{
uint32_t index, i;
radio_float_t y;
index = (int)dmod(mu*pObj->M, (radio_float_t)pObj->M);
for(i=0; i < pObj->N; i++)
{
pObj->pState[i] = RBufGetAt(&pObj->rbuf, m-i);
}
FIR(pObj->ppCoeff[index], pObj->pState, pObj->N, &x, &y, 1);
RBufPut(&pObj->rbuf, x);
return y;
}
void FirCpxInit(fir_cpx_t *pObj, uint32_t N)
{
pObj->pX = (cpx_t*)malloc(N*sizeof(cpx_t));
memset(pObj->pX, 0, N*sizeof(cpx_t));
pObj->N = N;
pObj->r = 0;
pObj->w = 0;
}
void FirCpxFree(fir_cpx_t *pObj)
{
free(pObj->pX);
}
void FirCpxProcessReal(fir_cpx_t *pObj, radio_float_t *pW, cpx_t *pSrc, cpx_t *pDst, uint32_t downSampleFactor, uint32_t len)
{
uint32_t i, j, w, r, N, k;
w = pObj->w;
r = pObj->r;
N = pObj->N;
for (i=0; i < len/downSampleFactor; i++)
{
for (k=0; k < downSampleFactor; k++)
{
pObj->pX[w++] = pSrc[i*downSampleFactor + k];
if (w >= N)
w = 0;
}
pDst[i].real = pDst[i].imag = 0;
for (j=0; j < N; j++)
{
pDst[i].real += pObj->pX[r].real * pW[j];
pDst[i].imag += pObj->pX[r].imag * pW[j];
r--;
if (r >= N)
r = N-1;
}
for (k=0; k < downSampleFactor; k++)
{
r++;
if (r >= N)
r = 0;
}
}
pObj->r = r;
pObj->w = w;
}
void FirCpxProcessComplex(fir_cpx_t *pObj, cpx_t *pW, cpx_t *pSrc, cpx_t *pDst, uint32_t len)
{
(void)pObj;
(void)pW;
(void)pSrc;
(void)pDst;
(void)len;
}
// --------------------------------------------------------------
radio_float_t PolyPhaseCpxIpInit(ppip_cpx_t *pObj, radio_float_t fa, radio_float_t tsym, radio_float_t alpha, uint32_t N, uint32_t M)
{
uint32_t i, j;
fir_float_t *pCoeff;
radio_float_t k;
// Calculate polyphase filter
pCoeff = (fir_float_t*)malloc((N+1)*M*sizeof(fir_float_t));
memset(pCoeff, 0, (N+1)*M*sizeof(fir_float_t));
k = CalcFirSRRC(pCoeff, M*fa, tsym, alpha, N*M);
CalcKaiser(pCoeff, pCoeff, (radio_float_t)2.4, N*M);
pObj->ppCoeff = (fir_float_t**)malloc(M*sizeof(fir_float_t*));
for(i=0; i < M; i++)
{
pObj->ppCoeff[i] = (fir_float_t*)malloc(N*sizeof(fir_float_t));
memset(pObj->ppCoeff[i], 0, N*sizeof(fir_float_t));
}
for(i=0; i < M; i++)
{
for(j=0; j < N; j++)
{
pObj->ppCoeff[i][j] = M*pCoeff[M*j+M/2+i];
}
}
// FIFO
pObj->w = 0;
pObj->r = 0;
pObj->L = 2*N; // Influences STR-Loop delay
pObj->pFifo = (cpx_t*)malloc(pObj->L*sizeof(cpx_t));
memset(pObj->pFifo, 0, pObj->L*sizeof(cpx_t));
pObj->M = M;
pObj->N = N;
free(pCoeff);
return k/M;
}
void PolyPhaseCpxIpFree(ppip_cpx_t *pObj)
{
uint32_t i;
for(i=0; i < pObj->M; i++)
{
free(pObj->ppCoeff[i]);
}
free(pObj->ppCoeff);
pObj->ppCoeff = NULL;
free(pObj->pFifo);
pObj->pFifo = NULL;
}
cpx_t PolyPhaseCpxIpProcess(ppip_cpx_t *pObj, cpx_t x, INT32 m, radio_float_t mu)
{
uint32_t index, j, N, L, r;
radio_float_t *pW;
cpx_t y;
int i;
index = (uint32_t)dmod(mu*pObj->M, (radio_float_t)pObj->M);
pW = pObj->ppCoeff[index];
L = pObj->L;
N = pObj->N;
r = m % L;
pObj->pFifo[pObj->w++] = x;
if (pObj->w == L)
pObj->w = 0;
y.real = pObj->pFifo[r].real * pW[0];
y.imag = pObj->pFifo[r].imag * pW[0];
for (j=1; j < N; j++)
{
i = (int)m - j;
if (i < 0)
{
i = 0;
}
r = i % L;
y.real += pObj->pFifo[r].real * pW[j];
y.imag += pObj->pFifo[r].imag * pW[j];
}
return y;
}
void FarrowPPIPCpxInit(ppip_farrow_cpx_t *pObj, uint32_t M, uint32_t N)
{
uint32_t i;
pObj->ppCoeff = (fir_float_t**)malloc(M*sizeof(fir_float_t*));
for(i=0; i < M; i++)
{
pObj->ppCoeff[i] = (fir_float_t*)malloc(N*sizeof(fir_float_t));
memset(pObj->ppCoeff[i], 0, N*sizeof(fir_float_t));
}
pObj->M = M;
pObj->N = N;
pObj->pH = (cpx_t*)malloc(M*sizeof(cpx_t));
pObj->pB = (cpx_t*)malloc(M*sizeof(cpx_t));
pObj->w = 0;
pObj->r = 0;
pObj->L = 2*N; // Influences STR-Loop delay
pObj->pFifo = (cpx_t*)malloc(pObj->L*sizeof(cpx_t));
memset(pObj->pFifo, 0, pObj->L*sizeof(cpx_t));
}
void FarrowPPIPCpxFree(ppip_farrow_cpx_t *pObj)
{
uint32_t i;
for(i=0; i < pObj->M; i++)
{
free(pObj->ppCoeff[i]);
}
free(pObj->ppCoeff);
pObj->ppCoeff = NULL;
free(pObj->pH);
free(pObj->pFifo);
pObj->pFifo = NULL;
}
cpx_t horner(cpx_t *a, cpx_t *b, uint32_t M, radio_float_t mu)
{
uint32_t i;
b[0] = a[0];
for (i=1; i < M; i++)
{
b[i].real = a[i].real+mu*b[i-1].real;
b[i].imag = a[i].imag+mu*b[i-1].imag;
}
return b[M-1];
}
cpx_t FarrowPPIPCpxProcess(ppip_farrow_cpx_t *pObj, cpx_t x, INT32 m, radio_float_t mu)
{
INT32 i;
uint32_t n, j, N, L, r;
cpx_t y;
L = pObj->L;
N = pObj->N;
pObj->pFifo[pObj->w++] = x;
if (pObj->w == L)
pObj->w = 0;
// Partial filter responses
for (n=0; n < pObj->M; n++)
{
r = (uint32_t)m % L;
j=0;
pObj->pH[n].real = pObj->pFifo[r].real * pObj->ppCoeff[n][j];
pObj->pH[n].imag = pObj->pFifo[r].imag * pObj->ppCoeff[n][j];
j++;
for (; j < N; j++)
{
i = (INT32)m - j;
if (i < 0)
i = 0;
r = i % L;
pObj->pH[n].real += pObj->pFifo[r].real * pObj->ppCoeff[n][j];
pObj->pH[n].imag += pObj->pFifo[r].imag * pObj->ppCoeff[n][j];
}
}
// Combine
y = horner(pObj->pH, pObj->pB, pObj->M, mu);
return y;
}
#endif
// --------------------------------------------------------------
// Data functions
// --------------------------------------------------------------
uint32_t Scramble(uint8_t *pSrcDst, uint32_t state, uint32_t poly, uint32_t len)
{
int i;
while(len)
{
*pSrcDst ^= (uint8_t)state;
pSrcDst++;
len--;
for (i=0; i < 8; i++)
{
if (state & 0x0001)
state = (state >> 1) ^ poly;
else
state = (state >> 1);
}
}
return state;
}
// --------------------------------------------------------------
uint32_t FrameCalcNumStreamBytes(uint32_t len_raw)
{
uint32_t len, num_frames;
num_frames = (int)ceil((float)len_raw / FRAME_NUM_BYTES_PER_FRAME);
len = num_frames*sizeof(frame_t);
if (len < sizeof(frame_t))
len = sizeof(frame_t);
return len;
}
// --------------------------------------------------------------
uint32_t FrameFormat(uint8_t *pRaw, uint8_t *pFormatted, uint32_t len_raw, uint32_t *pPrn_state, uint16_t frame_type)
{
frame_t frame;
uint32_t bytes_remain, len_formatted, len;
uint32_t prn_state;
if (len_raw == 0)
return 0;
prn_state = *pPrn_state;
// Set preamble
frame.hdr.preamble[0] = FRAME_PREAMBLE_IV;
frame.hdr.preamble[1] = ~(frame.hdr.preamble[0]);
bytes_remain = len_raw;
len_formatted = 0;
while(bytes_remain)
{
len = FRAME_NUM_BYTES_PER_FRAME;
if (bytes_remain < FRAME_NUM_BYTES_PER_FRAME)
len = bytes_remain;
memset(frame.data, 0, FRAME_NUM_BYTES_PER_FRAME);
memcpy(frame.data, pRaw, len);
frame.hdr.crc16 = Crc16(FRAME_CRC16_POLY, FRAME_CRC16_IV, frame.data, FRAME_NUM_BYTES_PER_FRAME);
frame.hdr.type = frame_type;
frame.hdr.prn_state = prn_state;
frame.hdr.length = (uint16_t)len;
prn_state = Scramble(frame.data, prn_state, FRAME_SCRAMBLER_POLY, FRAME_NUM_BYTES_PER_FRAME);
prn_state = Scramble((uint8_t*)&frame.hdr.crc16, prn_state, FRAME_SCRAMBLER_POLY, sizeof(frame.hdr.crc16));
prn_state = Scramble((uint8_t*)&frame.hdr.type, prn_state, FRAME_SCRAMBLER_POLY, sizeof(frame.hdr.type));
prn_state = Scramble((uint8_t*)&frame.hdr.length, prn_state, FRAME_SCRAMBLER_POLY, sizeof(frame.hdr.length));
pRaw += len;
bytes_remain -= len;
memcpy(pFormatted, &frame, sizeof(frame_t));
pFormatted += sizeof(frame_t);
len_formatted += sizeof(frame_t);
}
*pPrn_state = prn_state;
return len_formatted;
}
// --------------------------------------------------------------
uint32_t FrameDeformat(uint8_t *pFormatted, uint8_t *pRaw, uint32_t len_formatted, uint16_t frame_type_mask)
{
frame_hdr_t hdr;
uint32_t bytes_remain, len_raw, sync_state, frame_sync, i;
uint16_t crc16_ist;
uint8_t temp[FRAME_NUM_BYTES_PER_FRAME];
uint32_t prn_state;
if (len_formatted == 0)
return 0;
i = 0;
bytes_remain = len_formatted;
len_raw = 0;
while(bytes_remain)
{
sync_state = 0;
do
{
// Find frame boundaries
switch(sync_state)
{
case 0:
if (pFormatted[i] == FRAME_PREAMBLE_IV)
{
sync_state = 1;
}
break;
case 1:
if ((uint8_t)(~pFormatted[i]) == pFormatted[i-1])
{
sync_state = 2;
}
else
{
sync_state = 0;
}
break;
}
i++;
bytes_remain--;
frame_sync = (sync_state == 2);
} while(bytes_remain && !frame_sync);
memcpy(&hdr, &pFormatted[i-2], sizeof(frame_hdr_t));
memcpy(temp, &pFormatted[i-2+sizeof(frame_hdr_t)], FRAME_NUM_BYTES_PER_FRAME);
prn_state = Scramble(temp, hdr.prn_state, FRAME_SCRAMBLER_POLY, FRAME_NUM_BYTES_PER_FRAME);
prn_state = Scramble((uint8_t*)&hdr.crc16, prn_state, FRAME_SCRAMBLER_POLY, sizeof(hdr.crc16));
prn_state = Scramble((uint8_t*)&hdr.type, prn_state, FRAME_SCRAMBLER_POLY, sizeof(hdr.type));
Scramble((uint8_t*)&hdr.length, prn_state, FRAME_SCRAMBLER_POLY, sizeof(hdr.length));
crc16_ist = Crc16(FRAME_CRC16_POLY, FRAME_CRC16_IV, temp, FRAME_NUM_BYTES_PER_FRAME);
if (crc16_ist == hdr.crc16)
{
if ((hdr.type & frame_type_mask) == frame_type_mask)
{
memcpy(&pRaw[len_raw], temp, hdr.length);
len_raw += hdr.length;
}
i += FRAME_NUM_BYTES_PER_FRAME + sizeof(frame_hdr_t) - 2;
bytes_remain -= (FRAME_NUM_BYTES_PER_FRAME + sizeof(frame_hdr_t) - 2);
}
if ((int)bytes_remain < sizeof(frame_t))
bytes_remain = 0;
}
return len_raw;
}
// --------------------------------------------------------------
// Transmission order MSB first
uint32_t FrameSerialize(uint8_t *pSrc, uint8_t *pDst, uint32_t nBitsPerSym, uint32_t srclen)
{
uint32_t bits_remain, i, j;
uint8_t src, dst;
if (srclen == 0)
return 0;
if (nBitsPerSym > 8)
return (uint32_t)-1;
j = 0;
src = *pSrc;
bits_remain = 8;
while(srclen)
{
dst = 0;
for (i=0; i < nBitsPerSym; i++)
{
dst <<= 1;
dst |= (0x01 & (src >> 7));
src <<= 1;
bits_remain--;
if (bits_remain == 0)
{
pSrc++;
bits_remain = 8;
src = *pSrc;
srclen--;
}
}
pDst[j++] = dst;
}
return j;
}
// --------------------------------------------------------------
uint32_t FrameDeSerialize(uint8_t *pSrc, uint8_t *pDst, uint32_t nBitsPerSym, uint32_t srclen, uint16_t frame_type_mask)
{
uint32_t size, err, bits_remain, i, j, byte_sync, srcRemain, bitStart, numCorrupt;
uint8_t src, dst, *pBitStart;
uint16_t dst16, t;
uint8_t frame[sizeof(frame_t)], data[FRAME_NUM_BYTES_PER_FRAME];
if (srclen == 0)
return 0;
if (nBitsPerSym > 8)
return (uint32_t)-1;
src = *pSrc;
bits_remain = nBitsPerSym;
bitStart = bits_remain;
pBitStart = pSrc;
numCorrupt = 0;
t = (FRAME_PREAMBLE_IV << 8) | (0xFF & ~FRAME_PREAMBLE_IV);
size = 0;
do
{
j = 0;
dst16 = 0;
byte_sync = 0;
do
{
bits_remain--;
dst16 <<= 1;
dst16 |= (0x01 & (src >> (bits_remain)));
if (bits_remain == 0)
{
pSrc++;
bits_remain = nBitsPerSym;
src = *pSrc;
srclen--;
if (!srclen)
break;
}
// Find frame boundaries
if (dst16 == t)
{
pBitStart = pSrc;
bitStart = bits_remain;
srcRemain = srclen;
byte_sync = 1;
frame[j++] = 0xFF & (t >> 8);
frame[j++] = 0xFF & t;
}
} while(srclen && !byte_sync);
if (!srclen)
break;
for(j; j < sizeof(frame_t); j++)
{
dst = 0;
for (i=0; i < 8; i++)
{
bits_remain--;
dst <<= 1;
dst |= (0x01 & (src >> (bits_remain)));
if (bits_remain == 0)
{
pSrc++;
bits_remain = nBitsPerSym;
src = *pSrc;
srclen--;
if (!srclen)
break;
}
}
frame[j] = dst;
if (!srclen)
break;
}
if (!srclen)
break;
err = FrameDeformat(frame, data, sizeof(frame_t), frame_type_mask);
if (err > 0)
{
memcpy(&pDst[size], frame, sizeof(frame_t));
size += sizeof(frame_t);
}
else
{
if (size > 0)
numCorrupt++;
bits_remain = bitStart;
pSrc = pBitStart;
srclen = srcRemain;
}
} while(srclen);
printf("Number of corrupted frames = %d\n", numCorrupt);
return size;
}
// --------------------------------------------------------------
// Differential M-PSK symbol mapping
uint32_t FrameSymbolsMap(uint8_t *pBits, cpx_t *pSym, uint32_t nBitsPerSym, uint32_t num_syms, uint32_t type)
{
uint32_t i;
sym_map_t sym_mapper;
if (num_syms == 0)
return 0;
SymMapInit(&sym_mapper, nBitsPerSym, type);
for(i=0; i < num_syms; i++)
{
pSym[i] = SymMapEncode(&sym_mapper, pBits[i]);
}
return num_syms;
}
// --------------------------------------------------------------
// Differential M-PSK symbol de-mapping
uint32_t FrameSymbolsDemap(cpx_t *pSym, uint8_t *pBits, uint32_t nBitsPerSym, uint32_t num_syms, uint32_t type)
{
uint32_t i;
sym_map_t sym_demapper;
sym_err_t sym_err;
if (num_syms == 0)
return 0;
memset(&sym_err, 0, sizeof(sym_err_t));
SymMapInit(&sym_demapper, nBitsPerSym, type);
for(i=0; i < num_syms; i++)
{
pBits[i] = SymMapDecode(&sym_demapper, pSym[i], &sym_err);
}
return num_syms;
}
// --------------------------------------------------------------
// Symbol
// --------------------------------------------------------------
void SymErrInit(sym_err_t *pObj)
{
memset(pObj, 0, sizeof(sym_err_t));
}
// --------------------------------------------------------------
void SymStatInit(sym_stat_t *pObj, uint32_t nBitsPerSym)
{
uint32_t i;
memset(pObj, 0, sizeof(sym_stat_t));
pObj->num_const = 1;
for(i=0; i < nBitsPerSym; i++)
{
pObj->num_const *= 2;
}
pObj->pPerSymStat = (per_sym_stat_t*)malloc(pObj->num_const*sizeof(per_sym_stat_t));
for(i=0; i < pObj->num_const; i++)
{
pObj->pPerSymStat[i].count = 0;
pObj->pPerSymStat[i].var_err_mag = 0;
pObj->pPerSymStat[i].var_err_phi = 0;
SlidingVarInit(&pObj->pPerSymStat[i].sl_err_mag, 1000, 1000);
SlidingVarInit(&pObj->pPerSymStat[i].sl_err_phi, 1000, 1000);
}
}
void SymStatFree(sym_stat_t *pObj)
{
if(pObj->pPerSymStat)
free(pObj->pPerSymStat);
}
void SymStatUpDate(sym_stat_t *pObj, uint8_t sym, sym_err_t *pSym_err)
{
// Statistics
pObj->sym_cnt++;
pObj->pPerSymStat[sym].count++;
pObj->pPerSymStat[sym].p = (radio_float_t)pObj->pPerSymStat[sym].count/pObj->sym_cnt;
pObj->pPerSymStat[sym].var_err_mag = SlidingVarProcess(&pObj->pPerSymStat[sym].sl_err_mag, pSym_err->err_mag);
pObj->pPerSymStat[sym].var_err_phi = SlidingVarProcess(&pObj->pPerSymStat[sym].sl_err_phi, pSym_err->err_phi);
}
void SymStatPrint(sym_stat_t *pObj)
{
uint32_t i;
printf("Number of constellations : %d\n", pObj->num_const);
printf("Number of total symbols : %d\n", pObj->sym_cnt);
printf("Sym#\tOccur.\t\tProb.\t\tVar(MagErr)[dB]\tVar(PhiErr/PI)[dB]\n");
for(i=0; i < pObj->num_const; i++)
{
printf("%4.1d\t%6.d\t\t%1.2g\t\t%.2f\t\t%.2f\n",
i,
pObj->pPerSymStat[i].count,
pObj->pPerSymStat[i].p,
10*log10(pObj->pPerSymStat[i].var_err_mag),
10*log10(pObj->pPerSymStat[i].var_err_phi/(PI*PI)));
}
}
// --------------------------------------------------------------
// Symbol demapper for receiver works on each symbol
// --------------------------------------------------------------
void SymMapInit(sym_map_t *pObj, uint32_t nBitsPerSym, uint32_t type)
{
cpx_t iq;
uint32_t i, j, k, m, n, u, Ns, Nq, Nsq, map_idx_i, map_idx_q;
radio_float_t phi, dphi, ii, qq, iii, qqq, temp, stepIQ;
radio_float_t mag, sum2, sum4;
int signI[4] = {+1, -1, -1, +1};
int signQ[4] = {+1, +1, -1, -1};
int even;
pObj->mask = 0;
pObj->nBitsPerSym = nBitsPerSym;
pObj->num_const = 1;
pObj->type = type;
pObj->iq_step = 0;
pObj->iq_max = 0;
pObj->Pref = 0;
for(k=0; k < nBitsPerSym; k++)
{
pObj->num_const *= 2;
pObj->mask <<= 1;
pObj->mask |= 1;
}
pObj->pMapTbl = (map_t*)malloc(pObj->num_const*sizeof(map_t));
pObj->ppMapTbl = NULL;
Ns = (uint32_t)sqrt(pObj->num_const);
Nq = pObj->num_const/4;
Nsq = (uint32_t)sqrt(Nq);
stepIQ = (radio_float_t)sqrt(2.0)/(Ns-1);
sum2 = sum4 = 0;
switch(type)
{
case MAP_MODE_PSK:
pObj->Es = 1.0; // Symbol transmit power
pObj->Eb = pObj->Es/nBitsPerSym;
pObj->Pref = (radio_float_t)(1.0/sqrt(2.0));
dphi = 2*(radio_float_t)PI/pObj->num_const;
phi = (radio_float_t)PI/pObj->num_const;
for (k=0; k < pObj->num_const; k++)
{
iq.real = (radio_float_t)cos(phi);
iq.imag = (radio_float_t)sin(phi);
pObj->pMapTbl[k].phi = (radio_float_t)CpxPhiS(iq);
pObj->pMapTbl[k].mag = (radio_float_t)CpxMagS(iq);
pObj->pMapTbl[k].rect = iq;
phi += dphi;
}
break;
case MAP_MODE_QAM:
pObj->Es = (radio_float_t)0.5*stepIQ*stepIQ;
pObj->Eb = pObj->Es/nBitsPerSym;
pObj->ppMapTbl = (map_t**)malloc(Ns*sizeof(map_t*));
for (i=0; i< Ns; i++)
pObj->ppMapTbl[i] = (map_t*)malloc(Ns*sizeof(map_t));
ii = (radio_float_t)(1.0/sqrt(2.0));
pObj->iq_max = ii;
qq = ii;
even = 1;
k = 0;
for (m=0; m < Nsq; m++)
{
for (n=0; n < Nsq; n++)
{
iii = ii;
qqq = qq;
for (j=0; j < 4; j++)
{
u = Nq*j+k;
iq.real = iii*signI[j];
iq.imag = qqq*signQ[j];
mag = (radio_float_t)CpxMagS(iq);
phi = (radio_float_t)CpxPhiS(iq);
pObj->pMapTbl[u].mag = mag;
pObj->pMapTbl[u].phi = phi;
pObj->pMapTbl[u].rect = iq;
sum2 += mag*mag;
sum4 += mag*mag*mag*mag;
temp = iii;
iii = qqq;
qqq = temp;
map_idx_i = (int)(0.5 +(0.5*iq.real/pObj->iq_max + 0.5)*(Ns-1));
map_idx_q = (int)(0.5 +(0.5*iq.imag/pObj->iq_max + 0.5)*(Ns-1));
pObj->ppMapTbl[map_idx_i][map_idx_q].mag = mag;
pObj->ppMapTbl[map_idx_i][map_idx_q].phi = phi;
pObj->ppMapTbl[map_idx_i][map_idx_q].rect = iq;
pObj->ppMapTbl[map_idx_i][map_idx_q].sym = u;
}
ii = ii - even*stepIQ;
k++;
}
qq = qq - stepIQ;
ii = ii + even*stepIQ;
even = -even;
}
switch(pObj->num_const)
{
// QPSK
case 4:
pObj->Pref = (radio_float_t)0.707;
break;
// 16-QAM
case 16:
pObj->Pref = (radio_float_t)0.385;
break;
// 64-QAM
case 64:
pObj->Pref = (radio_float_t)0.31;
break;
// 256-QAM
case 256:
pObj->Pref = (radio_float_t)0.27;
break;
default:
break;
}
break;
default:
break;
}
pObj->iq_step = stepIQ;
pObj->iq_side_len = Ns;
sum2 /= pObj->num_const;
sum4 /= pObj->num_const;
pObj->R2 = sum4/sum2;
pObj->R4 = sum4/(sum2*sum2);
pObj->sym_last = 0;
}
// --------------------------------------------------------------
void SymMapFree(sym_map_t *pObj)
{
uint32_t i;
if (pObj->pMapTbl)
{
free(pObj->pMapTbl);
pObj->pMapTbl = NULL;
}
if (pObj->ppMapTbl)
{
for (i=0; i< (uint32_t)sqrt(pObj->num_const); i++)
free(pObj->ppMapTbl[i]);
free(pObj->ppMapTbl);
pObj->ppMapTbl = NULL;
}
}
// --------------------------------------------------------------
cpx_t SymMapEncode(sym_map_t *pObj, uint8_t bit)
{
uint32_t sym;
cpx_t iq;
// Differential encode
sym = pObj->mask & ((uint32_t)bit + pObj->sym_last);
pObj->sym_last = sym;
iq = pObj->pMapTbl[sym].rect;
return iq;
}
// --------------------------------------------------------------
uint8_t SymMapDecode2(sym_map_t *pObj, cpx_t x, sym_err_t *pSymErr)
{
cpx_t err;
uint32_t k;
uint32_t sym, bit;
radio_float_t dist, best_dist, min_err_mag, err_mag, mag, phi;
mag = (radio_float_t)CpxMagS(x);
phi = (radio_float_t)CpxPhiS(x);
best_dist = 1000;
min_err_mag = 1000;
for(k=0; k < pObj->num_const; k++)
{
err = CpxSubS(pObj->pMapTbl[k].rect, x);
err_mag = pObj->pMapTbl[k].mag - mag;
dist = err.real*err.real + err.imag*err.imag;
if (dist < best_dist)
{
best_dist = dist;
// pSymErr->err_mag = err_mag;
pSymErr->err_phi = pObj->pMapTbl[k].phi - phi;
pSymErr->err = err;
pSymErr->mag = mag;
pSymErr->phi = phi;
pSymErr->hard_sym = pObj->pMapTbl[k].rect;
sym = k;
}
if ((radio_float_t)fabs(err_mag) < min_err_mag)
{
pSymErr->err_mag = err_mag;
pSymErr->hard_mag = pObj->pMapTbl[k].mag;
min_err_mag = (radio_float_t)fabs(err_mag);
}
}
// Differential decode
bit = (uint8_t)(pObj->mask & (sym - pObj->sym_last));
pObj->sym_last = sym;
return bit;
}
map_t SymMapGetSymbol(sym_map_t *pObj, cpx_t x)
{
map_t map;
uint32_t map_idx_i, map_idx_q;
radio_float_t rx_i, rx_q;
rx_i = dclamp(x.real, -pObj->iq_max, pObj->iq_max);
rx_q = dclamp(x.imag, -pObj->iq_max, pObj->iq_max);
map_idx_i = (int)(0.5 +(0.5*rx_i/pObj->iq_max + 0.5)*(pObj->iq_side_len-1));
map_idx_q = (int)(0.5 +(0.5*rx_q/pObj->iq_max + 0.5)*(pObj->iq_side_len-1));
map = pObj->ppMapTbl[map_idx_i][map_idx_q];
return map;
}
uint8_t SymMapDecode(sym_map_t *pObj, cpx_t x, sym_err_t *pSymErr)
{
map_t map;
uint32_t bit;
map = SymMapGetSymbol(pObj, x);
pSymErr->err_phi = map.phi - (radio_float_t)CpxPhiS(x);
pSymErr->err_mag = map.mag - (radio_float_t)CpxMagS(x);
pSymErr->err = CpxSubS(map.rect, x);
pSymErr->mag = CpxMagS(x);
pSymErr->phi = CpxPhiS(x);
pSymErr->soft_sym = x;
pSymErr->hard_sym = map.rect;
pSymErr->hard_mag = map.mag;
// Differential decode
bit = (uint8_t)(pObj->mask & (map.sym - pObj->sym_last));
pObj->sym_last = map.sym;
return bit;
}
// --------------------------------------------------------------
radio_float_t SymMapGetModulus(sym_map_t *pObj, cpx_t x)
{
uint32_t k;
radio_float_t best_mod, min_err_mag, err_mag, mag;
mag = (radio_float_t)CpxMagS(x);
min_err_mag = 1000;
for(k=0; k < pObj->num_const; k++)
{
err_mag = pObj->pMapTbl[k].mag - mag;
if ((radio_float_t)fabs(err_mag) < min_err_mag)
{
best_mod = pObj->pMapTbl[k].mag;
min_err_mag = (radio_float_t)fabs(err_mag);
}
}
return best_mod;
}
// --------------------------------------------------------------
// Equalizer
// --------------------------------------------------------------
#if 0
void EQComplexInit(eq_cpx_t *pObj, uint32_t N)
{
pObj->N = N;
pObj->pX = (cpx_t*)malloc(pObj->N*sizeof(cpx_t));
pObj->pW = (cpx_t*)malloc(pObj->N*sizeof(cpx_t));
memset(pObj->pX, 0, pObj->N*sizeof(cpx_t));
memset(pObj->pW, 0, pObj->N*sizeof(cpx_t));
}
void EQComplexFree(eq_cpx_t *pObj)
{
free(pObj->pX);
free(pObj->pW);
}
cpx_t EQComplexProcess(eq_cpx_t *pObj, cpx_t x)
{
uint32_t i;
cpx_t y, t;
for(i=pObj->N-1; (int)i > 0; i--)
{
pObj->pX[i] = pObj->pX[i-1];
}
// fill M top positions with M new data
pObj->pX[i] = x;
y.real = 0;
y.imag = 0;
for(i=0; i < pObj->N; i++)
{
t = CpxMulS(pObj->pX[i], CpxConjS(pObj->pW[i]));
y = CpxAddS(y, t);
}
return y;
}
// --------------------------------------------------------------
void CMAInit(cma_t *pObj, uint32_t ntaps, uint32_t nSamplesPerSym)
{
pObj->M = nSamplesPerSym;
pObj->N = ntaps;
pObj->Px = 0;
pObj->Px_last = 0;
EQComplexInit(&pObj->eq, pObj->N);
}
void CMAFree(cma_t *pObj)
{
EQComplexFree(&pObj->eq);
}
cpx_t CMAProcess(cma_t *pObj, cpx_t x)
{
cpx_t y;
radio_float_t x2, x1;
y = EQComplexProcess(&pObj->eq, x);
x1 = CpxMagS(x);
x2 = CpxMagS(pObj->eq.pX[pObj->eq.N-1]);
pObj->Px += (x1*x1 - pObj->Px_last);
pObj->Px_last = x2*x2;
return y;
}
// Proakis: page 698
cpx_t CMAGodard(cpx_t sym_s_eq, radio_float_t mag_h, radio_float_t R2)
{
cpx_t d;
radio_float_t mag_s, t;
mag_s = CpxMagS(sym_s_eq);
t = (radio_float_t)((mag_h + R2*mag_s - mag_s*mag_s*mag_s)/(1E-4+mag_h));
d = CpxScaleRealS(sym_s_eq, t);
return d;
}
radio_float_t CMATrain(cma_t *pObj, cpx_t y, cpx_t d, radio_float_t mu)
{
cpx_t e;
e = CpxSubS(d, y);
LMSUpdateWeigths(&pObj->eq, e, mu/(1.f+pObj->Px));
return CpxMagS(e);
}
// --------------------------------------------------------------
void DFEComplexInit(dfe_cpx_t *pObj, uint32_t K)
{
pObj->N = 2*K+1;
pObj->N_ff = K+1;
pObj->N_fb = K;
EQComplexInit(&pObj->eq, pObj->N);
}
void DFEComplexFree(dfe_cpx_t *pObj)
{
EQComplexFree(&pObj->eq);
}
cpx_t DFEComplexProcess(dfe_cpx_t *pObj, cpx_t xs, cpx_t xh)
{
INT32 i;
cpx_t y, t, *pW, *pX;
pX = pObj->eq.pX;
pW = pObj->eq.pW;
// Shift Feedback part
for(i=pObj->N-1; i > (INT32)pObj->N_ff; i--)
{
pX[i] = pX[i-1];
}
// put last x into buffer
pX[i] = xh;
// Shift Feed forward part
for(i=pObj->N_ff-1; i > 0; i--)
{
pX[i] = pX[i-1];
}
// put current x into buffer
pX[i] = xs;
y.real = 0;
y.imag = 0;
for(i=0; i < (INT32)pObj->N; i++)
{
t = CpxMulS(pX[i], CpxConjS(pW[i]));
y = CpxAddS(y, t);
}
return y;
}
void DFEAdaptLMS(dfe_cpx_t *pObj, cpx_t e, radio_float_t mu)
{
LMSUpdateWeigths(&pObj->eq, e, mu);
}
// --------------------------------------------------------------
void LMSUpdateWeigths(eq_cpx_t *pObj, cpx_t e, radio_float_t mu)
{
uint32_t i;
for(i=0; i < pObj->N; i++)
{
pObj->pW[i] = CpxAddS(pObj->pW[i], CpxMulS(CpxScaleRealS(CpxConjS(e), mu), pObj->pX[i]));
}
}
// --------------------------------------------------------------
void CoeffComplexUnitAt(cpx_t *pW, uint32_t N, uint32_t dly)
{
if (dly >= N)
dly = 0;
memset(pW, 0, N*sizeof(cpx_t));
pW[dly].real = 1.0;
pW[dly].imag = 0.0;
}
void CoeffComplexConv(cpx_t *pSrc, cpx_t *pSrcDst, uint32_t N, uint32_t dly)
{
uint32_t i, j, N2;
cpx_t *pX, *pW, t, energy = {0};
radio_float_t energy_correct;
N2 = N+dly;
pX = (cpx_t*)malloc(N2*sizeof(cpx_t));
memset(pX, 0, N2*sizeof(cpx_t));
pW = (cpx_t*)malloc(N2*sizeof(cpx_t));
memset(pW, 0, N2*sizeof(cpx_t));
CpxCopy(pSrc, pX, N);
for(j=0; j < N; j++)
energy = CpxAddS(energy, pSrcDst[j]);
energy_correct = (radio_float_t)(1.0/CpxMagS(energy));
for(i=0; i < N2; i++)
{
for(j=0; j < N; j++)
{
t = CpxMulS(pX[N-j+i-1], pSrcDst[j]);
pW[i] = CpxScaleRealS(CpxAddS(pW[i], t), energy_correct);
}
}
CpxCopy(&pW[N/2], pSrcDst, N);
}
// --------------------------------------------------------------
void RLSInit(rls_t *pObj, uint32_t N, uint32_t M)
{
uint32_t i, j;
radio_float_t *pR;
pObj->w = (radio_float_t*)malloc(N*sizeof(radio_float_t));
memset(pObj->w, 0, N*sizeof(radio_float_t));
pObj->w[0] = 1.0f;
pObj->pW = (cpx_t*)malloc(N*sizeof(cpx_t));
memset(pObj->pW, 0, N*sizeof(cpx_t));
pObj->z = (radio_float_t*)malloc(N*sizeof(radio_float_t));
memset(pObj->z, 0, N*sizeof(radio_float_t));
pObj->x = (radio_float_t*)malloc(N*sizeof(radio_float_t));
memset(pObj->x, 0, N*sizeof(radio_float_t));
pObj->pX = (cpx_t*)malloc(N*M*sizeof(cpx_t));
memset(pObj->pX, 0, N*M*sizeof(cpx_t));
pObj->R = (radio_float_t*)malloc(N*N*sizeof(radio_float_t));
memset(pObj->R, 0, N*N*sizeof(radio_float_t));
pObj->T = (radio_float_t*)malloc(N*N*sizeof(radio_float_t));
memset(pObj->T, 0, N*N*sizeof(radio_float_t));
pObj->T2 = (radio_float_t*)malloc(N*N*sizeof(radio_float_t));
memset(pObj->T2, 0, N*N*sizeof(radio_float_t));
pR = pObj->R;
for(i=0; i < N; i++)
for(j=0; j < N; j++)
pR[i+j*N] = (radio_float_t)1E6*(i==j);
pObj->N = N;
pObj->M = M;
}
void RLSFree(rls_t *pObj)
{
if(pObj->w)
free(pObj->w);
if(pObj->z)
free(pObj->z);
if(pObj->x)
free(pObj->x);
if(pObj->R)
free(pObj->R);
if(pObj->T)
free(pObj->T);
if(pObj->T2)
free(pObj->T2);
}
/*
void RLSProcess(rls_t *pObj, radio_float_t rho, radio_float_t mu, radio_float_t x, radio_float_t d, radio_float_t *pE, radio_float_t *pDD)
{
int i, j, k, N;
radio_float_t *pR, *pX, *pZ, *pT, *pT2, v, t, rho_i;
N = pObj->N;
FIR(pObj->w, pObj->x, N, &x, pDD, 1);
*pE = d - *pDD;
// Whitening
pR = pObj->R;
pX = pObj->x;
for(i=0; i < N; i++)
{
t = 0;
for(j=0; j < N; j++)
t += pR[j*N+i] * pX[j];
pObj->z[i] = t;
}
// Berechnunng der Normierungskonstante
v = rho;
for(i=0; i < N; i++)
v += pObj->x[i] * pObj->z[i];
v = (radio_float_t)1.0/v;
// Normierung
for(i=0; i < N; i++)
pObj->z[i] *= v;
// Filter update
for(i=0; i < N; i++)
pObj->w[i] += (mu * (*pE)*pObj->z[i]);
// Matrix update
pZ = pObj->z;
pX = pObj->x;
pT = pObj->T;
for(i=0; i < N; i++)
{
for(j=0; j < N; j++)
pT[j*N+i] = pZ[i] * pX[j];
}
pT = pObj->T;
pT2 = pObj->T2;
pR = pObj->R;
for (i=0;i<N;i++)
{
for (j=0;j<N;j++)
{
pT2[j*N+i] = 0;
for (k=0;k<N;k++)
{
pT2[j*N+i] += pT[k*N+i] * pR[j*N+k];
}
}
}
for(i=0; i < N*N; i++)
pR[i] -= pT2[i];
rho_i = (radio_float_t)1.0/rho;
for(i=0; i < N*N; i++)
pR[i] *= rho_i;
}
*/
cpx_t RLSProcess(rls_t *pObj, radio_float_t i, radio_float_t q)
{
uint32_t j;
cpx_t y, t;
y.real = 0;
y.imag = 0;
for(j=pObj->N-1; j != 0; j--)
{
pObj->pX[j] = pObj->pX[j-1];
}
pObj->pX[j].real = i;
pObj->pX[j].imag = q;
for(j=0; j < pObj->N; j++)
{
pObj->pW[j].real = pObj->w[j];
pObj->pW[j].imag = pObj->w[j];
}
/// for(j=0; j < pObj->N; j++)
// {
// t = CpxMuls(pObj->pX[M*j], CpxConjs(pObj->pW[j]));
// y = CpxAdds(y, t);
// }
for(j=0; j < pObj->N; j++)
{
t.real = pObj->pX[j].real * pObj->pW[j].real;
t.imag = pObj->pX[j].imag * pObj->pW[j].imag;
y = CpxAddS(y, t);
}
for(j=0; j < pObj->N; j++)
{
pObj->x[j] = pObj->pX[j].real;
}
return y;
}
radio_float_t RLSUpdate(rls_t *pObj, radio_float_t rho, radio_float_t mu, radio_float_t y, radio_float_t d)
{
int i, j, k, N;
radio_float_t *pR, *pX, *pZ, *pT, *pT2, v, t, rho_i, e;
N = pObj->N;
e = d - y;
pR = pObj->R;
pX = pObj->x;
// for(j=0; j < pObj->N; j++)
// {
// pObj->x[j] = pObj->pX[j*pObj->M].real;
// }
// Whitening
for(i=0; i < N; i++)
{
t = 0;
for(j=0; j < N; j++)
t += pR[j*N+i] * pX[j];
pObj->z[i] = t;
}
// Berechnunng der Normierungskonstante
v = rho;
for(i=0; i < N; i++)
v += pObj->x[i] * pObj->z[i];
v = (radio_float_t)1.0/v;
// Normierung
for(i=0; i < N; i++)
pObj->z[i] *= v;
// Filter update
for(i=0; i < N; i++)
pObj->w[i] += (mu * e * pObj->z[i]);
// Matrix update
pZ = pObj->z;
pX = pObj->x;
pT = pObj->T;
for(i=0; i < N; i++)
{
for(j=0; j < N; j++)
pT[j*N+i] = pZ[i] * pX[j];
}
pT = pObj->T;
pT2 = pObj->T2;
pR = pObj->R;
for (i=0;i<N;i++)
{
for (j=0;j<N;j++)
{
pT2[j*N+i] = 0;
for (k=0;k<N;k++)
{
pT2[j*N+i] += pT[k*N+i] * pR[j*N+k];
}
}
}
for(i=0; i < N*N; i++)
pR[i] -= pT2[i];
rho_i = (radio_float_t)1.0/rho;
for(i=0; i < N*N; i++)
pR[i] *= rho_i;
return e;
}
#endif
// --------------------------------------------------------------