Factor out the sample -> magnitude conversion code and make everything a little less sample-rate-dependent.
Add optional noise measurement (cheaper than the old version) Add optional DC filter (expensive, not really needed with rtlsdr input)
This commit is contained in:
parent
f58ff14d7c
commit
03b53c2d29
2
Makefile
2
Makefile
|
@ -25,7 +25,7 @@ all: dump1090 view1090
|
||||||
%.o: %.c *.h
|
%.o: %.c *.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c $< -o $@
|
$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c $< -o $@
|
||||||
|
|
||||||
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o demod_2000.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o
|
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o demod_2000.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o convert.o
|
||||||
$(CC) -g -o $@ $^ $(LIBS) $(LIBS_RTL) $(LDFLAGS)
|
$(CC) -g -o $@ $^ $(LIBS) $(LIBS_RTL) $(LDFLAGS)
|
||||||
|
|
||||||
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o
|
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o
|
||||||
|
|
317
convert.c
Normal file
317
convert.c
Normal file
|
@ -0,0 +1,317 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// convert.c: support for various IQ -> magnitude conversions
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "dump1090.h"
|
||||||
|
|
||||||
|
struct converter_state {
|
||||||
|
float dc_a;
|
||||||
|
float dc_b;
|
||||||
|
float z1_I;
|
||||||
|
float z1_Q;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void convert_uc8_nodc_nopower(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_power)
|
||||||
|
{
|
||||||
|
uint16_t *in = iq_data;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
MODES_NOTUSED(state);
|
||||||
|
|
||||||
|
// unroll this a bit
|
||||||
|
for (i = 0; i < (nsamples>>3); ++i) {
|
||||||
|
*mag_data++ = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = Modes.maglut[*in++];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (nsamples&7); ++i) {
|
||||||
|
*mag_data++ = Modes.maglut[*in++];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_power)
|
||||||
|
*out_power = 0.0; // not measured
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_uc8_nodc_power(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_power)
|
||||||
|
{
|
||||||
|
uint16_t *in = iq_data;
|
||||||
|
unsigned i;
|
||||||
|
uint16_t mag;
|
||||||
|
uint64_t power = 0;
|
||||||
|
|
||||||
|
MODES_NOTUSED(state);
|
||||||
|
|
||||||
|
// unroll this a bit
|
||||||
|
for (i = 0; i < (nsamples>>3); ++i) {
|
||||||
|
mag = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = mag;
|
||||||
|
power += mag*mag;
|
||||||
|
|
||||||
|
mag = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = mag;
|
||||||
|
power += mag*mag;
|
||||||
|
|
||||||
|
mag = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = mag;
|
||||||
|
power += mag*mag;
|
||||||
|
|
||||||
|
mag = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = mag;
|
||||||
|
power += mag*mag;
|
||||||
|
|
||||||
|
mag = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = mag;
|
||||||
|
power += mag*mag;
|
||||||
|
|
||||||
|
mag = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = mag;
|
||||||
|
power += mag*mag;
|
||||||
|
|
||||||
|
mag = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = mag;
|
||||||
|
power += mag*mag;
|
||||||
|
|
||||||
|
mag = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = mag;
|
||||||
|
power += mag*mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < (nsamples&7); ++i) {
|
||||||
|
mag = Modes.maglut[*in++];
|
||||||
|
*mag_data++ = mag;
|
||||||
|
power += mag*mag;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_power)
|
||||||
|
*out_power = power / (65535.0 * 65535.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_uc8_generic(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_power)
|
||||||
|
{
|
||||||
|
uint8_t *in = iq_data;
|
||||||
|
float power = 0.0;
|
||||||
|
float z1_I = state->z1_I;
|
||||||
|
float z1_Q = state->z1_Q;
|
||||||
|
const float dc_a = state->dc_a;
|
||||||
|
const float dc_b = state->dc_b;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
uint8_t I, Q;
|
||||||
|
float fI, fQ, magsq;
|
||||||
|
|
||||||
|
for (i = 0; i < nsamples; ++i) {
|
||||||
|
I = *in++;
|
||||||
|
Q = *in++;
|
||||||
|
fI = (I - 127.5) / 127.5;
|
||||||
|
fQ = (Q - 127.5) / 127.5;
|
||||||
|
|
||||||
|
// DC block
|
||||||
|
z1_I = fI * dc_a + z1_I * dc_b;
|
||||||
|
z1_Q = fQ * dc_a + z1_Q * dc_b;
|
||||||
|
fI -= z1_I;
|
||||||
|
fQ -= z1_Q;
|
||||||
|
|
||||||
|
magsq = fI * fI + fQ * fQ;
|
||||||
|
if (magsq > 1)
|
||||||
|
magsq = 1;
|
||||||
|
|
||||||
|
power += magsq;
|
||||||
|
*mag_data++ = (uint16_t)(sqrtf(magsq) * 65535.0 + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->z1_I = z1_I;
|
||||||
|
state->z1_Q = z1_Q;
|
||||||
|
|
||||||
|
if (out_power)
|
||||||
|
*out_power = power;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_sc16_generic(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_power)
|
||||||
|
{
|
||||||
|
uint16_t *in = iq_data;
|
||||||
|
float power = 0.0;
|
||||||
|
float z1_I = state->z1_I;
|
||||||
|
float z1_Q = state->z1_Q;
|
||||||
|
const float dc_a = state->dc_a;
|
||||||
|
const float dc_b = state->dc_b;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
int16_t I, Q;
|
||||||
|
float fI, fQ, magsq;
|
||||||
|
|
||||||
|
for (i = 0; i < nsamples; ++i) {
|
||||||
|
I = (int16_t)le16toh(*in++);
|
||||||
|
Q = (int16_t)le16toh(*in++);
|
||||||
|
fI = I / 32768.0;
|
||||||
|
fQ = Q / 32768.0;
|
||||||
|
|
||||||
|
// DC block
|
||||||
|
z1_I = fI * dc_a + z1_I * dc_b;
|
||||||
|
z1_Q = fQ * dc_a + z1_Q * dc_b;
|
||||||
|
fI -= z1_I;
|
||||||
|
fQ -= z1_Q;
|
||||||
|
|
||||||
|
magsq = fI * fI + fQ * fQ;
|
||||||
|
if (magsq > 1)
|
||||||
|
magsq = 1;
|
||||||
|
|
||||||
|
power += magsq;
|
||||||
|
*mag_data++ = (uint16_t)(sqrtf(magsq) * 65535.0 + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->z1_I = z1_I;
|
||||||
|
state->z1_Q = z1_Q;
|
||||||
|
|
||||||
|
if (out_power)
|
||||||
|
*out_power = power;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_sc16q11_generic(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_power)
|
||||||
|
{
|
||||||
|
uint16_t *in = iq_data;
|
||||||
|
float power = 0.0;
|
||||||
|
float z1_I = state->z1_I;
|
||||||
|
float z1_Q = state->z1_Q;
|
||||||
|
const float dc_a = state->dc_a;
|
||||||
|
const float dc_b = state->dc_b;
|
||||||
|
|
||||||
|
unsigned i;
|
||||||
|
int16_t I, Q;
|
||||||
|
float fI, fQ, magsq;
|
||||||
|
|
||||||
|
for (i = 0; i < nsamples; ++i) {
|
||||||
|
I = (int16_t)le16toh(*in++);
|
||||||
|
Q = (int16_t)le16toh(*in++);
|
||||||
|
fI = I / 2048.0;
|
||||||
|
fQ = Q / 2048.0;
|
||||||
|
|
||||||
|
// DC block
|
||||||
|
z1_I = fI * dc_a + z1_I * dc_b;
|
||||||
|
z1_Q = fQ * dc_a + z1_Q * dc_b;
|
||||||
|
fI -= z1_I;
|
||||||
|
fQ -= z1_Q;
|
||||||
|
|
||||||
|
magsq = fI * fI + fQ * fQ;
|
||||||
|
if (magsq > 1)
|
||||||
|
magsq = 1;
|
||||||
|
|
||||||
|
power += magsq;
|
||||||
|
*mag_data++ = (uint16_t)(sqrtf(magsq) * 65535.0 + 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
state->z1_I = z1_I;
|
||||||
|
state->z1_Q = z1_Q;
|
||||||
|
|
||||||
|
if (out_power)
|
||||||
|
*out_power = power;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
input_format_t format;
|
||||||
|
int can_filter_dc;
|
||||||
|
int can_compute_power;
|
||||||
|
iq_convert_fn fn;
|
||||||
|
const char *description;
|
||||||
|
} converters_table[] = {
|
||||||
|
// In order of preference
|
||||||
|
{ INPUT_UC8, 0, 0, convert_uc8_nodc_nopower, "UC8, integer/table path" },
|
||||||
|
{ INPUT_UC8, 0, 1, convert_uc8_nodc_power, "UC8, integer/table path, with power measurement" },
|
||||||
|
{ INPUT_UC8, 1, 1, convert_uc8_generic, "UC8, float path" },
|
||||||
|
{ INPUT_SC16, 1, 1, convert_sc16_generic, "SC16, float path" },
|
||||||
|
{ INPUT_SC16Q11, 1, 1, convert_sc16q11_generic, "SC16Q11, float path" },
|
||||||
|
{ 0, 0, 0, NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
iq_convert_fn init_converter(input_format_t format,
|
||||||
|
double sample_rate,
|
||||||
|
int filter_dc,
|
||||||
|
int compute_power,
|
||||||
|
struct converter_state **out_state)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; converters_table[i].fn; ++i) {
|
||||||
|
if (converters_table[i].format != format)
|
||||||
|
continue;
|
||||||
|
if (filter_dc && !converters_table[i].can_filter_dc)
|
||||||
|
continue;
|
||||||
|
if (compute_power && !converters_table[i].can_compute_power)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!converters_table[i].fn) {
|
||||||
|
fprintf(stderr, "no suitable converter for format=%d power=%d dc=%d\n",
|
||||||
|
format, compute_power, filter_dc);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Using sample converter: %s\n", converters_table[i].description);
|
||||||
|
|
||||||
|
*out_state = malloc(sizeof(struct converter_state));
|
||||||
|
if (! *out_state) {
|
||||||
|
fprintf(stderr, "can't allocate converter state\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*out_state)->z1_I = 0;
|
||||||
|
(*out_state)->z1_Q = 0;
|
||||||
|
|
||||||
|
if (filter_dc) {
|
||||||
|
// init DC block @ 1Hz
|
||||||
|
(*out_state)->dc_b = exp(-2.0 * M_PI * 1.0 / sample_rate);
|
||||||
|
(*out_state)->dc_a = 1.0 - (*out_state)->dc_b;
|
||||||
|
} else {
|
||||||
|
// if the converter does filtering, make sure it has no effect
|
||||||
|
(*out_state)->dc_b = 1.0;
|
||||||
|
(*out_state)->dc_a = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return converters_table[i].fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_converter(struct converter_state *state)
|
||||||
|
{
|
||||||
|
free(state);
|
||||||
|
}
|
40
convert.h
Normal file
40
convert.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// convert.h: support for various IQ -> magnitude conversions
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef DUMP1090_CONVERT_H
|
||||||
|
#define DUMP1090_CONVERT_H
|
||||||
|
|
||||||
|
struct converter_state;
|
||||||
|
typedef enum { INPUT_UC8=0, INPUT_SC16, INPUT_SC16Q11 } input_format_t;
|
||||||
|
|
||||||
|
typedef void (*iq_convert_fn)(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_power);
|
||||||
|
|
||||||
|
iq_convert_fn init_converter(input_format_t format,
|
||||||
|
double sample_rate,
|
||||||
|
int filter_dc,
|
||||||
|
int compute_power,
|
||||||
|
struct converter_state **out_state);
|
||||||
|
|
||||||
|
void cleanup_converter(struct converter_state *state);
|
||||||
|
|
||||||
|
#endif
|
47
demod_2400.c
47
demod_2400.c
|
@ -19,12 +19,6 @@
|
||||||
|
|
||||||
#include "dump1090.h"
|
#include "dump1090.h"
|
||||||
|
|
||||||
//
|
|
||||||
// Measuring the noise power is actually surprisingly expensive on an ARM -
|
|
||||||
// it increases the CPU use of the demodulator by 1/3. So it's off by default.
|
|
||||||
// You can turn it back on here:
|
|
||||||
#undef MEASURE_NOISE
|
|
||||||
|
|
||||||
// 2.4MHz sampling rate version
|
// 2.4MHz sampling rate version
|
||||||
//
|
//
|
||||||
// When sampling at 2.4MHz we have exactly 6 samples per 5 symbols.
|
// When sampling at 2.4MHz we have exactly 6 samples per 5 symbols.
|
||||||
|
@ -155,26 +149,20 @@ static int best_phase(uint16_t *m) {
|
||||||
// Given 'mlen' magnitude samples in 'm', sampled at 2.4MHz,
|
// Given 'mlen' magnitude samples in 'm', sampled at 2.4MHz,
|
||||||
// try to demodulate some Mode S messages.
|
// try to demodulate some Mode S messages.
|
||||||
//
|
//
|
||||||
void demodulate2400(struct mag_buf *mag) {
|
void demodulate2400(struct mag_buf *mag)
|
||||||
|
{
|
||||||
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;
|
||||||
#ifdef MEASURE_NOISE
|
|
||||||
uint32_t last_message_end = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
unsigned char *bestmsg;
|
unsigned char *bestmsg;
|
||||||
int bestscore, bestphase;
|
int bestscore, bestphase;
|
||||||
|
|
||||||
#ifdef MEASURE_NOISE
|
|
||||||
// noise floor:
|
|
||||||
uint32_t noise_power_count = 0;
|
|
||||||
uint64_t noise_power_sum = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
uint16_t *m = mag->data;
|
uint16_t *m = mag->data;
|
||||||
uint32_t mlen = mag->length;
|
uint32_t mlen = mag->length;
|
||||||
|
|
||||||
|
double total_signal_power = 0.0;
|
||||||
|
|
||||||
memset(&mm, 0, sizeof(mm));
|
memset(&mm, 0, sizeof(mm));
|
||||||
msg = msg1;
|
msg = msg1;
|
||||||
|
|
||||||
|
@ -185,19 +173,6 @@ void demodulate2400(struct mag_buf *mag) {
|
||||||
int initial_phase, first_phase, last_phase, try_phase;
|
int initial_phase, first_phase, last_phase, try_phase;
|
||||||
int msglen;
|
int msglen;
|
||||||
|
|
||||||
#ifdef MEASURE_NOISE
|
|
||||||
// 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++;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -445,7 +420,7 @@ void demodulate2400(struct mag_buf *mag) {
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
for (k = 0; k < signal_len; ++k) {
|
for (k = 0; k < signal_len; ++k) {
|
||||||
uint64_t s = TRUE_AMPLITUDE(m[j+19+k]);
|
uint64_t s = m[j+19+k];
|
||||||
signal_power_sum += s * s;
|
signal_power_sum += s * s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,6 +432,8 @@ void demodulate2400(struct mag_buf *mag) {
|
||||||
Modes.stats_current.peak_signal_power = signal_power;
|
Modes.stats_current.peak_signal_power = signal_power;
|
||||||
if (signal_power > 0.50119)
|
if (signal_power > 0.50119)
|
||||||
Modes.stats_current.strong_signal_count++; // signal power above -3dBFS
|
Modes.stats_current.strong_signal_count++; // signal power above -3dBFS
|
||||||
|
|
||||||
|
total_signal_power += signal_power_sum / MAX_POWER;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode the received message
|
// Decode the received message
|
||||||
|
@ -480,18 +457,16 @@ void demodulate2400(struct mag_buf *mag) {
|
||||||
// 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)
|
||||||
#ifdef MEASURE_NOISE
|
|
||||||
last_message_end = j + (8 + msglen)*12/5;
|
|
||||||
#endif
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MEASURE_NOISE
|
/* update noise power if measured */
|
||||||
Modes.stats_current.noise_power_sum += (noise_power_sum / MAX_POWER / noise_power_count);
|
if (Modes.measure_noise) {
|
||||||
|
Modes.stats_current.noise_power_sum += (mag->total_power - total_signal_power) / mag->length;
|
||||||
Modes.stats_current.noise_power_count ++;
|
Modes.stats_current.noise_power_count ++;
|
||||||
#endif
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
180
dump1090.c
180
dump1090.c
|
@ -166,9 +166,16 @@ void modesInit(void) {
|
||||||
pthread_mutex_init(&Modes.data_mutex,NULL);
|
pthread_mutex_init(&Modes.data_mutex,NULL);
|
||||||
pthread_cond_init(&Modes.data_cond,NULL);
|
pthread_cond_init(&Modes.data_cond,NULL);
|
||||||
|
|
||||||
|
if (Modes.oversample)
|
||||||
|
Modes.sample_rate = 2400000.0;
|
||||||
|
else
|
||||||
|
Modes.sample_rate = 2000000.0;
|
||||||
|
|
||||||
// Allocate the various buffers used by Modes
|
// Allocate the various buffers used by Modes
|
||||||
Modes.trailing_samples = (Modes.oversample ? (MODES_OS_PREAMBLE_SAMPLES + MODES_OS_LONG_MSG_SAMPLES) : (MODES_PREAMBLE_SAMPLES + MODES_LONG_MSG_SAMPLES)) + 16;
|
Modes.trailing_samples = (MODES_PREAMBLE_US + MODES_LONG_MSG_BITS + 16) * 1e-6 * Modes.sample_rate;
|
||||||
|
|
||||||
if ( ((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
|
if ( ((Modes.maglut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
|
||||||
|
((Modes.magsqlut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) ||
|
||||||
((Modes.log10lut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) )
|
((Modes.log10lut = (uint16_t *) malloc(sizeof(uint16_t) * 256 * 256) ) == NULL) )
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Out of memory allocating data buffer.\n");
|
fprintf(stderr, "Out of memory allocating data buffer.\n");
|
||||||
|
@ -213,54 +220,26 @@ void modesInit(void) {
|
||||||
if (Modes.net_sndbuf_size > (MODES_NET_SNDBUF_MAX))
|
if (Modes.net_sndbuf_size > (MODES_NET_SNDBUF_MAX))
|
||||||
{Modes.net_sndbuf_size = MODES_NET_SNDBUF_MAX;}
|
{Modes.net_sndbuf_size = MODES_NET_SNDBUF_MAX;}
|
||||||
|
|
||||||
// Each I and Q value varies from 0 to 255, which represents a range from -1 to +1. To get from the
|
// compute UC8 magnitude lookup table
|
||||||
// unsigned (0-255) range you therefore subtract 127 (or 128 or 127.5) from each I and Q, giving you
|
|
||||||
// a range from -127 to +128 (or -128 to +127, or -127.5 to +127.5)..
|
|
||||||
//
|
|
||||||
// To decode the AM signal, you need the magnitude of the waveform, which is given by sqrt((I^2)+(Q^2))
|
|
||||||
// The most this could be is if I&Q are both 128 (or 127 or 127.5), so you could end up with a magnitude
|
|
||||||
// of 181.019 (or 179.605, or 180.312)
|
|
||||||
//
|
|
||||||
// However, in reality the magnitude of the signal should never exceed the range -1 to +1, because the
|
|
||||||
// values are I = rCos(w) and Q = rSin(w). Therefore the integer computed magnitude should (can?) never
|
|
||||||
// exceed 128 (or 127, or 127.5 or whatever)
|
|
||||||
//
|
|
||||||
// If we scale up the results so that they range from 0 to 65535 (16 bits) then we need to multiply
|
|
||||||
// by 511.99, (or 516.02 or 514). antirez's original code multiplies by 360, presumably because he's
|
|
||||||
// assuming the maximim calculated amplitude is 181.019, and (181.019 * 360) = 65166.
|
|
||||||
//
|
|
||||||
// So lets see if we can improve things by subtracting 127.5, Well in integer arithmatic we can't
|
|
||||||
// subtract half, so, we'll double everything up and subtract one, and then compensate for the doubling
|
|
||||||
// in the multiplier at the end.
|
|
||||||
//
|
|
||||||
// If we do this we can never have I or Q equal to 0 - they can only be as small as +/- 1.
|
|
||||||
// This gives us a minimum magnitude of root 2 (0.707), so the dynamic range becomes (1.414-255). This
|
|
||||||
// also affects our scaling value, which is now 65535/(255 - 1.414), or 258.433254
|
|
||||||
//
|
|
||||||
// The sums then become mag = 258.433254 * (sqrt((I*2-255)^2 + (Q*2-255)^2) - 1.414)
|
|
||||||
// or mag = (258.433254 * sqrt((I*2-255)^2 + (Q*2-255)^2)) - 365.4798
|
|
||||||
//
|
|
||||||
// We also need to clip mag just incaes any rogue I/Q values somehow do have a magnitude greater than 255.
|
|
||||||
//
|
|
||||||
|
|
||||||
for (i = 0; i <= 255; i++) {
|
for (i = 0; i <= 255; i++) {
|
||||||
for (q = 0; q <= 255; q++) {
|
for (q = 0; q <= 255; q++) {
|
||||||
int mag, mag_i, mag_q;
|
float fI, fQ, magsq;
|
||||||
|
|
||||||
mag_i = (i * 2) - 255;
|
fI = (i - 127.5) / 127.5;
|
||||||
mag_q = (q * 2) - 255;
|
fQ = (q - 127.5) / 127.5;
|
||||||
|
magsq = fI * fI + fQ * fQ;
|
||||||
|
if (magsq > 1)
|
||||||
|
magsq = 1;
|
||||||
|
|
||||||
mag = (int) round((sqrt((mag_i*mag_i)+(mag_q*mag_q)) * 258.433254) - 365.4798);
|
Modes.magsqlut[le16toh((i*256)+q)] = (uint16_t) round(magsq * 65535.0);
|
||||||
|
Modes.maglut[le16toh((i*256)+q)] = (uint16_t) round(sqrtf(magsq) * 65535.0);
|
||||||
Modes.maglut[(i*256)+q] = (uint16_t) ((mag < 65535) ? mag : 65535);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the log10 lookup table.
|
// Prepare the log10 lookup table: 100log10(x)
|
||||||
// This maps from a magnitude value x (scaled as above) to 100log10(x)
|
Modes.log10lut[0] = 0; // poorly defined..
|
||||||
for (i = 0; i <= 65535; i++) {
|
for (i = 1; i <= 65535; i++) {
|
||||||
int l10 = (int) round(100 * log10( (i + 365.4798) / 258.433254) );
|
Modes.log10lut[i] = (uint16_t) round(100.0 * log10(i));
|
||||||
Modes.log10lut[i] = (uint16_t) ((l10 < 65535 ? l10 : 65535));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare error correction tables
|
// Prepare error correction tables
|
||||||
|
@ -269,7 +248,32 @@ void modesInit(void) {
|
||||||
|
|
||||||
if (Modes.show_only)
|
if (Modes.show_only)
|
||||||
icaoFilterAdd(Modes.show_only);
|
icaoFilterAdd(Modes.show_only);
|
||||||
|
|
||||||
|
// Prepare sample conversion
|
||||||
|
if (!Modes.net_only) {
|
||||||
|
if (Modes.filename == NULL) // using a real RTLSDR, use UC8 input always
|
||||||
|
Modes.input_format = INPUT_UC8;
|
||||||
|
|
||||||
|
Modes.converter_function = init_converter(Modes.input_format,
|
||||||
|
Modes.sample_rate,
|
||||||
|
Modes.dc_filter,
|
||||||
|
Modes.measure_noise, /* total power is interesting if we want noise */
|
||||||
|
&Modes.converter_state);
|
||||||
|
if (!Modes.converter_function) {
|
||||||
|
fprintf(stderr, "Can't initialize sample converter, giving up.\n");
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_samples(void *iq,
|
||||||
|
uint16_t *mag,
|
||||||
|
unsigned nsamples,
|
||||||
|
double *power)
|
||||||
|
{
|
||||||
|
Modes.converter_function(iq, mag, nsamples, Modes.converter_state, power);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// =============================== RTLSDR handling ==========================
|
// =============================== RTLSDR handling ==========================
|
||||||
//
|
//
|
||||||
|
@ -361,7 +365,7 @@ int modesInitRTLSDR(void) {
|
||||||
rtlsdr_set_freq_correction(Modes.dev, Modes.ppm_error);
|
rtlsdr_set_freq_correction(Modes.dev, Modes.ppm_error);
|
||||||
if (Modes.enable_agc) rtlsdr_set_agc_mode(Modes.dev, 1);
|
if (Modes.enable_agc) rtlsdr_set_agc_mode(Modes.dev, 1);
|
||||||
rtlsdr_set_center_freq(Modes.dev, Modes.freq);
|
rtlsdr_set_center_freq(Modes.dev, Modes.freq);
|
||||||
rtlsdr_set_sample_rate(Modes.dev, Modes.oversample ? MODES_OVERSAMPLE_RATE : MODES_DEFAULT_RATE);
|
rtlsdr_set_sample_rate(Modes.dev, (unsigned)Modes.sample_rate);
|
||||||
|
|
||||||
rtlsdr_reset_buffer(Modes.dev);
|
rtlsdr_reset_buffer(Modes.dev);
|
||||||
fprintf(stderr, "Gain reported by device: %.2f dB\n",
|
fprintf(stderr, "Gain reported by device: %.2f dB\n",
|
||||||
|
@ -386,7 +390,6 @@ static struct timespec reader_thread_start;
|
||||||
void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) {
|
void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) {
|
||||||
struct mag_buf *outbuf;
|
struct mag_buf *outbuf;
|
||||||
struct mag_buf *lastbuf;
|
struct mag_buf *lastbuf;
|
||||||
uint16_t *p, *q;
|
|
||||||
uint32_t slen;
|
uint32_t slen;
|
||||||
unsigned next_free_buffer;
|
unsigned next_free_buffer;
|
||||||
unsigned free_bufs;
|
unsigned free_bufs;
|
||||||
|
@ -445,13 +448,8 @@ void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) {
|
||||||
pthread_mutex_unlock(&Modes.data_mutex);
|
pthread_mutex_unlock(&Modes.data_mutex);
|
||||||
|
|
||||||
// Compute the sample timestamp and system timestamp for the start of the block
|
// Compute the sample timestamp and system timestamp for the start of the block
|
||||||
if (Modes.oversample) {
|
outbuf->sampleTimestamp = lastbuf->sampleTimestamp + 12e6 * (lastbuf->length + outbuf->dropped) / Modes.sample_rate;
|
||||||
outbuf->sampleTimestamp = lastbuf->sampleTimestamp + (lastbuf->length + outbuf->dropped) * 5;
|
block_duration = 1e9 * slen / Modes.sample_rate;
|
||||||
block_duration = slen * 5000U / 12;
|
|
||||||
} else {
|
|
||||||
outbuf->sampleTimestamp = lastbuf->sampleTimestamp + (lastbuf->length + outbuf->dropped) * 6;
|
|
||||||
block_duration = slen * 6000U / 12;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the approx system time for the start of this block
|
// Get the approx system time for the start of this block
|
||||||
clock_gettime(CLOCK_REALTIME, &outbuf->sysTimestamp);
|
clock_gettime(CLOCK_REALTIME, &outbuf->sysTimestamp);
|
||||||
|
@ -462,15 +460,12 @@ void rtlsdrCallback(unsigned char *buf, uint32_t len, void *ctx) {
|
||||||
if (outbuf->dropped == 0 && lastbuf->length >= Modes.trailing_samples) {
|
if (outbuf->dropped == 0 && lastbuf->length >= Modes.trailing_samples) {
|
||||||
memcpy(outbuf->data, lastbuf->data + lastbuf->length - Modes.trailing_samples, Modes.trailing_samples * sizeof(uint16_t));
|
memcpy(outbuf->data, lastbuf->data + lastbuf->length - Modes.trailing_samples, Modes.trailing_samples * sizeof(uint16_t));
|
||||||
} else {
|
} else {
|
||||||
memset(outbuf->data, 127, Modes.trailing_samples * sizeof(uint16_t));
|
memset(outbuf->data, 0, Modes.trailing_samples * sizeof(uint16_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert the new data
|
// Convert the new data
|
||||||
outbuf->length = slen;
|
outbuf->length = slen;
|
||||||
p = (uint16_t*)buf;
|
convert_samples(buf, &outbuf->data[Modes.trailing_samples], slen, &outbuf->total_power);
|
||||||
q = &outbuf->data[Modes.trailing_samples];
|
|
||||||
while (slen-- > 0)
|
|
||||||
*q++ = Modes.maglut[*p++];
|
|
||||||
|
|
||||||
// Push the new data to the demodulation thread
|
// Push the new data to the demodulation thread
|
||||||
pthread_mutex_lock(&Modes.data_mutex);
|
pthread_mutex_lock(&Modes.data_mutex);
|
||||||
|
@ -498,7 +493,7 @@ void readDataFromFile(void) {
|
||||||
void *readbuf;
|
void *readbuf;
|
||||||
int bytes_per_sample = 0;
|
int bytes_per_sample = 0;
|
||||||
|
|
||||||
switch (Modes.file_format) {
|
switch (Modes.input_format) {
|
||||||
case INPUT_UC8:
|
case INPUT_UC8:
|
||||||
bytes_per_sample = 2;
|
bytes_per_sample = 2;
|
||||||
break;
|
break;
|
||||||
|
@ -518,14 +513,10 @@ void readDataFromFile(void) {
|
||||||
pthread_mutex_lock(&Modes.data_mutex);
|
pthread_mutex_lock(&Modes.data_mutex);
|
||||||
while (!Modes.exit && !eof) {
|
while (!Modes.exit && !eof) {
|
||||||
ssize_t nread, toread;
|
ssize_t nread, toread;
|
||||||
|
|
||||||
void *r;
|
void *r;
|
||||||
uint16_t *in, *out;
|
|
||||||
|
|
||||||
struct mag_buf *outbuf, *lastbuf;
|
struct mag_buf *outbuf, *lastbuf;
|
||||||
unsigned next_free_buffer;
|
unsigned next_free_buffer;
|
||||||
unsigned slen;
|
unsigned slen;
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
next_free_buffer = (Modes.first_free_buffer + 1) % MODES_MAG_BUFFERS;
|
next_free_buffer = (Modes.first_free_buffer + 1) % MODES_MAG_BUFFERS;
|
||||||
if (next_free_buffer == Modes.first_filled_buffer) {
|
if (next_free_buffer == Modes.first_filled_buffer) {
|
||||||
|
@ -539,11 +530,7 @@ void readDataFromFile(void) {
|
||||||
pthread_mutex_unlock(&Modes.data_mutex);
|
pthread_mutex_unlock(&Modes.data_mutex);
|
||||||
|
|
||||||
// Compute the sample timestamp and system timestamp for the start of the block
|
// Compute the sample timestamp and system timestamp for the start of the block
|
||||||
if (Modes.oversample) {
|
outbuf->sampleTimestamp = lastbuf->sampleTimestamp + 12e6 * lastbuf->length / Modes.sample_rate;
|
||||||
outbuf->sampleTimestamp = lastbuf->sampleTimestamp + lastbuf->length * 5;
|
|
||||||
} else {
|
|
||||||
outbuf->sampleTimestamp = lastbuf->sampleTimestamp + lastbuf->length * 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy trailing data from last block (or reset if not valid)
|
// Copy trailing data from last block (or reset if not valid)
|
||||||
if (lastbuf->length >= Modes.trailing_samples) {
|
if (lastbuf->length >= Modes.trailing_samples) {
|
||||||
|
@ -571,42 +558,7 @@ void readDataFromFile(void) {
|
||||||
slen = outbuf->length = MODES_MAG_BUF_SAMPLES - toread/bytes_per_sample;
|
slen = outbuf->length = MODES_MAG_BUF_SAMPLES - toread/bytes_per_sample;
|
||||||
|
|
||||||
// Convert the new data
|
// Convert the new data
|
||||||
out = outbuf->data + Modes.trailing_samples;
|
convert_samples(readbuf, &outbuf->data[Modes.trailing_samples], slen, &outbuf->total_power);
|
||||||
in = (uint16_t*)readbuf;
|
|
||||||
switch (Modes.file_format) {
|
|
||||||
case INPUT_UC8:
|
|
||||||
for (i = 0; i < slen; ++i)
|
|
||||||
*out++ = Modes.maglut[*in++];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INPUT_SC16:
|
|
||||||
for (i = 0; i < slen; ++i) {
|
|
||||||
int16_t I, Q;
|
|
||||||
float mag;
|
|
||||||
|
|
||||||
I = (int16_t)le16toh(*in++);
|
|
||||||
Q = (int16_t)le16toh(*in++);
|
|
||||||
mag = sqrtf(I*I + Q*Q) * (65536.0 / 32768.0);
|
|
||||||
if (mag > 65535)
|
|
||||||
mag = 65535;
|
|
||||||
*out++ = (uint16_t)mag;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INPUT_SC16Q11:
|
|
||||||
for (i = 0; i < slen; ++i) {
|
|
||||||
int16_t I, Q;
|
|
||||||
float mag;
|
|
||||||
|
|
||||||
I = (int16_t)le16toh(*in++);
|
|
||||||
Q = (int16_t)le16toh(*in++);
|
|
||||||
mag = sqrtf(I*I + Q*Q) * (65536.0 / 2048.0);
|
|
||||||
if (mag > 65535)
|
|
||||||
mag = 65535;
|
|
||||||
*out++ = (uint16_t)mag;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Modes.interactive) {
|
if (Modes.interactive) {
|
||||||
// Wait until we are allowed to release this buffer to the main thread
|
// Wait until we are allowed to release this buffer to the main thread
|
||||||
|
@ -614,7 +566,7 @@ void readDataFromFile(void) {
|
||||||
;
|
;
|
||||||
|
|
||||||
// compute the time we can deliver the next buffer.
|
// compute the time we can deliver the next buffer.
|
||||||
next_buffer_delivery.tv_nsec += (outbuf->length * (Modes.oversample ? 5000 : 6000) / 12);
|
next_buffer_delivery.tv_nsec += outbuf->length * 1e9 / Modes.sample_rate;
|
||||||
normalize_timespec(&next_buffer_delivery);
|
normalize_timespec(&next_buffer_delivery);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -719,6 +671,7 @@ void showHelp(void) {
|
||||||
"--enable-agc Enable the Automatic Gain Control (default: off)\n"
|
"--enable-agc Enable the Automatic Gain Control (default: off)\n"
|
||||||
"--freq <hz> Set frequency (default: 1090 Mhz)\n"
|
"--freq <hz> Set frequency (default: 1090 Mhz)\n"
|
||||||
"--ifile <filename> Read data from file (use '-' for stdin)\n"
|
"--ifile <filename> Read data from file (use '-' for stdin)\n"
|
||||||
|
"--iformat <format> Sample format for --ifile: UC8 (default), SC16, or SC16Q11\n"
|
||||||
"--interactive Interactive mode refreshing data on screen\n"
|
"--interactive Interactive mode refreshing data on screen\n"
|
||||||
"--interactive-rows <num> Max number of rows in interactive mode (default: 15)\n"
|
"--interactive-rows <num> Max number of rows in interactive mode (default: 15)\n"
|
||||||
"--interactive-ttl <sec> Remove from list if idle for <sec> (default: 60)\n"
|
"--interactive-ttl <sec> Remove from list if idle for <sec> (default: 60)\n"
|
||||||
|
@ -758,11 +711,12 @@ void showHelp(void) {
|
||||||
"--quiet Disable output to stdout. Use for daemon applications\n"
|
"--quiet Disable output to stdout. Use for daemon applications\n"
|
||||||
"--show-only <addr> Show only messages from the given ICAO on stdout\n"
|
"--show-only <addr> Show only messages from the given ICAO on stdout\n"
|
||||||
"--ppm <error> Set receiver error in parts per million (default 0)\n"
|
"--ppm <error> Set receiver error in parts per million (default 0)\n"
|
||||||
"--no-decode Don't decode the message contents beyond the minimum necessary\n"
|
|
||||||
"--write-json <dir> Periodically write json output to <dir> (for serving by a separate webserver)\n"
|
"--write-json <dir> Periodically write json output to <dir> (for serving by a separate webserver)\n"
|
||||||
"--write-json-every <t> Write json output every t seconds (default 1)\n"
|
"--write-json-every <t> Write json output every t seconds (default 1)\n"
|
||||||
"--json-location-accuracy <n> Accuracy of receiver location in json metadata: 0=no location, 1=approximate, 2=exact\n"
|
"--json-location-accuracy <n> Accuracy of receiver location in json metadata: 0=no location, 1=approximate, 2=exact\n"
|
||||||
"--oversample Enable oversampling at 2.4MHz\n"
|
"--oversample Use the 2.4MHz demodulator\n"
|
||||||
|
"--dcfilter Apply a 1Hz DC filter to input data (requires lots more CPU)\n"
|
||||||
|
"--measure-noise Measure noise power (requires slightly more CPU)\n"
|
||||||
"--help Show this help\n"
|
"--help Show this help\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Debug mode flags: d = Log frames decoded with errors\n"
|
"Debug mode flags: d = Log frames decoded with errors\n"
|
||||||
|
@ -974,16 +928,20 @@ int main(int argc, char **argv) {
|
||||||
} else if (!strcmp(argv[j],"--iformat") && more) {
|
} else if (!strcmp(argv[j],"--iformat") && more) {
|
||||||
++j;
|
++j;
|
||||||
if (!strcasecmp(argv[j], "uc8")) {
|
if (!strcasecmp(argv[j], "uc8")) {
|
||||||
Modes.file_format = INPUT_UC8;
|
Modes.input_format = INPUT_UC8;
|
||||||
} else if (!strcasecmp(argv[j], "sc16")) {
|
} else if (!strcasecmp(argv[j], "sc16")) {
|
||||||
Modes.file_format = INPUT_SC16;
|
Modes.input_format = INPUT_SC16;
|
||||||
} else if (!strcasecmp(argv[j], "sc16q11")) {
|
} else if (!strcasecmp(argv[j], "sc16q11")) {
|
||||||
Modes.file_format = INPUT_SC16Q11;
|
Modes.input_format = INPUT_SC16Q11;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Input format '%s' not understood (supported values: UC8, SC16, SC16Q11)\n",
|
fprintf(stderr, "Input format '%s' not understood (supported values: UC8, SC16, SC16Q11)\n",
|
||||||
argv[j]);
|
argv[j]);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(argv[j],"--dcfilter")) {
|
||||||
|
Modes.dc_filter = 1;
|
||||||
|
} else if (!strcmp(argv[j],"--measure-noise")) {
|
||||||
|
Modes.measure_noise = 1;
|
||||||
} else if (!strcmp(argv[j],"--fix")) {
|
} else if (!strcmp(argv[j],"--fix")) {
|
||||||
Modes.nfix_crc = 1;
|
Modes.nfix_crc = 1;
|
||||||
} else if (!strcmp(argv[j],"--no-fix")) {
|
} else if (!strcmp(argv[j],"--no-fix")) {
|
||||||
|
@ -1224,10 +1182,11 @@ int main(int argc, char **argv) {
|
||||||
// stuff at the same time.
|
// stuff at the same time.
|
||||||
pthread_mutex_unlock(&Modes.data_mutex);
|
pthread_mutex_unlock(&Modes.data_mutex);
|
||||||
|
|
||||||
if (Modes.oversample)
|
if (Modes.oversample) {
|
||||||
demodulate2400(buf);
|
demodulate2400(buf);
|
||||||
else
|
} else {
|
||||||
demodulate2000(buf);
|
demodulate2000(buf);
|
||||||
|
}
|
||||||
|
|
||||||
Modes.stats_current.samples_processed += buf->length;
|
Modes.stats_current.samples_processed += buf->length;
|
||||||
Modes.stats_current.samples_dropped += buf->dropped;
|
Modes.stats_current.samples_dropped += buf->dropped;
|
||||||
|
@ -1262,6 +1221,7 @@ int main(int argc, char **argv) {
|
||||||
display_total_stats();
|
display_total_stats();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup_converter(Modes.converter_state);
|
||||||
log_with_timestamp("Normal exit.");
|
log_with_timestamp("Normal exit.");
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
|
20
dump1090.h
20
dump1090.h
|
@ -205,10 +205,8 @@
|
||||||
|
|
||||||
#define MODES_NOTUSED(V) ((void) V)
|
#define MODES_NOTUSED(V) ((void) V)
|
||||||
|
|
||||||
// adjust for zero offset of amplitude values
|
#define MAX_AMPLITUDE 65535.0
|
||||||
#define TRUE_AMPLITUDE(x) ((x) + 365)
|
#define MAX_POWER (MAX_AMPLITUDE * MAX_AMPLITUDE)
|
||||||
#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
|
||||||
|
|
||||||
|
@ -220,6 +218,7 @@
|
||||||
#include "stats.h"
|
#include "stats.h"
|
||||||
#include "cpr.h"
|
#include "cpr.h"
|
||||||
#include "icao_filter.h"
|
#include "icao_filter.h"
|
||||||
|
#include "convert.h"
|
||||||
|
|
||||||
//======================== structure declarations =========================
|
//======================== structure declarations =========================
|
||||||
|
|
||||||
|
@ -248,10 +247,9 @@ struct mag_buf {
|
||||||
uint64_t sampleTimestamp; // Clock timestamp of the start of this block, 12MHz clock
|
uint64_t sampleTimestamp; // Clock timestamp of the start of this block, 12MHz clock
|
||||||
struct timespec sysTimestamp; // Estimated system time at start of block
|
struct timespec sysTimestamp; // Estimated system time at start of block
|
||||||
uint32_t dropped; // Number of dropped samples preceding this buffer
|
uint32_t dropped; // Number of dropped samples preceding this buffer
|
||||||
|
double total_power; // Sum of per-sample input power (in the range [0.0,1.0] per sample), or 0 if not measured
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum { INPUT_UC8=0, INPUT_SC16, INPUT_SC16Q11 } input_format_t;
|
|
||||||
|
|
||||||
// Program global state
|
// Program global state
|
||||||
struct { // Internal state
|
struct { // Internal state
|
||||||
pthread_t reader_thread;
|
pthread_t reader_thread;
|
||||||
|
@ -265,13 +263,21 @@ struct { // Internal state
|
||||||
struct timespec reader_cpu_accumulator; // CPU time used by the reader thread, copied out and reset by the main thread under the mutex
|
struct timespec reader_cpu_accumulator; // CPU time used by the reader thread, copied out and reset by the main thread under the mutex
|
||||||
|
|
||||||
unsigned trailing_samples; // extra trailing samples in magnitude buffers
|
unsigned trailing_samples; // extra trailing samples in magnitude buffers
|
||||||
|
double sample_rate; // actual sample rate in use (in hz)
|
||||||
|
|
||||||
int fd; // --ifile option file descriptor
|
int fd; // --ifile option file descriptor
|
||||||
input_format_t file_format; // --iformat option
|
input_format_t input_format; // --iformat option
|
||||||
uint16_t *maglut; // I/Q -> Magnitude lookup table
|
uint16_t *maglut; // I/Q -> Magnitude lookup table
|
||||||
|
uint16_t *magsqlut; // I/Q -> Magnitude-squared lookup table
|
||||||
uint16_t *log10lut; // Magnitude -> log10 lookup table
|
uint16_t *log10lut; // Magnitude -> log10 lookup table
|
||||||
int exit; // Exit from the main loop when true
|
int exit; // Exit from the main loop when true
|
||||||
|
|
||||||
|
// Sample conversion
|
||||||
|
int dc_filter; // should we apply a DC filter?
|
||||||
|
int measure_noise; // should we measure noise power?
|
||||||
|
iq_convert_fn converter_function;
|
||||||
|
struct converter_state *converter_state;
|
||||||
|
|
||||||
// RTLSDR
|
// RTLSDR
|
||||||
char * dev_name;
|
char * dev_name;
|
||||||
int gain;
|
int gain;
|
||||||
|
|
|
@ -306,7 +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);}
|
||||||
|
|
||||||
mm->signalLevel = 1.0 * TRUE_AMPLITUDE(fSig + fNoise) * TRUE_AMPLITUDE(fSig + fNoise) / MAX_POWER;
|
mm->signalLevel = (fSig + fNoise) * (fSig + fNoise) / MAX_POWER;
|
||||||
|
|
||||||
return ModeABits;
|
return ModeABits;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue