diff --git a/acars.c b/acars.c index 4b0528d..e25c672 100644 --- a/acars.c +++ b/acars.c @@ -213,6 +213,7 @@ static void *blk_thread(void *arg) { .type = STATSD_UCOUNTER, .name = "decoder.msg.good", .value.u = 1 }, { .type = STATSD_LGAUGE, .name = "decoder.msg.errs", .value.l = blk->err }, { .type = STATSD_FGAUGE, .name = "decoder.msg.lvl", .value.f = blk->lvl }, + { .type = STATSD_FGAUGE, .name = "decoder.msg.nf", .value.f = blk->nf }, { .type = STATSD_LGAUGE, .name = "decoder.msg.len", .value.l = blk->txtlen }, }; // use the frequency if available, else the channel number @@ -251,18 +252,22 @@ int initAcars(channel_t *ch) void decodeAcars(channel_t *ch) { + const float mag = ch->MskMag; uint8_t r = ch->outbits; //vprerr("#%d r: %x, count: %d, st: %d\n", ch->chn+1, r, ch->count, ch->Acarsstate); ch->nbits = 8; // by default we'll read another byte next + /* update power level exp moving average. Average over last 16 bytes */ + ch->MskPwr = ch->MskPwr - (1.0F/16.0F * (ch->MskPwr - mag * mag)); + switch (ch->Acarsstate) { case PREKEY: if (ch->count >= 16 && 0xFF != r) { // we have our first non-0xFF byte after a sequence uint8_t q = ~r; // avoid type promotion in calling ffs(~r) int l = ffs(q); // find the first (LSb) 0 in r - vprerr("#%d synced, count: %d, r: %x, fz: %d, lvl: %5.1f\n", ch->chn+1, ch->count, r, l, 10 * log10(ch->MskLvl)); + vprerr("#%d synced, count: %d, r: %x, fz: %d, lvl: %5.1f\n", ch->chn+1, ch->count, r, l, 10 * log10(ch->MskPwr)); ch->count = 0; ch->Acarsstate = SYNC; @@ -299,6 +304,8 @@ void decodeAcars(channel_t *ch) ch->count++; break; default: + /* outside of msgs, update noise floor moving average: long term (10^3 'bytes') magnitude exp moving average */ + ch->MskNF = ch->MskNF - (1e-3F * (ch->MskNF - mag)); ch->count = 0; break; } @@ -347,7 +354,8 @@ void decodeAcars(channel_t *ch) } gettimeofday(&(ch->blk->tv), NULL); ch->Acarsstate = TXT; - ch->blk->lvl = 10 * log10(ch->MskLvl); + ch->blk->lvl = 10 * log10(ch->MskPwr); + ch->blk->nf = 20 * log10(ch->MskNF); ch->blk->chn = ch->chn; ch->blk->txtlen = 0; ch->blk->err = 0; diff --git a/acarsdec.h b/acarsdec.h index e3ec7ff..7521b64 100644 --- a/acarsdec.h +++ b/acarsdec.h @@ -54,7 +54,7 @@ typedef struct mskblk_s { struct mskblk_s *prev; struct timeval tv; - float lvl; + float lvl, nf; uint8_t chn; // there will never be 255 channels uint8_t txtlen; uint8_t err; @@ -88,7 +88,7 @@ typedef struct { char be; char msn[4]; // only for libacars - null-terminated copy of msg.no[0-3] int err; - float lvl; + float lvl, nf; #ifdef HAVE_LIBACARS la_reasm_status reasm_status; la_proto_node *decoded_tree; @@ -104,7 +104,9 @@ typedef struct { float complex *inb; double MskPhi; double MskDf; - float MskLvl; + float MskMag; // signal magnitude moving average + float MskPwr; // signal power moving average (average of magnitude squared) + float MskNF; // noise floor moving average (average of magnitude outside of msg blocks) float MskClk; unsigned int MskS, idx; diff --git a/msk.c b/msk.c index 16b6143..7a2e4cd 100644 --- a/msk.c +++ b/msk.c @@ -54,12 +54,10 @@ int initMsk(channel_t *ch) static inline void putbit(float v, channel_t *ch) { ch->outbits >>= 1; - if (v > 0) { + if (v > 0) ch->outbits |= 0x80; - } - ch->nbits--; - if (ch->nbits <= 0) + if (--ch->nbits == 0) decodeAcars(ch); } @@ -106,12 +104,11 @@ void demodMSK(channel_t *ch, int len) v += h[o] * ch->inb[(j + idx) % FLEN]; /* normalize */ - lvl = cabsf(v); - v /= lvl + 1e-8; + lvl = cabsf(v) + 1e-8F; + v /= lvl; - /* update level exp moving average. Average over last 16*8 bits */ - lvl = lvl * lvl; - ch->MskLvl = ch->MskLvl - (1.0F/128.0F * (ch->MskLvl - lvl)); + /* update magnitude exp moving average. Average over last 8 bits */ + ch->MskMag = ch->MskMag - (1.0F/8.0F * (ch->MskMag - lvl)); if (ch->MskS & 1) { vo = cimagf(v); diff --git a/output.c b/output.c index 1f1433f..78ffa26 100644 --- a/output.c +++ b/output.c @@ -391,10 +391,10 @@ static int fmt_msg(acarsmsg_t *msg, int chn, struct timeval tv, char *buf, size_ int len = 0; if (R.inmode >= IN_RTL) - len += snprintf(buf + len, bufsz - len, "[#%1d (F:%3.3f L:%+5.1f E:%1d) ", chn + 1, - R.channels[chn].Fr / 1000000.0, msg->lvl, msg->err); + len += snprintf(buf + len, bufsz - len, "[#%1d (F:%3.3f L:%+5.1f/%.1f E:%1d) ", chn + 1, + R.channels[chn].Fr / 1000000.0, msg->lvl, msg->nf, msg->err); else - len += snprintf(buf + len, bufsz - len, "[#%1d (L:%+5.1f E:%1d) ", chn + 1, msg->lvl, msg->err); + len += snprintf(buf + len, bufsz - len, "[#%1d (L:%+5.1f/%.1f E:%1d) ", chn + 1, msg->lvl, msg->nf, msg->err); if (R.inmode != IN_SNDFILE) len += fmt_date(tv, buf + len, bufsz - len); @@ -472,7 +472,7 @@ static int fmt_oneline(acarsmsg_t *msg, int chn, struct timeval tv, char *buf, s if (*pstr == '\n' || *pstr == '\r') *pstr = ' '; - len = snprintf(buf, bufsz, "#%1d (L:%+5.1f E:%1d) ", chn + 1, msg->lvl, msg->err); + len = snprintf(buf, bufsz, "#%1d (L:%+5.1f/%.1f E:%1d) ", chn + 1, msg->lvl, msg->nf, msg->err); if (R.inmode != IN_SNDFILE) len += fmt_date(tv, buf + len, bufsz - len); @@ -575,6 +575,8 @@ static int fmt_json(acarsmsg_t *msg, int chn, struct timeval tv, char *buf, size cJSON_AddRawToObject(json_obj, "freq", convert_tmp); snprintf(convert_tmp, sizeof(convert_tmp), "%2.1f", msg->lvl); cJSON_AddRawToObject(json_obj, "level", convert_tmp); + snprintf(convert_tmp, sizeof(convert_tmp), "%.1f", msg->nf); + cJSON_AddRawToObject(json_obj, "noise", convert_tmp); cJSON_AddNumberToObject(json_obj, "error", msg->err); snprintf(convert_tmp, sizeof(convert_tmp), "%c", msg->mode); cJSON_AddStringToObject(json_obj, "mode", convert_tmp); @@ -727,6 +729,7 @@ void outputmsg(const msgblk_t *blk) /* fill msg struct */ memset(&msg, 0, sizeof(msg)); msg.lvl = blk->lvl; + msg.nf = blk->nf; msg.err = blk->err; msg.mode = blk->txt.d.mode;