diff --git a/demod/mod/demod_mod.c b/demod/mod/demod_mod.c index a75396e..1d6504d 100644 --- a/demod/mod/demod_mod.c +++ b/demod/mod/demod_mod.c @@ -835,7 +835,7 @@ int read_slbit(dsp_t *dsp, int *bit, int inv, int ofs, int pos, float l, int spi } sample -= dc; - if ( l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum -= sample; + if (l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum -= sample; dsp->sc++; } while (dsp->sc < bg); // n < dsp->sps @@ -853,9 +853,9 @@ int read_slbit(dsp_t *dsp, int *bit, int inv, int ofs, int pos, float l, int spi +dsp->bufs[(dsp->sample_out-dsp->buffered+1 + ofs + dsp->M) % dsp->M]); sample = avg + scale*(sample - avg); // spikes } - sample -= dc; + sample -= dc; - if ( l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum += sample; + if (l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum += sample; dsp->sc++; } while (dsp->sc < bg); // n < dsp->sps @@ -867,6 +867,81 @@ int read_slbit(dsp_t *dsp, int *bit, int inv, int ofs, int pos, float l, int spi return 0; } +int read_softbit(dsp_t *dsp, hsbit_t *shb, int inv, int ofs, int pos, float l, int spike) { +// symlen==2: manchester2 10->0,01->1: 2.bit + + float sample; + float avg; + float ths = 0.5, scale = 0.27; + + double sum = 0.0; + double mid; + //double l = 1.0; + + double bg = pos*dsp->symlen*dsp->sps; + double dc = 0.0; + + ui8_t bit = 0; + + + if (dsp->opt_dc && dsp->opt_iq < 2) dc = dsp->dc; + + if (pos == 0) { + bg = 0; + dsp->sc = 0; + } + + + if (dsp->symlen == 2) { + mid = bg + (dsp->sps-1)/2.0; + bg += dsp->sps; + do { + if (dsp->buffered > 0) dsp->buffered -= 1; + else if (f32buf_sample(dsp, inv) == EOF) return EOF; + + sample = dsp->bufs[(dsp->sample_out-dsp->buffered + ofs + dsp->M) % dsp->M]; + if (spike && fabs(sample - avg) > ths) { + 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]); + sample = avg + scale*(sample - avg); // spikes + } + sample -= dc; + + if (l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum -= sample; + + dsp->sc++; + } while (dsp->sc < bg); // n < dsp->sps + } + + mid = bg + (dsp->sps-1)/2.0; + bg += dsp->sps; + do { + if (dsp->buffered > 0) dsp->buffered -= 1; + else if (f32buf_sample(dsp, inv) == EOF) return EOF; + + sample = dsp->bufs[(dsp->sample_out-dsp->buffered + ofs + dsp->M) % dsp->M]; + if (spike && fabs(sample - avg) > ths) { + 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]); + sample = avg + scale*(sample - avg); // spikes + } + sample -= dc; + + if (l < 0 || (mid-l < dsp->sc && dsp->sc < mid+l)) sum += sample; + + dsp->sc++; + } while (dsp->sc < bg); // n < dsp->sps + + + if (sum >= 0) bit = 1; + else bit = 0; + + shb->hb = bit; + shb->sb = (float)sum; + + return 0; +} + /* -------------------------------------------------------------------------- */ #define IF_SAMPLE_RATE 48000 diff --git a/demod/mod/demod_mod.h b/demod/mod/demod_mod.h index a1cc1ae..bfe3a14 100644 --- a/demod/mod/demod_mod.h +++ b/demod/mod/demod_mod.h @@ -138,10 +138,17 @@ typedef struct { } pcm_t; +typedef struct { + ui8_t hb; + float sb; +} hsbit_t; + + float read_wav_header(pcm_t *, FILE *); int f32buf_sample(dsp_t *, int); int read_slbit(dsp_t *, int*, int, int, int, float, int); +int read_softbit(dsp_t *, hsbit_t *, int, int, int, float, int ); int init_buffers(dsp_t *); int free_buffers(dsp_t *); diff --git a/demod/mod/dfm09mod.c b/demod/mod/dfm09mod.c index e5d21c7..f101a37 100644 --- a/demod/mod/dfm09mod.c +++ b/demod/mod/dfm09mod.c @@ -68,7 +68,7 @@ typedef struct { float status[2]; float _frmcnt; char sonde_id[16]; // "ID__:xxxxxxxx\0\0" - char frame_bits[BITFRAME_LEN+4]; + hsbit_t frame[BITFRAME_LEN+4]; // char frame_bits[BITFRAME_LEN+4]; char dat_str[9][13+1]; sn_t snc; pcksts_t pck[9]; @@ -98,6 +98,15 @@ static char dfm_header[] = "0100010111001111"; #define DAT2 (16+160) // 104 bit // frame: 280 bit +static ui8_t G[8][4] = // Generator + {{ 1, 0, 0, 0}, + { 0, 1, 0, 0}, + { 0, 0, 1, 0}, + { 0, 0, 0, 1}, + { 0, 1, 1, 1}, + { 1, 0, 1, 1}, + { 1, 1, 0, 1}, + { 1, 1, 1, 0}}; static ui8_t H[4][8] = // Parity-Check {{ 0, 1, 1, 1, 1, 0, 0, 0}, { 1, 0, 1, 1, 0, 1, 0, 0}, @@ -105,6 +114,28 @@ static ui8_t H[4][8] = // Parity-Check { 1, 1, 1, 0, 0, 0, 0, 1}}; static ui8_t He[8] = { 0x7, 0xB, 0xD, 0xE, 0x8, 0x4, 0x2, 0x1}; // Spalten von H: // 1-bit-error-Syndrome +static ui8_t codewords[16][8]; // (valid) Hamming codewords + +static int nib4bits(ui8_t nib, ui8_t *bits) { // big endian + int j; + + nib &= 0xF; + for (j = 0; j < 4; j++) { + bits[j] = (nib>>(3-j)) & 0x1; + } + return 0; +} + +static int gencode(ui8_t msg[4], ui8_t code[8]) { + int i, j; // Gm=c + for (i = 0; i < 8; i++) { + code[i] = 0; + for (j = 0; j < 4; j++) { + code[i] ^= G[i][j] & msg[j]; + } + } + return 0; +} static ui32_t bits2val(ui8_t *bits, int len) { // big endian int j; @@ -117,18 +148,16 @@ static ui32_t bits2val(ui8_t *bits, int len) { // big endian return val; } -static void deinterleave(char *str, int L, ui8_t *block) { +static void deinterleave(hsbit_t *str, int L, hsbit_t *block) { int i, j; for (j = 0; j < B; j++) { // L = 7, 13 for (i = 0; i < L; i++) { - if (str[L*j+i] >= 0x30 && str[L*j+i] <= 0x31) { - block[B*i+j] = str[L*j+i] - 0x30; // ASCII -> bit - } + block[B*i+j] = str[L*j+i]; } } } -static int check(ui8_t code[8]) { +static int check(int opt_ecc, hsbit_t code[8]) { int i, j; // Bei Demodulierung durch Nulldurchgaenge, wenn durch Fehler ausser Takt, ui32_t synval = 0; // verschieben sich die bits. Fuer Hamming-Decode waere es besser, ui8_t syndrom[4]; // sync zu Beginn mit Header und dann Takt beibehalten fuer decision. @@ -137,7 +166,7 @@ static int check(ui8_t code[8]) { for (i = 0; i < 4; i++) { // S = 4 syndrom[i] = 0; for (j = 0; j < 8; j++) { // B = 8 - syndrom[i] ^= H[i][j] & code[j]; + syndrom[i] ^= H[i][j] & code[j].hb; } } synval = bits2val(syndrom, 4); @@ -151,22 +180,64 @@ static int check(ui8_t code[8]) { } } else ret = 0; - if (ret > 0) code[ret-1] ^= 0x1; + + if (ret > 0) code[ret-1].hb ^= 0x1; // d=1: 1-bit-error + else if (ret < 0 && opt_ecc == 2) { // d=2: 2-bit-error: soft decision + // Hamming [8,4] + // 256 words: + // 16 codewords + // 16*8=128 1-error words (dist=1) + // 16*7=112 2-error words (dist=2) + // each 2-error word has 4 codewords w/ dist=2 + // choose best "correlation" + int n; + int maxn = -1; + int d = 0; + float sum = 0.0; + float maxsum = 0.0; + for (i = 0; i < 8; i++) { + sum += (2*code[i].hb-1) * code[i].sb; + } + for (n = 0; n < 16; n++) { + d = 0; + sum = 0.0; + for (i = 0; i < 8; i++) { // d(a,b) = sum_i a[i]^b[i] + if (code[i].hb != codewords[n][i]) d++; + } + if (d == 2) { // dist=2 + // softbits correlation: + // - interleaving + // + no pulse-shaping -> sum + for (i = 0; i < 8; i++) { + sum += (2*codewords[n][i]-1) * code[i].sb; + } + if (sum*sum >= maxsum*maxsum) { + maxsum = sum; + maxn = n; + } + } + } + if (maxn >= 0) { + for (i = 0; i < 8; i++) { + if (code[i].hb = codewords[maxn][i]); + } + } + } return ret; } -static int hamming(int opt_ecc, ui8_t *ham, int L, ui8_t *sym) { +static int hamming(int opt_ecc, hsbit_t *ham, int L, ui8_t *sym) { int i, j; int ecc = 0, ret = 0; // L = 7, 13 for (i = 0; i < L; i++) { // L * 2 nibble (data+parity) if (opt_ecc) { - ecc = check(ham+B*i); + ecc = check(opt_ecc, ham+B*i); if (ecc > 0) ret |= (1<frame_bits+CONF, 7, hamming_conf); - deinterleave(gpx->frame_bits+DAT1, 13, hamming_dat1); - deinterleave(gpx->frame_bits+DAT2, 13, hamming_dat2); + deinterleave(gpx->frame+CONF, 7, hamming_conf); + deinterleave(gpx->frame+DAT1, 13, hamming_dat1); + deinterleave(gpx->frame+DAT2, 13, hamming_dat2); ret0 = hamming(gpx->option.ecc, hamming_conf, 7, block_conf); ret1 = hamming(gpx->option.ecc, hamming_dat1, 13, block_dat1); @@ -750,14 +821,14 @@ static int print_frame(gpx_t *gpx) { } else if (gpx->option.ecc) { - if (ret0 == 0 || ret0 > 0) { + if (ret0 == 0 || ret0 > 0 || gpx->option.ecc == 2) { conf_out(gpx, block_conf, ret0); } - if (ret1 == 0 || ret1 > 0) { + if (ret1 == 0 || ret1 > 0 || gpx->option.ecc == 2) { frid = dat_out(gpx, block_dat1, ret1); if (frid == 8) print_gpx(gpx); } - if (ret2 == 0 || ret2 > 0) { + if (ret2 == 0 || ret2 > 0 || gpx->option.ecc == 2) { frid = dat_out(gpx, block_dat2, ret2); if (frid == 8) print_gpx(gpx); } @@ -866,7 +937,7 @@ int main(int argc, char **argv) { int ret = 0; int k; - int bit; + hsbit_t hsbit; int bitpos = 0; int bitQ; int pos; @@ -926,7 +997,8 @@ int main(int argc, char **argv) { else if ( (strcmp(*argv, "-i") == 0) || (strcmp(*argv, "--invert") == 0) ) { option_inv = 0x1; } - else if ( (strcmp(*argv, "--ecc") == 0) ) { option_ecc = 1; } + else if ( (strcmp(*argv, "--ecc" ) == 0) ) { option_ecc = 1; } + else if ( (strcmp(*argv, "--ecc2") == 0) ) { option_ecc = 2; } else if ( (strcmp(*argv, "--ptu") == 0) ) { option_ptu = 1; //gpx.ptu_out = 1; // force ptu (non PS-15) @@ -1002,9 +1074,26 @@ int main(int argc, char **argv) { } if (!wavloaded) fp = stdin; + if ( option_dist || option_json ) option_ecc = 1; + + + if (option_ecc) + { + ui8_t nib, msg[4], code[8]; + for (nib = 0; nib < 16; nib++) { + nib4bits(nib, msg); + gencode(msg, code); + for (k = 0; k < 8; k++) codewords[nib][k] = code[k]; + } + } // init gpx - strcpy(gpx.frame_bits, dfm_header); //, sizeof(dfm_header); + //strcpy(gpx.frame_bits, dfm_header); //, sizeof(dfm_header); + for (k = 0; k < strlen(dfm_header); k++) { + gpx.frame[k].hb = dfm_header[k] & 1; + gpx.frame[k].sb = 2*gpx.frame[k].hb - 1; + } + for (k = 0; k < 9; k++) gpx.pck[k].ec = -1; // init ecc-status gpx.option.inv = option_inv; @@ -1093,89 +1182,92 @@ int main(int argc, char **argv) { bitofs += shift; - while ( 1 ) + while ( 1 ) + { + if (option_bin) { // aka find_binrawhead() + header_found = find_binhead(fp, &hdb, &_mv); // symbols or bits? + hdrcnt += nfrms; + } + else { // FM-audio: + header_found = find_header(&dsp, thres, 2, bitofs, dsp.opt_dc); // optional 2nd pass: dc=0 + _mv = dsp.mv; + } + if (header_found == EOF) break; + + // mv == correlation score + if (_mv *(0.5-gpx.option.inv) < 0) { + if (gpx.option.aut == 0) header_found = 0; + else gpx.option.inv ^= 0x1; + } + + if (header_found) { - if (option_bin) { // aka find_binrawhead() - header_found = find_binhead(fp, &hdb, &_mv); // symbols or bits? - hdrcnt += nfrms; - } - else { // FM-audio: - header_found = find_header(&dsp, thres, 2, bitofs, dsp.opt_dc); // optional 2nd pass: dc=0 - _mv = dsp.mv; - } - if (header_found == EOF) break; + bitpos = 0; + pos = headerlen; + pos /= 2; - // mv == correlation score - if (_mv *(0.5-gpx.option.inv) < 0) { - if (gpx.option.aut == 0) header_found = 0; - else gpx.option.inv ^= 0x1; - } + //if (fabs(mv) > 0.85) nfrms = 8; else nfrms = 4; // test OK/KO/NO count - if (header_found) - { - bitpos = 0; - pos = headerlen; - pos /= 2; - - //if (fabs(mv) > 0.85) nfrms = 8; else nfrms = 4; // test OK/KO/NO count - - frm = 0; - while ( frm < nfrms ) { // nfrms=1,2,4,8 + frm = 0; + while ( frm < nfrms ) { // nfrms=1,2,4,8 + if (option_bin) { + gpx._frmcnt = hdrcnt + frm; + } + else { + gpx._frmcnt = dsp.mv_pos/(2.0*dsp.sps*BITFRAME_LEN) + frm; + } + while ( pos < BITFRAME_LEN ) + { if (option_bin) { - gpx._frmcnt = hdrcnt + frm; + // symbols or bits? + // manchester1 1->10,0->01: 1.bit (DFM-06) + // manchester2 0->10,1->01: 2.bit (DFM-09) + bitQ = fgetc(fp); + if (bitQ != EOF) { + hsbit.hb = bitQ & 0x1; + bitQ = fgetc(fp); // check: rbit0^rbit1=1 (Manchester) + if (bitQ != EOF) hsbit.hb = bitQ & 0x1; // 2.bit (DFM-09) + hsbit.sb = 2*hsbit.hb - 1; + } } else { - gpx._frmcnt = dsp.mv_pos/(2.0*dsp.sps*BITFRAME_LEN) + frm; - } - while ( pos < BITFRAME_LEN ) - { - if (option_bin) { - // symbols or bits? - // manchester1 1->10,0->01: 1.bit (DFM-06) - // manchester2 0->10,1->01: 2.bit (DFM-09) - bitQ = fgetc(fp); - if (bitQ != EOF) { - bit = bitQ & 0x1; - bitQ = fgetc(fp); // check: rbit0^rbit1=1 (Manchester) - if (bitQ != EOF) bit = bitQ & 0x1; // 2.bit (DFM-09) - } + if (option_iq >= 2) { + float bl = -1; + if (option_iq > 2) bl = 4.0; + bitQ = read_softbit(&dsp, &hsbit, 0/*gpx.option.inv*/, bitofs, bitpos, bl, 0); } else { - if (option_iq >= 2) { - float bl = -1; - if (option_iq > 2) bl = 4.0; - bitQ = read_slbit(&dsp, &bit, 0/*gpx.option.inv*/, bitofs, bitpos, bl, 0); - } - else { - bitQ = read_slbit(&dsp, &bit, 0/*gpx.option.inv*/, bitofs, bitpos, -1, spike); - } + bitQ = read_softbit(&dsp, &hsbit, 0/*gpx.option.inv*/, bitofs, bitpos, -1, spike); } - if ( bitQ == EOF ) { frm = nfrms; break; } // liest 2x EOF - - if (gpx.option.inv) bit ^= 1; - - gpx.frame_bits[pos] = 0x30 + bit; - pos++; - bitpos += 1; } - gpx.frame_bits[pos] = '\0'; + if ( bitQ == EOF ) { frm = nfrms; break; } // liest 2x EOF - ret = print_frame(&gpx); - if (pos < BITFRAME_LEN) break; - pos = 0; - frm += 1; - //if (ret < 0) frms += 1; + if (gpx.option.inv) { + hsbit.hb ^= 1; + hsbit.sb = -hsbit.sb; + } + + gpx.frame[pos] = hsbit; + pos++; + bitpos += 1; } + + ret = print_frame(&gpx); + if (pos < BITFRAME_LEN) break; + pos = 0; + frm += 1; + //if (ret < 0) frms += 1; } - - header_found = 0; - pos = headerlen; } - if (!option_bin) free_buffers(&dsp); - else { - if (hdb.buf) { free(hdb.buf); hdb.buf = NULL; } - } + header_found = 0; + pos = headerlen; + } + + if (!option_bin) free_buffers(&dsp); + else { + if (hdb.buf) { free(hdb.buf); hdb.buf = NULL; } + } fclose(fp);