~ubuntu-branches/debian/sid/acfax/sid

« back to all changes in this revision

Viewing changes to mod_demod.c

  • Committer: Bazaar Package Importer
  • Author(s): Hamish Moffatt
  • Date: 2001-12-27 12:07:46 UTC
  • Revision ID: james.westby@ubuntu.com-20011227120746-iz2p5k757bcla8ov
Tags: upstream-981011
ImportĀ upstreamĀ versionĀ 981011

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    ACfax - Fax reception with X11-interface for amateur radio
 
3
    Copyright (C) 1995-1998 Andreas Czechanowski, DL4SDC
 
4
 
 
5
    This program is free software; you can redistribute it and/or modify
 
6
    it under the terms of the GNU General Public License as published by
 
7
    the Free Software Foundation; either version 2 of the License, or
 
8
    (at your option) any later version.
 
9
 
 
10
    This program is distributed in the hope that it will be useful,
 
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
    GNU General Public License for more details.
 
14
 
 
15
    You should have received a copy of the GNU General Public License
 
16
    along with this program; if not, write to the Free Software Foundation,
 
17
    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
18
 
 
19
    andreas.czechanowski@ins.uni-stuttgart.de
 
20
*/
 
21
    
 
22
/*
 
23
 * mod_demod.c - FM and AM modulator/demodulator for ACfax
 
24
 */
 
25
 
 
26
#include <stdio.h>
 
27
#include <stdlib.h>
 
28
#include <math.h>
 
29
#include <unistd.h>
 
30
#include "mod_demod.h"
 
31
 
 
32
SHORT int firwide[] = {  6,   20,   7, -42, -74, -12, 159, 353, 440 };
 
33
SHORT int firmiddle[] = {   0, -18, -38, -39,   0,  83, 191, 284, 320 };
 
34
SHORT int firnarrow[] = {  -7, -18, -15,  11,  56, 116, 177, 223, 240 };
 
35
 
 
36
/* these some more coefficient tables were for testing only. */
 
37
/* int firwide[] = {  12,  24,   7, -42, -74, -12, 159, 353, 440 }; */
 
38
/* int firnarrow[] = { -16, -21, -15,  11,  56, 116, 177, 223, 240 }; */
 
39
/* int fircheap[] = { 0, 0, 0, 0, 0, 0, 36, 99, 128 }; */
 
40
/* int firtoobig[] = { -14, -12, 18, 40, -1, -80, -71, 114, 381, 510 } */
 
41
/* int firnotbad[] = { 11, 16, 1, -29, -44, -3, 98, 208, 256 }; */
 
42
 
 
43
static SHORT int *fcoeff = firmiddle;
 
44
static int *sqrt_lo;    /* square-root lookup-table for AM demodulator */
 
45
static int *sqrt_hi;    /* (splitted in 2 parts) */
 
46
static int *sintab;     /* sine wave table for FM modulator */
 
47
static int *asntab;     /* arcsin-table for FM-demodulator */
 
48
static int *fmphsinc;   /* phase-increment-table for FM modulator */
 
49
static char *amreal;    /* amplitude tables for AM modulator */
 
50
static int compval;     /* comparator value for APT detecion */
 
51
 
 
52
/*
 
53
void main(int argc, char **argv)
 
54
{
 
55
  char indata[2048];
 
56
  int  outdata[1024];
 
57
  int  q;
 
58
 
 
59
  modem_init();
 
60
  set_modem_param (FIL_MIDL, 255, 400);
 
61
  while ((q = fread(indata, 1, 2048, stdin)) > 0) {
 
62
    q &= 0xfffe;
 
63
    fm_demod(indata, q, outdata);
 
64
  }
 
65
}
 
66
*/
 
67
 
 
68
/* Initialize the modulator/demodulator functions. This function allocates
 
69
   space for the arrays and lookup-tables
 
70
*/
 
71
 
 
72
void modem_init(void)
 
73
{
 
74
  int i;
 
75
  static int inited = 0;
 
76
 
 
77
  if (inited) return;
 
78
 
 
79
  sqrt_lo = (int *)malloc(2048*sizeof(int));
 
80
  sqrt_hi = (int *)malloc(2048*sizeof(int));
 
81
  if (!(sqrt_lo) || !(sqrt_hi)) {
 
82
    perror("modem_init:sqrt_*");
 
83
    exit(1);
 
84
  }
 
85
  amreal = (char *)malloc(258);
 
86
  if (!(amreal)) {
 
87
    perror("modem_init:am{real|imag}");
 
88
    exit(1);
 
89
  }
 
90
  sintab = (int *)malloc(1024*sizeof(int));
 
91
  if (!(sintab)) {
 
92
    perror("modem_init:sintab");
 
93
    exit(1);
 
94
  }
 
95
  asntab = (int *)malloc(512*sizeof(int));
 
96
  if (!(asntab)) {
 
97
    perror("modem_init:asntab");
 
98
    exit(1);
 
99
  }
 
100
  fmphsinc = (int *)malloc(258*sizeof(int));
 
101
  for (i=0; i<1024; i++)
 
102
    sintab[i] = 127.5 + 127*sin(i*PI/512.0); 
 
103
 
 
104
  inited = -1;
 
105
}
 
106
 
 
107
/* set up a lookup-table for the given deviation which gives values from
 
108
   0 to maxval with clipping beyond the edges for reception, initialize
 
109
   a lookup-table for FM transmission.
 
110
*/
 
111
void set_modem_param(int filter, int maxval, int devi)
 
112
{
 
113
  int phmax;
 
114
  int i;
 
115
 
 
116
  /* initialize decoder first, if not already done */
 
117
  modem_init();
 
118
  /* do some range-checking */
 
119
  if (devi < 100) devi = 100;
 
120
  if (devi > 1200) devi = 1200;
 
121
  if (maxval < 1) maxval = 1;
 
122
  if (maxval > 255) maxval = 255;
 
123
  phmax = 255.9 * sin(devi * PI / 4000.0) + 0.5;
 
124
  for (i=0; i<512; i++) {
 
125
    if (i <= 256-phmax)
 
126
      asntab[i] = 0;
 
127
    else if (i >= 256+phmax)
 
128
      asntab[i] = maxval;
 
129
    else
 
130
      asntab[i] = maxval * 2000 / devi * asin((i-256.0)/256.5) / PI
 
131
                + maxval/ 2;
 
132
  }
 
133
  for (i=0; i<2048; i++) {
 
134
    sqrt_lo[i] = (sqrt(i) * maxval / 256.0) + 0.5;
 
135
    sqrt_hi[i] = (sqrt(32*i) * maxval / 256.0) + 0.5;
 
136
  }
 
137
  for (i=0; i<=maxval; i++)
 
138
    fmphsinc[i] = devi / 2000.0 * 65536;
 
139
  for (i=0; i<= maxval; i++)
 
140
    amreal[i] = 127.5 + 127.5*i/maxval;
 
141
  compval = maxval >> 1;
 
142
  switch (filter) {
 
143
    case FIL_NARR:
 
144
      fcoeff = firnarrow;
 
145
      fprintf(stderr, "selecting narrow filter\n");
 
146
      break;
 
147
    case FIL_MIDL:
 
148
      fcoeff = firmiddle;
 
149
      fprintf(stderr, "selecting middle filter\n");
 
150
      break;
 
151
    case FIL_WIDE:
 
152
      fcoeff = firwide;
 
153
      fprintf(stderr, "selecting wide filter\n");
 
154
      break;
 
155
  }
 
156
}
 
157
 
 
158
/* Demodulate the samples taken with 8kHz to a frequency sampled with 4kHz.
 
159
   This is done with a delay-demodulator :
 
160
 
 
161
               +----------+  +-------+     +----+  +---+
 
162
            +->|*sin(2kHz)|->|FIR-LPF|--*->|z^-1|->|mul|--+
 
163
            |  +----------+  +-------+  |  +----+  +---+  |
 
164
            |                           *-->--     /      |     AM^2
 
165
            |                           |     \   /       |+     |
 
166
            |                      +---------+ \ /      +---+  +---+
 
167
   <input>--+               AM^2<--|amp^2 det|  X       |add|->|div|--<FM-out>
 
168
            |                      +---------+ / \      +---+  +---+
 
169
            |                           |     /   \       |-
 
170
            |                           *-->--     \      |
 
171
            |  +----------+  +-------+  |  +----+  +---+  |
 
172
            +->|*cos(2kHz)|->|FIR-LPF|--*->|z^-1|->|mul|--+
 
173
               +----------+  +-------+     +----+  +---+
 
174
 
 
175
   The cosine-signal is simply a sequence of 1,0,-1,0 , and the sine-
 
176
   signal is a sequence of 0,1,0,-1 values because the frequency of
 
177
   these is exactly a fouth of the sample-rate. The values multiplied by
 
178
   zero need not be evaluated by  the FIR-filter, what reduces the
 
179
   calculation-effort to one half. Taps of the FIR-chain which are to
 
180
   be multiplied with the same coefficient (possible due to the
 
181
   symmetry of the pulse-response) are first added or subtracted,
 
182
   so again reducing the number of multiplications to one half.
 
183
 
 
184
   NOTE: incnt must be a multiple of 2 to operate properly !
 
185
         output range is determined by asntab, which is set up by
 
186
         set_modem_param. This table also performs the arcsin-correction
 
187
         and clips values that are beyond the given deviation.
 
188
*/
 
189
void fm_demod(char *smplin, int incnt, char *decout)
 
190
{
 
191
  static SHORT int firbuf[32];  /* buffer holding the input-values */
 
192
/*  static int inptr = 0;       / pointer for data-entry into firbuf */
 
193
/*  static int rdptr = 0;       / pointer for data-output from firbuf */
 
194
  static int neg = 0;           /* flag changing every 2 sample-points */
 
195
  static int px, py, qx, qy;    /* the filtered output-results */
 
196
  static int pamp, qamp, pfrq, qfrq;
 
197
/*
 
198
  static int n = 0;
 
199
  int smplptr = 0;
 
200
*/
 
201
 
 
202
  while (incnt >= 2) {
 
203
 
 
204
    /* shift buffer "left" by 2 : copy firbuf[2..17] to firbuf[0..15] */
 
205
    memcpy(firbuf, firbuf+2, (16*sizeof(int)));
 
206
    /* enter 2 new samle-points into buffer */
 
207
    firbuf[16] = *(unsigned char *)smplin++ - 128;
 
208
    firbuf[17] = *(unsigned char *)smplin++ - 128;
 
209
    incnt -= 2;
 
210
    
 
211
    /* do the first quarter : multiply with +0-0+0-0+0-0+0-0+ for px
 
212
       and 0-0+0-0+0-0+0-0+0 for py.
 
213
       2 sample-periodes later, multiply with 0-0+0 for px and -0+0- for py,
 
214
       what is done using the neg variable as flag. In this case, the result
 
215
       for frequency is negated (amplitude is always positive) */
 
216
    px =  (firbuf[0] + firbuf[16]) * fcoeff[0];
 
217
    px -= (firbuf[2] + firbuf[14]) * fcoeff[2];
 
218
    px += (firbuf[4] + firbuf[12]) * fcoeff[4];
 
219
    px -= (firbuf[6] + firbuf[10]) * fcoeff[6];
 
220
    px += (firbuf[8]) * fcoeff[8];
 
221
    px >>= 2;
 
222
    py =  (firbuf[15] - firbuf[1])  * fcoeff[1];
 
223
    py += (firbuf[3]  - firbuf[13]) * fcoeff[3];
 
224
    py += (firbuf[11] - firbuf[5])  * fcoeff[5];
 
225
    py += (firbuf[7]  - firbuf[9])  * fcoeff[7];
 
226
    py >>= 2;
 
227
/*
 
228
    dfft->src[smplptr].r = (neg) ? -px : px;
 
229
    dfft->src[smplptr].i = 0;
 
230
    smplptr++;
 
231
*/
 
232
/*    rdptr = (rdptr+1) & 31; */
 
233
    pamp = ((px*px + py*py) >> 8) + 1;
 
234
    pfrq = (px*qy - py*qx) / (pamp + qamp);
 
235
 
 
236
    /* do the second quarter : multiply with 0-0+0-0+0-0+0-0+0 for px,
 
237
       -0+0-0+0-0+0-0+0- for py */
 
238
    qx =  (firbuf[15+1] - firbuf[1+1])  * fcoeff[1];
 
239
    qx += (firbuf[3+1]  - firbuf[13+1]) * fcoeff[3];
 
240
    qx += (firbuf[11+1] - firbuf[5+1])  * fcoeff[5];
 
241
    qx += (firbuf[7+1]  - firbuf[9+1])  * fcoeff[7];
 
242
    qx >>= 2;
 
243
    qy = -(firbuf[0+1] + firbuf[16+1]) * fcoeff[0];
 
244
    qy += (firbuf[2+1] + firbuf[14+1]) * fcoeff[2];
 
245
    qy -= (firbuf[4+1] + firbuf[12+1]) * fcoeff[4];
 
246
    qy += (firbuf[6+1] + firbuf[10+1]) * fcoeff[6];
 
247
    qy -= (firbuf[8+1]) * fcoeff[8]; 
 
248
    qy >>= 2;
 
249
/*
 
250
    dfft->src[smplptr].r = (neg) ? -qx : qx;
 
251
    dfft->src[smplptr].i = 0;
 
252
    smplptr++;
 
253
*/
 
254
/*    rdptr = (rdptr+1) & 31; */
 
255
    qamp = ((qx*qx + qy*qy) >> 8) + 1;
 
256
    qfrq = (px*qy - py*qx) / (qamp + pamp);
 
257
 
 
258
    /* asntab gives values from minval to maxval for given deviation */
 
259
    *decout = (unsigned char)asntab[(pfrq+qfrq+256) & 511];
 
260
/*
 
261
    printf("%3d %5d %5d\n", n, (px*qy)/1024, (py*qx)/1024);
 
262
    printf("%3d %5d %5d\n", n, *decout, pamp+qamp);
 
263
    n++;
 
264
*/
 
265
    decout++;
 
266
    neg = ~neg;
 
267
  }
 
268
/*
 
269
  do_dfft(dfft);
 
270
  for (smplptr=0; smplptr<1024; smplptr++) {
 
271
    dx = dfft->dest[smplptr].r;
 
272
    dy = dfft->dest[smplptr].i;
 
273
    printf("%4.1f %3.1f\n", smplptr * 3.906, 20*log10(sqrt(dx*dx + dy*dy))); 
 
274
  }
 
275
*/
 
276
}
 
277
 
 
278
 
 
279
/* Demodulate the samples taken with 9.6kHz to an amplitude sampled with 4.8kHz.
 
280
   This done with a synchronous demodulator :
 
281
 
 
282
               +------------+  +-------+  +------+
 
283
            +->|*sin(2.4kHz)|->|FIR-LPF|->|square|-+
 
284
            |  +------------+  +-------+  +------+ |
 
285
            |                                      |
 
286
            |                                      |
 
287
            |                                   +-----+  +-------+
 
288
   <input>--+                                   |adder|->|sq.root|--<AM-out>
 
289
            |                                   +-----+  +-------+
 
290
            |                                      |
 
291
            |                                      |
 
292
            |  +------------+  +-------+  +------+ |
 
293
            +->|*cos(2.4kHz)|->|FIR-LPF|->|square|-+ 
 
294
               +------------+  +-------+  +------+
 
295
 
 
296
   The cosine-signal is simply a sequence of 1,0,-1,0 , and the sine-
 
297
   signal is a sequence of 0,1,0,-1 values because the frequency of
 
298
   these is exactly a fouth of the sample-rate. The values multiplied by
 
299
   zero need not be evaluated by  the FIR-filter, what reduces the
 
300
   calculation-effort to one half.
 
301
 
 
302
   NOTE: incnt must be a multiple of 2 to operate properly !
 
303
         output range is determined by sqrt_lo and sqrt_hi, which
 
304
         are set up by set_modem_param.
 
305
*/
 
306
void am_demod(char *smplin, int incnt, char *decout)
 
307
{
 
308
  static SHORT int firbuf[32];  /* buffer holding the input-values */
 
309
/*  static int inptr = 0;       / pointer for data-entry into firbuf */
 
310
/*  static int rdptr = 0;       / pointer for data-output from firbuf */
 
311
  static int neg = 0;           /* flag changing every 2 sample-points */
 
312
  static int px, py, qx, qy;    /* the filtered output-results */
 
313
  static int pamp, qamp;
 
314
/*
 
315
  static int n = 0;
 
316
  int smplptr = 0;
 
317
*/
 
318
 
 
319
  while (incnt >= 2) {
 
320
 
 
321
    /* shift buffer "left" by 2 : copy firbuf[2..17] to firbuf[0..15] */
 
322
    memcpy(firbuf, firbuf+2, (16*sizeof(int)));
 
323
    /* enter 2 new samle-points into buffer */
 
324
    firbuf[16] = *(unsigned char *)smplin++ - 128;
 
325
    firbuf[17] = *(unsigned char *)smplin++ - 128;
 
326
    incnt -= 2;
 
327
    
 
328
    /* do the first quarter : multiply with +0-0+0-0+0-0+0-0+ for px
 
329
       and 0-0+0-0+0-0+0-0+0 for py.
 
330
       2 sample-periodes later, multiply with 0-0+0 for px and -0+0- for py,
 
331
       what is done using the neg variable as flag. In this case, the result
 
332
       for frequency is negated (amplitude is always positive) */
 
333
    px =  (firbuf[0] + firbuf[16]) * fcoeff[0];
 
334
    px -= (firbuf[2] + firbuf[14]) * fcoeff[2];
 
335
    px += (firbuf[4] + firbuf[12]) * fcoeff[4];
 
336
    px -= (firbuf[6] + firbuf[10]) * fcoeff[6];
 
337
    px += firbuf[8] * fcoeff[8];
 
338
    px >>= 2;
 
339
    py =  (firbuf[15] - firbuf[1])  * fcoeff[1];
 
340
    py += (firbuf[3]  - firbuf[13]) * fcoeff[3];
 
341
    py += (firbuf[11] - firbuf[5])  * fcoeff[5];
 
342
    py += (firbuf[7]  - firbuf[9])  * fcoeff[7];
 
343
    py >>= 2;
 
344
/*
 
345
    dfft->src[smplptr].r = (neg) ? -px : px;
 
346
    dfft->src[smplptr].i = 0;
 
347
    smplptr++;
 
348
*/
 
349
/*    rdptr = (rdptr+1) & 31; */
 
350
    pamp = (px*px + py*py);
 
351
 
 
352
    /* do the second quarter : multiply with 0-0+0-0+0-0+0-0+0 for px,
 
353
       -0+0-0+0-0+0-0+0- for py */
 
354
    qx =  (firbuf[15+1] - firbuf[1+1])  * fcoeff[1];
 
355
    qx += (firbuf[3+1]  - firbuf[13+1]) * fcoeff[3];
 
356
    qx += (firbuf[11+1] - firbuf[5+1])  * fcoeff[5];
 
357
    qx += (firbuf[7+1]  - firbuf[9+1])  * fcoeff[7];
 
358
    qx >>= 2;
 
359
    qy = -(firbuf[0+1] + firbuf[16+1]) * fcoeff[0];
 
360
    qy += (firbuf[2+1] + firbuf[14+1]) * fcoeff[2];
 
361
    qy -= (firbuf[4+1] + firbuf[12+1]) * fcoeff[4];
 
362
    qy += (firbuf[6+1] + firbuf[10+1]) * fcoeff[6];
 
363
    qy -= firbuf[8+1] * fcoeff[8]; 
 
364
    qy >>= 2;
 
365
/*
 
366
    dfft->src[smplptr].r = (neg) ? -qx : qx;
 
367
    dfft->src[smplptr].i = 0;
 
368
    smplptr++;
 
369
*/
 
370
/*    rdptr = (rdptr+1) & 31; */
 
371
    qamp = (qx*qx + qy*qy + pamp) / 6400;
 
372
 
 
373
    if (qamp >= 65535)
 
374
      *decout = sqrt_hi[2047];
 
375
    else if (qamp >= 2047)
 
376
      *decout = (unsigned char)sqrt_hi[qamp >> 5];
 
377
    else
 
378
      *decout = (unsigned char)sqrt_lo[qamp];
 
379
 
 
380
/*
 
381
    printf("%3d %5d %5d\n", n, (px*px)/1024, (py*py)/1024);
 
382
    printf("%3d %5d %5d\n", n, *decout, qamp);
 
383
    n++;
 
384
*/
 
385
    decout++;
 
386
    neg = ~neg;
 
387
  }
 
388
}
 
389
 
 
390
/* Encode a frequency sampled at 4kHz to an AF-signal sampled at 8kHz.
 
391
   This is done by shifting the phase by the appropriate value for each
 
392
   sample.
 
393
*/ 
 
394
void fm_modulate(char *codin, int incnt, char *smplout)
 
395
{
 
396
  static int phs = 0;
 
397
 
 
398
  while (incnt-- > 0) {
 
399
    phs += 0x10000 + fmphsinc[*(unsigned char *)codin++];
 
400
    phs &= 0x3ffff;
 
401
    *smplout++ = (char)sintab[phs >> 8];
 
402
    phs += 0x10000 + fmphsinc[*(unsigned char *)codin++];
 
403
    phs &= 0x3ffff;
 
404
    *smplout++ = (char)sintab[phs >> 8];
 
405
  }
 
406
}
 
407
 
 
408
/* Encode an amplitude sampled at 4.8kHz to an AF-signal sampled at 9.6kHz.
 
409
   This is done by multiplying the amplitude-values with a sampled sine-
 
410
   function represented by a 0,1,0,-1 sequence.
 
411
*/
 
412
void am_modulate(char *codin, int incnt, char *smplout)
 
413
{
 
414
  static int neg = 0;
 
415
 
 
416
  while (incnt-- > 0) {
 
417
    if (neg) {
 
418
      *smplout++ = amreal[*(unsigned char *)codin++];
 
419
      *smplout++ = 128; /*amimag[*codin++]*/ 
 
420
    } else {
 
421
      *smplout++ = amreal[*(unsigned char *)codin++] ^ 0xff;
 
422
      *smplout++ = 128; /*amimag[*codin++] ^ 0xff*/
 
423
    }
 
424
    neg = ~neg;
 
425
  }
 
426
}
 
427