The FAX modem receive synchronisation algorithms have been changed to prevent

occasional false recognition of a fast modem when its really the V.21 modem.
This was sometimes messing up T.38 gateway operation.
This commit is contained in:
Steve Underwood 2012-10-11 20:16:45 +08:00
parent aa6bb702de
commit cfce1fd240
8 changed files with 78 additions and 97 deletions

View File

@ -28,6 +28,9 @@
#if !defined(_SPANDSP_DDS_H_) #if !defined(_SPANDSP_DDS_H_)
#define _SPANDSP_DDS_H_ #define _SPANDSP_DDS_H_
#define DDS_PHASE_RATE(frequency) (int32_t) ((frequency)*65536.0f*65536.0f/SAMPLE_RATE)
#define DDS_PHASE(angle) (int32_t) ((uint32_t) (((angle < 0.0f) ? (360.0f + angle) : angle)*65536.0f*65536.0f/360.0f))
#if defined(__cplusplus) #if defined(__cplusplus)
extern "C" extern "C"
{ {

View File

@ -29,11 +29,10 @@
/* Target length for the equalizer is about 63 taps, to deal with the worst stuff /* Target length for the equalizer is about 63 taps, to deal with the worst stuff
in V.56bis. */ in V.56bis. */
/*! The length of the equalizer buffer */ /*! The length of the equalizer buffer */
//#define V17_EQUALIZER_LEN 33 #define V17_EQUALIZER_LEN 33
#define V17_EQUALIZER_LEN 17
/*! Samples before the target position in the equalizer buffer */ /*! Samples before the target position in the equalizer buffer */
//#define V17_EQUALIZER_PRE_LEN 16 #define V17_EQUALIZER_PRE_LEN 16
#define V17_EQUALIZER_PRE_LEN 8
/*! The number of taps in the pulse shaping/bandpass filter */ /*! The number of taps in the pulse shaping/bandpass filter */
#define V17_RX_FILTER_STEPS 27 #define V17_RX_FILTER_STEPS 27
@ -72,7 +71,7 @@ struct v17_rx_state_s
routine. */ routine. */
void *qam_user_data; void *qam_user_data;
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINT)
/*! \brief The scaling factor assessed by the AGC algorithm. */ /*! \brief The scaling factor assessed by the AGC algorithm. */
int16_t agc_scaling; int16_t agc_scaling;
/*! \brief The previous value of agc_scaling, needed to reuse old training. */ /*! \brief The previous value of agc_scaling, needed to reuse old training. */
@ -202,10 +201,10 @@ struct v17_rx_state_s
This is only for performance analysis purposes. */ This is only for performance analysis purposes. */
int total_baud_timing_correction; int total_baud_timing_correction;
/*! \brief Starting phase angles for the coarse carrier aquisition step. */ /*! \brief The previous symbol phase angles for the coarse carrier aquisition step. */
int32_t start_angles[2]; int32_t last_angles[2];
/*! \brief History list of phase angles for the coarse carrier aquisition step. */ /*! \brief History list of phase angle differences for the coarse carrier aquisition step. */
int32_t angles[16]; int32_t diff_angles[16];
/*! \brief A pointer to the current space map. There is a space map for /*! \brief A pointer to the current space map. There is a space map for
each trellis state. */ each trellis state. */
@ -219,7 +218,7 @@ struct v17_rx_state_s
int full_path_to_past_state_locations[V17_TRELLIS_STORAGE_DEPTH][8]; int full_path_to_past_state_locations[V17_TRELLIS_STORAGE_DEPTH][8];
/*! \brief The trellis. */ /*! \brief The trellis. */
int past_state_locations[V17_TRELLIS_STORAGE_DEPTH][8]; int past_state_locations[V17_TRELLIS_STORAGE_DEPTH][8];
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINT)
/*! \brief Euclidean distances (actually the squares of the distances) /*! \brief Euclidean distances (actually the squares of the distances)
from the last states of the trellis. */ from the last states of the trellis. */
uint32_t distances[8]; uint32_t distances[8];

View File

@ -183,10 +183,11 @@ struct v27ter_rx_state_s
This is only for performance analysis purposes. */ This is only for performance analysis purposes. */
int total_baud_timing_correction; int total_baud_timing_correction;
/*! \brief Starting phase angles for the coarse carrier aquisition step. */ /*! \brief The previous symbol phase angles for the coarse carrier aquisition step. */
int32_t start_angles[2]; int32_t last_angles[2];
/*! \brief History list of phase angles for the coarse carrier aquisition step. */ /*! \brief History list of phase angle differences for the coarse carrier aquisition step. */
int32_t angles[16]; int32_t diff_angles[16];
/*! \brief Error and flow logging control */ /*! \brief Error and flow logging control */
logging_state_t logging; logging_state_t logging;
}; };

View File

@ -184,10 +184,10 @@ struct v29_rx_state_s
This is only for performance analysis purposes. */ This is only for performance analysis purposes. */
int total_baud_timing_correction; int total_baud_timing_correction;
/*! \brief Starting phase angles for the coarse carrier aquisition step. */ /*! \brief The previous symbol phase angles for the coarse carrier aquisition step. */
int32_t start_angles[2]; int32_t last_angles[2];
/*! \brief History list of phase angles for the coarse carrier aquisition step. */ /*! \brief History list of phase angle differences for the coarse carrier aquisition step. */
int32_t angles[16]; int32_t diff_angles[16];
/*! \brief The position of the current symbol in the constellation, used for /*! \brief The position of the current symbol in the constellation, used for
differential decoding. */ differential decoding. */

View File

@ -718,9 +718,9 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
if (++s->training_count >= 100) if (++s->training_count >= 100)
{ {
/* Record the current phase angle */ /* Record the current phase angle */
s->angles[0] =
s->start_angles[0] = arctan2(z.im, z.re);
s->training_stage = TRAINING_STAGE_LOG_PHASE; s->training_stage = TRAINING_STAGE_LOG_PHASE;
vec_zeroi32(s->diff_angles, 16);
s->last_angles[0] = arctan2(z.im, z.re);
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
if (s->agc_scaling_save == 0) if (s->agc_scaling_save == 0)
s->agc_scaling_save = s->agc_scaling; s->agc_scaling_save = s->agc_scaling;
@ -740,16 +740,16 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* We should already know the accurate carrier frequency. All we need to sort /* We should already know the accurate carrier frequency. All we need to sort
out is the phase. */ out is the phase. */
/* Check if we just saw A or B */ /* Check if we just saw A or B */
if ((uint32_t) (angle - s->start_angles[0]) < 0x80000000U) if ((uint32_t) (angle - s->last_angles[0]) < 0x80000000U)
{ {
angle = s->start_angles[0]; angle = s->last_angles[0];
s->angles[0] = 0xC0000000 + 219937506; s->last_angles[0] = 0xC0000000 + 219937506;
s->angles[1] = 0x80000000 + 219937506; s->last_angles[1] = 0x80000000 + 219937506;
} }
else else
{ {
s->angles[0] = 0x80000000 + 219937506; s->last_angles[0] = 0x80000000 + 219937506;
s->angles[1] = 0xC0000000 + 219937506; s->last_angles[1] = 0xC0000000 + 219937506;
} }
/* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer /* Make a step shift in the phase, to pull it into line. We need to rotate the equalizer
buffer, as well as the carrier phase, for this to play out nicely. */ buffer, as well as the carrier phase, for this to play out nicely. */
@ -775,8 +775,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
} }
else else
{ {
s->angles[1] = s->last_angles[1] = angle;
s->start_angles[1] = angle;
s->training_stage = TRAINING_STAGE_WAIT_FOR_CDBA; s->training_stage = TRAINING_STAGE_WAIT_FOR_CDBA;
} }
break; break;
@ -785,55 +784,32 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
angle = arctan2(z.im, z.re); angle = arctan2(z.im, z.re);
/* Look for the initial ABAB sequence to display a phase reversal, which will /* Look for the initial ABAB sequence to display a phase reversal, which will
signal the start of the scrambled CDBA segment */ signal the start of the scrambled CDBA segment */
ang = angle - s->angles[(s->training_count - 1) & 0xF]; i = s->training_count + 1;
s->angles[(s->training_count + 1) & 0xF] = angle; ang = angle - s->last_angles[i & 1];
s->last_angles[i & 1] = angle;
/* Do a coarse frequency adjustment about half way through the reversals, as if we wait until s->diff_angles[i & 0xF] = s->diff_angles[(i - 2) & 0xF] + (ang >> 4);
the end, we might have rotated too far to correct properly. */ if ((ang > DDS_PHASE(90.0f) || ang < DDS_PHASE(-90.0f)) && s->training_count >= 13)
if (s->training_count == 100)
{
i = s->training_count;
j = i & 0xF;
ang = (s->angles[j] - s->start_angles[0])/i
+ (s->angles[j | 0x1] - s->start_angles[1])/i;
s->carrier_phase_rate += 3*(ang/20);
//span_log(&s->logging, SPAN_LOG_FLOW, "Angles %x, %x, %x, %x, dist %d\n", s->angles[j], s->start_angles[0], s->angles[j | 0x1], s->start_angles[1], i);
s->start_angles[0] = s->angles[j];
s->start_angles[1] = s->angles[j | 0x1];
//span_log(&s->logging, SPAN_LOG_FLOW, "%d %d %d %d %d\n", s->angles[s->training_count & 0xF], s->start_angles[0], s->angles[(s->training_count | 0x1) & 0xF], s->start_angles[1], s->training_count);
span_log(&s->logging, SPAN_LOG_FLOW, "First coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
}
if ((ang > 0x40000000 || ang < -0x40000000) && s->training_count >= 13)
{ {
span_log(&s->logging, SPAN_LOG_FLOW, "We seem to have a reversal at symbol %d\n", s->training_count); span_log(&s->logging, SPAN_LOG_FLOW, "We seem to have a reversal at symbol %d\n", s->training_count);
/* We seem to have a phase reversal */ /* We seem to have a phase reversal */
/* Slam the carrier frequency into line, based on the total phase drift over the last /* Slam the carrier frequency into line, based on the total phase drift over the last
section. Use the shift from the odd bits and the shift from the even bits to get section. Use the shift from the odd bits and the shift from the even bits to get
better jitter suppression. */ better jitter suppression. */
/* TODO: We are supposed to deal with frequancy errors up to +-8Hz. Over 200+
symbols that is more than half a cycle. We get confused an do crazy things.
We can only cope with errors up to 5Hz right now. We need to implement
greater tolerance to be compliant, although it doesn't really matter much
these days. */
/* Step back a few symbols so we don't get ISI distorting things. */ /* Step back a few symbols so we don't get ISI distorting things. */
i = (s->training_count - 8) & ~1; i = (s->training_count - 8) & ~1;
/* Avoid the possibility of a divide by zero */ /* Avoid the possibility of a divide by zero */
if (i - 100 + 8) if (i > 1)
{ {
j = i & 0xF; j = i & 0xF;
ang = (s->angles[j] - s->start_angles[0])/(i - 100 + 8) ang = (s->diff_angles[j] + s->diff_angles[j | 0x1])/(i - 1);
+ (s->angles[j | 0x1] - s->start_angles[1])/(i - 100 + 8); s->carrier_phase_rate += 3*16*(ang/20);
s->carrier_phase_rate += 3*(ang/20); span_log(&s->logging, SPAN_LOG_FLOW, "Angles %x, %x, dist %d\n", s->last_angles[0], s->last_angles[1], i);
span_log(&s->logging, SPAN_LOG_FLOW, "Angles %x, %x, %x, %x, dist %d\n", s->angles[j], s->start_angles[0], s->angles[j | 0x1], s->start_angles[1], i);
} }
//span_log(&s->logging, SPAN_LOG_FLOW, "%d %d %d %d %d\n", s->angles[s->training_count & 0xF], s->start_angles[0], s->angles[(s->training_count | 0x1) & 0xF], s->start_angles[1], s->training_count); span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
span_log(&s->logging, SPAN_LOG_FLOW, "Second coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
/* Check if the carrier frequency is plausible */ /* Check if the carrier frequency is plausible */
if (s->carrier_phase_rate < dds_phase_ratef(CARRIER_NOMINAL_FREQ - 20.0f) if (s->carrier_phase_rate < DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ - 20.0f)
|| ||
s->carrier_phase_rate > dds_phase_ratef(CARRIER_NOMINAL_FREQ + 20.0f)) s->carrier_phase_rate > DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ + 20.0f))
{ {
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 */
@ -1025,8 +1001,8 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* Look for the initial ABAB sequence to display a phase reversal, which will /* Look for the initial ABAB sequence to display a phase reversal, which will
signal the start of the scrambled CDBA segment */ signal the start of the scrambled CDBA segment */
angle = arctan2(z.im, z.re); angle = arctan2(z.im, z.re);
ang = angle - s->angles[s->training_count & 1]; ang = angle - s->last_angles[s->training_count & 1];
if (ang > 0x40000000 || ang < -0x40000000) if (ang > DDS_PHASE(90.0f) || ang < DDS_PHASE(-90.0f))
{ {
/* We seem to have a phase reversal */ /* We seem to have a phase reversal */
/* We have just seen the first symbol of the scrambled sequence, so skip it. */ /* We have just seen the first symbol of the scrambled sequence, so skip it. */
@ -1507,8 +1483,8 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
#endif #endif
if (short_train != 2) if (short_train != 2)
s->short_train = short_train; s->short_train = short_train;
memset(s->start_angles, 0, sizeof(s->start_angles)); memset(s->last_angles, 0, sizeof(s->last_angles));
memset(s->angles, 0, sizeof(s->angles)); memset(s->diff_angles, 0, sizeof(s->diff_angles));
/* Initialise the TCM decoder parameters. */ /* Initialise the TCM decoder parameters. */
/* The accumulated distance vectors are set so state zero starts /* The accumulated distance vectors are set so state zero starts
@ -1544,7 +1520,7 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
} }
else else
{ {
s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ); s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
equalizer_reset(s); equalizer_reset(s);
#if defined(SPANDSP_USE_FIXED_POINTx) #if defined(SPANDSP_USE_FIXED_POINTx)
s->agc_scaling_save = 0; s->agc_scaling_save = 0;
@ -1618,7 +1594,7 @@ SPAN_DECLARE(v17_rx_state_t *) v17_rx_init(v17_rx_state_t *s, int bit_rate, put_
s->short_train = FALSE; s->short_train = FALSE;
s->scrambler_tap = 18 - 1; s->scrambler_tap = 18 - 1;
v17_rx_signal_cutoff(s, -45.5f); v17_rx_signal_cutoff(s, -45.5f);
s->carrier_phase_rate_save = dds_phase_ratef(CARRIER_NOMINAL_FREQ); s->carrier_phase_rate_save = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
v17_rx_restart(s, bit_rate, s->short_train); v17_rx_restart(s, bit_rate, s->short_train);
return s; return s;
} }

View File

@ -956,7 +956,7 @@ int v22bis_rx_restart(v22bis_state_t *s)
s->rx.training_count = 0; s->rx.training_count = 0;
s->rx.signal_present = FALSE; s->rx.signal_present = FALSE;
s->rx.carrier_phase_rate = dds_phase_ratef((s->calling_party) ? 2400.0f : 1200.0f); s->rx.carrier_phase_rate = (s->calling_party) ? DDS_PHASE_RATE(2400.0f) : DDS_PHASE_RATE(1200.0f);
s->rx.carrier_phase = 0; s->rx.carrier_phase = 0;
power_meter_init(&s->rx.rx_power, 5); power_meter_init(&s->rx.rx_power, 5);
v22bis_rx_signal_cutoff(s, -45.5f); v22bis_rx_signal_cutoff(s, -45.5f);

View File

@ -566,15 +566,14 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
{ {
s->gardner_step = 32; s->gardner_step = 32;
s->training_stage = TRAINING_STAGE_LOG_PHASE; s->training_stage = TRAINING_STAGE_LOG_PHASE;
s->angles[0] = vec_zeroi32(s->diff_angles, 16);
s->start_angles[0] = arctan2(z.im, z.re); s->last_angles[0] = arctan2(z.im, z.re);
} }
break; break;
case TRAINING_STAGE_LOG_PHASE: case TRAINING_STAGE_LOG_PHASE:
/* Record the current alternate phase angle */ /* Record the current alternate phase angle */
target = &zero; target = &zero;
s->angles[1] = s->last_angles[1] = arctan2(z.im, z.re);
s->start_angles[1] = arctan2(z.im, z.re);
s->training_count = 1; s->training_count = 1;
s->training_stage = TRAINING_STAGE_WAIT_FOR_HOP; s->training_stage = TRAINING_STAGE_WAIT_FOR_HOP;
break; break;
@ -583,9 +582,11 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
angle = arctan2(z.im, z.re); angle = arctan2(z.im, z.re);
/* Look for the initial ABAB sequence to display a phase reversal, which will /* Look for the initial ABAB sequence to display a phase reversal, which will
signal the start of the scrambled ABAB segment */ signal the start of the scrambled ABAB segment */
ang = angle - s->angles[(s->training_count - 1) & 0xF]; i = s->training_count + 1;
s->angles[(s->training_count + 1) & 0xF] = angle; ang = angle - s->last_angles[i & 1];
if ((ang > 0x20000000 || ang < -0x20000000) && s->training_count >= 3) s->last_angles[i & 1] = angle;
s->diff_angles[i & 0xF] = s->diff_angles[(i - 2) & 0xF] + (ang >> 4);
if ((ang > DDS_PHASE(45.0f) || ang < DDS_PHASE(-45.0f)) && s->training_count >= 13)
{ {
/* We seem to have a phase reversal */ /* We seem to have a phase reversal */
/* Slam the carrier frequency into line, based on the total phase drift over the last /* Slam the carrier frequency into line, based on the total phase drift over the last
@ -595,20 +596,20 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
/* Step back a few symbols so we don't get ISI distorting things. */ /* Step back a few symbols so we don't get ISI distorting things. */
i = (s->training_count - 8) & ~1; i = (s->training_count - 8) & ~1;
/* Avoid the possibility of a divide by zero */ /* Avoid the possibility of a divide by zero */
if (i) if (i > 1)
{ {
j = i & 0xF; j = i & 0xF;
ang = (s->angles[j] - s->start_angles[0])/i + (s->angles[j | 0x1] - s->start_angles[1])/i; ang = (s->diff_angles[j] + s->diff_angles[j | 0x1])/(i - 1);
if (s->bit_rate == 4800) if (s->bit_rate == 4800)
s->carrier_phase_rate += ang/10; s->carrier_phase_rate += 16*(ang/10);
else else
s->carrier_phase_rate += 3*(ang/40); s->carrier_phase_rate += 3*16*(ang/40);
} }
span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count); span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
/* Check if the carrier frequency is plausible */ /* Check if the carrier frequency is plausible */
if (s->carrier_phase_rate < dds_phase_ratef(CARRIER_NOMINAL_FREQ - 20.0f) if (s->carrier_phase_rate < DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ - 20.0f)
|| ||
s->carrier_phase_rate > dds_phase_ratef(CARRIER_NOMINAL_FREQ + 20.0f)) s->carrier_phase_rate > DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ + 20.0f))
{ {
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 */
@ -1065,7 +1066,7 @@ SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_
} }
else else
{ {
s->carrier_phase_rate = dds_phase_ratef(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) (1024.0f*FP_FACTOR)*1.414f/283.0f;
#else #else

View File

@ -600,8 +600,8 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
{ {
/* Record the current phase angle */ /* Record the current phase angle */
s->training_stage = TRAINING_STAGE_LOG_PHASE; s->training_stage = TRAINING_STAGE_LOG_PHASE;
s->angles[0] = vec_zeroi32(s->diff_angles, 16);
s->start_angles[0] = arctan2(z.im, z.re); s->last_angles[0] = arctan2(z.im, z.re);
#if defined(SPANDSP_USE_FIXED_POINT) #if defined(SPANDSP_USE_FIXED_POINT)
if (s->agc_scaling_save == 0) if (s->agc_scaling_save == 0)
s->agc_scaling_save = s->agc_scaling; s->agc_scaling_save = s->agc_scaling;
@ -614,8 +614,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
case TRAINING_STAGE_LOG_PHASE: case TRAINING_STAGE_LOG_PHASE:
/* Record the current alternate phase angle */ /* Record the current alternate phase angle */
target = &zero; target = &zero;
s->angles[1] = s->last_angles[1] = arctan2(z.im, z.re);
s->start_angles[1] = arctan2(z.im, z.re);
s->training_count = 1; s->training_count = 1;
s->training_stage = TRAINING_STAGE_WAIT_FOR_CDCD; s->training_stage = TRAINING_STAGE_WAIT_FOR_CDCD;
break; break;
@ -624,9 +623,11 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
angle = arctan2(z.im, z.re); angle = arctan2(z.im, z.re);
/* Look for the initial ABAB sequence to display a phase reversal, which will /* Look for the initial ABAB sequence to display a phase reversal, which will
signal the start of the scrambled CDCD segment */ signal the start of the scrambled CDCD segment */
ang = angle - s->angles[(s->training_count - 1) & 0xF]; i = s->training_count + 1;
s->angles[(s->training_count + 1) & 0xF] = angle; ang = angle - s->last_angles[i & 1];
if ((ang > 0x20000000 || ang < -0x20000000) && s->training_count >= 13) s->last_angles[i & 1] = angle;
s->diff_angles[i & 0xF] = s->diff_angles[(i - 2) & 0xF] + (ang >> 4);
if ((ang > DDS_PHASE(45.0f) || ang < DDS_PHASE(-45.0f)) && s->training_count >= 13)
{ {
/* We seem to have a phase reversal */ /* We seem to have a phase reversal */
/* Slam the carrier frequency into line, based on the total phase drift over the last /* Slam the carrier frequency into line, based on the total phase drift over the last
@ -636,17 +637,17 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
/* Step back a few symbols so we don't get ISI distorting things. */ /* Step back a few symbols so we don't get ISI distorting things. */
i = (s->training_count - 8) & ~1; i = (s->training_count - 8) & ~1;
/* Avoid the possibility of a divide by zero */ /* Avoid the possibility of a divide by zero */
if (i) if (i > 1)
{ {
j = i & 0xF; j = i & 0xF;
ang = (s->angles[j] - s->start_angles[0])/i + (s->angles[j | 0x1] - s->start_angles[1])/i; ang = (s->diff_angles[j] + s->diff_angles[j | 0x1])/(i - 1);
s->carrier_phase_rate += 3*(ang/20); s->carrier_phase_rate += 3*16*(ang/20);
} }
span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f\n", dds_frequencyf(s->carrier_phase_rate)); span_log(&s->logging, SPAN_LOG_FLOW, "Coarse carrier frequency %7.2f\n", dds_frequencyf(s->carrier_phase_rate));
/* Check if the carrier frequency is plausible */ /* Check if the carrier frequency is plausible */
if (s->carrier_phase_rate < dds_phase_ratef(CARRIER_NOMINAL_FREQ - 20.0f) if (s->carrier_phase_rate < DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ - 20.0f)
|| ||
s->carrier_phase_rate > dds_phase_ratef(CARRIER_NOMINAL_FREQ + 20.0f)) s->carrier_phase_rate > DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ + 20.0f))
{ {
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 */
@ -1111,7 +1112,7 @@ SPAN_DECLARE(int) v29_rx_restart(v29_rx_state_t *s, int bit_rate, int old_train)
} }
else else
{ {
s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ); s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ);
equalizer_reset(s); equalizer_reset(s);
#if defined(SPANDSP_USE_FIXED_POINT) #if defined(SPANDSP_USE_FIXED_POINT)
s->agc_scaling_save = 0; s->agc_scaling_save = 0;