322 lines
8.0 KiB
C
322 lines
8.0 KiB
C
|
/*
|
|||
|
* V34 constant data generator
|
|||
|
*
|
|||
|
* Copyright (c) 1999,2000 Fabrice Bellard.
|
|||
|
*
|
|||
|
* This code is released under the GNU General Public License version
|
|||
|
* 2. Please read the file COPYING to know the exact terms of the
|
|||
|
* license.
|
|||
|
*/
|
|||
|
#include <stdlib.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <math.h>
|
|||
|
#include <assert.h>
|
|||
|
|
|||
|
#include "dsp.h"
|
|||
|
|
|||
|
#define V34_SAMPLE_RATE_NUM 10
|
|||
|
#define V34_SAMPLE_RATE_DEN 3
|
|||
|
#define V34_SAMPLE_RATE ((2400*V34_SAMPLE_RATE_NUM)/V34_SAMPLE_RATE_DEN)
|
|||
|
#define V22_TX_FILTER_SIZE (20 * 40)
|
|||
|
|
|||
|
#define RC_FILTER_SIZE 40
|
|||
|
|
|||
|
void find_data_rot(int *data_ptr, int *rot_ptr, int x0, int y0)
|
|||
|
{
|
|||
|
int xx,yy,data,rot,x,y;
|
|||
|
|
|||
|
/* find the data & rotation */
|
|||
|
for(data=0;data<4;data++) {
|
|||
|
x = -3 + (data & 1) * 4;
|
|||
|
y = -3 + (data >> 1) * 4;
|
|||
|
for(rot=0;rot<4;rot++) {
|
|||
|
if (x == x0 && y == y0) {
|
|||
|
*data_ptr = data;
|
|||
|
*rot_ptr = rot;
|
|||
|
return;
|
|||
|
}
|
|||
|
/* rotate by 90 */
|
|||
|
xx = y;
|
|||
|
yy = -x;
|
|||
|
x = xx;
|
|||
|
y = yy;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/* 0 : rotation by 180, 1 = rotation by 90 */
|
|||
|
int classify(int x[2][2])
|
|||
|
{
|
|||
|
int x0, y0, x1, y1,d0,d1,r0,r1;
|
|||
|
|
|||
|
x0 = 2 * x[0][0] - 3;
|
|||
|
y0 = 2 * x[0][1] - 3;
|
|||
|
x1 = 2 * x[1][0] - 3;
|
|||
|
y1 = 2 * x[1][1] - 3;
|
|||
|
|
|||
|
find_data_rot(&d0,&r0,x0,y0);
|
|||
|
find_data_rot(&d1,&r1,x1,y1);
|
|||
|
if (((r0 - r1) & 1) == 0)
|
|||
|
return 0;
|
|||
|
else
|
|||
|
return 1;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
void gen_table(int nb_trans)
|
|||
|
{
|
|||
|
int Y[5],Yt[5], trans, ss[2][3], xx[2][2];
|
|||
|
int res, i, y0;
|
|||
|
|
|||
|
printf("u8 trellis_trans_%d[256][4] = {\n",
|
|||
|
nb_trans);
|
|||
|
|
|||
|
for(y0=0;y0<2;y0++) {
|
|||
|
|
|||
|
for(trans=0;trans<nb_trans;trans++) {
|
|||
|
printf(" /* trans=%d y0=%d */\n", trans, y0);
|
|||
|
Yt[1] = trans & 1;
|
|||
|
Yt[2] = (trans >> 1) & 1;
|
|||
|
Yt[4] = (trans >> 2) & 1;
|
|||
|
Yt[3] = (trans >> 3) & 1;
|
|||
|
|
|||
|
for(xx[0][0] = 0; xx[0][0] < 4; xx[0][0]++)
|
|||
|
for(xx[0][1] = 0; xx[0][1] < 4; xx[0][1]++)
|
|||
|
for(xx[1][0] = 0; xx[1][0] < 4; xx[1][0]++)
|
|||
|
for(xx[1][1] = 0; xx[1][1] < 4; xx[1][1]++) {
|
|||
|
|
|||
|
/* (<28> 9.6.3.1) find Y vector. We traducted the table into binary expressions */
|
|||
|
for(i=0;i<2;i++) {
|
|||
|
int x,y,y0,x0,y1,x1;
|
|||
|
|
|||
|
/* XXX: is it right to suppose that we use figure 9 as a periodic mapping ? */
|
|||
|
x = xx[i][0];
|
|||
|
y = xx[i][1];
|
|||
|
|
|||
|
x0 = x & 1;
|
|||
|
x1 = ((x & 2) >> 1);
|
|||
|
y0 = y & 1;
|
|||
|
y1 = ((y & 2) >> 1);
|
|||
|
|
|||
|
ss[i][2] = x1 ^ y1 ^ y0 ^ x0;
|
|||
|
ss[i][1] = y0;
|
|||
|
ss[i][0] = y0 ^ x0;
|
|||
|
}
|
|||
|
|
|||
|
/* table 13 traducted into binary operations */
|
|||
|
Y[4] = ss[0][2] ^ ss[1][2];
|
|||
|
Y[3] = ss[0][1];
|
|||
|
Y[2] = ss[0][0];
|
|||
|
Y[1] = (ss[0][0] & ~ss[1][0] & 1) ^ ss[0][1] ^ ss[1][1];
|
|||
|
|
|||
|
res = 0;
|
|||
|
switch(nb_trans) {
|
|||
|
case 4:
|
|||
|
res = (Yt[1] == Y[1] &&
|
|||
|
Yt[2] == Y[2]);
|
|||
|
break;
|
|||
|
case 8:
|
|||
|
res = (Yt[1] == Y[1] &&
|
|||
|
Yt[2] == Y[2] &&
|
|||
|
Yt[4] == Y[4]);
|
|||
|
break;
|
|||
|
case 16:
|
|||
|
res = (Yt[1] == Y[1] &&
|
|||
|
Yt[2] == Y[2] &&
|
|||
|
Yt[3] == Y[3] &&
|
|||
|
Yt[4] == Y[4]);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (res && classify(xx) == y0) {
|
|||
|
printf(" { %d, %d, %d, %d },\n",
|
|||
|
xx[0][0],
|
|||
|
xx[0][1],
|
|||
|
xx[1][0],
|
|||
|
xx[1][1]);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
printf("};\n");
|
|||
|
}
|
|||
|
|
|||
|
static u8 S_tab[6][8] = {
|
|||
|
/* a, c, d1, e1, d2, e2, J, P */
|
|||
|
{ 1, 1, 2, 3, 3, 4, 7, 12, }, /* S=2400 */
|
|||
|
{ 8, 7, 3, 5, 2, 3, 8, 12, }, /* S=2743 */
|
|||
|
{ 7, 6, 3, 5, 2, 3, 7, 14, }, /* S=2800 */
|
|||
|
{ 5, 4, 3, 5, 2, 3, 7, 15, }, /* S=3000 */
|
|||
|
{ 4, 3, 4, 7, 3, 5, 7, 16, }, /* S=3200 */
|
|||
|
{10, 7, 4, 7, 4, 7, 8, 15, }, /* S=3429 */
|
|||
|
};
|
|||
|
|
|||
|
/* this table depends on the sample rate. We have S=a1/c1 * V34_SAMPLE_RATE */
|
|||
|
static u8 baud_tab[6][2] = {
|
|||
|
/* a1, c1 */
|
|||
|
{ 3, 10 },
|
|||
|
{ 12, 35 },
|
|||
|
{ 7, 20 },
|
|||
|
{ 3, 8 },
|
|||
|
{ 2, 5 },
|
|||
|
{ 3, 7 },
|
|||
|
};
|
|||
|
|
|||
|
#define FFT_SIZE 2048
|
|||
|
|
|||
|
/* build a square raised cosine nyquist filter of n coefficients
|
|||
|
centered on f0, with coefficients alpha and beta.
|
|||
|
*/
|
|||
|
|
|||
|
void build_sqr_nyquist_filter(float *filter,
|
|||
|
float f0, float alpha, float beta, int n)
|
|||
|
{
|
|||
|
float f, f1, f2, val, tau, norm;
|
|||
|
int i,j;
|
|||
|
complex tab[FFT_SIZE];
|
|||
|
|
|||
|
f1 = (1.0 - beta) * alpha;
|
|||
|
f2 = (1.0 + beta) * alpha;
|
|||
|
tau = 0.5 / alpha;
|
|||
|
norm = tau / sqrt(FFT_SIZE);
|
|||
|
if (f0 != 0)
|
|||
|
norm *= 0.5;
|
|||
|
|
|||
|
for(i=0;i<=FFT_SIZE/2;i++) {
|
|||
|
f = i / (float)FFT_SIZE;
|
|||
|
|
|||
|
/* center on f0 */
|
|||
|
f = fabs(f - f0);
|
|||
|
|
|||
|
if (f <= f1)
|
|||
|
val = 1;
|
|||
|
else if (f <= f2) {
|
|||
|
val = 0.5 * (1.0 + cos((M_PI * tau / beta) * (f - f1)));
|
|||
|
} else {
|
|||
|
val = 0;
|
|||
|
}
|
|||
|
val = sqrt(val);
|
|||
|
|
|||
|
tab[i].re = val * norm;
|
|||
|
tab[i].im = 0;
|
|||
|
}
|
|||
|
|
|||
|
for(i=1;i<FFT_SIZE;i++) tab[FFT_SIZE - i] = tab[i];
|
|||
|
|
|||
|
fft_calc(tab, FFT_SIZE, 0);
|
|||
|
|
|||
|
j = FFT_SIZE - ((n-1)/2);
|
|||
|
for(i=0;i<n;i++) {
|
|||
|
filter[i] = tab[j].re;
|
|||
|
if (++j == FFT_SIZE)
|
|||
|
j = 0;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void write_filter(char *name, float *filter, int n)
|
|||
|
{
|
|||
|
int i;
|
|||
|
|
|||
|
printf("s16 %s[%d]=\n{\n",
|
|||
|
name, n);
|
|||
|
for(i=0;i<n;i++) {
|
|||
|
printf("%6d, ", (int)(filter[i] * 0x4000));
|
|||
|
if ((i % 8) == 7)
|
|||
|
printf("\n");
|
|||
|
}
|
|||
|
printf("\n};\n");
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
int main(int argc, char **argv)
|
|||
|
{
|
|||
|
int i, j, n;
|
|||
|
float filter[FFT_SIZE];
|
|||
|
char buf[512];
|
|||
|
|
|||
|
printf("/* THIS SOURCE CODE IS AUTOMATICALLY GENERATED - DO NOT MODIFY */\n");
|
|||
|
printf("/*\n"
|
|||
|
" * V34 tables\n"
|
|||
|
" * \n"
|
|||
|
" * Copyright (c) 1999,2000 Fabrice Bellard.\n"
|
|||
|
" *\n"
|
|||
|
" * This code is released under the GNU General Public License version\n"
|
|||
|
" * 2. Please read the file COPYING to know the exact terms of the\n"
|
|||
|
" * license.\n"
|
|||
|
" */\n");
|
|||
|
|
|||
|
printf("#include \"lm.h\"\n"
|
|||
|
"#include \"v34priv.h\"\n"
|
|||
|
"\n");
|
|||
|
|
|||
|
/* tables for trellis coded modulation */
|
|||
|
gen_table(4);
|
|||
|
gen_table(8);
|
|||
|
gen_table(16);
|
|||
|
|
|||
|
/* rx filters which convert the 8000 Hz flow to (symbol_rate * 3)
|
|||
|
with a nyquist filter */
|
|||
|
|
|||
|
for(j=0;j<6;j++) {
|
|||
|
float symbol_rate, carrier, alpha, beta, freq;
|
|||
|
|
|||
|
symbol_rate = 2400.0 *
|
|||
|
(float)S_tab[j][0] / (float)S_tab[j][1];
|
|||
|
|
|||
|
for(i=0;i<2;i++) {
|
|||
|
if (i == 1 &&
|
|||
|
S_tab[j][2] == S_tab[j][4] &&
|
|||
|
S_tab[j][3] == S_tab[j][5])
|
|||
|
break;
|
|||
|
|
|||
|
carrier = symbol_rate *
|
|||
|
(float)S_tab[j][2 + 2*i] / (float)S_tab[j][3 + 2*i];
|
|||
|
|
|||
|
alpha = symbol_rate / (2.0 * symbol_rate * 3.0 * baud_tab[j][1]);
|
|||
|
beta = 0.1;
|
|||
|
freq = carrier / (symbol_rate * 3.0 * baud_tab[j][1]);
|
|||
|
n = RC_FILTER_SIZE * baud_tab[j][1] + 1;
|
|||
|
|
|||
|
printf("/* S=%d carrier=%d alpha=%f beta=%f f0=%f */\n",
|
|||
|
(int)rint(symbol_rate),
|
|||
|
(int)rint(carrier),
|
|||
|
alpha, beta, freq);
|
|||
|
|
|||
|
build_sqr_nyquist_filter(filter, freq, alpha, beta, n);
|
|||
|
|
|||
|
sprintf(buf, "v34_rx_filter_%d_%d",
|
|||
|
(int)rint(symbol_rate),
|
|||
|
(int)rint(carrier));
|
|||
|
|
|||
|
write_filter(buf, filter, n);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* tx filters */
|
|||
|
|
|||
|
for(j=0;j<6;j++) {
|
|||
|
float alpha, beta;
|
|||
|
|
|||
|
alpha = 1.0 / (2.0 * baud_tab[j][1]);
|
|||
|
beta = 0.1;
|
|||
|
n = RC_FILTER_SIZE * baud_tab[j][1] + 1;
|
|||
|
|
|||
|
build_sqr_nyquist_filter(filter, 0.0, alpha, beta, n);
|
|||
|
|
|||
|
sprintf(buf, "v34_rc_%d_filter", baud_tab[j][1]);
|
|||
|
write_filter(buf, filter, n);
|
|||
|
}
|
|||
|
|
|||
|
/* V22 filters */
|
|||
|
|
|||
|
/* 600 sym/s for 8000 Hz, beta=0.75 */
|
|||
|
build_sqr_nyquist_filter(filter, 0.0, 1.0 / (2.0 * 40.0), 0.75,
|
|||
|
V22_TX_FILTER_SIZE);
|
|||
|
|
|||
|
write_filter("v22_tx_filter", filter, V22_TX_FILTER_SIZE);
|
|||
|
|
|||
|
return 0;
|
|||
|
}
|