Changed FSK demodulator to use s16/7200 at will.
This commit is contained in:
parent
93427029cb
commit
21e4f59a95
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue