diff --git a/libs/spandsp/src/spandsp/dds.h b/libs/spandsp/src/spandsp/dds.h index 10bf99fdf7..c4b8b6bb13 100644 --- a/libs/spandsp/src/spandsp/dds.h +++ b/libs/spandsp/src/spandsp/dds.h @@ -28,6 +28,9 @@ #if !defined(_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) extern "C" { diff --git a/libs/spandsp/src/spandsp/private/v17rx.h b/libs/spandsp/src/spandsp/private/v17rx.h index a968290010..f25007e9ea 100644 --- a/libs/spandsp/src/spandsp/private/v17rx.h +++ b/libs/spandsp/src/spandsp/private/v17rx.h @@ -29,11 +29,10 @@ /* Target length for the equalizer is about 63 taps, to deal with the worst stuff in V.56bis. */ /*! The length of the equalizer buffer */ -//#define V17_EQUALIZER_LEN 33 -#define V17_EQUALIZER_LEN 17 +#define V17_EQUALIZER_LEN 33 + /*! Samples before the target position in the equalizer buffer */ -//#define V17_EQUALIZER_PRE_LEN 16 -#define V17_EQUALIZER_PRE_LEN 8 +#define V17_EQUALIZER_PRE_LEN 16 /*! The number of taps in the pulse shaping/bandpass filter */ #define V17_RX_FILTER_STEPS 27 @@ -72,7 +71,7 @@ struct v17_rx_state_s routine. */ 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. */ int16_t agc_scaling; /*! \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. */ int total_baud_timing_correction; - /*! \brief Starting phase angles for the coarse carrier aquisition step. */ - int32_t start_angles[2]; - /*! \brief History list of phase angles for the coarse carrier aquisition step. */ - int32_t angles[16]; + /*! \brief The previous symbol phase angles for the coarse carrier aquisition step. */ + int32_t last_angles[2]; + /*! \brief History list of phase angle differences for the coarse carrier aquisition step. */ + int32_t diff_angles[16]; /*! \brief A pointer to the current space map. There is a space map for each trellis state. */ @@ -219,7 +218,7 @@ struct v17_rx_state_s int full_path_to_past_state_locations[V17_TRELLIS_STORAGE_DEPTH][8]; /*! \brief The trellis. */ 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) from the last states of the trellis. */ uint32_t distances[8]; diff --git a/libs/spandsp/src/spandsp/private/v27ter_rx.h b/libs/spandsp/src/spandsp/private/v27ter_rx.h index 92bf937d83..e10781f72e 100644 --- a/libs/spandsp/src/spandsp/private/v27ter_rx.h +++ b/libs/spandsp/src/spandsp/private/v27ter_rx.h @@ -183,10 +183,11 @@ struct v27ter_rx_state_s This is only for performance analysis purposes. */ int total_baud_timing_correction; - /*! \brief Starting phase angles for the coarse carrier aquisition step. */ - int32_t start_angles[2]; - /*! \brief History list of phase angles for the coarse carrier aquisition step. */ - int32_t angles[16]; + /*! \brief The previous symbol phase angles for the coarse carrier aquisition step. */ + int32_t last_angles[2]; + /*! \brief History list of phase angle differences for the coarse carrier aquisition step. */ + int32_t diff_angles[16]; + /*! \brief Error and flow logging control */ logging_state_t logging; }; diff --git a/libs/spandsp/src/spandsp/private/v29rx.h b/libs/spandsp/src/spandsp/private/v29rx.h index 17e900582e..385c787dd6 100644 --- a/libs/spandsp/src/spandsp/private/v29rx.h +++ b/libs/spandsp/src/spandsp/private/v29rx.h @@ -184,10 +184,10 @@ struct v29_rx_state_s This is only for performance analysis purposes. */ int total_baud_timing_correction; - /*! \brief Starting phase angles for the coarse carrier aquisition step. */ - int32_t start_angles[2]; - /*! \brief History list of phase angles for the coarse carrier aquisition step. */ - int32_t angles[16]; + /*! \brief The previous symbol phase angles for the coarse carrier aquisition step. */ + int32_t last_angles[2]; + /*! \brief History list of phase angle differences for the coarse carrier aquisition step. */ + int32_t diff_angles[16]; /*! \brief The position of the current symbol in the constellation, used for differential decoding. */ diff --git a/libs/spandsp/src/v17rx.c b/libs/spandsp/src/v17rx.c index 9d692a1548..b275270b49 100644 --- a/libs/spandsp/src/v17rx.c +++ b/libs/spandsp/src/v17rx.c @@ -718,9 +718,9 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample) if (++s->training_count >= 100) { /* Record the current phase angle */ - s->angles[0] = - s->start_angles[0] = arctan2(z.im, z.re); 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 (s->agc_scaling_save == 0) 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 out is the phase. */ /* 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]; - s->angles[0] = 0xC0000000 + 219937506; - s->angles[1] = 0x80000000 + 219937506; + angle = s->last_angles[0]; + s->last_angles[0] = 0xC0000000 + 219937506; + s->last_angles[1] = 0x80000000 + 219937506; } else { - s->angles[0] = 0x80000000 + 219937506; - s->angles[1] = 0xC0000000 + 219937506; + s->last_angles[0] = 0x80000000 + 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 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 { - s->angles[1] = - s->start_angles[1] = angle; + s->last_angles[1] = angle; s->training_stage = TRAINING_STAGE_WAIT_FOR_CDBA; } 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); /* Look for the initial ABAB sequence to display a phase reversal, which will signal the start of the scrambled CDBA segment */ - ang = angle - s->angles[(s->training_count - 1) & 0xF]; - s->angles[(s->training_count + 1) & 0xF] = angle; - - /* Do a coarse frequency adjustment about half way through the reversals, as if we wait until - the end, we might have rotated too far to correct properly. */ - 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) + i = s->training_count + 1; + ang = angle - s->last_angles[i & 1]; + s->last_angles[i & 1] = angle; + s->diff_angles[i & 0xF] = s->diff_angles[(i - 2) & 0xF] + (ang >> 4); + if ((ang > DDS_PHASE(90.0f) || ang < DDS_PHASE(-90.0f)) && s->training_count >= 13) { 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 */ /* 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 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. */ i = (s->training_count - 8) & ~1; /* Avoid the possibility of a divide by zero */ - if (i - 100 + 8) + if (i > 1) { j = i & 0xF; - ang = (s->angles[j] - s->start_angles[0])/(i - 100 + 8) - + (s->angles[j | 0x1] - s->start_angles[1])/(i - 100 + 8); - 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); + ang = (s->diff_angles[j] + s->diff_angles[j | 0x1])/(i - 1); + s->carrier_phase_rate += 3*16*(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, "%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, "Second 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 */ - 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"); /* 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 signal the start of the scrambled CDBA segment */ angle = arctan2(z.im, z.re); - ang = angle - s->angles[s->training_count & 1]; - if (ang > 0x40000000 || ang < -0x40000000) + ang = angle - s->last_angles[s->training_count & 1]; + if (ang > DDS_PHASE(90.0f) || ang < DDS_PHASE(-90.0f)) { /* We seem to have a phase reversal */ /* 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 if (short_train != 2) s->short_train = short_train; - memset(s->start_angles, 0, sizeof(s->start_angles)); - memset(s->angles, 0, sizeof(s->angles)); + memset(s->last_angles, 0, sizeof(s->last_angles)); + memset(s->diff_angles, 0, sizeof(s->diff_angles)); /* Initialise the TCM decoder parameters. */ /* 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 { - s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ); + s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ); equalizer_reset(s); #if defined(SPANDSP_USE_FIXED_POINTx) 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->scrambler_tap = 18 - 1; 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); return s; } diff --git a/libs/spandsp/src/v22bis_rx.c b/libs/spandsp/src/v22bis_rx.c index 41e3076042..d124d7bcd8 100644 --- a/libs/spandsp/src/v22bis_rx.c +++ b/libs/spandsp/src/v22bis_rx.c @@ -956,7 +956,7 @@ int v22bis_rx_restart(v22bis_state_t *s) s->rx.training_count = 0; 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; power_meter_init(&s->rx.rx_power, 5); v22bis_rx_signal_cutoff(s, -45.5f); diff --git a/libs/spandsp/src/v27ter_rx.c b/libs/spandsp/src/v27ter_rx.c index b38481b87a..a4a9f5eeb9 100644 --- a/libs/spandsp/src/v27ter_rx.c +++ b/libs/spandsp/src/v27ter_rx.c @@ -566,15 +566,14 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t { s->gardner_step = 32; s->training_stage = TRAINING_STAGE_LOG_PHASE; - s->angles[0] = - s->start_angles[0] = arctan2(z.im, z.re); + vec_zeroi32(s->diff_angles, 16); + s->last_angles[0] = arctan2(z.im, z.re); } break; case TRAINING_STAGE_LOG_PHASE: /* Record the current alternate phase angle */ target = &zero; - s->angles[1] = - s->start_angles[1] = arctan2(z.im, z.re); + s->last_angles[1] = arctan2(z.im, z.re); s->training_count = 1; s->training_stage = TRAINING_STAGE_WAIT_FOR_HOP; 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); /* Look for the initial ABAB sequence to display a phase reversal, which will signal the start of the scrambled ABAB segment */ - ang = angle - s->angles[(s->training_count - 1) & 0xF]; - s->angles[(s->training_count + 1) & 0xF] = angle; - if ((ang > 0x20000000 || ang < -0x20000000) && s->training_count >= 3) + i = s->training_count + 1; + ang = angle - s->last_angles[i & 1]; + 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 */ /* 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. */ i = (s->training_count - 8) & ~1; /* Avoid the possibility of a divide by zero */ - if (i) + if (i > 1) { 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) - s->carrier_phase_rate += ang/10; + s->carrier_phase_rate += 16*(ang/10); 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); /* 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"); /* Park this modem */ @@ -1065,7 +1066,7 @@ SPAN_DECLARE(int) v27ter_rx_restart(v27ter_rx_state_t *s, int bit_rate, int old_ } 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) s->agc_scaling = (float) (1024.0f*FP_FACTOR)*1.414f/283.0f; #else diff --git a/libs/spandsp/src/v29rx.c b/libs/spandsp/src/v29rx.c index a8a1ed9c94..dec0c1f277 100644 --- a/libs/spandsp/src/v29rx.c +++ b/libs/spandsp/src/v29rx.c @@ -600,8 +600,8 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample) { /* Record the current phase angle */ s->training_stage = TRAINING_STAGE_LOG_PHASE; - s->angles[0] = - s->start_angles[0] = arctan2(z.im, z.re); + vec_zeroi32(s->diff_angles, 16); + s->last_angles[0] = arctan2(z.im, z.re); #if defined(SPANDSP_USE_FIXED_POINT) if (s->agc_scaling_save == 0) 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: /* Record the current alternate phase angle */ target = &zero; - s->angles[1] = - s->start_angles[1] = arctan2(z.im, z.re); + s->last_angles[1] = arctan2(z.im, z.re); s->training_count = 1; s->training_stage = TRAINING_STAGE_WAIT_FOR_CDCD; break; @@ -624,9 +623,11 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample) angle = arctan2(z.im, z.re); /* Look for the initial ABAB sequence to display a phase reversal, which will signal the start of the scrambled CDCD segment */ - ang = angle - s->angles[(s->training_count - 1) & 0xF]; - s->angles[(s->training_count + 1) & 0xF] = angle; - if ((ang > 0x20000000 || ang < -0x20000000) && s->training_count >= 13) + i = s->training_count + 1; + ang = angle - s->last_angles[i & 1]; + 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 */ /* 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. */ i = (s->training_count - 8) & ~1; /* Avoid the possibility of a divide by zero */ - if (i) + if (i > 1) { 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); + ang = (s->diff_angles[j] + s->diff_angles[j | 0x1])/(i - 1); + 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)); /* 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"); /* 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 { - s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ); + s->carrier_phase_rate = DDS_PHASE_RATE(CARRIER_NOMINAL_FREQ); equalizer_reset(s); #if defined(SPANDSP_USE_FIXED_POINT) s->agc_scaling_save = 0;