Measure signal power / noise power (at least in 2.4MHz mode).
Switch signalLevel back to a power measurement, don't put SNR in there. But make it a 0.0 - 1.0 double so we're not scaling everywhere. Adjust for the amplitude offset when calculating power. Adapt everything else to the new scheme.
This commit is contained in:
parent
5beecb9f4f
commit
19082d92ea
|
@ -540,7 +540,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
|
||||||
&& (errors <= MODES_MSG_ENCODER_ERRS) ) {
|
&& (errors <= MODES_MSG_ENCODER_ERRS) ) {
|
||||||
// Set initial mm structure details
|
// Set initial mm structure details
|
||||||
mm.timestampMsg = Modes.timestampBlk + (j*6);
|
mm.timestampMsg = Modes.timestampBlk + (j*6);
|
||||||
mm.signalLevel = (snr > 255 ? 255 : (uint8_t)snr);
|
mm.signalLevel = (365.0*60 + sigLevel + noiseLevel) * (365.0*60 + sigLevel + noiseLevel) / MAX_POWER / 60 / 60;
|
||||||
mm.phase_corrected = use_correction;
|
mm.phase_corrected = use_correction;
|
||||||
|
|
||||||
// Decode the received message
|
// Decode the received message
|
||||||
|
|
42
demod_2400.c
42
demod_2400.c
|
@ -153,10 +153,15 @@ void demodulate2400(uint16_t *m, uint32_t mlen) {
|
||||||
struct modesMessage mm;
|
struct modesMessage mm;
|
||||||
unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg;
|
unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg;
|
||||||
uint32_t j;
|
uint32_t j;
|
||||||
|
uint32_t last_message_end = 0;
|
||||||
|
|
||||||
unsigned char *bestmsg;
|
unsigned char *bestmsg;
|
||||||
int bestscore, bestphase;
|
int bestscore, bestphase;
|
||||||
|
|
||||||
|
// noise floor:
|
||||||
|
uint32_t noise_power_count = 0;
|
||||||
|
uint64_t noise_power_sum = 0;
|
||||||
|
|
||||||
memset(&mm, 0, sizeof(mm));
|
memset(&mm, 0, sizeof(mm));
|
||||||
msg = msg1;
|
msg = msg1;
|
||||||
|
|
||||||
|
@ -167,6 +172,17 @@ void demodulate2400(uint16_t *m, uint32_t mlen) {
|
||||||
int initial_phase, first_phase, last_phase, try_phase;
|
int initial_phase, first_phase, last_phase, try_phase;
|
||||||
int msglen;
|
int msglen;
|
||||||
|
|
||||||
|
// update noise for all samples that aren't part of a message
|
||||||
|
// (we don't know if m[j] is or not, yet, so work one sample
|
||||||
|
// in arrears)
|
||||||
|
if (j > last_message_end+1) {
|
||||||
|
// There seems to be a weird compiler bug I'm hitting here..
|
||||||
|
// if you compute the square directly, it occasionally gets mangled.
|
||||||
|
uint64_t s = TRUE_AMPLITUDE(m[j-1]);
|
||||||
|
noise_power_sum += s * s;
|
||||||
|
noise_power_count++;
|
||||||
|
}
|
||||||
|
|
||||||
// Look for a message starting at around sample 0 with phase offset 3..7
|
// Look for a message starting at around sample 0 with phase offset 3..7
|
||||||
|
|
||||||
// Ideal sample values for preambles with different phase
|
// Ideal sample values for preambles with different phase
|
||||||
|
@ -403,6 +419,28 @@ void demodulate2400(uint16_t *m, uint32_t mlen) {
|
||||||
mm.score = bestscore;
|
mm.score = bestscore;
|
||||||
mm.bFlags = mm.correctedbits = 0;
|
mm.bFlags = mm.correctedbits = 0;
|
||||||
|
|
||||||
|
// measure signal power
|
||||||
|
{
|
||||||
|
uint64_t signal_power_sum = 0;
|
||||||
|
double signal_power;
|
||||||
|
int signal_len = msglen*12/5 + 1;
|
||||||
|
int k;
|
||||||
|
|
||||||
|
for (k = 0; k < signal_len; ++k) {
|
||||||
|
uint64_t s = TRUE_AMPLITUDE(m[j+19+k]);
|
||||||
|
signal_power_sum += s * s;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm.signalLevel = signal_power = signal_power_sum / MAX_POWER / signal_len;
|
||||||
|
Modes.stats_current.signal_power_sum += signal_power;
|
||||||
|
Modes.stats_current.signal_power_count ++;
|
||||||
|
|
||||||
|
if (signal_power > Modes.stats_current.peak_signal_power)
|
||||||
|
Modes.stats_current.peak_signal_power = signal_power;
|
||||||
|
if (signal_power > 0.50119)
|
||||||
|
Modes.stats_current.strong_signal_count++; // signal power above -3dBFS
|
||||||
|
}
|
||||||
|
|
||||||
// Decode the received message
|
// Decode the received message
|
||||||
if (decodeModesMessage(&mm, bestmsg) < 0)
|
if (decodeModesMessage(&mm, bestmsg) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
@ -426,10 +464,14 @@ void demodulate2400(uint16_t *m, uint32_t mlen) {
|
||||||
// where the preamble of the second message clobbered the last
|
// where the preamble of the second message clobbered the last
|
||||||
// few bits of the first message, but the message bits didn't
|
// few bits of the first message, but the message bits didn't
|
||||||
// overlap)
|
// overlap)
|
||||||
|
last_message_end = j + (8 + msglen)*12/5;
|
||||||
j += (8 + msglen - 8)*12/5 - 1;
|
j += (8 + msglen - 8)*12/5 - 1;
|
||||||
|
|
||||||
// Pass data to the next layer
|
// Pass data to the next layer
|
||||||
useModesMessage(&mm);
|
useModesMessage(&mm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Modes.stats_current.noise_power_sum += (noise_power_sum / MAX_POWER / noise_power_count);
|
||||||
|
Modes.stats_current.noise_power_count ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -209,6 +209,11 @@
|
||||||
|
|
||||||
#define MODES_NOTUSED(V) ((void) V)
|
#define MODES_NOTUSED(V) ((void) V)
|
||||||
|
|
||||||
|
// adjust for zero offset of amplitude values
|
||||||
|
#define TRUE_AMPLITUDE(x) ((x) + 365)
|
||||||
|
#define MAX_AMPLITUDE TRUE_AMPLITUDE(65535)
|
||||||
|
#define MAX_POWER (1.0 * MAX_AMPLITUDE * MAX_AMPLITUDE)
|
||||||
|
|
||||||
// Include subheaders after all the #defines are in place
|
// Include subheaders after all the #defines are in place
|
||||||
|
|
||||||
#include "anet.h"
|
#include "anet.h"
|
||||||
|
@ -235,7 +240,7 @@ struct client {
|
||||||
struct aircraft {
|
struct aircraft {
|
||||||
uint32_t addr; // ICAO address
|
uint32_t addr; // ICAO address
|
||||||
char flight[16]; // Flight number
|
char flight[16]; // Flight number
|
||||||
unsigned char signalLevel[8]; // Last 8 Signal Amplitudes
|
double signalLevel[8]; // Last 8 Signal Amplitudes
|
||||||
int altitude; // Altitude
|
int altitude; // Altitude
|
||||||
int speed; // Velocity
|
int speed; // Velocity
|
||||||
int track; // Angle of flight
|
int track; // Angle of flight
|
||||||
|
@ -402,7 +407,7 @@ struct modesMessage {
|
||||||
int phase_corrected; // True if phase correction was applied
|
int phase_corrected; // True if phase correction was applied
|
||||||
uint64_t timestampMsg; // Timestamp of the message
|
uint64_t timestampMsg; // Timestamp of the message
|
||||||
int remote; // If set this message is from a remote station
|
int remote; // If set this message is from a remote station
|
||||||
unsigned char signalLevel; // Signal Amplitude
|
double signalLevel; // RSSI, in the range [0..1], as a fraction of full-scale power
|
||||||
int score;
|
int score;
|
||||||
|
|
||||||
// DF 11, DF 17
|
// DF 11, DF 17
|
||||||
|
|
|
@ -68,16 +68,18 @@ static uint64_t mstime(void) {
|
||||||
// of aircraft
|
// of aircraft
|
||||||
//
|
//
|
||||||
struct aircraft *interactiveCreateAircraft(struct modesMessage *mm) {
|
struct aircraft *interactiveCreateAircraft(struct modesMessage *mm) {
|
||||||
|
static struct aircraft zeroAircraft;
|
||||||
struct aircraft *a = (struct aircraft *) malloc(sizeof(*a));
|
struct aircraft *a = (struct aircraft *) malloc(sizeof(*a));
|
||||||
|
int i;
|
||||||
|
|
||||||
// Default everything to zero/NULL
|
// Default everything to zero/NULL
|
||||||
memset(a, 0, sizeof(*a));
|
*a = zeroAircraft;
|
||||||
|
|
||||||
// Now initialise things that should not be 0/NULL to their defaults
|
// Now initialise things that should not be 0/NULL to their defaults
|
||||||
a->addr = mm->addr;
|
a->addr = mm->addr;
|
||||||
a->lat = a->lon = 0.0;
|
for (i = 0; i < 8; ++i)
|
||||||
memset(a->signalLevel, mm->signalLevel, 8); // First time, initialise everything
|
a->signalLevel[i] = mm->signalLevel; // First time, initialise everything
|
||||||
// to the first signal strength
|
// to the first signal strength
|
||||||
|
|
||||||
// mm->msgtype 32 is used to represent Mode A/C. These values can never change, so
|
// mm->msgtype 32 is used to represent Mode A/C. These values can never change, so
|
||||||
// set them once here during initialisation, and don't bother to set them every
|
// set them once here during initialisation, and don't bother to set them every
|
||||||
|
@ -521,7 +523,7 @@ void interactiveShowData(void) {
|
||||||
|
|
||||||
if (Modes.interactive_rtl1090 == 0) {
|
if (Modes.interactive_rtl1090 == 0) {
|
||||||
printf (
|
printf (
|
||||||
"Hex Mode Sqwk Flight Alt Spd Hdg Lat Long Sig Msgs Ti%c\n", progress);
|
"Hex Mode Sqwk Flight Alt Spd Hdg Lat Long RSSI Msgs Ti%c\n", progress);
|
||||||
} else {
|
} else {
|
||||||
printf (
|
printf (
|
||||||
"Hex Flight Alt V/S GS TT SSR G*456^ Msgs Seen %c\n", progress);
|
"Hex Flight Alt V/S GS TT SSR G*456^ Msgs Seen %c\n", progress);
|
||||||
|
@ -576,9 +578,9 @@ void interactiveShowData(void) {
|
||||||
char strMode[5] = " ";
|
char strMode[5] = " ";
|
||||||
char strLat[8] = " ";
|
char strLat[8] = " ";
|
||||||
char strLon[9] = " ";
|
char strLon[9] = " ";
|
||||||
unsigned char * pSig = a->signalLevel;
|
double * pSig = a->signalLevel;
|
||||||
unsigned int signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
|
double signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
|
||||||
pSig[4] + pSig[5] + pSig[6] + pSig[7] + 3) >> 3;
|
pSig[4] + pSig[5] + pSig[6] + pSig[7]) / 8.0;
|
||||||
|
|
||||||
if ((flags & MODEAC_MSG_FLAG) == 0) {
|
if ((flags & MODEAC_MSG_FLAG) == 0) {
|
||||||
strMode[0] = 'S';
|
strMode[0] = 'S';
|
||||||
|
@ -599,9 +601,9 @@ void interactiveShowData(void) {
|
||||||
snprintf(strFl, 6, "%5d", altitude);
|
snprintf(strFl, 6, "%5d", altitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%06X %-4s %-4s %-8s %5s %3s %3s %7s %8s %2d.%1d %5d %2d\n",
|
printf("%06X %-4s %-4s %-8s %5s %3s %3s %7s %8s %5.1f %5d %2d\n",
|
||||||
a->addr, strMode, strSquawk, a->flight, strFl, strGs, strTt,
|
a->addr, strMode, strSquawk, a->flight, strFl, strGs, strTt,
|
||||||
strLat, strLon, signalAverage/5, 2*(signalAverage%5), msgs, (int)(now - a->seen));
|
strLat, strLon, 10 * log10(signalAverage), msgs, (int)(now - a->seen));
|
||||||
}
|
}
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
10
mode_ac.c
10
mode_ac.c
|
@ -144,7 +144,6 @@ int detectModeA(uint16_t *m, struct modesMessage *mm)
|
||||||
int F1_sig, F1_noise;
|
int F1_sig, F1_noise;
|
||||||
int F2_sig, F2_noise;
|
int F2_sig, F2_noise;
|
||||||
int fSig, fNoise, fLevel, fLoLo;
|
int fSig, fNoise, fLevel, fLoLo;
|
||||||
int snr;
|
|
||||||
|
|
||||||
// m[0] contains the energy from 0 -> 499 nS
|
// m[0] contains the energy from 0 -> 499 nS
|
||||||
// m[1] contains the energy from 500 -> 999 nS
|
// m[1] contains the energy from 500 -> 999 nS
|
||||||
|
@ -307,14 +306,7 @@ int detectModeA(uint16_t *m, struct modesMessage *mm)
|
||||||
if ((ModeABits < 3) || (ModeABits & 0xFFFF8808) || (ModeAErrs) )
|
if ((ModeABits < 3) || (ModeABits & 0xFFFF8808) || (ModeAErrs) )
|
||||||
{return (ModeABits = 0);}
|
{return (ModeABits = 0);}
|
||||||
|
|
||||||
// snr = 5 * 20log10(fSig / (fSig+fNoise)) (in units of 0.2dB)
|
mm->signalLevel = 1.0 * TRUE_AMPLITUDE(fSig + fNoise) * TRUE_AMPLITUDE(fSig + fNoise) / MAX_POWER;
|
||||||
// = 100log10(fSig) - 100log10(fSig+fNoise)
|
|
||||||
while (fSig > 65535 || (fSig + fNoise) > 65535) {
|
|
||||||
fSig >>= 1;
|
|
||||||
fNoise >>= 1;
|
|
||||||
}
|
|
||||||
snr = Modes.log10lut[fSig] - Modes.log10lut[fSig + fNoise];
|
|
||||||
mm->signalLevel = ((snr < 255) ? (uint8_t)snr : 255);
|
|
||||||
|
|
||||||
return ModeABits;
|
return ModeABits;
|
||||||
}
|
}
|
||||||
|
|
3
mode_s.c
3
mode_s.c
|
@ -1005,7 +1005,8 @@ void displayModesMessage(struct modesMessage *mm) {
|
||||||
if (mm->correctedbits != 0)
|
if (mm->correctedbits != 0)
|
||||||
printf("No. of bit errors fixed: %d\n", mm->correctedbits);
|
printf("No. of bit errors fixed: %d\n", mm->correctedbits);
|
||||||
|
|
||||||
printf("SNR: %d.%d dB\n", mm->signalLevel/5, 2*(mm->signalLevel%5));
|
if (mm->signalLevel > 0)
|
||||||
|
printf("RSSI: %.1f dBFS\n", 10 * log10(mm->signalLevel));
|
||||||
|
|
||||||
if (mm->score)
|
if (mm->score)
|
||||||
printf("Score: %d\n", mm->score);
|
printf("Score: %d\n", mm->score);
|
||||||
|
|
9
net_io.c
9
net_io.c
|
@ -293,7 +293,7 @@ void modesSendBeastOutput(struct modesMessage *mm) {
|
||||||
if (0x1A == ch) {*p++ = ch; }
|
if (0x1A == ch) {*p++ = ch; }
|
||||||
}
|
}
|
||||||
|
|
||||||
*p++ = (ch = mm->signalLevel);
|
*p++ = ch = (char) round(mm->signalLevel * 255);
|
||||||
if (0x1A == ch) {*p++ = ch; }
|
if (0x1A == ch) {*p++ = ch; }
|
||||||
|
|
||||||
for (j = 0; j < msgLen; j++) {
|
for (j = 0; j < msgLen; j++) {
|
||||||
|
@ -568,7 +568,8 @@ int decodeBinMessage(struct client *c, char *p) {
|
||||||
if (0x1A == ch) {p++;}
|
if (0x1A == ch) {p++;}
|
||||||
}
|
}
|
||||||
|
|
||||||
mm.signalLevel = ch = *p++; // Grab the signal level
|
ch = *p++; // Grab the signal level
|
||||||
|
mm.signalLevel = ((unsigned)ch / 255.0);
|
||||||
if (0x1A == ch) {p++;}
|
if (0x1A == ch) {p++;}
|
||||||
|
|
||||||
for (j = 0; j < msgLen; j++) { // and the data
|
for (j = 0; j < msgLen; j++) { // and the data
|
||||||
|
@ -627,7 +628,7 @@ int decodeHexMessage(struct client *c, char *hex) {
|
||||||
// Mark messages received over the internet as remote so that we don't try to
|
// Mark messages received over the internet as remote so that we don't try to
|
||||||
// pass them off as being received by this instance when forwarding them
|
// pass them off as being received by this instance when forwarding them
|
||||||
mm.remote = 1;
|
mm.remote = 1;
|
||||||
mm.signalLevel = 0xFF;
|
mm.signalLevel = 0.0;
|
||||||
|
|
||||||
// Remove spaces on the left and on the right
|
// Remove spaces on the left and on the right
|
||||||
while(l && isspace(hex[l-1])) {
|
while(l && isspace(hex[l-1])) {
|
||||||
|
@ -644,7 +645,7 @@ int decodeHexMessage(struct client *c, char *hex) {
|
||||||
|
|
||||||
switch(hex[0]) {
|
switch(hex[0]) {
|
||||||
case '<': {
|
case '<': {
|
||||||
mm.signalLevel = (hexDigitVal(hex[13])<<4) | hexDigitVal(hex[14]);
|
mm.signalLevel = ((hexDigitVal(hex[13])<<4) | hexDigitVal(hex[14])) / 255.0;
|
||||||
hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ;
|
hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ;
|
||||||
break;}
|
break;}
|
||||||
|
|
||||||
|
|
33
stats.c
33
stats.c
|
@ -110,6 +110,22 @@ void display_stats(struct stats *st) {
|
||||||
printf("%d phase enhancement attempts\n", st->out_of_phase);
|
printf("%d phase enhancement attempts\n", st->out_of_phase);
|
||||||
display_demod_stats("phase enhanced ", &st->demod_phasecorrected);
|
display_demod_stats("phase enhanced ", &st->demod_phasecorrected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (st->noise_power_count) {
|
||||||
|
printf("%.1f dBFS noise floor\n",
|
||||||
|
10 * log10(st->noise_power_sum / st->noise_power_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st->signal_power_count) {
|
||||||
|
printf("%.1f dBFS mean signal power\n",
|
||||||
|
10 * log10(st->signal_power_sum / st->signal_power_count));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%.1f dBFS peak signal power\n",
|
||||||
|
10 * log10(st->peak_signal_power));
|
||||||
|
|
||||||
|
printf("%u messages with signal power above -3dBFS\n",
|
||||||
|
st->strong_signal_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("%d remote messages accepted\n"
|
printf("%d remote messages accepted\n"
|
||||||
|
@ -206,6 +222,23 @@ void add_stats(const struct stats *st1, const struct stats *st2, struct stats *t
|
||||||
// total messages:
|
// total messages:
|
||||||
target->messages_total = st1->messages_total + st2->messages_total;
|
target->messages_total = st1->messages_total + st2->messages_total;
|
||||||
|
|
||||||
|
// noise floor:
|
||||||
|
target->noise_power_sum = st1->noise_power_sum + st2->noise_power_sum;
|
||||||
|
target->noise_power_count = st1->noise_power_count + st2->noise_power_count;
|
||||||
|
|
||||||
|
// mean signal power:
|
||||||
|
target->signal_power_sum = st1->signal_power_sum + st2->signal_power_sum;
|
||||||
|
target->signal_power_count = st1->signal_power_count + st2->signal_power_count;
|
||||||
|
|
||||||
|
// peak signal power seen
|
||||||
|
if (st1->peak_signal_power > st2->peak_signal_power)
|
||||||
|
target->peak_signal_power = st1->peak_signal_power;
|
||||||
|
else
|
||||||
|
target->peak_signal_power = st2->peak_signal_power;
|
||||||
|
|
||||||
|
// strong signals
|
||||||
|
target->strong_signal_count = st1->strong_signal_count + st2->strong_signal_count;
|
||||||
|
|
||||||
// CPR decoding:
|
// CPR decoding:
|
||||||
target->cpr_global_ok = st1->cpr_global_ok + st2->cpr_global_ok;
|
target->cpr_global_ok = st1->cpr_global_ok + st2->cpr_global_ok;
|
||||||
target->cpr_global_bad = st1->cpr_global_bad + st2->cpr_global_bad;
|
target->cpr_global_bad = st1->cpr_global_bad + st2->cpr_global_bad;
|
||||||
|
|
14
stats.h
14
stats.h
|
@ -91,6 +91,20 @@ struct stats {
|
||||||
|
|
||||||
struct timespec cputime;
|
struct timespec cputime;
|
||||||
|
|
||||||
|
// noise floor:
|
||||||
|
double noise_power_sum;
|
||||||
|
uint32_t noise_power_count;
|
||||||
|
|
||||||
|
// mean signal power:
|
||||||
|
double signal_power_sum;
|
||||||
|
uint32_t signal_power_count;
|
||||||
|
|
||||||
|
// peak signal power seen
|
||||||
|
double peak_signal_power;
|
||||||
|
|
||||||
|
// number of signals with power > -3dBFS
|
||||||
|
uint32_t strong_signal_count;
|
||||||
|
|
||||||
// remote messages:
|
// remote messages:
|
||||||
unsigned int remote_accepted;
|
unsigned int remote_accepted;
|
||||||
unsigned int remote_rejected;
|
unsigned int remote_rejected;
|
||||||
|
|
Loading…
Reference in a new issue