git-svn-id: http://moon:8086/svn/software/trunk/libsrc/radio@1 b431acfa-c32f-4a4a-93f1-934dc6c82436
298 lines
7.5 KiB
C
Executable File
298 lines
7.5 KiB
C
Executable File
// --------------------------------------------------------------
|
|
#include <stdio.h> // for SymStatPrint() remove later
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <math.h>
|
|
#include "radio_types.h"
|
|
#include "symbol.h"
|
|
|
|
// --------------------------------------------------------------
|
|
// 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, E_m2, E_m2_c, E_m4;
|
|
radio_float_t c_smma;
|
|
cpx_t E_a4;
|
|
int signI[4] = {+1, -1, -1, +1};
|
|
int signQ[4] = {+1, +1, -1, -1};
|
|
int even;
|
|
pObj->nBitsPerSym = nBitsPerSym;
|
|
pObj->num_const = 1;
|
|
pObj->type = type;
|
|
pObj->iq_step = 0;
|
|
pObj->iq_max = 0;
|
|
pObj->Pref = 0;
|
|
E_a4 = Cpx(0,0);
|
|
c_smma = (radio_float_t)1; // Tuning constant S-MMA
|
|
for(k=0; k < nBitsPerSym; k++)
|
|
{
|
|
pObj->num_const *= 2;
|
|
}
|
|
pObj->pMapTbl = (map_t*)malloc(pObj->num_const*sizeof(map_t));
|
|
pObj->ppMapTbl = NULL;
|
|
|
|
Ns = (uint32_t)sqrt((radio_float_t)pObj->num_const);
|
|
Nq = pObj->num_const/4;
|
|
Nsq = (uint32_t)sqrt((radio_float_t)Nq);
|
|
stepIQ = (radio_float_t)sqrt(2.0)/(Ns-1);
|
|
E_m2_c = E_m2 = E_m4 = 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;
|
|
E_m2_c += (radio_float_t)pow(mag, 2+c_smma);
|
|
E_m2 += (radio_float_t)pow(mag, 2);
|
|
E_m4 += (radio_float_t)pow(mag, 4);
|
|
E_a4.real += (radio_float_t)pow(iq.real, 4);
|
|
E_a4.imag += (radio_float_t)pow(iq.imag, 4);
|
|
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 = (symbol_t)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;
|
|
pObj->R2_cma = E_m4/E_m2;
|
|
pObj->R_mma.real = 2*E_a4.real/E_m2;
|
|
pObj->R_mma.imag = 2*E_a4.imag/E_m2;
|
|
pObj->R_smma.real = 2*E_a4.real/E_m2_c;
|
|
pObj->R_smma.imag = 2*E_a4.imag/E_m2_c;
|
|
}
|
|
|
|
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((float)pObj->num_const); i++)
|
|
free(pObj->ppMapTbl[i]);
|
|
|
|
free(pObj->ppMapTbl);
|
|
pObj->ppMapTbl = NULL;
|
|
}
|
|
}
|
|
|
|
void SymMapReinit(sym_map_t *pObj, uint32_t nBitsPerSym, uint32_t type)
|
|
{
|
|
SymMapFree(pObj);
|
|
SymMapInit(pObj, nBitsPerSym, type);
|
|
}
|
|
|
|
cpx_t SymMapMap(sym_map_t *pObj, symbol_t symbol)
|
|
{
|
|
if (symbol >= pObj->num_const)
|
|
return Cpx(0,0);
|
|
|
|
return pObj->pMapTbl[(uint32_t)symbol].rect;
|
|
}
|
|
|
|
symbol_t SymMapDemap(sym_map_t *pObj, cpx_t x)
|
|
{
|
|
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));
|
|
|
|
return pObj->ppMapTbl[map_idx_i][map_idx_q].sym;
|
|
}
|
|
|
|
map_t SymMapGetSymbolInfo(sym_map_t *pObj, symbol_t symbol)
|
|
{
|
|
return pObj->pMapTbl[(uint32_t)symbol];
|
|
}
|
|
|
|
sym_err_t SymMapGetError(sym_map_t *pObj, cpx_t x, symbol_t symbol)
|
|
{
|
|
map_t map;
|
|
sym_err_t res;
|
|
|
|
map = SymMapGetSymbolInfo(pObj, symbol);
|
|
|
|
res.err_mag = map.mag - (radio_float_t)CpxMagS(x);
|
|
res.err_phi = map.phi - (radio_float_t)CpxPhiS(x);
|
|
res.err = CpxSubS(map.rect, x);
|
|
res.mag = CpxMagS(x);
|
|
res.phi = CpxPhiS(x);
|
|
res.soft_sym = x;
|
|
res.hard_sym = map.rect;
|
|
res.hard_mag = map.mag;
|
|
res.hard_phi = map.phi;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
// --------------------------------------------------------------
|
|
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);
|
|
|
|
pObj->pPerSymStat = 0;
|
|
}
|
|
|
|
void SymStatReset(sym_stat_t *pObj)
|
|
{
|
|
uint32_t i;
|
|
pObj->sym_cnt = 0;
|
|
for(i=0; i < pObj->num_const; i++)
|
|
{
|
|
pObj->pPerSymStat[i].count = 0;
|
|
}
|
|
}
|
|
|
|
void SymStatUpDate(sym_stat_t *pObj, symbol_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)));
|
|
}
|
|
} |