MP3-H1 mod: (P)TU v0.1

pull/37/head
Zilog80 2021-03-18 23:41:53 +01:00
rodzic 9faed57afe
commit ff74eae6f2
1 zmienionych plików z 316 dodań i 169 usunięć

Wyświetl plik

@ -78,14 +78,17 @@ typedef struct {
double lat; double lon; double alt;
double vH; double vD; double vV;
ui8_t numSats;
float calA;
float calB;
float calC;
float calA; // A(ntc)
float calB; // B(ntc)
float calC; // C(ntc)
float A_adcT; float B_adcT; float C_adcT;
float A_adcH; float B_adcH; float C_adcH;
ui8_t frame[FRAME_LEN+16];
char frame_bits[BITFRAME_LEN+16];
ui32_t cfg[16];
ui32_t snC;
ui32_t snD;
float T; float RH;
ui8_t crcOK;
//
int sec_day;
@ -246,6 +249,8 @@ static i16_t i2(ui8_t *bytes) { // 16bit signed int
#define pos_GPSecefZ (OFS+16) // 4 byte
#define pos_GPSecefV (OFS+20) // 3*2 byte
#define pos_GPSnSats (OFS+26) // 1 byte (num Sats ?)
#define pos_PTU1 (OFS+35) // 4 byte
#define pos_PTU2 (OFS+39) // 4 byte
#define pos_CNT2 (OFS+43) // 1 byte (0x01..0x10 ?)
#define pos_CFG (OFS+44) // 2/4 byte
#define pos_CRC (OFS+48) // 2 byte
@ -416,6 +421,52 @@ static int get_time(gpx_t *gpx) {
return 0;
}
static float f32(ui32_t w) {
float f = 0.0f;
memcpy(&f, &w, 4);
return f;
}
static int get_ptu(gpx_t *gpx) {
float t = -273.15f;
float rh = -1.0f;
float ADC_MAX = 32767.0; //32767=(1<<15)? 32767?
int ADCT = u4(gpx->frame+pos_PTU1); // u3?
float adc_t = ADCT/100.0;
int ADCH = u4(gpx->frame+pos_PTU2); // u3?
float adc_h = ADCH/100.0;
if (gpx->calA*gpx->calB*gpx->calC > 0)
{
if (gpx->A_adcT*gpx->B_adcT*gpx->C_adcT > 0.0) {
float poly1 = adc_t*adc_t * gpx->A_adcT + adc_t * gpx->B_adcT + gpx->C_adcT;
float Rt = 100000.0*poly1 / (ADC_MAX - poly1);
if (Rt > 0.0) {
t = gpx->calB/log(Rt/gpx->calA) - gpx->calC - 273.15f;
}
}
}
gpx->T = t;
if (gpx->T > -273.0f)
{
if (gpx->A_adcH*gpx->B_adcH*gpx->C_adcH > 0.0) { // double?
float poly2 = adc_h*adc_h * gpx->A_adcH + adc_h * gpx->B_adcH + gpx->A_adcH;
float K = poly2/ADC_MAX;
rh = (K - 0.1515) / (0.00636*(1.05460 - 0.00216*gpx->T)); // if T = 273.15, set T=0 ?
}
}
gpx->RH = rh;
return 0;
}
static int get_cfg(gpx_t *gpx) {
gpx->subcnt1 = (gpx->frame[pos_CNT1] & 0xF);
@ -427,15 +478,37 @@ static int get_cfg(gpx_t *gpx) {
gpx->cfg[gpx->subcnt1] = cfg32;
switch (gpx->subcnt1) { // or use subcnt2 ?
// T-ntc A, B, C
case 0x0: //sub2=0x01:
memcpy(&gpx->calA, &cfg32, 4);
gpx->calA = f32(cfg32); //memcpy(&gpx->calA, &cfg32, 4);
break;
case 0x1: //sub2=0x02:
memcpy(&gpx->calB, &cfg32, 4);
gpx->calB = f32(cfg32); //memcpy(&gpx->calB, &cfg32, 4);
break;
case 0x2: //sub2=0x03:
memcpy(&gpx->calC, &cfg32, 4);
gpx->calC = f32(cfg32); //memcpy(&gpx->calC, &cfg32, 4);
break;
// ADC1/ADC_T calib ?
case 0x3: //sub2=0x04:
gpx->A_adcT = f32(cfg32);
break;
case 0x4: //sub2=0x05:
gpx->B_adcT = f32(cfg32);
break;
case 0x5: //sub2=0x06:
gpx->C_adcT = f32(cfg32);
break;
// ADC2/ADC_H calib ?
case 0x6: //sub2=0x07:
gpx->A_adcH = f32(cfg32);
break;
case 0x7: //sub2=0x08:
gpx->B_adcH = f32(cfg32);
break;
case 0x8: //sub2=0x09:
gpx->C_adcH = f32(cfg32);
break;
// radiosonde/GNSS SN
case 0xC: //sub2=0x0D: SN GLONASS/GPS ?
if (cfg32 != gpx->snC && gpx->snC > 0) {
//reset_cfg
@ -444,6 +517,7 @@ static int get_cfg(gpx_t *gpx) {
}
gpx->snC = cfg32; // 16 or 32 bit ?
break;
// sensor SN
case 0xD: //sub2=0x0E: SN sensor boom ?
if (cfg32 != gpx->snD && gpx->snD > 0) {
//reset_cfg
@ -452,8 +526,10 @@ static int get_cfg(gpx_t *gpx) {
}
gpx->snD = cfg32; // 16 or 32 bit ?
break;
// sensor date
case 0xE: //sub2=0x0F: calib date ?
break;
// date
case 0xF: //sub2=0x10: date
gpx->yr = cfg32 % 100;
gpx->yr += 2000;
@ -488,6 +564,8 @@ static void print_gpx(gpx_t *gpx, int crcOK) {
get_time(gpx);
get_GPSkoord(gpx);
get_ptu(gpx);
if (gpx->sec_day != gpx->sec_day_prev || !gpx->option.unq)
{
printf(" [%2d] ", gpx->subcnt1);
@ -500,6 +578,13 @@ static void print_gpx(gpx_t *gpx, int crcOK) {
printf(" vH: %4.1f D: %5.1f vV: %3.1f ", gpx->vH, gpx->vD, gpx->vV);
if (gpx->option.vbs > 1) printf(" sats: %d ", gpx->numSats);
if (gpx->option.ptu) {
if (gpx->T > -273.0f || gpx->RH > -0.5f) printf(" ");
if (gpx->T > -273.0f) printf(" T=%.1fC", gpx->T);
if (gpx->RH > -0.5f) printf(" RH=%.0f%%", gpx->RH);
if (gpx->T > -273.0f || gpx->RH > -0.5f) printf(" ");
}
if (gpx->option.col) {
if (gpx->crcOK) printf(" "col_CSok"[OK]"ANSI_COLOR_RESET);
else printf(" "col_CSno"[NO]"ANSI_COLOR_RESET);
@ -530,12 +615,12 @@ static void print_gpx(gpx_t *gpx, int crcOK) {
if (gpx->option.dbg)
{
printf(" : ");
printf(" [0x%X:0x%02X]", gpx->subcnt1, gpx->subcnt2);
//printf(" [0x%X:0x%02X]", gpx->subcnt1, gpx->subcnt2);
printf(" 0x%08X =", gpx->cfg[gpx->subcnt1]);
if (gpx->subcnt1 > 0x8) printf(" %u ", gpx->cfg[gpx->subcnt1]); // 0x9,0xA not const
else {
float *f = (float*)(gpx->cfg+gpx->subcnt1);
printf(" %.4f ", *f);
printf(" %g ", *f);
}
}
}
@ -563,6 +648,14 @@ static void print_gpx(gpx_t *gpx, int crcOK) {
printf(", \"frame\": %lu, ", (unsigned long)gpx->gps_cnt); // sec_gps0+0.5
printf("\"id\": \"MRZ-%d-%d\", \"datetime\": \"%04d-%02d-%02dT%02d:%02d:%02dZ\", \"lat\": %.5f, \"lon\": %.5f, \"alt\": %.5f, \"vel_h\": %.5f, \"heading\": %.5f, \"vel_v\": %.5f, \"sats\": %d",
gpx->snC, gpx->snD, gpx->yr, gpx->mth, gpx->day, gpx->hrs, gpx->min, gpx->sec, gpx->lat, gpx->lon, gpx->alt, gpx->vH, gpx->vD, gpx->vV, gpx->numSats);
if (gpx->option.ptu) {
if (gpx->T > -273.0) {
fprintf(stdout, ", \"temp\": %.1f", gpx->T );
}
if (gpx->RH > -0.5) {
fprintf(stdout, ", \"humidity\": %.1f", gpx->RH );
}
}
if (gpx->jsn_freq > 0) {
printf(", \"freq\": %d", gpx->jsn_freq);
}
@ -577,31 +670,57 @@ static void print_gpx(gpx_t *gpx, int crcOK) {
}
static void print_frame(gpx_t *gpx, int pos) {
static void print_frame(gpx_t *gpx, int pos, int b2B) {
int j;
int crcOK = 0;
static int frame_count = 0;
if (gpx->option.raw == 2) {
//printf(" :%6.1f: ", sample_count/(double)sample_rate);
//
for (j = 0; j < pos; j++) {
printf("%c", gpx->frame_bits[j]);
if (b2B)
{
if (gpx->option.raw == 2) {
//printf(" :%6.1f: ", sample_count/(double)sample_rate);
//
for (j = 0; j < pos; j++) {
printf("%c", gpx->frame_bits[j]);
}
//if (frame_count % 3 == 2)
{
printf("\n");
}
}
//if (frame_count % 3 == 2)
{
printf("\n");
else {
int frmlen = (pos-bits_ofs)/8;
bits2bytes(gpx->frame_bits+bits_ofs, gpx->frame, frmlen);
crcOK = (check_CRC(gpx) == 0);
if (gpx->option.raw == 1) {
//printf(" :%6.1f: ", sample_count/(double)sample_rate);
//
for (j = 0; j < frmlen; j++) {
printf("%02X ", gpx->frame[j]);
}
printf(" %s", crcOK ? "[OK]" : "[NO]");
printf("\n");
}
else {
//if (frame_count % 3 == 0)
{
if (pos/8 > pos_GPSecefV+6) print_gpx(gpx, crcOK);
}
}
}
}
else {
int frmlen = (pos-bits_ofs)/8;
bits2bytes(gpx->frame_bits+bits_ofs, gpx->frame, frmlen);
else
{
int frmlen = pos;
crcOK = (check_CRC(gpx) == 0);
if (gpx->option.raw == 1) {
if (gpx->option.raw) {
//printf(" :%6.1f: ", sample_count/(double)sample_rate);
//
for (j = 0; j < frmlen; j++) {
@ -611,11 +730,7 @@ static void print_frame(gpx_t *gpx, int pos) {
printf("\n");
}
else {
//if (frame_count % 3 == 0)
{
if (pos/8 > pos_GPSecefV+6) print_gpx(gpx, crcOK);
}
if (pos > pos_GPSecefV+6) print_gpx(gpx, crcOK);
}
}
@ -643,6 +758,7 @@ int main(int argc, char **argv) {
int option_pcmraw = 0;
int wavloaded = 0;
int sel_wavch = 0; // audio channel: left
int rawhex = 0;
int k;
int bitQ;
@ -772,6 +888,7 @@ int main(int argc, char **argv) {
if (frq < 300000000) frq = -1;
cfreq = frq;
}
else if (strcmp(*argv, "--rawhex") == 0) { rawhex = 3; } // raw hex input
else if (strcmp(*argv, "-") == 0) {
int sample_rate = 0, bits_sample = 0, channels = 0;
++argv;
@ -811,173 +928,203 @@ int main(int argc, char **argv) {
}
#endif
if (!option_softin) {
if (!rawhex) {
if (option_iq == 0 && option_pcmraw) {
fclose(fp);
fprintf(stderr, "error: raw data not IQ\n");
return -1;
}
if (option_iq) sel_wavch = 0;
if (!option_softin) {
pcm.sel_ch = sel_wavch;
if (option_pcmraw == 0) {
k = read_wav_header(&pcm, fp);
if ( k < 0 ) {
if (option_iq == 0 && option_pcmraw) {
fclose(fp);
fprintf(stderr, "error: wav header\n");
fprintf(stderr, "error: raw data not IQ\n");
return -1;
}
if (option_iq) sel_wavch = 0;
pcm.sel_ch = sel_wavch;
if (option_pcmraw == 0) {
k = read_wav_header(&pcm, fp);
if ( k < 0 ) {
fclose(fp);
fprintf(stderr, "error: wav header\n");
return -1;
}
}
if (cfreq > 0) {
int fq_kHz = (cfreq - dsp.xlt_fq*pcm.sr + 500)/1e3;
gpx.jsn_freq = fq_kHz;
}
// mrz-n1: BT=1.0, h=2.0 ?
symlen = 2;
// init dsp
//
dsp.fp = fp;
dsp.sr = pcm.sr;
dsp.bps = pcm.bps;
dsp.nch = pcm.nch;
dsp.ch = pcm.sel_ch;
dsp.br = (float)BAUD_RATE;
dsp.sps = (float)dsp.sr/dsp.br;
dsp.symlen = symlen;
dsp.symhd = symlen;
dsp._spb = dsp.sps*symlen;
dsp.hdr = mrz_header;
dsp.hdrlen = strlen(mrz_header);
dsp.BT = 1.0; // bw/time (ISI) // 1.0..2.0 // TODO
dsp.h = 2.0; // // 1.5..2.5? modulation index abzgl. BT // TODO
dsp.opt_iq = option_iq;
dsp.opt_iqdc = option_iqdc;
dsp.opt_lp = option_lp;
dsp.lpIQ_bw = lpIQ_bw; // 9.0e3 (8e3..10e3) // IF lowpass bandwidth
dsp.lpFM_bw = 6e3; // FM audio lowpass
dsp.opt_dc = option_dc;
dsp.opt_IFmin = option_min;
if ( dsp.sps < 5 ) {
fprintf(stderr, "note: sample rate low (%.1f sps)\n", dsp.sps);
}
if (baudrate > 0) {
dsp.br = (float)baudrate;
dsp.sps = (float)dsp.sr/dsp.br;
fprintf(stderr, "sps corr: %.4f\n", dsp.sps);
}
k = init_buffers(&dsp);
if ( k < 0 ) {
fprintf(stderr, "error: init buffers\n");
return -1;
}
//if (option_iq >= 2) bitofs += 1; // FM: +1 , IQ: +2
bitofs += shift;
}
else {
// init circular header bit buffer
hdb.hdr = mrz_header;
hdb.len = strlen(mrz_header);
//hdb.thb = 1.0 - 3.1/(float)hdb.len; // 1.0-max_bit_errors/hdrlen
hdb.bufpos = -1;
hdb.buf = NULL;
/*
calloc(hdb.len, sizeof(char));
if (hdb.buf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
*/
hdb.ths = 0.82; // caution 0.8: false positive / offset
hdb.sbuf = calloc(hdb.len, sizeof(float));
if (hdb.sbuf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
}
if (cfreq > 0) {
int fq_kHz = (cfreq - dsp.xlt_fq*pcm.sr + 500)/1e3;
gpx.jsn_freq = fq_kHz;
}
// mrz-n1: BT=1.0, h=2.0 ?
symlen = 2;
manchester1(mrz_header, gpx.frame_bits, HEADLEN); // HEADLEN==FRAMESTART
// init dsp
//
dsp.fp = fp;
dsp.sr = pcm.sr;
dsp.bps = pcm.bps;
dsp.nch = pcm.nch;
dsp.ch = pcm.sel_ch;
dsp.br = (float)BAUD_RATE;
dsp.sps = (float)dsp.sr/dsp.br;
dsp.symlen = symlen;
dsp.symhd = symlen;
dsp._spb = dsp.sps*symlen;
dsp.hdr = mrz_header;
dsp.hdrlen = strlen(mrz_header);
dsp.BT = 1.0; // bw/time (ISI) // 1.0..2.0 // TODO
dsp.h = 2.0; // // 1.5..2.5? modulation index abzgl. BT // TODO
dsp.opt_iq = option_iq;
dsp.opt_iqdc = option_iqdc;
dsp.opt_lp = option_lp;
dsp.lpIQ_bw = lpIQ_bw; // 9.0e3 (8e3..10e3) // IF lowpass bandwidth
dsp.lpFM_bw = 6e3; // FM audio lowpass
dsp.opt_dc = option_dc;
dsp.opt_IFmin = option_min;
if ( dsp.sps < 5 ) {
fprintf(stderr, "note: sample rate low (%.1f sps)\n", dsp.sps);
}
if (baudrate > 0) {
dsp.br = (float)baudrate;
dsp.sps = (float)dsp.sr/dsp.br;
fprintf(stderr, "sps corr: %.4f\n", dsp.sps);
}
k = init_buffers(&dsp);
if ( k < 0 ) {
fprintf(stderr, "error: init buffers\n");
return -1;
}
//if (option_iq >= 2) bitofs += 1; // FM: +1 , IQ: +2
bitofs += shift;
}
else {
// init circular header bit buffer
hdb.hdr = mrz_header;
hdb.len = strlen(mrz_header);
//hdb.thb = 1.0 - 3.1/(float)hdb.len; // 1.0-max_bit_errors/hdrlen
hdb.bufpos = -1;
hdb.buf = NULL;
/*
calloc(hdb.len, sizeof(char));
if (hdb.buf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
*/
hdb.ths = 0.82; // caution 0.8: false positive / offset
hdb.sbuf = calloc(hdb.len, sizeof(float));
if (hdb.sbuf == NULL) {
fprintf(stderr, "error: malloc\n");
return -1;
}
}
manchester1(mrz_header, gpx.frame_bits, HEADLEN); // HEADLEN==FRAMESTART
while ( 1 )
{
if (option_softin) {
header_found = find_softbinhead(fp, &hdb, &_mv);
}
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)
while ( 1 )
{
bitpos = 0;
pos = FRAMESTART/2;
if (option_softin) {
header_found = find_softbinhead(fp, &hdb, &_mv);
}
else { // FM-audio:
header_found = find_header(&dsp, thres, 2, bitofs, dsp.opt_dc); // optional 2nd pass: dc=0
_mv = dsp.mv;
}
while ( pos < BITFRAME_LEN )
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_softin) {
float s1 = 0.0;
float s2 = 0.0;
float s = 0.0;
bitQ = f32soft_read(fp, &s1);
if (bitQ != EOF) {
bitQ = f32soft_read(fp, &s2);
bitpos = 0;
pos = FRAMESTART/2;
while ( pos < BITFRAME_LEN )
{
if (option_softin) {
float s1 = 0.0;
float s2 = 0.0;
float s = 0.0;
bitQ = f32soft_read(fp, &s1);
if (bitQ != EOF) {
s = s2-s1; // integrate both symbols // Manchester2=s2 (invert to Manchester1=s1 below)
bit = (s>=0.0); // no soft decoding
hsbit.hb = bit;
hsbit.sb = s;
bitQ = f32soft_read(fp, &s2);
if (bitQ != EOF) {
s = s2-s1; // integrate both symbols // Manchester2=s2 (invert to Manchester1=s1 below)
bit = (s>=0.0); // no soft decoding
hsbit.hb = bit;
hsbit.sb = s;
}
}
}
}
else {
float bl = -1;
if (option_iq > 2) bl = 2.0;
//bitQ = read_slbit(&dsp, &bit, 0, bitofs, bitpos, bl, 0); // symlen=2
bitQ = read_softbit2p(&dsp, &hsbit, 0, bitofs, bitpos, bl, 0, &hsbit1); // symlen=2
bit = hsbit.hb;
}
if ( bitQ == EOF ) break; // liest 2x EOF
else {
float bl = -1;
if (option_iq > 2) bl = 2.0;
//bitQ = read_slbit(&dsp, &bit, 0, bitofs, bitpos, bl, 0); // symlen=2
bitQ = read_softbit2p(&dsp, &hsbit, 0, bitofs, bitpos, bl, 0, &hsbit1); // symlen=2
bit = hsbit.hb;
}
if ( bitQ == EOF ) break; // liest 2x EOF
if (!gpx.option.inv) { // Manchester1
hsbit.hb ^= 1;
hsbit.sb = -hsbit.sb;
bit ^= 1;
if (!gpx.option.inv) { // Manchester1
hsbit.hb ^= 1;
hsbit.sb = -hsbit.sb;
bit ^= 1;
}
gpx.frame_bits[pos] = 0x30 + (hsbit.hb & 1);
bitpos += 1;
pos++;
}
gpx.frame_bits[pos] = '\0';
gpx.frame_bits[pos] = 0x30 + (hsbit.hb & 1);
print_frame(&gpx, pos, 1);
if (pos < BITFRAME_LEN) break;
header_found = 0;
bitpos += 1;
pos++;
}
gpx.frame_bits[pos] = '\0';
print_frame(&gpx, pos);
if (pos < BITFRAME_LEN) break;
header_found = 0;
}
if (!option_softin) free_buffers(&dsp);
else {
if (hdb.buf) { free(hdb.buf); hdb.buf = NULL; }
}
}
else //if (rawhex)
{
char buffer_rawhex[3*FRAME_LEN+12];
char *pbuf = NULL, *buf_sp = NULL;
ui8_t frmbyte;
int frameofs = 0, len, i;
if (!option_softin) free_buffers(&dsp);
else {
if (hdb.buf) { free(hdb.buf); hdb.buf = NULL; }
while (1 > 0) {
pbuf = fgets(buffer_rawhex, 3*FRAME_LEN+12, fp);
if (pbuf == NULL) break;
buffer_rawhex[3*FRAME_LEN] = '\0';
buf_sp = strchr(buffer_rawhex, '['); // # (%d) ecc-info?
if (buf_sp != NULL && buf_sp-buffer_rawhex < 3*FRAME_LEN) {
buffer_rawhex[buf_sp-buffer_rawhex] = '\0';
}
len = strlen(buffer_rawhex) / 3;
if (len > 20) {
for (i = 0; i < len; i++) { //%2x SCNx8=%hhx(inttypes.h)
sscanf(buffer_rawhex+3*i, "%2hhx", &frmbyte);
// wenn ohne %hhx: sscanf(buffer_rawhex+rawhex*i, "%2x", &byte); frame[frameofs+i] = (ui8_t)byte;
gpx.frame[frameofs+i] = frmbyte;
}
print_frame(&gpx, len, 0);
}
}
}