SDRAngel  4.11.5
Developer docs for <a href="https://github.com/f4exb/sdrangel">SDRangel<\a>, an Open Source Qt5 / OpenGL 3.0+ SDR and signal analyzer frontend to various hardware.
Classes | Public Types | Public Member Functions | Public Attributes | Static Public Attributes | Private Member Functions | Private Attributes | List of all members
leansdr::fast_qpsk_receiver< T > Struct Template Reference

#include <sdr.h>

+ Inheritance diagram for leansdr::fast_qpsk_receiver< T >:
+ Collaboration diagram for leansdr::fast_qpsk_receiver< T >:

Classes

struct  polar
 

Public Types

typedef u8 hardsymbol
 

Public Member Functions

 fast_qpsk_receiver (scheduler *sch, pipebuf< complex< T >> &_in, pipebuf< hardsymbol > &_out, pipebuf< float > *_freq_out=NULL, pipebuf< complex< T >> *_cstln_out=NULL)
 
void set_omega (float _omega, float tol=10e-6)
 
void set_freq (float freq)
 
void update_freq_limits ()
 
void run ()
 
- Public Member Functions inherited from leansdr::runnable
 runnable (scheduler *_sch, const char *name)
 
- Public Member Functions inherited from leansdr::runnable_common
 runnable_common (const char *_name)
 
virtual ~runnable_common ()
 
virtual void shutdown ()
 

Public Attributes

unsigned long meas_decimation
 
float omega
 
float min_omega
 
float max_omega
 
signed long freqw
 
signed long min_freqw
 
signed long max_freqw
 
float pll_adjustment
 
bool allow_drift
 
cu8 p
 
cu8 c
 
- Public Attributes inherited from leansdr::runnable_common
const char * name
 

Static Public Attributes

static const unsigned int chunk_size = 128
 
static const int RLUT_BITS = 8
 
static const int RLUT_ANGLES = 1 << RLUT_BITS
 

Private Member Functions

u_angle fast_arg (const cu8 &c)
 
cu8 arg_to_symbol (u_angle a)
 
void init_lookup_tables ()
 

Private Attributes

struct leansdr::fast_qpsk_receiver::polar lut_polar [256][256]
 
cu8 lut_rect [RLUT_ANGLES][256]
 
cu8 lut_sincos [65536]
 
struct {
   cu8   p
 
   cu8   c
 
hist [3]
 
pipereader< cu8in
 
pipewriter< hardsymbolout
 
float mu
 
u_angle phase
 
unsigned long meas_count
 
pipewriter< float > * freq_out
 
pipewriter< float > * mer_out
 
pipewriter< cu8 > * cstln_out
 

Additional Inherited Members

- Protected Attributes inherited from leansdr::runnable
schedulersch
 

Detailed Description

template<typename T>
struct leansdr::fast_qpsk_receiver< T >

Definition at line 1321 of file sdr.h.

Member Typedef Documentation

◆ hardsymbol

template<typename T >
typedef u8 leansdr::fast_qpsk_receiver< T >::hardsymbol

Definition at line 1323 of file sdr.h.

Constructor & Destructor Documentation

◆ fast_qpsk_receiver()

template<typename T >
leansdr::fast_qpsk_receiver< T >::fast_qpsk_receiver ( scheduler sch,
pipebuf< complex< T >> &  _in,
pipebuf< hardsymbol > &  _out,
pipebuf< float > *  _freq_out = NULL,
pipebuf< complex< T >> *  _cstln_out = NULL 
)
inline

Definition at line 1331 of file sdr.h.

1335  : runnable(sch, "Fast QPSK receiver"),
1336  meas_decimation(1048576),
1337  pll_adjustment(1.0),
1338  allow_drift(false),
1339  in(_in),
1340  out(_out, chunk_size),
1341  mu(0),
1342  phase(0),
1343  meas_count(0)
1344  {
1345  set_omega(1);
1346  set_freq(0);
1347  freq_out = _freq_out ? new pipewriter<float>(*_freq_out) : NULL;
1348  cstln_out = _cstln_out ? new pipewriter<complex<T>>(*_cstln_out) : NULL;
1349  memset(hist, 0, sizeof(hist));
1351  }
static const unsigned int chunk_size
Definition: sdr.h:1329
void set_omega(float _omega, float tol=10e-6)
Definition: sdr.h:1353
void set_freq(float freq)
Definition: sdr.h:1361
runnable(scheduler *_sch, const char *name)
Definition: framework.h:193
struct leansdr::fast_qpsk_receiver::@9 hist[3]
pipewriter< cu8 > * cstln_out
Definition: sdr.h:1597
unsigned long meas_decimation
Definition: sdr.h:1324
unsigned long meas_count
Definition: sdr.h:1595
scheduler * sch
Definition: framework.h:199
pipewriter< hardsymbol > out
Definition: sdr.h:1592
pipewriter< float > * freq_out
Definition: sdr.h:1596
pipereader< cu8 > in
Definition: sdr.h:1591

Member Function Documentation

◆ arg_to_symbol()

template<typename T >
cu8 leansdr::fast_qpsk_receiver< T >::arg_to_symbol ( u_angle  a)
inlineprivate

Definition at line 1546 of file sdr.h.

1547  {
1548  return lut_sincos[a];
1549  }
cu8 lut_sincos[65536]
Definition: sdr.h:1544

◆ fast_arg()

template<typename T >
u_angle leansdr::fast_qpsk_receiver< T >::fast_arg ( const cu8 c)
inlineprivate

Definition at line 1537 of file sdr.h.

References leansdr::complex< T >::im, and leansdr::complex< T >::re.

1538  {
1539  // TBD read cu8 as u16 index, same endianness as in init()
1540  return lut_polar[c.re][c.im].a;
1541  }
struct leansdr::fast_qpsk_receiver::polar lut_polar[256][256]

◆ init_lookup_tables()

template<typename T >
void leansdr::fast_qpsk_receiver< T >::init_lookup_tables ( )
inlineprivate

Definition at line 1551 of file sdr.h.

References cos(), leansdr::auto_notch< T >::slot::i, leansdr::complex< T >::im, M_PI, leansdr::complex< T >::re, and sin().

1552  {
1553  for (int i = 0; i < 256; ++i)
1554  {
1555  for (int q = 0; q < 256; ++q)
1556  {
1557  // Don't cast float to unsigned directly
1558  lut_polar[i][q].a = (s_angle)(atan2f(q - 128, i - 128) * 65536 / (2 * M_PI));
1559  lut_polar[i][q].r = (int)hypotf(i - 128, q - 128);
1560  }
1561  }
1562 
1563  for (unsigned long a = 0; a < 65536; ++a)
1564  {
1565  float f = 2 * M_PI * a / 65536;
1566  lut_sincos[a].re = 128 + cstln_amp * cosf(f);
1567  lut_sincos[a].im = 128 + cstln_amp * sinf(f);
1568  }
1569 
1570  for (int a = 0; a < RLUT_ANGLES; ++a)
1571  {
1572  for (int r = 0; r < 256; ++r)
1573  {
1574  lut_rect[a][r].re = (int)(128 + r * cos(2 * M_PI * a / RLUT_ANGLES));
1575  lut_rect[a][r].im = (int)(128 + r * sin(2 * M_PI * a / RLUT_ANGLES));
1576  }
1577  }
1578  }
Fixed< IntType, IntBits > cos(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2271
static const int RLUT_ANGLES
Definition: sdr.h:1376
cu8 lut_sincos[65536]
Definition: sdr.h:1544
#define M_PI
Definition: rdsdemod.cpp:27
int16_t s_angle
Definition: sdr.h:385
Fixed< IntType, IntBits > sin(Fixed< IntType, IntBits > const &x)
Definition: fixed.h:2265
int32_t i
Definition: decimators.h:244
struct leansdr::fast_qpsk_receiver::polar lut_polar[256][256]
const float cstln_amp
Definition: sdr.h:404
cu8 lut_rect[RLUT_ANGLES][256]
Definition: sdr.h:1543
+ Here is the call graph for this function:

◆ run()

template<typename T >
void leansdr::fast_qpsk_receiver< T >::run ( )
inlinevirtual

Reimplemented from leansdr::runnable_common.

Definition at line 1378 of file sdr.h.

References leansdr::fast_qpsk_receiver< T >::polar::a, leansdr::cstln_amp, leansdr::fail(), leansdr::complex< T >::im, leansdr::auto_notch< T >::in, M_PI, leansdr::auto_notch< T >::out, leansdr::auto_notch< T >::phase, leansdr::fast_qpsk_receiver< T >::polar::r, and leansdr::complex< T >::re.

1379  {
1380  // Magic constants that work with the qa recordings.
1381  signed long freq_alpha = 0.04 * 65536;
1382  signed long freq_beta = 0.0012 * 256 * 65536 / omega * pll_adjustment;
1383 
1384  if (!freq_beta)
1385  fail("Excessive oversampling");
1386 
1387  float gain_mu = 0.02 / (cstln_amp * cstln_amp) * 2;
1388 
1389  int max_meas = chunk_size / meas_decimation + 1;
1390  // Largin margin on output_size because mu adjustments
1391  // can lead to more than chunk_size/min_omega symbols.
1392 
1393  while (in.readable() >= chunk_size + 1 && // +1 for interpolation
1394  out.writable() >= chunk_size && (!freq_out || freq_out->writable() >= max_meas) && (!cstln_out || cstln_out->writable() >= max_meas))
1395  {
1396  complex<T> *pin = in.rd(), *pin0 = pin, *pend = pin + chunk_size;
1397  hardsymbol *pout = out.wr(), *pout0 = pout;
1398 
1399  cu8 s;
1400  u_angle symbol_arg = 0; // Exported for constellation viewer
1401 
1402  while (pin < pend)
1403  {
1404  // Here mu is the time of the next symbol counted from 0 at pin.
1405  if (mu < 1)
1406  {
1407  // Here 0<=mu<1 is the fractional time of the next symbol
1408  // between pin and pin+1.
1409 
1410  // Derotate and interpolate
1411 #if 0 /* Phase only (does not work)
1412  Careful with the float/signed/unsigned casts */
1413  u_angle a0 = fast_arg(pin[0]) - phase;
1414  u_angle a1 = fast_arg(pin[1]) - (phase+freqw);
1415  s_angle da = a1 - a0;
1416  symbol_arg = a0 + (s_angle)(da*mu);
1417  s = arg_to_symbol(symbol_arg);
1418 #elif 1 // Linear by lookup-table. 1.2M on bench3bishs
1419  polar *p0 = &lut_polar[pin[0].re][pin[0].im];
1420  u_angle a0 = (u_angle)(p0->a - phase) >> (16 - RLUT_BITS);
1421  cu8 *p0r = &lut_rect[a0][p0->r >> 1];
1422  polar *p1 = &lut_polar[pin[1].re][pin[1].im];
1423  u_angle a1 = (u_angle)(p1->a - (phase + freqw)) >> (16 - RLUT_BITS);
1424  cu8 *p1r = &lut_rect[a1][p1->r >> 1];
1425  s.re = (int)(p0r->re + (p1r->re - p0r->re) * mu);
1426  s.im = (int)(p0r->im + (p1r->im - p0r->im) * mu);
1427  symbol_arg = fast_arg(s);
1428 #else // Linear floating-point, for reference
1429  float a0 = -(int)phase * M_PI / 32768;
1430  float cosa0 = cosf(a0), sina0 = sinf(a0);
1431  complex<float>
1432  p0r(((float)pin[0].re - 128) * cosa0 - ((float)pin[0].im - 128) * sina0,
1433  ((float)pin[0].re - 128) * sina0 + ((float)pin[0].im - 128) * cosa0);
1434  float a1 = -(int)(phase + freqw) * M_PI / 32768;
1435  float cosa1 = cosf(a1), sina1 = sinf(a1);
1436  complex<float>
1437  p1r(((float)pin[1].re - 128) * cosa1 - ((float)pin[1].im - 128) * sina1,
1438  ((float)pin[1].re - 128) * sina1 + ((float)pin[1].im - 128) * cosa1);
1439  s.re = (int)(128 + p0r.re + (p1r.re - p0r.re) * mu);
1440  s.im = (int)(128 + p0r.im + (p1r.im - p0r.im) * mu);
1441  symbol_arg = fast_arg(s);
1442 #endif
1443 
1444  int quadrant = symbol_arg >> 14;
1445  static unsigned char quadrant_to_symbol[4] = {0, 2, 3, 1};
1446  *pout = quadrant_to_symbol[quadrant];
1447  ++pout;
1448 
1449  // PLL
1450  s_angle phase_error = (s_angle)(symbol_arg & 16383) - 8192;
1451  phase += (phase_error * freq_alpha + 32768) >> 16;
1452  freqw += (phase_error * freq_beta + 32768 * 256) >> 24;
1453 
1454  // Modified Mueller and Müller
1455  // mu[k]=real((c[k]-c[k-2])*conj(p[k-1])-(p[k]-p[k-2])*conj(c[k-1]))
1456  // =dot(c[k]-c[k-2],p[k-1]) - dot(p[k]-p[k-2],c[k-1])
1457  // p = received signals
1458  // c = decisions (constellation points)
1459  hist[2] = hist[1];
1460  hist[1] = hist[0];
1461 #define HIST_FLOAT 0
1462 #if HIST_FLOAT
1463  hist[0].p.re = (float)s.re - 128;
1464  hist[0].p.im = (float)s.im - 128;
1465 
1466  cu8 cp = arg_to_symbol((symbol_arg & 49152) + 8192);
1467  hist[0].c.re = (float)cp.re - 128;
1468  hist[0].c.im = (float)cp.im - 128;
1469 
1470  float muerr =
1471  ((hist[0].p.re - hist[2].p.re) * hist[1].c.re +
1472  (hist[0].p.im - hist[2].p.im) * hist[1].c.im) -
1473  ((hist[0].c.re - hist[2].c.re) * hist[1].p.re +
1474  (hist[0].c.im - hist[2].c.im) * hist[1].p.im);
1475 #else
1476  hist[0].p = s;
1477  hist[0].c = arg_to_symbol((symbol_arg & 49152) + 8192);
1478 
1479  int muerr =
1480  ((signed char)(hist[0].p.re - hist[2].p.re) * ((int)hist[1].c.re - 128) + (signed char)(hist[0].p.im - hist[2].p.im) * ((int)hist[1].c.im - 128)) - ((signed char)(hist[0].c.re - hist[2].c.re) * ((int)hist[1].p.re - 128) + (signed char)(hist[0].c.im - hist[2].c.im) * ((int)hist[1].p.im - 128));
1481 #endif
1482  float mucorr = muerr * gain_mu;
1483  const float max_mucorr = 0.1;
1484  // TBD Optimize out statically
1485  if (mucorr < -max_mucorr)
1486  mucorr = -max_mucorr;
1487  if (mucorr > max_mucorr)
1488  mucorr = max_mucorr;
1489  mu += mucorr;
1490  mu += omega; // Next symbol time;
1491  } // mu<1
1492 
1493  // Next sample
1494  ++pin;
1495  --mu;
1496  phase += freqw;
1497  } // chunk_size
1498 
1499  in.read(pin - pin0);
1500  out.written(pout - pout0);
1501 
1502  if (symbol_arg && cstln_out)
1503  // Output the last interpolated PSK symbol, max once per chunk_size
1504  cstln_out->write(s);
1505 
1506  // This is best done periodically ouside the inner loop,
1507  // but will cause non-deterministic output.
1508 
1509  if (!allow_drift)
1510  {
1511  if (freqw < min_freqw || freqw > max_freqw)
1512  freqw = (max_freqw + min_freqw) / 2;
1513  }
1514 
1515  // Output measurements
1516 
1517  meas_count += pin - pin0;
1518 
1519  while (meas_count >= meas_decimation)
1520  {
1522 
1523  if (freq_out)
1524  freq_out->write((float)freqw / 65536);
1525  }
1526 
1527  } // Work to do
1528  }
static const unsigned int chunk_size
Definition: sdr.h:1329
static const int RLUT_BITS
Definition: sdr.h:1375
uint16_t u_angle
Definition: sdr.h:384
signed long min_freqw
Definition: sdr.h:1326
#define M_PI
Definition: rdsdemod.cpp:27
struct leansdr::fast_qpsk_receiver::@9 hist[3]
pipewriter< cu8 > * cstln_out
Definition: sdr.h:1597
int16_t s_angle
Definition: sdr.h:385
signed long max_freqw
Definition: sdr.h:1326
complex< u8 > cu8
Definition: sdr.h:30
unsigned long meas_decimation
Definition: sdr.h:1324
void fail(const char *s)
Definition: framework.cpp:11
unsigned long meas_count
Definition: sdr.h:1595
u_angle fast_arg(const cu8 &c)
Definition: sdr.h:1537
void written(unsigned long n)
Definition: framework.h:308
struct leansdr::fast_qpsk_receiver::polar lut_polar[256][256]
std::complex< Fixed< IntType, IntBits > > polar(const Fixed< IntType, IntBits > &rho, const Fixed< IntType, IntBits > &theta)
Definition: fixed.h:2409
void write(const T &e)
Definition: framework.h:319
pipewriter< hardsymbol > out
Definition: sdr.h:1592
const float cstln_amp
Definition: sdr.h:404
cu8 arg_to_symbol(u_angle a)
Definition: sdr.h:1546
pipewriter< float > * freq_out
Definition: sdr.h:1596
pipereader< cu8 > in
Definition: sdr.h:1591
cu8 lut_rect[RLUT_ANGLES][256]
Definition: sdr.h:1543
+ Here is the call graph for this function:

◆ set_freq()

template<typename T >
void leansdr::fast_qpsk_receiver< T >::set_freq ( float  freq)
inline

Definition at line 1361 of file sdr.h.

1362  {
1363  freqw = freq * 65536;
1365  }

◆ set_omega()

template<typename T >
void leansdr::fast_qpsk_receiver< T >::set_omega ( float  _omega,
float  tol = 10e-6 
)
inline

Definition at line 1353 of file sdr.h.

1354  {
1355  omega = _omega;
1356  min_omega = omega * (1 - tol);
1357  max_omega = omega * (1 + tol);
1359  }

◆ update_freq_limits()

template<typename T >
void leansdr::fast_qpsk_receiver< T >::update_freq_limits ( )
inline

Definition at line 1367 of file sdr.h.

1368  {
1369  // Prevent PLL from locking at +-symbolrate/4.
1370  // TODO The +-SR/8 limit is suitable for QPSK only.
1371  min_freqw = freqw - 65536 / max_omega / 8;
1372  max_freqw = freqw + 65536 / max_omega / 8;
1373  }
signed long min_freqw
Definition: sdr.h:1326
signed long max_freqw
Definition: sdr.h:1326

Member Data Documentation

◆ allow_drift

template<typename T >
bool leansdr::fast_qpsk_receiver< T >::allow_drift

Definition at line 1328 of file sdr.h.

◆ c

template<typename T >
cu8 leansdr::fast_qpsk_receiver< T >::c

Definition at line 1587 of file sdr.h.

◆ chunk_size

template<typename T >
const unsigned int leansdr::fast_qpsk_receiver< T >::chunk_size = 128
static

Definition at line 1329 of file sdr.h.

◆ cstln_out

template<typename T >
pipewriter<cu8>* leansdr::fast_qpsk_receiver< T >::cstln_out
private

Definition at line 1597 of file sdr.h.

◆ freq_out

template<typename T >
pipewriter<float>* leansdr::fast_qpsk_receiver< T >::freq_out
private

Definition at line 1596 of file sdr.h.

◆ freqw

template<typename T >
signed long leansdr::fast_qpsk_receiver< T >::freqw

Definition at line 1326 of file sdr.h.

◆ hist

struct { ... } leansdr::fast_qpsk_receiver< T >::hist[3]

◆ in

template<typename T >
pipereader<cu8> leansdr::fast_qpsk_receiver< T >::in
private

Definition at line 1591 of file sdr.h.

◆ lut_polar

template<typename T >
struct leansdr::fast_qpsk_receiver::polar leansdr::fast_qpsk_receiver< T >::lut_polar[256][256]
private

◆ lut_rect

template<typename T >
cu8 leansdr::fast_qpsk_receiver< T >::lut_rect[RLUT_ANGLES][256]
private

Definition at line 1543 of file sdr.h.

◆ lut_sincos

template<typename T >
cu8 leansdr::fast_qpsk_receiver< T >::lut_sincos[65536]
private

Definition at line 1544 of file sdr.h.

◆ max_freqw

template<typename T >
signed long leansdr::fast_qpsk_receiver< T >::max_freqw

Definition at line 1326 of file sdr.h.

◆ max_omega

template<typename T >
float leansdr::fast_qpsk_receiver< T >::max_omega

Definition at line 1325 of file sdr.h.

◆ meas_count

template<typename T >
unsigned long leansdr::fast_qpsk_receiver< T >::meas_count
private

Definition at line 1595 of file sdr.h.

◆ meas_decimation

template<typename T >
unsigned long leansdr::fast_qpsk_receiver< T >::meas_decimation

Definition at line 1324 of file sdr.h.

◆ mer_out

template<typename T >
pipewriter<float> * leansdr::fast_qpsk_receiver< T >::mer_out
private

Definition at line 1596 of file sdr.h.

◆ min_freqw

template<typename T >
signed long leansdr::fast_qpsk_receiver< T >::min_freqw

Definition at line 1326 of file sdr.h.

◆ min_omega

template<typename T >
float leansdr::fast_qpsk_receiver< T >::min_omega

Definition at line 1325 of file sdr.h.

◆ mu

template<typename T >
float leansdr::fast_qpsk_receiver< T >::mu
private

Definition at line 1593 of file sdr.h.

◆ omega

template<typename T >
float leansdr::fast_qpsk_receiver< T >::omega

Definition at line 1325 of file sdr.h.

◆ out

template<typename T >
pipewriter<hardsymbol> leansdr::fast_qpsk_receiver< T >::out
private

Definition at line 1592 of file sdr.h.

◆ p

template<typename T >
cu8 leansdr::fast_qpsk_receiver< T >::p

Definition at line 1586 of file sdr.h.

◆ phase

template<typename T >
u_angle leansdr::fast_qpsk_receiver< T >::phase
private

Definition at line 1594 of file sdr.h.

◆ pll_adjustment

template<typename T >
float leansdr::fast_qpsk_receiver< T >::pll_adjustment

Definition at line 1327 of file sdr.h.

◆ RLUT_ANGLES

template<typename T >
const int leansdr::fast_qpsk_receiver< T >::RLUT_ANGLES = 1 << RLUT_BITS
static

Definition at line 1376 of file sdr.h.

◆ RLUT_BITS

template<typename T >
const int leansdr::fast_qpsk_receiver< T >::RLUT_BITS = 8
static

Definition at line 1375 of file sdr.h.


The documentation for this struct was generated from the following file: