Changed FSK demodulator to use s16/7200 at will.

This commit is contained in:
Andreas Beck 1999-07-02 15:02:50 +00:00
parent 93427029cb
commit 21e4f59a95
2 changed files with 111 additions and 27 deletions

View File

@ -1,6 +1,14 @@
Changelog:
----------
99-07-02 [becka]:
* Changes to fsk_demod:
- First parameter at creation now gives samplerate. Allows for
7200 samples/second.
- Changed demodulator to read signed 16 encoded data. Hope that
works.
- Heavily commented it.
99-07-01 [morten]:
* Added new framework for State-machines, see misc/statemachines.c
and G3/fsm.c

View File

@ -2,10 +2,18 @@
******************************************************************************
Fax program for ISDN.
FSK demodulator. Takes alaw data and demodulates it to a stream of
0/1,conf pairs.
FSK demodulator. Takes signed 16 bit data and demodulates it to a
stream of bytes containing 0/1,conf pairs.
conf is a "confidence value" ranging from 0-100% giving you an idea
about how sure the demodulator is about the result. Extended periods
of low confidence usually indicate carrier loss. Short periods are
normal when the transmitted symbol changes. This behaviour can be used
to re-lock PLLs.
We do a s16->alaw conversion here to allow for table lookup.
This is suboptimal as we then do alaw->s16->alaw.
Copyright (C) 1998 Andreas Beck [becka@ggi-project.org]
Copyright (C) 1999 Andreas Beck [becka@ggi-project.org]
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
@ -34,33 +42,50 @@
#include <stdarg.h>
#include <sys/times.h>
#include <ifax/ifax.h>
#include <ifax/alaw.h>
/* Turn on to generate a big bunch of debugging code.
*/
#undef BIGDEBUG
/* Data structures for the fourier analysis.
*/
typedef struct four_help {
int depth,depthsquare,currpos;
int currreal,currimag;
char *histreal,*histimag;
int stpos,ctpos,stdepth;
char *fasttable;
int depth, /* width of the fourier window */
depthsquare, /* square of it. Used for normalizing */
currpos; /* sliding pointer into the history */
int currreal,currimag; /* The current real and imaginary parts of
the fourier transform. */
char *histreal,*histimag;/* History over the window to be able to
remove the coefficients when they
slide out of the window */
int stpos,ctpos,stdepth;/* Offsets for the current sine-position,
the cosine position (shifted by pi/4)
and the depth of the table. */
char *fasttable; /* Lookup table for the multiplication
in the DFT. Directly gives
sin(omega*t)*i(t) */
} four_help;
/* private data of a fsk_demod module.
*/
typedef struct {
four_help freq1,freq2;
int f1,f2;
int baud;
four_help freq1,freq2; /* fourier data for both channels */
int f1,f2; /* frequencies for 1 and 0 */
int baud; /* baudrate - gives fourier window */
int sps; /* samples per second */
} fskdemod_private;
/* Calculate the greatest common divisor. This is used to see when a waveform
* repeats. This optimizes the length of the waveform table.
* Euclidian algorithm.
*/
int gcd(int d1,int d2)
{
/* FIXME ! Is this correct ? Pretty long ago that I did that last time ... */
while(d1!=d2)
{
if (d1>d2) d1-=d2;
@ -73,36 +98,58 @@ int gcd(int d1,int d2)
/* The following do the DFT "on the fly" with a sliding window.
*/
static void init_four_help(four_help *hlp,int depth,int freq)
/* Set up all the tables.
*/
static void init_four_help(fskdemod_private *priv,four_help *hlp,int depth,int freq)
{
int x,y;
char *ftptr;
double sinval;
hlp->depth=depth;
hlp->depthsquare=depth*depth;
hlp->currpos=0;
hlp->currreal=hlp->currimag=0;
hlp->depth=depth; /* window size */
hlp->depthsquare=depth*depth; /* normalizing helper variable */
hlp->currpos=0; /* window initial position. */
hlp->currreal=hlp->currimag=0; /* there is no energy in a zero window */
/* Allocate the history windows and erase them. */
hlp->histreal=malloc(sizeof(hlp->histreal[0])*depth);
hlp->histimag=malloc(sizeof(hlp->histimag[0])*depth);
while(depth--)
hlp->histreal[depth]=
hlp->histimag[depth]=0;
x=gcd(freq,SAMPLES_PER_SECOND);x=SAMPLES_PER_SECOND/x;
/* Calculate size of the sine lookup tables. At worst this is
sps, if they have no common divisor (we have no fractional
rates, so after 1 second we must have a match again).
As this is pretty large like 8000sps*256values=2MB, we try to
optimize by finding the GCD which gives the fraction of seconds
after which the frequency pattern repeats at the samplerate.
*/
x=gcd(freq,priv->sps);x=priv->sps/x;
/* We derive the cosine part by shifting by PI/4. If that doesn't
* compute, we have a slight error. Warn about that. All V.21
* signals at 8000 or 7200 sps will not trigger that case.
*/
if (x%4) {
fprintf(stderr,"fsk_demod: ERROR: sinetable size not divideable by 4.\n"
"Cosine shift is slighty incorrect.\n");
}
/* The table is 256 entries per sample */
hlp->stdepth=256*x;
hlp->stpos=0;
hlp->ctpos=256*(x/4); /* The bracket _IS_ important. Do not optimize. */
/* Allocate and fill the table. The table contains sin(omega*t)*i(t)
* and is accessed by t*256+i(t), where i(t) is assumed to be alaw-
* encoded for better dynamics. Any encoding would do. Just make sure
* you choose the same encoding in add_samp.
*/
hlp->fasttable=malloc(sizeof(hlp->fasttable[0])*hlp->stdepth);
ftptr=hlp->fasttable;
for(x=0;x<hlp->stdepth/256;x++)
{
sinval=sin(x*2.0*M_PI*(double)freq/(double)SAMPLES_PER_SECOND);
sinval=sin(x*2.0*M_PI*(double)freq/(double)priv->sps);
for(y=0;y<256;y++)
*ftptr++=((int)(sinval*alaw2int(y))) >>
((sizeof(int)-sizeof(char))*8);
@ -118,21 +165,39 @@ static void destroy_four_help(four_help *hlp)
free(hlp->fasttable);hlp->fasttable=NULL;
}
inline void add_samp(four_help *hlp,char sample)
/* Slide the DFT window by one sample.
*/
inline void add_samp(four_help *hlp,ifax_sint16 sample)
{
unsigned char mysample;
/* convert sample to alaw for table lookup.
*/
mysample=sint2wala[((unsigned)sample>>4)&0xFFF];
/* remove old sample that slides out of the window.
* We could optimize a little further here by directly storing
* the power instead of the individual values, but I prefer to
* keep the information. We could easily modify this system to
* demodulate a PSK stream this way.
*/
hlp->currreal-=hlp->histreal[hlp->currpos];
hlp->currimag-=hlp->histimag[hlp->currpos];
/* Add and store new samples using the lookup-tables. */
hlp->currreal+=
(hlp->histreal[hlp->currpos]=hlp->fasttable[hlp->stpos+(unsigned char)sample]);
(hlp->histreal[hlp->currpos]=hlp->fasttable[hlp->stpos+(unsigned char)mysample]);
hlp->currimag+=
(hlp->histimag[hlp->currpos]=hlp->fasttable[hlp->ctpos+(unsigned char)sample]);
(hlp->histimag[hlp->currpos]=hlp->fasttable[hlp->ctpos+(unsigned char)mysample]);
/* Slide on the table pointers. */
hlp->currpos++ ;if (hlp->currpos>=hlp->depth ) hlp->currpos=0;
hlp->stpos+=256;if (hlp->stpos >=hlp->stdepth) hlp->stpos=0;
hlp->ctpos+=256;if (hlp->ctpos >=hlp->stdepth) hlp->ctpos=0;
}
/* Destroy the private data.
*/
void fskdemod_destroy(ifax_modp self)
{
fskdemod_private *priv=(fskdemod_private *)self->private;
@ -144,15 +209,20 @@ void fskdemod_destroy(ifax_modp self)
return;
}
/* Module has no commands.
*/
int fskdemod_command(ifax_modp self,int cmd,va_list cmds)
{
return 0; /* Not yet used. */
}
/* Handler - go through the data, slide it into the DFT, give back a 0/1
* decision and a confidence value.
*/
int fskdemod_handle(ifax_modp self, void *data, size_t length)
{
unsigned char dat[2];
char *input=data;
ifax_sint16 *input=data;
int a1,a2,conf,pwr;
int handled=0;
@ -192,6 +262,11 @@ int fskdemod_handle(ifax_modp self, void *data, size_t length)
return handled;
}
/* Constructor. Arguments:
* int samplerate; - rate at which samples come in
* int f1,f2; - frequencies that encode 1 and 0
* int baud; - the baudrate of the transmission. Influences DFT window.
*/
int fskdemod_construct(ifax_modp self,va_list args)
{
fskdemod_private *priv;
@ -203,14 +278,15 @@ int fskdemod_construct(ifax_modp self,va_list args)
self->handle_input =fskdemod_handle;
self->command =fskdemod_command;
priv->sps =va_arg(args,int);
priv->f1 =va_arg(args,int);
priv->f2 =va_arg(args,int);
priv->baud=va_arg(args,int);
sampbaud=(SAMPLES_PER_SECOND+priv->baud)/priv->baud;
sampbaud=(priv->sps+priv->baud)/priv->baud;
init_four_help(&priv->freq1,sampbaud,priv->f1);
init_four_help(&priv->freq2,sampbaud,priv->f2);
init_four_help(priv,&priv->freq1,sampbaud,priv->f1);
init_four_help(priv,&priv->freq2,sampbaud,priv->f2);
return 0;
}