diff --git a/auto_rx/autorx/__init__.py b/auto_rx/autorx/__init__.py index 806fe6b..5fec504 100644 --- a/auto_rx/autorx/__init__.py +++ b/auto_rx/autorx/__init__.py @@ -17,7 +17,7 @@ except ImportError: # MINOR - New sonde type support, other fairly big changes that may result in telemetry or config file incompatability issus. # PATCH - Small changes, or minor feature additions. -__version__ = "1.5.8-beta1" +__version__ = "1.5.8-beta2" # Global Variables diff --git a/demod/mod/demod_mod.c b/demod/mod/demod_mod.c index 51e3538..d6d4533 100644 --- a/demod/mod/demod_mod.c +++ b/demod/mod/demod_mod.c @@ -145,7 +145,7 @@ static int dft_window(dft_t *dft, int w) { /* ------------------------------------------------------------------------------------ */ -static int getCorrDFT(dsp_t *dsp) { +static int getCorrDFT(dsp_t *dsp, float thres) { int i; int mp = -1; float mx = 0.0; @@ -155,9 +155,8 @@ static int getCorrDFT(dsp_t *dsp) { ui32_t mpos = 0; ui32_t pos = dsp->sample_out; - double dc = 0.0; - int mp_ofs = 0; float *sbuf = dsp->bufs; + float *dcbuf = dsp->fm_buffer; dsp->mv = 0.0; dsp->dc = 0.0; @@ -166,38 +165,32 @@ static int getCorrDFT(dsp_t *dsp) { if (dsp->sample_out < dsp->L) return -2; - if (dsp->opt_iq > 1 && dsp->opt_dc) { - mp_ofs = (dsp->sps-1)/2; - sbuf = dsp->fm_buffer; - } - else { - sbuf = dsp->bufs; - } - for (i = 0; i < dsp->K + dsp->L; i++) (dsp->DFT).xn[i] = sbuf[(pos+dsp->M -(dsp->K + dsp->L-1) + i) % dsp->M]; - while (i < dsp->DFT.N) (dsp->DFT).xn[i++] = 0.0; + for (i = 0; i < dsp->K + dsp->L; i++) dsp->DFT.xn[i] = sbuf[(pos+dsp->M -(dsp->K + dsp->L-1) + i) % dsp->M]; + while (i < dsp->DFT.N) dsp->DFT.xn[i++] = 0.0; rdft(&dsp->DFT, dsp->DFT.xn, dsp->DFT.X); if (dsp->opt_dc) { + /* //X[0] = 0; // nicht ueber gesamte Laenge ... M10 // // L < K ? // only last 2L samples (avoid M10 carrier offset) - dc = 0.0; - for (i = dsp->K - dsp->L; i < dsp->K + dsp->L; i++) dc += (dsp->DFT).xn[i]; + double dc = 0.0; + for (i = dsp->K - dsp->L; i < dsp->K + dsp->L; i++) dc += dsp->DFT.xn[i]; dc /= 2.0*(float)dsp->L; dsp->DFT.X[0] -= dsp->DFT.N * dc ;//* 0.95; - Nidft(&dsp->DFT, dsp->DFT.X, (dsp->DFT).cx); - for (i = 0; i < dsp->DFT.N; i++) (dsp->DFT).xn[i] = creal((dsp->DFT).cx[i])/(float)dsp->DFT.N; + */ + dsp->DFT.X[0] = 0; + Nidft(&dsp->DFT, dsp->DFT.X, dsp->DFT.cx); + for (i = 0; i < dsp->DFT.N; i++) dsp->DFT.xn[i] = creal(dsp->DFT.cx[i])/(float)dsp->DFT.N; } for (i = 0; i < dsp->DFT.N; i++) dsp->DFT.Z[i] = dsp->DFT.X[i]*dsp->DFT.Fm[i]; Nidft(&dsp->DFT, dsp->DFT.Z, dsp->DFT.cx); - if (fabs(dc) < 0.5) dsp->dc = dc; - // relativ Peak - Normierung erst zum Schluss; // dann jedoch nicht zwingend corr-Max wenn FM-Amplitude bzw. norm(x) nicht konstant @@ -220,21 +213,88 @@ static int getCorrDFT(dsp_t *dsp) { //xnorm = sqrt(dsp->qs[(mpos + 2*dsp->M) % dsp->M]); // Nvar = L xnorm = 0.0; - for (i = 0; i < dsp->L; i++) xnorm += (dsp->DFT).xn[mp-i]*(dsp->DFT).xn[mp-i]; + for (i = 0; i < dsp->L; i++) xnorm += dsp->DFT.xn[mp-i]*dsp->DFT.xn[mp-i]; xnorm = sqrt(xnorm); - mx /= xnorm*(dsp->DFT).N; - - if (dsp->opt_iq > 1 && dsp->opt_dc) mpos += mp_ofs; + mx /= xnorm*dsp->DFT.N; dsp->mv = mx; dsp->mv_pos = mpos; - if (pos == dsp->sample_out) dsp->buffered = dsp->sample_out - mpos; + if (pos == dsp->sample_out) dsp->buffered = dsp->sample_out - dsp->mv_pos; -// FM: s = gain * carg(w)/M_PI = gain * dphi / PI // gain=0.8 -// FM audio gain? dc relative to FM-envelope?! -// + + dsp->mv2 = 0.0f; + dsp->mv2_pos = 0; + if (dsp->opt_dc) { + if (dsp->opt_iq >= 2 && fabs(mx) < thres) { /*&& !dsp->locked*/ + mx = 0.0f; + mpos = 0; + + for (i = 0; i < dsp->K + dsp->L; i++) dsp->DFT.xn[i] = dcbuf[(pos+dsp->M -(dsp->K + dsp->L-1) + i) % dsp->M]; + while (i < dsp->DFT.N) dsp->DFT.xn[i++] = 0.0; + rdft(&dsp->DFT, dsp->DFT.xn, dsp->DFT.X); + + dsp->DFT.X[0] = 0; + Nidft(&dsp->DFT, dsp->DFT.X, dsp->DFT.cx); + for (i = 0; i < dsp->DFT.N; i++) dsp->DFT.xn[i] = creal(dsp->DFT.cx[i])/(float)dsp->DFT.N; + + for (i = 0; i < dsp->DFT.N; i++) dsp->DFT.Z[i] = dsp->DFT.X[i]*dsp->DFT.Fm[i]; + + Nidft(&dsp->DFT, dsp->DFT.Z, dsp->DFT.cx); + + 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; + } + } + 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 = 0.0; + for (i = 0; i < dsp->L; i++) xnorm += dsp->DFT.xn[mp-i]*dsp->DFT.xn[mp-i]; + xnorm = sqrt(xnorm); + + mx /= xnorm*dsp->DFT.N; + + + dsp->mv2 = mx; + dsp->mv2_pos = mpos - (dsp->lpFMtaps - (dsp->sps-1))/2; + + if (dsp->mv2 > thres || dsp->mv2 < -thres) { + dsp->mv = dsp->mv2; + dsp->mv_pos = dsp->mv2_pos; + + if (pos == dsp->sample_out) dsp->buffered = dsp->sample_out - dsp->mv2_pos; + } + } + } + + + if (dsp->opt_dc) + { + double dc = 0.0; + int mp_ofs = 0; + if (dsp->opt_iq >= 2 && dsp->mv2_pos == 0) { + mp_ofs = (dsp->lpFMtaps - (dsp->sps-1))/2; + } + dc = 0.0; // rs41 without preamble? + // unbalanced header? + for (i = 0; i < dsp->L; i++) dc += dcbuf[(mp_ofs + mpos - i + dsp->M) % dsp->M]; + dc /= (float)dsp->L; + dsp->dc = dc; + } + + + // FM: s = gain * carg(w)/M_PI = gain * dphi / PI // gain=0.8 + // FM audio gain? dc relative to FM-envelope?! + // dsp->dDf = dsp->sr * dsp->dc / (2.0*FM_GAIN); // remaining freq offset return mp; @@ -597,6 +657,7 @@ static float re_lowpass(float buffer[], ui32_t sample, ui32_t taps, float *ws) { int f32buf_sample(dsp_t *dsp, int inv) { float s = 0.0; + float s_fm = s; float xneu, xalt; float complex z, w, z0; @@ -604,25 +665,41 @@ int f32buf_sample(dsp_t *dsp, int inv) { double t = dsp->sample_in / (double)dsp->sr; - if (dsp->opt_iq) { - + if (dsp->opt_iq) + { if (dsp->opt_iq == 5) { ui32_t s_reset = dsp->dectaps*dsp->lut_len; int j; if ( f32read_cblock(dsp) < dsp->decM ) return EOF; for (j = 0; j < dsp->decM; j++) { - dsp->decXbuffer[dsp->sample_dec % dsp->dectaps] = dsp->decMbuf[j] * dsp->ex[dsp->sample_dec % dsp->lut_len]; + if (dsp->opt_nolut) { + double _s_base = (double)(dsp->sample_in*dsp->decM+j); // dsp->sample_dec + double f0 = dsp->xlt_fq*_s_base - dsp->Df*_s_base/(double)dsp->sr_base; + z = dsp->decMbuf[j] * cexp(f0*2*M_PI*I); + } + else { + z = dsp->decMbuf[j] * dsp->ex[dsp->sample_dec % dsp->lut_len]; + } + + dsp->decXbuffer[dsp->sample_dec % dsp->dectaps] = z; dsp->sample_dec += 1; if (dsp->sample_dec == s_reset) dsp->sample_dec = 0; } - z = lowpass(dsp->decXbuffer, dsp->sample_dec, dsp->dectaps, ws_dec); + if (dsp->decM > 1) + { + z = lowpass(dsp->decXbuffer, dsp->sample_dec, dsp->dectaps, ws_dec); + } } else if ( f32read_csample(dsp, &z) == EOF ) return EOF; - z *= cexp(-t*2*M_PI*dsp->Df*I); + if (dsp->opt_dc && !dsp->opt_nolut) + { + z *= cexp(-t*2*M_PI*dsp->Df*I); + } + // IF-lowpass - if (dsp->opt_lp) { + if (dsp->opt_lp & LP_IQ) { dsp->lpIQ_buf[dsp->sample_in % dsp->lpIQtaps] = z; z = lowpass(dsp->lpIQ_buf, dsp->sample_in, dsp->lpIQtaps, dsp->ws_lpIQ); } @@ -630,82 +707,88 @@ int f32buf_sample(dsp_t *dsp, int inv) { z0 = dsp->rot_iqbuf[(dsp->sample_in-1 + dsp->N_IQBUF) % dsp->N_IQBUF]; w = z * conj(z0); - s = gain * carg(w)/M_PI; + s_fm = gain * carg(w)/M_PI; dsp->rot_iqbuf[dsp->sample_in % dsp->N_IQBUF] = z; - // FM-lowpass - if (dsp->opt_lp) { - dsp->lpFM_buf[dsp->sample_in % dsp->lpFMtaps] = s; - s = re_lowpass(dsp->lpFM_buf, dsp->sample_in, dsp->lpFMtaps, dsp->ws_lpFM); - } - - dsp->fm_buffer[(dsp->sample_in - dsp->lpFMtaps/2 + dsp->M) % dsp->M] = s; - - if (dsp->opt_iq >= 2) { - double xbit = 0.0; - //float complex xi = cexp(+I*M_PI*dsp->h/dsp->sps); - double f1 = -dsp->h*dsp->sr/(2*dsp->sps); - double f2 = -f1; + if (dsp->opt_iq >= 2) { + double xbit = 0.0; + //float complex xi = cexp(+I*M_PI*dsp->h/dsp->sps); + double f1 = -dsp->h*dsp->sr/(2.0*dsp->sps); + double f2 = -f1; - float complex X0 = 0; - float complex X = 0; + float complex X0 = 0; + float complex X = 0; - int n = dsp->sps; - double tn = (dsp->sample_in-n) / (double)dsp->sr; - //t = dsp->sample_in / (double)dsp->sr; - //z = dsp->rot_iqbuf[dsp->sample_in % dsp->N_IQBUF]; - z0 = dsp->rot_iqbuf[(dsp->sample_in-n + dsp->N_IQBUF) % dsp->N_IQBUF]; + int n = dsp->sps; + double tn = (dsp->sample_in-n) / (double)dsp->sr; + //t = dsp->sample_in / (double)dsp->sr; + //z = dsp->rot_iqbuf[dsp->sample_in % dsp->N_IQBUF]; + z0 = dsp->rot_iqbuf[(dsp->sample_in-n + dsp->N_IQBUF) % dsp->N_IQBUF]; - // f1 - X0 = z0 * cexp(-tn*2*M_PI*f1*I); // alt - X = z * cexp(-t *2*M_PI*f1*I); // neu - dsp->F1sum += X - X0; + // f1 + X0 = z0 * cexp(-tn*2*M_PI*f1*I); // alt + X = z * cexp(-t *2*M_PI*f1*I); // neu + dsp->F1sum += X - X0; - // f2 - X0 = z0 * cexp(-tn*2*M_PI*f2*I); // alt - X = z * cexp(-t *2*M_PI*f2*I); // neu - dsp->F2sum += X - X0; + // f2 + X0 = z0 * cexp(-tn*2*M_PI*f2*I); // alt + X = z * cexp(-t *2*M_PI*f2*I); // neu + dsp->F2sum += X - X0; - xbit = cabs(dsp->F2sum) - cabs(dsp->F1sum); + xbit = cabs(dsp->F2sum) - cabs(dsp->F1sum); - s = xbit / dsp->sps; - } - else if (0 && dsp->opt_iq >= 4) - { - double xbit = 0.0; - //float complex xi = cexp(+I*M_PI*dsp->h/dsp->sps); - double f1 = -dsp->h*dsp->sr/(2*dsp->sps); - double f2 = -f1; - - float complex X1 = 0; - float complex X2 = 0; - - int n = dsp->sps; - - while (n > 0) { - n--; - t = -n / (double)dsp->sr; - z = dsp->rot_iqbuf[(dsp->sample_in - n + dsp->N_IQBUF) % dsp->N_IQBUF]; // +1 - X1 += z*cexp(-t*2*M_PI*f1*I); - X2 += z*cexp(-t*2*M_PI*f2*I); + s = xbit / dsp->sps; } + else if (0 && dsp->opt_iq == 4) { + double xbit = 0.0; + //float complex xi = cexp(+I*M_PI*dsp->h/dsp->sps); + double f1 = -dsp->h*dsp->sr/(2*dsp->sps); + double f2 = -f1; - xbit = cabs(X2) - cabs(X1); + float complex X1 = 0; + float complex X2 = 0; - s = xbit / dsp->sps; + int n = dsp->sps; + + while (n > 0) { + n--; + t = -n / (double)dsp->sr; + z = dsp->rot_iqbuf[(dsp->sample_in - n + dsp->N_IQBUF) % dsp->N_IQBUF]; // +1 + X1 += z*cexp(-t*2*M_PI*f1*I); + X2 += z*cexp(-t*2*M_PI*f2*I); + } + + xbit = cabs(X2) - cabs(X1); + + s = xbit / dsp->sps; + } + } + else { + s = s_fm; } } else { if (f32read_sample(dsp, &s) == EOF) return EOF; + s_fm = s; } + // FM-lowpass + if (dsp->opt_lp & LP_FM) { + dsp->lpFM_buf[dsp->sample_in % dsp->lpFMtaps] = s_fm; + s_fm = re_lowpass(dsp->lpFM_buf, dsp->sample_in, dsp->lpFMtaps, dsp->ws_lpFM); + if (dsp->opt_iq < 2) s = s_fm; + } + + dsp->fm_buffer[dsp->sample_in % dsp->M] = s_fm; + if (inv) s = -s; dsp->bufs[dsp->sample_in % dsp->M] = s; + 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 @@ -728,20 +811,23 @@ static int read_bufbit(dsp_t *dsp, int symlen, char *bits, ui32_t mvp, int pos) ui32_t rcount = ceil(rbitgrenze);//+0.99; // dfm? double sum = 0.0; + double dc = 0.0; + + if (dsp->opt_dc && dsp->opt_iq < 2) dc = dsp->dc; // bei symlen=2 (Manchester) kein dc noetig: -dc+dc=0 ; // allerdings M10-header mit symlen=1 rbitgrenze += dsp->sps; do { - sum += dsp->bufs[(rcount + mvp + dsp->M) % dsp->M] - dsp->dc; + sum += dsp->bufs[(rcount + mvp + dsp->M) % dsp->M] - dc; rcount++; } while (rcount < rbitgrenze); // n < dsp->sps if (symlen == 2) { rbitgrenze += dsp->sps; do { - sum -= dsp->bufs[(rcount + mvp + dsp->M) % dsp->M] - dsp->dc; + sum -= dsp->bufs[(rcount + mvp + dsp->M) % dsp->M] - dc; rcount++; } while (rcount < rbitgrenze); // n < dsp->sps } @@ -767,7 +853,7 @@ static int headcmp(dsp_t *dsp, int opt_dc) { int len = dsp->hdrlen/dsp->symhd; int inv = dsp->mv < 0; - if (opt_dc == 0 || dsp->opt_iq > 1) dsp->dc = 0; // reset? e.g. 2nd pass + //if (opt_dc == 0 || dsp->opt_iq > 1) dsp->dc = 0; if (dsp->symhd != 1) step = 2; if (inv) sign=1; @@ -1067,6 +1153,7 @@ int init_buffers(dsp_t *dsp) { float *m = NULL; + // decimate if (dsp->opt_iq == 5) { int IF_sr = IF_SAMPLE_RATE; // designated IF sample rate @@ -1107,40 +1194,42 @@ int init_buffers(dsp_t *dsp) { } if (dsp->opt_iq == 5) { - // look up table, exp-rotation - int W = 2*8; // 16 Hz window - int d = 1; // 1..W , groesster Teiler d <= W von sr_base - int freq = (int)( dsp->xlt_fq * (double)dsp->sr_base + 0.5); - int freq0 = freq; // init - double f0 = freq0 / (double)dsp->sr_base; // init + if (!dsp->opt_nolut) + { + // look up table, exp-rotation + int W = 2*8; // 16 Hz window + int d = 1; // 1..W , groesster Teiler d <= W von sr_base + int freq = (int)( dsp->xlt_fq * (double)dsp->sr_base + 0.5); + int freq0 = freq; // init + double f0 = freq0 / (double)dsp->sr_base; // init - for (d = W; d > 0; d--) { // groesster Teiler d <= W von sr - if (dsp->sr_base % d == 0) break; - } - if (d == 0) d = 1; // d >= 1 ? - - for (k = 0; k < W/2; k++) { - if ((freq+k) % d == 0) { - freq0 = freq + k; - break; + for (d = W; d > 0; d--) { // groesster Teiler d <= W von sr + if (dsp->sr_base % d == 0) break; } - if ((freq-k) % d == 0) { - freq0 = freq - k; - break; + if (d == 0) d = 1; // d >= 1 ? + + for (k = 0; k < W/2; k++) { + if ((freq+k) % d == 0) { + freq0 = freq + k; + break; + } + if ((freq-k) % d == 0) { + freq0 = freq - k; + break; + } + } + + dsp->lut_len = dsp->sr_base / d; + f0 = freq0 / (double)dsp->sr_base; + + dsp->ex = calloc(dsp->lut_len+1, sizeof(float complex)); + if (dsp->ex == NULL) return -1; + for (n = 0; n < dsp->lut_len; n++) { + t = f0*(double)n; + dsp->ex[n] = cexp(t*2*M_PI*I); } } - dsp->lut_len = dsp->sr_base / d; - f0 = freq0 / (double)dsp->sr_base; - - dsp->ex = calloc(dsp->lut_len+1, sizeof(float complex)); - if (dsp->ex == NULL) return -1; - for (n = 0; n < dsp->lut_len; n++) { - t = f0*(double)n; - dsp->ex[n] = cexp(t*2*M_PI*I); - } - - dsp->decXbuffer = calloc( dsp->dectaps+1, sizeof(float complex)); if (dsp->decXbuffer == NULL) return -1; @@ -1148,13 +1237,13 @@ int init_buffers(dsp_t *dsp) { if (dsp->decMbuf == NULL) return -1; } - if (dsp->opt_iq && dsp->opt_lp) + // IF lowpass + if (dsp->opt_iq && (dsp->opt_lp & LP_IQ)) { float f_lp; // lowpass_bw int taps; // lowpass taps: 4*sr/transition_bw - // IF lowpass - f_lp = 24e3; // default + f_lp = 24e3/(float)dsp->sr/2.0; // default if (dsp->lpIQ_bw) f_lp = dsp->lpIQ_bw/(float)dsp->sr/2.0; taps = 4*dsp->sr/IF_TRANSITION_BW; if (taps%2==0) taps++; taps = lowpass_init(1.5*f_lp, taps, &dsp->ws_lpIQ0); if (taps < 0) return -1; @@ -1175,10 +1264,15 @@ int init_buffers(dsp_t *dsp) { } // locked: //taps = lowpass_update(dsp->lpIQ_fbw, dsp->lpIQtaps, dsp->ws_lpIQ); if (taps < 0) return -1; + } + // FM lowpass + if (dsp->opt_lp & LP_FM) + { + float f_lp; // lowpass_bw + int taps; // lowpass taps: 4*sr/transition_bw - // FM lowpass - f_lp = 10e3; // default + f_lp = 10e3/(float)dsp->sr; // default if (dsp->lpFM_bw > 0) f_lp = dsp->lpFM_bw/(float)dsp->sr; taps = 4*dsp->sr/FM_TRANSITION_BW; if (taps%2==0) taps++; taps = lowpass_init(f_lp, taps, &dsp->ws_lpFM); if (taps < 0) return -1; @@ -1188,6 +1282,7 @@ int init_buffers(dsp_t *dsp) { if (dsp->lpFM_buf == NULL) return -1; } + memset(&IQdc, 0, sizeof(IQdc)); IQdc.maxlim = dsp->sr; IQdc.maxcnt = IQdc.maxlim/32; // 32,16,8,4,2,1 @@ -1333,18 +1428,23 @@ int free_buffers(dsp_t *dsp) { { if (dsp->decXbuffer) { free(dsp->decXbuffer); dsp->decXbuffer = NULL; } if (dsp->decMbuf) { free(dsp->decMbuf); dsp->decMbuf = NULL; } - if (dsp->ex) { free(dsp->ex); dsp->ex = NULL; } + if (!dsp->opt_nolut) { + if (dsp->ex) { free(dsp->ex); dsp->ex = NULL; } + } if (ws_dec) { free(ws_dec); ws_dec = NULL; } } // IF lowpass - if (dsp->opt_iq && dsp->opt_lp) + if (dsp->opt_iq && (dsp->opt_lp & LP_IQ)) { if (dsp->ws_lpIQ0) { free(dsp->ws_lpIQ0); dsp->ws_lpIQ0 = NULL; } if (dsp->ws_lpIQ1) { free(dsp->ws_lpIQ1); dsp->ws_lpIQ1 = NULL; } if (dsp->lpIQ_buf) { free(dsp->lpIQ_buf); dsp->lpIQ_buf = NULL; } - + } + // FM lowpass + if (dsp->opt_lp & LP_FM) + { if (dsp->ws_lpFM) { free(dsp->ws_lpFM); dsp->ws_lpFM = NULL; } if (dsp->lpFM_buf) { free(dsp->lpFM_buf); dsp->lpFM_buf = NULL; } } @@ -1369,7 +1469,7 @@ int find_header(dsp_t *dsp, float thres, int hdmax, int bitofs, int opt_dc) { k += 1; if (k >= dsp->K-4) { mvpos0 = dsp->mv_pos; - mp = getCorrDFT(dsp); // correlation score -> dsp->mv + mp = getCorrDFT(dsp, thres); // correlation score -> dsp->mv //if (option_auto == 0 && dsp->mv < 0) mv = 0; k = 0; } @@ -1378,17 +1478,40 @@ int find_header(dsp_t *dsp, float thres, int hdmax, int bitofs, int opt_dc) { continue; } - if (dsp->mv > thres || dsp->mv < -thres) { - - if (dsp->opt_dc) { // Problem: FM-gain - if (dsp->opt_iq < 2) dsp->Df += dsp->dDf*0.4; - else { - double ofs = fabs(dsp->dDf); // (iq-decode controls FM-gain) - if (ofs > 200.0) + if (dsp->mv > thres || dsp->mv < -thres) + { + if (dsp->opt_dc) + { + if (dsp->opt_iq) { + if (fabs(dsp->dDf) > 100.0) { - dsp->Df += dsp->dDf * 2/3.0; + double diffDf = dsp->dDf*0.6; //0.4 + if (1 && dsp->opt_iq >= 2) { + // update rot_iqbuf, F1sum, F2sum + double f1 = -dsp->h*dsp->sr/(2*dsp->sps); + double f2 = -f1; + float complex X1 = 0; + float complex X2 = 0; + float complex _z = 0; + int _n = dsp->sps; + while ( _n > 0 ) + { + // update rot_iqbuf + double _tn = (dsp->sample_in - _n) / (double)dsp->sr; + dsp->rot_iqbuf[(dsp->sample_in - _n + dsp->N_IQBUF) % dsp->N_IQBUF] *= cexp(-_tn*2*M_PI*diffDf*I); + // + //update/reset F1sum, F2sum + _z = dsp->rot_iqbuf[(dsp->sample_in - _n + dsp->N_IQBUF) % dsp->N_IQBUF]; + X1 += _z*cexp(-_tn*2*M_PI*f1*I); + X2 += _z*cexp(-_tn*2*M_PI*f2*I); + _n--; + } + dsp->F1sum = X1; + dsp->F2sum = X2; + } + dsp->Df += diffDf; } - if (ofs > 1000.0) { //dsp->opt_lp + if (fabs(dsp->dDf) > 1e3) { if (dsp->locked) { dsp->locked = 0; dsp->ws_lpIQ = dsp->ws_lpIQ0; diff --git a/demod/mod/demod_mod.h b/demod/mod/demod_mod.h index d2a2879..8225156 100644 --- a/demod/mod/demod_mod.h +++ b/demod/mod/demod_mod.h @@ -7,13 +7,20 @@ #define M_PI (3.1415926535897932384626433832795) #endif +#define LP_IQ 1 +#define LP_FM 2 +#define LP_IQFM 4 + +#ifndef INTTYPES +#define INTTYPES typedef unsigned char ui8_t; typedef unsigned short ui16_t; typedef unsigned int ui32_t; typedef char i8_t; typedef short i16_t; typedef int i32_t; +#endif typedef struct { @@ -58,6 +65,9 @@ typedef struct { float mv; ui32_t mv_pos; // + float mv2; + ui32_t mv2_pos; + // int N_norm; int Nvar; float xsum; @@ -91,6 +101,7 @@ typedef struct { double dc; double Df; double dDf; + // ui32_t sample_posframe; ui32_t sample_posnoise; @@ -100,6 +111,7 @@ typedef struct { double SNRdB; // decimate + int opt_nolut; // default: LUT int opt_IFmin; int decM; ui32_t sr_base; @@ -126,7 +138,7 @@ typedef struct { int lpFMtaps; // ui32_t float *ws_lpFM; float *lpFM_buf; - float *fm_buffer; + float *fm_buffer; } dsp_t; diff --git a/demod/mod/mXXmod.c b/demod/mod/mXXmod.c index 2bce2f5..ad9b986 100644 --- a/demod/mod/mXXmod.c +++ b/demod/mod/mXXmod.c @@ -92,6 +92,9 @@ static char rawheader[] = "10011001100110010100110010011001"; #define t_M20 0x20 typedef struct { + ui32_t gps_cnt; + ui8_t cnt; + ui8_t _diffcnt; int week; int tow_ms; int gpssec; int jahr; int monat; int tag; int wday; @@ -99,9 +102,10 @@ typedef struct { double lat; double lon; double alt; double vH; double vD; double vV; double vx; double vy; double vD2; + float T; float RH; float TH; float P; ui8_t numSV; ui8_t utc_ofs; - char SN[12]; + char SN[12+4]; ui8_t SNraw[3]; ui8_t frame_bytes[FRAME_LEN+AUX_LEN+4]; char frame_bits[BITFRAME_LEN+BITAUX_LEN+8]; @@ -181,9 +185,9 @@ frame[0x0] = framelen // (0x43,) 0x45 frame[0x1] = 0x20 (type M20) frame[0x02..0x18]: most important data at beginning (incl. counter + M10check) -frame[0x02..0x03]: ADC -frame[0x04..0x05]: ADC -frame[0x06..0x07]: ADC temperature +frame[0x02..0x03]: ADC RH (incl.555) +frame[0x04..0x05]: ADC Temperatur , frame[0x46]: scale/range ? +frame[0x06..0x07]: ADC RH-Temperature range: 0:0..4095 , 1:4096..8191 , 2:8192..12287 frame[0x08..0x0A]: GPS altitude frame[0x0B..0x0E]: GPS hor.Vel. (velE,velN) frame[0x0F..0x11]: GPS TOW @@ -242,6 +246,7 @@ frame[0x44..0x45]: frame check #define col_TXT "\x1b[38;5;244m" #define col_FRTXT "\x1b[38;5;244m" #define col_CSok "\x1b[38;5;2m" +#define col_CSoo "\x1b[38;5;220m" #define col_CSno "\x1b[38;5;1m" #define col_CNST "\x1b[38;5;58m" // 3 byte @@ -281,11 +286,12 @@ static int get_GPSweek(gpx_t *gpx) { static char weekday[7][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; static int get_GPStime(gpx_t *gpx) { - int i; + int i, ret = 0; unsigned byte; ui8_t gpstime_bytes[4]; int gpstime, day; int ms; + double sec_gps0 = 0.0; for (i = 0; i < 3; i++) { byte = gpx->frame_bytes[pos_GPSTOW + i]; @@ -312,6 +318,15 @@ static int get_GPStime(gpx_t *gpx) { gpx->min = (gpstime%3600)/60; gpx->sek = gpstime%60 + ms/1000.0; + + ret = get_GPSweek(gpx); + if (ret) return ret; + + sec_gps0 = (double)gpx->week*SECONDS_IN_WEEK + gpx->tow_ms/1e3; + gpx->gps_cnt = (ui32_t)(sec_gps0+0.5); + gpx->cnt = gpx->frame_bytes[pos_CNT]; + gpx->_diffcnt = (ui8_t)(gpx->gps_cnt - gpx->cnt); + return 0; } @@ -435,18 +450,29 @@ static int get_SN(gpx_t *gpx) { ui8_t ym = b0 & 0x7F; // #{0x0,..,0x77}=120=10*12 ui8_t y = ym / 12; ui8_t m = (ym % 12)+1; // there is b0=0x69<0x80 from 2018-09-19 ... + ui32_t sn_val = 0; - for (i = 0; i < 11; i++) gpx->SN[i] = ' '; gpx->SN[11] = '\0'; + for (i = 0; i < 11; i++) gpx->SN[i] = ' '; gpx->SN[11] = '\0'; + for (i = 12; i < 15; i++) gpx->SN[i] = '\0'; gpx->SN[15] = '\0'; for (i = 0; i < 3; i++) { gpx->SNraw[i] = gpx->frame_bytes[pos_SN + i]; } + sn_val = (gpx->SNraw[0]<<16) | (gpx->SNraw[1]<<8) | gpx->SNraw[2]; sprintf(gpx->SN, "%u%02u", y, m); // more samples needed - sprintf(gpx->SN+3, " %u ", (s2&0x3)+2); // (b0>>7)+1? (s2&0x3)+2? + sprintf(gpx->SN+3, "-%u-", (s2&0x3)+2); // (b0>>7)+1? (s2&0x3)+2? sprintf(gpx->SN+6, "%u", (s2>>(2+13))&0x1); // ?(s2>>(2+13))&0x1 ?? (s2&0x3)? sprintf(gpx->SN+7, "%04u", (s2>>2)&0x1FFF); + + if (sn_val == 0) + { // get_GPStime(gpx); + // replace SN: 001-2-00000 -> 000-0-00000-[_diffcnt] + sprintf(gpx->SN, "%s", "000-0-00000"); + sprintf(gpx->SN+11, "-%03u", gpx->_diffcnt & 0xFF); + } + return 0; } @@ -527,13 +553,83 @@ static int blk_checkM10(int len, ui8_t *msg) { /* -------------------------------------------------------------------------- */ -static float get_Tntc0(gpx_t *gpx) { -// SMD ntc +static float get_Temp(gpx_t *gpx) { +// NTC-Thermistor Shibaura PB5-41E ? +// T00 = 273.15 + 0.0 , R00 = 15e3 +// T25 = 273.15 + 25.0 , R25 = 5.369e3 +// B00 = 3450.0 Kelvin // 0C..100C, poor fit low temps +// [ T/C , R/1e3 ] ( [P__-43]/2.0 ): +// [ -50.0 , 204.0 ] +// [ -45.0 , 150.7 ] +// [ -40.0 , 112.6 ] +// [ -35.0 , 84.90 ] +// [ -30.0 , 64.65 ] +// [ -25.0 , 49.66 ] +// [ -20.0 , 38.48 ] +// [ -15.0 , 30.06 ] +// [ -10.0 , 23.67 ] +// [ -5.0 , 18.78 ] +// [ 0.0 , 15.00 ] +// [ 5.0 , 12.06 ] +// [ 10.0 , 9.765 ] +// [ 15.0 , 7.955 ] +// [ 20.0 , 6.515 ] +// [ 25.0 , 5.370 ] +// [ 30.0 , 4.448 ] +// [ 35.0 , 3.704 ] +// [ 40.0 , 3.100 ] +// -> Steinhart-Hart coefficients (polyfit): + float p0 = 1.07303516e-03, + p1 = 2.41296733e-04, + p2 = 2.26744154e-06, + p3 = 6.52855181e-08; +// T/K = 1/( p0 + p1*ln(R) + p2*ln(R)^2 + p3*ln(R)^3 ) + + // range/scale 0, 1, 2: // M10-pcb + float Rs[3] = { 12.1e3 , 36.5e3 , 475.0e3 }; // bias/series + float Rp[3] = { 1e20 , 330.0e3 , 2000.0e3 }; // parallel, Rp[0]=inf + + ui8_t scT = 0; // {0,1,2}, range/scale voltage divider + ui16_t ADC_RT; // ADC12 + //ui16_t Tcal[2]; + + float x, R; + float T = 0; // T/Kelvin + + ADC_RT = (gpx->frame_bytes[0x5] << 8) | gpx->frame_bytes[0x4]; + + //ui8_t sc = gpx->frame_bytes[0x32] & 3; // (frame[0x32]<<8)|frame[0x31] + // frame[0x31..0x32], frame[0x32]: 0x9=0b1001:0, 0xA=0b1010:1, 0x8=0b1000:2 + // ? Temp-Calibration depending on range ? + // + // range: 0:0..4095 , 1:4096..8191 , 2:8192..12287 + /* + if (sc == 0x1) { scT = 0; } + else if (sc == 0x2) { scT = 1; ADC_RT -= 4096; } + else if (sc == 0x0) { scT = 2; ADC_RT -= 8192; } + else: // sc == 0x3 // test only range below: + */ + // range, i.e. (ADC_RT>>12)&3 + if (ADC_RT > 8191) { scT = 2; ADC_RT -= 8192; } + else if (ADC_RT > 4095) { scT = 1; ADC_RT -= 4096; } + else { scT = 0; } // also if (ADC_RT>>12)&3 == 3 + + // ADC12 , 4096 = 1<<12, max: 4095 + x = (4095.0-ADC_RT)/ADC_RT; // (Vcc-Vout)/Vout = Vcc/Vout - 1 + R = Rs[scT] /( x - Rs[scT]/Rp[scT] ); + + if (R > 0) T = 1/( p0 + p1*log(R) + p2*log(R)*log(R) + p3*log(R)*log(R)*log(R) ); + + return T - 273.15; // Celsius +} + +static float get_Tntc2(gpx_t *gpx) { + // SMD ntc , RH-Temperature float Rs = 22.1e3; // P5.6=Vcc - float R25 = 2.2e3;// 0.119e3; //2.2e3; - float b = 3650.0; // B/Kelvin - float T25 = 25.0 + 273.15; // T0=25C, R0=R25=5k -// -> Steinhart–Hart coefficients (polyfit): + float R25 = 2.2e3;// 0.119e3; //2.2e3; + float b = 3650.0; // B/Kelvin + float T25 = 25.0 + 273.15; // T0=25C, R0=R25=5k + // -> Steinhart-Hart coefficients (polyfit): float p0 = 4.42606809e-03, p1 = -6.58184309e-04, p2 = 8.95735557e-05, @@ -551,6 +647,67 @@ static float get_Tntc0(gpx_t *gpx) { return T - 273.15; } +static float get_RHraw(gpx_t *gpx) { + float _rh = -1.0; + float _RH = -1.0; + ui16_t ADC_rh; + + ADC_rh = (gpx->frame_bytes[0x03] << 8) | gpx->frame_bytes[0x02]; + _rh = ADC_rh / (float)(1<<15); + + _RH = -1.0; + if (_rh < 1.05) _RH = _rh*100.0; + + // Transfer function ? + // Calibration ? + // (Hyland and Wexler) Tntc2 (T_RH) <-> Tmain ? + + return _RH; +} + +static float get_RH(gpx_t *gpx) { +// from DF9DQ, +// https://github.com/einergehtnochrein/ra-firmware +// + float TU = get_Tntc2(gpx); + float RH = -1.0f; + float x; + + ui16_t humval = (gpx->frame_bytes[0x03] << 8) | gpx->frame_bytes[0x02]; + ui16_t rh_cal = (gpx->frame_bytes[0x30] << 8) | gpx->frame_bytes[0x2F]; + + float humidityCalibration = 6.4e8f / (rh_cal + 80000.0f); + + x = (humval + 80000.0f) * humidityCalibration * (1.0f - 5.8e-4f * (TU-25.0f)); + x = 4.16e9f / x; + x = 10.087f*x*x*x - 211.62f*x*x + 1388.2f*x - 2797.0f; + + RH = -1.0f; + if (humval < 48000) + { + RH = x; + if (RH < 0.0f ) RH = 0.0f; + if (RH > 100.0f) RH = 100.0f; + } + + // (Hyland and Wexler) Tntc2 (T_RH) <-> Tmain ? + + return RH; +} + +static float get_P(gpx_t *gpx) { +// cf. DF9DQ +// + float hPa = 0.0f; + ui16_t val = (gpx->frame_bytes[0x25] << 8) | gpx->frame_bytes[0x24]; + + if (val > 0) { + hPa = val/16.0f; + } + + return hPa; +} + /* -------------------------------------------------------------------------- */ static int print_pos(gpx_t *gpx, int bcOK, int csOK) { @@ -559,8 +716,7 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) { if (1 || gpx->type == t_M20) { err = 0; - err |= get_GPSweek(gpx); - err |= get_GPStime(gpx); + err |= get_GPStime(gpx); // incl. get_GPSweek(gpx) err |= get_GPSlat(gpx); err |= get_GPSlon(gpx); err |= get_GPSalt(gpx); @@ -573,6 +729,12 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) { Gps2Date(gpx->week, gpx->gpssec, &gpx->jahr, &gpx->monat, &gpx->tag); get_SN(gpx); + if (gpx->option.ptu && csOK) { + gpx->T = get_Temp(gpx); // temperature + gpx->TH = get_Tntc2(gpx); // rel. humidity sensor temperature + gpx->RH = get_RH(gpx); // relative humidity + gpx->P = get_P(gpx); // (optional) pressure + } if ( !gpx->option.slt ) { @@ -596,15 +758,21 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) { } if (gpx->option.vbs >= 2) { fprintf(stdout, " # "); - if (bcOK) fprintf(stdout, " "col_CSok"(ok)"col_TXT); - else fprintf(stdout, " "col_CSno"(no)"col_TXT); + if (bcOK > 0) fprintf(stdout, " "col_CSok"(ok)"col_TXT); + else if (bcOK < 0) fprintf(stdout, " "col_CSoo"(oo)"col_TXT); + else fprintf(stdout, " "col_CSno"(no)"col_TXT); + // if (csOK) fprintf(stdout, " "col_CSok"[OK]"col_TXT); else fprintf(stdout, " "col_CSno"[NO]"col_TXT); } if (gpx->option.ptu && csOK) { - if (gpx->option.vbs >= 3) { - float t0 = get_Tntc0(gpx); - if (t0 > -270.0) fprintf(stdout, " (T0:%.1fC) ", t0); + fprintf(stdout, " "); + if (gpx->T > -273.0f) fprintf(stdout, " T:%.1fC", gpx->T); + if (gpx->RH > -0.5f) fprintf(stdout, " RH=%.0f%%", gpx->RH); + if (gpx->TH > -273.0f) fprintf(stdout, " TH:%.1fC", gpx->TH); + if (gpx->P > 0.0f) { + if (gpx->P < 100.0f) fprintf(stdout, " P=%.2fhPa ", gpx->P); + else fprintf(stdout, " P=%.1fhPa ", gpx->P); } } fprintf(stdout, ANSI_COLOR_RESET""); @@ -628,13 +796,21 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) { } if (gpx->option.vbs >= 2) { fprintf(stdout, " # "); - if (bcOK) fprintf(stdout, " (ok)"); else fprintf(stdout, " (no)"); + //if (bcOK) fprintf(stdout, " (ok)"); else fprintf(stdout, " (no)"); + if (bcOK > 0) fprintf(stdout, " (ok)"); + else if (bcOK < 0) fprintf(stdout, " (oo)"); + else fprintf(stdout, " (no)"); + // if (csOK) fprintf(stdout, " [OK]"); else fprintf(stdout, " [NO]"); } if (gpx->option.ptu && csOK) { - if (gpx->option.vbs >= 3) { - float t0 = get_Tntc0(gpx); - if (t0 > -270.0) fprintf(stdout, " (T0:%.1fC) ", t0); + fprintf(stdout, " "); + if (gpx->T > -273.0f) fprintf(stdout, " T:%.1fC", gpx->T); + if (gpx->RH > -0.5f) fprintf(stdout, " RH=%.0f%%", gpx->RH); + if (gpx->TH > -273.0f) fprintf(stdout, " TH:%.1fC", gpx->TH); + if (gpx->P > 0.0f) { + if (gpx->P < 100.0f) fprintf(stdout, " P=%.2fhPa ", gpx->P); + else fprintf(stdout, " P=%.1fhPa ", gpx->P); } } } @@ -647,17 +823,20 @@ static int print_pos(gpx_t *gpx, int bcOK, int csOK) { if (csOK) { char *ver_jsn = NULL; int j; - char sn_id[4+12] = "M20-"; - double sec_gps0 = (double)gpx->week*SECONDS_IN_WEEK + gpx->tow_ms/1e3; + char sn_id[4+12+4] = "M20-"; - strncpy(sn_id+4, gpx->SN, 12); - sn_id[15] = '\0'; - for (j = 0; sn_id[j]; j++) { if (sn_id[j] == ' ') sn_id[j] = '-'; } + strncpy(sn_id+4, gpx->SN, 12+4); + sn_id[15+4] = '\0'; fprintf(stdout, "{ \"type\": \"%s\"", "M20"); - fprintf(stdout, ", \"frame\": %lu, ", (unsigned long)(sec_gps0+0.5)); + fprintf(stdout, ", \"frame\": %lu, ", (unsigned long)gpx->gps_cnt); // sec_gps0+0.5 fprintf(stdout, "\"id\": \"%s\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%06.3fZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f", sn_id, gpx->jahr, gpx->monat, gpx->tag, gpx->std, gpx->min, gpx->sek, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vV); + if (gpx->option.ptu) { // temperature + if (gpx->T > -273.0f) fprintf(stdout, ", \"temp\": %.1f", gpx->T ); + if (gpx->RH > -0.5f) fprintf(stdout, ", \"humidity\": %.1f", gpx->RH ); + if (gpx->P > 0.0f) fprintf(stdout, ", \"pressure\": %.2f", gpx->P ); + } fprintf(stdout, ", \"rawid\": \"M20_%02X%02X%02X\"", gpx->frame_bytes[pos_SN], gpx->frame_bytes[pos_SN+1], gpx->frame_bytes[pos_SN+2]); // gpx->type fprintf(stdout, ", \"subtype\": \"0x%02X\"", gpx->type); if (gpx->jsn_freq > 0) { @@ -681,7 +860,7 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) { int i; ui8_t byte; int cs1, cs2; - int bc1, bc2; + int bc1, bc2, bc; int flen = stdFLEN; // stdFLEN=0x64, auxFLEN=0x76; M20:0x45 ? if (b2B) { @@ -699,6 +878,9 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) { bc1 = (gpx->frame_bytes[pos_BlkChk] << 8) | gpx->frame_bytes[pos_BlkChk+1]; bc2 = blk_checkM10(len_BlkChk, gpx->frame_bytes+2); // len(essentialBlock+chk16) = 0x16 + if (bc1 == bc2) bc = 1; + else if (bc1 == 0) bc = -1; + else bc = 0; switch (gpx->frame_bytes[1]) { case 0x8F: gpx->type = t_M2K2; break; @@ -732,8 +914,9 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) { } if (gpx->option.vbs) { fprintf(stdout, " # "col_Check"%04x"col_FRTXT, cs2); - if (bc1 == bc2) fprintf(stdout, " "col_CSok"(ok)"col_TXT); - else fprintf(stdout, " "col_CSno"(no)"col_TXT); + if (bc > 0) fprintf(stdout, " "col_CSok"(ok)"col_TXT); + else if (bc < 0) fprintf(stdout, " "col_CSoo"(oo)"col_TXT); + else fprintf(stdout, " "col_CSno"(no)"col_TXT); if (cs1 == cs2) fprintf(stdout, " "col_CSok"[OK]"col_TXT); else fprintf(stdout, " "col_CSno"[NO]"col_TXT); } @@ -746,13 +929,15 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) { } if (gpx->option.vbs) { fprintf(stdout, " # %04x", cs2); - if (bc1 == bc2) fprintf(stdout, " (ok)"); else fprintf(stdout, " (no)"); + if (bc > 0) fprintf(stdout, " (ok)"); + else if (bc < 0) fprintf(stdout, " (oo)"); + else fprintf(stdout, " (no)"); if (cs1 == cs2) fprintf(stdout, " [OK]"); else fprintf(stdout, " [NO]"); } fprintf(stdout, "\n"); } if (gpx->option.slt /*&& gpx->option.jsn*/) { - print_pos(gpx, bc1 == bc2, cs1 == cs2); + print_pos(gpx, bc, cs1 == cs2); } } /* @@ -766,7 +951,7 @@ static int print_frame(gpx_t *gpx, int pos, int b2B) { } } */ - else print_pos(gpx, bc1 == bc2, cs1 == cs2); + else print_pos(gpx, bc, cs1 == cs2); return (gpx->frame_bytes[0]<<8)|gpx->frame_bytes[1]; } @@ -782,6 +967,7 @@ int main(int argc, char **argv) { int option_iqdc = 0; int option_lp = 0; int option_dc = 0; + int option_noLUT = 0; int option_softin = 0; int option_pcmraw = 0; int wavloaded = 0; @@ -810,6 +996,8 @@ int main(int argc, char **argv) { float thres = 0.76; float _mv = 0.0; + float lpIQ_bw = 24e3; + int symlen = 2; int bitofs = 0; // 0 .. +2 int shift = 0; @@ -901,8 +1089,18 @@ int main(int argc, char **argv) { dsp.xlt_fq = -fq; // S(t) -> S(t)*exp(-f*2pi*I*t) option_iq = 5; } - else if (strcmp(*argv, "--lp") == 0) { option_lp = 1; } // IQ lowpass + else if (strcmp(*argv, "--lpIQ") == 0) { option_lp |= LP_IQ; } // IQ/IF lowpass + else if (strcmp(*argv, "--lpbw") == 0) { // IQ lowpass BW / kHz + double bw = 0.0; + ++argv; + if (*argv) bw = atof(*argv); + else return -1; + if (bw > 4.6 && bw < 48.0) lpIQ_bw = bw*1e3; + option_lp |= LP_IQ; + } + else if (strcmp(*argv, "--lpFM") == 0) { option_lp |= LP_FM; } // FM lowpass else if (strcmp(*argv, "--dc") == 0) { option_dc = 1; } + else if (strcmp(*argv, "--noLUT") == 0) { option_noLUT = 1; } else if (strcmp(*argv, "--min") == 0) { option_min = 1; } @@ -943,6 +1141,13 @@ int main(int argc, char **argv) { } if (!wavloaded) fp = stdin; + if (option_iq == 5 && option_dc) option_lp |= LP_FM; + + // LUT faster for decM, however frequency correction after decimation + // LUT recommonded if decM > 2 + // + if (option_noLUT && option_iq == 5) dsp.opt_nolut = 1; else dsp.opt_nolut = 0; + if (gpx.option.raw && gpx.option.jsn) gpx.option.slt = 1; @@ -1003,7 +1208,7 @@ int main(int argc, char **argv) { dsp.opt_iq = option_iq; dsp.opt_iqdc = option_iqdc; dsp.opt_lp = option_lp; - dsp.lpIQ_bw = 24e3; // IF lowpass bandwidth + dsp.lpIQ_bw = lpIQ_bw; //24e3; // IF lowpass bandwidth dsp.lpFM_bw = 10e3; // FM audio lowpass dsp.opt_dc = option_dc; dsp.opt_IFmin = option_min;