This commit is contained in:
Kurt Moraw
2020-11-15 01:32:47 +01:00
parent f0fc9622a4
commit e335d4efbf
24 changed files with 1215 additions and 551 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
CXXFLAGS = -Wall -O3 -std=c++0x -Wno-write-strings -Wno-narrowing
LDFLAGS = -lpthread -lrt -lsndfile -lasound -lm -lbass -lbassflac -lfftw3 -lfftw3_threads -lliquid
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o audio.o udp.o fft.o liquid_if.o
OBJ = hsmodem.o constellation.o crc16.o frame_packer.o main_helper.o scrambler.o speed.o fec.o audio.o udp.o fft.o liquid_if.o symboltracker.o
default: $(OBJ)
g++ $(CXXFLAGS) -o ../LinuxRelease/hsmodem $(OBJ) $(LDFLAGS)
+8 -3
View File
@@ -369,7 +369,7 @@ void setPBvolume(int v)
float vf = v;
vf /= 100;
printf("set PB volume to:%d / %f [0..1]\n", v, vf );
//printf("set PB volume to:%d / %f [0..1]\n", v, vf );
selectPBdevice();
if (!BASS_SetVolume(vf))
@@ -383,7 +383,7 @@ void setCAPvolume(int v)
float vf = v;
vf /= 100;
printf("set CAP volume to:%d / %f [0..1]\n", v, vf);
//printf("set CAP volume to:%d / %f [0..1]\n", v, vf);
selectCAPdevice();
if (!BASS_RecordSetInput(-1,BASS_INPUT_ON,vf))
@@ -462,7 +462,7 @@ void PB_UNLOCK() { pthread_mutex_unlock(&pb_crit_sec); }
#define AUDIO_BUFFERMAXTIME 2 // fifo can buffer this time in [s]
#define AUDIO_PLAYBACK_BUFLEN (48000 * 10) // space for 10 seconds of samples
#define AUDIO_CAPTURE_BUFLEN (48000 * 10)
#define AUDIO_CAPTURE_BUFLEN (48000) // space for 1s
int cap_wridx=0;
int cap_rdidx=0;
@@ -487,6 +487,11 @@ void init_pipes()
// overwrite old data if the fifo is full
void cap_write_fifo(float sample)
{
if (((cap_wridx + 1) % AUDIO_CAPTURE_BUFLEN) == cap_rdidx)
{
printf("cap fifo full\n");
}
CAP_LOCK;
cap_buffer[cap_wridx] = sample;
if(++cap_wridx >= AUDIO_CAPTURE_BUFLEN) cap_wridx = 0;
Binary file not shown.
+41 -2
View File
@@ -157,7 +157,7 @@ void setPBvolume(int v)
if (vf < minPBvol) vf = minPBvol;
if (vf > maxPBvol) vf = maxPBvol;
printf("set PB volume to:%d / %f [%f..%f]\n", v, vf, minPBvol, maxPBvol);
//printf("set PB volume to:%d / %f [%f..%f]\n", v, vf, minPBvol, maxPBvol);
selectPBdevice_wasapi();
if (!BASS_WASAPI_SetVolume(BASS_WASAPI_CURVE_DB, vf))
@@ -216,16 +216,55 @@ DWORD CALLBACK PBcallback_wasapi(void* buffer, DWORD length, void* user)
free(fdata);
return length;
}
/*
#define MCHECK 10
void nullChecker(float fv, float *pbuf, DWORD len)
{
static float farr[MCHECK];
static int idx = 0;
static int f = 1;
static int anz = 0;
if (f)
{
f = 0;
for (int i = 0; i < MCHECK; i++)
farr[i] = 1;
}
farr[idx] = fv;
idx++;
if (idx == MCHECK) idx = 0;
float nu = 0;
for (int i = 0; i < MCHECK; i++)
{
nu += farr[i];
}
if (nu == 0)
{
// how many 00s ar in the current buffer
int a = 0;
for (unsigned int i = 0; i < len-1; i++)
{
if (pbuf[i] == 0 && pbuf[i+1] == 0) a++;
}
printf("=============== null sequence detected: %d len:%d nullanz:%d\n",anz++,len,a);
}
}
*/
DWORD CALLBACK CAPcallback_wasapi(void* buffer, DWORD length, void* user)
{
//printf("CAP callback, len:%d\n",length);
//measure_speed_bps(length/sizeof(float)/ WASAPI_CHANNELS);
float* fbuffer = (float*)buffer;
//showbytestringf((char*)"rx: ", fbuffer, 20);
//showbytestringf((char*)"rx: ", fbuffer, 10);
//printf("%10.6f\n", fbuffer[0]);
for (unsigned int i = 0; i < (length / sizeof(float)); i += WASAPI_CHANNELS)
{
//nullChecker(fbuffer[i],fbuffer, length / sizeof(float));
cap_write_fifo(fbuffer[i]);
}
+54 -16
View File
@@ -32,6 +32,7 @@ uint8_t rx_status = 0;
int framecounter = 0;
int lastframenum = 0;
int getPayload_error = 0;
// header for TX,
uint8_t TXheaderbytes[HEADERLEN] = {0x53, 0xe1, 0xa6};
@@ -95,7 +96,7 @@ uint8_t *Pack(uint8_t *payload, int type, int status, int *plen)
// polulate the raw frame
// make the frame counter
if(status & (1<<4))
if(status == 0)
framecounter = 0; // first block of a stream
else
framecounter++;
@@ -131,30 +132,46 @@ uint8_t *Pack(uint8_t *payload, int type, int status, int *plen)
return txblock;
}
#ifdef _WIN32_
#define MAXHEADERRS 5
#endif
#define MAXHEADERRS 0
#ifdef _LINUX_
#define MAXHEADERRS 2 // takes less CPU time, important for Rasberry PI
#endif
/*
* Header erros will not cause any data errors because the CRC will filter out
* false header detects,
* but it will cause higher CPU load due to excessive execution of FEC and CRC
*/
int seekHeadersyms()
*/
int seekHeadersyms(int symnum)
{
int ret = -1;
int errs = 0;
int exp_hdr = (UDPBLOCKLEN * 8) / bitsPerSymbol; // we expect a new header at this symbol number
symnum %= exp_hdr;
int maxerr = MAXHEADERRS;
if(constellationSize == 4)
{
// QPSK
for(int tab=0; tab<4; tab++)
{
int errs = 0;
errs = 0;
for(int i=0; i<HEADERLEN*8/2; i++)
{
if(rxbuffer[i] != QPSK_headertab[tab][i])
{
errs++;
}
}
if(errs <= MAXHEADERRS) return tab;
if (errs <= maxerr)
{
ret = tab;
break;
}
}
}
else
@@ -162,17 +179,27 @@ int seekHeadersyms()
// 8PSK
for(int tab=0; tab<8; tab++)
{
int errs = 0;
errs = 0;
for(int i=0; i<HEADERLEN*8/3; i++)
{
if(rxbuffer[i] != _8PSK_headertab[tab][i])
{
errs++;
}
}
if(errs <= MAXHEADERRS) return tab;
if(errs <= maxerr)
{
ret = tab;
break;
}
}
}
if (ret != -1)
{
//printf("header detected at symbol:%d, headererrors:%d\n", symnum,errs);
return ret;
}
//if (symnum == 0) printf("header expected at symbol:%d but not found\n", symnum);
return -1;
}
@@ -184,6 +211,7 @@ uint8_t *unpack_data(uint8_t *rxd, int len)
{
int framerdy = 0;
static uint8_t payload[PAYLOADLEN+10];
static int symnum = 0;
rx_status = 0;
// shift all received symbols through rxbuffer
@@ -196,13 +224,13 @@ uint8_t *unpack_data(uint8_t *rxd, int len)
memmove(rxbuffer,rxbuffer+1,frmlen-1);
// insert new symbol at the top
rxbuffer[frmlen-1] = rxd[sym];
symnum++;
//showbytestring((char*)"rx: ",rxbuffer,30);
int rotations = seekHeadersyms();
int rotations = seekHeadersyms(symnum);
if(rotations != -1)
{
//printf("Header found, rotation: %d\n",rotations);
// rxbuffer contains all symbols of the received frame
// convert to bytes
@@ -226,6 +254,14 @@ uint8_t *unpack_data(uint8_t *rxd, int len)
{
memcpy(payload,pl, PAYLOADLEN+10);
framerdy = 1;
if(symnum != 688)
printf("Header found, rotation: %d at symbol no.: %d result: OK\n", rotations, symnum);
symnum = 0;
}
else
{
if((symnum % ((UDPBLOCKLEN * 8) / bitsPerSymbol)) == 0)
printf("Header found, rotation: %d at symbol no.: %d result: %d\n", rotations, symnum, getPayload_error);
}
}
}
@@ -273,6 +309,7 @@ uint8_t *getPayload(uint8_t *rxb)
if(ret == 0)
{
//printf("fec ERROR\n");
getPayload_error = 1;
return NULL; // fec impossible
}
//printf("fec ok\n");
@@ -285,6 +322,7 @@ uint8_t *getPayload(uint8_t *rxb)
if (crc != rxcrc)
{
//printf("crc ERROR\n");
getPayload_error = 2;
return NULL; // no data found
}
//printf("crc OK\n");
@@ -308,8 +346,8 @@ uint8_t *getPayload(uint8_t *rxb)
payload[4] = rx_status; // frame lost information
payload[5] = speed >> 8; // measured line speed
payload[6] = speed;
payload[7] = 0; // free for later use
payload[8] = 0;
payload[7] = maxLevel; // actual max level on sound capture in %
payload[8] = 0; // free for later use
payload[9] = 0;
//printf("Frame no.: %d, type:%d, minfo:%d\n",framenumrx,payload[0],payload[3]);
+14 -5
View File
@@ -91,6 +91,7 @@ int UdpDataPort_fromGR_I_Q = 40137;
int speedmode = 2;
int bitsPerSymbol = 2; // QPSK=2, 8PSK=3
int constellationSize = 4; // QPSK=4, 8PSK=8
int psk8mode=0; // 0=APSK8, 1=PSK8
char localIP[] = { "127.0.0.1" };
char ownfilename[] = { "hsmodem" };
@@ -202,7 +203,7 @@ int main(int argc, char* argv[])
//doArraySend();
if (demodulator() == 0)
sleep_ms(100);
sleep_ms(10);
}
printf("stopped: %d\n", keeprunning);
@@ -242,6 +243,14 @@ SPEEDRATE sr[8] = {
void startModem()
{
if (speedmode >= 8)
{
speedmode = speedmode - 4;
psk8mode = 1;
}
else
psk8mode = 0;
bitsPerSymbol = sr[speedmode].bpsym;
constellationSize = (1 << bitsPerSymbol); // QPSK=4, 8PSK=8
@@ -394,7 +403,7 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
//if (getSending() == 1) return; // already sending (Array sending)
if (minfo == 0)
if (minfo == 0 || minfo == 3)
{
// this is the first frame of a larger file
sendAnnouncement();
@@ -403,8 +412,8 @@ void appdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
// caprate: samples/s. This are symbols: caprate/txinterpolfactor
// and bits: symbols * bitsPerSymbol
// and bytes/second: bits/8 = (caprate/txinterpolfactor) * bitsPerSymbol / 8
// one frame has 258 bytes, so we need for 5s: 5* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
int numframespreamble = 5 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
// one frame has 258 bytes, so we need for 6s: 6* ((caprate/txinterpolfactor) * bitsPerSymbol / 8) /258 + 1 frames
int numframespreamble = 6 * ((caprate / txinterpolfactor) * bitsPerSymbol / 8) / 258 + 1;
for (int i = 0; i < numframespreamble; i++)
toGR_sendData(pdata + 2, type, minfo);
}
@@ -460,7 +469,7 @@ void GRdata_rxdata(uint8_t* pdata, int len, struct sockaddr_in* rxsock)
if (++fnd >= (wt * ws))
{
fnd = 0;
//printf("no signal detected %d, reset RX modem\n", wt);
printf("no signal detected %d, reset RX modem\n", wt);
resetModem();
}
}
+12
View File
@@ -1,3 +1,4 @@
#pragma once
#ifdef _WIN32
#define _WIN32_
@@ -60,6 +61,7 @@
#include "frameformat.h"
#include "fec.h"
#include "udp.h"
#include "symboltracker.h"
#define jpg_tempfilename "rxdata.jpg"
@@ -129,6 +131,14 @@ void exit_fft();
void showbytestringf(char* title, float* data, int anz);
uint16_t* make_waterfall(float fre, int* retlen);
void km_symtrack_cccf_create(int _ftype,
unsigned int _k,
unsigned int _m,
float _beta,
int _ms);
void km_symtrack_cccf_reset(int mode);
void km_symtrack_cccf_set_bandwidth(float _bw);
void km_symtrack_execute(liquid_float_complex _x, liquid_float_complex* _y, unsigned int* _ny, unsigned int* psym_out);
extern int speedmode;
extern int bitsPerSymbol;
@@ -146,6 +156,8 @@ extern int announcement;
extern int ann_running;
extern int transmissions;
extern int linespeed;
extern uint8_t maxLevel;
extern int psk8mode;
#ifdef _LINUX_
int isRunning(char* prgname);
+2
View File
@@ -228,6 +228,7 @@
<ClInclude Include="frameformat.h" />
<ClInclude Include="hsmodem.h" />
<ClInclude Include="liquid.h" />
<ClInclude Include="symboltracker.h" />
<ClInclude Include="udp.h" />
</ItemGroup>
<ItemGroup>
@@ -243,6 +244,7 @@
<ClCompile Include="main_helper.cpp" />
<ClCompile Include="scrambler.cpp" />
<ClCompile Include="speed.cpp" />
<ClCompile Include="symboltracker.cpp" />
<ClCompile Include="udp.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+6
View File
@@ -54,6 +54,9 @@
<ClCompile Include="audio_wasapi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="symboltracker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="hsmodem.h">
@@ -86,5 +89,8 @@
<ClInclude Include="bassflac.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="symboltracker.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
+52 -25
View File
@@ -51,9 +51,13 @@ modulation_scheme getMod()
{
if(bitsPerSymbol == 2)
return LIQUID_MODEM_QPSK;
//return LIQUID_MODEM_APSK4;
else
return LIQUID_MODEM_APSK8;
else
{
if(psk8mode == 0)
return LIQUID_MODEM_APSK8;
else
return LIQUID_MODEM_PSK8;
}
}
// =========== MODULATOR ==================================================
@@ -209,7 +213,6 @@ void modulator(uint8_t sym_in)
nco_crcf dnnco = NULL;
symtrack_cccf symtrack = NULL;
modem demod = NULL;
firdecim_crcf decim = NULL;
// decimator parameters
@@ -221,8 +224,9 @@ int ftype_st = LIQUID_FIRFILT_RRC;
unsigned int k_st = 4; // samples per symbol
unsigned int m_st = 7; // filter delay (symbols)
float beta_st = beta_excessBW;//0.30f; // filter excess bandwidth factor
float bandwidth_st = 0.7f; // loop filter bandwidth
float bandwidth_st = 0.9f; // loop filter bandwidth
uint8_t maxLevel = 0; // maximum level over the last x samples in %
void init_demodulator()
{
@@ -241,34 +245,23 @@ void init_demodulator()
// create symbol tracking synchronizer
//k_st = txinterpolfactor;
symtrack = symtrack_cccf_create(ftype_st,k_st,m_st,beta_st,getMod());
symtrack_cccf_set_bandwidth(symtrack,bandwidth_st);
int ret = symtrack_cccf_set_eq_dd(symtrack);
if (ret != LIQUID_OK)
{
printf("symtrack_cccf_set_eq_dd failed\n");
}
// demodulator
demod = modem_create(getMod());
printf("RX demodulator running\n");
//symtrack = km_symtrack_cccf_create(ftype_st,k_st,m_st,beta_st,getMod());
km_symtrack_cccf_create(ftype_st, k_st, m_st, beta_st, getMod());
//symtrack_cccf_set_bandwidth(symtrack,bandwidth_st);
km_symtrack_cccf_set_bandwidth(bandwidth_st);
}
void close_demodulator()
{
if(symtrack != NULL) symtrack_cccf_destroy(symtrack);
if(demod != NULL) modem_destroy(demod);
if(decim != NULL) firdecim_crcf_destroy(decim);
symtrack = NULL;
demod = NULL;
decim = NULL;
}
void resetModem()
{
//printf("Reset Symtrack\n");
symtrack_cccf_reset(symtrack);
km_symtrack_cccf_reset(0xff);
}
// called for Audio-Samples (FFT)
@@ -301,6 +294,34 @@ void make_FFTdata(float f)
}
}
#define MCHECK 1000
void getMax(float fv)
{
static float farr[MCHECK];
static int idx = 0;
static int f = 1;
if (f)
{
f = 0;
for (int i = 0; i < MCHECK; i++)
farr[i] = 1;
}
farr[idx] = fv;
idx++;
if (idx == MCHECK)
{
idx = 0;
float max = 0;
for (int i = 0; i < MCHECK; i++)
{
if (farr[i] > max) max = farr[i];
}
maxLevel = (uint8_t)(max*100);
//printf("max: %10.6f\n", max);
}
}
int demodulator()
{
@@ -313,13 +334,16 @@ static int ccol_idx = 0;
float f;
int ret = cap_read_fifo(&f);
if(ret == 0) return 0;
// input volume
#ifdef _WIN32_
f *= softwareCAPvolume;
#endif
make_FFTdata(f*120);
getMax(f);
make_FFTdata(f*60);
// downconvert into baseband
// still at soundcard sample rate
@@ -340,19 +364,22 @@ static int ccol_idx = 0;
ccol_idx = 0;
// we have rxPreInterpolfactor samples in ccol
//printf("sc:%10.6f dn:%10.6f j%10.6f ", f, c.real, c.imag);
liquid_float_complex y;
firdecim_crcf_execute(decim, ccol, &y);
unsigned int num_symbols_sync;
liquid_float_complex syms;
symtrack_cccf_execute(symtrack, y, &syms, &num_symbols_sync);
//symtrack_cccf_execute(symtrack, y, &syms, &num_symbols_sync);
unsigned int nsym_out; // output symbol
km_symtrack_execute(y, &syms, &num_symbols_sync,&nsym_out);
if(num_symbols_sync > 1) printf("symtrack_cccf_execute %d output symbols ???\n",num_symbols_sync);
if(num_symbols_sync != 0)
{
unsigned int sym_out; // output symbol
modem_demodulate(demod, syms, &sym_out);
sym_out = nsym_out;
measure_speed_syms(1);
// try to extract a complete frame
+1 -1
View File
@@ -89,7 +89,7 @@ void showbytestringf(char* title, float* data, int anz)
{
printf("%s. Len %d: ", title, anz);
for (int i = 0; i < anz; i++)
printf("%.6f ", data[i]);
printf("%7.4f ", data[i]);
printf("\n");
}
+173
View File
@@ -0,0 +1,173 @@
#include "hsmodem.h"
SYMTRACK km_symtrack;
SYMTRACK* q = &km_symtrack;
// create km_symtrack object with basic parameters
// _ftype : filter type (e.g. LIQUID_FIRFILT_RRC)
// _k : samples per symbol
// _m : filter delay (symbols)
// _beta : filter excess bandwidth
// _ms : modulation scheme (e.g. LIQUID_MODEM_QPSK)
void km_symtrack_cccf_create(int _ftype,
unsigned int _k,
unsigned int _m,
float _beta,
int _ms)
{
// validate input
if (_k < 2)
printf((char *)"symtrack_cccf_create(), filter samples/symbol must be at least 2\n");
if (_m == 0)
printf((char*)"symtrack_cccf_create(), filter delay must be greater than zero\n");
if (_beta <= 0.0f || _beta > 1.0f)
printf((char*)"symtrack_cccf_create(), filter excess bandwidth must be in [0,1]\n");
if (_ms == LIQUID_MODEM_UNKNOWN || _ms >= LIQUID_MODEM_NUM_SCHEMES)
printf((char*)"symtrack_cccf_create(), invalid modulation scheme\n");
// set input parameters
q->filter_type = _ftype;
q->k = _k;
q->m = _m;
q->beta = _beta;
q->mod_scheme = _ms == LIQUID_MODEM_UNKNOWN ? LIQUID_MODEM_BPSK : _ms;
// create automatic gain control
q->agc = agc_crcf_create();
// create symbol synchronizer (output rate: 2 samples per symbol)
if (q->filter_type == LIQUID_FIRFILT_UNKNOWN)
q->symsync = symsync_crcf_create_kaiser(q->k, q->m, 0.9f, 16);
else
q->symsync = symsync_crcf_create_rnyquist(q->filter_type, q->k, q->m, q->beta, 16);
symsync_crcf_set_output_rate(q->symsync, 2);
// create equalizer as default low-pass filter with integer symbol delay (2 samples/symbol)
q->eq_len = 2 * 4 + 1;
q->eq = eqlms_cccf_create_lowpass(q->eq_len, 0.45f);
q->eq_strategy = q->SYMTRACK_EQ_DD;
// nco and phase-locked loop
q->nco = nco_crcf_create(LIQUID_VCO);
// demodulator
q->demod = modem_create((modulation_scheme)q->mod_scheme);
// set default bandwidth
km_symtrack_cccf_set_bandwidth(0.9f);
// reset and return main object
km_symtrack_cccf_reset(0xff);
}
void km_symtrack_cccf_reset(int mode)
{
// reset objects
if (mode & 1) agc_crcf_reset(q->agc);
if (mode & 2) symsync_crcf_reset(q->symsync);
if (mode & 4) eqlms_cccf_reset(q->eq);
if (mode & 8) nco_crcf_reset(q->nco);
if (mode & 0x10) modem_reset(q->demod);
// reset internal counters
q->symsync_index = 0;
q->num_syms_rx = 0;
}
void km_symtrack_cccf_set_bandwidth(float _bw)
{
// validate input
if (_bw < 0)
printf("symtrack_set_bandwidth(), bandwidth must be in [0,1]\n");
// set bandwidths accordingly
float agc_bandwidth = 0.02f * _bw;
float symsync_bandwidth = 0.001f * _bw;
float eq_bandwidth = 0.02f * _bw;
float pll_bandwidth = 0.001f * _bw;
// automatic gain control
agc_crcf_set_bandwidth(q->agc, agc_bandwidth);
// symbol timing recovery
symsync_crcf_set_lf_bw(q->symsync, symsync_bandwidth);
// equalizer
eqlms_cccf_set_bw(q->eq, eq_bandwidth);
// phase-locked loop
nco_crcf_pll_set_bandwidth(q->nco, pll_bandwidth);
}
#define MX 10
// execute synchronizer on single input sample
// _q : synchronizer object
// _x : input data sample
// _y : output data array
// _ny : number of samples written to output buffer
void km_symtrack_execute(liquid_float_complex _x, liquid_float_complex* _y, unsigned int* _ny, unsigned int *psym_out)
{
liquid_float_complex v; // output sample
unsigned int i;
unsigned int num_outputs = 0;
// run sample through automatic gain control
agc_crcf_execute(q->agc, _x, &v);
// symbol synchronizer
unsigned int nw = 0;
symsync_crcf_execute(q->symsync, &v, 1, q->symsync_buf, &nw);
// process each output sample
for (i = 0; i < nw; i++) {
// update phase-locked loop
nco_crcf_step(q->nco);
nco_crcf_mix_down(q->nco, q->symsync_buf[i], &v);
// equalizer/decimator
eqlms_cccf_push(q->eq, v);
// decimate result, noting that symsync outputs at exactly 2 samples/symbol
q->symsync_index++;
if (!(q->symsync_index % 2))
continue;
// increment number of symbols received
q->num_syms_rx++;
// compute equalizer filter output; updating coefficients is dependent upon strategy
liquid_float_complex d_hat;
eqlms_cccf_execute(q->eq, &d_hat);
// demodulate result, apply phase correction
unsigned int sym_out;
modem_demodulate(q->demod, d_hat, &sym_out);
*psym_out = sym_out;
float phase_error = modem_get_demodulator_phase_error(q->demod);
// update pll
nco_crcf_pll_step(q->nco, phase_error);
// update equalizer independent of the signal: estimate error
// assuming constant modulus signal
// TODO: check lock conditions of previous object to determine when to run equalizer
liquid_float_complex d_prime;
d_prime.real = d_prime.imag = 0;
if (q->num_syms_rx > 200)
{
modem_get_demodulator_sample(q->demod, &d_prime);
eqlms_cccf_step(q->eq, d_prime, d_hat);
}
// save result to output
_y[num_outputs++] = d_hat;
}
/*float fr = nco_crcf_get_frequency(q->nco);
float ph = nco_crcf_get_phase(q->nco);
printf("%10.6f %10.6f %10.6f %10.6f\n", fr, ph, _x.real, _x.imag);*/
* _ny = num_outputs;
}
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include "liquid.h"
typedef struct _SYMTRACK_ {
// parameters
int filter_type; // filter type (e.g. LIQUID_FIRFILT_RRC)
unsigned int k; // samples/symbol
unsigned int m; // filter semi-length
float beta; // filter excess bandwidth
int mod_scheme; // demodulator
// automatic gain control
agc_crcf agc; // agc object
float agc_bandwidth; // agc bandwidth
// symbol timing recovery
symsync_crcf symsync; // symbol timing recovery object
float symsync_bandwidth; // symsync loop bandwidth
liquid_float_complex symsync_buf[8]; // symsync output buffer
unsigned int symsync_index; // symsync output sample index
// equalizer/decimator
eqlms_cccf eq; // equalizer (LMS)
unsigned int eq_len; // equalizer length
float eq_bandwidth; // equalizer bandwidth
enum {
SYMTRACK_EQ_CM, // equalizer strategy: constant modulus
SYMTRACK_EQ_DD, // equalizer strategy: decision directed
SYMTRACK_EQ_OFF, // equalizer strategy: disabled
} eq_strategy;
// nco/phase-locked loop
nco_crcf nco; // nco (carrier recovery)
float pll_bandwidth; // phase-locked loop bandwidth
// demodulator
modem demod; // linear modem demodulator
// state and counters
unsigned int num_syms_rx; // number of symbols recovered
} SYMTRACK;