RS-tracker/demod/mod/demod_mod.c

774 wiersze
22 KiB
C
Czysty Zwykły widok Historia

2019-01-31 22:41:06 +00:00
/*
* sync header: correlation/matched filter
* compile:
* gcc -c demod_iq.c
*
* author: zilog80
*/
/* ------------------------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "demod_iq.h"
/* ------------------------------------------------------------------------------------ */
2019-02-20 22:23:57 +00:00
static void raw_dft(dft_t *dft, float complex *Z) {
2019-01-31 22:41:06 +00:00
int s, l, l2, i, j, k;
float complex w1, w2, T;
j = 1;
2019-02-20 22:23:57 +00:00
for (i = 1; i < dft->N; i++) {
2019-01-31 22:41:06 +00:00
if (i < j) {
T = Z[j-1];
Z[j-1] = Z[i-1];
Z[i-1] = T;
}
2019-02-20 22:23:57 +00:00
k = dft->N/2;
2019-01-31 22:41:06 +00:00
while (k < j) {
j = j - k;
k = k/2;
}
j = j + k;
}
2019-02-20 22:23:57 +00:00
for (s = 0; s < dft->LOG2N; s++) {
2019-01-31 22:41:06 +00:00
l2 = 1 << s;
l = l2 << 1;
w1 = (float complex)1.0;
2019-02-20 22:23:57 +00:00
w2 = dft->ew[s]; // cexp(-I*M_PI/(float)l2)
2019-01-31 22:41:06 +00:00
for (j = 1; j <= l2; j++) {
2019-02-20 22:23:57 +00:00
for (i = j; i <= dft->N; i += l) {
2019-01-31 22:41:06 +00:00
k = i + l2;
T = Z[k-1] * w1;
Z[k-1] = Z[i-1] - T;
Z[i-1] = Z[i-1] + T;
}
w1 = w1 * w2;
}
}
}
2019-02-20 22:23:57 +00:00
static void cdft(dft_t *dft, float complex *z, float complex *Z) {
2019-01-31 22:41:06 +00:00
int i;
2019-02-20 22:23:57 +00:00
for (i = 0; i < dft->N; i++) Z[i] = z[i];
raw_dft(dft, Z);
2019-01-31 22:41:06 +00:00
}
2019-02-20 22:23:57 +00:00
static void rdft(dft_t *dft, float *x, float complex *Z) {
2019-01-31 22:41:06 +00:00
int i;
2019-02-20 22:23:57 +00:00
for (i = 0; i < dft->N; i++) Z[i] = (float complex)x[i];
raw_dft(dft, Z);
}
static void Nidft(dft_t *dft, float complex *Z, float complex *z) {
int i;
for (i = 0; i < dft->N; i++) z[i] = conj(Z[i]);
raw_dft(dft, z);
2019-01-31 22:41:06 +00:00
// idft():
2019-02-20 22:23:57 +00:00
// for (i = 0; i < dft->N; i++) z[i] = conj(z[i])/(float)dft->N; // hier: z reell
2019-01-31 22:41:06 +00:00
}
2019-02-20 22:23:57 +00:00
static float bin2freq0(dft_t *dft, int k) {
float fq = dft->sr * k / /*(float)*/dft->N;
if (fq >= dft->sr/2.0) fq -= dft->sr;
return fq;
}
static float bin2freq(dft_t *dft, int k) {
float fq = k / (float)dft->N;
if ( fq >= 0.5) fq -= 1.0;
return fq*dft->sr;
}
static float bin2fq(dft_t *dft, int k) {
float fq = k / (float)dft->N;
if ( fq >= 0.5) fq -= 1.0;
2019-01-31 22:41:06 +00:00
return fq;
}
2019-02-20 22:23:57 +00:00
static int max_bin(dft_t *dft, float complex *Z) {
2019-01-31 22:41:06 +00:00
int k, kmax;
double max;
max = 0; kmax = 0;
2019-02-20 22:23:57 +00:00
for (k = 0; k < dft->N; k++) {
2019-01-31 22:41:06 +00:00
if (cabs(Z[k]) > max) {
max = cabs(Z[k]);
kmax = k;
}
}
return kmax;
}
2019-02-20 22:23:57 +00:00
static int dft_window(dft_t *dft, int w) {
int n;
if (w < 0 || w > 3) return -1;
for (n = 0; n < dft->N2; n++) {
switch (w)
{
case 0: // (boxcar)
dft->win[n] = 1.0;
break;
case 1: // Hann
dft->win[n] = 0.5 * ( 1.0 - cos(2*M_PI*n/(float)(dft->N2-1)) );
break ;
case 2: // Hamming
dft->win[n] = 25/46.0 + (1.0 - 25/46.0)*cos(2*M_PI*n / (float)(dft->N2-1));
break ;
case 3: // Blackmann
dft->win[n] = 7938/18608.0
- 9240/18608.0*cos(2*M_PI*n / (float)(dft->N2-1))
+ 1430/18608.0*cos(4*M_PI*n / (float)(dft->N2-1));
break ;
}
}
while (n < dft->N) dft->win[n++] = 0.0;
return 0;
}
2019-01-31 22:41:06 +00:00
/* ------------------------------------------------------------------------------------ */
2019-03-03 13:30:16 +00:00
int getCorrDFT(dsp_t *dsp, ui32_t pos, float *maxv, ui32_t *maxvpos) {
2019-01-31 22:41:06 +00:00
int i;
int mp = -1;
float mx = 0.0;
2019-03-03 13:30:16 +00:00
float mx2 = 0.0;
float re_cx = 0.0;
2019-01-31 22:41:06 +00:00
float xnorm = 1;
2019-02-20 22:23:57 +00:00
ui32_t mpos = 0;
dsp->dc = 0.0;
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
if (dsp->K + dsp->L > dsp->DFT.N) return -1;
if (dsp->sample_out < dsp->L) return -2;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (pos == 0) pos = dsp->sample_out;
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
dsp->dc = get_bufmu(dsp, pos - dsp->sample_out); //oder unten: dft_dc = creal(X[0])/(K+L);
2019-02-20 22:23:57 +00:00
// wenn richtige Stelle (Varianz pruefen, kein M10-carrier?), dann von bufs[] subtrahieren
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
for (i = 0; i < dsp->K + dsp->L; i++) (dsp->DFT).xn[i] = dsp->bufs[(pos+dsp->M -(dsp->K + dsp->L-1) + i) % dsp->M];
while (i < dsp->DFT.N) (dsp->DFT).xn[i++] = 0.0;
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
rdft(&dsp->DFT, dsp->DFT.xn, dsp->DFT.X);
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
// dft_dc = creal(dsp->DFT.X[0])/dsp->DFT.N;
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
for (i = 0; i < dsp->DFT.N; i++) dsp->DFT.Z[i] = dsp->DFT.X[i]*dsp->DFT.Fm[i];
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
Nidft(&dsp->DFT, dsp->DFT.Z, dsp->DFT.cx);
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
// relativ Peak - Normierung erst zum Schluss;
// dann jedoch nicht zwingend corr-Max wenn FM-Amplitude bzw. norm(x) nicht konstant
// (z.B. rs41 Signal-Pausen). Moeglicherweise wird dann wahres corr-Max in dem
// K-Fenster nicht erkannt, deshalb K nicht zu gross waehlen.
//
mx2 = 0.0; // t = L-1
for (i = dsp->L-1; i < dsp->K + dsp->L; i++) { // i=t .. i=t+K < t+1+K
re_cx = creal(dsp->DFT.cx[i]); // imag(cx)=0
if (re_cx*re_cx > mx2) {
mx = re_cx;
mx2 = mx*mx;
mp = i;
2019-01-31 22:41:06 +00:00
}
}
2019-03-03 13:30:16 +00:00
if (mp == dsp->L-1 || mp == dsp->K + dsp->L-1) return -4; // Randwert
// mp == t mp == K+t
mpos = pos - (dsp->K + dsp->L-1) + mp; // t = L-1
//xnorm = sqrt(dsp->qs[(mpos + 2*dsp->M) % dsp->M]); // Nvar = L
xnorm = 0.0;
for (i = 0; i < dsp->L; i++) xnorm += dsp->bufs[(mpos-i + dsp->M) % dsp->M]*dsp->bufs[(mpos-i + dsp->M) % dsp->M];
xnorm = sqrt(xnorm);
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
mx /= xnorm*(dsp->DFT).N;
2019-01-31 22:41:06 +00:00
*maxv = mx;
*maxvpos = mpos;
2019-02-20 22:23:57 +00:00
if (pos == dsp->sample_out) dsp->buffered = dsp->sample_out - mpos;
2019-01-31 22:41:06 +00:00
return mp;
}
/* ------------------------------------------------------------------------------------ */
static int findstr(char *buff, char *str, int pos) {
int i;
for (i = 0; i < 4; i++) {
if (buff[(pos+i)%4] != str[i]) break;
}
return i;
}
2019-02-20 22:23:57 +00:00
float read_wav_header(pcm_t *pcm, FILE *fp) {
2019-01-31 22:41:06 +00:00
char txt[4+1] = "\0\0\0\0";
unsigned char dat[4];
int byte, p=0;
2019-02-20 22:23:57 +00:00
int sample_rate = 0, bits_sample = 0, channels = 0;
2019-01-31 22:41:06 +00:00
if (fread(txt, 1, 4, fp) < 4) return -1;
if (strncmp(txt, "RIFF", 4)) return -1;
if (fread(txt, 1, 4, fp) < 4) return -1;
// pos_WAVE = 8L
if (fread(txt, 1, 4, fp) < 4) return -1;
if (strncmp(txt, "WAVE", 4)) return -1;
// pos_fmt = 12L
for ( ; ; ) {
if ( (byte=fgetc(fp)) == EOF ) return -1;
txt[p % 4] = byte;
p++; if (p==4) p=0;
if (findstr(txt, "fmt ", p) == 4) break;
}
if (fread(dat, 1, 4, fp) < 4) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
channels = dat[0] + (dat[1] << 8);
if (fread(dat, 1, 4, fp) < 4) return -1;
memcpy(&sample_rate, dat, 4); //sample_rate = dat[0]|(dat[1]<<8)|(dat[2]<<16)|(dat[3]<<24);
if (fread(dat, 1, 4, fp) < 4) return -1;
if (fread(dat, 1, 2, fp) < 2) return -1;
//byte = dat[0] + (dat[1] << 8);
if (fread(dat, 1, 2, fp) < 2) return -1;
bits_sample = dat[0] + (dat[1] << 8);
// pos_dat = 36L + info
for ( ; ; ) {
if ( (byte=fgetc(fp)) == EOF ) return -1;
txt[p % 4] = byte;
p++; if (p==4) p=0;
if (findstr(txt, "data", p) == 4) break;
}
if (fread(dat, 1, 4, fp) < 4) return -1;
fprintf(stderr, "sample_rate: %d\n", sample_rate);
fprintf(stderr, "bits : %d\n", bits_sample);
fprintf(stderr, "channels : %d\n", channels);
2019-02-20 22:23:57 +00:00
if (pcm->sel_ch < 0 || pcm->sel_ch >= channels) pcm->sel_ch = 0; // default channel: 0
fprintf(stderr, "channel-In : %d\n", pcm->sel_ch+1);
2019-01-31 22:41:06 +00:00
if ((bits_sample != 8) && (bits_sample != 16)) return -1;
2019-02-20 22:23:57 +00:00
pcm->sr = sample_rate;
pcm->bps = bits_sample;
pcm->nch = channels;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
return 0;
2019-01-31 22:41:06 +00:00
}
2019-02-20 22:23:57 +00:00
static int f32read_sample(dsp_t *dsp, float *s) {
2019-01-31 22:41:06 +00:00
int i;
short b = 0;
2019-02-20 22:23:57 +00:00
for (i = 0; i < dsp->nch; i++) {
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (fread( &b, dsp->bps/8, 1, dsp->fp) != 1) return EOF;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (i == dsp->ch) { // i = 0: links bzw. mono
2019-01-31 22:41:06 +00:00
//if (bits_sample == 8) sint = b-128; // 8bit: 00..FF, centerpoint 0x80=128
//if (bits_sample == 16) sint = (short)b;
2019-02-20 22:23:57 +00:00
if (dsp->bps == 8) { b -= 128; }
2019-01-31 22:41:06 +00:00
*s = b/128.0;
2019-02-20 22:23:57 +00:00
if (dsp->bps == 16) { *s /= 256.0; }
2019-01-31 22:41:06 +00:00
}
}
return 0;
}
2019-02-20 22:23:57 +00:00
static int f32read_csample(dsp_t *dsp, float complex *z) {
2019-01-31 22:41:06 +00:00
short x = 0, y = 0;
2019-02-20 22:23:57 +00:00
if (fread( &x, dsp->bps/8, 1, dsp->fp) != 1) return EOF;
if (fread( &y, dsp->bps/8, 1, dsp->fp) != 1) return EOF;
2019-01-31 22:41:06 +00:00
*z = x + I*y;
2019-02-20 22:23:57 +00:00
if (dsp->bps == 8) { *z -= 128 + I*128; }
2019-01-31 22:41:06 +00:00
*z /= 128.0;
2019-02-20 22:23:57 +00:00
if (dsp->bps == 16) { *z /= 256.0; }
2019-01-31 22:41:06 +00:00
return 0;
}
2019-02-20 22:23:57 +00:00
float get_bufvar(dsp_t *dsp, int ofs) {
float mu = dsp->xs[(dsp->sample_out+dsp->M + ofs) % dsp->M]/dsp->Nvar;
float var = dsp->qs[(dsp->sample_out+dsp->M + ofs) % dsp->M]/dsp->Nvar - mu*mu;
2019-01-31 22:41:06 +00:00
return var;
}
2019-02-20 22:23:57 +00:00
float get_bufmu(dsp_t *dsp, int ofs) {
float mu = dsp->xs[(dsp->sample_out+dsp->M + ofs) % dsp->M]/dsp->Nvar;
2019-01-31 22:41:06 +00:00
return mu;
}
2019-02-20 22:23:57 +00:00
static int get_SNR(dsp_t *dsp) {
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (dsp->opt_iq)
// if(dsp->rs_typ == RS41)
{
if (dsp->sample_posnoise > 0) // rs41
2019-01-31 22:41:06 +00:00
{
2019-02-20 22:23:57 +00:00
if (dsp->sample_out >= dsp->sample_posframe && dsp->sample_out < dsp->sample_posframe+dsp->len_sq) {
if (dsp->sample_out == dsp->sample_posframe) dsp->V_signal = 0.0;
dsp->V_signal += cabs(dsp->rot_iqbuf[dsp->sample_out % dsp->N_IQBUF]);
2019-01-31 22:41:06 +00:00
}
2019-02-20 22:23:57 +00:00
if (dsp->sample_out == dsp->sample_posframe+dsp->len_sq) dsp->V_signal /= (double)dsp->len_sq;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (dsp->sample_out >= dsp->sample_posnoise && dsp->sample_out < dsp->sample_posnoise+dsp->len_sq) {
if (dsp->sample_out == dsp->sample_posnoise) dsp->V_noise = 0.0;
dsp->V_noise += cabs(dsp->rot_iqbuf[dsp->sample_out % dsp->N_IQBUF]);
2019-01-31 22:41:06 +00:00
}
2019-02-20 22:23:57 +00:00
if (dsp->sample_out == dsp->sample_posnoise+dsp->len_sq) {
dsp->V_noise /= (double)dsp->len_sq;
if (dsp->V_signal > 0 && dsp->V_noise > 0) {
2019-01-31 22:41:06 +00:00
// iq-samples/V [-1..1]
// dBw = 2*dBv, P=c*U*U
// dBw = 2*10*log10(V/V0)
2019-02-20 22:23:57 +00:00
dsp->SNRdB = 20.0 * log10(dsp->V_signal/dsp->V_noise+1e-20);
2019-01-31 22:41:06 +00:00
}
}
}
2019-02-20 22:23:57 +00:00
}
else dsp->SNRdB = 0;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
return 0;
}
int f32buf_sample(dsp_t *dsp, int inv) {
float s = 0.0;
float xneu, xalt;
float complex z, w, z0;
//static float complex z0; //= 1.0;
double gain = 1.0;
double t = dsp->sample_in / (double)dsp->sr;
if (dsp->opt_iq) {
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if ( f32read_csample(dsp, &z) == EOF ) return EOF;
dsp->raw_iqbuf[dsp->sample_in % dsp->N_IQBUF] = z;
z *= cexp(-t*2*M_PI*dsp->df*I);
z0 = dsp->rot_iqbuf[(dsp->sample_in-1 + dsp->N_IQBUF) % dsp->N_IQBUF];
w = z * conj(z0);
s = gain * carg(w)/M_PI;
//z0 = z;
dsp->rot_iqbuf[dsp->sample_in % dsp->N_IQBUF] = z;
get_SNR(dsp);
if (dsp->opt_iq >= 2)
2019-01-31 22:41:06 +00:00
{
double xbit = 0.0;
2019-02-20 22:23:57 +00:00
//float complex xi = cexp(+I*M_PI*dsp->h/dsp->sps);
double f1 = -dsp->h*dsp->sr/(2*dsp->sps);
2019-01-31 22:41:06 +00:00
double f2 = -f1;
float complex X1 = 0;
float complex X2 = 0;
2019-02-20 22:23:57 +00:00
int n = dsp->sps;
2019-01-31 22:41:06 +00:00
while (n > 0) {
n--;
2019-02-20 22:23:57 +00:00
t = -n / (double)dsp->sr;
z = dsp->rot_iqbuf[(dsp->sample_in - n + dsp->N_IQBUF) % dsp->N_IQBUF]; // +1
2019-01-31 22:41:06 +00:00
X1 += z*cexp(-t*2*M_PI*f1*I);
X2 += z*cexp(-t*2*M_PI*f2*I);
}
xbit = cabs(X2) - cabs(X1);
2019-02-20 22:23:57 +00:00
s = xbit / dsp->sps;
2019-01-31 22:41:06 +00:00
}
}
else {
2019-02-20 22:23:57 +00:00
if (f32read_sample(dsp, &s) == EOF) return EOF;
2019-01-31 22:41:06 +00:00
}
if (inv) s = -s; // swap IQ?
2019-02-20 22:23:57 +00:00
dsp->bufs[dsp->sample_in % dsp->M] = s - dsp->dc_ofs;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
xneu = dsp->bufs[(dsp->sample_in ) % dsp->M];
xalt = dsp->bufs[(dsp->sample_in+dsp->M - dsp->Nvar) % dsp->M];
dsp->xsum += xneu - xalt; // + xneu - xalt
dsp->qsum += (xneu - xalt)*(xneu + xalt); // + xneu*xneu - xalt*xalt
dsp->xs[dsp->sample_in % dsp->M] = dsp->xsum;
dsp->qs[dsp->sample_in % dsp->M] = dsp->qsum;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
dsp->sample_out = dsp->sample_in - dsp->delay;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
dsp->sample_in += 1;
2019-01-31 22:41:06 +00:00
return 0;
}
2019-02-20 22:23:57 +00:00
static int read_bufbit(dsp_t *dsp, int symlen, char *bits, ui32_t mvp, int pos) {
2019-01-31 22:41:06 +00:00
// symlen==2: manchester2 0->10,1->01->1: 2.bit
2019-02-20 22:23:57 +00:00
float rbitgrenze = pos*symlen*dsp->sps;
ui32_t rcount = rbitgrenze+0.99; // ceil
2019-01-31 22:41:06 +00:00
double sum = 0.0;
2019-02-20 22:23:57 +00:00
rbitgrenze += dsp->sps;
2019-01-31 22:41:06 +00:00
do {
2019-02-20 22:23:57 +00:00
sum += dsp->bufs[(rcount + mvp + dsp->M) % dsp->M];
2019-01-31 22:41:06 +00:00
rcount++;
2019-02-20 22:23:57 +00:00
} while (rcount < rbitgrenze); // n < dsp->sps
2019-01-31 22:41:06 +00:00
if (symlen == 2) {
2019-02-20 22:23:57 +00:00
rbitgrenze += dsp->sps;
2019-01-31 22:41:06 +00:00
do {
2019-02-20 22:23:57 +00:00
sum -= dsp->bufs[(rcount + mvp + dsp->M) % dsp->M];
2019-01-31 22:41:06 +00:00
rcount++;
2019-02-20 22:23:57 +00:00
} while (rcount < rbitgrenze); // n < dsp->sps
2019-01-31 22:41:06 +00:00
}
if (symlen != 2) {
if (sum >= 0) *bits = '1';
else *bits = '0';
}
else {
if (sum >= 0) strncpy(bits, "10", 2);
else strncpy(bits, "01", 2);
}
return 0;
}
2019-02-20 22:23:57 +00:00
int headcmp(dsp_t *dsp, int symlen, ui32_t mvp, int inv, int option_dc) {
2019-01-31 22:41:06 +00:00
int errs = 0;
int pos;
int step = 1;
char sign = 0;
2019-03-03 13:30:16 +00:00
int len = dsp->hdrlen/symlen;
2019-01-31 22:41:06 +00:00
if (symlen != 1) step = 2;
if (inv) sign=1;
2019-03-03 13:30:16 +00:00
for (pos = 0; pos < len; pos++) { // L = dsp->hdrlen * dsp->sps + 0.5;
//read_bufbit(dsp, symlen, dsp->rawbits+pos*step, mvp+1-(int)(len*dsp->sps), pos);
read_bufbit(dsp, symlen, dsp->rawbits+pos*step, mvp+1-dsp->L, pos);
2019-01-31 22:41:06 +00:00
}
2019-02-20 22:23:57 +00:00
dsp->rawbits[pos] = '\0';
2019-01-31 22:41:06 +00:00
while (len > 0) {
2019-02-20 22:23:57 +00:00
if ((dsp->rawbits[len-1]^sign) != dsp->hdr[len-1]) errs += 1;
2019-01-31 22:41:06 +00:00
len--;
}
if (option_dc && errs < 3) {
2019-02-20 22:23:57 +00:00
dsp->dc_ofs += dsp->dc;
2019-01-31 22:41:06 +00:00
}
return errs;
}
2019-02-20 22:23:57 +00:00
int get_fqofs_rs41(dsp_t *dsp, ui32_t mvp, float *freq, float *snr) {
2019-01-31 22:41:06 +00:00
int j;
int buf_start;
2019-02-13 10:43:36 +00:00
int presamples;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
// if(dsp->rs_typ == RS41_PREAMBLE) ...
if (dsp->opt_iq)
2019-02-13 10:43:36 +00:00
{
2019-02-20 22:23:57 +00:00
presamples = 256*dsp->sps;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (presamples > dsp->DFT.N2) presamples = dsp->DFT.N2;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
buf_start = mvp - dsp->hdrlen*dsp->sps - presamples;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
while (buf_start < 0) buf_start += dsp->N_IQBUF;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
for (j = 0; j < dsp->DFT.N2; j++) {
dsp->DFT.Z[j] = dsp->DFT.win[j]*dsp->raw_iqbuf[(buf_start+j) % dsp->N_IQBUF];
2019-02-13 10:43:36 +00:00
}
2019-02-20 22:23:57 +00:00
while (j < dsp->DFT.N) dsp->DFT.Z[j++] = 0;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
raw_dft(&dsp->DFT, dsp->DFT.Z);
dsp->df = bin2freq(&dsp->DFT, max_bin(&dsp->DFT, dsp->DFT.Z));
2019-01-31 22:41:06 +00:00
2019-02-13 10:43:36 +00:00
// if |df|<eps, +-2400Hz dominant (rs41)
2019-02-20 22:23:57 +00:00
if (fabs(dsp->df) > 1000.0) dsp->df = 0.0;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
dsp->sample_posframe = dsp->sample_in; // > sample_out //mvp - dsp->hdrlen*dsp->sps;
dsp->sample_posnoise = mvp + dsp->sr*7/8.0; // rs41
2019-01-31 22:41:06 +00:00
2019-02-13 10:43:36 +00:00
2019-02-20 22:23:57 +00:00
*freq = dsp->df;
*snr = dsp->SNRdB;
2019-02-13 10:43:36 +00:00
}
else return -1;
2019-01-31 22:41:06 +00:00
return 0;
}
/* -------------------------------------------------------------------------- */
2019-03-03 13:30:16 +00:00
int read_slbit(dsp_t *dsp, int symlen, int *bit, int inv, int ofs, int pos, float l, int spike) {
2019-01-31 22:41:06 +00:00
// symlen==2: manchester2 10->0,01->1: 2.bit
2019-02-20 22:23:57 +00:00
float bitgrenze = pos*symlen*dsp->sps;
2019-03-03 13:30:16 +00:00
ui32_t scount = ceil(bitgrenze);//+0.99; // dfm?
2019-01-31 22:41:06 +00:00
float sample;
2019-03-03 13:30:16 +00:00
float avg;
float ths = 0.5, scale = 0.27;
2019-01-31 22:41:06 +00:00
double sum = 0.0;
double mid;
2019-02-20 22:23:57 +00:00
//double l = 0.5 .. 1.0 .. sps/2;
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
if (pos == 0) scount = 0;
2019-01-31 22:41:06 +00:00
if (symlen == 2) {
2019-02-20 22:23:57 +00:00
mid = bitgrenze + (dsp->sps-1)/2.0;
bitgrenze += dsp->sps;
2019-01-31 22:41:06 +00:00
do {
2019-02-20 22:23:57 +00:00
if (dsp->buffered > 0) dsp->buffered -= 1;
else if (f32buf_sample(dsp, inv) == EOF) return EOF;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
sample = dsp->bufs[(dsp->sample_out-dsp->buffered + ofs + dsp->M) % dsp->M];
2019-03-03 13:30:16 +00:00
avg = 0.5*(dsp->bufs[(dsp->sample_out-dsp->buffered-1 + ofs + dsp->M) % dsp->M]
+dsp->bufs[(dsp->sample_out-dsp->buffered+1 + ofs + dsp->M) % dsp->M]);
if (spike && fabs(sample - avg) > ths) sample = avg + scale*(sample - avg); // spikes
2019-02-20 22:23:57 +00:00
if ( l < 0 || (mid-l < scount && scount < mid+l)) sum -= sample;
2019-01-31 22:41:06 +00:00
scount++;
2019-02-20 22:23:57 +00:00
} while (scount < bitgrenze); // n < dsp->sps
2019-01-31 22:41:06 +00:00
}
2019-02-20 22:23:57 +00:00
mid = bitgrenze + (dsp->sps-1)/2.0;
bitgrenze += dsp->sps;
2019-01-31 22:41:06 +00:00
do {
2019-02-20 22:23:57 +00:00
if (dsp->buffered > 0) dsp->buffered -= 1;
else if (f32buf_sample(dsp, inv) == EOF) return EOF;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
sample = dsp->bufs[(dsp->sample_out-dsp->buffered + ofs + dsp->M) % dsp->M];
2019-03-03 13:30:16 +00:00
avg = 0.5*(dsp->bufs[(dsp->sample_out-dsp->buffered-1 + ofs + dsp->M) % dsp->M]
+dsp->bufs[(dsp->sample_out-dsp->buffered+1 + ofs + dsp->M) % dsp->M]);
if (spike && fabs(sample - avg) > ths) sample = avg + scale*(sample - avg); // spikes
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if ( l < 0 || (mid-l < scount && scount < mid+l)) sum += sample;
2019-01-31 22:41:06 +00:00
scount++;
2019-02-20 22:23:57 +00:00
} while (scount < bitgrenze); // n < dsp->sps
2019-01-31 22:41:06 +00:00
if (sum >= 0) *bit = 1;
else *bit = 0;
return 0;
}
/* -------------------------------------------------------------------------- */
#define SQRT2 1.4142135624 // sqrt(2)
// sigma = sqrt(log(2)) / (2*PI*BT):
//#define SIGMA 0.2650103635 // BT=0.5: 0.2650103635 , BT=0.3: 0.4416839392
// Gaussian FM-pulse
static double Q(double x) {
return 0.5 - 0.5*erf(x/SQRT2);
}
static double pulse(double t, double sigma) {
return Q((t-0.5)/sigma) - Q((t+0.5)/sigma);
}
2019-02-20 22:23:57 +00:00
static double norm2_vect(float *vect, int n) {
2019-01-31 22:41:06 +00:00
int i;
double x, y = 0.0;
2019-02-20 22:23:57 +00:00
for (i = 0; i < n; i++) {
x = vect[i];
2019-01-31 22:41:06 +00:00
y += x*x;
}
return y;
}
2019-02-20 22:23:57 +00:00
int init_buffers(dsp_t *dsp) {
2019-01-31 22:41:06 +00:00
int i, pos;
float b0, b1, b2, b, t;
float normMatch;
2019-02-20 22:23:57 +00:00
double sigma = sqrt(log(2)) / (2*M_PI*dsp->BT);
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
int p2 = 1;
int K, L, M;
2019-01-31 22:41:06 +00:00
int n, k;
float *m = NULL;
2019-03-03 13:30:16 +00:00
L = dsp->hdrlen * dsp->sps + 0.5;
M = 3*L;
//if (dsp->sps < 6) M = 6*L;
dsp->delay = L/16;
dsp->sample_in = 0;
p2 = 1;
while (p2 < M) p2 <<= 1;
while (p2 < 0x2000) p2 <<= 1; // or 0x4000, if sample not too short
M = p2;
dsp->DFT.N = p2;
dsp->DFT.LOG2N = log(dsp->DFT.N)/log(2)+0.1; // 32bit cpu ... intermediate floating-point precision
//while ((1 << dsp->DFT.LOG2N) < dsp->DFT.N) dsp->DFT.LOG2N++; // better N = (1 << LOG2N) ...
K = M-L - dsp->delay; // L+K < M
dsp->DFT.sr = dsp->sr;
dsp->K = K;
dsp->L = L;
dsp->M = M;
dsp->Nvar = L; // wenn Nvar fuer xnorm, dann Nvar=rshd.L
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
dsp->bufs = (float *)calloc( M+1, sizeof(float)); if (dsp->bufs == NULL) return -100;
2019-03-03 13:30:16 +00:00
dsp->match = (float *)calloc( L+1, sizeof(float)); if (dsp->match == NULL) return -100;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
dsp->xs = (float *)calloc( M+1, sizeof(float)); if (dsp->xs == NULL) return -100;
dsp->qs = (float *)calloc( M+1, sizeof(float)); if (dsp->qs == NULL) return -100;
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
dsp->rawbits = (char *)calloc( 2*dsp->hdrlen+1, sizeof(char)); if (dsp->rawbits == NULL) return -100;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
for (i = 0; i < M; i++) dsp->bufs[i] = 0.0;
2019-01-31 22:41:06 +00:00
2019-03-03 13:30:16 +00:00
for (i = 0; i < L; i++) {
2019-02-20 22:23:57 +00:00
pos = i/dsp->sps;
t = (i - pos*dsp->sps)/dsp->sps - 0.5;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
b1 = ((dsp->hdr[pos] & 0x1) - 0.5)*2.0;
2019-01-31 22:41:06 +00:00
b = b1*pulse(t, sigma);
if (pos > 0) {
2019-02-20 22:23:57 +00:00
b0 = ((dsp->hdr[pos-1] & 0x1) - 0.5)*2.0;
2019-01-31 22:41:06 +00:00
b += b0*pulse(t+1, sigma);
}
2019-02-20 22:23:57 +00:00
if (pos < dsp->hdrlen-1) {
b2 = ((dsp->hdr[pos+1] & 0x1) - 0.5)*2.0;
2019-01-31 22:41:06 +00:00
b += b2*pulse(t-1, sigma);
}
2019-02-20 22:23:57 +00:00
dsp->match[i] = b;
2019-01-31 22:41:06 +00:00
}
2019-03-03 13:30:16 +00:00
normMatch = sqrt( norm2_vect(dsp->match, L) );
for (i = 0; i < L; i++) {
2019-02-20 22:23:57 +00:00
dsp->match[i] /= normMatch;
2019-01-31 22:41:06 +00:00
}
2019-02-20 22:23:57 +00:00
dsp->DFT.xn = calloc(dsp->DFT.N+1, sizeof(float)); if (dsp->DFT.xn == NULL) return -1;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
dsp->DFT.Fm = calloc(dsp->DFT.N+1, sizeof(float complex)); if (dsp->DFT.Fm == NULL) return -1;
dsp->DFT.X = calloc(dsp->DFT.N+1, sizeof(float complex)); if (dsp->DFT.X == NULL) return -1;
dsp->DFT.Z = calloc(dsp->DFT.N+1, sizeof(float complex)); if (dsp->DFT.Z == NULL) return -1;
dsp->DFT.cx = calloc(dsp->DFT.N+1, sizeof(float complex)); if (dsp->DFT.cx == NULL) return -1;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
dsp->DFT.ew = calloc(dsp->DFT.LOG2N+1, sizeof(float complex)); if (dsp->DFT.ew == NULL) return -1;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
// FFT window
// a) N2 = N
// b) N2 < N (interpolation)
dsp->DFT.win = calloc(dsp->DFT.N+1, sizeof(float complex)); if (dsp->DFT.win == NULL) return -1; // float real
dsp->DFT.N2 = dsp->DFT.N;
2019-03-03 13:30:16 +00:00
//dsp->DFT.N2 = dsp->DFT.N/2 - 1; // N=2^log2N
2019-02-20 22:23:57 +00:00
dft_window(&dsp->DFT, 1);
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
for (n = 0; n < dsp->DFT.LOG2N; n++) {
2019-01-31 22:41:06 +00:00
k = 1 << n;
2019-02-20 22:23:57 +00:00
dsp->DFT.ew[n] = cexp(-I*M_PI/(float)k);
2019-01-31 22:41:06 +00:00
}
2019-02-20 22:23:57 +00:00
m = calloc(dsp->DFT.N+1, sizeof(float)); if (m == NULL) return -1;
2019-03-03 13:30:16 +00:00
for (i = 0; i < L; i++) m[L-1 - i] = dsp->match[i]; // t = L-1
2019-02-20 22:23:57 +00:00
while (i < dsp->DFT.N) m[i++] = 0.0;
rdft(&dsp->DFT, m, dsp->DFT.Fm);
2019-01-31 22:41:06 +00:00
free(m); m = NULL;
2019-02-20 22:23:57 +00:00
if (dsp->opt_iq)
2019-01-31 22:41:06 +00:00
{
2019-02-20 22:23:57 +00:00
if (dsp->nch < 2) return -1;
2019-03-03 13:30:16 +00:00
2019-02-20 22:23:57 +00:00
dsp->N_IQBUF = dsp->DFT.N;
dsp->raw_iqbuf = calloc(dsp->N_IQBUF+1, sizeof(float complex)); if (dsp->raw_iqbuf == NULL) return -1;
dsp->rot_iqbuf = calloc(dsp->N_IQBUF+1, sizeof(float complex)); if (dsp->rot_iqbuf == NULL) return -1;
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
dsp->len_sq = dsp->sps*8;
2019-01-31 22:41:06 +00:00
}
return K;
}
2019-02-20 22:23:57 +00:00
int free_buffers(dsp_t *dsp) {
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (dsp->match) { free(dsp->match); dsp->match = NULL; }
if (dsp->bufs) { free(dsp->bufs); dsp->bufs = NULL; }
if (dsp->xs) { free(dsp->xs); dsp->xs = NULL; }
if (dsp->qs) { free(dsp->qs); dsp->qs = NULL; }
if (dsp->rawbits) { free(dsp->rawbits); dsp->rawbits = NULL; }
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (dsp->DFT.xn) { free(dsp->DFT.xn); dsp->DFT.xn = NULL; }
if (dsp->DFT.ew) { free(dsp->DFT.ew); dsp->DFT.ew = NULL; }
if (dsp->DFT.Fm) { free(dsp->DFT.Fm); dsp->DFT.Fm = NULL; }
if (dsp->DFT.X) { free(dsp->DFT.X); dsp->DFT.X = NULL; }
if (dsp->DFT.Z) { free(dsp->DFT.Z); dsp->DFT.Z = NULL; }
if (dsp->DFT.cx) { free(dsp->DFT.cx); dsp->DFT.cx = NULL; }
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (dsp->DFT.win) { free(dsp->DFT.win); dsp->DFT.win = NULL; }
2019-01-31 22:41:06 +00:00
2019-02-20 22:23:57 +00:00
if (dsp->opt_iq)
2019-01-31 22:41:06 +00:00
{
2019-02-20 22:23:57 +00:00
if (dsp->raw_iqbuf) { free(dsp->raw_iqbuf); dsp->raw_iqbuf = NULL; }
if (dsp->rot_iqbuf) { free(dsp->rot_iqbuf); dsp->rot_iqbuf = NULL; }
2019-01-31 22:41:06 +00:00
}
return 0;
}
/* ------------------------------------------------------------------------------------ */
2019-02-20 22:23:57 +00:00
ui32_t get_sample(dsp_t *dsp) {
return dsp->sample_out;
2019-01-31 22:41:06 +00:00
}