Some tweaks to the V.22bis modem, so it builds OK in a fixed point build
This commit is contained in:
parent
cc08b939c4
commit
80d5c5aa53
|
@ -26,10 +26,10 @@
|
|||
#if !defined(_SPANDSP_PRIVATE_V22BIS_H_)
|
||||
#define _SPANDSP_PRIVATE_V22BIS_H_
|
||||
|
||||
/*! The number of steps to the left and to the right of the target position in the equalizer buffer. */
|
||||
#define V22BIS_EQUALIZER_LEN 7
|
||||
/*! One less than a power of 2 >= (2*V22BIS_EQUALIZER_LEN + 1) */
|
||||
#define V22BIS_EQUALIZER_MASK 15
|
||||
/*! The length of the equalizer buffer */
|
||||
#define V22BIS_EQUALIZER_LEN 17
|
||||
/*! Samples before the target position in the equalizer buffer */
|
||||
#define V22BIS_EQUALIZER_PRE_LEN 8
|
||||
|
||||
/*! The number of taps in the transmit pulse shaping filter */
|
||||
#define V22BIS_TX_FILTER_STEPS 9
|
||||
|
@ -99,9 +99,9 @@ struct v22bis_state_s
|
|||
/* Receive section */
|
||||
struct
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
/*! \brief The scaling factor accessed by the AGC algorithm. */
|
||||
float agc_scaling;
|
||||
int16_t agc_scaling;
|
||||
/*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
|
||||
int16_t rrc_filter[V22BIS_RX_FILTER_STEPS];
|
||||
#else
|
||||
|
@ -131,15 +131,14 @@ struct v22bis_state_s
|
|||
uint32_t carrier_phase;
|
||||
/*! \brief The update rate for the phase of the carrier (i.e. the DDS increment). */
|
||||
int32_t carrier_phase_rate;
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
/*! \brief A measure of how much mismatch there is between the real constellation,
|
||||
and the decoded symbol positions. */
|
||||
float training_error;
|
||||
int32_t training_error;
|
||||
/*! \brief The proportional part of the carrier tracking filter. */
|
||||
float carrier_track_p;
|
||||
int32_t carrier_track_p;
|
||||
/*! \brief The integral part of the carrier tracking filter. */
|
||||
float carrier_track_i;
|
||||
int32_t carrier_track_i;
|
||||
#else
|
||||
/*! \brief A measure of how much mismatch there is between the real constellation,
|
||||
and the decoded symbol positions. */
|
||||
|
@ -166,20 +165,20 @@ struct v22bis_state_s
|
|||
|
||||
int constellation_state;
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
/*! \brief The current delta factor for updating the equalizer coefficients. */
|
||||
float eq_delta;
|
||||
int16_t eq_delta;
|
||||
/*! \brief The adaptive equalizer coefficients. */
|
||||
complexi_t eq_coeff[2*V22BIS_EQUALIZER_LEN + 1];
|
||||
complexi16_t eq_coeff[V22BIS_EQUALIZER_LEN];
|
||||
/*! \brief The equalizer signal buffer. */
|
||||
complexi_t eq_buf[V22BIS_EQUALIZER_MASK + 1];
|
||||
complexi16_t eq_buf[V22BIS_EQUALIZER_LEN];
|
||||
#else
|
||||
/*! \brief The current delta factor for updating the equalizer coefficients. */
|
||||
float eq_delta;
|
||||
/*! \brief The adaptive equalizer coefficients. */
|
||||
complexf_t eq_coeff[2*V22BIS_EQUALIZER_LEN + 1];
|
||||
complexf_t eq_coeff[V22BIS_EQUALIZER_LEN];
|
||||
/*! \brief The equalizer signal buffer. */
|
||||
complexf_t eq_buf[V22BIS_EQUALIZER_MASK + 1];
|
||||
complexf_t eq_buf[V22BIS_EQUALIZER_LEN];
|
||||
#endif
|
||||
/*! \brief Current offset into the equalizer buffer. */
|
||||
int eq_step;
|
||||
|
@ -205,20 +204,22 @@ struct v22bis_state_s
|
|||
/* Transmit section */
|
||||
struct
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
/*! \brief The guard tone level. */
|
||||
float guard_level;
|
||||
int16_t guard_tone_gain;
|
||||
/*! \brief The gain factor needed to achieve the specified output power. */
|
||||
float gain;
|
||||
int16_t gain;
|
||||
/*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
|
||||
complexf_t rrc_filter[2*V22BIS_TX_FILTER_STEPS];
|
||||
int16_t rrc_filter_re[V22BIS_TX_FILTER_STEPS];
|
||||
int16_t rrc_filter_im[V22BIS_TX_FILTER_STEPS];
|
||||
#else
|
||||
/*! \brief The guard tone level. */
|
||||
float guard_level;
|
||||
float guard_tone_gain;
|
||||
/*! \brief The gain factor needed to achieve the specified output power. */
|
||||
float gain;
|
||||
/*! \brief The root raised cosine (RRC) pulse shaping filter buffer. */
|
||||
complexf_t rrc_filter[2*V22BIS_TX_FILTER_STEPS];
|
||||
float rrc_filter_re[V22BIS_TX_FILTER_STEPS];
|
||||
float rrc_filter_im[V22BIS_TX_FILTER_STEPS];
|
||||
#endif
|
||||
|
||||
/*! \brief Current offset into the RRC pulse shaping filter buffer. */
|
||||
|
|
|
@ -86,7 +86,11 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx_fillin(v22bis_state_t *s, int len);
|
|||
\brief Get a snapshot of the current equalizer coefficients.
|
||||
\param coeffs The vector of complex coefficients.
|
||||
\return The number of coefficients in the vector. */
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
SPAN_DECLARE(int) v22bis_rx_equalizer_state(v22bis_state_t *s, complexi16_t **coeffs);
|
||||
#else
|
||||
SPAN_DECLARE(int) v22bis_rx_equalizer_state(v22bis_state_t *s, complexf_t **coeffs);
|
||||
#endif
|
||||
|
||||
/*! Get the current received carrier frequency.
|
||||
\param s The modem context.
|
||||
|
|
|
@ -69,9 +69,9 @@
|
|||
#include "spandsp/private/logging.h"
|
||||
#include "spandsp/private/v22bis.h"
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
#include "v22bis_rx_1200_floating_rrc.h"
|
||||
#include "v22bis_rx_2400_floating_rrc.h"
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
#include "v22bis_rx_1200_fixed_rrc.h"
|
||||
#include "v22bis_rx_2400_fixed_rrc.h"
|
||||
#else
|
||||
#include "v22bis_rx_1200_floating_rrc.h"
|
||||
#include "v22bis_rx_2400_floating_rrc.h"
|
||||
|
@ -79,6 +79,11 @@
|
|||
|
||||
#define ms_to_symbols(t) (((t)*600)/1000)
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
#define FP_FACTOR 4096
|
||||
#define FP_SHIFT_FACTOR 12
|
||||
#endif
|
||||
|
||||
/*! The adaption rate coefficient for the equalizer */
|
||||
#define EQUALIZER_DELTA 0.25f
|
||||
/*! The number of phase shifted coefficient set for the pulse shaping/bandpass filter */
|
||||
|
@ -167,24 +172,28 @@ void v22bis_report_status_change(v22bis_state_t *s, int status)
|
|||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
SPAN_DECLARE(int) v22bis_rx_equalizer_state(v22bis_state_t *s, complexi16_t **coeffs)
|
||||
#else
|
||||
SPAN_DECLARE(int) v22bis_rx_equalizer_state(v22bis_state_t *s, complexf_t **coeffs)
|
||||
#endif
|
||||
{
|
||||
*coeffs = s->rx.eq_coeff;
|
||||
return 2*V22BIS_EQUALIZER_LEN + 1;
|
||||
return V22BIS_EQUALIZER_LEN;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
void v22bis_equalizer_coefficient_reset(v22bis_state_t *s)
|
||||
{
|
||||
/* Start with an equalizer based on everything being perfect */
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
cvec_zeroi16(s->rx.eq_coeff, 2*V22BIS_EQUALIZER_LEN + 1);
|
||||
s->rx.eq_coeff[V22BIS_EQUALIZER_LEN] = complex_seti16(3*FP_FACTOR, 0*FP_FACTOR);
|
||||
s->rx.eq_delta = 32768.0f*EQUALIZER_DELTA/(2*V22BIS_EQUALIZER_LEN + 1);
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
cvec_zeroi16(s->rx.eq_coeff, V22BIS_EQUALIZER_LEN);
|
||||
s->rx.eq_coeff[V22BIS_EQUALIZER_PRE_LEN] = complex_seti16(FP_Q_4_12(3.0), FP_Q_4_12(0.0));
|
||||
s->rx.eq_delta = 32768.0f*EQUALIZER_DELTA/V22BIS_EQUALIZER_LEN;
|
||||
#else
|
||||
cvec_zerof(s->rx.eq_coeff, 2*V22BIS_EQUALIZER_LEN + 1);
|
||||
s->rx.eq_coeff[V22BIS_EQUALIZER_LEN] = complex_setf(3.0f, 0.0f);
|
||||
s->rx.eq_delta = EQUALIZER_DELTA/(2*V22BIS_EQUALIZER_LEN + 1);
|
||||
cvec_zerof(s->rx.eq_coeff, V22BIS_EQUALIZER_LEN);
|
||||
s->rx.eq_coeff[V22BIS_EQUALIZER_PRE_LEN] = complex_setf(3.0f, 0.0f);
|
||||
s->rx.eq_delta = EQUALIZER_DELTA/V22BIS_EQUALIZER_LEN;
|
||||
#endif
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
@ -192,63 +201,68 @@ void v22bis_equalizer_coefficient_reset(v22bis_state_t *s)
|
|||
static void equalizer_reset(v22bis_state_t *s)
|
||||
{
|
||||
v22bis_equalizer_coefficient_reset(s);
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
cvec_zeroi16(s->rx.eq_buf, V22BIS_EQUALIZER_MASK + 1);
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
cvec_zeroi16(s->rx.eq_buf, V22BIS_EQUALIZER_LEN);
|
||||
#else
|
||||
cvec_zerof(s->rx.eq_buf, V22BIS_EQUALIZER_MASK + 1);
|
||||
cvec_zerof(s->rx.eq_buf, V22BIS_EQUALIZER_LEN);
|
||||
#endif
|
||||
s->rx.eq_put_step = 20 - 1;
|
||||
s->rx.eq_step = 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static complexf_t equalizer_get(v22bis_state_t *s)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
static __inline__ complexi16_t equalizer_get(v22bis_state_t *s)
|
||||
{
|
||||
int i;
|
||||
int p;
|
||||
complexf_t z;
|
||||
complexf_t z1;
|
||||
complexi32_t zz;
|
||||
complexi16_t z;
|
||||
|
||||
/* Get the next equalized value. */
|
||||
z = complex_setf(0.0f, 0.0f);
|
||||
p = s->rx.eq_step - 1;
|
||||
for (i = 0; i < 2*V22BIS_EQUALIZER_LEN + 1; i++)
|
||||
{
|
||||
p = (p - 1) & V22BIS_EQUALIZER_MASK;
|
||||
z1 = complex_mulf(&s->rx.eq_coeff[i], &s->rx.eq_buf[p]);
|
||||
z = complex_addf(&z, &z1);
|
||||
}
|
||||
zz = cvec_circular_dot_prodi16(s->rx.eq_buf, s->rx.eq_coeff, V22BIS_EQUALIZER_LEN, s->rx.eq_step);
|
||||
z.re = zz.re >> FP_SHIFT_FACTOR;
|
||||
z.im = zz.im >> FP_SHIFT_FACTOR;
|
||||
return z;
|
||||
}
|
||||
#else
|
||||
static __inline__ complexf_t equalizer_get(v22bis_state_t *s)
|
||||
{
|
||||
/* Get the next equalized value. */
|
||||
return cvec_circular_dot_prodf(s->rx.eq_buf, s->rx.eq_coeff, V22BIS_EQUALIZER_LEN, s->rx.eq_step);
|
||||
}
|
||||
#endif
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void tune_equalizer(v22bis_state_t *s, const complexf_t *z, const complexf_t *target)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
static void tune_equalizer(v22bis_state_t *s, const complexi16_t *z, const complexi16_t *target)
|
||||
{
|
||||
int i;
|
||||
int p;
|
||||
complexf_t ez;
|
||||
complexf_t z1;
|
||||
complexi16_t err;
|
||||
|
||||
/* Find the x and y mismatch from the exact constellation position. */
|
||||
ez = complex_subf(target, z);
|
||||
ez.re *= s->rx.eq_delta;
|
||||
ez.im *= s->rx.eq_delta;
|
||||
|
||||
p = s->rx.eq_step - 1;
|
||||
for (i = 0; i < 2*V22BIS_EQUALIZER_LEN + 1; i++)
|
||||
{
|
||||
p = (p - 1) & V22BIS_EQUALIZER_MASK;
|
||||
z1 = complex_conjf(&s->rx.eq_buf[p]);
|
||||
z1 = complex_mulf(&ez, &z1);
|
||||
s->rx.eq_coeff[i] = complex_addf(&s->rx.eq_coeff[i], &z1);
|
||||
/* If we don't leak a little bit we seem to get some wandering adaption */
|
||||
s->rx.eq_coeff[i].re *= 0.9999f;
|
||||
s->rx.eq_coeff[i].im *= 0.9999f;
|
||||
}
|
||||
err.re = target->re*FP_FACTOR - z->re;
|
||||
err.im = target->im*FP_FACTOR - z->im;
|
||||
err.re = ((int32_t) err.re*s->rx.eq_delta) >> 15;
|
||||
err.im = ((int32_t) err.im*s->rx.eq_delta) >> 15;
|
||||
cvec_circular_lmsi16(s->rx.eq_buf, s->rx.eq_coeff, V22BIS_EQUALIZER_LEN, s->rx.eq_step, &err);
|
||||
}
|
||||
#else
|
||||
static void tune_equalizer(v22bis_state_t *s, const complexf_t *z, const complexf_t *target)
|
||||
{
|
||||
complexf_t err;
|
||||
|
||||
/* Find the x and y mismatch from the exact constellation position. */
|
||||
err = complex_subf(target, z);
|
||||
err.re *= s->rx.eq_delta;
|
||||
err.im *= s->rx.eq_delta;
|
||||
cvec_circular_lmsf(s->rx.eq_buf, s->rx.eq_coeff, V22BIS_EQUALIZER_LEN, s->rx.eq_step, &err);
|
||||
}
|
||||
#endif
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
static __inline__ void track_carrier(v22bis_state_t *s, const complexi16_t *z, const complexi16_t *target)
|
||||
#else
|
||||
static __inline__ void track_carrier(v22bis_state_t *s, const complexf_t *z, const complexf_t *target)
|
||||
#endif
|
||||
{
|
||||
float error;
|
||||
|
||||
|
@ -336,40 +350,69 @@ static int decode_baudx(v22bis_state_t *s, int nearest)
|
|||
|
||||
static __inline__ void symbol_sync(v22bis_state_t *s)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
int32_t p;
|
||||
int32_t q;
|
||||
complexi16_t zz;
|
||||
complexi16_t a;
|
||||
complexi16_t b;
|
||||
complexi16_t c;
|
||||
#else
|
||||
float p;
|
||||
float q;
|
||||
complexf_t zz;
|
||||
complexf_t a;
|
||||
complexf_t b;
|
||||
complexf_t c;
|
||||
#endif
|
||||
int aa[3];
|
||||
int i;
|
||||
int j;
|
||||
|
||||
/* This routine adapts the position of the half baud samples entering the equalizer. */
|
||||
|
||||
/* Perform a Gardner test for baud alignment on the three most recent samples. */
|
||||
for (i = 0, j = s->rx.eq_step; i < 3; i++)
|
||||
{
|
||||
if (--j < 0)
|
||||
j = V22BIS_EQUALIZER_LEN - 1;
|
||||
aa[i] = j;
|
||||
}
|
||||
if (s->rx.sixteen_way_decisions)
|
||||
{
|
||||
p = s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK].re
|
||||
- s->rx.eq_buf[(s->rx.eq_step - 1) & V22BIS_EQUALIZER_MASK].re;
|
||||
p *= s->rx.eq_buf[(s->rx.eq_step - 2) & V22BIS_EQUALIZER_MASK].re;
|
||||
p = s->rx.eq_buf[aa[2]].re - s->rx.eq_buf[aa[0]].re;
|
||||
p *= s->rx.eq_buf[aa[1]].re;
|
||||
|
||||
q = s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK].im
|
||||
- s->rx.eq_buf[(s->rx.eq_step - 1) & V22BIS_EQUALIZER_MASK].im;
|
||||
q *= s->rx.eq_buf[(s->rx.eq_step - 2) & V22BIS_EQUALIZER_MASK].im;
|
||||
q = s->rx.eq_buf[aa[2]].im - s->rx.eq_buf[aa[0]].im;
|
||||
q *= s->rx.eq_buf[aa[1]].im;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Rotate the points to the 45 degree positions, to maximise the effectiveness of
|
||||
the Gardner algorithm. This is particularly significant at the start of operation
|
||||
to pull things in quickly. */
|
||||
zz = complex_setf(0.894427, 0.44721f);
|
||||
a = complex_mulf(&s->rx.eq_buf[(s->rx.eq_step - 3) & V22BIS_EQUALIZER_MASK], &zz);
|
||||
b = complex_mulf(&s->rx.eq_buf[(s->rx.eq_step - 2) & V22BIS_EQUALIZER_MASK], &zz);
|
||||
c = complex_mulf(&s->rx.eq_buf[(s->rx.eq_step - 1) & V22BIS_EQUALIZER_MASK], &zz);
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
zz = complex_seti16(FP_Q_6_10(0.894427), FP_Q_6_10(0.44721f));
|
||||
a = complex_muli16(&s->rx.eq_buf[aa[2]], &zz);
|
||||
b = complex_muli16(&s->rx.eq_buf[aa[1]], &zz);
|
||||
c = complex_muli16(&s->rx.eq_buf[aa[0]], &zz);
|
||||
p = (a.re - c.re)*b.re;
|
||||
q = (a.im - c.im)*b.im;
|
||||
#else
|
||||
zz = complex_setf(0.894427, 0.44721f);
|
||||
a = complex_mulf(&s->rx.eq_buf[aa[2]], &zz);
|
||||
b = complex_mulf(&s->rx.eq_buf[aa[1]], &zz);
|
||||
c = complex_mulf(&s->rx.eq_buf[aa[0]], &zz);
|
||||
p = (a.re - c.re)*b.re;
|
||||
q = (a.im - c.im)*b.im;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
s->rx.gardner_integrate += (p + q > 0) ? s->rx.gardner_step : -s->rx.gardner_step;
|
||||
#else
|
||||
s->rx.gardner_integrate += (p + q > 0.0f) ? s->rx.gardner_step : -s->rx.gardner_step;
|
||||
#endif
|
||||
|
||||
if (abs(s->rx.gardner_integrate) >= 16)
|
||||
{
|
||||
|
@ -386,11 +429,21 @@ static __inline__ void symbol_sync(v22bis_state_t *s)
|
|||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
static void process_half_baud(v22bis_state_t *s, const complexi16_t *sample)
|
||||
#else
|
||||
static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
|
||||
#endif
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
complexi16_t z;
|
||||
complexi16_t zz;
|
||||
const complexi16_t *target;
|
||||
#else
|
||||
complexf_t z;
|
||||
complexf_t zz;
|
||||
const complexf_t *target;
|
||||
#endif
|
||||
int re;
|
||||
int im;
|
||||
int nearest;
|
||||
|
@ -403,7 +456,8 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
|
|||
/* Add a sample to the equalizer's circular buffer, but don't calculate anything
|
||||
at this time. */
|
||||
s->rx.eq_buf[s->rx.eq_step] = z;
|
||||
s->rx.eq_step = (s->rx.eq_step + 1) & V22BIS_EQUALIZER_MASK;
|
||||
if (++s->rx.eq_step >= V22BIS_EQUALIZER_LEN)
|
||||
s->rx.eq_step = 0;
|
||||
|
||||
/* On alternate insertions we have a whole baud and must process it. */
|
||||
if ((s->rx.baud_phase ^= 1))
|
||||
|
@ -416,6 +470,18 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
|
|||
/* Find the constellation point */
|
||||
if (s->rx.sixteen_way_decisions)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
re = (int) (z.re + FP_Q_6_10(3.0f));
|
||||
if (re > 5)
|
||||
re = 5;
|
||||
else if (re < 0)
|
||||
re = 0;
|
||||
im = (int) (z.im + FP_Q_6_10(3.0f));
|
||||
if (im > 5)
|
||||
im = 5;
|
||||
else if (im < 0)
|
||||
im = 0;
|
||||
#else
|
||||
re = (int) (z.re + 3.0f);
|
||||
if (re > 5)
|
||||
re = 5;
|
||||
|
@ -426,13 +492,19 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
|
|||
im = 5;
|
||||
else if (im < 0)
|
||||
im = 0;
|
||||
#endif
|
||||
nearest = space_map_v22bis[re][im];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Rotate to 45 degrees, to make the slicing trivial */
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
zz = complex_seti16(FP_Q_4_12(0.894427), FP_Q_4_12(0.44721f));
|
||||
zz = complex_muli16(&z, &zz);
|
||||
#else
|
||||
zz = complex_setf(0.894427, 0.44721f);
|
||||
zz = complex_mulf(&z, &zz);
|
||||
#endif
|
||||
nearest = 0x01;
|
||||
if (zz.re < 0.0f)
|
||||
nearest |= 0x04;
|
||||
|
@ -490,10 +562,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
|
|||
error could be higher. */
|
||||
s->rx.gardner_step = 4;
|
||||
s->rx.pattern_repeats = 0;
|
||||
if (s->calling_party)
|
||||
s->rx.training = V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES;
|
||||
else
|
||||
s->rx.training = V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
|
||||
s->rx.training = (s->calling_party) ? V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES : V22BIS_RX_TRAINING_STAGE_SCRAMBLED_ONES_AT_1200;
|
||||
/* Be pessimistic and see what the handshake brings */
|
||||
s->negotiated_bit_rate = 1200;
|
||||
break;
|
||||
|
@ -527,14 +596,14 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
|
|||
/* It looks like the answering machine is sending us a clean unscrambled 11 or 00 */
|
||||
if (s->bit_rate == 2400)
|
||||
{
|
||||
/* Try to establish at 2400bps */
|
||||
/* Try to establish at 2400bps. */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting U0011 (S1) (Caller)\n");
|
||||
s->tx.training = V22BIS_TX_TRAINING_STAGE_U0011;
|
||||
s->tx.training_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Only try to establish at 1200bps */
|
||||
/* Only try to establish at 1200bps. */
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 (1200) (Caller)\n");
|
||||
s->tx.training = V22BIS_TX_TRAINING_STAGE_S11;
|
||||
s->tx.training_count = 0;
|
||||
|
@ -547,14 +616,14 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
|
|||
break;
|
||||
case V22BIS_RX_TRAINING_STAGE_UNSCRAMBLED_ONES_SUSTAINING:
|
||||
/* Calling modem only */
|
||||
/* Wait for the end of the unscrambled ones at 1200bps */
|
||||
/* Wait for the end of the unscrambled ones at 1200bps. */
|
||||
target = &v22bis_constellation[nearest];
|
||||
track_carrier(s, &z, target);
|
||||
raw_bits = phase_steps[((nearest >> 2) - (s->rx.constellation_state >> 2)) & 3];
|
||||
s->rx.constellation_state = nearest;
|
||||
if (raw_bits != s->rx.last_raw_bits)
|
||||
{
|
||||
/* This looks like the end of the sustained initial unscrambled 11 or 00 */
|
||||
/* This looks like the end of the sustained initial unscrambled 11 or 00. */
|
||||
s->tx.training_count = 0;
|
||||
s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11;
|
||||
s->rx.training_count = 0;
|
||||
|
@ -600,11 +669,11 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
|
|||
}
|
||||
if (s->rx.training_count >= ms_to_symbols(270))
|
||||
{
|
||||
/* If we haven't seen the S1 signal by now, we are committed to be in 1200bps mode */
|
||||
/* If we haven't seen the S1 signal by now, we are committed to be in 1200bps mode. */
|
||||
if (s->calling_party)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "+++ Rx normal operation (1200)\n");
|
||||
/* The transmit side needs to sustain the scrambled ones for a timed period */
|
||||
/* The transmit side needs to sustain the scrambled ones for a timed period. */
|
||||
s->tx.training_count = 0;
|
||||
s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11;
|
||||
/* Normal reception starts immediately */
|
||||
|
@ -614,7 +683,7 @@ static void process_half_baud(v22bis_state_t *s, const complexf_t *sample)
|
|||
else
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 (1200) (Answerer)\n");
|
||||
/* The transmit side needs to sustain the scrambled ones for a timed period */
|
||||
/* The transmit side needs to sustain the scrambled ones for a timed period. */
|
||||
s->tx.training_count = 0;
|
||||
s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11;
|
||||
/* The receive side needs to wait a timed period, receiving scrambled ones,
|
||||
|
@ -695,12 +764,21 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
|
|||
{
|
||||
int i;
|
||||
int step;
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
complexi16_t z;
|
||||
complexi16_t zz;
|
||||
complexi16_t sample;
|
||||
int32_t ii;
|
||||
int32_t qq;
|
||||
float vv;
|
||||
#else
|
||||
complexf_t z;
|
||||
complexf_t zz;
|
||||
int32_t power;
|
||||
complexf_t sample;
|
||||
float ii;
|
||||
float qq;
|
||||
#endif
|
||||
int32_t power;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
|
@ -717,7 +795,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
|
|||
if (s->calling_party)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_2400_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_2400_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15;
|
||||
#else
|
||||
ii = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_2400_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
#endif
|
||||
|
@ -725,7 +803,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
|
|||
else
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_1200_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_1200_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15;
|
||||
#else
|
||||
ii = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_1200_re[6], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
#endif
|
||||
|
@ -753,11 +831,25 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
|
|||
{
|
||||
/* Only spend effort processing this data if the modem is not
|
||||
parked, after a training failure. */
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
z = dds_complexi16(&s->rx.carrier_phase, s->rx.carrier_phase_rate);
|
||||
#else
|
||||
z = dds_complexf(&s->rx.carrier_phase, s->rx.carrier_phase_rate);
|
||||
#endif
|
||||
if (s->rx.training == V22BIS_RX_TRAINING_STAGE_SYMBOL_ACQUISITION)
|
||||
{
|
||||
/* Only AGC during the initial symbol acquisition, and then lock the gain. */
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
vv = 0.18f*3.60f/sqrtf(power);
|
||||
if (vv > 32767.0f)
|
||||
s->rx.agc_scaling = 32767;
|
||||
else if (vv > -32768.0f)
|
||||
s->rx.agc_scaling = -32768;
|
||||
else
|
||||
s->rx.agc_scaling = vv;
|
||||
#else
|
||||
s->rx.agc_scaling = 0.18f*3.60f/sqrtf(power);
|
||||
#endif
|
||||
}
|
||||
/* Put things into the equalization buffer at T/2 rate. The Gardner algorithm
|
||||
will fiddle the step to align this with the symbols. */
|
||||
|
@ -774,8 +866,8 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
|
|||
if (s->calling_party)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_2400_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
qq = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_2400_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_2400_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15;
|
||||
qq = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_2400_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15;
|
||||
#else
|
||||
ii = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_2400_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
qq = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_2400_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
|
@ -784,15 +876,20 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx(v22bis_state_t *s, const int16_t amp[], int l
|
|||
else
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_1200_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
qq = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_1200_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
ii = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_1200_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15;
|
||||
qq = vec_circular_dot_prodi16(s->rx.rrc_filter, rx_pulseshaper_1200_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step) >> 15;
|
||||
#else
|
||||
ii = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_1200_re[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
qq = vec_circular_dot_prodf(s->rx.rrc_filter, rx_pulseshaper_1200_im[step], V22BIS_RX_FILTER_STEPS, s->rx.rrc_filter_step);
|
||||
#endif
|
||||
}
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
sample.re = ((int32_t) ii*s->rx.agc_scaling) >> 10;
|
||||
sample.im = ((int32_t) qq*s->rx.agc_scaling) >> 10;
|
||||
#else
|
||||
sample.re = ii*s->rx.agc_scaling;
|
||||
sample.im = qq*s->rx.agc_scaling;
|
||||
#endif
|
||||
/* Shift to baseband - since this is done in a full complex form, the
|
||||
result is clean, and requires no further filtering apart from the
|
||||
equalizer. */
|
||||
|
@ -817,7 +914,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx_fillin(v22bis_state_t *s, int len)
|
|||
return 0;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
dds_advance(&s->rx.carrier_phase, s->rx.carrier_phase_rate);
|
||||
#else
|
||||
dds_advancef(&s->rx.carrier_phase, s->rx.carrier_phase_rate);
|
||||
|
@ -830,7 +927,7 @@ SPAN_DECLARE_NONSTD(int) v22bis_rx_fillin(v22bis_state_t *s, int len)
|
|||
|
||||
int v22bis_rx_restart(v22bis_state_t *s)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
vec_zeroi16(s->rx.rrc_filter, sizeof(s->rx.rrc_filter)/sizeof(s->rx.rrc_filter[0]));
|
||||
#else
|
||||
vec_zerof(s->rx.rrc_filter, sizeof(s->rx.rrc_filter)/sizeof(s->rx.rrc_filter[0]));
|
||||
|
@ -861,8 +958,13 @@ int v22bis_rx_restart(v22bis_state_t *s)
|
|||
s->rx.training_error = 0.0f;
|
||||
s->rx.total_baud_timing_correction = 0;
|
||||
/* We want the carrier to pull in faster on the answerer side, as it has very little time to adapt. */
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
s->rx.carrier_track_i = (s->calling_party) ? 8000 : 40000;
|
||||
s->rx.carrier_track_p = 8000000;
|
||||
#else
|
||||
s->rx.carrier_track_i = (s->calling_party) ? 8000.0f : 40000.0f;
|
||||
s->rx.carrier_track_p = 8000000.0f;
|
||||
#endif
|
||||
|
||||
s->negotiated_bit_rate = 1200;
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
#include "spandsp/private/logging.h"
|
||||
#include "spandsp/private/v22bis.h"
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINTx)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
#include "v22bis_tx_fixed_rrc.h"
|
||||
#else
|
||||
#include "v22bis_tx_floating_rrc.h"
|
||||
|
@ -246,24 +246,28 @@ static const int phase_steps[4] =
|
|||
1, 0, 2, 3
|
||||
};
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
const complexi16_t v22bis_constellation[16] =
|
||||
#else
|
||||
const complexf_t v22bis_constellation[16] =
|
||||
#endif
|
||||
{
|
||||
{ 1.0f, 1.0f},
|
||||
{ 3.0f, 1.0f}, /* 1200bps 00 */
|
||||
{ 1.0f, 3.0f},
|
||||
{ 3.0f, 3.0f},
|
||||
{-1.0f, 1.0f},
|
||||
{-1.0f, 3.0f}, /* 1200bps 01 */
|
||||
{-3.0f, 1.0f},
|
||||
{-3.0f, 3.0f},
|
||||
{-1.0f, -1.0f},
|
||||
{-3.0f, -1.0f}, /* 1200bps 10 */
|
||||
{-1.0f, -3.0f},
|
||||
{-3.0f, -3.0f},
|
||||
{ 1.0f, -1.0f},
|
||||
{ 1.0f, -3.0f}, /* 1200bps 11 */
|
||||
{ 3.0f, -1.0f},
|
||||
{ 3.0f, -3.0f}
|
||||
{ 1, 1},
|
||||
{ 3, 1}, /* 1200bps 00 */
|
||||
{ 1, 3},
|
||||
{ 3, 3},
|
||||
{-1, 1},
|
||||
{-1, 3}, /* 1200bps 01 */
|
||||
{-3, 1},
|
||||
{-3, 3},
|
||||
{-1, -1},
|
||||
{-3, -1}, /* 1200bps 10 */
|
||||
{-1, -3},
|
||||
{-3, -3},
|
||||
{ 1, -1},
|
||||
{ 1, -3}, /* 1200bps 11 */
|
||||
{ 3, -1},
|
||||
{ 3, -3}
|
||||
};
|
||||
|
||||
static int fake_get_bit(void *user_data)
|
||||
|
@ -308,9 +312,17 @@ static __inline__ int get_scrambled_bit(v22bis_state_t *s)
|
|||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
static complexi16_t training_get(v22bis_state_t *s)
|
||||
#else
|
||||
static complexf_t training_get(v22bis_state_t *s)
|
||||
#endif
|
||||
{
|
||||
complexf_t z;
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
static const complexi16_t zero = {0, 0};
|
||||
#else
|
||||
static const complexf_t zero = {0.0f, 0.0f};
|
||||
#endif
|
||||
int bits;
|
||||
|
||||
/* V.22bis training sequence */
|
||||
|
@ -329,20 +341,17 @@ static complexf_t training_get(v22bis_state_t *s)
|
|||
case V22BIS_TX_TRAINING_STAGE_INITIAL_SILENCE:
|
||||
/* Silence */
|
||||
s->tx.constellation_state = 0;
|
||||
z = complex_setf(0.0f, 0.0f);
|
||||
break;
|
||||
return zero;
|
||||
case V22BIS_TX_TRAINING_STAGE_U11:
|
||||
/* Send continuous unscrambled ones at 1200bps (i.e. 270 degree phase steps). */
|
||||
/* Only the answering modem sends unscrambled ones. It is the first thing exchanged between the modems. */
|
||||
s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3]) & 3;
|
||||
z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
|
||||
break;
|
||||
return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
|
||||
case V22BIS_TX_TRAINING_STAGE_U0011:
|
||||
/* Continuous unscrambled double dibit 00 11 at 1200bps. This is termed the S1 segment in
|
||||
the V.22bis spec. It is only sent to request or accept 2400bps mode, and lasts 100+-3ms. After this
|
||||
timed burst, we unconditionally change to sending scrambled ones at 1200bps. */
|
||||
s->tx.constellation_state = (s->tx.constellation_state + phase_steps[3*(s->tx.training_count & 1)]) & 3;
|
||||
z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
|
||||
if (++s->tx.training_count >= ms_to_symbols(100))
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "+++ starting S11 after U0011\n");
|
||||
|
@ -357,7 +366,7 @@ static complexf_t training_get(v22bis_state_t *s)
|
|||
s->tx.training = V22BIS_TX_TRAINING_STAGE_TIMED_S11;
|
||||
}
|
||||
}
|
||||
break;
|
||||
return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
|
||||
case V22BIS_TX_TRAINING_STAGE_TIMED_S11:
|
||||
/* A timed period of scrambled ones at 1200bps. */
|
||||
if (++s->tx.training_count >= ms_to_symbols(756))
|
||||
|
@ -383,8 +392,7 @@ static complexf_t training_get(v22bis_state_t *s)
|
|||
bits = scramble(s, 1);
|
||||
bits = (bits << 1) | scramble(s, 1);
|
||||
s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3;
|
||||
z = v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
|
||||
break;
|
||||
return v22bis_constellation[(s->tx.constellation_state << 2) | 0x01];
|
||||
case V22BIS_TX_TRAINING_STAGE_S1111:
|
||||
/* Scrambled ones at 2400bps. We send a timed 200ms burst, and switch to normal operation at 2400bps */
|
||||
bits = scramble(s, 1);
|
||||
|
@ -392,7 +400,6 @@ static complexf_t training_get(v22bis_state_t *s)
|
|||
s->tx.constellation_state = (s->tx.constellation_state + phase_steps[bits]) & 3;
|
||||
bits = scramble(s, 1);
|
||||
bits = (bits << 1) | scramble(s, 1);
|
||||
z = v22bis_constellation[(s->tx.constellation_state << 2) | bits];
|
||||
if (++s->tx.training_count >= ms_to_symbols(200))
|
||||
{
|
||||
/* We have completed training. Now handle some real work. */
|
||||
|
@ -402,18 +409,23 @@ static complexf_t training_get(v22bis_state_t *s)
|
|||
v22bis_report_status_change(s, SIG_STATUS_TRAINING_SUCCEEDED);
|
||||
s->tx.current_get_bit = s->get_bit;
|
||||
}
|
||||
break;
|
||||
case V22BIS_TX_TRAINING_STAGE_PARKED:
|
||||
default:
|
||||
z = complex_setf(0.0f, 0.0f);
|
||||
break;
|
||||
return v22bis_constellation[(s->tx.constellation_state << 2) | bits];
|
||||
}
|
||||
return z;
|
||||
return zero;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
static complexi16_t getbaud(v22bis_state_t *s)
|
||||
#else
|
||||
static complexf_t getbaud(v22bis_state_t *s)
|
||||
#endif
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
static const complexi16_t zero = {0, 0};
|
||||
#else
|
||||
static const complexf_t zero = {0.0f, 0.0f};
|
||||
#endif
|
||||
int bits;
|
||||
|
||||
if (s->tx.training)
|
||||
|
@ -428,7 +440,7 @@ static complexf_t getbaud(v22bis_state_t *s)
|
|||
if (s->tx.shutdown)
|
||||
{
|
||||
if (++s->tx.shutdown > 10)
|
||||
return complex_setf(0.0f, 0.0f);
|
||||
return zero;
|
||||
}
|
||||
/* The first two bits define the quadrant */
|
||||
bits = get_scrambled_bit(s);
|
||||
|
@ -450,11 +462,18 @@ static complexf_t getbaud(v22bis_state_t *s)
|
|||
|
||||
SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
|
||||
{
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
complexi16_t v;
|
||||
complexi32_t x;
|
||||
complexi32_t z;
|
||||
int16_t iamp;
|
||||
#else
|
||||
complexf_t v;
|
||||
complexf_t x;
|
||||
complexf_t z;
|
||||
int i;
|
||||
int sample;
|
||||
float famp;
|
||||
#endif
|
||||
int sample;
|
||||
|
||||
if (s->tx.shutdown > 10)
|
||||
return 0;
|
||||
|
@ -463,28 +482,41 @@ SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
|
|||
if ((s->tx.baud_phase += 3) >= 40)
|
||||
{
|
||||
s->tx.baud_phase -= 40;
|
||||
s->tx.rrc_filter[s->tx.rrc_filter_step] =
|
||||
s->tx.rrc_filter[s->tx.rrc_filter_step + V22BIS_TX_FILTER_STEPS] = getbaud(s);
|
||||
v = getbaud(s);
|
||||
s->tx.rrc_filter_re[s->tx.rrc_filter_step] = v.re;
|
||||
s->tx.rrc_filter_im[s->tx.rrc_filter_step] = v.im;
|
||||
if (++s->tx.rrc_filter_step >= V22BIS_TX_FILTER_STEPS)
|
||||
s->tx.rrc_filter_step = 0;
|
||||
}
|
||||
/* Root raised cosine pulse shaping at baseband */
|
||||
x = complex_setf(0.0f, 0.0f);
|
||||
for (i = 0; i < V22BIS_TX_FILTER_STEPS; i++)
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
x.re = vec_circular_dot_prodi16(s->tx.rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step) >> 4;
|
||||
x.im = vec_circular_dot_prodi16(s->tx.rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step) >> 4;
|
||||
/* Now create and modulate the carrier */
|
||||
z = dds_complexi32(&s->tx.carrier_phase, s->tx.carrier_phase_rate);
|
||||
iamp = (x.re*z.re - x.im*z.im) >> 15;
|
||||
iamp = (int16_t) (((int32_t) iamp*s->tx.gain) >> 11);
|
||||
if (s->tx.guard_phase_rate && (s->tx.rrc_filter_re[s->tx.rrc_filter_step] != 0 || s->tx.rrc_filter_im[s->tx.rrc_filter_step] != 0))
|
||||
{
|
||||
x.re += tx_pulseshaper[39 - s->tx.baud_phase][i]*s->tx.rrc_filter[i + s->tx.rrc_filter_step].re;
|
||||
x.im += tx_pulseshaper[39 - s->tx.baud_phase][i]*s->tx.rrc_filter[i + s->tx.rrc_filter_step].im;
|
||||
/* Add the guard tone */
|
||||
iamp += dds_mod(&s->tx.guard_phase, s->tx.guard_phase_rate, s->tx.guard_tone_gain, 0);
|
||||
}
|
||||
/* Don't bother saturating. We should never clip. */
|
||||
amp[sample] = iamp;
|
||||
#else
|
||||
/* Root raised cosine pulse shaping at baseband */
|
||||
x.re = vec_circular_dot_prodf(s->tx.rrc_filter_re, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step);
|
||||
x.im = vec_circular_dot_prodf(s->tx.rrc_filter_im, tx_pulseshaper[TX_PULSESHAPER_COEFF_SETS - 1 - s->tx.baud_phase], V22BIS_TX_FILTER_STEPS, s->tx.rrc_filter_step);
|
||||
/* Now create and modulate the carrier */
|
||||
z = dds_complexf(&(s->tx.carrier_phase), s->tx.carrier_phase_rate);
|
||||
famp = (x.re*z.re - x.im*z.im)*s->tx.gain;
|
||||
if (s->tx.guard_phase_rate && (s->tx.rrc_filter[s->tx.rrc_filter_step].re != 0.0f || s->tx.rrc_filter[s->tx.rrc_filter_step].im != 0.0f))
|
||||
if (s->tx.guard_phase_rate && (s->tx.rrc_filter_re[s->tx.rrc_filter_step] != 0.0f || s->tx.rrc_filter_im[s->tx.rrc_filter_step] != 0.0f))
|
||||
{
|
||||
/* Add the guard tone */
|
||||
famp += dds_modf(&(s->tx.guard_phase), s->tx.guard_phase_rate, s->tx.guard_level, 0);
|
||||
famp += dds_modf(&s->tx.guard_phase, s->tx.guard_phase_rate, s->tx.guard_tone_gain, 0);
|
||||
}
|
||||
/* Don't bother saturating. We should never clip. */
|
||||
amp[sample] = (int16_t) lfastrintf(famp);
|
||||
#endif
|
||||
}
|
||||
return sample;
|
||||
}
|
||||
|
@ -492,34 +524,49 @@ SPAN_DECLARE_NONSTD(int) v22bis_tx(v22bis_state_t *s, int16_t amp[], int len)
|
|||
|
||||
SPAN_DECLARE(void) v22bis_tx_power(v22bis_state_t *s, float power)
|
||||
{
|
||||
float l;
|
||||
float sig_power;
|
||||
float guard_tone_power;
|
||||
float sig_gain;
|
||||
float guard_tone_gain;
|
||||
|
||||
/* If is there is a guard tone we need to scale down the signal power a bit, so the aggregate of the signal
|
||||
and guard tone power is the specified power. */
|
||||
if (s->tx.guard_phase_rate == dds_phase_ratef(550.0f))
|
||||
{
|
||||
l = 1.6f*powf(10.0f, (power - 1.0f - DBM0_MAX_POWER)/20.0f);
|
||||
s->tx.gain = l*32768.0f/(TX_PULSESHAPER_GAIN*3.0f);
|
||||
l = powf(10.0f, (power - 1.0f - 3.0f - DBM0_MAX_POWER)/20.0f);
|
||||
s->tx.guard_level = l*32768.0f;
|
||||
sig_power = power - 1.0f;
|
||||
guard_tone_power = sig_power - 3.0f;
|
||||
}
|
||||
else if(s->tx.guard_phase_rate == dds_phase_ratef(1800.0f))
|
||||
{
|
||||
l = 1.6f*powf(10.0f, (power - 1.0f - 1.0f - DBM0_MAX_POWER)/20.0f);
|
||||
s->tx.gain = l*32768.0f/(TX_PULSESHAPER_GAIN*3.0f);
|
||||
l = powf(10.0f, (power - 1.0f - 6.0f - DBM0_MAX_POWER)/20.0f);
|
||||
s->tx.guard_level = l*32768.0f;
|
||||
sig_power = power - 0.55f;
|
||||
guard_tone_power = sig_power - 6.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = 1.6f*powf(10.0f, (power - DBM0_MAX_POWER)/20.0f);
|
||||
s->tx.gain = l*32768.0f/(TX_PULSESHAPER_GAIN*3.0f);
|
||||
s->tx.guard_level = 0;
|
||||
sig_power = power;
|
||||
guard_tone_power = -9999.0f;
|
||||
}
|
||||
sig_gain = 0.4490f*powf(10.0f, (sig_power - DBM0_MAX_POWER)/20.0f)*32768.0f/TX_PULSESHAPER_GAIN;
|
||||
guard_tone_gain = powf(10.0f, (guard_tone_power - DBM0_MAX_POWER)/20.0f)*32768.0f;
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
s->tx.gain = (int16_t) sig_gain;
|
||||
s->tx.guard_tone_gain = (int16_t) guard_tone_gain;
|
||||
#else
|
||||
s->tx.gain = sig_gain;
|
||||
s->tx.guard_tone_gain = guard_tone_gain;
|
||||
#endif
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static int v22bis_tx_restart(v22bis_state_t *s)
|
||||
{
|
||||
cvec_zerof(s->tx.rrc_filter, sizeof(s->tx.rrc_filter)/sizeof(s->tx.rrc_filter[0]));
|
||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||
vec_zeroi16(s->tx.rrc_filter_re, sizeof(s->tx.rrc_filter_re)/sizeof(s->tx.rrc_filter_re[0]));
|
||||
vec_zeroi16(s->tx.rrc_filter_im, sizeof(s->tx.rrc_filter_im)/sizeof(s->tx.rrc_filter_im[0]));
|
||||
#else
|
||||
vec_zerof(s->tx.rrc_filter_re, sizeof(s->tx.rrc_filter_re)/sizeof(s->tx.rrc_filter_re[0]));
|
||||
vec_zerof(s->tx.rrc_filter_im, sizeof(s->tx.rrc_filter_im)/sizeof(s->tx.rrc_filter_im[0]));
|
||||
#endif
|
||||
s->tx.rrc_filter_step = 0;
|
||||
s->tx.scramble_reg = 0;
|
||||
s->tx.scrambler_pattern_count = 0;
|
||||
|
|
Loading…
Reference in New Issue