A little more modem polishing

This commit is contained in:
Steve Underwood 2013-03-21 22:16:51 +08:00
parent 8396519956
commit ac0defb874
3 changed files with 167 additions and 207 deletions

View File

@ -105,6 +105,8 @@ struct t4_rx_state_s
/*! \brief The width of the current page, in pixels. */
uint32_t image_width;
/*! \brief The length of the current page, in pixels. */
uint32_t image_length;
union
{

View File

@ -65,13 +65,15 @@
#include "spandsp/private/v27ter_rx.h"
#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_SHIFT_FACTOR 12
#else
#define FP_SCALE(x) (x)
#endif
#define FP_CONSTELLATION_SCALE(x) FP_SCALE(x)
#include "v27ter_rx_4800_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] =
#endif
{
{FP_SCALE( 1.414f), FP_SCALE( 0.0f)}, /* 0deg */
{FP_SCALE( 1.0f), FP_SCALE( 1.0f)}, /* 45deg */
{FP_SCALE( 0.0f), FP_SCALE( 1.414f)}, /* 90deg */
{FP_SCALE(-1.0f), FP_SCALE( 1.0f)}, /* 135deg */
{FP_SCALE(-1.414f), FP_SCALE( 0.0f)}, /* 180deg */
{FP_SCALE(-1.0f), FP_SCALE(-1.0f)}, /* 225deg */
{FP_SCALE( 0.0f), FP_SCALE(-1.414f)}, /* 270deg */
{FP_SCALE( 1.0f), FP_SCALE(-1.0f)} /* 315deg */
{FP_CONSTELLATION_SCALE( 1.414f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 0deg */
{FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 45deg */
{FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE( 1.414f)}, /* 90deg */
{FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE( 1.0f)}, /* 135deg */
{FP_CONSTELLATION_SCALE(-1.414f), FP_CONSTELLATION_SCALE( 0.0f)}, /* 180deg */
{FP_CONSTELLATION_SCALE(-1.0f), FP_CONSTELLATION_SCALE(-1.0f)}, /* 225deg */
{FP_CONSTELLATION_SCALE( 0.0f), FP_CONSTELLATION_SCALE(-1.414f)}, /* 270deg */
{FP_CONSTELLATION_SCALE( 1.0f), FP_CONSTELLATION_SCALE(-1.0f)} /* 315deg */
};
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. */
#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);
s->eq_coeff[V27TER_EQUALIZER_PRE_LEN + 1] = x;
cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN;
#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);
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)
abs_re = abs(z->re);
abs_im = abs(z->im);
if (abs_im*1000 > abs_re*414 && abs_im*1000 < abs_re*2414)
#else
abs_re = fabsf(z->re);
abs_im = fabsf(z->im);
if (abs_im > abs_re*0.4142136f && abs_im < abs_re*2.4142136f)
#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. */
#if defined(SPANDSP_USE_FIXED_POINT)
b1 = (z->re < 0);
b2 = (z->im < 0);
#else
b1 = (z->re < 0.0f);
b2 = (z->im < 0.0f);
#endif
b1 = (z->re < FP_SCALE(0.0f));
b2 = (z->im < FP_SCALE(0.0f));
bits = (b2 << 2) | ((b1 ^ b2) << 1) | 1;
}
else
@ -402,10 +398,7 @@ static __inline__ void put_bit(v27ter_rx_state_t *s, int bit)
{
int out_bit;
bit &= 1;
out_bit = descramble(s, bit);
/* We need to strip the last part of the training before we let data
go to the application. */
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 z16;
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
float p;
complexf_t z;
complexf_t zz;
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
int i;
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 2400bps the symbols are 2.0 (Euclidian) apart. */
#if defined(SPANDSP_USE_FIXED_POINT)
if ((s->bit_rate == 4800 && s->training_error < V27TER_TRAINING_SEG_6_LEN*FP_FACTOR*FP_FACTOR/4)
if ((s->bit_rate == 4800 && s->training_error < FP_CONSTELLATION_SCALE(V27TER_TRAINING_SEG_6_LEN)*FP_CONSTELLATION_SCALE(0.25f))
||
(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);
#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);
#endif
/* 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 */
#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
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
}
/* 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;
if (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)
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;
@ -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.im = -sample.re*z.im - sample.im*z.re;
#endif
s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2;
process_half_baud(s, &zz);
}
#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 */
#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
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
}
/* 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;
if (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)
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;
@ -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.im = -sample.re*z.im - sample.im*z.re;
#endif
s->eq_put_step += RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
process_half_baud(s, &zz);
}
#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)
vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
s->training_error = 0;
#else
vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
s->training_error = 0.0f;
#endif
s->training_error = FP_CONSTELLATION_SCALE(0.0f);
s->rrc_filter_step = 0;
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);
#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
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
equalizer_reset(s);
}

View File

@ -64,17 +64,25 @@
#include "spandsp/private/v29rx.h"
#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_SHIFT_FACTOR 12
#else
#define FP_SCALE(x) (x)
#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)
#include "v29rx_rrc.h"
#include "v29tx_constellation_maps.h"
/*! The nominal frequency of the carrier, in Hertz */
@ -92,6 +100,23 @@
/*! The length of training segment 4, in symbols */
#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
{
TRAINING_STAGE_NORMAL_OPERATION = 0,
@ -130,33 +155,6 @@ static const uint8_t space_map_9600[20][20] =
/* 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)
{
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 */
#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);
s->eq_coeff[V29_EQUALIZER_PRE_LEN] = x;
cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN;
#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);
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. */
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.im = zz.im >> FP_SHIFT_FACTOR;
z.re = zz.re >> FP_CONSTELLATION_SHIFT_FACTOR;
z.im = zz.im >> FP_CONSTELLATION_SHIFT_FACTOR;
return z;
}
#else
@ -300,36 +298,6 @@ static void tune_equalizer(v29_rx_state_t *s, const complexf_t *z, const complex
#endif
/*- 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)
static __inline__ void track_carrier(v29_rx_state_t *s, const complexi16_t *z, const complexi16_t *target)
#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,
as the angular error for the larger amplitude constellation points is probably
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
parameters are coarser at first, until we get precisely on target. Then,
the filter will be damped more to keep us on target. */
#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 += ((s->carrier_track_p*error) >> FP_SHIFT_FACTOR);
#else
error = z->im*target->re - z->re*target->im;
s->carrier_phase_rate += (int32_t) (s->carrier_track_i*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
}
/*- 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)
{
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 -
before we let data go to the application. */
out_bit = descramble(s, bit);
if (s->training_stage == TRAINING_STAGE_NORMAL_OPERATION)
{
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. */
#if defined(SPANDSP_USE_FIXED_POINT)
re = (z->re + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
im = (z->im + 5*FP_FACTOR) >> (FP_SHIFT_FACTOR - 1);
re = (z->re + FP_CONSTELLATION_SCALE(5.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1);
im = (z->im + FP_CONSTELLATION_SCALE(5.0f)) >> (FP_CONSTELLATION_SHIFT_FACTOR - 1);
#else
re = (int) ((z->re + 5.0f)*2.0f);
im = (int) ((z->im + 5.0f)*2.0f);
re = (int) ((z->re + FP_CONSTELLATION_SCALE(5.0f))*2.0f);
im = (int) ((z->im + FP_CONSTELLATION_SCALE(5.0f))*2.0f);
#endif
if (re > 19)
re = 19;
@ -499,9 +501,9 @@ static __inline__ void symbol_sync(v29_rx_state_t *s)
#if defined(SPANDSP_USE_FIXED_POINT)
/* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
/* Cross correlate */
v = (((s->symbol_sync_low[1] >> 5)*(s->symbol_sync_high[0] >> 4)) >> 15)*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[1] >> 5)*(s->symbol_sync_high[1] >> 4)) >> 15)*SYNC_MIXED_EDGES_COEFF_3;
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] >> (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] >> (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 */
p = v - s->symbol_sync_dc_filter[1];
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 */
s->baud_phase -= p;
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
/* Cross correlate */
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 */
s->baud_phase -= p;
v = fabsf(s->baud_phase);
if (v > 30.0f)
#endif
if (v > FP_SYNC_SCALE_32(30.0f))
{
i = (v > 1000.0f) ? 5 : 1;
if (s->baud_phase < 0.0f)
i = (v > FP_SYNC_SCALE_32(1000.0f)) ? 5 : 1;
if (s->baud_phase < FP_SYNC_SCALE_32(0.0f))
i = -i;
//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->total_baud_timing_correction += i;
}
#endif
}
/*- 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 z16;
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
float p;
complexf_t z;
complexf_t zz;
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
int bit;
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;
vec_zeroi32(s->diff_angles, 16);
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 (s->agc_scaling_save == 0)
s->agc_scaling_save = s->agc_scaling;
span_log(&s->logging, SPAN_LOG_FLOW, "Locking AGC at %d\n", s->agc_scaling);
#else
if (s->agc_scaling_save == 0.0f)
s->agc_scaling_save = s->agc_scaling;
span_log(&s->logging, SPAN_LOG_FLOW, "Locking AGC at %f\n", s->agc_scaling);
#endif
s->agc_scaling_save = s->agc_scaling;
}
}
break;
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");
/* Park this modem */
#if defined(SPANDSP_USE_FIXED_POINT)
s->agc_scaling_save = 0;
#else
s->agc_scaling_save = 0.0f;
#endif
s->agc_scaling_save = FP_SCALE(0.0f);
s->training_stage = TRAINING_STAGE_PARKED;
report_status_change(s, SIG_STATUS_TRAINING_FAILED);
break;
@ -695,11 +686,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
of a real training sequence. */
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (sequence failed)\n");
/* Park this modem */
#if defined(SPANDSP_USE_FIXED_POINT)
s->agc_scaling_save = 0;
#else
s->agc_scaling_save = 0.0f;
#endif
s->agc_scaling_save = FP_SCALE(0.0f);
s->training_stage = TRAINING_STAGE_PARKED;
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)
{
s->training_stage = TRAINING_STAGE_TRAIN_ON_CDCD_AND_TEST;
s->training_error = FP_CONSTELLATION_SCALE(0.0f);
#if defined(SPANDSP_USE_FIXED_POINT)
s->training_error = 0;
s->carrier_track_i = 200;
s->carrier_track_p = 1000000;
#else
s->training_error = 0.0f;
s->carrier_track_i = 200.0f;
s->carrier_track_p = 1000000.0f;
#endif
@ -746,15 +732,12 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
{
#if defined(SPANDSP_USE_FIXED_POINT)
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
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
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->constellation_state = 0;
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");
/* Park this modem */
#if defined(SPANDSP_USE_FIXED_POINT)
s->agc_scaling_save = 0;
#else
s->agc_scaling_save = 0.0f;
#endif
s->agc_scaling_save = FP_SCALE(0.0f);
s->training_stage = TRAINING_STAGE_PARKED;
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
if (++s->training_count >= V29_TRAINING_SEG_4_LEN)
{
#if defined(SPANDSP_USE_FIXED_POINT)
if (s->training_error < 48*FP_FACTOR*FP_FACTOR)
#else
if (s->training_error < 48.0f)
#endif
if (s->training_error < FP_CONSTELLATION_SCALE(48.0f)*FP_CONSTELLATION_SCALE(1.0f))
{
/* We are up and running */
#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 */
#if defined(SPANDSP_USE_FIXED_POINT)
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %d)\n", s->training_error);
s->agc_scaling_save = 0;
#else
span_log(&s->logging, SPAN_LOG_FLOW, "Training failed (constellation mismatch %f)\n", s->training_error);
s->agc_scaling_save = 0.0f;
#endif
s->agc_scaling_save = FP_SCALE(0.0f);
s->training_stage = TRAINING_STAGE_PARKED;
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;
}
#if defined(IAXMODEM_STUFF)
/* Carrier has dropped, but the put_bit is
pending the signal_present delay. */
/* Carrier has dropped, but the put_bit is pending the
signal_present delay. */
s->carrier_drop_pending = TRUE;
#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)
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;
#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 */
#if defined(SPANDSP_USE_FIXED_POINT)
/* 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[0] = v;
/* 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[0] = v;
#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 */
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[0] = v;
/* 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[0] = v;
#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)
{
/* 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 (s->agc_scaling_save == 0)
s->agc_scaling = saturate16(((int32_t) (1024.0f*FP_FACTOR*1.25f))/fixed_sqrt32(power));
s->agc_scaling = saturate16(((int32_t) (FP_SCALE(1.25f)*1024.0f))/fixed_sqrt32(power));
#else
if (s->agc_scaling_save == 0.0f)
s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*1.25f/sqrtf(power);
s->agc_scaling = (FP_SCALE(1.25f)/RX_PULSESHAPER_GAIN)/fixed_sqrt32(power);
#endif
}
/* Pulse shape while still at the carrier frequency, using a quadrature
pair of filters. This results in a properly bandpass filtered complex
signal, which can be brought directly to baseband by complex mixing.
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)
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;
@ -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.im = -sample.re*z.im - sample.im*z.re;
#endif
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
process_half_baud(s, &zz);
}
#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);
equalizer_reset(s);
s->agc_scaling_save = FP_SCALE(0.0f);
#if defined(SPANDSP_USE_FIXED_POINT)
s->agc_scaling_save = 0;
s->agc_scaling = (float) (1024.0f*FP_FACTOR)*1.25f/735.0f;
s->agc_scaling = (float) (FP_SCALE(1.25f)*1024.0f)/735.0f;
#else
s->agc_scaling_save = 0.0f;
s->agc_scaling = (1.0f/RX_PULSESHAPER_GAIN)*1.25f/735.0f;
s->agc_scaling = (FP_SCALE(1.25f)/RX_PULSESHAPER_GAIN)/735.0f;
#endif
}
#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;
/* Initialise the working data for symbol timing synchronisation */
#if defined(SPANDSP_USE_FIXED_POINT)
for (i = 0; i < 2; i++)
{
s->symbol_sync_low[i] = 0;
s->symbol_sync_high[i] = 0;
s->symbol_sync_dc_filter[i] = 0;
s->symbol_sync_low[i] = FP_SCALE(0.0f);
s->symbol_sync_high[i] = FP_SCALE(0.0f);
s->symbol_sync_dc_filter[i] = FP_SCALE(0.0f);
}
s->baud_phase = 0;
#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_phase = FP_SCALE(0.0f);
s->baud_half = 0;
s->total_baud_timing_correction = 0;