update to snapshot spandsp-20080919.tar.gz

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@9770 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2008-10-01 03:59:45 +00:00
parent 7460c20ecd
commit 2825fb6e5b
40 changed files with 717 additions and 544 deletions

View File

@ -1 +1 @@
Tue Sep 30 23:55:26 EDT 2008
Tue Sep 30 23:59:24 EDT 2008

View File

@ -16,7 +16,7 @@
## License along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.101 2008/09/08 12:45:02 steveu Exp $
## $Id: Makefile.am,v 1.103 2008/09/19 14:02:05 steveu Exp $
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
@ -37,6 +37,7 @@ libspandsp_la_SOURCES = adsi.c \
bitstream.c \
complex_filters.c \
complex_vector_float.c \
complex_vector_int.c \
crc.c \
dds_float.c \
dds_int.c \
@ -45,8 +46,7 @@ libspandsp_la_SOURCES = adsi.c \
fax.c \
fsk.c \
g711.c \
g722_encode.c \
g722_decode.c \
g722.c \
g726.c \
gsm0610_decode.c \
gsm0610_encode.c \

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: awgn.c,v 1.16 2008/07/02 14:48:25 steveu Exp $
* $Id: awgn.c,v 1.17 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -57,7 +57,7 @@
#endif
#include "spandsp/telephony.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/awgn.h"
/* Gaussian noise generator constants */

View File

@ -1,7 +1,7 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* vector_float.c - Floating vector arithmetic routines.
* complex_vector_float.c - Floating complex vector arithmetic routines.
*
* Written by Steve Underwood <steveu@coppice.org>
*
@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: complex_vector_float.c,v 1.8 2008/07/02 14:48:25 steveu Exp $
* $Id: complex_vector_float.c,v 1.10 2008/09/18 13:16:49 steveu Exp $
*/
/*! \file */
@ -50,4 +50,84 @@
#include "spandsp/vector_float.h"
#include "spandsp/complex_vector_float.h"
complexf_t cvec_dot_prodf(const complexf_t x[], const complexf_t y[], int n)
{
int i;
complexf_t z;
z = complex_setf(0.0f, 0.0f);
for (i = 0; i < n; i++)
{
z.re += (x[i].re*y[i].re - x[i].im*y[i].im);
z.im += (x[i].re*y[i].im + x[i].im*y[i].re);
}
return z;
}
/*- End of function --------------------------------------------------------*/
complex_t cvec_dot_prod(const complex_t x[], const complex_t y[], int n)
{
int i;
complex_t z;
z = complex_set(0.0, 0.0);
for (i = 0; i < n; i++)
{
z.re += (x[i].re*y[i].re - x[i].im*y[i].im);
z.im += (x[i].re*y[i].im + x[i].im*y[i].re);
}
return z;
}
/*- End of function --------------------------------------------------------*/
#if defined(HAVE_LONG_DOUBLE)
complexl_t cvec_dot_prodl(const complexl_t x[], const complexl_t y[], int n)
{
int i;
complexl_t z;
z = complex_setl(0.0L, 0.0L);
for (i = 0; i < n; i++)
{
z.re += (x[i].re*y[i].re - x[i].im*y[i].im);
z.im += (x[i].re*y[i].im + x[i].im*y[i].re);
}
return z;
}
/*- End of function --------------------------------------------------------*/
#endif
complexf_t cvec_circular_dot_prodf(const complexf_t x[], const complexf_t y[], int n, int pos)
{
complexf_t z;
complexf_t z1;
z = cvec_dot_prodf(&x[pos], &y[0], n - pos);
z1 = cvec_dot_prodf(&x[0], &y[n - pos], pos);
z = complex_addf(&z, &z1);
return z;
}
/*- End of function --------------------------------------------------------*/
void cvec_lmsf(const complexf_t x[], complexf_t y[], int n, const complexf_t *error)
{
int i;
for (i = 0; i < n; i++)
{
y[i].re += (x[i].im*error->im + x[i].re*error->re);
y[i].im += (x[i].re*error->im - x[i].im*error->re);
/* Leak a little to tame uncontrolled wandering */
y[i].re *= 0.9999f;
y[i].im *= 0.9999f;
}
}
/*- End of function --------------------------------------------------------*/
void cvec_circular_lmsf(const complexf_t x[], complexf_t y[], int n, int pos, const complexf_t *error)
{
cvec_lmsf(&x[pos], &y[0], n - pos, error);
cvec_lmsf(&x[0], &y[n - pos], pos, error);
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -27,7 +27,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: echo.c,v 1.27 2008/08/29 09:28:13 steveu Exp $
* $Id: echo.c,v 1.28 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -96,6 +96,7 @@
#include "spandsp/telephony.h"
#include "spandsp/logging.h"
#include "spandsp/saturated.h"
#include "spandsp/dc_restore.h"
#include "spandsp/bit_operations.h"
#include "spandsp/echo.h"

View File

@ -25,7 +25,7 @@
* This code is based on the widely used GSM 06.10 code available from
* http://kbs.cs.tu-berlin.de/~jutta/toast.html
*
* $Id: gsm0610_decode.c,v 1.21 2008/07/02 14:48:25 steveu Exp $
* $Id: gsm0610_decode.c,v 1.22 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -48,7 +48,7 @@
#include "spandsp/telephony.h"
#include "spandsp/bitstream.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/gsm0610.h"
#include "gsm0610_local.h"
@ -66,9 +66,9 @@ static void postprocessing(gsm0610_state_t *s, int16_t amp[])
{
tmp = gsm_mult_r(msr, 28180);
/* De-emphasis */
msr = gsm_add(amp[k], tmp);
msr = saturated_add16(amp[k], tmp);
/* Truncation & upscaling */
amp[k] = (int16_t) (gsm_add(msr, msr) & 0xFFF8);
amp[k] = (int16_t) (saturated_add16(msr, msr) & 0xFFF8);
}
/*endfor*/
s->msr = msr;

View File

@ -25,7 +25,7 @@
* This code is based on the widely used GSM 06.10 code available from
* http://kbs.cs.tu-berlin.de/~jutta/toast.html
*
* $Id: gsm0610_encode.c,v 1.25 2008/07/02 14:48:25 steveu Exp $
* $Id: gsm0610_encode.c,v 1.26 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -48,7 +48,7 @@
#include "spandsp/telephony.h"
#include "spandsp/bitstream.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/gsm0610.h"
#include "gsm0610_local.h"
@ -93,7 +93,7 @@ static void encode_a_frame(gsm0610_state_t *s, gsm0610_frame_t *f, const int16_t
gsm0610_rpe_encoding(s, s->e + 5, &f->xmaxc[k], &f->Mc[k], f->xMc[k]);
for (i = 0; i < 40; i++)
dp[i] = gsm_add(s->e[5 + i], dpp[i]);
dp[i] = saturated_add16(s->e[5 + i], dpp[i]);
/*endfor*/
dp += 40;
dpp += 40;

View File

@ -25,7 +25,7 @@
* This code is based on the widely used GSM 06.10 code available from
* http://kbs.cs.tu-berlin.de/~jutta/toast.html
*
* $Id: gsm0610_long_term.c,v 1.16 2008/07/02 14:48:25 steveu Exp $
* $Id: gsm0610_long_term.c,v 1.17 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -47,7 +47,7 @@
#include "spandsp/telephony.h"
#include "spandsp/bitstream.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/gsm0610.h"
#include "gsm0610_local.h"
@ -185,7 +185,7 @@ static int16_t evaluate_ltp_parameters(int16_t d[40],
for (k = 0; k < 40; k++)
{
temp = d[k];
temp = gsm_abs(temp);
temp = saturated_abs16(temp);
if (temp > dmax)
dmax = temp;
/*endif*/
@ -314,7 +314,7 @@ static int16_t evaluate_ltp_parameters(int16_t d[40],
quantization of the LTP gain b to get the coded version bc. */
for (bc = 0; bc <= 2; bc++)
{
if (R <= gsm_mult(S, gsm_DLB[bc]))
if (R <= saturated_mul16(S, gsm_DLB[bc]))
break;
/*endif*/
}
@ -340,7 +340,7 @@ static void long_term_analysis_filtering(int16_t bc,
for (k = 0; k < 40; k++)
{
dpp[k] = gsm_mult_r(gsm_QLB[bc], dp[k - Nc]);
e[k] = gsm_sub(d[k], dpp[k]);
e[k] = saturated_sub16(d[k], dpp[k]);
}
/*endfor*/
}
@ -398,7 +398,7 @@ void gsm0610_long_term_synthesis_filtering(gsm0610_state_t *s,
for (k = 0; k < 40; k++)
{
drpp = gsm_mult_r(brp, drp[k - Nr]);
drp[k] = gsm_add(erp[k], drpp);
drp[k] = saturated_add16(erp[k], drpp);
}
/*endfor*/

View File

@ -25,7 +25,7 @@
* This code is based on the widely used GSM 06.10 code available from
* http://kbs.cs.tu-berlin.de/~jutta/toast.html
*
* $Id: gsm0610_lpc.c,v 1.21 2008/09/04 14:40:05 steveu Exp $
* $Id: gsm0610_lpc.c,v 1.22 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -49,7 +49,7 @@
#include "spandsp/telephony.h"
#include "spandsp/bitstream.h"
#include "spandsp/bit_operations.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/vector_int.h"
#include "spandsp/gsm0610.h"
@ -230,7 +230,7 @@ static void autocorrelation(int16_t amp[GSM0610_FRAME_LEN], int32_t L_ACF[9])
#else
for (smax = 0, k = 0; k < GSM0610_FRAME_LEN; k++)
{
temp = gsm_abs(amp[k]);
temp = saturated_abs16(amp[k]);
if (temp > smax)
smax = (int16_t) temp;
/*endif*/
@ -398,7 +398,7 @@ static void reflection_coefficients(int32_t L_ACF[9], int16_t r[8])
for (n = 1; n <= 8; n++, r++)
{
temp = P[1];
temp = gsm_abs (temp);
temp = saturated_abs16(temp);
if (P[0] < temp)
{
for (i = n; i <= 8; i++)
@ -421,15 +421,15 @@ static void reflection_coefficients(int32_t L_ACF[9], int16_t r[8])
/* Schur recursion */
temp = gsm_mult_r(P[1], *r);
P[0] = gsm_add(P[0], temp);
P[0] = saturated_add16(P[0], temp);
for (m = 1; m <= 8 - n; m++)
{
temp = gsm_mult_r(K[m], *r);
P[m] = gsm_add(P[m + 1], temp);
P[m] = saturated_add16(P[m + 1], temp);
temp = gsm_mult_r(P[m + 1], *r);
K[m] = gsm_add(K[m], temp);
K[m] = saturated_add16(K[m], temp);
}
/*endfor*/
}
@ -453,8 +453,7 @@ static void transform_to_log_area_ratios(int16_t r[8])
/* Computation of the LAR[0..7] from the r[0..7] */
for (i = 1; i <= 8; i++, r++)
{
temp = *r;
temp = gsm_abs(temp);
temp = saturated_abs16(*r);
assert(temp >= 0);
if (temp < 22118)
@ -496,9 +495,9 @@ static void quantization_and_coding(int16_t LAR[8])
#undef STEP
#define STEP(A,B,MAC,MIC) \
temp = gsm_mult(A, *LAR); \
temp = gsm_add(temp, B); \
temp = gsm_add(temp, 256); \
temp = saturated_mul16(A, *LAR); \
temp = saturated_add16(temp, B); \
temp = saturated_add16(temp, 256); \
temp >>= 9; \
*LAR = (int16_t) ((temp > MAC) \
? \

View File

@ -25,7 +25,7 @@
* This code is based on the widely used GSM 06.10 code available from
* http://kbs.cs.tu-berlin.de/~jutta/toast.html
*
* $Id: gsm0610_preprocess.c,v 1.13 2008/07/02 14:48:25 steveu Exp $
* $Id: gsm0610_preprocess.c,v 1.14 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -47,7 +47,7 @@
#include "spandsp/telephony.h"
#include "spandsp/bitstream.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/gsm0610.h"
#include "gsm0610_local.h"
@ -121,7 +121,7 @@ void gsm0610_preprocess(gsm0610_state_t *s, const int16_t amp[GSM0610_FRAME_LEN]
* L_temp = (++L_temp) >> 1;
* L_z2 = L_z2 - L_temp;
*/
L_z2 = gsm_l_add(L_z2, L_s2);
L_z2 = saturated_add32(L_z2, L_s2);
#else
/* This does L_z2 = L_z2 * 0x7FD5/0x8000 + L_s2 */
msp = (int16_t) (L_z2 >> 15);
@ -129,16 +129,16 @@ void gsm0610_preprocess(gsm0610_state_t *s, const int16_t amp[GSM0610_FRAME_LEN]
L_s2 += gsm_mult_r(lsp, 32735);
L_temp = (int32_t) msp*32735;
L_z2 = gsm_l_add(L_temp, L_s2);
L_z2 = saturated_add32(L_temp, L_s2);
#endif
/* Compute sof[k] with rounding */
L_temp = gsm_l_add(L_z2, 16384);
L_temp = saturated_add32(L_z2, 16384);
/* 4.2.3 Preemphasis */
msp = gsm_mult_r(mp, -28180);
mp = (int16_t) (L_temp >> 15);
so[k] = gsm_add(mp, msp);
so[k] = saturated_add16(mp, msp);
}
/*endfor*/

View File

@ -25,7 +25,7 @@
* This code is based on the widely used GSM 06.10 code available from
* http://kbs.cs.tu-berlin.de/~jutta/toast.html
*
* $Id: gsm0610_rpe.c,v 1.21 2008/07/02 14:48:25 steveu Exp $
* $Id: gsm0610_rpe.c,v 1.22 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -47,7 +47,7 @@
#include "spandsp/telephony.h"
#include "spandsp/bitstream.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/gsm0610.h"
#include "gsm0610_local.h"
@ -139,8 +139,8 @@ static void weighting_filter(const int16_t *e, // signal [-5..0.39.44] IN
/* for (i = 0; i <= 10; i++)
* {
* L_temp = gsm_l_mult(wt[k + i], gsm_H[i]);
* L_result = gsm_l_add(L_result, L_temp);
* L_temp = saturated_mul_16_32(wt[k + i], gsm_H[i]);
* L_result = saturated_add32(L_result, L_temp);
* }
*/
@ -351,7 +351,7 @@ static void apcm_quantization(int16_t xM[13],
for (i = 0; i < 13; i++)
{
temp = xM[i];
temp = gsm_abs(temp);
temp = saturated_abs16(temp);
if (temp > xmax)
xmax = temp;
/*endif*/
@ -379,7 +379,7 @@ static void apcm_quantization(int16_t xM[13],
temp = (int16_t) (exp + 5);
assert(temp <= 11 && temp >= 0);
xmaxc = gsm_add((xmax >> temp), exp << 3);
xmaxc = saturated_add16((xmax >> temp), exp << 3);
/* Quantizing and coding of the xM[0..12] RPE sequence
to get the xMc[0..12] */
@ -406,7 +406,7 @@ static void apcm_quantization(int16_t xM[13],
assert(temp1 >= 0 && temp1 < 16);
temp = xM[i] << temp1;
temp = gsm_mult(temp, temp2);
temp = saturated_mul16(temp, temp2);
temp >>= 12;
xMc[i] = (int16_t) (temp + 4); /* See note below */
}
@ -445,8 +445,8 @@ static void apcm_inverse_quantization(int16_t xMc[13],
#endif
temp1 = gsm_FAC[mant]; /* See 4.2-15 for mant */
temp2 = gsm_sub(6, exp); /* See 4.2-15 for exp */
temp3 = gsm_asl(1, gsm_sub (temp2, 1));
temp2 = saturated_sub16(6, exp); /* See 4.2-15 for exp */
temp3 = gsm_asl(1, saturated_sub16(temp2, 1));
for (i = 0; i < 13; i++)
{
@ -457,7 +457,7 @@ static void apcm_inverse_quantization(int16_t xMc[13],
temp <<= 12; /* 16 bit signed */
temp = gsm_mult_r(temp1, temp);
temp = gsm_add(temp, temp3);
temp = saturated_add16(temp, temp3);
xMp[i] = gsm_asr(temp, temp2);
}
/*endfor*/

View File

@ -25,7 +25,7 @@
* This code is based on the widely used GSM 06.10 code available from
* http://kbs.cs.tu-berlin.de/~jutta/toast.html
*
* $Id: gsm0610_short_term.c,v 1.15 2008/07/02 14:48:25 steveu Exp $
* $Id: gsm0610_short_term.c,v 1.16 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -47,7 +47,7 @@
#include "spandsp/telephony.h"
#include "spandsp/bitstream.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/gsm0610.h"
#include "gsm0610_local.h"
@ -69,10 +69,10 @@ static void decode_log_area_ratios(int16_t LARc[8], int16_t *LARpp)
#undef STEP
#define STEP(B,MIC,INVA) \
temp1 = gsm_add(*LARc++, MIC) << 10; \
temp1 = gsm_sub(temp1, B << 1); \
temp1 = gsm_mult_r (INVA, temp1); \
*LARpp++ = gsm_add(temp1, temp1);
temp1 = saturated_add16(*LARc++, MIC) << 10; \
temp1 = saturated_sub16(temp1, B << 1); \
temp1 = gsm_mult_r(INVA, temp1); \
*LARpp++ = saturated_add16(temp1, temp1);
STEP( 0, -32, 13107);
STEP( 0, -32, 13107);
@ -110,8 +110,8 @@ static void coefficients_0_12(int16_t *LARpp_j_1,
for (i = 1; i <= 8; i++, LARp++, LARpp_j_1++, LARpp_j++)
{
*LARp = gsm_add(*LARpp_j_1 >> 2, *LARpp_j >> 2);
*LARp = gsm_add(*LARp, *LARpp_j_1 >> 1);
*LARp = saturated_add16(*LARpp_j_1 >> 2, *LARpp_j >> 2);
*LARp = saturated_add16(*LARp, *LARpp_j_1 >> 1);
}
/*endfor*/
}
@ -124,7 +124,7 @@ static void coefficients_13_26(int16_t *LARpp_j_1,
int i;
for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++)
*LARp = gsm_add(*LARpp_j_1 >> 1, *LARpp_j >> 1);
*LARp = saturated_add16(*LARpp_j_1 >> 1, *LARpp_j >> 1);
/*endfor*/
}
/*- End of function --------------------------------------------------------*/
@ -137,8 +137,8 @@ static void coefficients_27_39(int16_t *LARpp_j_1,
for (i = 1; i <= 8; i++, LARpp_j_1++, LARpp_j++, LARp++)
{
*LARp = gsm_add(*LARpp_j_1 >> 2, *LARpp_j >> 2);
*LARp = gsm_add(*LARp, *LARpp_j >> 1);
*LARp = saturated_add16(*LARpp_j_1 >> 2, *LARpp_j >> 2);
*LARp = saturated_add16(*LARp, *LARpp_j >> 1);
}
/*endfor*/
}
@ -182,7 +182,7 @@ static void larp_to_rp(int16_t LARp[8])
else if (temp < 20070)
temp += 11059;
else
temp = gsm_add(temp >> 2, 26112);
temp = saturated_add16(temp >> 2, 26112);
/*endif*/
*LARpx = -temp;
}
@ -193,7 +193,7 @@ static void larp_to_rp(int16_t LARp[8])
else if (temp < 20070)
temp += 11059;
else
temp = gsm_add(temp >> 2, 26112);
temp = saturated_add16(temp >> 2, 26112);
/*endif*/
*LARpx = temp;
}
@ -279,7 +279,7 @@ static void short_term_synthesis_filtering(gsm0610_state_t *s,
:
(int16_t) (((int32_t) tmp1*(int32_t) tmp2 + 16384) >> 15) & 0xFFFF);
sri = gsm_sub(sri, tmp2);
sri = saturated_sub16(sri, tmp2);
tmp1 = ((tmp1 == INT16_MIN && sri == INT16_MIN)
?
@ -287,7 +287,7 @@ static void short_term_synthesis_filtering(gsm0610_state_t *s,
:
(int16_t) (((int32_t) tmp1*(int32_t) sri + 16384) >> 15) & 0xFFFF);
v[i + 1] = gsm_add(v[i], tmp1);
v[i + 1] = saturated_add16(v[i], tmp1);
}
/*endfor*/
*sr++ =

View File

@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: ima_adpcm.c,v 1.28 2008/07/02 14:48:25 steveu Exp $
* $Id: ima_adpcm.c,v 1.29 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -44,7 +44,7 @@
#endif
#include "spandsp/telephony.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/ima_adpcm.h"
/*

View File

@ -133,6 +133,10 @@ SOURCE=.\complex_vector_float.c
# End Source File
# Begin Source File
SOURCE=.\complex_vector_int.c
# End Source File
# Begin Source File
SOURCE=.\crc.c
# End Source File
# Begin Source File
@ -165,11 +169,7 @@ SOURCE=.\g711.c
# End Source File
# Begin Source File
SOURCE=.\g722_encode.c
# End Source File
# Begin Source File
SOURCE=.\g722_decode.c
SOURCE=.\g722.c
# End Source File
# Begin Source File

View File

@ -23,7 +23,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: make_modem_filter.c,v 1.11 2008/07/02 14:48:25 steveu Exp $
* $Id: make_modem_filter.c,v 1.12 2008/09/18 14:59:30 steveu Exp $
*/
#if defined(HAVE_CONFIG_H)
@ -158,6 +158,7 @@ static void make_rx_filter(int coeff_sets,
{
int i;
int j;
int k;
int m;
int x;
int total_coeffs;
@ -166,7 +167,11 @@ static void make_rx_filter(int coeff_sets,
double gain;
double peak;
double coeffs[MAX_COEFF_SETS*MAX_COEFFS_PER_FILTER + 1];
#if 0
complex_t co[MAX_COEFFS_PER_FILTER];
#else
double cox[MAX_COEFFS_PER_FILTER];
#endif
total_coeffs = coeff_sets*coeffs_per_filter + 1;
alpha = baud_rate/(2.0*(double) (coeff_sets*SAMPLE_RATE));
@ -203,6 +208,7 @@ static void make_rx_filter(int coeff_sets,
modem code. */
printf("#define RX_PULSESHAPER%s_GAIN %ff\n", tag, gain);
printf("#define RX_PULSESHAPER%s_COEFF_SETS %d\n", tag, coeff_sets);
#if 0
printf("static const %s rx_pulseshaper%s[RX_PULSESHAPER%s_COEFF_SETS][%d] =\n",
(fixed_point) ? "complexi16_t" : "complexf_t",
tag,
@ -244,6 +250,55 @@ static void make_rx_filter(int coeff_sets,
printf(" }\n");
}
printf("};\n");
#else
for (k = 0; k < 2; k++)
{
printf("static const %s rx_pulseshaper%s_%s[RX_PULSESHAPER%s_COEFF_SETS][%d] =\n",
(fixed_point) ? "int16_t" : "float",
tag,
(k == 0) ? "re" : "im",
tag,
coeffs_per_filter);
printf("{\n");
for (j = 0; j < coeff_sets; j++)
{
/* Complex modulate the filter, to make it a complex pulse shaping bandpass filter
centred at the nominal carrier frequency. Use the same phase for all the coefficient
sets. This means the modem can step the carrier in whole samples, and not worry about
the fractional sample shift caused by selecting amongst the various coefficient sets. */
for (i = 0; i < coeffs_per_filter; i++)
{
m = i - (coeffs_per_filter >> 1);
x = i*coeff_sets + j;
if (k == 0)
cox[i] = coeffs[x]*cos(carrier*m);
else
cox[i] = coeffs[x]*sin(carrier*m);
}
printf(" {\n");
if (fixed_point)
printf(" %8d, /* Filter %d */\n", (int) cox[0], j);
else
printf(" %15.10ff, /* Filter %d */\n", cox[0], j);
for (i = 1; i < coeffs_per_filter - 1; i++)
{
if (fixed_point)
printf(" %8d,\n", (int) cox[i]);
else
printf(" %15.10ff,\n", cox[i]);
}
if (fixed_point)
printf(" %8d\n", (int) cox[i]);
else
printf(" %15.10ff\n", cox[i]);
if (j < coeff_sets - 1)
printf(" },\n");
else
printf(" }\n");
}
printf("};\n");
}
#endif
}
/*- End of function --------------------------------------------------------*/

View File

@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: noise.c,v 1.24 2008/08/17 14:18:11 steveu Exp $
* $Id: noise.c,v 1.25 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -45,7 +45,7 @@
#endif
#include "spandsp/telephony.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/noise.h"
int16_t noise(noise_state_t *s)

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: plc.c,v 1.22 2008/07/02 14:48:25 steveu Exp $
* $Id: plc.c,v 1.23 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -45,7 +45,7 @@
#include <limits.h>
#include "spandsp/telephony.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/plc.h"
/* We do a straight line fade to zero volume in 50ms when we are filling in for missing data. */

View File

@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: sig_tone.c,v 1.24 2008/08/17 16:25:52 steveu Exp $
* $Id: sig_tone.c,v 1.25 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -48,6 +48,7 @@
#undef SPANDSP_USE_FIXED_POINT
#include "spandsp/telephony.h"
#include "spandsp/dc_restore.h"
#include "spandsp/saturated.h"
#include "spandsp/complex.h"
#include "spandsp/dds.h"
#include "spandsp/sig_tone.h"

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: spandsp.h.in,v 1.10 2008/09/01 16:07:34 steveu Exp $
* $Id: spandsp.h.in,v 1.11 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -69,6 +69,7 @@
#include <spandsp/hdlc.h>
#include <spandsp/async.h>
#include <spandsp/noise.h>
#include <spandsp/saturated.h>
#include <spandsp/time_scale.h>
#include <spandsp/tone_detect.h>
#include <spandsp/tone_generate.h>

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: complex_vector_float.h,v 1.8 2008/04/17 14:27:00 steveu Exp $
* $Id: complex_vector_float.h,v 1.10 2008/09/18 13:16:49 steveu Exp $
*/
#if !defined(_SPANDSP_COMPLEX_VECTOR_FLOAT_H_)
@ -120,6 +120,42 @@ static __inline__ void cvec_setl(complexl_t z[], complexl_t *x, int n)
/*- End of function --------------------------------------------------------*/
#endif
/*! \brief Find the dot product of two complex float vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
complexf_t cvec_dot_prodf(const complexf_t x[], const complexf_t y[], int n);
/*! \brief Find the dot product of two complex double vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
complex_t cvec_dot_prod(const complex_t x[], const complex_t y[], int n);
#if defined(HAVE_LONG_DOUBLE)
/*! \brief Find the dot product of two complex long double vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
complexl_t cvec_dot_prodl(const complexl_t x[], const complexl_t y[], int n);
#endif
/*! \brief Find the dot product of two complex float vectors, where the first is a circular buffer
with an offset for the starting position.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\param pos The starting position in the x vector.
\return The dot product of the two vectors. */
complexf_t cvec_circular_dot_prodf(const complexf_t x[], const complexf_t y[], int n, int pos);
void cvec_lmsf(const complexf_t x[], complexf_t y[], int n, const complexf_t *error);
void cvec_circular_lmsf(const complexf_t x[], complexf_t y[], int n, int pos, const complexf_t *error);
#if defined(__cplusplus)
}
#endif

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: complex_vector_int.h,v 1.1 2008/09/01 16:07:34 steveu Exp $
* $Id: complex_vector_int.h,v 1.3 2008/09/18 13:16:49 steveu Exp $
*/
#if !defined(_SPANDSP_COMPLEX_VECTOR_INT_H_)
@ -96,6 +96,33 @@ static __inline__ void cvec_seti32(complexi32_t z[], complexi32_t *x, int n)
}
/*- End of function --------------------------------------------------------*/
/*! \brief Find the dot product of two complex int16_t vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
complexi32_t cvec_dot_prodi16(const complexi16_t x[], const complexi16_t y[], int n);
/*! \brief Find the dot product of two complex int32_t vectors.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\return The dot product of the two vectors. */
complexi32_t cvec_dot_prodi32(const complexi32_t x[], const complexi32_t y[], int n);
/*! \brief Find the dot product of two complex int16_t vectors, where the first is a circular buffer
with an offset for the starting position.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\param pos The starting position in the x vector.
\return The dot product of the two vectors. */
complexi32_t cvec_circular_dot_prodi16(const complexi16_t x[], const complexi16_t y[], int n, int pos);
void cvec_lmsi16(const complexi16_t x[], complexi16_t y[], int n, const complexi16_t *error);
void cvec_circular_lmsi16(const complexi16_t x[], complexi16_t y[], int n, int pos, const complexi16_t *error);
#if defined(__cplusplus)
}
#endif

View File

@ -23,7 +23,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: dc_restore.h,v 1.23 2008/08/16 14:59:50 steveu Exp $
* $Id: dc_restore.h,v 1.24 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -85,60 +85,6 @@ static __inline__ int16_t dc_restore_estimate(dc_restore_state_t *dc)
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t saturate(int32_t amp)
{
int16_t amp16;
/* Hopefully this is optimised for the common case - not clipping */
amp16 = (int16_t) amp;
if (amp == amp16)
return amp16;
if (amp > INT16_MAX)
return INT16_MAX;
return INT16_MIN;
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t fsaturatef(float famp)
{
if (famp > 32767.0f)
return INT16_MAX;
if (famp < -32768.0f)
return INT16_MIN;
return (int16_t) rintf(famp);
}
/*- End of function --------------------------------------------------------*/
static __inline__ int16_t fsaturate(double damp)
{
if (damp > 32767.0)
return INT16_MAX;
if (damp < -32768.0)
return INT16_MIN;
return (int16_t) rint(damp);
}
/*- End of function --------------------------------------------------------*/
static __inline__ float ffsaturatef(float famp)
{
if (famp > 32767.0f)
return (float) INT16_MAX;
if (famp < -32768.0f)
return (float) INT16_MIN;
return famp;
}
/*- End of function --------------------------------------------------------*/
static __inline__ double ffsaturate(double famp)
{
if (famp > 32767.0)
return (double) INT16_MAX;
if (famp < -32768.0)
return (double) INT16_MIN;
return famp;
}
/*- End of function --------------------------------------------------------*/
#if defined(__cplusplus)
}
#endif

View File

@ -28,7 +28,7 @@
* Computer Science, Speech Group
* Chengxiang Lu and Alex Hauptmann
*
* $Id: g722.h,v 1.19 2008/04/17 14:27:00 steveu Exp $
* $Id: g722.h,v 1.20 2008/09/19 14:02:05 steveu Exp $
*/
@ -56,6 +56,20 @@ enum
G722_PACKED = 0x0002
};
/*! The per band parameters for both encoding and decoding G.722 */
typedef struct
{
int16_t s;
int16_t sz;
int16_t r[3];
int16_t a[3];
int16_t p[3];
int16_t d[7];
int16_t b[7];
int16_t nb;
int16_t det;
} g722_band_t;
typedef struct
{
/*! TRUE if the operating in the special ITU test mode, with the band split filters
@ -69,28 +83,15 @@ typedef struct
int bits_per_sample;
/*! Signal history for the QMF */
int x[24];
int16_t x[12];
int16_t y[12];
int ptr;
struct
{
int s;
int sp;
int sz;
int r[3];
int a[3];
int ap[3];
int p[3];
int d[7];
int b[7];
int bp[7];
int sg[7];
int nb;
int det;
} band[2];
g722_band_t band[2];
unsigned int in_buffer;
uint32_t in_buffer;
int in_bits;
unsigned int out_buffer;
uint32_t out_buffer;
int out_bits;
} g722_encode_state_t;
@ -107,28 +108,15 @@ typedef struct
int bits_per_sample;
/*! Signal history for the QMF */
int x[24];
int16_t x[12];
int16_t y[12];
int ptr;
struct
{
int s;
int sp;
int sz;
int r[3];
int a[3];
int ap[3];
int p[3];
int d[7];
int b[7];
int bp[7];
int sg[7];
int nb;
int det;
} band[2];
g722_band_t band[2];
unsigned int in_buffer;
uint32_t in_buffer;
int in_bits;
unsigned int out_buffer;
uint32_t out_buffer;
int out_bits;
} g722_decode_state_t;

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v17rx.h,v 1.54 2008/09/16 13:02:05 steveu Exp $
* $Id: v17rx.h,v 1.57 2008/09/18 14:59:30 steveu Exp $
*/
/*! \file */
@ -213,9 +213,8 @@ TCM absolutely transformed the phone line modem business.
/* Target length for the equalizer is about 63 taps, to deal with the worst stuff
in V.56bis. */
#define V17_EQUALIZER_PRE_LEN 7 /* this much before the real event */
#define V17_EQUALIZER_POST_LEN 7 /* this much after the real event */
#define V17_EQUALIZER_MASK 63 /* one less than a power of 2 >= (V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN) */
#define V17_EQUALIZER_PRE_LEN 8 /* This much before the real event */
#define V17_EQUALIZER_POST_LEN 8 /* This much after the real event (must be even) */
#define V17_RX_FILTER_STEPS 27
@ -253,9 +252,9 @@ typedef struct
/*! \brief The route raised cosine (RRC) pulse shaping filter buffer. */
#if defined(SPANDSP_USE_FIXED_POINT)
int16_t rrc_filter[2*V17_RX_FILTER_STEPS];
int16_t rrc_filter[V17_RX_FILTER_STEPS];
#else
float rrc_filter[2*V17_RX_FILTER_STEPS];
float rrc_filter[V17_RX_FILTER_STEPS];
#endif
/*! \brief Current offset into the RRC pulse shaping filter buffer. */
int rrc_filter_step;
@ -332,7 +331,7 @@ typedef struct
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexi16_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexi16_t eq_buf[V17_EQUALIZER_MASK + 1];
complexi16_t eq_buf[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! Low band edge filter for symbol sync. */
int32_t symbol_sync_low[2];
@ -355,7 +354,7 @@ typedef struct
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexf_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexf_t eq_buf[V17_EQUALIZER_MASK + 1];
complexf_t eq_buf[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
/*! Low band edge filter for symbol sync. */
float symbol_sync_low[2];

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v27ter_rx.h,v 1.51 2008/09/16 14:12:23 steveu Exp $
* $Id: v27ter_rx.h,v 1.53 2008/09/18 14:59:30 steveu Exp $
*/
/*! \file */
@ -48,9 +48,8 @@ straightforward.
/* Target length for the equalizer is about 43 taps for 4800bps and 32 taps for 2400bps
to deal with the worst stuff in V.56bis. */
#define V27TER_EQUALIZER_PRE_LEN 15 /* this much before the real event */
#define V27TER_EQUALIZER_POST_LEN 15 /* this much after the real event */
#define V27TER_EQUALIZER_MASK 63 /* one less than a power of 2 >= (V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN) */
#define V27TER_EQUALIZER_PRE_LEN 16 /* This much before the real event */
#define V27TER_EQUALIZER_POST_LEN 14 /* This much after the real event (must be even) */
#define V27TER_RX_4800_FILTER_STEPS 27
#define V27TER_RX_2400_FILTER_STEPS 27
@ -88,9 +87,9 @@ typedef struct
/*! \brief The route raised cosine (RRC) pulse shaping filter buffer. */
#if defined(SPANDSP_USE_FIXED_POINT)
int16_t rrc_filter[2*V27TER_RX_FILTER_STEPS];
int16_t rrc_filter[V27TER_RX_FILTER_STEPS];
#else
float rrc_filter[2*V27TER_RX_FILTER_STEPS];
float rrc_filter[V27TER_RX_FILTER_STEPS];
#endif
/*! \brief Current offset into the RRC pulse shaping filter buffer. */
int rrc_filter_step;
@ -174,7 +173,7 @@ typedef struct
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
/*complexi16_t*/ complexf_t eq_coeff_save[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
/*complexi16_t*/ complexf_t eq_buf[V27TER_EQUALIZER_MASK + 1];
/*complexi16_t*/ complexf_t eq_buf[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
#else
/*! \brief The scaling factor accessed by the AGC algorithm. */
float agc_scaling;
@ -188,7 +187,7 @@ typedef struct
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexf_t eq_coeff_save[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexf_t eq_buf[V27TER_EQUALIZER_MASK + 1];
complexf_t eq_buf[V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN];
#endif
/*! \brief Integration variable for damping the Gardner algorithm tests. */

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v29rx.h,v 1.62 2008/09/16 14:12:23 steveu Exp $
* $Id: v29rx.h,v 1.64 2008/09/18 14:59:30 steveu Exp $
*/
/*! \file */
@ -122,9 +122,8 @@ therefore, only tests that bits starting at bit 24 are really ones.
/* Target length for the equalizer is about 63 taps, to deal with the worst stuff
in V.56bis. */
#define V29_EQUALIZER_PRE_LEN 15 /* this much before the real event */
#define V29_EQUALIZER_POST_LEN 15 /* this much after the real event */
#define V29_EQUALIZER_MASK 63 /* one less than a power of 2 >= (2*V29_EQUALIZER_LEN + 1) */
#define V29_EQUALIZER_PRE_LEN 16 /* This much before the real event */
#define V29_EQUALIZER_POST_LEN 14 /* This much after the real event (must be even) */
#define V29_RX_FILTER_STEPS 27
@ -157,9 +156,9 @@ typedef struct
/*! \brief The route raised cosine (RRC) pulse shaping filter buffer. */
#if defined(SPANDSP_USE_FIXED_POINT)
int16_t rrc_filter[2*V29_RX_FILTER_STEPS];
int16_t rrc_filter[V29_RX_FILTER_STEPS];
#else
float rrc_filter[2*V29_RX_FILTER_STEPS];
float rrc_filter[V29_RX_FILTER_STEPS];
#endif
/*! \brief Current offset into the RRC pulse shaping filter buffer. */
int rrc_filter_step;
@ -242,7 +241,7 @@ typedef struct
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexi16_t eq_coeff_save[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexi16_t eq_buf[V29_EQUALIZER_MASK + 1];
complexi16_t eq_buf[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! Low band edge filter for symbol sync. */
int32_t symbol_sync_low[2];
@ -265,7 +264,7 @@ typedef struct
/*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
complexf_t eq_coeff_save[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! \brief The equalizer signal buffer. */
complexf_t eq_buf[V29_EQUALIZER_MASK + 1];
complexf_t eq_buf[V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN];
/*! Low band edge filter for symbol sync. */
float symbol_sync_low[2];

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: vector_float.h,v 1.11 2008/09/01 16:07:34 steveu Exp $
* $Id: vector_float.h,v 1.13 2008/09/18 13:54:32 steveu Exp $
*/
#if !defined(_SPANDSP_VECTOR_FLOAT_H_)
@ -128,6 +128,19 @@ double vec_dot_prod(const double x[], const double y[], int n);
long double vec_dot_prodl(const long double x[], const long double y[], int n);
#endif
/*! \brief Find the dot product of two float vectors, where the first is a circular buffer
with an offset for the starting position.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\param pos The starting position in the x vector.
\return The dot product of the two vectors. */
float vec_circular_dot_prodf(const float x[], const float y[], int n, int pos);
void vec_lmsf(const float x[], float y[], int n, float error);
void vec_circular_lmsf(const float x[], float y[], int n, int pos, float error);
#if defined(__cplusplus)
}
#endif

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: vector_int.h,v 1.11 2008/09/01 16:07:34 steveu Exp $
* $Id: vector_int.h,v 1.13 2008/09/18 13:54:32 steveu Exp $
*/
#if !defined(_SPANDSP_VECTOR_INT_H_)
@ -103,6 +103,19 @@ static __inline__ void vec_seti32(int32_t z[], int32_t x, int n)
\return The dot product of the two vectors. */
int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n);
/*! \brief Find the dot product of two int16_t vectors, where the first is a circular buffer
with an offset for the starting position.
\param x The first vector.
\param y The first vector.
\param n The number of elements in the vectors.
\param pos The starting position in the x vector.
\return The dot product of the two vectors. */
int32_t vec_circular_dot_prodi16(const int16_t x[], const int16_t y[], int n, int pos);
void vec_lmsi16(const int16_t x[], int16_t y[], int n, int16_t error);
void vec_circular_lmsi16(const int16_t x[], int16_t y[], int n, int pos, int16_t error);
/*! \brief Find the minimum and maximum values in an int16_t vector.
\param x The vector to be searched.
\param n The number of elements in the vector.

View File

@ -30,8 +30,8 @@
/* The date and time of the version are in UTC form. */
#define SPANDSP_RELEASE_DATE 20080916
#define SPANDSP_RELEASE_TIME 152844
#define SPANDSP_RELEASE_DATE 20080919
#define SPANDSP_RELEASE_TIME 142905
#endif
/*- End of file ------------------------------------------------------------*/

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: time_scale.c,v 1.23 2008/07/28 15:14:30 steveu Exp $
* $Id: time_scale.c,v 1.24 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -48,6 +48,7 @@
#include "spandsp/telephony.h"
#include "spandsp/time_scale.h"
#include "spandsp/saturated.h"
/*
Time scaling for speech, based on the Pointer Interval Controlled

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v17rx.c,v 1.118 2008/09/16 14:12:23 steveu Exp $
* $Id: v17rx.c,v 1.123 2008/09/18 15:59:55 steveu Exp $
*/
/*! \file */
@ -48,6 +48,8 @@
#include "spandsp/complex.h"
#include "spandsp/vector_float.h"
#include "spandsp/complex_vector_float.h"
#include "spandsp/vector_int.h"
#include "spandsp/complex_vector_int.h"
#include "spandsp/async.h"
#include "spandsp/power_meter.h"
#include "spandsp/arctan2.h"
@ -81,6 +83,8 @@
#define V17_BRIDGE_WORD 0x8880
#define V17_EQUALIZER_LEN (V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN)
enum
{
TRAINING_STAGE_NORMAL_OPERATION = 0,
@ -149,16 +153,16 @@ int v17_rx_equalizer_state(v17_rx_state_t *s, complexf_t **coeffs)
#endif
{
*coeffs = s->eq_coeff;
return V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN;
return V17_EQUALIZER_LEN;
}
/*- End of function --------------------------------------------------------*/
static void equalizer_save(v17_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINTx)
cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V17_EQUALIZER_LEN);
#else
cvec_copyf(s->eq_coeff_save, s->eq_coeff, V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_copyf(s->eq_coeff_save, s->eq_coeff, V17_EQUALIZER_LEN);
#endif
}
/*- End of function --------------------------------------------------------*/
@ -166,13 +170,13 @@ static void equalizer_save(v17_rx_state_t *s)
static void equalizer_restore(v17_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINTx)
cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_buf, V17_EQUALIZER_MASK);
s->eq_delta = 32768.0f*EQUALIZER_SLOW_ADAPT_RATIO*EQUALIZER_DELTA/(V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V17_EQUALIZER_LEN);
cvec_zeroi16(s->eq_buf, V17_EQUALIZER_LEN);
s->eq_delta = 32768.0f*EQUALIZER_SLOW_ADAPT_RATIO*EQUALIZER_DELTA/V17_EQUALIZER_LEN;
#else
cvec_copyf(s->eq_coeff, s->eq_coeff_save, V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_buf, V17_EQUALIZER_MASK);
s->eq_delta = EQUALIZER_SLOW_ADAPT_RATIO*EQUALIZER_DELTA/(V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_copyf(s->eq_coeff, s->eq_coeff_save, V17_EQUALIZER_LEN);
cvec_zerof(s->eq_buf, V17_EQUALIZER_LEN);
s->eq_delta = EQUALIZER_SLOW_ADAPT_RATIO*EQUALIZER_DELTA/V17_EQUALIZER_LEN;
#endif
s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
@ -184,15 +188,15 @@ static void equalizer_reset(v17_rx_state_t *s)
{
/* Start with an equalizer based on everything being perfect */
#if defined(SPANDSP_USE_FIXED_POINTx)
cvec_zeroi16(s->eq_coeff, V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_coeff, V17_EQUALIZER_LEN);
s->eq_coeff[V17_EQUALIZER_PRE_LEN] = complex_seti16(3*FP_FACTOR, 0);
cvec_zeroi16(s->eq_buf, V17_EQUALIZER_MASK);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/(V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_buf, V17_EQUALIZER_LEN);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V17_EQUALIZER_LEN;
#else
cvec_zerof(s->eq_coeff, V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_coeff, V17_EQUALIZER_LEN);
s->eq_coeff[V17_EQUALIZER_PRE_LEN] = complex_setf(3.0f, 0.0f);
cvec_zerof(s->eq_buf, V17_EQUALIZER_MASK);
s->eq_delta = EQUALIZER_DELTA/(V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_buf, V17_EQUALIZER_LEN);
s->eq_delta = EQUALIZER_DELTA/V17_EQUALIZER_LEN;
#endif
s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
@ -206,21 +210,7 @@ static __inline__ complexi16_t equalizer_get(v17_rx_state_t *s)
static __inline__ complexf_t equalizer_get(v17_rx_state_t *s)
#endif
{
int i;
int p;
complexf_t z;
complexf_t z1;
/* Get the next equalized value. */
z = complex_setf(0.0f, 0.0f);
p = s->eq_step - 1;
for (i = 0; i < V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V17_EQUALIZER_MASK;
z1 = complex_mulf(&s->eq_coeff[i], &s->eq_buf[p]);
z = complex_addf(&z, &z1);
}
return z;
return cvec_circular_dot_prodf(s->eq_buf, s->eq_coeff, V17_EQUALIZER_LEN, s->eq_step);
}
/*- End of function --------------------------------------------------------*/
@ -230,28 +220,18 @@ static void tune_equalizer(v17_rx_state_t *s, const complexi16_t *z, const compl
static void tune_equalizer(v17_rx_state_t *s, const complexf_t *z, const complexf_t *target)
#endif
{
int i;
int p;
complexf_t ez;
complexf_t z1;
complexf_t err;
/* Find the x and y mismatch from the exact constellation position. */
ez = complex_subf(target, z);
err = complex_subf(target, z);
//span_log(&s->logging, SPAN_LOG_FLOW, "Equalizer error %f\n", sqrt(ez.re*ez.re + ez.im*ez.im));
ez.re *= s->eq_delta;
ez.im *= s->eq_delta;
err.re *= s->eq_delta;
err.im *= s->eq_delta;
p = s->eq_step - 1;
for (i = 0; i < V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V17_EQUALIZER_MASK;
z1 = complex_conjf(&s->eq_buf[p]);
z1 = complex_mulf(&ez, &z1);
s->eq_coeff[i] = complex_addf(&s->eq_coeff[i], &z1);
/* Leak a little to tame uncontrolled wandering */
s->eq_coeff[i].re *= 0.9999f;
s->eq_coeff[i].im *= 0.9999f;
}
err = complex_subf(target, z);
err.re *= s->eq_delta;
err.im *= s->eq_delta;
cvec_circular_lmsf(s->eq_buf, s->eq_coeff, V17_EQUALIZER_LEN, s->eq_step, &err);
}
/*- End of function --------------------------------------------------------*/
@ -565,7 +545,8 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
/* Add a sample to the equalizer's circular buffer, but don't calculate anything
at this time. */
s->eq_buf[s->eq_step] = *sample;
s->eq_step = (s->eq_step + 1) & V17_EQUALIZER_MASK;
if (++s->eq_step >= V17_EQUALIZER_LEN)
s->eq_step = 0;
/* On alternate insertions we have a whole baud and must process it. */
if ((s->baud_half ^= 1))
@ -628,7 +609,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
p = 3.14159f + angle*2.0f*3.14159f/(65536.0f*65536.0f) - 0.321751f;
span_log(&s->logging, SPAN_LOG_FLOW, "Spin (short) by %.5f rads\n", p);
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V17_EQUALIZER_MASK; i++)
for (i = 0; i < V17_EQUALIZER_LEN; i++)
s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
s->carrier_phase += (0x80000000 + angle - 219937506);
@ -716,7 +697,7 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
p = angle*2.0f*3.14159f/(65536.0f*65536.0f) - 0.321751f;
span_log(&s->logging, SPAN_LOG_FLOW, "Spin (long) by %.5f rads\n", p);
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V17_EQUALIZER_MASK; i++)
for (i = 0; i < V17_EQUALIZER_LEN; i++)
s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
s->carrier_phase += (angle - 219937506);
@ -960,7 +941,6 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
int v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
{
int i;
int j;
int step;
int16_t x;
int32_t diff;
@ -968,15 +948,18 @@ int v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
complexf_t zz;
complexf_t sample;
#if defined(SPANDSP_USE_FIXED_POINT)
complexi_t zi;
int32_t vi;
#endif
#if defined(SPANDSP_USE_FIXED_POINTx)
int32_t v;
#else
float v;
#endif
int32_t power;
float v;
for (i = 0; i < len; i++)
{
s->rrc_filter[s->rrc_filter_step] =
s->rrc_filter[s->rrc_filter_step + V17_RX_FILTER_STEPS] = amp[i];
s->rrc_filter[s->rrc_filter_step] = amp[i];
if (++s->rrc_filter_step >= V17_RX_FILTER_STEPS)
s->rrc_filter_step = 0;
@ -1052,17 +1035,13 @@ int v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
if (step < 0)
step += RX_PULSESHAPER_COEFF_SETS;
#if defined(SPANDSP_USE_FIXED_POINT)
zi.re = (int32_t) rx_pulseshaper[step][0].re*(int32_t) s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V17_RX_FILTER_STEPS; j++)
zi.re += (int32_t) rx_pulseshaper[step][j].re*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
sample.re = zi.re*s->agc_scaling;
vi = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_re[step], V17_RX_FILTER_STEPS, s->rrc_filter_step);
//sample.re = (vi*(int32_t) s->agc_scaling) >> 15;
sample.re = vi*s->agc_scaling;
#else
zz.re = rx_pulseshaper[step][0].re*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V17_RX_FILTER_STEPS; j++)
zz.re += rx_pulseshaper[step][j].re*s->rrc_filter[j + s->rrc_filter_step];
sample.re = zz.re*s->agc_scaling;
v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_re[step], V17_RX_FILTER_STEPS, s->rrc_filter_step);
sample.re = v*s->agc_scaling;
#endif
/* 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;
@ -1087,27 +1066,22 @@ int v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
step = -s->eq_put_step;
if (step > RX_PULSESHAPER_COEFF_SETS - 1)
step = RX_PULSESHAPER_COEFF_SETS - 1;
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
#if defined(SPANDSP_USE_FIXED_POINT)
zi.im = (int32_t) rx_pulseshaper[step][0].im*(int32_t) s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V17_RX_FILTER_STEPS; j++)
zi.im += (int32_t) rx_pulseshaper[step][j].im*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
sample.im = zi.im*s->agc_scaling;
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
vi = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_im[step], V17_RX_FILTER_STEPS, s->rrc_filter_step);
//sample.im = (vi*(int32_t) s->agc_scaling) >> 15;
sample.im = vi*s->agc_scaling;
z = dds_lookup_complexf(s->carrier_phase);
zz.re = sample.re*z.re - sample.im*z.im;
zz.im = -sample.re*z.im - sample.im*z.re;
process_half_baud(s, &zz);
#else
zz.im = rx_pulseshaper[step][0].im*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V17_RX_FILTER_STEPS; j++)
zz.im += rx_pulseshaper[step][j].im*s->rrc_filter[j + s->rrc_filter_step];
sample.im = zz.im*s->agc_scaling;
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_im[step], V17_RX_FILTER_STEPS, s->rrc_filter_step);
sample.im = v*s->agc_scaling;
z = dds_lookup_complexf(s->carrier_phase);
zz.re = sample.re*z.re - sample.im*z.im;
zz.im = -sample.re*z.im - sample.im*z.re;
process_half_baud(s, &zz);
#endif
process_half_baud(s, &zz);
}
#if defined(SPANDSP_USE_FIXED_POINT)
dds_advance(&s->carrier_phase, s->carrier_phase_rate);
@ -1165,7 +1139,7 @@ int v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_train)
}
s->bit_rate = bit_rate;
#if defined(SPANDSP_USE_FIXED_POINT)
memset(s->rrc_filter, 0, sizeof(s->rrc_filter));
vec_zeroi16(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
#else
vec_zerof(s->rrc_filter, sizeof(s->rrc_filter)/sizeof(s->rrc_filter[0]));
#endif

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v22bis_rx.c,v 1.41 2008/09/07 12:45:17 steveu Exp $
* $Id: v22bis_rx.c,v 1.42 2008/09/18 14:59:30 steveu Exp $
*/
/*! \file */
@ -590,15 +590,15 @@ int v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
/* TODO: get rid of this */
if (s->caller)
{
ii = rx_pulseshaper_2400[6][0].re*s->rx.rrc_filter[s->rx.rrc_filter_step];
ii = rx_pulseshaper_2400_re[6][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
ii += rx_pulseshaper_2400[6][j].re*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
ii += rx_pulseshaper_2400_re[6][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
}
else
{
ii = rx_pulseshaper_1200[6][0].re*s->rx.rrc_filter[s->rx.rrc_filter_step];
ii = rx_pulseshaper_1200_re[6][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
ii += rx_pulseshaper_1200[6][j].re*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
ii += rx_pulseshaper_1200_re[6][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
}
power = power_meter_update(&(s->rx.rx_power), (int16_t) (ii/10.0f));
if (s->rx.signal_present)
@ -643,22 +643,22 @@ int v22bis_rx(v22bis_state_t *s, const int16_t amp[], int len)
s->rx.eq_put_step += PULSESHAPER_COEFF_SETS*40/(3*2);
if (s->caller)
{
ii = rx_pulseshaper_2400[step][0].re*s->rx.rrc_filter[s->rx.rrc_filter_step];
qq = rx_pulseshaper_2400[step][0].im*s->rx.rrc_filter[s->rx.rrc_filter_step];
ii = rx_pulseshaper_2400_re[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
qq = rx_pulseshaper_2400_im[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
{
ii += rx_pulseshaper_2400[step][j].re*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
qq += rx_pulseshaper_2400[step][j].im*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
ii += rx_pulseshaper_2400_re[step][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
qq += rx_pulseshaper_2400_im[step][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
}
}
else
{
ii = rx_pulseshaper_1200[step][0].re*s->rx.rrc_filter[s->rx.rrc_filter_step];
qq = rx_pulseshaper_1200[step][0].im*s->rx.rrc_filter[s->rx.rrc_filter_step];
ii = rx_pulseshaper_1200_re[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
qq = rx_pulseshaper_1200_im[step][0]*s->rx.rrc_filter[s->rx.rrc_filter_step];
for (j = 1; j < V22BIS_RX_FILTER_STEPS; j++)
{
ii += rx_pulseshaper_1200[step][j].re*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
qq += rx_pulseshaper_1200[step][j].im*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
ii += rx_pulseshaper_1200_re[step][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
qq += rx_pulseshaper_1200_im[step][j]*s->rx.rrc_filter[j + s->rx.rrc_filter_step];
}
}
sample.re = ii*s->rx.agc_scaling;

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v27ter_rx.c,v 1.104 2008/09/16 14:12:23 steveu Exp $
* $Id: v27ter_rx.c,v 1.107 2008/09/18 14:59:30 steveu Exp $
*/
/*! \file */
@ -86,6 +86,8 @@
#define V27TER_TRAINING_SEG_5_LEN 1074
#define V27TER_TRAINING_SEG_6_LEN 8
#define V27TER_EQUALIZER_LEN (V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN)
enum
{
TRAINING_STAGE_NORMAL_OPERATION = 0,
@ -168,16 +170,16 @@ int v27ter_rx_equalizer_state(v27ter_rx_state_t *s, complexf_t **coeffs)
#endif
{
*coeffs = s->eq_coeff;
return V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN;
return V27TER_EQUALIZER_LEN;
}
/*- End of function --------------------------------------------------------*/
static void equalizer_save(v27ter_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINTx)
cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_LEN);
#else
cvec_copyf(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_copyf(s->eq_coeff_save, s->eq_coeff, V27TER_EQUALIZER_LEN);
#endif
}
/*- End of function --------------------------------------------------------*/
@ -185,13 +187,13 @@ static void equalizer_save(v27ter_rx_state_t *s)
static void equalizer_restore(v27ter_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINTx)
cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_MASK);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/(V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_LEN);
cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN);
#else
cvec_copyf(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_buf, V27TER_EQUALIZER_MASK);
s->eq_delta = EQUALIZER_DELTA/(V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_copyf(s->eq_coeff, s->eq_coeff_save, V27TER_EQUALIZER_LEN);
cvec_zerof(s->eq_buf, V27TER_EQUALIZER_LEN);
s->eq_delta = EQUALIZER_DELTA/V27TER_EQUALIZER_LEN;
#endif
s->eq_put_step = (s->bit_rate == 4800) ? RX_PULSESHAPER_4800_COEFF_SETS*5/2 : RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
@ -203,15 +205,15 @@ static void equalizer_reset(v27ter_rx_state_t *s)
{
/* Start with an equalizer based on everything being perfect. */
#if defined(SPANDSP_USE_FIXED_POINTx)
cvec_zeroi16(s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_coeff, V27TER_EQUALIZER_LEN);
s->eq_coeff[V27TER_EQUALIZER_PRE_LEN] = complex_seti16(1.414f*FP_FACTOR, 0);
cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_MASK);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/(V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_buf, V27TER_EQUALIZER_LEN);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V27TER_EQUALIZER_LEN);
#else
cvec_zerof(s->eq_coeff, V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_coeff, V27TER_EQUALIZER_LEN);
s->eq_coeff[V27TER_EQUALIZER_PRE_LEN] = complex_setf(1.414f, 0.0f);
cvec_zerof(s->eq_buf, V27TER_EQUALIZER_MASK);
s->eq_delta = EQUALIZER_DELTA/(V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_buf, V27TER_EQUALIZER_LEN);
s->eq_delta = EQUALIZER_DELTA/V27TER_EQUALIZER_LEN;
#endif
s->eq_put_step = (s->bit_rate == 4800) ? RX_PULSESHAPER_4800_COEFF_SETS*5/2 : RX_PULSESHAPER_2400_COEFF_SETS*20/(3*2);
@ -237,36 +239,19 @@ static __inline__ complexi16_t equalizer_get(v27ter_rx_state_t *s)
static __inline__ complexf_t equalizer_get(v27ter_rx_state_t *s)
#endif
{
int i;
int p;
#if defined(SPANDSP_USE_FIXED_POINTx)
complexi32_t zz;
complexi16_t z;
complexi16_t z1;
#else
complexf_t z;
complexf_t z1;
#endif
/* Get the next equalized value. */
p = s->eq_step - 1;
#if defined(SPANDSP_USE_FIXED_POINTx)
z = complex_seti16(0, 0);
for (i = 0; i < V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V27TER_EQUALIZER_MASK;
z1 = complex_mul_q4_12(&s->eq_coeff[i], &s->eq_buf[p]);
z = complex_addi16(&z, &z1);
}
#else
z = complex_setf(0.0f, 0.0f);
for (i = 0; i < V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V27TER_EQUALIZER_MASK;
z1 = complex_mulf(&s->eq_coeff[i], &s->eq_buf[p]);
z = complex_addf(&z, &z1);
}
#endif
zz = cvec_circular_dot_prodi16(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step);
z.re = zz.re >> FP_SHIFT_FACTOR;
z.im = zz.im >> FP_SHIFT_FACTOR;
return z;
#else
/* Get the next equalized value. */
return cvec_circular_dot_prodf(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step);
#endif
}
/*- End of function --------------------------------------------------------*/
@ -276,45 +261,24 @@ static void tune_equalizer(v27ter_rx_state_t *s, const complexi16_t *z, const co
static void tune_equalizer(v27ter_rx_state_t *s, const complexf_t *z, const complexf_t *target)
#endif
{
int i;
int p;
#if defined(SPANDSP_USE_FIXED_POINTx)
complexi16_t ez;
complexi16_t z1;
#else
complexf_t ez;
complexf_t z1;
#endif
complexi16_t err;
/* Find the x and y mismatch from the exact constellation position. */
#if defined(SPANDSP_USE_FIXED_POINTx)
ez.re = target->re*FP_FACTOR - z->re;
ez.im = target->im*FP_FACTOR - z->im;
ez.re = ((int32_t) ez.re*(int32_t) s->eq_delta) >> 15;
ez.im = ((int32_t) ez.im*(int32_t) s->eq_delta) >> 15;
err.re = target->re*FP_FACTOR - z->re;
err.im = target->im*FP_FACTOR - z->im;
err.re = ((int32_t) err.re*(int32_t) s->eq_delta) >> 15;
err.im = ((int32_t) err.im*(int32_t) s->eq_delta) >> 15;
cvec_circular_lmsi16(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step, &err);
#else
ez = complex_subf(target, z);
ez.re *= s->eq_delta;
ez.im *= s->eq_delta;
#endif
complexf_t err;
p = s->eq_step - 1;
for (i = 0; i < V27TER_EQUALIZER_PRE_LEN + 1 + V27TER_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V27TER_EQUALIZER_MASK;
#if defined(SPANDSP_USE_FIXED_POINTx)
z1 = complex_conji16(&s->eq_buf[p]);
z1 = complex_mul_q4_12(&ez, &z1);
s->eq_coeff[i] = complex_addi16(&s->eq_coeff[i], &z1);
#else
z1 = complex_conjf(&s->eq_buf[p]);
z1 = complex_mulf(&ez, &z1);
s->eq_coeff[i] = complex_addf(&s->eq_coeff[i], &z1);
/* Leak a little to tame uncontrolled wandering */
s->eq_coeff[i].re *= 0.9999f;
s->eq_coeff[i].im *= 0.9999f;
/* Find the x and y mismatch from the exact constellation position. */
err = complex_subf(target, z);
err.re *= s->eq_delta;
err.im *= s->eq_delta;
cvec_circular_lmsf(s->eq_buf, s->eq_coeff, V27TER_EQUALIZER_LEN, s->eq_step, &err);
#endif
}
}
/*- End of function --------------------------------------------------------*/
@ -508,13 +472,13 @@ static __inline__ void symbol_sync(v27ter_rx_state_t *s)
/* This routine adapts the position of the half baud samples entering the equalizer. */
/* Perform a Gardner test for baud alignment */
p = s->eq_buf[(s->eq_step - 3) & V27TER_EQUALIZER_MASK].re
- s->eq_buf[(s->eq_step - 1) & V27TER_EQUALIZER_MASK].re;
p *= s->eq_buf[(s->eq_step - 2) & V27TER_EQUALIZER_MASK].re;
p = s->eq_buf[(s->eq_step - 3) & V27TER_EQUALIZER_LEN].re
- s->eq_buf[(s->eq_step - 1) & V27TER_EQUALIZER_LEN].re;
p *= s->eq_buf[(s->eq_step - 2) & V27TER_EQUALIZER_LEN].re;
q = s->eq_buf[(s->eq_step - 3) & V27TER_EQUALIZER_MASK].im
- s->eq_buf[(s->eq_step - 1) & V27TER_EQUALIZER_MASK].im;
q *= s->eq_buf[(s->eq_step - 2) & V27TER_EQUALIZER_MASK].im;
q = s->eq_buf[(s->eq_step - 3) & V27TER_EQUALIZER_LEN].im
- s->eq_buf[(s->eq_step - 1) & V27TER_EQUALIZER_LEN].im;
q *= s->eq_buf[(s->eq_step - 2) & V27TER_EQUALIZER_LEN].im;
s->gardner_integrate += (p + q > 0.0f) ? s->gardner_step : -s->gardner_step;
@ -560,7 +524,8 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
#else
s->eq_buf[s->eq_step] = *sample;
#endif
s->eq_step = (s->eq_step + 1) & V27TER_EQUALIZER_MASK;
if (++s->eq_step >= V27TER_EQUALIZER_LEN)
s->eq_step = 0;
/* On alternate insertions we have a whole baud, and must process it. */
if ((s->baud_half ^= 1))
@ -642,7 +607,7 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
p = angle*2.0f*3.14159f/(65536.0f*65536.0f);
#if defined(SPANDSP_USE_FIXED_POINTx)
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V27TER_EQUALIZER_MASK; i++)
for (i = 0; i < V27TER_EQUALIZER_LEN; i++)
{
z1 = complex_setf(s->eq_buf[i].re, s->eq_buf[i].im);
z1 = complex_mulf(&z1, &zz);
@ -651,7 +616,7 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
}
#else
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V27TER_EQUALIZER_MASK; i++)
for (i = 0; i < V27TER_EQUALIZER_LEN; i++)
s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
#endif
s->carrier_phase += angle;
@ -774,7 +739,6 @@ static __inline__ void process_half_baud(v27ter_rx_state_t *s, const complexf_t
int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
{
int i;
int j;
int step;
int16_t x;
int32_t diff;
@ -782,11 +746,12 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
complexi16_t z;
complexi16_t zz;
complexi16_t sample;
complexi32_t zi;
int32_t v;
#else
complexf_t z;
complexf_t zz;
complexf_t sample;
float v;
#endif
int32_t power;
@ -794,8 +759,7 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
{
for (i = 0; i < len; i++)
{
s->rrc_filter[s->rrc_filter_step] =
s->rrc_filter[s->rrc_filter_step + V27TER_RX_4800_FILTER_STEPS] = amp[i];
s->rrc_filter[s->rrc_filter_step] = amp[i];
if (++s->rrc_filter_step >= V27TER_RX_4800_FILTER_STEPS)
s->rrc_filter_step = 0;
@ -887,28 +851,18 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
step = RX_PULSESHAPER_4800_COEFF_SETS - 1;
s->eq_put_step += RX_PULSESHAPER_4800_COEFF_SETS*5/2;
#if defined(SPANDSP_USE_FIXED_POINT)
zi.re = (int32_t) rx_pulseshaper_4800[step][0].re*(int32_t) s->rrc_filter[s->rrc_filter_step];
zi.im = (int32_t) rx_pulseshaper_4800[step][0].im*(int32_t) s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V27TER_RX_4800_FILTER_STEPS; j++)
{
zi.re += (int32_t) rx_pulseshaper_4800[step][j].re*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
zi.im += (int32_t) rx_pulseshaper_4800[step][j].im*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
}
sample.re = ((int32_t) zi.re*(int32_t) s->agc_scaling) >> 15;
sample.im = ((int32_t) zi.im*(int32_t) s->agc_scaling) >> 15;
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_4800_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
sample.re = (v*(int32_t) s->agc_scaling) >> 15;
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_4800_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
sample.im = (v*(int32_t) s->agc_scaling) >> 15;
z = dds_lookup_complexi16(s->carrier_phase);
zz.re = ((int32_t) sample.re*(int32_t) z.re - (int32_t) sample.im*(int32_t) z.im) >> 15;
zz.im = ((int32_t) -sample.re*(int32_t) z.im - (int32_t) sample.im*(int32_t) z.re) >> 15;
#else
zz.re = rx_pulseshaper_4800[step][0].re*s->rrc_filter[s->rrc_filter_step];
zz.im = rx_pulseshaper_4800[step][0].im*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V27TER_RX_4800_FILTER_STEPS; j++)
{
zz.re += rx_pulseshaper_4800[step][j].re*s->rrc_filter[j + s->rrc_filter_step];
zz.im += rx_pulseshaper_4800[step][j].im*s->rrc_filter[j + s->rrc_filter_step];
}
sample.re = zz.re*s->agc_scaling;
sample.im = zz.im*s->agc_scaling;
v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_4800_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
sample.re = v*s->agc_scaling;
v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_4800_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
sample.im = v*s->agc_scaling;
z = dds_lookup_complexf(s->carrier_phase);
zz.re = sample.re*z.re - sample.im*z.im;
zz.im = -sample.re*z.im - sample.im*z.re;
@ -926,8 +880,7 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
{
for (i = 0; i < len; i++)
{
s->rrc_filter[s->rrc_filter_step] =
s->rrc_filter[s->rrc_filter_step + V27TER_RX_2400_FILTER_STEPS] = amp[i];
s->rrc_filter[s->rrc_filter_step] = amp[i];
if (++s->rrc_filter_step >= V27TER_RX_2400_FILTER_STEPS)
s->rrc_filter_step = 0;
@ -1020,28 +973,18 @@ int v27ter_rx(v27ter_rx_state_t *s, const int16_t amp[], int len)
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)
zi.re = (int32_t) rx_pulseshaper_2400[step][0].re*(int32_t) s->rrc_filter[s->rrc_filter_step];
zi.im = (int32_t) rx_pulseshaper_2400[step][0].im*(int32_t) s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V27TER_RX_2400_FILTER_STEPS; j++)
{
zi.re += (int32_t) rx_pulseshaper_2400[step][j].re*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
zi.im += (int32_t) rx_pulseshaper_2400[step][j].im*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
}
sample.re = ((int32_t) zi.re*(int32_t) s->agc_scaling) >> 15;
sample.im = ((int32_t) zi.im*(int32_t) s->agc_scaling) >> 15;
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_2400_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
sample.re = (v*(int32_t) s->agc_scaling) >> 15;
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_2400_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
sample.im = (v*(int32_t) s->agc_scaling) >> 15;
z = dds_lookup_complexi16(s->carrier_phase);
zz.re = ((int32_t) sample.re*(int32_t) z.re - (int32_t) sample.im*(int32_t) z.im) >> 15;
zz.im = ((int32_t) -sample.re*(int32_t) z.im - (int32_t) sample.im*(int32_t) z.re) >> 15;
#else
zz.re = rx_pulseshaper_2400[step][0].re*s->rrc_filter[s->rrc_filter_step];
zz.im = rx_pulseshaper_2400[step][0].im*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V27TER_RX_2400_FILTER_STEPS; j++)
{
zz.re += rx_pulseshaper_2400[step][j].re*s->rrc_filter[j + s->rrc_filter_step];
zz.im += rx_pulseshaper_2400[step][j].im*s->rrc_filter[j + s->rrc_filter_step];
}
sample.re = zz.re*s->agc_scaling;
sample.im = zz.im*s->agc_scaling;
v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_2400_re[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
sample.re = v*s->agc_scaling;
v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_2400_im[step], V27TER_RX_FILTER_STEPS, s->rrc_filter_step);
sample.im = v*s->agc_scaling;
z = dds_lookup_complexf(s->carrier_phase);
zz.re = sample.re*z.re - sample.im*z.im;
zz.im = -sample.re*z.im - sample.im*z.re;

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: v29rx.c,v 1.140 2008/09/16 14:12:23 steveu Exp $
* $Id: v29rx.c,v 1.144 2008/09/18 14:59:30 steveu Exp $
*/
/*! \file */
@ -79,6 +79,8 @@
#define V29_TRAINING_SEG_3_LEN 384
#define V29_TRAINING_SEG_4_LEN 48
#define V29_EQUALIZER_LEN (V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN)
enum
{
TRAINING_STAGE_NORMAL_OPERATION = 0,
@ -176,16 +178,16 @@ int v29_rx_equalizer_state(v29_rx_state_t *s, complexf_t **coeffs)
#endif
{
*coeffs = s->eq_coeff;
return V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN;
return V29_EQUALIZER_LEN;
}
/*- End of function --------------------------------------------------------*/
static void equalizer_save(v29_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINT)
cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_copyi16(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_LEN);
#else
cvec_copyf(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_copyf(s->eq_coeff_save, s->eq_coeff, V29_EQUALIZER_LEN);
#endif
}
/*- End of function --------------------------------------------------------*/
@ -193,13 +195,13 @@ static void equalizer_save(v29_rx_state_t *s)
static void equalizer_restore(v29_rx_state_t *s)
{
#if defined(SPANDSP_USE_FIXED_POINT)
cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_buf, V29_EQUALIZER_MASK);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_copyi16(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_LEN);
cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN;
#else
cvec_copyf(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_buf, V29_EQUALIZER_MASK);
s->eq_delta = EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_copyf(s->eq_coeff, s->eq_coeff_save, V29_EQUALIZER_LEN);
cvec_zerof(s->eq_buf, V29_EQUALIZER_LEN);
s->eq_delta = EQUALIZER_DELTA/V29_EQUALIZER_LEN;
#endif
s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
@ -211,15 +213,15 @@ static void equalizer_reset(v29_rx_state_t *s)
{
/* Start with an equalizer based on everything being perfect */
#if defined(SPANDSP_USE_FIXED_POINT)
cvec_zeroi16(s->eq_coeff, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
s->eq_coeff[V29_EQUALIZER_PRE_LEN] = complex_seti16(3*FP_FACTOR, 0*FP_FACTOR);
cvec_zeroi16(s->eq_buf, V29_EQUALIZER_MASK);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_zeroi16(s->eq_coeff, V29_EQUALIZER_LEN);
s->eq_coeff[V29_EQUALIZER_POST_LEN] = complex_seti16(3*FP_FACTOR, 0*FP_FACTOR);
cvec_zeroi16(s->eq_buf, V29_EQUALIZER_LEN);
s->eq_delta = 32768.0f*EQUALIZER_DELTA/V29_EQUALIZER_LEN;
#else
cvec_zerof(s->eq_coeff, V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
s->eq_coeff[V29_EQUALIZER_PRE_LEN] = complex_setf(3.0f, 0.0f);
cvec_zerof(s->eq_buf, V29_EQUALIZER_MASK);
s->eq_delta = EQUALIZER_DELTA/(V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN);
cvec_zerof(s->eq_coeff, V29_EQUALIZER_LEN);
s->eq_coeff[V29_EQUALIZER_POST_LEN] = complex_setf(3.0f, 0.0f);
cvec_zerof(s->eq_buf, V29_EQUALIZER_LEN);
s->eq_delta = EQUALIZER_DELTA/V29_EQUALIZER_LEN;
#endif
s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
@ -232,8 +234,8 @@ static __inline__ complexi16_t complex_mul_q4_12(const complexi16_t *x, const co
{
complexi16_t z;
z.re = ((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im) >> 12;
z.im = ((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re) >> 12;
z.re = ((int32_t) x->re*(int32_t) y->re - (int32_t) x->im*(int32_t) y->im) >> FP_SHIFT_FACTOR;
z.im = ((int32_t) x->re*(int32_t) y->im + (int32_t) x->im*(int32_t) y->re) >> FP_SHIFT_FACTOR;
return z;
}
/*- End of function --------------------------------------------------------*/
@ -245,36 +247,19 @@ static __inline__ complexi16_t equalizer_get(v29_rx_state_t *s)
static __inline__ complexf_t equalizer_get(v29_rx_state_t *s)
#endif
{
int i;
int p;
#if defined(SPANDSP_USE_FIXED_POINT)
complexi32_t zz;
complexi16_t z;
complexi16_t z1;
#else
complexf_t z;
complexf_t z1;
#endif
/* Get the next equalized value. */
p = s->eq_step - 1;
#if defined(SPANDSP_USE_FIXED_POINT)
z = complex_seti16(0, 0);
for (i = 0; i < V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V29_EQUALIZER_MASK;
z1 = complex_mul_q4_12(&s->eq_coeff[i], &s->eq_buf[p]);
z = complex_addi16(&z, &z1);
}
#else
z = complex_setf(0.0f, 0.0f);
for (i = 0; i < V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V29_EQUALIZER_MASK;
z1 = complex_mulf(&s->eq_coeff[i], &s->eq_buf[p]);
z = complex_addf(&z, &z1);
}
#endif
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;
return z;
#else
/* Get the next equalized value. */
return cvec_circular_dot_prodf(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step);
#endif
}
/*- End of function --------------------------------------------------------*/
@ -284,45 +269,24 @@ static void tune_equalizer(v29_rx_state_t *s, const complexi16_t *z, const compl
static void tune_equalizer(v29_rx_state_t *s, const complexf_t *z, const complexf_t *target)
#endif
{
int i;
int p;
#if defined(SPANDSP_USE_FIXED_POINT)
complexi16_t ez;
complexi16_t z1;
#else
complexf_t ez;
complexf_t z1;
#endif
complexi16_t err;
/* Find the x and y mismatch from the exact constellation position. */
#if defined(SPANDSP_USE_FIXED_POINT)
ez.re = target->re*FP_FACTOR - z->re;
ez.im = target->im*FP_FACTOR - z->im;
ez.re = ((int32_t) ez.re*(int32_t) s->eq_delta) >> 15;
ez.im = ((int32_t) ez.im*(int32_t) s->eq_delta) >> 15;
err.re = target->re*FP_FACTOR - z->re;
err.im = target->im*FP_FACTOR - z->im;
err.re = ((int32_t) err.re*(int32_t) s->eq_delta) >> 15;
err.im = ((int32_t) err.im*(int32_t) s->eq_delta) >> 15;
cvec_circular_lmsi16(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step, &err);
#else
ez = complex_subf(target, z);
ez.re *= s->eq_delta;
ez.im *= s->eq_delta;
#endif
complexf_t err;
p = s->eq_step - 1;
for (i = 0; i < V29_EQUALIZER_PRE_LEN + 1 + V29_EQUALIZER_POST_LEN; i++)
{
p = (p - 1) & V29_EQUALIZER_MASK;
#if defined(SPANDSP_USE_FIXED_POINT)
z1 = complex_conji16(&s->eq_buf[p]);
z1 = complex_mul_q4_12(&ez, &z1);
s->eq_coeff[i] = complex_addi16(&s->eq_coeff[i], &z1);
#else
z1 = complex_conjf(&s->eq_buf[p]);
z1 = complex_mulf(&ez, &z1);
s->eq_coeff[i] = complex_addf(&s->eq_coeff[i], &z1);
/* Leak a little to tame uncontrolled wandering */
s->eq_coeff[i].re *= 0.9999f;
s->eq_coeff[i].im *= 0.9999f;
/* Find the x and y mismatch from the exact constellation position. */
err = complex_subf(target, z);
err.re *= s->eq_delta;
err.im *= s->eq_delta;
cvec_circular_lmsf(s->eq_buf, s->eq_coeff, V29_EQUALIZER_LEN, s->eq_step, &err);
#endif
}
}
/*- End of function --------------------------------------------------------*/
@ -597,7 +561,8 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
/* Add a sample to the equalizer's circular buffer, but don't calculate anything
at this time. */
s->eq_buf[s->eq_step] = *sample;
s->eq_step = (s->eq_step + 1) & V29_EQUALIZER_MASK;
if (++s->eq_step >= V29_EQUALIZER_LEN)
s->eq_step = 0;
/* On alternate insertions we have a whole baud, and must process it. */
if ((s->baud_half ^= 1))
@ -687,7 +652,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
p = angle*2.0f*3.14159f/(65536.0f*65536.0f);
#if defined(SPANDSP_USE_FIXED_POINT)
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V29_EQUALIZER_MASK; i++)
for (i = 0; i < V29_EQUALIZER_LEN; i++)
{
z1 = complex_setf(s->eq_buf[i].re, s->eq_buf[i].im);
z1 = complex_mulf(&z1, &zz);
@ -696,7 +661,7 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
}
#else
zz = complex_setf(cosf(p), -sinf(p));
for (i = 0; i <= V29_EQUALIZER_MASK; i++)
for (i = 0; i < V29_EQUALIZER_LEN; i++)
s->eq_buf[i] = complex_mulf(&s->eq_buf[i], &zz);
#endif
s->carrier_phase += angle;
@ -860,7 +825,6 @@ static void process_half_baud(v29_rx_state_t *s, complexf_t *sample)
int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
{
int i;
int j;
int step;
int16_t x;
int32_t diff;
@ -879,8 +843,7 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
for (i = 0; i < len; i++)
{
s->rrc_filter[s->rrc_filter_step] =
s->rrc_filter[s->rrc_filter_step + V29_RX_FILTER_STEPS] = amp[i];
s->rrc_filter[s->rrc_filter_step] = amp[i];
if (++s->rrc_filter_step >= V29_RX_FILTER_STEPS)
s->rrc_filter_step = 0;
@ -956,25 +919,21 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
if (step < 0)
step += RX_PULSESHAPER_COEFF_SETS;
#if defined(SPANDSP_USE_FIXED_POINT)
v = (int32_t) rx_pulseshaper[step][0].re*(int32_t) s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
v += (int32_t) rx_pulseshaper[step][j].re*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_re[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
sample.re = (v*s->agc_scaling) >> 15;
#else
v = rx_pulseshaper[step][0].re*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
v += rx_pulseshaper[step][j].re*s->rrc_filter[j + s->rrc_filter_step];
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) >> 12) + ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> 12) + sample.re;
v = ((s->symbol_sync_low[0]*SYNC_LOW_BAND_EDGE_COEFF_0) >> FP_SHIFT_FACTOR) + ((s->symbol_sync_low[1]*SYNC_LOW_BAND_EDGE_COEFF_1) >> FP_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) >> 12) + ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> 12) + sample.re;
v = ((s->symbol_sync_high[0]*SYNC_HIGH_BAND_EDGE_COEFF_0) >> FP_SHIFT_FACTOR) + ((s->symbol_sync_high[1]*SYNC_HIGH_BAND_EDGE_COEFF_1) >> FP_SHIFT_FACTOR) + sample.re;
s->symbol_sync_high[1] = s->symbol_sync_high[0];
s->symbol_sync_high[0] = v;
#else
@ -1008,17 +967,13 @@ int v29_rx(v29_rx_state_t *s, const int16_t amp[], int len)
step = RX_PULSESHAPER_COEFF_SETS - 1;
s->eq_put_step += RX_PULSESHAPER_COEFF_SETS*10/(3*2);
#if defined(SPANDSP_USE_FIXED_POINT)
v = (int32_t) rx_pulseshaper[step][0].im*(int32_t) s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
v += (int32_t) rx_pulseshaper[step][j].im*(int32_t) s->rrc_filter[j + s->rrc_filter_step];
v = vec_circular_dot_prodi16(s->rrc_filter, rx_pulseshaper_im[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
sample.im = (v*s->agc_scaling) >> 15;
z = dds_lookup_complexi16(s->carrier_phase);
zz.re = ((int32_t) sample.re*(int32_t) z.re - (int32_t) sample.im*(int32_t) z.im) >> 15;
zz.im = ((int32_t) -sample.re*(int32_t) z.im - (int32_t) sample.im*(int32_t) z.re) >> 15;
#else
v = rx_pulseshaper[step][0].im*s->rrc_filter[s->rrc_filter_step];
for (j = 1; j < V29_RX_FILTER_STEPS; j++)
v += rx_pulseshaper[step][j].im*s->rrc_filter[j + s->rrc_filter_step];
v = vec_circular_dot_prodf(s->rrc_filter, rx_pulseshaper_im[step], V29_RX_FILTER_STEPS, s->rrc_filter_step);
sample.im = v*s->agc_scaling;
z = dds_lookup_complexf(s->carrier_phase);
zz.re = sample.re*z.re - sample.im*z.im;

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: vector_float.c,v 1.12 2008/09/16 15:21:52 steveu Exp $
* $Id: vector_float.c,v 1.14 2008/09/18 13:54:32 steveu Exp $
*/
/*! \file */
@ -337,22 +337,25 @@ float vec_dot_prodf(const float x[], const float y[], int n)
{
int i;
float z;
__m128 num1, num2, num3, num4;
__m128 n1;
__m128 n2;
__m128 n3;
__m128 n4;
z = 0.0f;
if ((i = n & ~3))
{
num4 = _mm_setzero_ps(); //sets sum to zero
n4 = _mm_setzero_ps(); //sets sum to zero
for (i -= 4; i >= 0; i -= 4)
{
num1 = _mm_loadu_ps(x + i);
num2 = _mm_loadu_ps(y + i);
num3 = _mm_mul_ps(num1, num2);
num4 = _mm_add_ps(num4, num3);
n1 = _mm_loadu_ps(x + i);
n2 = _mm_loadu_ps(y + i);
n3 = _mm_mul_ps(n1, n2);
n4 = _mm_add_ps(n4, n3);
}
num4 = _mm_add_ps(_mm_movehl_ps(num4, num4), num4);
num4 = _mm_add_ss(_mm_shuffle_ps(num4, num4, 1), num4);
_mm_store_ss(&z, num4);
n4 = _mm_add_ps(_mm_movehl_ps(n4, n4), n4);
n4 = _mm_add_ss(_mm_shuffle_ps(n4, n4, 1), n4);
_mm_store_ss(&z, n4);
}
/* Now deal with the last 1 to 3 elements, which don't fill in an SSE2 register */
switch (n & 3)
@ -405,4 +408,34 @@ long double vec_dot_prodl(const long double x[], const long double y[], int n)
}
/*- End of function --------------------------------------------------------*/
#endif
float vec_circular_dot_prodf(const float x[], const float y[], int n, int pos)
{
float z;
z = vec_dot_prodf(&x[pos], &y[0], n - pos);
z += vec_dot_prodf(&x[0], &y[n - pos], pos);
return z;
}
/*- End of function --------------------------------------------------------*/
void vec_lmsf(const float x[], float y[], int n, float error)
{
int i;
for (i = 0; i < n; i++)
{
y[i] += x[i]*error;
/* Leak a little to tame uncontrolled wandering */
y[i] *= 0.9999f;
}
}
/*- End of function --------------------------------------------------------*/
void vec_circular_lmsf(const float x[], float y[], int n, int pos, float error)
{
vec_lmsf(&x[pos], &y[0], n - pos, error);
vec_lmsf(&x[0], &y[n - pos], pos, error);
}
/*- End of function --------------------------------------------------------*/
/*- End of file ------------------------------------------------------------*/

View File

@ -22,7 +22,7 @@
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: vector_int.c,v 1.13 2008/09/16 15:21:52 steveu Exp $
* $Id: vector_int.c,v 1.15 2008/09/18 13:54:32 steveu Exp $
*/
/*! \file */
@ -160,6 +160,32 @@ int32_t vec_dot_prodi16(const int16_t x[], const int16_t y[], int n)
}
/*- End of function --------------------------------------------------------*/
int32_t vec_circular_dot_prodi16(const int16_t x[], const int16_t y[], int n, int pos)
{
int32_t z;
z = vec_dot_prodi16(&x[pos], &y[0], n - pos);
z += vec_dot_prodi16(&x[0], &y[n - pos], pos);
return z;
}
/*- End of function --------------------------------------------------------*/
void vec_lmsi16(const int16_t x[], int16_t y[], int n, int16_t error)
{
int i;
for (i = 0; i < n; i++)
y[i] += ((int32_t) x[i]*(int32_t) error) >> 15;
}
/*- End of function --------------------------------------------------------*/
void vec_circular_lmsi16(const int16_t x[], int16_t y[], int n, int pos, int16_t error)
{
vec_lmsi16(&x[pos], &y[0], n - pos, error);
vec_lmsi16(&x[0], &y[n - pos], pos, error);
}
/*- End of function --------------------------------------------------------*/
int32_t vec_min_maxi16(const int16_t x[], int n, int16_t out[])
{
#if defined(__GNUC__) && defined(SPANDSP_USE_MMX)

View File

@ -16,7 +16,7 @@
## along with this program; if not, write to the Free Software
## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
##
## $Id: Makefile.am,v 1.106 2008/09/09 14:05:55 steveu Exp $
## $Id: Makefile.am,v 1.107 2008/09/18 12:05:35 steveu Exp $
AM_CFLAGS = $(COMP_VENDOR_CFLAGS)
AM_LDFLAGS = $(COMP_VENDOR_LDFLAGS)
@ -41,6 +41,9 @@ noinst_PROGRAMS = adsi_tests \
bell_mf_tx_tests \
bert_tests \
bit_operations_tests \
complex_tests \
complex_vector_float_tests \
complex_vector_int_tests \
crc_tests \
dc_restore_tests \
dds_tests \
@ -132,6 +135,15 @@ bert_tests_LDADD = $(LIBDIR) -lspandsp
bit_operations_tests_SOURCES = bit_operations_tests.c
bit_operations_tests_LDADD = $(LIBDIR) -lspandsp
complex_tests_SOURCES = complex_tests.c
complex_tests_LDADD = $(LIBDIR) -lspandsp
complex_vector_float_tests_SOURCES = complex_vector_float_tests.c
complex_vector_float_tests_LDADD = $(LIBDIR) -lspandsp
complex_vector_int_tests_SOURCES = complex_vector_int_tests.c
complex_vector_int_tests_LDADD = $(LIBDIR) -lspandsp
crc_tests_SOURCES = crc_tests.c
crc_tests_LDADD = $(LIBDIR) -lspandsp

View File

@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: g722_tests.c,v 1.26 2008/05/13 13:17:25 steveu Exp $
* $Id: g722_tests.c,v 1.27 2008/09/19 14:02:05 steveu Exp $
*/
/*! \file */
@ -109,8 +109,10 @@ static const char *itu_test_files[] =
static const char *encode_test_files[] =
{
TESTDATA_DIR "T1C1.XMT", TESTDATA_DIR "T2R1.COD",
TESTDATA_DIR "T1C2.XMT", TESTDATA_DIR "T2R2.COD",
TESTDATA_DIR "T1C1.XMT",
TESTDATA_DIR "T2R1.COD",
TESTDATA_DIR "T1C2.XMT",
TESTDATA_DIR "T2R2.COD",
NULL
};
@ -295,6 +297,7 @@ int main(int argc, char *argv[])
if (itutests)
{
#if 1
/* ITU G.722 encode tests, using configuration 1. The QMF is bypassed */
for (file = 0; encode_test_files[file]; file += 2)
{
@ -341,7 +344,8 @@ int main(int argc, char *argv[])
}
printf("Test passed\n");
}
#endif
#if 1
/* ITU G.722 decode tests, using configuration 2. The QMF is bypassed */
/* Run each of the tests for each of the modes - 48kbps, 56kbps and 64kbps. */
for (mode = 1; mode <= 3; mode++)
@ -404,7 +408,7 @@ int main(int argc, char *argv[])
printf("Test passed\n");
}
}
#endif
printf("Tests passed.\n");
}
else

View File

@ -17,7 +17,7 @@
# License along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id: regression_tests.sh,v 1.52 2008/09/02 13:56:10 steveu Exp $
# $Id: regression_tests.sh,v 1.53 2008/09/18 12:09:51 steveu Exp $
#
ITUTESTS_TIF=../test-data/itu/fax/itutests.tif
@ -99,6 +99,33 @@ then
fi
echo bit_operations_tests completed OK
./complex_tests >$STDOUT_DEST 2>$STDERR_DEST
RETVAL=$?
if [ $RETVAL != 0 ]
then
echo complex_tests failed!
exit $RETVAL
fi
echo complex_tests completed OK
./complex_vector_float_tests >$STDOUT_DEST 2>$STDERR_DEST
RETVAL=$?
if [ $RETVAL != 0 ]
then
echo complex_vector_float_tests failed!
exit $RETVAL
fi
echo complex_vector_float_tests completed OK
./complex_vector_int_tests >$STDOUT_DEST 2>$STDERR_DEST
RETVAL=$?
if [ $RETVAL != 0 ]
then
echo complex_vector_int_tests failed!
exit $RETVAL
fi
echo complex_vector_int_tests completed OK
./crc_tests >$STDOUT_DEST 2>$STDERR_DEST
RETVAL=$?
if [ $RETVAL != 0 ]

View File

@ -1,7 +1,7 @@
/*
* SpanDSP - a series of DSP components for telephony
*
* vector_int_tests.c
* complex_vector_int_tests.c
*
* Written by Steve Underwood <steveu@coppice.org>
*
@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: vector_int_tests.c,v 1.9 2008/09/16 15:21:52 steveu Exp $
* $Id: vector_int_tests.c,v 1.10 2008/09/18 12:05:35 steveu Exp $
*/
#if defined(HAVE_CONFIG_H)
@ -139,10 +139,51 @@ static int test_vec_min_maxi16(void)
}
/*- End of function --------------------------------------------------------*/
static int test_vec_circular_dot_prodi16(void)
{
int i;
int j;
int pos;
int len;
int32_t za;
int32_t zb;
int16_t x[99];
int16_t y[99];
/* Verify that we can do circular sample buffer "dot" linear coefficient buffer
operations properly, by doing two sub-dot products. */
for (i = 0; i < 99; i++)
{
x[i] = rand();
y[i] = rand();
}
len = 95;
for (pos = 0; pos < len; pos++)
{
za = vec_circular_dot_prodi16(x, y, len, pos);
zb = 0;
for (i = 0; i < len; i++)
{
j = (pos + i) % len;
zb += (int32_t) x[j]*(int32_t) y[i];
}
if (za != zb)
{
printf("Tests failed\n");
exit(2);
}
}
return 0;
}
/*- End of function --------------------------------------------------------*/
int main(int argc, char *argv[])
{
test_vec_dot_prodi16();
test_vec_min_maxi16();
test_vec_circular_dot_prodi16();
printf("Tests passed.\n");
return 0;