Skip to content
This repository has been archived by the owner on Aug 1, 2020. It is now read-only.
/ readsb Public archive

Commit

Permalink
Factor out the sample -> magnitude conversion code and make everythin…
Browse files Browse the repository at this point in the history
…g 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)
  • Loading branch information
mutability committed Jun 15, 2015
1 parent f58ff14 commit 03b53c2
Show file tree
Hide file tree
Showing 7 changed files with 454 additions and 156 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ all: dump1090 view1090
%.o: %.c *.h
$(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)

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
Expand Down
317 changes: 317 additions & 0 deletions convert.c
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
//
// 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:https://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 changes: 40 additions & 0 deletions convert.h
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>
//
// 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:https://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

0 comments on commit 03b53c2

Please sign in to comment.