forked from Mirrors/freeswitch
A little more modem polishing
This commit is contained in:
parent
8396519956
commit
ac0defb874
@ -105,6 +105,8 @@ struct t4_rx_state_s
|
|||||||
|
|
||||||
/*! \brief The width of the current page, in pixels. */
|
/*! \brief The width of the current page, in pixels. */
|
||||||
uint32_t image_width;
|
uint32_t image_width;
|
||||||
|
/*! \brief The length of the current page, in pixels. */
|
||||||
|
uint32_t image_length;
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
|
@ -65,13 +65,15 @@
|
|||||||
#include "spandsp/private/v27ter_rx.h"
|
#include "spandsp/private/v27ter_rx.h"
|
||||||
|
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
#define FP_SCALE FP_Q_6_10
|
#define FP_SCALE(x) FP_Q_6_10(x)
|
||||||
#define FP_FACTOR 4096
|
#define FP_FACTOR 4096
|
||||||
#define FP_SHIFT_FACTOR 12
|
#define FP_SHIFT_FACTOR 12
|
||||||
#else
|
#else
|
||||||
#define FP_SCALE(x) (x)
|
#define FP_SCALE(x) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define FP_CONSTELLATION_SCALE(x) FP_SCALE(x)
|
||||||
|
|
||||||
#include "v27ter_rx_4800_rrc.h"
|
#include "v27ter_rx_4800_rrc.h"
|
||||||
#include "v27ter_rx_2400_rrc.h"
|
#include "v27ter_rx_2400_rrc.h"
|
||||||
|
|
||||||
@ -115,14 +117,14 @@ static const complexi16_t v27ter_constellation[8] =
|
|||||||
static const complexf_t v27ter_constellation[8] =
|
static const complexf_t v27ter_constellation[8] =
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
{FP_SCALE( 1.414f), FP_SCALE( 0.0f)}, /* 0deg */
|
{FP_CONSTELLATION_SCALE( 1.414f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0deg */
|
||||||
{FP_SCALE( 1.0f), FP_SCALE( 1.0f)}, /* 45deg */
|
{FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 45deg */
|
||||||
{FP_SCALE( 0.0f), FP_SCALE( 1.414f)}, /* 90deg */
|
{FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 1.414f)}, /* 90deg */
|
||||||
{FP_SCALE(-1.0f), FP_SCALE( 1.0f)}, /* 135deg */
|
{FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 135deg */
|
||||||
{FP_SCALE(-1.414f), FP_SCALE( 0.0f)}, /* 180deg */
|
{FP_CONSTELLATION_SCALE(-1.414f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 180deg */
|
||||||
{FP_SCALE(-1.0f), FP_SCALE(-1.0f)}, /* 225deg */
|
{FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 225deg */
|
||||||
{FP_SCALE( 0.0f), FP_SCALE(-1.414f)}, /* 270deg */
|
{FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-1.414f)}, /* 270deg */
|
||||||
{FP_SCALE( 1.0f), FP_SCALE(-1.0f)} /* 315deg */
|
{FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-1.0f)} /* 315deg */
|
||||||
};
|
};
|
||||||
|
|
||||||
SPAN_DECLARE(float) v27ter_rx_carrier_frequency(v27ter_rx_state_t *s)
|
SPAN_DECLARE(float) v27ter_rx_carrier_frequency(v27ter_rx_state_t *s)
|
||||||
@ -205,14 +207,14 @@ static void equalizer_reset(v27ter_rx_state_t *s)
|
|||||||
{
|
{
|
||||||
/* Start with an equalizer based on everything being perfect. */
|
/* Start with an equalizer based on everything being perfect. */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
static const complexi16_t x = {FP_SCALE(1.414f), FP_SCALE(0.0f)};
|
static const complexi16_t x = {FP_CONSTELLATION_SCALE(1.414f), FP_CONSTELLATION_SCALE(0.0f)};
|
||||||
|
|
||||||
cvec_zeroi16(s->eq_coeff, V27TER_EQUALIZER_LEN);
|
cvec_zeroi16(s->eq_coeff, V27TER_EQUALIZER_LEN);
|
||||||
s->eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1] = x;
|
s->eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1] = x;
|
||||||
cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN);
|
cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN);
|
||||||
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN;
|
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN;
|
||||||
#else
|
#else
|
||||||
static const complexf_t x = {1.414f, 0.0f};
|
static const complexf_t x = {FP_CONSTELLATION_SCALE(1.414f), FP_CONSTELLATION_SCALE(0.0f)};
|
||||||
|
|
||||||
cvec_zerof(s->eq_coeff, V27TER_EQUALIZER_LEN);
|
cvec_zerof(s->eq_coeff, V27TER_EQUALIZER_LEN);
|
||||||
s->eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1] = x;
|
s->eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1] = x;
|
||||||
@ -336,21 +338,15 @@ static __inline__ int find_octant(complexf_t *z)
|
|||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
abs_re = abs(z->re);
|
abs_re = abs(z->re);
|
||||||
abs_im = abs(z->im);
|
abs_im = abs(z->im);
|
||||||
if (abs_im*1000 > abs_re*414 && abs_im*1000 < abs_re*2414)
|
|
||||||
#else
|
#else
|
||||||
abs_re = fabsf(z->re);
|
abs_re = fabsf(z->re);
|
||||||
abs_im = fabsf(z->im);
|
abs_im = fabsf(z->im);
|
||||||
if (abs_im > abs_re*0.4142136f && abs_im < abs_re*2.4142136f)
|
|
||||||
#endif
|
#endif
|
||||||
|
if (abs_im*FP_SCALE(1.0f) > abs_re*FP_SCALE(0.4142136f) && abs_im*FP_SCALE(1.0f) < abs_re*FP_SCALE(2.4142136f))
|
||||||
{
|
{
|
||||||
/* Split the space along the two axes. */
|
/* Split the space along the two axes. */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
b1 = (z->re < FP_SCALE(0.0f));
|
||||||
b1 = (z->re < 0);
|
b2 = (z->im < FP_SCALE(0.0f));
|
||||||
b2 = (z->im < 0);
|
|
||||||
#else
|
|
||||||
b1 = (z->re < 0.0f);
|
|
||||||
b2 = (z->im < 0.0f);
|
|
||||||
#endif
|
|
||||||
bits = (b2 << 2) | ((b1 ^ b2) << 1) | 1;
|
bits = (b2 << 2) | ((b1 ^ b2) << 1) | 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -402,10 +398,7 @@ static __inline__ void put_bit(v27ter_rx_state_t *s, int bit)
|
|||||||
{
|
{
|
||||||
int out_bit;
|
int out_bit;
|
||||||
|
|
||||||
bit &= 1;
|
|
||||||
|
|
||||||
out_bit = descramble(s, bit);
|
out_bit = descramble(s, bit);
|
||||||
|
|
||||||
/* We need to strip the last part of the training before we let data
|
/* We need to strip the last part of the training before we let data
|
||||||
go to the application. */
|
go to the application. */
|
||||||
if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
|
if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
|
||||||
@ -519,13 +512,13 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
|
|||||||
complexi16_t z;
|
complexi16_t z;
|
||||||
complexi16_t z16;
|
complexi16_t z16;
|
||||||
const complexi16_t *target;
|
const complexi16_t *target;
|
||||||
static const complexi16_t zero = {0, 0};
|
static const complexi16_t zero = {FP_SCALE(0.0f), FP_SCALE(0.0f)};
|
||||||
#else
|
#else
|
||||||
float p;
|
float p;
|
||||||
complexf_t z;
|
complexf_t z;
|
||||||
complexf_t zz;
|
complexf_t zz;
|
||||||
const complexf_t *target;
|
const complexf_t *target;
|
||||||
static const complexf_t zero = {0.0f, 0.0f};
|
static const complexf_t zero = {FP_SCALE(0.0f), FP_SCALE(0.0f)};
|
||||||
#endif
|
#endif
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
@ -697,17 +690,13 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
|
|||||||
{
|
{
|
||||||
/* At 4800bps the symbols are 1.08238 (Euclidian) apart.
|
/* At 4800bps the symbols are 1.08238 (Euclidian) apart.
|
||||||
At 2400bps the symbols are 2.0 (Euclidian) apart. */
|
At 2400bps the symbols are 2.0 (Euclidian) apart. */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
if ((s->bit_rate == 4800 && s->training_error < FP_CONSTELLATION_SCALE(V27TER_TRAINING_SEG_6_LEN)*FP_CONSTELLATION_SCALE(0.25f))
|
||||||
if ((s->bit_rate == 4800 && s->training_error < V27TER_TRAINING_SEG_6_LEN*FP_FACTOR*FP_FACTOR/4)
|
|
||||||
||
|
||
|
||||||
(s->bit_rate == 2400 && s->training_error < V27TER_TRAINING_SEG_6_LEN*FP_FACTOR*FP_FACTOR/2))
|
(s->bit_rate == 2400 && s->training_error < FP_CONSTELLATION_SCALE(V27TER_TRAINING_SEG_6_LEN)*FP_CONSTELLATION_SCALE(0.5f)))
|
||||||
{
|
{
|
||||||
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %d)\n", s->bit_rate, s->training_error);
|
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %d)\n", s->bit_rate, s->training_error);
|
||||||
#else
|
#else
|
||||||
if ((s->bit_rate == 4800 && s->training_error < V27TER_TRAINING_SEG_6_LEN*0.25f)
|
|
||||||
||
|
|
||||||
(s->bit_rate == 2400 && s->training_error < V27TER_TRAINING_SEG_6_LEN*0.5f))
|
|
||||||
{
|
|
||||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %f)\n", s->bit_rate, s->training_error);
|
span_log(&s->logging, SPAN_LOG_FLOW, "Training succeeded at %dbps (constellation mismatch %f)\n", s->bit_rate, s->training_error);
|
||||||
#endif
|
#endif
|
||||||
/* We are up and running */
|
/* We are up and running */
|
||||||
@ -858,9 +847,9 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
|
|||||||
{
|
{
|
||||||
/* Only AGC during the initial training */
|
/* Only AGC during the initial training */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
s->agc_scaling = saturate16(((int32_t) (1024.0f*FP_FACTOR*1.414f))/fixed_sqrt32(power));
|
s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.414f)*1024.0f))/fixed_sqrt32(power));
|
||||||
#else
|
#else
|
||||||
s->agc_scaling = (1.0f/RX_PULSESHAPER_4800_GAIN)*1.414f/sqrtf(power);
|
s->agc_scaling = (FP_SCALE(1.414f)/RX_PULSESHAPER_4800_GAIN)/fixed_sqrt32(power);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/* Pulse shape while still at the carrier frequency, using a quadrature
|
/* Pulse shape while still at the carrier frequency, using a quadrature
|
||||||
@ -870,7 +859,6 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
|
|||||||
step = -s->eq_put_step;
|
step = -s->eq_put_step;
|
||||||
if (step > RX_PULSESHAPER_4800_COEFF_SETS - 1)
|
if (step > RX_PULSESHAPER_4800_COEFF_SETS - 1)
|
||||||
step = RX_PULSESHAPER_4800_COEFF_SETS - 1;
|
step = RX_PULSESHAPER_4800_COEFF_SETS - 1;
|
||||||
s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2;
|
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_4800_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
|
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_4800_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
|
||||||
sample.re = (v*s->agc_scaling) >> 10;
|
sample.re = (v*s->agc_scaling) >> 10;
|
||||||
@ -888,6 +876,7 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
|
|||||||
zz.re = sample.re*z.re - sample.im*z.im;
|
zz.re = sample.re*z.re - sample.im*z.im;
|
||||||
zz.im = -sample.re*z.im - sample.im*z.re;
|
zz.im = -sample.re*z.im - sample.im*z.re;
|
||||||
#endif
|
#endif
|
||||||
|
s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2;
|
||||||
process_half_baud(s, &zz);
|
process_half_baud(s, &zz);
|
||||||
}
|
}
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
@ -920,9 +909,9 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
|
|||||||
{
|
{
|
||||||
/* Only AGC during the initial training */
|
/* Only AGC during the initial training */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
s->agc_scaling = saturate16(((int32_t) (1024.0f*FP_FACTOR*1.414f))/fixed_sqrt32(power));
|
s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.414f)*1024.0f))/fixed_sqrt32(power));
|
||||||
#else
|
#else
|
||||||
s->agc_scaling = (1.0f/RX_PULSESHAPER_2400_GAIN)*1.414f/sqrtf(power);
|
s->agc_scaling = (FP_SCALE(1.414f)/RX_PULSESHAPER_2400_GAIN)/fixed_sqrt32(power);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/* Pulse shape while still at the carrier frequency, using a quadrature
|
/* Pulse shape while still at the carrier frequency, using a quadrature
|
||||||
@ -932,7 +921,6 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
|
|||||||
step = -s->eq_put_step;
|
step = -s->eq_put_step;
|
||||||
if (step > RX_PULSESHAPER_2400_COEFF_SETS - 1)
|
if (step > RX_PULSESHAPER_2400_COEFF_SETS - 1)
|
||||||
step = RX_PULSESHAPER_2400_COEFF_SETS - 1;
|
step = RX_PULSESHAPER_2400_COEFF_SETS - 1;
|
||||||
s->eq_put_step += RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
|
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_2400_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
|
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_2400_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
|
||||||
sample.re = (v*s->agc_scaling) >> 10;
|
sample.re = (v*s->agc_scaling) >> 10;
|
||||||
@ -950,6 +938,7 @@ SPAN_DECLARE_NONSTD(int) v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], in
|
|||||||
zz.re = sample.re*z.re - sample.im*z.im;
|
zz.re = sample.re*z.re - sample.im*z.im;
|
||||||
zz.im = -sample.re*z.im - sample.im*z.re;
|
zz.im = -sample.re*z.im - sample.im*z.re;
|
||||||
#endif
|
#endif
|
||||||
|
s->eq_put_step += RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
|
||||||
process_half_baud(s, &zz);
|
process_half_baud(s, &zz);
|
||||||
}
|
}
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
@ -1027,11 +1016,10 @@ SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_
|
|||||||
|
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
|
vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
|
||||||
s->training_error = 0;
|
|
||||||
#else
|
#else
|
||||||
vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
|
vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
|
||||||
s->training_error = 0.0f;
|
|
||||||
#endif
|
#endif
|
||||||
|
s->training_error = FP_CONSTELLATION_SCALE(0.0f);
|
||||||
s->rrc_filter_step = 0;
|
s->rrc_filter_step = 0;
|
||||||
|
|
||||||
s->scramble_reg = 0x3C;
|
s->scramble_reg = 0x3C;
|
||||||
@ -1068,9 +1056,9 @@ SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_
|
|||||||
{
|
{
|
||||||
s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
|
s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
s->agc_scaling = (float) (1024.0f*FP_FACTOR)*1.414f/283.0f;
|
s->agc_scaling = (float) FP_SCALE(1.414f)*1024.0f/283.0f;
|
||||||
#else
|
#else
|
||||||
s->agc_scaling = (1.0f/RX_PULSESHAPER_4800_GAIN)*1.414f/283.0f;
|
s->agc_scaling = (FP_SCALE(1.414f)/RX_PULSESHAPER_4800_GAIN)/283.0f;
|
||||||
#endif
|
#endif
|
||||||
equalizer_reset(s);
|
equalizer_reset(s);
|
||||||
}
|
}
|
||||||
|
@ -64,17 +64,25 @@
|
|||||||
#include "spandsp/private/v29rx.h"
|
#include "spandsp/private/v29rx.h"
|
||||||
|
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
#define FP_SCALE FP_Q_4_12
|
#define FP_SCALE(x) FP_Q_4_12(x)
|
||||||
#define FP_FACTOR 4096
|
#define FP_FACTOR 4096
|
||||||
#define FP_SHIFT_FACTOR 12
|
#define FP_SHIFT_FACTOR 12
|
||||||
#else
|
#else
|
||||||
#define FP_SCALE(x) (x)
|
#define FP_SCALE(x) (x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "v29rx_rrc.h"
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
|
#define FP_SYNC_SCALE(x) FP_Q_6_10(x)
|
||||||
|
#define FP_SYNC_SCALE_32(x) FP_Q_6_10_32(x)
|
||||||
|
#define FP_SYNC_SHIFT_FACTOR 10
|
||||||
|
#else
|
||||||
|
#define FP_SYNC_SCALE(x) (x)
|
||||||
|
#define FP_SYNC_SCALE_32(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
#define FP_CONSTELLATION_SCALE(x) FP_SCALE(x)
|
#define FP_CONSTELLATION_SCALE(x) FP_SCALE(x)
|
||||||
|
|
||||||
|
#include "v29rx_rrc.h"
|
||||||
#include "v29tx_constellation_maps.h"
|
#include "v29tx_constellation_maps.h"
|
||||||
|
|
||||||
/*! The nominal frequency of the carrier, in Hertz */
|
/*! The nominal frequency of the carrier, in Hertz */
|
||||||
@ -92,6 +100,23 @@
|
|||||||
/*! The length of training segment 4, in symbols */
|
/*! The length of training segment 4, in symbols */
|
||||||
#define V29_TRAINING_SEG_4_LEN 48
|
#define V29_TRAINING_SEG_4_LEN 48
|
||||||
|
|
||||||
|
/* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
|
||||||
|
/* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */
|
||||||
|
/* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */
|
||||||
|
#define SIN_LOW_BAND_EDGE 0.382683432f
|
||||||
|
#define COS_LOW_BAND_EDGE 0.923879533f
|
||||||
|
#define SIN_HIGH_BAND_EDGE 0.760405966f
|
||||||
|
#define COS_HIGH_BAND_EDGE -0.649448048f
|
||||||
|
#define ALPHA 0.99f
|
||||||
|
|
||||||
|
#define SYNC_LOW_BAND_EDGE_COEFF_0 FP_SYNC_SCALE(2.0f*ALPHA*COS_LOW_BAND_EDGE)
|
||||||
|
#define SYNC_LOW_BAND_EDGE_COEFF_1 FP_SYNC_SCALE(-ALPHA*ALPHA)
|
||||||
|
#define SYNC_LOW_BAND_EDGE_COEFF_2 FP_SYNC_SCALE(-ALPHA*SIN_LOW_BAND_EDGE)
|
||||||
|
#define SYNC_HIGH_BAND_EDGE_COEFF_0 FP_SYNC_SCALE(2.0f*ALPHA*COS_HIGH_BAND_EDGE)
|
||||||
|
#define SYNC_HIGH_BAND_EDGE_COEFF_1 FP_SYNC_SCALE(-ALPHA*ALPHA)
|
||||||
|
#define SYNC_HIGH_BAND_EDGE_COEFF_2 FP_SYNC_SCALE(-ALPHA*SIN_HIGH_BAND_EDGE)
|
||||||
|
#define SYNC_MIXED_EDGES_COEFF_3 FP_SYNC_SCALE(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
TRAINING_STAGE_NORMAL_OPERATION = 0,
|
TRAINING_STAGE_NORMAL_OPERATION = 0,
|
||||||
@ -130,33 +155,6 @@ static const uint8_t space_map_9600[20][20] =
|
|||||||
/* Middle ^ Middle */
|
/* Middle ^ Middle */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Coefficients for the band edge symbol timing synchroniser (alpha = 0.99) */
|
|
||||||
/* low_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ - BAUD_RATE/2.0f)/SAMPLE_RATE; */
|
|
||||||
/* high_edge = 2.0f*M_PI*(CARRIER_NOMINAL_FREQ + BAUD_RATE/2.0f)/SAMPLE_RATE; */
|
|
||||||
#define SIN_LOW_BAND_EDGE 0.382683432f
|
|
||||||
#define COS_LOW_BAND_EDGE 0.923879533f
|
|
||||||
#define SIN_HIGH_BAND_EDGE 0.760405966f
|
|
||||||
#define COS_HIGH_BAND_EDGE -0.649448048f
|
|
||||||
#define ALPHA 0.99f
|
|
||||||
|
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
|
||||||
#define SYNC_LOW_BAND_EDGE_COEFF_0 FP_Q_6_10(2.0f*ALPHA*COS_LOW_BAND_EDGE)
|
|
||||||
#define SYNC_LOW_BAND_EDGE_COEFF_1 FP_Q_6_10(-ALPHA*ALPHA)
|
|
||||||
#define SYNC_LOW_BAND_EDGE_COEFF_2 FP_Q_6_10(-ALPHA*SIN_LOW_BAND_EDGE)
|
|
||||||
#define SYNC_HIGH_BAND_EDGE_COEFF_0 FP_Q_6_10(2.0f*ALPHA*COS_HIGH_BAND_EDGE)
|
|
||||||
#define SYNC_HIGH_BAND_EDGE_COEFF_1 FP_Q_6_10(-ALPHA*ALPHA)
|
|
||||||
#define SYNC_HIGH_BAND_EDGE_COEFF_2 FP_Q_6_10(-ALPHA*SIN_HIGH_BAND_EDGE)
|
|
||||||
#define SYNC_MIXED_EDGES_COEFF_3 FP_Q_6_10(-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
|
|
||||||
#else
|
|
||||||
#define SYNC_LOW_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_LOW_BAND_EDGE)
|
|
||||||
#define SYNC_LOW_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
|
|
||||||
#define SYNC_LOW_BAND_EDGE_COEFF_2 (-ALPHA*SIN_LOW_BAND_EDGE)
|
|
||||||
#define SYNC_HIGH_BAND_EDGE_COEFF_0 (2.0f*ALPHA*COS_HIGH_BAND_EDGE)
|
|
||||||
#define SYNC_HIGH_BAND_EDGE_COEFF_1 (-ALPHA*ALPHA)
|
|
||||||
#define SYNC_HIGH_BAND_EDGE_COEFF_2 (-ALPHA*SIN_HIGH_BAND_EDGE)
|
|
||||||
#define SYNC_MIXED_EDGES_COEFF_3 (-ALPHA*ALPHA*(SIN_HIGH_BAND_EDGE*COS_LOW_BAND_EDGE - SIN_LOW_BAND_EDGE*COS_HIGH_BAND_EDGE))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SPAN_DECLARE(float) v29_rx_carrier_frequency(v29_rx_state_t *s)
|
SPAN_DECLARE(float) v29_rx_carrier_frequency(v29_rx_state_t *s)
|
||||||
{
|
{
|
||||||
return dds_frequencyf(s->carrier_phase_rate);
|
return dds_frequencyf(s->carrier_phase_rate);
|
||||||
@ -234,14 +232,14 @@ static void equalizer_reset(v29_rx_state_t *s)
|
|||||||
{
|
{
|
||||||
/* Start with an equalizer based on everything being perfect */
|
/* Start with an equalizer based on everything being perfect */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
static const complexi16_t x = {FP_SCALE(3.0f), FP_SCALE(0.0f)};
|
static const complexi16_t x = {FP_CONSTELLATION_SCALE(3.0f), FP_CONSTELLATION_SCALE(0.0f)};
|
||||||
|
|
||||||
cvec_zeroi16(s->eq_coeff, V29_EQUALIZER_LEN);
|
cvec_zeroi16(s->eq_coeff, V29_EQUALIZER_LEN);
|
||||||
s->eq_coeff[V29_EQUALIZER_PRE_LEN] = x;
|
s->eq_coeff[V29_EQUALIZER_PRE_LEN] = x;
|
||||||
cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN);
|
cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN);
|
||||||
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN;
|
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN;
|
||||||
#else
|
#else
|
||||||
static const complexf_t x = {3.0f, 0.0f};
|
static const complexf_t x = {FP_CONSTELLATION_SCALE(3.0f), FP_CONSTELLATION_SCALE(0.0f)};
|
||||||
|
|
||||||
cvec_zerof(s->eq_coeff, V29_EQUALIZER_LEN);
|
cvec_zerof(s->eq_coeff, V29_EQUALIZER_LEN);
|
||||||
s->eq_coeff[V29_EQUALIZER_PRE_LEN] = x;
|
s->eq_coeff[V29_EQUALIZER_PRE_LEN] = x;
|
||||||
@ -262,8 +260,8 @@ static __inline__ complexi16_t equalizer_get(v29_rx_state_t *s)
|
|||||||
|
|
||||||
/* Get the next equalized value. */
|
/* Get the next equalized value. */
|
||||||
zz = cvec_circular_dot_prodi16(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step);
|
zz = cvec_circular_dot_prodi16(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step);
|
||||||
z.re = zz.re >> FP_SHIFT_FACTOR;
|
z.re = zz.re >> FP_CONSTELLATION_SHIFT_FACTOR;
|
||||||
z.im = zz.im >> FP_SHIFT_FACTOR;
|
z.im = zz.im >> FP_CONSTELLATION_SHIFT_FACTOR;
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@ -300,36 +298,6 @@ static void tune_equalizer(v29_rx_state_t *s, const complexf_t *z, const complex
|
|||||||
#endif
|
#endif
|
||||||
/*- End of function --------------------------------------------------------*/
|
/*- End of function --------------------------------------------------------*/
|
||||||
|
|
||||||
static int scrambled_training_bit(v29_rx_state_t *s)
|
|
||||||
{
|
|
||||||
int bit;
|
|
||||||
|
|
||||||
/* Segment 3 of the training sequence - the scrambled CDCD part. */
|
|
||||||
/* Apply the 1 + x^-6 + x^-7 scrambler */
|
|
||||||
bit = s->training_scramble_reg & 1;
|
|
||||||
s->training_scramble_reg >>= 1;
|
|
||||||
if (bit ^ (s->training_scramble_reg & 1))
|
|
||||||
s->training_scramble_reg |= 0x40;
|
|
||||||
return bit;
|
|
||||||
}
|
|
||||||
/*- End of function --------------------------------------------------------*/
|
|
||||||
|
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
|
||||||
static __inline__ int find_quadrant(const complexi16_t *z)
|
|
||||||
#else
|
|
||||||
static __inline__ int find_quadrant(const complexf_t *z)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
int b1;
|
|
||||||
int b2;
|
|
||||||
|
|
||||||
/* Split the space along the two diagonals. */
|
|
||||||
b1 = (z->im > z->re);
|
|
||||||
b2 = (z->im < -z->re);
|
|
||||||
return (b2 << 1) | (b1 ^ b2);
|
|
||||||
}
|
|
||||||
/*- End of function --------------------------------------------------------*/
|
|
||||||
|
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
static __inline__ void track_carrier(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
|
static __inline__ void track_carrier(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
|
||||||
#else
|
#else
|
||||||
@ -355,37 +323,71 @@ static __inline__ void track_carrier(v29_rx_state_t *s, const complexf_t *z, con
|
|||||||
different amplitudes of the various target positions scale things. This isn't all bad,
|
different amplitudes of the various target positions scale things. This isn't all bad,
|
||||||
as the angular error for the larger amplitude constellation points is probably
|
as the angular error for the larger amplitude constellation points is probably
|
||||||
a more reliable indicator, and we are weighting it as such. */
|
a more reliable indicator, and we are weighting it as such. */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
|
||||||
error = (((int32_t) z->im*target->re) >> FP_SHIFT_FACTOR) - (((int32_t) z->re*target->im) >> FP_SHIFT_FACTOR);
|
|
||||||
#else
|
|
||||||
error = z->im*target->re - z->re*target->im;
|
|
||||||
#endif
|
|
||||||
/* Use a proportional-integral approach to tracking the carrier. The PI
|
/* Use a proportional-integral approach to tracking the carrier. The PI
|
||||||
parameters are coarser at first, until we get precisely on target. Then,
|
parameters are coarser at first, until we get precisely on target. Then,
|
||||||
the filter will be damped more to keep us on target. */
|
the filter will be damped more to keep us on target. */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
|
error = (((int32_t) z->im*target->re) >> FP_SHIFT_FACTOR) - (((int32_t) z->re*target->im) >> FP_SHIFT_FACTOR);
|
||||||
s->carrier_phase_rate += ((s->carrier_track_i*error) >> FP_SHIFT_FACTOR);
|
s->carrier_phase_rate += ((s->carrier_track_i*error) >> FP_SHIFT_FACTOR);
|
||||||
s->carrier_phase += ((s->carrier_track_p*error) >> FP_SHIFT_FACTOR);
|
s->carrier_phase += ((s->carrier_track_p*error) >> FP_SHIFT_FACTOR);
|
||||||
#else
|
#else
|
||||||
|
error = z->im*target->re - z->re*target->im;
|
||||||
s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error);
|
s->carrier_phase_rate += (int32_t) (s->carrier_track_i*error);
|
||||||
s->carrier_phase += (int32_t) (s->carrier_track_p*error);
|
s->carrier_phase += (int32_t) (s->carrier_track_p*error);
|
||||||
//span_log(&s->logging, SPAN_LOG_FLOW, "Im = %15.5f f = %15.5f\n", error, dds_frequencyf(s->carrier_phase_rate));
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
/*- End of function --------------------------------------------------------*/
|
/*- End of function --------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
|
static __inline__ int find_quadrant(const complexi16_t *z)
|
||||||
|
#else
|
||||||
|
static __inline__ int find_quadrant(const complexf_t *z)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
int b1;
|
||||||
|
int b2;
|
||||||
|
|
||||||
|
/* Split the space along the two diagonals. */
|
||||||
|
b1 = (z->im > z->re);
|
||||||
|
b2 = (z->im < -z->re);
|
||||||
|
return (b2 << 1) | (b1 ^ b2);
|
||||||
|
}
|
||||||
|
/*- End of function --------------------------------------------------------*/
|
||||||
|
|
||||||
|
static int scrambled_training_bit(v29_rx_state_t *s)
|
||||||
|
{
|
||||||
|
int bit;
|
||||||
|
|
||||||
|
/* Segment 3 of the training sequence - the scrambled CDCD part. */
|
||||||
|
/* Apply the 1 + x^-6 + x^-7 scrambler */
|
||||||
|
bit = s->training_scramble_reg & 1;
|
||||||
|
s->training_scramble_reg >>= 1;
|
||||||
|
if (bit ^ (s->training_scramble_reg & 1))
|
||||||
|
s->training_scramble_reg |= 0x40;
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
/*- End of function --------------------------------------------------------*/
|
||||||
|
|
||||||
|
static __inline__ int descramble(v29_rx_state_t *s, int in_bit)
|
||||||
|
{
|
||||||
|
int out_bit;
|
||||||
|
|
||||||
|
/* Descramble the bit */
|
||||||
|
in_bit &= 1;
|
||||||
|
out_bit = (in_bit ^ (s->scramble_reg >> (18 - 1)) ^ (s->scramble_reg >> (23 - 1))) & 1;
|
||||||
|
s->scramble_reg = (s->scramble_reg << 1) | in_bit;
|
||||||
|
|
||||||
|
return out_bit;
|
||||||
|
}
|
||||||
|
/*- End of function --------------------------------------------------------*/
|
||||||
|
|
||||||
static __inline__ void put_bit(v29_rx_state_t *s, int bit)
|
static __inline__ void put_bit(v29_rx_state_t *s, int bit)
|
||||||
{
|
{
|
||||||
int out_bit;
|
int out_bit;
|
||||||
|
|
||||||
bit &= 1;
|
|
||||||
|
|
||||||
/* Descramble the bit */
|
|
||||||
out_bit = (bit ^ (s->scramble_reg >> (18 - 1)) ^ (s->scramble_reg >> (23 - 1))) & 1;
|
|
||||||
s->scramble_reg = (s->scramble_reg << 1) | bit;
|
|
||||||
|
|
||||||
/* We need to strip the last part of the training - the test period of all 1s -
|
/* We need to strip the last part of the training - the test period of all 1s -
|
||||||
before we let data go to the application. */
|
before we let data go to the application. */
|
||||||
|
out_bit = descramble(s, bit);
|
||||||
if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
|
if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
|
||||||
{
|
{
|
||||||
s->put_bit(s->put_bit_user_data, out_bit);
|
s->put_bit(s->put_bit_user_data, out_bit);
|
||||||
@ -431,11 +433,11 @@ static void decode_baud(v29_rx_state_t *s, complexf_t *z)
|
|||||||
{
|
{
|
||||||
/* 9600 and 7200 are quite similar. */
|
/* 9600 and 7200 are quite similar. */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
re = (z->re + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
|
re = (z->re + FP_CONSTELLATION_SCALE(5.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1);
|
||||||
im = (z->im + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
|
im = (z->im + FP_CONSTELLATION_SCALE(5.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1);
|
||||||
#else
|
#else
|
||||||
re = (int) ((z->re + 5.0f)*2.0f);
|
re = (int) ((z->re + FP_CONSTELLATION_SCALE(5.0f))*2.0f);
|
||||||
im = (int) ((z->im + 5.0f)*2.0f);
|
im = (int) ((z->im + FP_CONSTELLATION_SCALE(5.0f))*2.0f);
|
||||||
#endif
|
#endif
|
||||||
if (re > 19)
|
if (re > 19)
|
||||||
re = 19;
|
re = 19;
|
||||||
@ -499,9 +501,9 @@ static __inline__ void symbol_sync(v29_rx_state_t *s)
|
|||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
/* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
|
/* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
|
||||||
/* Cross correlate */
|
/* Cross correlate */
|
||||||
v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*SYNC_LOW_BAND_EDGE_COEFF_2
|
v = (((s->symbol_sync_low[1] >> (FP_SYNC_SHIFT_FACTOR/2))*(s->symbol_sync_high[0] >> (FP_SYNC_SHIFT_FACTOR/2))) >> 14)*SYNC_LOW_BAND_EDGE_COEFF_2
|
||||||
- (((s->symbol_sync_low[0] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_HIGH_BAND_EDGE_COEFF_2
|
- (((s->symbol_sync_low[0] >> (FP_SYNC_SHIFT_FACTOR/2))*(s->symbol_sync_high[1] >> (FP_SYNC_SHIFT_FACTOR/2))) >> 14)*SYNC_HIGH_BAND_EDGE_COEFF_2
|
||||||
+ (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_MIXED_EDGES_COEFF_3;
|
+ (((s->symbol_sync_low[1] >> (FP_SYNC_SHIFT_FACTOR/2))*(s->symbol_sync_high[1] >> (FP_SYNC_SHIFT_FACTOR/2))) >> 14)*SYNC_MIXED_EDGES_COEFF_3;
|
||||||
/* Filter away any DC component */
|
/* Filter away any DC component */
|
||||||
p = v - s->symbol_sync_dc_filter[1];
|
p = v - s->symbol_sync_dc_filter[1];
|
||||||
s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
|
s->symbol_sync_dc_filter[1] = s->symbol_sync_dc_filter[0];
|
||||||
@ -509,15 +511,6 @@ static __inline__ void symbol_sync(v29_rx_state_t *s)
|
|||||||
/* A little integration will now filter away much of the HF noise */
|
/* A little integration will now filter away much of the HF noise */
|
||||||
s->baud_phase -= p;
|
s->baud_phase -= p;
|
||||||
v = labs(s->baud_phase);
|
v = labs(s->baud_phase);
|
||||||
if (v > 30*FP_FACTOR)
|
|
||||||
{
|
|
||||||
i = (v > 1000*FP_FACTOR) ? 5 : 1;
|
|
||||||
if (s->baud_phase < 0)
|
|
||||||
i = -i;
|
|
||||||
//printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
|
|
||||||
s->eq_put_step += i;
|
|
||||||
s->total_baud_timing_correction += i;
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
/* Cross correlate */
|
/* Cross correlate */
|
||||||
v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2
|
v = s->symbol_sync_low[1]*s->symbol_sync_high[0]*SYNC_LOW_BAND_EDGE_COEFF_2
|
||||||
@ -530,16 +523,16 @@ static __inline__ void symbol_sync(v29_rx_state_t *s)
|
|||||||
/* A little integration will now filter away much of the HF noise */
|
/* A little integration will now filter away much of the HF noise */
|
||||||
s->baud_phase -= p;
|
s->baud_phase -= p;
|
||||||
v = fabsf(s->baud_phase);
|
v = fabsf(s->baud_phase);
|
||||||
if (v > 30.0f)
|
#endif
|
||||||
|
if (v > FP_SYNC_SCALE_32(30.0f))
|
||||||
{
|
{
|
||||||
i = (v > 1000.0f) ? 5 : 1;
|
i = (v > FP_SYNC_SCALE_32(1000.0f)) ? 5 : 1;
|
||||||
if (s->baud_phase < 0.0f)
|
if (s->baud_phase < FP_SYNC_SCALE_32(0.0f))
|
||||||
i = -i;
|
i = -i;
|
||||||
//printf("v = %10.5f %5d - %f %f %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
|
//printf("v = %10.5f %5d - %f %f %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
|
||||||
s->eq_put_step += i;
|
s->eq_put_step += i;
|
||||||
s->total_baud_timing_correction += i;
|
s->total_baud_timing_correction += i;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
/*- End of function --------------------------------------------------------*/
|
/*- End of function --------------------------------------------------------*/
|
||||||
|
|
||||||
@ -560,13 +553,13 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
|
|||||||
complexi16_t z;
|
complexi16_t z;
|
||||||
complexi16_t z16;
|
complexi16_t z16;
|
||||||
const complexi16_t *target;
|
const complexi16_t *target;
|
||||||
static const complexi16_t zero = {0, 0};
|
static const complexi16_t zero = {FP_CONSTELLATION_SCALE(0.0f), FP_CONSTELLATION_SCALE(0.0f)};
|
||||||
#else
|
#else
|
||||||
float p;
|
float p;
|
||||||
complexf_t z;
|
complexf_t z;
|
||||||
complexf_t zz;
|
complexf_t zz;
|
||||||
const complexf_t *target;
|
const complexf_t *target;
|
||||||
static const complexf_t zero = {0.0f, 0.0f};
|
static const complexf_t zero = {FP_CONSTELLATION_SCALE(0.0f), FP_CONSTELLATION_SCALE(0.0f)};
|
||||||
#endif
|
#endif
|
||||||
int bit;
|
int bit;
|
||||||
int i;
|
int i;
|
||||||
@ -606,13 +599,15 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
|
|||||||
s->training_stage = TRAINING_STAGE_LOG_PHASE;
|
s->training_stage = TRAINING_STAGE_LOG_PHASE;
|
||||||
vec_zeroi32(s->diff_angles, 16);
|
vec_zeroi32(s->diff_angles, 16);
|
||||||
s->last_angles[0] = arctan2(z.im, z.re);
|
s->last_angles[0] = arctan2(z.im, z.re);
|
||||||
|
if (s->agc_scaling_save == FP_SCALE(0.0f))
|
||||||
|
{
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
if (s->agc_scaling_save == 0)
|
span_log(&s->logging, SPAN_LOG_FLOW, "Locking AGC at %d\n", s->agc_scaling);
|
||||||
s->agc_scaling_save = s->agc_scaling;
|
|
||||||
#else
|
#else
|
||||||
if (s->agc_scaling_save == 0.0f)
|
span_log(&s->logging, SPAN_LOG_FLOW, "Locking AGC at %f\n", s->agc_scaling);
|
||||||
s->agc_scaling_save = s->agc_scaling;
|
|
||||||
#endif
|
#endif
|
||||||
|
s->agc_scaling_save = s->agc_scaling;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TRAINING_STAGE_LOG_PHASE:
|
case TRAINING_STAGE_LOG_PHASE:
|
||||||
@ -655,11 +650,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
|
|||||||
{
|
{
|
||||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
|
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
|
||||||
/* Park this modem */
|
/* Park this modem */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
s->agc_scaling_save = FP_SCALE(0.0f);
|
||||||
s->agc_scaling_save = 0;
|
|
||||||
#else
|
|
||||||
s->agc_scaling_save = 0.0f;
|
|
||||||
#endif
|
|
||||||
s->training_stage = TRAINING_STAGE_PARKED;
|
s->training_stage = TRAINING_STAGE_PARKED;
|
||||||
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
|
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
|
||||||
break;
|
break;
|
||||||
@ -695,11 +686,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
|
|||||||
of a real training sequence. */
|
of a real training sequence. */
|
||||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
|
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
|
||||||
/* Park this modem */
|
/* Park this modem */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
s->agc_scaling_save = FP_SCALE(0.0f);
|
||||||
s->agc_scaling_save = 0;
|
|
||||||
#else
|
|
||||||
s->agc_scaling_save = 0.0f;
|
|
||||||
#endif
|
|
||||||
s->training_stage = TRAINING_STAGE_PARKED;
|
s->training_stage = TRAINING_STAGE_PARKED;
|
||||||
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
|
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
|
||||||
}
|
}
|
||||||
@ -715,12 +702,11 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
|
|||||||
if (++s->training_count >= V29_TRAINING_SEG_3_LEN - 48)
|
if (++s->training_count >= V29_TRAINING_SEG_3_LEN - 48)
|
||||||
{
|
{
|
||||||
s->training_stage = TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST;
|
s->training_stage = TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST;
|
||||||
|
s->training_error = FP_CONSTELLATION_SCALE(0.0f);
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
s->training_error = 0;
|
|
||||||
s->carrier_track_i = 200;
|
s->carrier_track_i = 200;
|
||||||
s->carrier_track_p = 1000000;
|
s->carrier_track_p = 1000000;
|
||||||
#else
|
#else
|
||||||
s->training_error = 0.0f;
|
|
||||||
s->carrier_track_i = 200.0f;
|
s->carrier_track_i = 200.0f;
|
||||||
s->carrier_track_p = 1000000.0f;
|
s->carrier_track_p = 1000000.0f;
|
||||||
#endif
|
#endif
|
||||||
@ -746,15 +732,12 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
|
|||||||
{
|
{
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %d\n", s->training_error);
|
span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %d\n", s->training_error);
|
||||||
if (s->training_error < 48*2*FP_FACTOR*FP_FACTOR)
|
|
||||||
{
|
|
||||||
s->training_error = 0;
|
|
||||||
#else
|
#else
|
||||||
span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %f\n", s->training_error);
|
span_log(&s->logging, SPAN_LOG_FLOW, "Constellation mismatch %f\n", s->training_error);
|
||||||
if (s->training_error < 48.0f*2.0f)
|
|
||||||
{
|
|
||||||
s->training_error = 0.0f;
|
|
||||||
#endif
|
#endif
|
||||||
|
if (s->training_error < FP_CONSTELLATION_SCALE(48.0f)*FP_CONSTELLATION_SCALE(2.0f))
|
||||||
|
{
|
||||||
|
s->training_error = FP_CONSTELLATION_SCALE(0.0f);
|
||||||
s->training_count = 0;
|
s->training_count = 0;
|
||||||
s->constellation_state = 0;
|
s->constellation_state = 0;
|
||||||
s->training_stage = TRAINING_STAGE_TEST_ONES;
|
s->training_stage = TRAINING_STAGE_TEST_ONES;
|
||||||
@ -763,11 +746,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
|
|||||||
{
|
{
|
||||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n");
|
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (convergence failed)\n");
|
||||||
/* Park this modem */
|
/* Park this modem */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
s->agc_scaling_save = FP_SCALE(0.0f);
|
||||||
s->agc_scaling_save = 0;
|
|
||||||
#else
|
|
||||||
s->agc_scaling_save = 0.0f;
|
|
||||||
#endif
|
|
||||||
s->training_stage = TRAINING_STAGE_PARKED;
|
s->training_stage = TRAINING_STAGE_PARKED;
|
||||||
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
|
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
|
||||||
}
|
}
|
||||||
@ -789,11 +768,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
|
|||||||
#endif
|
#endif
|
||||||
if (++s->training_count >= V29_TRAINING_SEG_4_LEN)
|
if (++s->training_count >= V29_TRAINING_SEG_4_LEN)
|
||||||
{
|
{
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
if (s->training_error < FP_CONSTELLATION_SCALE(48.0f)*FP_CONSTELLATION_SCALE(1.0f))
|
||||||
if (s->training_error < 48*FP_FACTOR*FP_FACTOR)
|
|
||||||
#else
|
|
||||||
if (s->training_error < 48.0f)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
/* We are up and running */
|
/* We are up and running */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
@ -815,11 +790,10 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
|
|||||||
/* Training has failed. Park this modem */
|
/* Training has failed. Park this modem */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %d)\n", s->training_error);
|
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %d)\n", s->training_error);
|
||||||
s->agc_scaling_save = 0;
|
|
||||||
#else
|
#else
|
||||||
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
|
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
|
||||||
s->agc_scaling_save = 0.0f;
|
|
||||||
#endif
|
#endif
|
||||||
|
s->agc_scaling_save = FP_SCALE(0.0f);
|
||||||
s->training_stage = TRAINING_STAGE_PARKED;
|
s->training_stage = TRAINING_STAGE_PARKED;
|
||||||
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
|
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
|
||||||
}
|
}
|
||||||
@ -888,8 +862,8 @@ static __inline__ int signal_detect(v29_rx_state_t *s, int16_t amp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#if defined(IAXMODEM_STUFF)
|
#if defined(IAXMODEM_STUFF)
|
||||||
/* Carrier has dropped, but the put_bit is
|
/* Carrier has dropped, but the put_bit is pending the
|
||||||
pending the signal_present delay. */
|
signal_present delay. */
|
||||||
s->carrier_drop_pending = TRUE;
|
s->carrier_drop_pending = TRUE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -949,27 +923,33 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
|
|||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
|
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
|
||||||
sample.re = (v*s->agc_scaling) >> 10;
|
sample.re = (v*s->agc_scaling) >> 10;
|
||||||
#else
|
|
||||||
v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
|
|
||||||
sample.re = v*s->agc_scaling;
|
|
||||||
#endif
|
|
||||||
/* Symbol timing synchronisation band edge filters */
|
/* Symbol timing synchronisation band edge filters */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
|
||||||
/* Low Nyquist band edge filter */
|
/* Low Nyquist band edge filter */
|
||||||
v = ((s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0) >> 10) + ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> 10) + sample.re;
|
v = ((s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0) >> FP_SYNC_SHIFT_FACTOR)
|
||||||
|
+ ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> FP_SYNC_SHIFT_FACTOR)
|
||||||
|
+ sample.re;
|
||||||
s->symbol_sync_low[1] = s->symbol_sync_low[0];
|
s->symbol_sync_low[1] = s->symbol_sync_low[0];
|
||||||
s->symbol_sync_low[0] = v;
|
s->symbol_sync_low[0] = v;
|
||||||
/* High Nyquist band edge filter */
|
/* High Nyquist band edge filter */
|
||||||
v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> 10) + ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> 10) + sample.re;
|
v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> FP_SYNC_SHIFT_FACTOR)
|
||||||
|
+ ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> FP_SYNC_SHIFT_FACTOR)
|
||||||
|
+ sample.re;
|
||||||
s->symbol_sync_high[1] = s->symbol_sync_high[0];
|
s->symbol_sync_high[1] = s->symbol_sync_high[0];
|
||||||
s->symbol_sync_high[0] = v;
|
s->symbol_sync_high[0] = v;
|
||||||
#else
|
#else
|
||||||
|
v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
|
||||||
|
sample.re = v*s->agc_scaling;
|
||||||
|
/* Symbol timing synchronisation band edge filters */
|
||||||
/* Low Nyquist band edge filter */
|
/* Low Nyquist band edge filter */
|
||||||
v = s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0 + s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1 + sample.re;
|
v = s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0
|
||||||
|
+ s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1
|
||||||
|
+ sample.re;
|
||||||
s->symbol_sync_low[1] = s->symbol_sync_low[0];
|
s->symbol_sync_low[1] = s->symbol_sync_low[0];
|
||||||
s->symbol_sync_low[0] = v;
|
s->symbol_sync_low[0] = v;
|
||||||
/* High Nyquist band edge filter */
|
/* High Nyquist band edge filter */
|
||||||
v = s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0 + s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1 + sample.re;
|
v = s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0
|
||||||
|
+ s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1
|
||||||
|
+ sample.re;
|
||||||
s->symbol_sync_high[1] = s->symbol_sync_high[0];
|
s->symbol_sync_high[1] = s->symbol_sync_high[0];
|
||||||
s->symbol_sync_high[0] = v;
|
s->symbol_sync_high[0] = v;
|
||||||
#endif
|
#endif
|
||||||
@ -978,18 +958,18 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
|
|||||||
if (s->eq_put_step <= 0)
|
if (s->eq_put_step <= 0)
|
||||||
{
|
{
|
||||||
/* Only AGC until we have locked down the setting. */
|
/* Only AGC until we have locked down the setting. */
|
||||||
|
if (s->agc_scaling_save == FP_SCALE(0.0f))
|
||||||
|
{
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
if (s->agc_scaling_save == 0)
|
s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.25f)*1024.0f))/fixed_sqrt32(power));
|
||||||
s->agc_scaling = saturate16(((int32_t) (1024.0f*FP_FACTOR*1.25f))/fixed_sqrt32(power));
|
|
||||||
#else
|
#else
|
||||||
if (s->agc_scaling_save == 0.0f)
|
s->agc_scaling = (FP_SCALE(1.25f)/RX_PULSESHAPER_GAIN)/fixed_sqrt32(power);
|
||||||
s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*1.25f/sqrtf(power);
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
/* Pulse shape while still at the carrier frequency, using a quadrature
|
/* Pulse shape while still at the carrier frequency, using a quadrature
|
||||||
pair of filters. This results in a properly bandpass filtered complex
|
pair of filters. This results in a properly bandpass filtered complex
|
||||||
signal, which can be brought directly to baseband by complex mixing.
|
signal, which can be brought directly to baseband by complex mixing.
|
||||||
No further filtering, to remove mixer harmonics, is needed. */
|
No further filtering, to remove mixer harmonics, is needed. */
|
||||||
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
|
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_im[step], V29_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
|
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_im[step], V29_RX_FILTER_STEPS, s->rrc_filter_step) >> 15;
|
||||||
sample.im = (v*s->agc_scaling) >> 10;
|
sample.im = (v*s->agc_scaling) >> 10;
|
||||||
@ -1003,6 +983,7 @@ SPAN_DECLARE_NONSTD(int) v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
|
|||||||
zz.re = sample.re*z.re - sample.im*z.im;
|
zz.re = sample.re*z.re - sample.im*z.im;
|
||||||
zz.im = -sample.re*z.im - sample.im*z.re;
|
zz.im = -sample.re*z.im - sample.im*z.re;
|
||||||
#endif
|
#endif
|
||||||
|
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
|
||||||
process_half_baud(s, &zz);
|
process_half_baud(s, &zz);
|
||||||
}
|
}
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
@ -1118,12 +1099,11 @@ SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
|
|||||||
{
|
{
|
||||||
s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
|
s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
|
||||||
equalizer_reset(s);
|
equalizer_reset(s);
|
||||||
|
s->agc_scaling_save = FP_SCALE(0.0f);
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
s->agc_scaling_save = 0;
|
s->agc_scaling = (float) (FP_SCALE(1.25f)*1024.0f)/735.0f;
|
||||||
s->agc_scaling = (float) (1024.0f*FP_FACTOR)*1.25f/735.0f;
|
|
||||||
#else
|
#else
|
||||||
s->agc_scaling_save = 0.0f;
|
s->agc_scaling = (FP_SCALE(1.25f)/RX_PULSESHAPER_GAIN)/735.0f;
|
||||||
s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*1.25f/735.0f;
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
#if defined(SPANDSP_USE_FIXED_POINT)
|
||||||
@ -1137,23 +1117,13 @@ SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
|
|||||||
s->eq_skip = 0;
|
s->eq_skip = 0;
|
||||||
|
|
||||||
/* Initialise the working data for symbol timing synchronisation */
|
/* Initialise the working data for symbol timing synchronisation */
|
||||||
#if defined(SPANDSP_USE_FIXED_POINT)
|
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
s->symbol_sync_low[i] = 0;
|
s->symbol_sync_low[i] = FP_SCALE(0.0f);
|
||||||
s->symbol_sync_high[i] = 0;
|
s->symbol_sync_high[i] = FP_SCALE(0.0f);
|
||||||
s->symbol_sync_dc_filter[i] = 0;
|
s->symbol_sync_dc_filter[i] = FP_SCALE(0.0f);
|
||||||
}
|
}
|
||||||
s->baud_phase = 0;
|
s->baud_phase = FP_SCALE(0.0f);
|
||||||
#else
|
|
||||||
for (i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
s->symbol_sync_low[i] = 0.0f;
|
|
||||||
s->symbol_sync_high[i] = 0.0f;
|
|
||||||
s->symbol_sync_dc_filter[i] = 0.0f;
|
|
||||||
}
|
|
||||||
s->baud_phase = 0.0f;
|
|
||||||
#endif
|
|
||||||
s->baud_half = 0;
|
s->baud_half = 0;
|
||||||
|
|
||||||
s->total_baud_timing_correction = 0;
|
s->total_baud_timing_correction = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user