mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-17 13:51:47 -05:00
DATV demod: leandvb: replace custom complex by std::complex
This commit is contained in:
parent
a066e4dbc1
commit
207115bc4c
@ -115,14 +115,14 @@ template<typename T> struct datvconstellation: runnable
|
|||||||
long pixels_per_frame;
|
long pixels_per_frame;
|
||||||
cstln_lut<eucl_ss, 256> **cstln; // Optional ptr to optional constellation
|
cstln_lut<eucl_ss, 256> **cstln; // Optional ptr to optional constellation
|
||||||
TVScreen *m_objDATVScreen;
|
TVScreen *m_objDATVScreen;
|
||||||
pipereader<complex<T> > in;
|
pipereader<std::complex<T> > in;
|
||||||
unsigned long phase;
|
unsigned long phase;
|
||||||
std::vector<int> cstln_rows;
|
std::vector<int> cstln_rows;
|
||||||
std::vector<int> cstln_cols;
|
std::vector<int> cstln_cols;
|
||||||
|
|
||||||
datvconstellation(
|
datvconstellation(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T> > &_in,
|
pipebuf<std::complex<T> > &_in,
|
||||||
T _xymin,
|
T _xymin,
|
||||||
T _xymax,
|
T _xymax,
|
||||||
const char *_name = nullptr,
|
const char *_name = nullptr,
|
||||||
@ -148,13 +148,13 @@ template<typename T> struct datvconstellation: runnable
|
|||||||
{
|
{
|
||||||
m_objDATVScreen->resetImage();
|
m_objDATVScreen->resetImage();
|
||||||
|
|
||||||
complex<T> *p = in.rd(), *pend = p + pixels_per_frame;
|
std::complex<T> *p = in.rd(), *pend = p + pixels_per_frame;
|
||||||
|
|
||||||
for (; p < pend; ++p)
|
for (; p < pend; ++p)
|
||||||
{
|
{
|
||||||
m_objDATVScreen->selectRow(256 * (p->re - xymin) / (xymax - xymin));
|
m_objDATVScreen->selectRow(256 * (p->real() - xymin) / (xymax - xymin));
|
||||||
m_objDATVScreen->setDataColor(
|
m_objDATVScreen->setDataColor(
|
||||||
256 - 256 * ((p->im - xymin) / (xymax - xymin)),
|
256 - 256 * ((p->imag() - xymin) / (xymax - xymin)),
|
||||||
255, 0, 255);
|
255, 0, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,9 +197,9 @@ template<typename T> struct datvconstellation: runnable
|
|||||||
|
|
||||||
for (int i = 0; i < (*cstln)->nsymbols; ++i)
|
for (int i = 0; i < (*cstln)->nsymbols; ++i)
|
||||||
{
|
{
|
||||||
complex<signed char> *p = &(*cstln)->symbols[i];
|
std::complex<signed char> *p = &(*cstln)->symbols[i];
|
||||||
int x = 256 * (p->re - xymin) / (xymax - xymin);
|
int x = 256 * (p->real() - xymin) / (xymax - xymin);
|
||||||
int y = 256 - 256 * (p->im - xymin) / (xymax - xymin);
|
int y = 256 - 256 * (p->imag() - xymin) / (xymax - xymin);
|
||||||
|
|
||||||
for (int d = -4; d <= 4; ++d)
|
for (int d = -4; d <= 4; ++d)
|
||||||
{
|
{
|
||||||
|
@ -1289,9 +1289,9 @@ void DATVDemodSink::feed(const SampleVector::const_iterator& begin, const Sample
|
|||||||
|
|
||||||
for (int intI = 0 ; intI < intRFOut; intI++)
|
for (int intI = 0 ; intI < intRFOut; intI++)
|
||||||
{
|
{
|
||||||
objIQ.re = objRF->real();
|
objIQ.real(objRF->real());
|
||||||
objIQ.im = objRF->imag();
|
objIQ.imag(objRF->imag());
|
||||||
magSq = objIQ.re*objIQ.re + objIQ.im*objIQ.im;
|
magSq = objIQ.real() * objIQ.real() + objIQ.imag() * objIQ.imag();
|
||||||
m_objMagSqAverage(magSq);
|
m_objMagSqAverage(magSq);
|
||||||
|
|
||||||
objRF ++;
|
objRF ++;
|
||||||
|
@ -119,14 +119,14 @@ template<typename T> struct datvdvbs2constellation: runnable
|
|||||||
long pixels_per_frame;
|
long pixels_per_frame;
|
||||||
/*cstln_lut<llr_ss, 256>*/ cstln_base **cstln; // Optional ptr to optional constellation
|
/*cstln_lut<llr_ss, 256>*/ cstln_base **cstln; // Optional ptr to optional constellation
|
||||||
TVScreen *m_objDATVScreen;
|
TVScreen *m_objDATVScreen;
|
||||||
pipereader<complex<T> > in;
|
pipereader<std::complex<T> > in;
|
||||||
unsigned long phase;
|
unsigned long phase;
|
||||||
std::vector<int> cstln_rows;
|
std::vector<int> cstln_rows;
|
||||||
std::vector<int> cstln_cols;
|
std::vector<int> cstln_cols;
|
||||||
|
|
||||||
datvdvbs2constellation(
|
datvdvbs2constellation(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T> > &_in,
|
pipebuf<std::complex<T> > &_in,
|
||||||
T _xymin,
|
T _xymin,
|
||||||
T _xymax,
|
T _xymax,
|
||||||
const char *_name = nullptr,
|
const char *_name = nullptr,
|
||||||
@ -154,13 +154,13 @@ template<typename T> struct datvdvbs2constellation: runnable
|
|||||||
{
|
{
|
||||||
m_objDATVScreen->resetImage();
|
m_objDATVScreen->resetImage();
|
||||||
|
|
||||||
complex<T> *p = in.rd(), *pend = p + pixels_per_frame;
|
std::complex<T> *p = in.rd(), *pend = p + pixels_per_frame;
|
||||||
|
|
||||||
for (; p < pend; ++p)
|
for (; p < pend; ++p)
|
||||||
{
|
{
|
||||||
m_objDATVScreen->selectRow(256 * (p->re - xymin) / (xymax - xymin));
|
m_objDATVScreen->selectRow(256 * (p->real() - xymin) / (xymax - xymin));
|
||||||
m_objDATVScreen->setDataColor(
|
m_objDATVScreen->setDataColor(
|
||||||
256 - 256 * ((p->im - xymin) / (xymax - xymin)),
|
256 - 256 * ((p->imag() - xymin) / (xymax - xymin)),
|
||||||
255, 0, 255);
|
255, 0, 255);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,9 +203,9 @@ template<typename T> struct datvdvbs2constellation: runnable
|
|||||||
|
|
||||||
for (int i = 0; i < (*cstln)->nsymbols; ++i)
|
for (int i = 0; i < (*cstln)->nsymbols; ++i)
|
||||||
{
|
{
|
||||||
complex<signed char> *p = &(*cstln)->symbols[i];
|
std::complex<signed char> *p = &(*cstln)->symbols[i];
|
||||||
int x = 256 * (p->re - xymin) / (xymax - xymin);
|
int x = 256 * (p->real() - xymin) / (xymax - xymin);
|
||||||
int y = 256 - 256 * (p->im - xymin) / (xymax - xymin);
|
int y = 256 - 256 * (p->imag() - xymin) / (xymax - xymin);
|
||||||
|
|
||||||
for (int d = -4; d <= 4; ++d)
|
for (int d = -4; d <= 4; ++d)
|
||||||
{
|
{
|
||||||
|
@ -28,15 +28,15 @@ namespace leansdr
|
|||||||
// DSP blocks
|
// DSP blocks
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// [cconverter] converts complex streams between numric types,
|
// [cconverter] converts std::complex streams between numric types,
|
||||||
// with optional ofsetting and rational scaling.
|
// with optional ofsetting and rational scaling.
|
||||||
template <typename Tin, int Zin, typename Tout, int Zout, int Gn, int Gd>
|
template <typename Tin, int Zin, typename Tout, int Zout, int Gn, int Gd>
|
||||||
struct cconverter : runnable
|
struct cconverter : runnable
|
||||||
{
|
{
|
||||||
cconverter(
|
cconverter(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<Tin>> &_in,
|
pipebuf<std::complex<Tin>> &_in,
|
||||||
pipebuf<complex<Tout>> &_out
|
pipebuf<std::complex<Tout>> &_out
|
||||||
) :
|
) :
|
||||||
runnable(sch, "cconverter"),
|
runnable(sch, "cconverter"),
|
||||||
in(_in),
|
in(_in),
|
||||||
@ -47,8 +47,8 @@ struct cconverter : runnable
|
|||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
unsigned long count = min(in.readable(), out.writable());
|
unsigned long count = min(in.readable(), out.writable());
|
||||||
complex<Tin> *pin = in.rd(), *pend = pin + count;
|
std::complex<Tin> *pin = in.rd(), *pend = pin + count;
|
||||||
complex<Tout> *pout = out.wr();
|
std::complex<Tout> *pout = out.wr();
|
||||||
|
|
||||||
for (; pin < pend; ++pin, ++pout)
|
for (; pin < pend; ++pin, ++pout)
|
||||||
{
|
{
|
||||||
@ -61,8 +61,8 @@ struct cconverter : runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<complex<Tin>> in;
|
pipereader<std::complex<Tin>> in;
|
||||||
pipewriter<complex<Tout>> out;
|
pipewriter<std::complex<Tout>> out;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -109,18 +109,22 @@ struct cfft_engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Float constants
|
// Float constants
|
||||||
omega = new complex<T>[n];
|
omega = new std::complex<T>[n];
|
||||||
omega_rev = new complex<T>[n];
|
omega_rev = new std::complex<T>[n];
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
float a = 2.0 * M_PI * i / n;
|
float a = 2.0 * M_PI * i / n;
|
||||||
omega_rev[i].re = (omega[i].re = cosf(a));
|
omega_rev[i].real(cosf(a));
|
||||||
omega_rev[i].im = -(omega[i].im = sinf(a));
|
omega[i].real(cosf(a));
|
||||||
|
omega_rev[i].imag(sinf(a));
|
||||||
|
omega[i].imag(sinf(a));
|
||||||
|
// omega_rev[i].re = (omega[i].re = cosf(a));
|
||||||
|
// omega_rev[i].im = -(omega[i].im = sinf(a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void inplace(complex<T> *data, bool reverse = false)
|
void inplace(std::complex<T> *data, bool reverse = false)
|
||||||
{
|
{
|
||||||
// Bit-reversal permutation
|
// Bit-reversal permutation
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
@ -129,13 +133,13 @@ struct cfft_engine
|
|||||||
|
|
||||||
if (r < i)
|
if (r < i)
|
||||||
{
|
{
|
||||||
complex<T> tmp = data[i];
|
std::complex<T> tmp = data[i];
|
||||||
data[i] = data[r];
|
data[i] = data[r];
|
||||||
data[r] = tmp;
|
data[r] = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<T> *om = reverse ? omega_rev : omega;
|
std::complex<T> *om = reverse ? omega_rev : omega;
|
||||||
// Danielson-Lanczos
|
// Danielson-Lanczos
|
||||||
for (int i = 0; i < logn; ++i)
|
for (int i = 0; i < logn; ++i)
|
||||||
{
|
{
|
||||||
@ -148,14 +152,14 @@ struct cfft_engine
|
|||||||
|
|
||||||
for (int k = 0; k < hbs; ++k)
|
for (int k = 0; k < hbs; ++k)
|
||||||
{
|
{
|
||||||
complex<T> &w = om[k * dom];
|
std::complex<T> &w = om[k * dom];
|
||||||
complex<T> &dqk = data[q + k];
|
std::complex<T> &dqk = data[q + k];
|
||||||
complex<T> x(w.re * dqk.re - w.im * dqk.im,
|
std::complex<T> x(w.real() * dqk.real() - w.imag() * dqk.imag(),
|
||||||
w.re * dqk.im + w.im * dqk.re);
|
w.real() * dqk.imag() + w.imag() * dqk.real());
|
||||||
data[q + k].re = data[p + k].re - x.re;
|
data[q + k].real(data[p + k].real() - x.real());
|
||||||
data[q + k].im = data[p + k].im - x.im;
|
data[q + k].imag(data[p + k].imag() - x.imag());
|
||||||
data[p + k].re = data[p + k].re + x.re;
|
data[p + k].real(data[p + k].real() + x.real());
|
||||||
data[p + k].im = data[p + k].im + x.im;
|
data[p + k].imag(data[p + k].imag() + x.imag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,10 +168,8 @@ struct cfft_engine
|
|||||||
{
|
{
|
||||||
float invn = 1.0 / n;
|
float invn = 1.0 / n;
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i) {
|
||||||
{
|
data[i] *= invn;
|
||||||
data[i].re *= invn;
|
|
||||||
data[i].im *= invn;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -187,8 +189,8 @@ struct cfft_engine
|
|||||||
}
|
}
|
||||||
|
|
||||||
int *bitrev;
|
int *bitrev;
|
||||||
complex<T> *omega;
|
std::complex<T> *omega;
|
||||||
complex<T> *omega_rev;
|
std::complex<T> *omega_rev;
|
||||||
int n;
|
int n;
|
||||||
float invsqrtn;
|
float invsqrtn;
|
||||||
int logn;
|
int logn;
|
||||||
@ -275,14 +277,14 @@ struct scaler : runnable
|
|||||||
pipewriter<Tout> out;
|
pipewriter<Tout> out;
|
||||||
};
|
};
|
||||||
|
|
||||||
// [awgb_c] generates complex white gaussian noise.
|
// [awgb_c] generates std::complex white gaussian noise.
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct wgn_c : runnable
|
struct wgn_c : runnable
|
||||||
{
|
{
|
||||||
wgn_c(
|
wgn_c(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T>>
|
pipebuf<std::complex<T>>
|
||||||
&_out
|
&_out
|
||||||
) :
|
) :
|
||||||
runnable(sch, "awgn"),
|
runnable(sch, "awgn"),
|
||||||
@ -294,7 +296,7 @@ struct wgn_c : runnable
|
|||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
int n = out.writable();
|
int n = out.writable();
|
||||||
complex<T> *pout = out.wr(), *pend = pout + n;
|
std::complex<T> *pout = out.wr(), *pend = pout + n;
|
||||||
|
|
||||||
while (pout < pend)
|
while (pout < pend)
|
||||||
{
|
{
|
||||||
@ -319,7 +321,7 @@ struct wgn_c : runnable
|
|||||||
float stddev;
|
float stddev;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pipewriter<complex<T>> out;
|
pipewriter<std::complex<T>> out;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -453,9 +455,9 @@ struct fir_filter : runnable
|
|||||||
{
|
{
|
||||||
float a = 2 * M_PI * f * (i - ncoeffs / 2.0);
|
float a = 2 * M_PI * f * (i - ncoeffs / 2.0);
|
||||||
float c = cosf(a), s = sinf(a);
|
float c = cosf(a), s = sinf(a);
|
||||||
// TBD Support T=complex
|
// TBD Support T=std::complex
|
||||||
shifted_coeffs[i].re = coeffs[i] * c;
|
shifted_coeffs[i].real(coeffs[i] * c);
|
||||||
shifted_coeffs[i].im = coeffs[i] * s;
|
shifted_coeffs[i].imag(coeffs[i] * s);
|
||||||
}
|
}
|
||||||
current_freq = f;
|
current_freq = f;
|
||||||
}
|
}
|
||||||
@ -556,7 +558,7 @@ struct fir_resampler : runnable
|
|||||||
{
|
{
|
||||||
float a = 2 * M_PI * f * i;
|
float a = 2 * M_PI * f * i;
|
||||||
float c = cosf(a), s = sinf(a);
|
float c = cosf(a), s = sinf(a);
|
||||||
// TBD Support T=complex
|
// TBD Support T=std::complex
|
||||||
shifted_coeffs[i].re = coeffs[i] * c;
|
shifted_coeffs[i].re = coeffs[i] * c;
|
||||||
shifted_coeffs[i].im = coeffs[i] * s;
|
shifted_coeffs[i].im = coeffs[i] * s;
|
||||||
}
|
}
|
||||||
|
@ -1733,8 +1733,8 @@ struct viterbi_sync : runnable
|
|||||||
|
|
||||||
for (int i = 0; i < cstln->nsymbols; ++i)
|
for (int i = 0; i < cstln->nsymbols; ++i)
|
||||||
{
|
{
|
||||||
int8_t I = cstln->symbols[i].re;
|
int8_t I = cstln->symbols[i].real();
|
||||||
int8_t Q = cstln->symbols[i].im;
|
int8_t Q = cstln->symbols[i].imag();
|
||||||
|
|
||||||
if (conj)
|
if (conj)
|
||||||
Q = -Q;
|
Q = -Q;
|
||||||
|
@ -81,15 +81,15 @@ struct s2_sof
|
|||||||
static const uint32_t VALUE = 0x18d2e82;
|
static const uint32_t VALUE = 0x18d2e82;
|
||||||
static const uint32_t MASK = 0x3ffffff;
|
static const uint32_t MASK = 0x3ffffff;
|
||||||
static const int LENGTH = 26;
|
static const int LENGTH = 26;
|
||||||
complex<T> symbols[LENGTH];
|
std::complex<T> symbols[LENGTH];
|
||||||
|
|
||||||
s2_sof()
|
s2_sof()
|
||||||
{
|
{
|
||||||
for (int s = 0; s < LENGTH; ++s)
|
for (int s = 0; s < LENGTH; ++s)
|
||||||
{
|
{
|
||||||
int angle = ((VALUE >> (LENGTH - 1 - s)) & 1) * 2 + (s & 1); // pi/2-BPSK
|
int angle = ((VALUE >> (LENGTH - 1 - s)) & 1) * 2 + (s & 1); // pi/2-BPSK
|
||||||
symbols[s].re = cstln_amp * cosf(M_PI / 4 + 2 * M_PI * angle / 4);
|
symbols[s].real(cstln_amp * cosf(M_PI / 4 + 2 * M_PI * angle / 4));
|
||||||
symbols[s].im = cstln_amp * sinf(M_PI / 4 + 2 * M_PI * angle / 4);
|
symbols[s].imag(cstln_amp * sinf(M_PI / 4 + 2 * M_PI * angle / 4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}; // s2_sof
|
}; // s2_sof
|
||||||
@ -105,7 +105,7 @@ struct s2_plscodes
|
|||||||
static const int COUNT = 128;
|
static const int COUNT = 128;
|
||||||
static const int LENGTH = 64;
|
static const int LENGTH = 64;
|
||||||
uint64_t codewords[COUNT];
|
uint64_t codewords[COUNT];
|
||||||
complex<T> symbols[COUNT][LENGTH];
|
std::complex<T> symbols[COUNT][LENGTH];
|
||||||
|
|
||||||
s2_plscodes()
|
s2_plscodes()
|
||||||
{
|
{
|
||||||
@ -149,8 +149,8 @@ struct s2_plscodes
|
|||||||
{
|
{
|
||||||
int yi = (code >> (LENGTH - 1 - i)) & 1;
|
int yi = (code >> (LENGTH - 1 - i)) & 1;
|
||||||
int nyi = yi ^ (i & 1);
|
int nyi = yi ^ (i & 1);
|
||||||
symbols[index][i].re = cstln_amp * (1 - 2 * nyi) / sqrtf(2);
|
symbols[index][i].real(cstln_amp * (1 - 2 * nyi) / sqrtf(2));
|
||||||
symbols[index][i].im = cstln_amp * (1 - 2 * yi) / sqrtf(2);
|
symbols[index][i].imag(cstln_amp * (1 - 2 * yi) / sqrtf(2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,10 +166,12 @@ template<typename T>
|
|||||||
struct s2_pilot
|
struct s2_pilot
|
||||||
{
|
{
|
||||||
static const int LENGTH = PILOT_LENGTH;
|
static const int LENGTH = PILOT_LENGTH;
|
||||||
complex<T> symbol;
|
std::complex<T> symbol;
|
||||||
|
|
||||||
s2_pilot() {
|
s2_pilot()
|
||||||
symbol.re = symbol.im = cstln_amp*0.707107;
|
{
|
||||||
|
symbol.real(cstln_amp*0.707107);
|
||||||
|
symbol.imag(cstln_amp*0.707107);
|
||||||
}
|
}
|
||||||
}; // s2_pilot
|
}; // s2_pilot
|
||||||
|
|
||||||
@ -375,21 +377,21 @@ struct s2_frame_transmitter : runnable
|
|||||||
s2_frame_transmitter(
|
s2_frame_transmitter(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<plslot<hard_ss>> &_in,
|
pipebuf<plslot<hard_ss>> &_in,
|
||||||
pipebuf<complex<T>> &_out
|
pipebuf<std::complex<T>> &_out
|
||||||
) :
|
) :
|
||||||
runnable(sch, "S2 frame transmitter"),
|
runnable(sch, "S2 frame transmitter"),
|
||||||
in(_in),
|
in(_in),
|
||||||
out(_out, modcod_info::MAX_SYMBOLS_PER_FRAME)
|
out(_out, modcod_info::MAX_SYMBOLS_PER_FRAME)
|
||||||
{
|
{
|
||||||
float amp = cstln_amp / sqrtf(2);
|
float amp = cstln_amp / sqrtf(2);
|
||||||
qsymbols[0].re = +amp;
|
qsymbols[0].real() = +amp;
|
||||||
qsymbols[0].im = +amp;
|
qsymbols[0].imag() = +amp;
|
||||||
qsymbols[1].re = +amp;
|
qsymbols[1].real() = +amp;
|
||||||
qsymbols[1].im = -amp;
|
qsymbols[1].imag() = -amp;
|
||||||
qsymbols[2].re = -amp;
|
qsymbols[2].real() = -amp;
|
||||||
qsymbols[2].im = +amp;
|
qsymbols[2].imag() = +amp;
|
||||||
qsymbols[3].re = -amp;
|
qsymbols[3].real() = -amp;
|
||||||
qsymbols[3].im = -amp;
|
qsymbols[3].imag() = -amp;
|
||||||
|
|
||||||
// Clear the constellation cache.
|
// Clear the constellation cache.
|
||||||
for (int i = 0; i < 32; ++i) {
|
for (int i = 0; i < 32; ++i) {
|
||||||
@ -443,10 +445,10 @@ struct s2_frame_transmitter : runnable
|
|||||||
const modcod_info *mcinfo,
|
const modcod_info *mcinfo,
|
||||||
const plslot<hard_ss> *pin,
|
const plslot<hard_ss> *pin,
|
||||||
int nslots,
|
int nslots,
|
||||||
complex<T> *pout
|
std::complex<T> *pout
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
complex<T> *pout0 = pout; // For sanity check
|
std::complex<T> *pout0 = pout; // For sanity check
|
||||||
// PLHEADER: SOF AND PLSCODE
|
// PLHEADER: SOF AND PLSCODE
|
||||||
// EN 302 307-1 section 5.5.2 PL signalling
|
// EN 302 307-1 section 5.5.2 PL signalling
|
||||||
memcpy(pout, sof.symbols, sof.LENGTH * sizeof(*pout));
|
memcpy(pout, sof.symbols, sof.LENGTH * sizeof(*pout));
|
||||||
@ -454,7 +456,7 @@ struct s2_frame_transmitter : runnable
|
|||||||
int pls_index = (pls->modcod << 2) | (pls->sf << 1) | pls->pilots;
|
int pls_index = (pls->modcod << 2) | (pls->sf << 1) | pls->pilots;
|
||||||
memcpy(pout, plscodes.symbols[pls_index], plscodes.LENGTH * sizeof(*pout));
|
memcpy(pout, plscodes.symbols[pls_index], plscodes.LENGTH * sizeof(*pout));
|
||||||
pout += plscodes.LENGTH;
|
pout += plscodes.LENGTH;
|
||||||
complex<T> *csymbols = get_csymbols(pls->modcod);
|
std::complex<T> *csymbols = get_csymbols(pls->modcod);
|
||||||
// Slots and pilots
|
// Slots and pilots
|
||||||
int till_next_pilot = pls->pilots ? 16 : nslots;
|
int till_next_pilot = pls->pilots ? 16 : nslots;
|
||||||
uint8_t *scr = &scrambling.Rn[0];
|
uint8_t *scr = &scrambling.Rn[0];
|
||||||
@ -485,7 +487,7 @@ struct s2_frame_transmitter : runnable
|
|||||||
return pout - pout0;
|
return pout - pout0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void scramble(const complex<T> *src, uint8_t r, complex<T> *dst)
|
inline void scramble(const std::complex<T> *src, uint8_t r, std::complex<T> *dst)
|
||||||
{
|
{
|
||||||
switch (r)
|
switch (r)
|
||||||
{
|
{
|
||||||
@ -508,10 +510,10 @@ struct s2_frame_transmitter : runnable
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<plslot<hard_ss>> in;
|
pipereader<plslot<hard_ss>> in;
|
||||||
pipewriter<complex<T>> out;
|
pipewriter<std::complex<T>> out;
|
||||||
complex<T> *pcsymbols[32]; // Constellations in use, indexed by modcod
|
std::complex<T> *pcsymbols[32]; // Constellations in use, indexed by modcod
|
||||||
|
|
||||||
complex<T> *get_csymbols(int modcod)
|
std::complex<T> *get_csymbols(int modcod)
|
||||||
{
|
{
|
||||||
if (!pcsymbols[modcod])
|
if (!pcsymbols[modcod])
|
||||||
{
|
{
|
||||||
@ -536,19 +538,19 @@ struct s2_frame_transmitter : runnable
|
|||||||
mcinfo->g3
|
mcinfo->g3
|
||||||
);
|
);
|
||||||
|
|
||||||
pcsymbols[modcod] = new complex<T>[cstln.nsymbols];
|
pcsymbols[modcod] = new std::complex<T>[cstln.nsymbols];
|
||||||
|
|
||||||
for ( int s=0; s<cstln.nsymbols; ++s )
|
for ( int s=0; s<cstln.nsymbols; ++s )
|
||||||
{
|
{
|
||||||
pcsymbols[modcod][s].re = cstln.symbols[s].re;
|
pcsymbols[modcod][s].real() = cstln.symbols[s].real();
|
||||||
pcsymbols[modcod][s].im = cstln.symbols[s].im;
|
pcsymbols[modcod][s].imag() = cstln.symbols[s].imag();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pcsymbols[modcod];
|
return pcsymbols[modcod];
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<T> qsymbols[4]; // RMS cstln_amp
|
std::complex<T> qsymbols[4]; // RMS cstln_amp
|
||||||
s2_sof<T> sof;
|
s2_sof<T> sof;
|
||||||
s2_plscodes<T> plscodes;
|
s2_plscodes<T> plscodes;
|
||||||
s2_scrambling scrambling;
|
s2_scrambling scrambling;
|
||||||
@ -577,14 +579,14 @@ struct s2_frame_receiver : runnable
|
|||||||
s2_frame_receiver(
|
s2_frame_receiver(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
sampler_interface<T> *_sampler,
|
sampler_interface<T> *_sampler,
|
||||||
pipebuf< complex<T> > &_in,
|
pipebuf< std::complex<T> > &_in,
|
||||||
pipebuf< plslot<SOFTSYMB> > &_out,
|
pipebuf< plslot<SOFTSYMB> > &_out,
|
||||||
pipebuf<float> *_freq_out=NULL,
|
pipebuf<float> *_freq_out=NULL,
|
||||||
pipebuf<float> *_ss_out=NULL,
|
pipebuf<float> *_ss_out=NULL,
|
||||||
pipebuf<float> *_mer_out=NULL,
|
pipebuf<float> *_mer_out=NULL,
|
||||||
pipebuf< complex<float> > *_cstln_out=NULL,
|
pipebuf< std::complex<float> > *_cstln_out=NULL,
|
||||||
pipebuf< complex<float> > *_cstln_pls_out=NULL,
|
pipebuf< std::complex<float> > *_cstln_pls_out=NULL,
|
||||||
pipebuf< complex<float> > *_symbols_out=NULL,
|
pipebuf< std::complex<float> > *_symbols_out=NULL,
|
||||||
pipebuf<int> *_state_out=NULL
|
pipebuf<int> *_state_out=NULL
|
||||||
) :
|
) :
|
||||||
runnable(sch, "S2 frame receiver"),
|
runnable(sch, "S2 frame receiver"),
|
||||||
@ -662,7 +664,7 @@ struct s2_frame_receiver : runnable
|
|||||||
// Useful for looking ahead (e.g. next pilots/SOF) then rewinding.
|
// Useful for looking ahead (e.g. next pilots/SOF) then rewinding.
|
||||||
|
|
||||||
struct sampler_state {
|
struct sampler_state {
|
||||||
complex<T> *p; // Pointer to samples (update when entering run())
|
std::complex<T> *p; // Pointer to samples (update when entering run())
|
||||||
float mu; // Time of next symbol, counted from p
|
float mu; // Time of next symbol, counted from p
|
||||||
float omega; // Samples per symbol
|
float omega; // Samples per symbol
|
||||||
float gain; // Scaling factor toward cstln_amp
|
float gain; // Scaling factor toward cstln_amp
|
||||||
@ -689,7 +691,7 @@ struct s2_frame_receiver : runnable
|
|||||||
sprintf(
|
sprintf(
|
||||||
buf,
|
buf,
|
||||||
"%9.2lf %+6.0f ppm %+3.0f ° %f",
|
"%9.2lf %+6.0f ppm %+3.0f ° %f",
|
||||||
(double)((p-(complex<T>*)NULL)&262143)+mu, // Arbitrary wrap
|
(double)((p-(std::complex<T>*)NULL)&262143)+mu, // Arbitrary wrap
|
||||||
fw16*1e6/65536,
|
fw16*1e6/65536,
|
||||||
fmodfs(ph16,65536.0f)*360/65536,
|
fmodfs(ph16,65536.0f)*360/65536,
|
||||||
gain
|
gain
|
||||||
@ -857,7 +859,7 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
void run_frame_probe_locked()
|
void run_frame_probe_locked()
|
||||||
{
|
{
|
||||||
complex<float> *psampled; // Data symbols (one per slot)
|
std::complex<float> *psampled; // Data symbols (one per slot)
|
||||||
|
|
||||||
if (cstln_out && cstln_out->writable()>=1024) {
|
if (cstln_out && cstln_out->writable()>=1024) {
|
||||||
psampled = cstln_out->wr();
|
psampled = cstln_out->wr();
|
||||||
@ -865,7 +867,7 @@ struct s2_frame_receiver : runnable
|
|||||||
psampled = NULL;
|
psampled = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<float> *psampled_pls; // PLHEADER symbols
|
std::complex<float> *psampled_pls; // PLHEADER symbols
|
||||||
|
|
||||||
if (cstln_pls_out && cstln_pls_out->writable()>=1024) {
|
if (cstln_pls_out && cstln_pls_out->writable()>=1024) {
|
||||||
psampled_pls = cstln_pls_out->wr();
|
psampled_pls = cstln_pls_out->wr();
|
||||||
@ -873,7 +875,7 @@ struct s2_frame_receiver : runnable
|
|||||||
psampled_pls = NULL;
|
psampled_pls = NULL;
|
||||||
}
|
}
|
||||||
#if TEST_DIVERSITY
|
#if TEST_DIVERSITY
|
||||||
complex<float> *psymbols = symbols_out ? symbols_out->wr() : NULL;
|
std::complex<float> *psymbols = symbols_out ? symbols_out->wr() : NULL;
|
||||||
float scale_symbols = 1.0 / cstln_amp;
|
float scale_symbols = 1.0 / cstln_amp;
|
||||||
#endif
|
#endif
|
||||||
sampler_state ss = ss_cache;
|
sampler_state ss = ss_cache;
|
||||||
@ -886,11 +888,11 @@ struct s2_frame_receiver : runnable
|
|||||||
// Interpolate PLHEADER.
|
// Interpolate PLHEADER.
|
||||||
|
|
||||||
const int PLH_LENGTH = sof.LENGTH + plscodes.LENGTH;
|
const int PLH_LENGTH = sof.LENGTH + plscodes.LENGTH;
|
||||||
complex<float> plh_symbols[PLH_LENGTH];
|
std::complex<float> plh_symbols[PLH_LENGTH];
|
||||||
|
|
||||||
for (int s=0; s<PLH_LENGTH; ++s)
|
for (int s=0; s<PLH_LENGTH; ++s)
|
||||||
{
|
{
|
||||||
complex<float> p = interp_next(&ss) * ss.gain;
|
std::complex<float> p = interp_next(&ss) * ss.gain;
|
||||||
plh_symbols[s] = p;
|
plh_symbols[s] = p;
|
||||||
|
|
||||||
if (psampled_pls) {
|
if (psampled_pls) {
|
||||||
@ -905,10 +907,10 @@ struct s2_frame_receiver : runnable
|
|||||||
// Optimization with half loop and even/odd processing in a single step
|
// Optimization with half loop and even/odd processing in a single step
|
||||||
for (int i = 0; i < sof.LENGTH/2; ++i)
|
for (int i = 0; i < sof.LENGTH/2; ++i)
|
||||||
{
|
{
|
||||||
complex<float> p0 = plh_symbols[2*i];
|
std::complex<float> p0 = plh_symbols[2*i];
|
||||||
complex<float> p1 = plh_symbols[2*i+1];
|
std::complex<float> p1 = plh_symbols[2*i+1];
|
||||||
float d0 = p0.im + p0.re;
|
float d0 = p0.imag() + p0.real();
|
||||||
float d1 = p1.im - p1.re;
|
float d1 = p1.imag() - p1.real();
|
||||||
sof_bits = (sof_bits<<2) | ((d0<0)<<1) | (d1<0);
|
sof_bits = (sof_bits<<2) | ((d0<0)<<1) | (d1<0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -934,10 +936,10 @@ struct s2_frame_receiver : runnable
|
|||||||
// Optimization with half loop and even/odd processing in a single step
|
// Optimization with half loop and even/odd processing in a single step
|
||||||
for (int i=0; i<plscodes.LENGTH/2; ++i)
|
for (int i=0; i<plscodes.LENGTH/2; ++i)
|
||||||
{
|
{
|
||||||
complex<float> p0 = plh_symbols[sof.LENGTH+2*i];
|
std::complex<float> p0 = plh_symbols[sof.LENGTH+2*i];
|
||||||
complex<float> p1 = plh_symbols[sof.LENGTH+2*i+1];
|
std::complex<float> p1 = plh_symbols[sof.LENGTH+2*i+1];
|
||||||
float d0 = p0.im + p0.re;
|
float d0 = p0.imag() + p0.real();
|
||||||
float d1 = p1.im - p1.re;
|
float d1 = p1.imag() - p1.real();
|
||||||
plscode = (plscode<<2) | ((d0<0)<<1) | (d1<0);
|
plscode = (plscode<<2) | ((d0<0)<<1) | (d1<0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -984,7 +986,7 @@ struct s2_frame_receiver : runnable
|
|||||||
// ss now points to first data slot.
|
// ss now points to first data slot.
|
||||||
ss.scr = scrambling.Rn;
|
ss.scr = scrambling.Rn;
|
||||||
|
|
||||||
complex<float> plh_expected[PLH_LENGTH];
|
std::complex<float> plh_expected[PLH_LENGTH];
|
||||||
|
|
||||||
std::copy(sof.symbols, sof.symbols + sof.LENGTH, plh_expected);
|
std::copy(sof.symbols, sof.symbols + sof.LENGTH, plh_expected);
|
||||||
std::copy(plscodes.symbols[plscode_index], plscodes.symbols[plscode_index] + plscodes.LENGTH, &plh_expected[sof.LENGTH]);
|
std::copy(plscodes.symbols[plscode_index], plscodes.symbols[plscode_index] + plscodes.LENGTH, &plh_expected[sof.LENGTH]);
|
||||||
@ -1254,7 +1256,7 @@ struct s2_frame_receiver : runnable
|
|||||||
// Read slot.
|
// Read slot.
|
||||||
freq_stats.add(ss.fw16);
|
freq_stats.add(ss.fw16);
|
||||||
pout->is_pls = false;
|
pout->is_pls = false;
|
||||||
complex<float> p; // Export last symbols for cstln_out
|
std::complex<float> p; // Export last symbols for cstln_out
|
||||||
|
|
||||||
for (int s=0; s<pout->LENGTH; ++s)
|
for (int s=0; s<pout->LENGTH; ++s)
|
||||||
{
|
{
|
||||||
@ -1267,11 +1269,11 @@ struct s2_frame_receiver : runnable
|
|||||||
(void) track_symbol(&ss, p, dcstln); // SLOW
|
(void) track_symbol(&ss, p, dcstln); // SLOW
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<float> d = descramble(&ss, p);
|
std::complex<float> d = descramble(&ss, p);
|
||||||
#if 1 // Slow
|
#if 1 // Slow
|
||||||
SOFTSYMB *symb = &dcstln->lookup(d.re, d.im)->ss;
|
SOFTSYMB *symb = &dcstln->lookup(d.real(), d.imag())->ss;
|
||||||
#else // Avoid scaling floats. May wrap at very low SNR.
|
#else // Avoid scaling floats. May wrap at very low SNR.
|
||||||
SOFTSYMB *symb = &dcstln->lookup((int)d.re, (int)d.im)->ss;
|
SOFTSYMB *symb = &dcstln->lookup((int)d.real(), (int)d.imag())->ss;
|
||||||
#endif
|
#endif
|
||||||
pout->symbols[s] = *symb;
|
pout->symbols[s] = *symb;
|
||||||
}
|
}
|
||||||
@ -1356,7 +1358,7 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
float find_plheader(sampler_state *pss, int search_range)
|
float find_plheader(sampler_state *pss, int search_range)
|
||||||
{
|
{
|
||||||
complex<T> best_corr = 0;
|
std::complex<T> best_corr = 0;
|
||||||
int best_imu = 0; // Avoid compiler warning.
|
int best_imu = 0; // Avoid compiler warning.
|
||||||
int best_pos = 0; // Avoid compiler warning.
|
int best_pos = 0; // Avoid compiler warning.
|
||||||
|
|
||||||
@ -1371,15 +1373,15 @@ struct s2_frame_receiver : runnable
|
|||||||
delete[] diffs;
|
delete[] diffs;
|
||||||
}
|
}
|
||||||
|
|
||||||
diffs = new complex<T>[ndiffs];
|
diffs = new std::complex<T>[ndiffs];
|
||||||
sampler_state ss = *pss;
|
sampler_state ss = *pss;
|
||||||
ss.mu += imu * ss.omega / interp;
|
ss.mu += imu * ss.omega / interp;
|
||||||
|
|
||||||
// Compute rotation between consecutive symbols.
|
// Compute rotation between consecutive symbols.
|
||||||
complex<T> prev = 0;
|
std::complex<T> prev = 0;
|
||||||
for (int i=0; i<ndiffs; ++i)
|
for (int i=0; i<ndiffs; ++i)
|
||||||
{
|
{
|
||||||
complex<T> p = interp_next(&ss);
|
std::complex<T> p = interp_next(&ss);
|
||||||
diffs[i] = conjprod(prev, p);
|
diffs[i] = conjprod(prev, p);
|
||||||
prev = p;
|
prev = p;
|
||||||
}
|
}
|
||||||
@ -1388,10 +1390,10 @@ struct s2_frame_receiver : runnable
|
|||||||
const int ncorrs = search_range;
|
const int ncorrs = search_range;
|
||||||
for (int i=0; i<ncorrs; ++i)
|
for (int i=0; i<ncorrs; ++i)
|
||||||
{
|
{
|
||||||
complex<T> c = correlate_plheader_diff(&diffs[i]);
|
std::complex<T> c = correlate_plheader_diff(&diffs[i]);
|
||||||
//if ( cnorm2(c) > cnorm2(best_corr) ) {
|
//if ( cnorm2(c) > cnorm2(best_corr) ) {
|
||||||
// c.im>0 enforces frequency error +-Fm/4
|
// c.imag()>0 enforces frequency error +-Fm/4
|
||||||
if (cnorm2(c)>cnorm2(best_corr) && c.im>0)
|
if (cnorm2(c)>cnorm2(best_corr) && c.imag()>0)
|
||||||
{
|
{
|
||||||
best_corr = c;
|
best_corr = c;
|
||||||
best_imu = imu;
|
best_imu = imu;
|
||||||
@ -1407,14 +1409,14 @@ struct s2_frame_receiver : runnable
|
|||||||
#if 0
|
#if 0
|
||||||
// Lowpass-filter the differential correlator.
|
// Lowpass-filter the differential correlator.
|
||||||
// (Does not help much.)
|
// (Does not help much.)
|
||||||
static complex<float> acc = 0;
|
static std::complex<float> acc = 0;
|
||||||
static const float k = 0.05;
|
static const float k = 0.05;
|
||||||
acc = best_corr*k + acc*(1-k);
|
acc = best_corr*k + acc*(1-k);
|
||||||
best_corr = acc;
|
best_corr = acc;
|
||||||
#endif
|
#endif
|
||||||
// Get rough estimate of carrier frequency from differential correlator.
|
// Get rough estimate of carrier frequency from differential correlator.
|
||||||
// (best_corr is nominally +j).
|
// (best_corr is nominally +j).
|
||||||
float freqw = atan2f(-best_corr.re, best_corr.im);
|
float freqw = atan2f(-best_corr.real(), best_corr.imag());
|
||||||
pss->fw16 += freqw * 65536 / (2*M_PI);
|
pss->fw16 += freqw * 65536 / (2*M_PI);
|
||||||
// Force refresh because correction may be large.
|
// Force refresh because correction may be large.
|
||||||
sampler->update_freq(pss->fw16/omega0);
|
sampler->update_freq(pss->fw16/omega0);
|
||||||
@ -1427,7 +1429,7 @@ struct s2_frame_receiver : runnable
|
|||||||
{
|
{
|
||||||
sampler_state ss = *pss;
|
sampler_state ss = *pss;
|
||||||
float power = 0;
|
float power = 0;
|
||||||
complex<T> symbs[sof.LENGTH];
|
std::complex<T> symbs[sof.LENGTH];
|
||||||
|
|
||||||
for (int i=0; i<sof.LENGTH; ++i)
|
for (int i=0; i<sof.LENGTH; ++i)
|
||||||
{
|
{
|
||||||
@ -1435,7 +1437,7 @@ struct s2_frame_receiver : runnable
|
|||||||
power += cnorm2(symbs[i]);
|
power += cnorm2(symbs[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<float> c = conjprod(sof.symbols, symbs, sof.LENGTH);
|
std::complex<float> c = conjprod(sof.symbols, symbs, sof.LENGTH);
|
||||||
c *= 1.0f / sof.LENGTH;
|
c *= 1.0f / sof.LENGTH;
|
||||||
align_phase(pss, c);
|
align_phase(pss, c);
|
||||||
float signal_amp = sqrtf(power/sof.LENGTH);
|
float signal_amp = sqrtf(power/sof.LENGTH);
|
||||||
@ -1448,22 +1450,22 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
// Correlate PLHEADER.
|
// Correlate PLHEADER.
|
||||||
|
|
||||||
complex<float> correlate_plheader_diff(complex<T> *diffs)
|
std::complex<float> correlate_plheader_diff(std::complex<T> *diffs)
|
||||||
{
|
{
|
||||||
complex<T> csof = correlate_sof_diff(diffs);
|
std::complex<T> csof = correlate_sof_diff(diffs);
|
||||||
complex<T> cplsc = correlate_plscode_diff(&diffs[sof.LENGTH]);
|
std::complex<T> cplsc = correlate_plscode_diff(&diffs[sof.LENGTH]);
|
||||||
// Use csof+cplsc or csof-cplsc, whichever maximizes likelihood.
|
// Use csof+cplsc or csof-cplsc, whichever maximizes likelihood.
|
||||||
complex<T> c0 = csof + cplsc; // Best when b7==0 (pilots off)
|
std::complex<T> c0 = csof + cplsc; // Best when b7==0 (pilots off)
|
||||||
complex<T> c1 = csof - cplsc; // Best when b7==1 (pilots on)
|
std::complex<T> c1 = csof - cplsc; // Best when b7==1 (pilots on)
|
||||||
complex<T> c = (cnorm2(c0)>cnorm2(c1)) ? c0 : c1;
|
std::complex<T> c = (cnorm2(c0)>cnorm2(c1)) ? c0 : c1;
|
||||||
return c * (1.0f/(26-1+64/2));
|
return c * (1.0f/(26-1+64/2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Correlate 25 differential transitions in SOF.
|
// Correlate 25 differential transitions in SOF.
|
||||||
|
|
||||||
complex<float> correlate_sof_diff(complex<T> *diffs)
|
std::complex<float> correlate_sof_diff(std::complex<T> *diffs)
|
||||||
{
|
{
|
||||||
complex<T> c = 0;
|
std::complex<T> c = 0;
|
||||||
const uint32_t dsof = sof.VALUE ^ (sof.VALUE>>1);
|
const uint32_t dsof = sof.VALUE ^ (sof.VALUE>>1);
|
||||||
|
|
||||||
for (int i=0; i<sof.LENGTH; ++i)
|
for (int i=0; i<sof.LENGTH; ++i)
|
||||||
@ -1484,9 +1486,9 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
// Correlate 32 data-independent transitions in PLSCODE.
|
// Correlate 32 data-independent transitions in PLSCODE.
|
||||||
|
|
||||||
complex<float> correlate_plscode_diff(complex<T> *diffs)
|
std::complex<float> correlate_plscode_diff(std::complex<T> *diffs)
|
||||||
{
|
{
|
||||||
complex<T> c = 0;
|
std::complex<T> c = 0;
|
||||||
uint64_t dscr = plscodes.SCRAMBLING ^ (plscodes.SCRAMBLING>>1);
|
uint64_t dscr = plscodes.SCRAMBLING ^ (plscodes.SCRAMBLING>>1);
|
||||||
|
|
||||||
for (int i=1; i<plscodes.LENGTH; i+=2)
|
for (int i=1; i<plscodes.LENGTH; i+=2)
|
||||||
@ -1534,8 +1536,8 @@ struct s2_frame_receiver : runnable
|
|||||||
// spans less than 90°.
|
// spans less than 90°.
|
||||||
|
|
||||||
void match_freq(
|
void match_freq(
|
||||||
complex<float> *expect,
|
std::complex<float> *expect,
|
||||||
complex<float> *recv,
|
std::complex<float> *recv,
|
||||||
int ns,
|
int ns,
|
||||||
sampler_state *ss)
|
sampler_state *ss)
|
||||||
{
|
{
|
||||||
@ -1543,16 +1545,16 @@ struct s2_frame_receiver : runnable
|
|||||||
fprintf(stderr, "match_freq\n");
|
fprintf(stderr, "match_freq\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<float> diff = 0;
|
std::complex<float> diff = 0;
|
||||||
|
|
||||||
for (int i=0; i<ns-1; ++i)
|
for (int i=0; i<ns-1; ++i)
|
||||||
{
|
{
|
||||||
complex<float> de = conjprod(expect[i], expect[i+1]);
|
std::complex<float> de = conjprod(expect[i], expect[i+1]);
|
||||||
complex<float> dr = conjprod(recv[i], recv[i+1]);
|
std::complex<float> dr = conjprod(recv[i], recv[i+1]);
|
||||||
diff += conjprod(de, dr);
|
diff += conjprod(de, dr);
|
||||||
}
|
}
|
||||||
|
|
||||||
float dfw16 = atan2f(diff.im,diff.re) * 65536 / (2*M_PI);
|
float dfw16 = atan2f(diff.imag(),diff.real()) * 65536 / (2*M_PI);
|
||||||
|
|
||||||
// Derotate.
|
// Derotate.
|
||||||
for (int i=0; i<ns; ++i) {
|
for (int i=0; i<ns; ++i) {
|
||||||
@ -1568,15 +1570,15 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
float interp_match_pilot(sampler_state *pss)
|
float interp_match_pilot(sampler_state *pss)
|
||||||
{
|
{
|
||||||
complex<T> symbols[pilot.LENGTH];
|
std::complex<T> symbols[pilot.LENGTH];
|
||||||
complex<T> expected[pilot.LENGTH];
|
std::complex<T> expected[pilot.LENGTH];
|
||||||
|
|
||||||
for (int i=0; i<pilot.LENGTH; ++i)
|
for (int i=0; i<pilot.LENGTH; ++i)
|
||||||
{
|
{
|
||||||
complex<float> p = interp_next(pss) * pss->gain;
|
std::complex<float> p = interp_next(pss) * pss->gain;
|
||||||
symbols[i] = descramble(pss, p);
|
symbols[i] = descramble(pss, p);
|
||||||
expected[i] = pilot.symbol;
|
expected[i] = pilot.symbol;
|
||||||
//fprintf(stderr, "%f %f\n", symbols[i].re, symbols[i].im);
|
//fprintf(stderr, "%f %f\n", symbols[i].real(), symbols[i].imag());
|
||||||
}
|
}
|
||||||
|
|
||||||
return match_ph_amp(expected, symbols, pilot.LENGTH, pss);
|
return match_ph_amp(expected, symbols, pilot.LENGTH, pss);
|
||||||
@ -1587,7 +1589,7 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
float interp_match_sof(sampler_state *pss)
|
float interp_match_sof(sampler_state *pss)
|
||||||
{
|
{
|
||||||
complex<T> symbols[pilot.LENGTH];
|
std::complex<T> symbols[pilot.LENGTH];
|
||||||
|
|
||||||
for (int i=0; i<sof.LENGTH; ++i) {
|
for (int i=0; i<sof.LENGTH; ++i) {
|
||||||
symbols[i] = interp_next(pss) * pss->gain;
|
symbols[i] = interp_next(pss) * pss->gain;
|
||||||
@ -1606,27 +1608,27 @@ struct s2_frame_receiver : runnable
|
|||||||
// Idempotent.
|
// Idempotent.
|
||||||
|
|
||||||
float match_ph_amp(
|
float match_ph_amp(
|
||||||
complex<float> *expect,
|
std::complex<float> *expect,
|
||||||
complex<float> *recv,
|
std::complex<float> *recv,
|
||||||
int ns,
|
int ns,
|
||||||
sampler_state *ss
|
sampler_state *ss
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
complex<float> rr = 0;
|
std::complex<float> rr = 0;
|
||||||
|
|
||||||
for (int i=0; i<ns; ++i) {
|
for (int i=0; i<ns; ++i) {
|
||||||
rr += conjprod(expect[i], recv[i]);
|
rr += conjprod(expect[i], recv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
rr *= 1.0f / (ns*cstln_amp);
|
rr *= 1.0f / (ns*cstln_amp);
|
||||||
float dph16 = atan2f(rr.im,rr.re) * 65536 / (2*M_PI);
|
float dph16 = atan2f(rr.imag(),rr.real()) * 65536 / (2*M_PI);
|
||||||
ss->ph16 += dph16;
|
ss->ph16 += dph16;
|
||||||
rr *= trig.expi(-dph16);
|
rr *= trig.expi(-dph16);
|
||||||
// rr.re is now the modulation amplitude.
|
// rr.real() is now the modulation amplitude.
|
||||||
float dgain = cstln_amp / rr.re;
|
float dgain = cstln_amp / rr.real();
|
||||||
ss->gain *= dgain;
|
ss->gain *= dgain;
|
||||||
// Rotate and scale. Compute error power.
|
// Rotate and scale. Compute error power.
|
||||||
complex<float> adj = trig.expi(-dph16) * dgain;
|
std::complex<float> adj = trig.expi(-dph16) * dgain;
|
||||||
float ev2 = 0;
|
float ev2 = 0;
|
||||||
|
|
||||||
for (int i=0; i<ns; ++i)
|
for (int i=0; i<ns; ++i)
|
||||||
@ -1680,11 +1682,11 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
for (int s = 0; s < ns; ++s)
|
for (int s = 0; s < ns; ++s)
|
||||||
{
|
{
|
||||||
complex<float> p = interp_next(&ssl) * ssl.gain;
|
std::complex<float> p = interp_next(&ssl) * ssl.gain;
|
||||||
typename cstln_lut<SOFTSYMB,256>::result *cr =
|
typename cstln_lut<SOFTSYMB,256>::result *cr =
|
||||||
dcstln->lookup(p.re, p.im);
|
dcstln->lookup(p.real(), p.imag());
|
||||||
complex<int8_t> &cp = dcstln->symbols[cr->symbol];
|
std::complex<int8_t> &cp = dcstln->symbols[cr->symbol];
|
||||||
complex<float> ev(p.re-cp.re, p.im-cp.im);
|
std::complex<float> ev(p.real()-cp.real(), p.imag()-cp.imag());
|
||||||
err += cnorm2(ev);
|
err += cnorm2(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1718,24 +1720,24 @@ struct s2_frame_receiver : runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<float> descramble(sampler_state *ss, const complex<float> &p)
|
std::complex<float> descramble(sampler_state *ss, const std::complex<float> &p)
|
||||||
{
|
{
|
||||||
int r = *ss->scr++;
|
int r = *ss->scr++;
|
||||||
complex<float> res;
|
std::complex<float> res;
|
||||||
|
|
||||||
switch (r)
|
switch (r)
|
||||||
{
|
{
|
||||||
case 3:
|
case 3:
|
||||||
res.re = -p.im;
|
res.real(-p.imag());
|
||||||
res.im = p.re;
|
res.imag(p.real());
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
res.re = -p.re;
|
res.real(-p.real());
|
||||||
res.im = -p.im;
|
res.imag(-p.imag());
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
res.re = p.im;
|
res.real(p.imag());
|
||||||
res.im = -p.re;
|
res.imag(-p.real());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
res = p;
|
res = p;
|
||||||
@ -1746,7 +1748,7 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
// Interpolator
|
// Interpolator
|
||||||
|
|
||||||
inline complex<float> interp_next(sampler_state *ss)
|
inline std::complex<float> interp_next(sampler_state *ss)
|
||||||
{
|
{
|
||||||
// Skip to next sample
|
// Skip to next sample
|
||||||
while (ss->mu >= 1)
|
while (ss->mu >= 1)
|
||||||
@ -1759,16 +1761,16 @@ struct s2_frame_receiver : runnable
|
|||||||
// Interpolate linearly then derotate.
|
// Interpolate linearly then derotate.
|
||||||
// This will fail with large carrier offsets (e.g. --tune).
|
// This will fail with large carrier offsets (e.g. --tune).
|
||||||
float cmu = 1.0f - ss->mu;
|
float cmu = 1.0f - ss->mu;
|
||||||
complex<float> s(ss->p[0].re*cmu + ss->p[1].re*ss->mu,
|
std::complex<float> s(ss->p[0].real()*cmu + ss->p[1].real()*ss->mu,
|
||||||
ss->p[0].im*cmu + ss->p[1].im*ss->mu);
|
ss->p[0].imag()*cmu + ss->p[1].imag()*ss->mu);
|
||||||
ss->mu += ss->omega;
|
ss->mu += ss->omega;
|
||||||
// Derotate
|
// Derotate
|
||||||
const complex<float> &rot = trig.expi(-ss->ph16);
|
const std::complex<float> &rot = trig.expi(-ss->ph16);
|
||||||
ss->ph16 += ss->fw16;
|
ss->ph16 += ss->fw16;
|
||||||
return rot * s;
|
return rot * s;
|
||||||
#else
|
#else
|
||||||
// Use generic interpolator
|
// Use generic interpolator
|
||||||
complex<float> s = sampler->interp(ss->p, ss->mu, ss->ph16);
|
std::complex<float> s = sampler->interp(ss->p, ss->mu, ss->ph16);
|
||||||
ss->mu += ss->omega;
|
ss->mu += ss->omega;
|
||||||
ss->ph16 += ss->fw16;
|
ss->ph16 += ss->fw16;
|
||||||
return s;
|
return s;
|
||||||
@ -1777,22 +1779,22 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
// Adjust phase in [ss] to cancel offset observed as [c].
|
// Adjust phase in [ss] to cancel offset observed as [c].
|
||||||
|
|
||||||
void align_phase(sampler_state *ss, const complex<float> &c)
|
void align_phase(sampler_state *ss, const std::complex<float> &c)
|
||||||
{
|
{
|
||||||
float err = atan2f(c.im,c.re) * 65536 / (2*M_PI);
|
float err = atan2f(c.imag(),c.real()) * 65536 / (2*M_PI);
|
||||||
ss->ph16 += err;
|
ss->ph16 += err;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint8_t track_symbol(
|
inline uint8_t track_symbol(
|
||||||
sampler_state *ss,
|
sampler_state *ss,
|
||||||
const complex<float> &p,
|
const std::complex<float> &p,
|
||||||
cstln_lut<SOFTSYMB,256> *c
|
cstln_lut<SOFTSYMB,256> *c
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
static const float kph = 4e-2;
|
static const float kph = 4e-2;
|
||||||
static const float kfw = 1e-4;
|
static const float kfw = 1e-4;
|
||||||
// Decision
|
// Decision
|
||||||
typename cstln_lut<SOFTSYMB,256>::result *cr = c->lookup(p.re, p.im);
|
typename cstln_lut<SOFTSYMB,256>::result *cr = c->lookup(p.real(), p.imag());
|
||||||
// Carrier tracking
|
// Carrier tracking
|
||||||
ss->ph16 += cr->phase_error * kph;
|
ss->ph16 += cr->phase_error * kph;
|
||||||
ss->fw16 += cr->phase_error * kfw;
|
ss->fw16 += cr->phase_error * kfw;
|
||||||
@ -1848,13 +1850,13 @@ struct s2_frame_receiver : runnable
|
|||||||
|
|
||||||
cstln_lut<SOFTSYMB,256> *cstln; // Last seen, or NULL (legacy)
|
cstln_lut<SOFTSYMB,256> *cstln; // Last seen, or NULL (legacy)
|
||||||
trig16 trig;
|
trig16 trig;
|
||||||
pipereader< complex<T> > in;
|
pipereader< std::complex<T> > in;
|
||||||
pipewriter< plslot<SOFTSYMB> > out;
|
pipewriter< plslot<SOFTSYMB> > out;
|
||||||
int meas_count;
|
int meas_count;
|
||||||
pipewriter<float> *freq_out, *ss_out, *mer_out;
|
pipewriter<float> *freq_out, *ss_out, *mer_out;
|
||||||
pipewriter< complex<float> > *cstln_out;
|
pipewriter< std::complex<float> > *cstln_out;
|
||||||
pipewriter< complex<float> > *cstln_pls_out;
|
pipewriter< std::complex<float> > *cstln_pls_out;
|
||||||
pipewriter< complex<float> > *symbols_out;
|
pipewriter< std::complex<float> > *symbols_out;
|
||||||
pipewriter<int> *state_out;
|
pipewriter<int> *state_out;
|
||||||
bool first_run;
|
bool first_run;
|
||||||
// S2 constants
|
// S2 constants
|
||||||
@ -1868,7 +1870,7 @@ struct s2_frame_receiver : runnable
|
|||||||
bool m_locked;
|
bool m_locked;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
complex<T> *diffs;
|
std::complex<T> *diffs;
|
||||||
sampler_state *sspilots;
|
sampler_state *sspilots;
|
||||||
}; // s2_frame_receiver
|
}; // s2_frame_receiver
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ void normalize_power(int n, T *coeffs, float gain = 1)
|
|||||||
float s2 = 0;
|
float s2 = 0;
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
s2 = s2 + coeffs[i] * coeffs[i]; // TBD complex
|
s2 = s2 + coeffs[i] * coeffs[i]; // TBD std::complex
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s2) {
|
if (s2) {
|
||||||
|
@ -260,7 +260,7 @@ struct file_printer : runnable
|
|||||||
|
|
||||||
// [file_carrayprinter] writes all data available from a [pipebuf]
|
// [file_carrayprinter] writes all data available from a [pipebuf]
|
||||||
// to a file descriptor on a single line.
|
// to a file descriptor on a single line.
|
||||||
// Special case for complex.
|
// Special case for std::complex.
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct file_carrayprinter : runnable
|
struct file_carrayprinter : runnable
|
||||||
@ -271,7 +271,7 @@ struct file_carrayprinter : runnable
|
|||||||
const char *_format,
|
const char *_format,
|
||||||
const char *_sep,
|
const char *_sep,
|
||||||
const char *_tail,
|
const char *_tail,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
int _fdout
|
int _fdout
|
||||||
) :
|
) :
|
||||||
runnable(sch, _in.name),
|
runnable(sch, _in.name),
|
||||||
@ -299,7 +299,7 @@ struct file_carrayprinter : runnable
|
|||||||
if (fout)
|
if (fout)
|
||||||
{
|
{
|
||||||
fprintf(fout, head, n);
|
fprintf(fout, head, n);
|
||||||
complex<T> *pin = in.rd();
|
std::complex<T> *pin = in.rd();
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i)
|
for (int i = 0; i < n; ++i)
|
||||||
{
|
{
|
||||||
@ -307,7 +307,7 @@ struct file_carrayprinter : runnable
|
|||||||
fprintf(fout, "%s", sep);
|
fprintf(fout, "%s", sep);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fout, format, pin[i].re * scale, pin[i].im * scale);
|
fprintf(fout, format, pin[i].real() * scale, pin[i].imag() * scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fout, "%s", tail);
|
fprintf(fout, "%s", tail);
|
||||||
@ -322,7 +322,7 @@ struct file_carrayprinter : runnable
|
|||||||
int fixed_size; // Number of elements per batch, or 0.
|
int fixed_size; // Number of elements per batch, or 0.
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
const char *head, *format, *sep, *tail;
|
const char *head, *format, *sep, *tail;
|
||||||
FILE *fout;
|
FILE *fout;
|
||||||
};
|
};
|
||||||
|
@ -182,7 +182,7 @@ struct cscope : runnable
|
|||||||
unsigned long decimation;
|
unsigned long decimation;
|
||||||
unsigned long pixels_per_frame;
|
unsigned long pixels_per_frame;
|
||||||
cstln_base **cstln; // Optional ptr to optional constellation
|
cstln_base **cstln; // Optional ptr to optional constellation
|
||||||
cscope(scheduler *sch, pipebuf<complex<T>> &_in, T _xymin, T _xymax,
|
cscope(scheduler *sch, pipebuf<std::complex<T>> &_in, T _xymin, T _xymax,
|
||||||
const char *_name = NULL)
|
const char *_name = NULL)
|
||||||
: runnable(sch, _name ? _name : _in.name),
|
: runnable(sch, _name ? _name : _in.name),
|
||||||
xymin(_xymin), xymax(_xymax),
|
xymin(_xymin), xymax(_xymax),
|
||||||
@ -199,7 +199,7 @@ struct cscope : runnable
|
|||||||
{
|
{
|
||||||
draw_begin();
|
draw_begin();
|
||||||
g.setfg(0, 255, 0);
|
g.setfg(0, 255, 0);
|
||||||
complex<T> *p = in.rd(), *pend = p + pixels_per_frame;
|
std::complex<T> *p = in.rd(), *pend = p + pixels_per_frame;
|
||||||
for (; p < pend; ++p)
|
for (; p < pend; ++p)
|
||||||
g.point(g.w * (p->re - xymin) / (xymax - xymin),
|
g.point(g.w * (p->re - xymin) / (xymax - xymin),
|
||||||
g.h - g.h * (p->im - xymin) / (xymax - xymin));
|
g.h - g.h * (p->im - xymin) / (xymax - xymin));
|
||||||
@ -209,7 +209,7 @@ struct cscope : runnable
|
|||||||
g.setfg(255, 255, 255);
|
g.setfg(255, 255, 255);
|
||||||
for (int i = 0; i < (*cstln)->nsymbols; ++i)
|
for (int i = 0; i < (*cstln)->nsymbols; ++i)
|
||||||
{
|
{
|
||||||
complex<signed char> *p = &(*cstln)->symbols[i];
|
std::complex<signed char> *p = &(*cstln)->symbols[i];
|
||||||
int x = g.w * (p->re - xymin) / (xymax - xymin);
|
int x = g.w * (p->re - xymin) / (xymax - xymin);
|
||||||
int y = g.h - g.h * (p->im - xymin) / (xymax - xymin);
|
int y = g.h - g.h * (p->im - xymin) / (xymax - xymin);
|
||||||
for (int d = -2; d <= 2; ++d)
|
for (int d = -2; d <= 2; ++d)
|
||||||
@ -228,7 +228,7 @@ struct cscope : runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//private:
|
//private:
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
unsigned long phase;
|
unsigned long phase;
|
||||||
gfx g;
|
gfx g;
|
||||||
void draw_begin()
|
void draw_begin()
|
||||||
@ -459,7 +459,7 @@ struct spectrumscope : runnable
|
|||||||
unsigned long size;
|
unsigned long size;
|
||||||
float amax;
|
float amax;
|
||||||
unsigned long decimation;
|
unsigned long decimation;
|
||||||
spectrumscope(scheduler *sch, pipebuf<complex<T>> &_in,
|
spectrumscope(scheduler *sch, pipebuf<std::complex<T>> &_in,
|
||||||
T _max, const char *_name = NULL)
|
T _max, const char *_name = NULL)
|
||||||
: runnable(sch, _name ? _name : _in.name),
|
: runnable(sch, _name ? _name : _in.name),
|
||||||
size(4096), amax(_max / sqrtf(size)),
|
size(4096), amax(_max / sqrtf(size)),
|
||||||
@ -488,14 +488,14 @@ struct spectrumscope : runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
static const int MAX_MARKERS = 4;
|
static const int MAX_MARKERS = 4;
|
||||||
float markers[MAX_MARKERS];
|
float markers[MAX_MARKERS];
|
||||||
int nmarkers;
|
int nmarkers;
|
||||||
int phase;
|
int phase;
|
||||||
gfx g;
|
gfx g;
|
||||||
cfft_engine<float> *fft;
|
cfft_engine<float> *fft;
|
||||||
void do_fft(complex<T> *input)
|
void do_fft(std::complex<T> *input)
|
||||||
{
|
{
|
||||||
draw_begin();
|
draw_begin();
|
||||||
if (!fft || fft->n != size)
|
if (!fft || fft->n != size)
|
||||||
@ -504,8 +504,8 @@ struct spectrumscope : runnable
|
|||||||
delete fft;
|
delete fft;
|
||||||
fft = new cfft_engine<float>(size);
|
fft = new cfft_engine<float>(size);
|
||||||
}
|
}
|
||||||
complex<T> *pin = input, *pend = pin + size;
|
std::complex<T> *pin = input, *pend = pin + size;
|
||||||
complex<float> data[size], *pout = data;
|
std::complex<float> data[size], *pout = data;
|
||||||
g.setfg(255, 0, 0);
|
g.setfg(255, 0, 0);
|
||||||
for (int x = 0; pin < pend; ++pin, ++pout, ++x)
|
for (int x = 0; pin < pend; ++pin, ++pout, ++x)
|
||||||
{
|
{
|
||||||
@ -518,9 +518,9 @@ struct spectrumscope : runnable
|
|||||||
for (int i = 0; i < size; ++i)
|
for (int i = 0; i < size; ++i)
|
||||||
{
|
{
|
||||||
int x = ((i < size / 2) ? i + size / 2 : i - size / 2) * g.w / size;
|
int x = ((i < size / 2) ? i + size / 2 : i - size / 2) * g.w / size;
|
||||||
complex<float> v = data[i];
|
std::complex<float> v = data[i];
|
||||||
;
|
;
|
||||||
float y = hypot(v.re, v.im);
|
float y = hypot(v.real(), v.imag());
|
||||||
g.line(x, g.h - 1, x, g.h - 1 - y * g.h / amax);
|
g.line(x, g.h - 1, x, g.h - 1 - y * g.h / amax);
|
||||||
}
|
}
|
||||||
if (g.buttons)
|
if (g.buttons)
|
||||||
@ -559,7 +559,7 @@ struct rfscope : runnable
|
|||||||
float hzoom; // Horizontal zoom factor
|
float hzoom; // Horizontal zoom factor
|
||||||
float db0, dbrange; // Vertical range db0 .. db0+dbrange
|
float db0, dbrange; // Vertical range db0 .. db0+dbrange
|
||||||
float bw; // Smoothing bandwidth
|
float bw; // Smoothing bandwidth
|
||||||
rfscope(scheduler *sch, pipebuf<complex<T>> &_in,
|
rfscope(scheduler *sch, pipebuf<std::complex<T>> &_in,
|
||||||
const char *_name = NULL)
|
const char *_name = NULL)
|
||||||
: runnable(sch, _name ? _name : _in.name),
|
: runnable(sch, _name ? _name : _in.name),
|
||||||
size(4096), decimation(DEFAULT_GUI_DECIMATION),
|
size(4096), decimation(DEFAULT_GUI_DECIMATION),
|
||||||
@ -581,13 +581,13 @@ struct rfscope : runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
int phase;
|
int phase;
|
||||||
gfx g;
|
gfx g;
|
||||||
cfft_engine<float> *fft;
|
cfft_engine<float> *fft;
|
||||||
float *filtered;
|
float *filtered;
|
||||||
|
|
||||||
void do_fft(complex<T> *input)
|
void do_fft(std::complex<T> *input)
|
||||||
{
|
{
|
||||||
g.events();
|
g.events();
|
||||||
draw_begin();
|
draw_begin();
|
||||||
@ -597,9 +597,9 @@ struct rfscope : runnable
|
|||||||
delete fft;
|
delete fft;
|
||||||
fft = new cfft_engine<float>(size);
|
fft = new cfft_engine<float>(size);
|
||||||
}
|
}
|
||||||
// Convert to complex<float> and transform
|
// Convert to std::complex<float> and transform
|
||||||
complex<T> *pin = input, *pend = pin + size;
|
std::complex<T> *pin = input, *pend = pin + size;
|
||||||
complex<float> data[size], *pout = data;
|
std::complex<float> data[size], *pout = data;
|
||||||
for (int x = 0; pin < pend; ++pin, ++pout, ++x)
|
for (int x = 0; pin < pend; ++pin, ++pout, ++x)
|
||||||
{
|
{
|
||||||
pout->re = (float)pin->re;
|
pout->re = (float)pin->re;
|
||||||
@ -609,9 +609,9 @@ struct rfscope : runnable
|
|||||||
float amp2[size];
|
float amp2[size];
|
||||||
for (int i = 0; i < size; ++i)
|
for (int i = 0; i < size; ++i)
|
||||||
{
|
{
|
||||||
complex<float> &v = data[i];
|
std::complex<float> &v = data[i];
|
||||||
;
|
;
|
||||||
amp2[i] = (v.re * v.re + v.im * v.im) * size;
|
amp2[i] = (v.real() * v.real() + v.imag() * v.imag()) * size;
|
||||||
}
|
}
|
||||||
if (!filtered)
|
if (!filtered)
|
||||||
{
|
{
|
||||||
|
@ -18,76 +18,12 @@
|
|||||||
#define LEANSDR_MATH_H
|
#define LEANSDR_MATH_H
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <complex>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace leansdr
|
namespace leansdr
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct complex
|
|
||||||
{
|
|
||||||
T re, im;
|
|
||||||
|
|
||||||
complex() {}
|
|
||||||
|
|
||||||
complex(T x) : re(x), im(0) {}
|
|
||||||
complex(T x, T y) : re(x), im(y) {}
|
|
||||||
|
|
||||||
inline void operator+=(const complex<T> &x)
|
|
||||||
{
|
|
||||||
re += x.re;
|
|
||||||
im += x.im;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void operator*=(const complex<T> &c)
|
|
||||||
{
|
|
||||||
T tre = re * c.re - im * c.im;
|
|
||||||
im = re * c.im + im * c.re;
|
|
||||||
re = tre;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void operator-=(const complex<T> &x)
|
|
||||||
{
|
|
||||||
re-=x.re;
|
|
||||||
im-=x.im;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void operator*=(const T &k)
|
|
||||||
{
|
|
||||||
re *= k;
|
|
||||||
im *= k;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
complex<T> operator+(const complex<T> &a, const complex<T> &b)
|
|
||||||
{
|
|
||||||
return complex<T>(a.re + b.re, a.im + b.im);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
complex<T> operator -(const complex<T> &a, const complex<T> &b) {
|
|
||||||
return complex<T>(a.re - b.re, a.im - b.im);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
complex<T> operator*(const complex<T> &a, const complex<T> &b)
|
|
||||||
{
|
|
||||||
return complex<T>(a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
complex<T> operator*(const complex<T> &a, const T &k)
|
|
||||||
{
|
|
||||||
return complex<T>(a.re * k, a.im * k);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
complex<T> operator*(const T &k, const complex<T> &a)
|
|
||||||
{
|
|
||||||
return complex<T>(k * a.re, k * a.im);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T dotprod(const T *u, const T *v, int n)
|
T dotprod(const T *u, const T *v, int n)
|
||||||
{
|
{
|
||||||
@ -101,13 +37,13 @@ T dotprod(const T *u, const T *v, int n)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T cnorm2(const complex<T> &u)
|
inline T cnorm2(const std::complex<T> &u)
|
||||||
{
|
{
|
||||||
return u.re * u.re + u.im * u.im;
|
return u.real() * u.real() + u.imag() * u.imag();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T cnorm2(const complex<T> *p, int n)
|
T cnorm2(const std::complex<T> *p, int n)
|
||||||
{
|
{
|
||||||
T res = 0;
|
T res = 0;
|
||||||
|
|
||||||
@ -120,19 +56,19 @@ T cnorm2(const complex<T> *p, int n)
|
|||||||
|
|
||||||
// Return conj(u)*v
|
// Return conj(u)*v
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline complex<T> conjprod(const complex<T> &u, const complex<T> &v)
|
inline std::complex<T> conjprod(const std::complex<T> &u, const std::complex<T> &v)
|
||||||
{
|
{
|
||||||
return complex<T>(
|
return std::complex<T>(
|
||||||
u.re * v.re + u.im * v.im,
|
u.real() * v.real() + u.imag() * v.imag(),
|
||||||
u.re * v.im - u.im * v.re
|
u.real() * v.imag() - u.imag() * v.real()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return sum(conj(u[i])*v[i])
|
// Return sum(conj(u[i])*v[i])
|
||||||
template <typename T>
|
template <typename T>
|
||||||
complex<T> conjprod(const complex<T> *u, const complex<T> *v, int n)
|
std::complex<T> conjprod(const std::complex<T> *u, const std::complex<T> *v, int n)
|
||||||
{
|
{
|
||||||
complex<T> acc = 0;
|
std::complex<T> acc = 0;
|
||||||
|
|
||||||
while (n--) {
|
while (n--) {
|
||||||
acc += conjprod(*u++, *v++);
|
acc += conjprod(*u++, *v++);
|
||||||
@ -156,25 +92,24 @@ int log2i(uint64_t x);
|
|||||||
|
|
||||||
struct trig16
|
struct trig16
|
||||||
{
|
{
|
||||||
complex<float> lut[65536]; // TBD static and shared
|
std::complex<float> lut[65536]; // TBD static and shared
|
||||||
|
|
||||||
trig16()
|
trig16()
|
||||||
{
|
{
|
||||||
for (int a = 0; a < 65536; ++a)
|
for (int a = 0; a < 65536; ++a)
|
||||||
{
|
{
|
||||||
float af = a * 2 * M_PI / 65536;
|
float af = a * 2 * M_PI / 65536;
|
||||||
lut[a].re = cosf(af);
|
lut[a] = {cosf(af), sinf(af)};
|
||||||
lut[a].im = sinf(af);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const complex<float> &expi(uint16_t a) const
|
inline const std::complex<float> &expi(uint16_t a) const
|
||||||
{
|
{
|
||||||
return lut[a];
|
return lut[a];
|
||||||
}
|
}
|
||||||
|
|
||||||
// a must fit in a int32_t, otherwise behaviour is undefined
|
// a must fit in a int32_t, otherwise behaviour is undefined
|
||||||
inline const complex<float> &expi(float a) const
|
inline const std::complex<float> &expi(float a) const
|
||||||
{
|
{
|
||||||
return expi((uint16_t)(int16_t)(int32_t)a);
|
return expi((uint16_t)(int16_t)(int32_t)a);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#define LEANSDR_SDR_H
|
#define LEANSDR_SDR_H
|
||||||
|
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
#include "leansdr/dsp.h"
|
#include "leansdr/dsp.h"
|
||||||
#include "leansdr/math.h"
|
#include "leansdr/math.h"
|
||||||
@ -29,11 +30,11 @@ namespace leansdr
|
|||||||
|
|
||||||
typedef float f32;
|
typedef float f32;
|
||||||
|
|
||||||
typedef complex<u8> cu8;
|
typedef std::complex<u8> cu8;
|
||||||
typedef complex<s8> cs8;
|
typedef std::complex<s8> cs8;
|
||||||
typedef complex<u16> cu16;
|
typedef std::complex<u16> cu16;
|
||||||
typedef complex<s16> cs16;
|
typedef std::complex<s16> cs16;
|
||||||
typedef complex<f32> cf32;
|
typedef std::complex<f32> cf32;
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
||||||
// SDR blocks
|
// SDR blocks
|
||||||
@ -52,8 +53,8 @@ struct auto_notch : runnable
|
|||||||
|
|
||||||
auto_notch(
|
auto_notch(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
pipebuf<complex<T>> &_out,
|
pipebuf<std::complex<T>> &_out,
|
||||||
int _nslots,
|
int _nslots,
|
||||||
T _agc_rms_setpoint
|
T _agc_rms_setpoint
|
||||||
) :
|
) :
|
||||||
@ -73,7 +74,7 @@ struct auto_notch : runnable
|
|||||||
for (int s = 0; s < nslots; ++s)
|
for (int s = 0; s < nslots; ++s)
|
||||||
{
|
{
|
||||||
__slots[s].i = -1;
|
__slots[s].i = -1;
|
||||||
__slots[s].expj = new complex<float>[fft.size()];
|
__slots[s].expj = new std::complex<float>[fft.size()];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,22 +107,21 @@ struct auto_notch : runnable
|
|||||||
|
|
||||||
void detect()
|
void detect()
|
||||||
{
|
{
|
||||||
complex<T> *pin = in.rd();
|
std::complex<T> *pin = in.rd();
|
||||||
complex<float> *data = new complex<float>[fft.size()];
|
std::complex<float> *data = new std::complex<float>[fft.size()];
|
||||||
float m0 = 0, m2 = 0;
|
float m0 = 0, m2 = 0;
|
||||||
|
|
||||||
for (int i = 0; i < fft.size(); ++i)
|
for (int i = 0; i < fft.size(); ++i)
|
||||||
{
|
{
|
||||||
data[i].re = pin[i].re;
|
data[i] = pin[i];
|
||||||
data[i].im = pin[i].im;
|
m2 += (float) pin[i].real() * pin[i].real() + (float) pin[i].imag() * pin[i].imag();
|
||||||
m2 += (float)pin[i].re * pin[i].re + (float)pin[i].im * pin[i].im;
|
|
||||||
|
|
||||||
if (gen_abs(pin[i].re) > m0) {
|
if (gen_abs(pin[i].real()) > m0) {
|
||||||
m0 = gen_abs(pin[i].re);
|
m0 = gen_abs(pin[i].real());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gen_abs(pin[i].im) > m0) {
|
if (gen_abs(pin[i].imag()) > m0) {
|
||||||
m0 = gen_abs(pin[i].im);
|
m0 = gen_abs(pin[i].imag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,7 +141,7 @@ struct auto_notch : runnable
|
|||||||
float *amp = new float[fft.size()];
|
float *amp = new float[fft.size()];
|
||||||
|
|
||||||
for (int i = 0; i < fft.size(); ++i) {
|
for (int i = 0; i < fft.size(); ++i) {
|
||||||
amp[i] = hypotf(data[i].re, data[i].im);
|
amp[i] = hypotf(data[i].real(), data[i].imag());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (slot *s = __slots; s < __slots + nslots; ++s)
|
for (slot *s = __slots; s < __slots + nslots; ++s)
|
||||||
@ -162,15 +162,15 @@ struct auto_notch : runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
s->i = iamax;
|
s->i = iamax;
|
||||||
s->estim.re = 0;
|
s->estim.real(0);
|
||||||
s->estim.im = 0;
|
s->estim.imag(0);
|
||||||
s->estt = 0;
|
s->estt = 0;
|
||||||
|
|
||||||
for (int i = 0; i < fft.size(); ++i)
|
for (int i = 0; i < fft.size(); ++i)
|
||||||
{
|
{
|
||||||
float a = 2 * M_PI * s->i * i / fft.size();
|
float a = 2 * M_PI * s->i * i / fft.size();
|
||||||
s->expj[i].re = cosf(a);
|
s->expj[i].real(cosf(a));
|
||||||
s->expj[i].im = sinf(a);
|
s->expj[i].imag(sinf(a));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -191,7 +191,7 @@ struct auto_notch : runnable
|
|||||||
|
|
||||||
void process()
|
void process()
|
||||||
{
|
{
|
||||||
complex<T> *pin = in.rd(), *pend = pin + fft.size(), *pout = out.wr();
|
std::complex<T> *pin = in.rd(), *pend = pin + fft.size(), *pout = out.wr();
|
||||||
|
|
||||||
for (slot *s = __slots; s < __slots + nslots; ++s) {
|
for (slot *s = __slots; s < __slots + nslots; ++s) {
|
||||||
s->ej = s->expj;
|
s->ej = s->expj;
|
||||||
@ -199,41 +199,41 @@ struct auto_notch : runnable
|
|||||||
|
|
||||||
for (; pin < pend; ++pin, ++pout)
|
for (; pin < pend; ++pin, ++pout)
|
||||||
{
|
{
|
||||||
complex<float> out = *pin;
|
std::complex<float> out = *pin;
|
||||||
// TODO Optimize for nslots==1 ?
|
// TODO Optimize for nslots==1 ?
|
||||||
|
|
||||||
for (slot *s = __slots; s < __slots + nslots; ++s->ej, ++s)
|
for (slot *s = __slots; s < __slots + nslots; ++s->ej, ++s)
|
||||||
{
|
{
|
||||||
complex<float> bb(
|
std::complex<float> bb(
|
||||||
pin->re * s->ej->re + pin->im * s->ej->im,
|
pin->real() * s->ej->real() + pin->imag() * s->ej->imag(),
|
||||||
-pin->re * s->ej->im + pin->im * s->ej->re
|
-pin->real() * s->ej->imag() + pin->imag() * s->ej->real()
|
||||||
);
|
);
|
||||||
s->estim.re = bb.re * k + s->estim.re * (1 - k);
|
s->estim.real(bb.real() * k + s->estim.real() * (1 - k));
|
||||||
s->estim.im = bb.im * k + s->estim.im * (1 - k);
|
s->estim.imag(bb.imag() * k + s->estim.imag() * (1 - k));
|
||||||
complex<float> sub(
|
std::complex<float> sub(
|
||||||
s->estim.re * s->ej->re - s->estim.im * s->ej->im,
|
s->estim.real() * s->ej->real() - s->estim.imag() * s->ej->imag(),
|
||||||
s->estim.re * s->ej->im + s->estim.im * s->ej->re
|
s->estim.real() * s->ej->imag() + s->estim.imag() * s->ej->real()
|
||||||
);
|
);
|
||||||
out.re -= sub.re;
|
out.real(out.real() - sub.real());
|
||||||
out.im -= sub.im;
|
out.imag(out.imag() - sub.imag());
|
||||||
}
|
}
|
||||||
|
|
||||||
pout->re = gain * out.re;
|
pout->real(gain * out.real());
|
||||||
pout->im = gain * out.im;
|
pout->imag(gain * out.imag());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cfft_engine<float> fft;
|
cfft_engine<float> fft;
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
pipewriter<complex<T>> out;
|
pipewriter<std::complex<T>> out;
|
||||||
int nslots;
|
int nslots;
|
||||||
|
|
||||||
struct slot
|
struct slot
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
complex<float> estim;
|
std::complex<float> estim;
|
||||||
complex<float> *expj, *ej;
|
std::complex<float> *expj, *ej;
|
||||||
int estt;
|
int estt;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -255,7 +255,7 @@ struct ss_estimator : runnable
|
|||||||
|
|
||||||
ss_estimator(
|
ss_estimator(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
pipebuf<T> &_out
|
pipebuf<T> &_out
|
||||||
) :
|
) :
|
||||||
runnable(sch, "SS estimator"),
|
runnable(sch, "SS estimator"),
|
||||||
@ -276,11 +276,11 @@ struct ss_estimator : runnable
|
|||||||
if (phase >= decimation)
|
if (phase >= decimation)
|
||||||
{
|
{
|
||||||
phase -= decimation;
|
phase -= decimation;
|
||||||
complex<T> *p = in.rd(), *pend = p + window_size;
|
std::complex<T> *p = in.rd(), *pend = p + window_size;
|
||||||
float s = 0;
|
float s = 0;
|
||||||
|
|
||||||
for (; p < pend; ++p) {
|
for (; p < pend; ++p) {
|
||||||
s += (float)p->re * p->re + (float)p->im * p->im;
|
s += (float)p->real() * p->real() + (float)p->imag() * p->imag();
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write(sqrtf(s / window_size));
|
out.write(sqrtf(s / window_size));
|
||||||
@ -291,7 +291,7 @@ struct ss_estimator : runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
pipewriter<T> out;
|
pipewriter<T> out;
|
||||||
unsigned long phase;
|
unsigned long phase;
|
||||||
};
|
};
|
||||||
@ -304,7 +304,7 @@ struct ss_amp_estimator : runnable
|
|||||||
|
|
||||||
ss_amp_estimator(
|
ss_amp_estimator(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
pipebuf<T> &_out_ss,
|
pipebuf<T> &_out_ss,
|
||||||
pipebuf<T> &_out_ampmin,
|
pipebuf<T> &_out_ampmin,
|
||||||
pipebuf<T> &_out_ampmax
|
pipebuf<T> &_out_ampmax
|
||||||
@ -329,13 +329,13 @@ struct ss_amp_estimator : runnable
|
|||||||
if (phase >= decimation)
|
if (phase >= decimation)
|
||||||
{
|
{
|
||||||
phase -= decimation;
|
phase -= decimation;
|
||||||
complex<T> *p = in.rd(), *pend = p + window_size;
|
std::complex<T> *p = in.rd(), *pend = p + window_size;
|
||||||
float s2 = 0;
|
float s2 = 0;
|
||||||
float amin = 1e38, amax = 0;
|
float amin = 1e38, amax = 0;
|
||||||
|
|
||||||
for (; p < pend; ++p)
|
for (; p < pend; ++p)
|
||||||
{
|
{
|
||||||
float mag2 = (float)p->re * p->re + (float)p->im * p->im;
|
float mag2 = (float)p->real() * p->real() + (float)p->imag() * p->imag();
|
||||||
s2 += mag2;
|
s2 += mag2;
|
||||||
float mag = sqrtf(mag2);
|
float mag = sqrtf(mag2);
|
||||||
|
|
||||||
@ -358,7 +358,7 @@ struct ss_amp_estimator : runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
pipewriter<T> out_ss, out_ampmin, out_ampmax;
|
pipewriter<T> out_ss, out_ampmin, out_ampmax;
|
||||||
unsigned long phase;
|
unsigned long phase;
|
||||||
};
|
};
|
||||||
@ -375,8 +375,8 @@ struct simple_agc : runnable
|
|||||||
|
|
||||||
simple_agc(
|
simple_agc(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
pipebuf<complex<T>> &_out
|
pipebuf<std::complex<T>> &_out
|
||||||
) :
|
) :
|
||||||
runnable(sch, "AGC"),
|
runnable(sch, "AGC"),
|
||||||
out_rms(1),
|
out_rms(1),
|
||||||
@ -388,18 +388,18 @@ struct simple_agc : runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
pipewriter<complex<T>> out;
|
pipewriter<std::complex<T>> out;
|
||||||
|
|
||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
while (in.readable() >= chunk_size && out.writable() >= chunk_size)
|
while (in.readable() >= chunk_size && out.writable() >= chunk_size)
|
||||||
{
|
{
|
||||||
complex<T> *pin = in.rd(), *pend = pin + chunk_size;
|
std::complex<T> *pin = in.rd(), *pend = pin + chunk_size;
|
||||||
float amp2 = 0;
|
float amp2 = 0;
|
||||||
|
|
||||||
for (; pin < pend; ++pin) {
|
for (; pin < pend; ++pin) {
|
||||||
amp2 += pin->re * pin->re + pin->im * pin->im;
|
amp2 += pin->real() * pin->real() + pin->imag() * pin->imag();
|
||||||
}
|
}
|
||||||
|
|
||||||
amp2 /= chunk_size;
|
amp2 /= chunk_size;
|
||||||
@ -411,13 +411,13 @@ struct simple_agc : runnable
|
|||||||
estimated = estimated * (1 - bw) + amp2 * bw;
|
estimated = estimated * (1 - bw) + amp2 * bw;
|
||||||
float gain = estimated ? out_rms / sqrtf(estimated) : 0;
|
float gain = estimated ? out_rms / sqrtf(estimated) : 0;
|
||||||
pin = in.rd();
|
pin = in.rd();
|
||||||
complex<T> *pout = out.wr();
|
std::complex<T> *pout = out.wr();
|
||||||
float bwcomp = 1 - bw;
|
float bwcomp = 1 - bw;
|
||||||
|
|
||||||
for (; pin < pend; ++pin, ++pout)
|
for (; pin < pend; ++pin, ++pout)
|
||||||
{
|
{
|
||||||
pout->re = pin->re * gain;
|
pout->real() = pin->real() * gain;
|
||||||
pout->im = pin->im * gain;
|
pout->imag() = pin->imag() * gain;
|
||||||
}
|
}
|
||||||
|
|
||||||
in.read(chunk_size);
|
in.read(chunk_size);
|
||||||
@ -521,7 +521,7 @@ struct cstln_base
|
|||||||
|
|
||||||
static const char *names[];
|
static const char *names[];
|
||||||
float amp_max; // Max amplitude. 1 for PSK, 0 if not applicable.
|
float amp_max; // Max amplitude. 1 for PSK, 0 if not applicable.
|
||||||
complex<int8_t> *symbols;
|
std::complex<int8_t> *symbols;
|
||||||
int nsymbols;
|
int nsymbols;
|
||||||
int nrotations;
|
int nrotations;
|
||||||
};
|
};
|
||||||
@ -546,7 +546,7 @@ struct cstln_lut : cstln_base
|
|||||||
amp_max = 1;
|
amp_max = 1;
|
||||||
nrotations = 2;
|
nrotations = 2;
|
||||||
nsymbols = 2;
|
nsymbols = 2;
|
||||||
symbols = new complex<signed char>[nsymbols];
|
symbols = new std::complex<signed char>[nsymbols];
|
||||||
#if 0 // BPSK at 0°
|
#if 0 // BPSK at 0°
|
||||||
symbols[0] = polar(1, 2, 0);
|
symbols[0] = polar(1, 2, 0);
|
||||||
symbols[1] = polar(1, 2, 1);
|
symbols[1] = polar(1, 2, 1);
|
||||||
@ -564,7 +564,7 @@ struct cstln_lut : cstln_base
|
|||||||
// EN 302 307, section 5.4.1
|
// EN 302 307, section 5.4.1
|
||||||
nrotations = 4;
|
nrotations = 4;
|
||||||
nsymbols = 4;
|
nsymbols = 4;
|
||||||
symbols = new complex<signed char>[nsymbols];
|
symbols = new std::complex<signed char>[nsymbols];
|
||||||
symbols[0] = polar(1, 4, 0.5);
|
symbols[0] = polar(1, 4, 0.5);
|
||||||
symbols[1] = polar(1, 4, 3.5);
|
symbols[1] = polar(1, 4, 3.5);
|
||||||
symbols[2] = polar(1, 4, 1.5);
|
symbols[2] = polar(1, 4, 1.5);
|
||||||
@ -577,7 +577,7 @@ struct cstln_lut : cstln_base
|
|||||||
// EN 302 307, section 5.4.2
|
// EN 302 307, section 5.4.2
|
||||||
nrotations = 8;
|
nrotations = 8;
|
||||||
nsymbols = 8;
|
nsymbols = 8;
|
||||||
symbols = new complex<signed char>[nsymbols];
|
symbols = new std::complex<signed char>[nsymbols];
|
||||||
symbols[0] = polar(1, 8, 1);
|
symbols[0] = polar(1, 8, 1);
|
||||||
symbols[1] = polar(1, 8, 0);
|
symbols[1] = polar(1, 8, 0);
|
||||||
symbols[2] = polar(1, 8, 4);
|
symbols[2] = polar(1, 8, 4);
|
||||||
@ -600,7 +600,7 @@ struct cstln_lut : cstln_base
|
|||||||
amp_max = r2;
|
amp_max = r2;
|
||||||
nrotations = 4;
|
nrotations = 4;
|
||||||
nsymbols = 16;
|
nsymbols = 16;
|
||||||
symbols = new complex<signed char>[nsymbols];
|
symbols = new std::complex<signed char>[nsymbols];
|
||||||
symbols[0] = polar(r2, 12, 1.5);
|
symbols[0] = polar(r2, 12, 1.5);
|
||||||
symbols[1] = polar(r2, 12, 10.5);
|
symbols[1] = polar(r2, 12, 10.5);
|
||||||
symbols[2] = polar(r2, 12, 4.5);
|
symbols[2] = polar(r2, 12, 4.5);
|
||||||
@ -636,7 +636,7 @@ struct cstln_lut : cstln_base
|
|||||||
amp_max = r3;
|
amp_max = r3;
|
||||||
nrotations = 4;
|
nrotations = 4;
|
||||||
nsymbols = 32;
|
nsymbols = 32;
|
||||||
symbols = new complex<signed char>[nsymbols];
|
symbols = new std::complex<signed char>[nsymbols];
|
||||||
symbols[0] = polar(r2, 12, 1.5);
|
symbols[0] = polar(r2, 12, 1.5);
|
||||||
symbols[1] = polar(r2, 12, 2.5);
|
symbols[1] = polar(r2, 12, 2.5);
|
||||||
symbols[2] = polar(r2, 12, 10.5);
|
symbols[2] = polar(r2, 12, 10.5);
|
||||||
@ -691,7 +691,7 @@ struct cstln_lut : cstln_base
|
|||||||
amp_max = r4;
|
amp_max = r4;
|
||||||
nrotations = 4;
|
nrotations = 4;
|
||||||
nsymbols = 64;
|
nsymbols = 64;
|
||||||
symbols = new complex<signed char>[nsymbols];
|
symbols = new std::complex<signed char>[nsymbols];
|
||||||
polar2(0, r4, 1.0 / 4, 7.0 / 4, 3.0 / 4, 5.0 / 4);
|
polar2(0, r4, 1.0 / 4, 7.0 / 4, 3.0 / 4, 5.0 / 4);
|
||||||
polar2(4, r4, 13.0 / 28, 43.0 / 28, 15.0 / 28, 41.0 / 28);
|
polar2(4, r4, 13.0 / 28, 43.0 / 28, 15.0 / 28, 41.0 / 28);
|
||||||
polar2(8, r4, 1.0 / 28, 55.0 / 28, 27.0 / 28, 29.0 / 28);
|
polar2(8, r4, 1.0 / 28, 55.0 / 28, 27.0 / 28, 29.0 / 28);
|
||||||
@ -770,10 +770,10 @@ struct cstln_lut : cstln_base
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
complex<signed char> polar(float r, int n, float i)
|
std::complex<signed char> polar(float r, int n, float i)
|
||||||
{
|
{
|
||||||
float a = i * 2 * M_PI / n;
|
float a = i * 2 * M_PI / n;
|
||||||
return complex<signed char>(
|
return std::complex<signed char>(
|
||||||
r * cosf(a) * cstln_amp,
|
r * cosf(a) * cstln_amp,
|
||||||
r * sinf(a) * cstln_amp
|
r * sinf(a) * cstln_amp
|
||||||
);
|
);
|
||||||
@ -787,7 +787,7 @@ struct cstln_lut : cstln_base
|
|||||||
for (int j = 0; j < 4; ++j)
|
for (int j = 0; j < 4; ++j)
|
||||||
{
|
{
|
||||||
float phi = a[j] * M_PI;
|
float phi = a[j] * M_PI;
|
||||||
symbols[i + j] = complex<signed char>(
|
symbols[i + j] = std::complex<signed char>(
|
||||||
r * cosf(phi) * cstln_amp,
|
r * cosf(phi) * cstln_amp,
|
||||||
r * sinf(phi) * cstln_amp
|
r * sinf(phi) * cstln_amp
|
||||||
);
|
);
|
||||||
@ -798,7 +798,7 @@ struct cstln_lut : cstln_base
|
|||||||
{
|
{
|
||||||
nrotations = 4;
|
nrotations = 4;
|
||||||
nsymbols = n;
|
nsymbols = n;
|
||||||
symbols = new complex<signed char>[nsymbols];
|
symbols = new std::complex<signed char>[nsymbols];
|
||||||
int m = sqrtl(n);
|
int m = sqrtl(n);
|
||||||
float scale;
|
float scale;
|
||||||
|
|
||||||
@ -817,8 +817,8 @@ struct cstln_lut : cstln_base
|
|||||||
{
|
{
|
||||||
float I = x - (float)(m - 1) / 2;
|
float I = x - (float)(m - 1) / 2;
|
||||||
float Q = y - (float)(m - 1) / 2;
|
float Q = y - (float)(m - 1) / 2;
|
||||||
symbols[s].re = I * scale * cstln_amp;
|
symbols[s].real(I * scale * cstln_amp);
|
||||||
symbols[s].im = Q * scale * cstln_amp;
|
symbols[s].imag(Q * scale * cstln_amp);
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -861,7 +861,7 @@ struct cstln_lut : cstln_base
|
|||||||
|
|
||||||
for (int s = 0; s < nsymbols; ++s)
|
for (int s = 0; s < nsymbols; ++s)
|
||||||
{
|
{
|
||||||
float d2 = ((I - symbols[s].re) * (I - symbols[s].re) + (Q - symbols[s].im) * (Q - symbols[s].im));
|
float d2 = ((I - symbols[s].real()) * (I - symbols[s].real()) + (Q - symbols[s].imag()) * (Q - symbols[s].imag()));
|
||||||
|
|
||||||
if (d2 < fss.dists2[fss.nearest]) {
|
if (d2 < fss.dists2[fss.nearest]) {
|
||||||
fss.nearest = s;
|
fss.nearest = s;
|
||||||
@ -893,8 +893,8 @@ struct cstln_lut : cstln_base
|
|||||||
// Always record nearest symbol and phase error for C&T.
|
// Always record nearest symbol and phase error for C&T.
|
||||||
pr->symbol = fss.nearest;
|
pr->symbol = fss.nearest;
|
||||||
float ph_symbol = atan2f(
|
float ph_symbol = atan2f(
|
||||||
symbols[pr->symbol].im,
|
symbols[pr->symbol].imag(),
|
||||||
symbols[pr->symbol].re
|
symbols[pr->symbol].real()
|
||||||
);
|
);
|
||||||
float ph_err = atan2f(Q, I) - ph_symbol;
|
float ph_err = atan2f(Q, I) - ph_symbol;
|
||||||
pr->phase_error = (int32_t)(ph_err * 65536 / (2 * M_PI)); // Mod 65536
|
pr->phase_error = (int32_t)(ph_err * 65536 / (2 * M_PI)); // Mod 65536
|
||||||
@ -926,7 +926,7 @@ struct cstln_lut : cstln_base
|
|||||||
// Highlight the constellation symbols.
|
// Highlight the constellation symbols.
|
||||||
for (int s = 0; s < nsymbols; ++s)
|
for (int s = 0; s < nsymbols; ++s)
|
||||||
{
|
{
|
||||||
if (symbols[s].re == I && symbols[s].im == Q) {
|
if (symbols[s].real() == I && symbols[s].imag() == Q) {
|
||||||
v ^= 128;
|
v ^= 128;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -962,7 +962,7 @@ struct sampler_interface
|
|||||||
virtual ~sampler_interface() {
|
virtual ~sampler_interface() {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual complex<T> interp(const complex<T> *pin, float mu, float phase) = 0;
|
virtual std::complex<T> interp(const std::complex<T> *pin, float mu, float phase) = 0;
|
||||||
|
|
||||||
virtual void update_freq(float freqw, int weight = 0)
|
virtual void update_freq(float freqw, int weight = 0)
|
||||||
{
|
{
|
||||||
@ -983,7 +983,7 @@ struct nearest_sampler : sampler_interface<T>
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<T> interp(const complex<T> *pin, float mu, float phase)
|
std::complex<T> interp(const std::complex<T> *pin, float mu, float phase)
|
||||||
{
|
{
|
||||||
(void) mu;
|
(void) mu;
|
||||||
return pin[0] * trig.expi(-phase);
|
return pin[0] * trig.expi(-phase);
|
||||||
@ -1003,11 +1003,11 @@ struct linear_sampler : sampler_interface<T>
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<T> interp(const complex<T> *pin, float mu, float phase)
|
std::complex<T> interp(const std::complex<T> *pin, float mu, float phase)
|
||||||
{
|
{
|
||||||
// Derotate pin[0] and pin[1]
|
// Derotate pin[0] and pin[1]
|
||||||
complex<T> s0 = pin[0] * trig.expi(-phase);
|
std::complex<T> s0 = pin[0] * trig.expi(-phase);
|
||||||
complex<T> s1 = pin[1] * trig.expi(-(phase + freqw));
|
std::complex<T> s1 = pin[1] * trig.expi(-(phase + freqw));
|
||||||
// Interpolate linearly
|
// Interpolate linearly
|
||||||
return s0 * (1 - mu) + s1 * mu;
|
return s0 * (1 - mu) + s1 * mu;
|
||||||
}
|
}
|
||||||
@ -1035,7 +1035,7 @@ struct fir_sampler : sampler_interface<T>
|
|||||||
subsampling(_subsampling),
|
subsampling(_subsampling),
|
||||||
update_freq_phase(0)
|
update_freq_phase(0)
|
||||||
{
|
{
|
||||||
shifted_coeffs = new complex<T>[ncoeffs];
|
shifted_coeffs = new std::complex<T>[ncoeffs];
|
||||||
do_update_freq(0); // In case application never calls update_freq()
|
do_update_freq(0); // In case application never calls update_freq()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,12 +1048,12 @@ struct fir_sampler : sampler_interface<T>
|
|||||||
return ncoeffs - 1;
|
return ncoeffs - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
complex<T> interp(const complex<T> *pin, float mu, float phase)
|
std::complex<T> interp(const std::complex<T> *pin, float mu, float phase)
|
||||||
{
|
{
|
||||||
// Apply FIR filter with subsampling
|
// Apply FIR filter with subsampling
|
||||||
complex<T> acc(0, 0);
|
std::complex<T> acc(0, 0);
|
||||||
complex<T> *pc = shifted_coeffs + (int)((1 - mu) * subsampling);
|
std::complex<T> *pc = shifted_coeffs + (int)((1 - mu) * subsampling);
|
||||||
complex<T> *pcend = shifted_coeffs + ncoeffs;
|
std::complex<T> *pcend = shifted_coeffs + ncoeffs;
|
||||||
|
|
||||||
if (subsampling == 1)
|
if (subsampling == 1)
|
||||||
{
|
{
|
||||||
@ -1133,7 +1133,7 @@ struct cstln_receiver : runnable
|
|||||||
cstln_receiver(
|
cstln_receiver(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
sampler_interface<T> *_sampler,
|
sampler_interface<T> *_sampler,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
pipebuf<SOFTSYMB> &_out,
|
pipebuf<SOFTSYMB> &_out,
|
||||||
pipebuf<float> *_freq_out = nullptr,
|
pipebuf<float> *_freq_out = nullptr,
|
||||||
pipebuf<float> *_ss_out = nullptr,
|
pipebuf<float> *_ss_out = nullptr,
|
||||||
@ -1264,13 +1264,13 @@ struct cstln_receiver : runnable
|
|||||||
{
|
{
|
||||||
sampler->update_freq(freqw, chunk_size);
|
sampler->update_freq(freqw, chunk_size);
|
||||||
|
|
||||||
complex<T> *pin = in.rd(), *pin0 = pin, *pend = pin + chunk_size;
|
std::complex<T> *pin = in.rd(), *pin0 = pin, *pend = pin + chunk_size;
|
||||||
SOFTSYMB *pout = out.wr(), *pout0 = pout;
|
SOFTSYMB *pout = out.wr(), *pout0 = pout;
|
||||||
|
|
||||||
// These are scoped outside the loop for SS and MER estimation.
|
// These are scoped outside the loop for SS and MER estimation.
|
||||||
complex<float> sg{0.0f, 0.0f}; // Symbol before AGC;
|
std::complex<float> sg{0.0f, 0.0f}; // Symbol before AGC;
|
||||||
complex<float> s; // For MER estimation and constellation viewer
|
std::complex<float> s; // For MER estimation and constellation viewer
|
||||||
complex<signed char> *cstln_point = nullptr;
|
std::complex<signed char> *cstln_point = nullptr;
|
||||||
|
|
||||||
while (pin < pend)
|
while (pin < pend)
|
||||||
{
|
{
|
||||||
@ -1284,7 +1284,7 @@ struct cstln_receiver : runnable
|
|||||||
|
|
||||||
// Constellation look-up
|
// Constellation look-up
|
||||||
typename cstln_lut<SOFTSYMB, 256>::result *cr =
|
typename cstln_lut<SOFTSYMB, 256>::result *cr =
|
||||||
cstln->lookup(s.re, s.im);
|
cstln->lookup(s.real(), s.imag());
|
||||||
*pout = cr->ss;
|
*pout = cr->ss;
|
||||||
++pout;
|
++pout;
|
||||||
|
|
||||||
@ -1299,13 +1299,13 @@ struct cstln_receiver : runnable
|
|||||||
// c = decisions (constellation points)
|
// c = decisions (constellation points)
|
||||||
hist[2] = hist[1];
|
hist[2] = hist[1];
|
||||||
hist[1] = hist[0];
|
hist[1] = hist[0];
|
||||||
hist[0].p.re = s.re;
|
hist[0].p.real(s.real());
|
||||||
hist[0].p.im = s.im;
|
hist[0].p.imag(s.imag());
|
||||||
cstln_point = &cstln->symbols[cr->symbol];
|
cstln_point = &cstln->symbols[cr->symbol];
|
||||||
hist[0].c.re = cstln_point->re;
|
hist[0].c.real(cstln_point->real());
|
||||||
hist[0].c.im = cstln_point->im;
|
hist[0].c.imag(cstln_point->imag());
|
||||||
float muerr = ((hist[0].p.re - hist[2].p.re) * hist[1].c.re + (hist[0].p.im - hist[2].p.im) * hist[1].c.im)
|
float muerr = ((hist[0].p.real() - hist[2].p.real()) * hist[1].c.real() + (hist[0].p.imag() - hist[2].p.imag()) * hist[1].c.imag())
|
||||||
- ((hist[0].c.re - hist[2].c.re) * hist[1].p.re + (hist[0].c.im - hist[2].c.im) * hist[1].p.im);
|
- ((hist[0].c.real() - hist[2].c.real()) * hist[1].p.real() + (hist[0].c.imag() - hist[2].c.imag()) * hist[1].p.imag());
|
||||||
float mucorr = muerr * gain_mu;
|
float mucorr = muerr * gain_mu;
|
||||||
const float max_mucorr = 0.1;
|
const float max_mucorr = 0.1;
|
||||||
|
|
||||||
@ -1346,7 +1346,7 @@ struct cstln_receiver : runnable
|
|||||||
// AGC
|
// AGC
|
||||||
// For APSK we must do AGC on the symbols, not the whole signal.
|
// For APSK we must do AGC on the symbols, not the whole signal.
|
||||||
// TODO Use a better estimator at low SNR.
|
// TODO Use a better estimator at low SNR.
|
||||||
float insp = sg.re * sg.re + sg.im * sg.im;
|
float insp = sg.real() * sg.real() + sg.imag() * sg.imag();
|
||||||
est_insp = insp * kest + est_insp * (1 - kest);
|
est_insp = insp * kest + est_insp * (1 - kest);
|
||||||
|
|
||||||
if (est_insp) {
|
if (est_insp) {
|
||||||
@ -1354,9 +1354,9 @@ struct cstln_receiver : runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SS and MER
|
// SS and MER
|
||||||
complex<float> ev(
|
std::complex<float> ev(
|
||||||
s.re - cstln_point->re,
|
s.real() - cstln_point->real(),
|
||||||
s.im - cstln_point->im
|
s.imag() - cstln_point->imag()
|
||||||
);
|
);
|
||||||
float sig_power, ev_power;
|
float sig_power, ev_power;
|
||||||
|
|
||||||
@ -1364,15 +1364,15 @@ struct cstln_receiver : runnable
|
|||||||
{
|
{
|
||||||
// Special case for BPSK: Ignore quadrature component of noise.
|
// Special case for BPSK: Ignore quadrature component of noise.
|
||||||
// TBD Projection on I axis assumes BPSK at 45°
|
// TBD Projection on I axis assumes BPSK at 45°
|
||||||
float sig_real = (cstln_point->re + cstln_point->im) * 0.707;
|
float sig_real = (cstln_point->real() + cstln_point->imag()) * 0.707;
|
||||||
float ev_real = (ev.re + ev.im) * 0.707;
|
float ev_real = (ev.real() + ev.imag()) * 0.707;
|
||||||
sig_power = sig_real * sig_real;
|
sig_power = sig_real * sig_real;
|
||||||
ev_power = ev_real * ev_real;
|
ev_power = ev_real * ev_real;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sig_power = (int)cstln_point->re * cstln_point->re + (int)cstln_point->im * cstln_point->im;
|
sig_power = (int)cstln_point->real() * cstln_point->real() + (int)cstln_point->imag() * cstln_point->imag();
|
||||||
ev_power = ev.re * ev.re + ev.im * ev.im;
|
ev_power = ev.real() * ev.real() + ev.imag() * ev.imag();
|
||||||
}
|
}
|
||||||
|
|
||||||
est_sp = sig_power * kest + est_sp * (1 - kest);
|
est_sp = sig_power * kest + est_sp * (1 - kest);
|
||||||
@ -1425,11 +1425,11 @@ struct cstln_receiver : runnable
|
|||||||
private:
|
private:
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
complex<float> p; // Received symbol
|
std::complex<float> p; // Received symbol
|
||||||
complex<float> c; // Matched constellation point
|
std::complex<float> c; // Matched constellation point
|
||||||
} hist[3];
|
} hist[3];
|
||||||
|
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
pipewriter<SOFTSYMB> out;
|
pipewriter<SOFTSYMB> out;
|
||||||
float est_insp, agc_gain;
|
float est_insp, agc_gain;
|
||||||
float mu; // PSK time expressed in clock ticks
|
float mu; // PSK time expressed in clock ticks
|
||||||
@ -1460,10 +1460,10 @@ struct fast_qpsk_receiver : runnable
|
|||||||
|
|
||||||
fast_qpsk_receiver(
|
fast_qpsk_receiver(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
pipebuf<hardsymbol> &_out,
|
pipebuf<hardsymbol> &_out,
|
||||||
pipebuf<float> *_freq_out = nullptr,
|
pipebuf<float> *_freq_out = nullptr,
|
||||||
pipebuf<complex<T>> *_cstln_out = nullptr
|
pipebuf<std::complex<T>> *_cstln_out = nullptr
|
||||||
) :
|
) :
|
||||||
runnable(sch, "Fast QPSK receiver"),
|
runnable(sch, "Fast QPSK receiver"),
|
||||||
meas_decimation(1048576),
|
meas_decimation(1048576),
|
||||||
@ -1478,7 +1478,7 @@ struct fast_qpsk_receiver : runnable
|
|||||||
set_omega(1);
|
set_omega(1);
|
||||||
set_freq(0);
|
set_freq(0);
|
||||||
freq_out = _freq_out ? new pipewriter<float>(*_freq_out) : nullptr;
|
freq_out = _freq_out ? new pipewriter<float>(*_freq_out) : nullptr;
|
||||||
cstln_out = _cstln_out ? new pipewriter<complex<T>>(*_cstln_out) : nullptr;
|
cstln_out = _cstln_out ? new pipewriter<std::complex<T>>(*_cstln_out) : nullptr;
|
||||||
memset(hist, 0, sizeof(hist));
|
memset(hist, 0, sizeof(hist));
|
||||||
init_lookup_tables();
|
init_lookup_tables();
|
||||||
}
|
}
|
||||||
@ -1537,7 +1537,7 @@ struct fast_qpsk_receiver : runnable
|
|||||||
while (in.readable() >= chunk_size + 1 && // +1 for interpolation
|
while (in.readable() >= chunk_size + 1 && // +1 for interpolation
|
||||||
out.writable() >= chunk_size && (!freq_out || freq_out->writable() >= max_meas) && (!cstln_out || cstln_out->writable() >= max_meas))
|
out.writable() >= chunk_size && (!freq_out || freq_out->writable() >= max_meas) && (!cstln_out || cstln_out->writable() >= max_meas))
|
||||||
{
|
{
|
||||||
complex<T> *pin = in.rd(), *pin0 = pin, *pend = pin + chunk_size;
|
std::complex<T> *pin = in.rd(), *pin0 = pin, *pend = pin + chunk_size;
|
||||||
hardsymbol *pout = out.wr(), *pout0 = pout;
|
hardsymbol *pout = out.wr(), *pout0 = pout;
|
||||||
|
|
||||||
cu8 s;
|
cu8 s;
|
||||||
@ -1560,28 +1560,28 @@ struct fast_qpsk_receiver : runnable
|
|||||||
symbol_arg = a0 + (s_angle)(da*mu);
|
symbol_arg = a0 + (s_angle)(da*mu);
|
||||||
s = arg_to_symbol(symbol_arg);
|
s = arg_to_symbol(symbol_arg);
|
||||||
#elif 1 // Linear by lookup-table. 1.2M on bench3bishs
|
#elif 1 // Linear by lookup-table. 1.2M on bench3bishs
|
||||||
polar *p0 = &lut_polar[pin[0].re][pin[0].im];
|
polar *p0 = &lut_polar[pin[0].real()][pin[0].imag()];
|
||||||
u_angle a0 = (u_angle)(p0->a - phase) >> (16 - RLUT_BITS);
|
u_angle a0 = (u_angle)(p0->a - phase) >> (16 - RLUT_BITS);
|
||||||
cu8 *p0r = &lut_rect[a0][p0->r >> 1];
|
cu8 *p0r = &lut_rect[a0][p0->r >> 1];
|
||||||
polar *p1 = &lut_polar[pin[1].re][pin[1].im];
|
polar *p1 = &lut_polar[pin[1].real()][pin[1].imag()];
|
||||||
u_angle a1 = (u_angle)(p1->a - (phase + freqw)) >> (16 - RLUT_BITS);
|
u_angle a1 = (u_angle)(p1->a - (phase + freqw)) >> (16 - RLUT_BITS);
|
||||||
cu8 *p1r = &lut_rect[a1][p1->r >> 1];
|
cu8 *p1r = &lut_rect[a1][p1->r >> 1];
|
||||||
s.re = (int)(p0r->re + (p1r->re - p0r->re) * mu);
|
s.real((int)(p0r->real() + (p1r->real() - p0r->real()) * mu));
|
||||||
s.im = (int)(p0r->im + (p1r->im - p0r->im) * mu);
|
s.imag((int)(p0r->imag() + (p1r->imag() - p0r->imag()) * mu));
|
||||||
symbol_arg = fast_arg(s);
|
symbol_arg = fast_arg(s);
|
||||||
#else // Linear floating-point, for reference
|
#else // Linear floating-point, for reference
|
||||||
float a0 = -(int)phase * M_PI / 32768;
|
float a0 = -(int)phase * M_PI / 32768;
|
||||||
float cosa0 = cosf(a0), sina0 = sinf(a0);
|
float cosa0 = cosf(a0), sina0 = sinf(a0);
|
||||||
complex<float>
|
std::complex<float>
|
||||||
p0r(((float)pin[0].re - 128) * cosa0 - ((float)pin[0].im - 128) * sina0,
|
p0r(((float)pin[0].real() - 128) * cosa0 - ((float)pin[0].imag() - 128) * sina0,
|
||||||
((float)pin[0].re - 128) * sina0 + ((float)pin[0].im - 128) * cosa0);
|
((float)pin[0].real() - 128) * sina0 + ((float)pin[0].imag() - 128) * cosa0);
|
||||||
float a1 = -(int)(phase + freqw) * M_PI / 32768;
|
float a1 = -(int)(phase + freqw) * M_PI / 32768;
|
||||||
float cosa1 = cosf(a1), sina1 = sinf(a1);
|
float cosa1 = cosf(a1), sina1 = sinf(a1);
|
||||||
complex<float>
|
std::complex<float>
|
||||||
p1r(((float)pin[1].re - 128) * cosa1 - ((float)pin[1].im - 128) * sina1,
|
p1r(((float)pin[1].real() - 128) * cosa1 - ((float)pin[1].imag() - 128) * sina1,
|
||||||
((float)pin[1].re - 128) * sina1 + ((float)pin[1].im - 128) * cosa1);
|
((float)pin[1].real() - 128) * sina1 + ((float)pin[1].imag() - 128) * cosa1);
|
||||||
s.re = (int)(128 + p0r.re + (p1r.re - p0r.re) * mu);
|
s.real() = (int)(128 + p0r.real() + (p1r.real() - p0r.real()) * mu);
|
||||||
s.im = (int)(128 + p0r.im + (p1r.im - p0r.im) * mu);
|
s.imag() = (int)(128 + p0r.imag() + (p1r.imag() - p0r.imag()) * mu);
|
||||||
symbol_arg = fast_arg(s);
|
symbol_arg = fast_arg(s);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1604,24 +1604,24 @@ struct fast_qpsk_receiver : runnable
|
|||||||
hist[1] = hist[0];
|
hist[1] = hist[0];
|
||||||
#define HIST_FLOAT 0
|
#define HIST_FLOAT 0
|
||||||
#if HIST_FLOAT
|
#if HIST_FLOAT
|
||||||
hist[0].p.re = (float)s.re - 128;
|
hist[0].p.real() = (float)s.real() - 128;
|
||||||
hist[0].p.im = (float)s.im - 128;
|
hist[0].p.imag() = (float)s.imag() - 128;
|
||||||
|
|
||||||
cu8 cp = arg_to_symbol((symbol_arg & 49152) + 8192);
|
cu8 cp = arg_to_symbol((symbol_arg & 49152) + 8192);
|
||||||
hist[0].c.re = (float)cp.re - 128;
|
hist[0].c.real() = (float)cp.real() - 128;
|
||||||
hist[0].c.im = (float)cp.im - 128;
|
hist[0].c.imag() = (float)cp.imag() - 128;
|
||||||
|
|
||||||
float muerr =
|
float muerr =
|
||||||
((hist[0].p.re - hist[2].p.re) * hist[1].c.re +
|
((hist[0].p.real() - hist[2].p.real()) * hist[1].c.real() +
|
||||||
(hist[0].p.im - hist[2].p.im) * hist[1].c.im) -
|
(hist[0].p.imag() - hist[2].p.imag()) * hist[1].c.imag()) -
|
||||||
((hist[0].c.re - hist[2].c.re) * hist[1].p.re +
|
((hist[0].c.real() - hist[2].c.real()) * hist[1].p.real() +
|
||||||
(hist[0].c.im - hist[2].c.im) * hist[1].p.im);
|
(hist[0].c.imag() - hist[2].c.imag()) * hist[1].p.imag());
|
||||||
#else
|
#else
|
||||||
hist[0].p = s;
|
hist[0].p = s;
|
||||||
hist[0].c = arg_to_symbol((symbol_arg & 49152) + 8192);
|
hist[0].c = arg_to_symbol((symbol_arg & 49152) + 8192);
|
||||||
|
|
||||||
int muerr =
|
int muerr =
|
||||||
((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));
|
((signed char)(hist[0].p.real() - hist[2].p.real()) * ((int)hist[1].c.real() - 128) + (signed char)(hist[0].p.imag() - hist[2].p.imag()) * ((int)hist[1].c.imag() - 128)) - ((signed char)(hist[0].c.real() - hist[2].c.real()) * ((int)hist[1].p.real() - 128) + (signed char)(hist[0].c.imag() - hist[2].c.imag()) * ((int)hist[1].p.imag() - 128));
|
||||||
#endif
|
#endif
|
||||||
float mucorr = muerr * gain_mu;
|
float mucorr = muerr * gain_mu;
|
||||||
const float max_mucorr = 0.1;
|
const float max_mucorr = 0.1;
|
||||||
@ -1689,7 +1689,7 @@ struct fast_qpsk_receiver : runnable
|
|||||||
u_angle fast_arg(const cu8 &c)
|
u_angle fast_arg(const cu8 &c)
|
||||||
{
|
{
|
||||||
// TBD read cu8 as u16 index, same endianness as in init()
|
// TBD read cu8 as u16 index, same endianness as in init()
|
||||||
return lut_polar[c.re][c.im].a;
|
return lut_polar[c.real()][c.imag()].a;
|
||||||
}
|
}
|
||||||
|
|
||||||
cu8 lut_rect[RLUT_ANGLES][256];
|
cu8 lut_rect[RLUT_ANGLES][256];
|
||||||
@ -1715,16 +1715,16 @@ struct fast_qpsk_receiver : runnable
|
|||||||
for (unsigned long a = 0; a < 65536; ++a)
|
for (unsigned long a = 0; a < 65536; ++a)
|
||||||
{
|
{
|
||||||
float f = 2 * M_PI * a / 65536;
|
float f = 2 * M_PI * a / 65536;
|
||||||
lut_sincos[a].re = 128 + cstln_amp * cosf(f);
|
lut_sincos[a].real() = 128 + cstln_amp * cosf(f);
|
||||||
lut_sincos[a].im = 128 + cstln_amp * sinf(f);
|
lut_sincos[a].imag() = 128 + cstln_amp * sinf(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int a = 0; a < RLUT_ANGLES; ++a)
|
for (int a = 0; a < RLUT_ANGLES; ++a)
|
||||||
{
|
{
|
||||||
for (int r = 0; r < 256; ++r)
|
for (int r = 0; r < 256; ++r)
|
||||||
{
|
{
|
||||||
lut_rect[a][r].re = (int)(128 + r * cos(2 * M_PI * a / RLUT_ANGLES));
|
lut_rect[a][r].real() = (int)(128 + r * cos(2 * M_PI * a / RLUT_ANGLES));
|
||||||
lut_rect[a][r].im = (int)(128 + r * sin(2 * M_PI * a / RLUT_ANGLES));
|
lut_rect[a][r].imag() = (int)(128 + r * sin(2 * M_PI * a / RLUT_ANGLES));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1732,8 +1732,8 @@ struct fast_qpsk_receiver : runnable
|
|||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
#if HIST_FLOAT
|
#if HIST_FLOAT
|
||||||
complex<float> p; // Received symbol
|
std::complex<float> p; // Received symbol
|
||||||
complex<float> c; // Matched constellation point
|
std::complex<float> c; // Matched constellation point
|
||||||
#else
|
#else
|
||||||
cu8 p; // Received symbol
|
cu8 p; // Received symbol
|
||||||
cu8 c; // Matched constellation point
|
cu8 c; // Matched constellation point
|
||||||
@ -1762,7 +1762,7 @@ struct cstln_transmitter : runnable
|
|||||||
cstln_transmitter(
|
cstln_transmitter(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<u8> &_in,
|
pipebuf<u8> &_in,
|
||||||
pipebuf<complex<Tout>> &_out
|
pipebuf<std::complex<Tout>> &_out
|
||||||
) :
|
) :
|
||||||
runnable(sch, "cstln_transmitter"),
|
runnable(sch, "cstln_transmitter"),
|
||||||
in(_in),
|
in(_in),
|
||||||
@ -1779,13 +1779,13 @@ struct cstln_transmitter : runnable
|
|||||||
|
|
||||||
int count = min(in.readable(), out.writable());
|
int count = min(in.readable(), out.writable());
|
||||||
u8 *pin = in.rd(), *pend = pin + count;
|
u8 *pin = in.rd(), *pend = pin + count;
|
||||||
complex<Tout> *pout = out.wr();
|
std::complex<Tout> *pout = out.wr();
|
||||||
|
|
||||||
for (; pin < pend; ++pin, ++pout)
|
for (; pin < pend; ++pin, ++pout)
|
||||||
{
|
{
|
||||||
complex<signed char> *cp = &cstln->symbols[*pin];
|
std::complex<signed char> *cp = &cstln->symbols[*pin];
|
||||||
pout->re = Zout + cp->re;
|
pout->real(Zout + cp->real());
|
||||||
pout->im = Zout + cp->im;
|
pout->imag(Zout + cp->imag());
|
||||||
}
|
}
|
||||||
|
|
||||||
in.read(count);
|
in.read(count);
|
||||||
@ -1794,7 +1794,7 @@ struct cstln_transmitter : runnable
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<u8> in;
|
pipereader<u8> in;
|
||||||
pipewriter<complex<Tout>> out;
|
pipewriter<std::complex<Tout>> out;
|
||||||
};
|
};
|
||||||
// cstln_transmitter
|
// cstln_transmitter
|
||||||
|
|
||||||
@ -1807,8 +1807,8 @@ struct rotator : runnable
|
|||||||
{
|
{
|
||||||
rotator(
|
rotator(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
pipebuf<complex<T>> &_out,
|
pipebuf<std::complex<T>> &_out,
|
||||||
float freq
|
float freq
|
||||||
) :
|
) :
|
||||||
runnable(sch, "rotator"),
|
runnable(sch, "rotator"),
|
||||||
@ -1832,15 +1832,15 @@ struct rotator : runnable
|
|||||||
void run()
|
void run()
|
||||||
{
|
{
|
||||||
unsigned long count = min(in.readable(), out.writable());
|
unsigned long count = min(in.readable(), out.writable());
|
||||||
complex<T> *pin = in.rd(), *pend = pin + count;
|
std::complex<T> *pin = in.rd(), *pend = pin + count;
|
||||||
complex<T> *pout = out.wr();
|
std::complex<T> *pout = out.wr();
|
||||||
|
|
||||||
for (; pin < pend; ++pin, ++pout, ++index)
|
for (; pin < pend; ++pin, ++pout, ++index)
|
||||||
{
|
{
|
||||||
float c = lut_cos[index];
|
float c = lut_cos[index];
|
||||||
float s = lut_sin[index];
|
float s = lut_sin[index];
|
||||||
pout->re = pin->re * c - pin->im * s;
|
pout->real(pin->real() * c - pin->imag() * s);
|
||||||
pout->im = pin->re * s + pin->im * c;
|
pout->imag(pin->real() * s + pin->imag() * c);
|
||||||
}
|
}
|
||||||
|
|
||||||
in.read(count);
|
in.read(count);
|
||||||
@ -1848,8 +1848,8 @@ struct rotator : runnable
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
pipewriter<complex<T>> out;
|
pipewriter<std::complex<T>> out;
|
||||||
float lut_cos[65536];
|
float lut_cos[65536];
|
||||||
float lut_sin[65536];
|
float lut_sin[65536];
|
||||||
unsigned short index; // Current phase
|
unsigned short index; // Current phase
|
||||||
@ -1870,7 +1870,7 @@ struct cnr_fft : runnable
|
|||||||
{
|
{
|
||||||
cnr_fft(
|
cnr_fft(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
pipebuf<float> &_out,
|
pipebuf<float> &_out,
|
||||||
float _bandwidth,
|
float _bandwidth,
|
||||||
int nfft = 4096
|
int nfft = 4096
|
||||||
@ -1944,7 +1944,7 @@ struct cnr_fft : runnable
|
|||||||
sorted = new T[fft.size()];
|
sorted = new T[fft.size()];
|
||||||
}
|
}
|
||||||
if (!data) {
|
if (!data) {
|
||||||
data = new complex<T>[fft.size()];
|
data = new std::complex<T>[fft.size()];
|
||||||
}
|
}
|
||||||
if (!power) {
|
if (!power) {
|
||||||
power = new T[fft.size()];
|
power = new T[fft.size()];
|
||||||
@ -1956,7 +1956,7 @@ struct cnr_fft : runnable
|
|||||||
fft.inplace(data, true);
|
fft.inplace(data, true);
|
||||||
|
|
||||||
for (int i = 0; i < fft.size(); ++i)
|
for (int i = 0; i < fft.size(); ++i)
|
||||||
power[i] = data[i].re * data[i].re + data[i].im * data[i].im;
|
power[i] = data[i].real() * data[i].real() + data[i].imag() * data[i].imag();
|
||||||
|
|
||||||
if (!avgpower)
|
if (!avgpower)
|
||||||
{
|
{
|
||||||
@ -2039,12 +2039,12 @@ struct cnr_fft : runnable
|
|||||||
// fprintf(stderr, "l: %d m: %d min: %f max: %f\n", l, m, min, max);
|
// fprintf(stderr, "l: %d m: %d min: %f max: %f\n", l, m, min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
pipewriter<float> out;
|
pipewriter<float> out;
|
||||||
cfft_engine<T> fft;
|
cfft_engine<T> fft;
|
||||||
T *avgpower;
|
T *avgpower;
|
||||||
T *sorted;
|
T *sorted;
|
||||||
complex<T> *data;
|
std::complex<T> *data;
|
||||||
T *power;
|
T *power;
|
||||||
int phase;
|
int phase;
|
||||||
float cslots_ratio;
|
float cslots_ratio;
|
||||||
@ -2062,7 +2062,7 @@ struct spectrum : runnable
|
|||||||
|
|
||||||
spectrum(
|
spectrum(
|
||||||
scheduler *sch,
|
scheduler *sch,
|
||||||
pipebuf<complex<T>> &_in,
|
pipebuf<std::complex<T>> &_in,
|
||||||
pipebuf<float[NFFT]> &_out
|
pipebuf<float[NFFT]> &_out
|
||||||
) :
|
) :
|
||||||
runnable(sch, "spectrum"),
|
runnable(sch, "spectrum"),
|
||||||
@ -2102,7 +2102,7 @@ struct spectrum : runnable
|
|||||||
private:
|
private:
|
||||||
void do_spectrum()
|
void do_spectrum()
|
||||||
{
|
{
|
||||||
complex<T> data[fft.n];
|
std::complex<T> data[fft.n];
|
||||||
|
|
||||||
if (decim == 1)
|
if (decim == 1)
|
||||||
{
|
{
|
||||||
@ -2110,7 +2110,7 @@ struct spectrum : runnable
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
complex<T> *pin = in.rd();
|
std::complex<T> *pin = in.rd();
|
||||||
|
|
||||||
for (int i = 0; i < fft.n; ++i, pin += decim) {
|
for (int i = 0; i < fft.n; ++i, pin += decim) {
|
||||||
data[i] = *pin;
|
data[i] = *pin;
|
||||||
@ -2121,7 +2121,7 @@ struct spectrum : runnable
|
|||||||
float power[NFFT];
|
float power[NFFT];
|
||||||
|
|
||||||
for (int i = 0; i < fft.n; ++i) {
|
for (int i = 0; i < fft.n; ++i) {
|
||||||
power[i] = (float)data[i].re * data[i].re + (float)data[i].im * data[i].im;
|
power[i] = (float)data[i].real() * data[i].real() + (float)data[i].imag() * data[i].imag();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!avgpower)
|
if (!avgpower)
|
||||||
@ -2146,7 +2146,7 @@ struct spectrum : runnable
|
|||||||
out.written(1);
|
out.written(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pipereader<complex<T>> in;
|
pipereader<std::complex<T>> in;
|
||||||
pipewriter<float[NFFT]> out;
|
pipewriter<float[NFFT]> out;
|
||||||
cfft_engine<T> fft;
|
cfft_engine<T> fft;
|
||||||
T *avgpower;
|
T *avgpower;
|
||||||
|
Loading…
Reference in New Issue
Block a user