Skip to content

Commit

Permalink
Use whole/fractional timestamps in the whole chain. This prevents loss
Browse files Browse the repository at this point in the history
of precision when setting time to UTC.
  • Loading branch information
bistromath committed Apr 17, 2015
1 parent da15a2d commit 9bdac2a
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 37 deletions.
6 changes: 3 additions & 3 deletions include/gr_air_modes/preamble.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ class AIR_MODES_API preamble : virtual public gr::block
{
public:
typedef boost::shared_ptr<preamble> sptr;
static sptr make(int channel_rate, float threshold_db);
static sptr make(float channel_rate, float threshold_db);

virtual void set_rate(int channel_rate) = 0;
virtual void set_rate(float channel_rate) = 0;
virtual void set_threshold(float threshold_db) = 0;
virtual int get_rate(void) = 0;
virtual float get_rate(void) = 0;
virtual float get_threshold(void) = 0;
};

Expand Down
57 changes: 35 additions & 22 deletions lib/preamble_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@

namespace gr {

air_modes::preamble::sptr air_modes::preamble::make(int channel_rate, float threshold_db) {
air_modes::preamble::sptr air_modes::preamble::make(float channel_rate, float threshold_db) {
return gnuradio::get_initial_sptr(new air_modes::preamble_impl(channel_rate, threshold_db));
}

air_modes::preamble_impl::preamble_impl(int channel_rate, float threshold_db) :
air_modes::preamble_impl::preamble_impl(float channel_rate, float threshold_db) :
gr::block ("preamble",
gr::io_signature::make2 (2, 2, sizeof(float), sizeof(float)), //stream 0 is received data, stream 1 is moving average for reference
gr::io_signature::make (1, 1, sizeof(float))) //the output soft symbols
Expand All @@ -53,11 +53,11 @@ air_modes::preamble_impl::preamble_impl(int channel_rate, float threshold_db) :
d_key = pmt::string_to_symbol("preamble_found");
}

void air_modes::preamble_impl::set_rate(int channel_rate) {
void air_modes::preamble_impl::set_rate(float channel_rate) {
d_samples_per_chip = channel_rate / d_chip_rate;
d_samples_per_symbol = d_samples_per_chip * 2;
d_check_width = 120 * d_samples_per_symbol;
d_secs_per_sample = 1.0/channel_rate;
d_sample_rate = channel_rate;
set_output_multiple(1+d_check_width*2);
set_history(d_samples_per_symbol);
}
Expand All @@ -71,8 +71,8 @@ float air_modes::preamble_impl::get_threshold(void) {
return d_threshold_db;
}

int air_modes::preamble_impl::get_rate(void) {
return d_samples_per_chip * d_chip_rate;
float air_modes::preamble_impl::get_rate(void) {
return d_sample_rate;
}

static void integrate_and_dump(float *out, const float *in, int chips, int samps_per_chip) {
Expand All @@ -97,19 +97,34 @@ static double correlate_preamble(const float *in, int samples_per_chip) {
return corr;
}

//todo: make it return a pair of some kind, otherwise you can lose precision
static double tag_to_timestamp(gr::tag_t tstamp, uint64_t abs_sample_cnt, double secs_per_sample) {
uint64_t ts_sample, last_whole_stamp;
double last_frac_stamp;

static pmt::pmt_t tag_to_timestamp(gr::tag_t tstamp, uint64_t abs_sample_cnt, int rate) {
if(tstamp.key == NULL || pmt::symbol_to_string(tstamp.key) != "rx_time") return 0;

last_whole_stamp = pmt::to_uint64(pmt::tuple_ref(tstamp.value, 0));
last_frac_stamp = pmt::to_double(pmt::tuple_ref(tstamp.value, 1));
ts_sample = tstamp.offset;
//the timestamp tag has tstamp.offset, the sample index of the timestamp tag
//also tstamp.value, a pmt pair with (uint64, double) representing int and
//fractional timestamp, respectively.
//this function also gets an abs_sample_cnt which represents the sample count to
//find a timestamp for. sps is obviously samples per second.
//
//so (abs_sample_cnt - tstamp.offset) is the delay we apply to the tag
// int((abs_sample_cnt - tstamp.offset)/sps) is the integer offset
// (abs_sample_cnt - tstamp.offset)/sps is the fractional offset

uint64_t last_whole_stamp = pmt::to_uint64(pmt::tuple_ref(tstamp.value, 0));
double last_frac_stamp = pmt::to_double(pmt::tuple_ref(tstamp.value, 1));
std::cout << "Rate: " << rate << std::endl;
uint64_t int_offset = int(abs_sample_cnt - tstamp.offset)/rate;
double frac_offset = ((abs_sample_cnt - tstamp.offset) % rate) / double(rate);

uint64_t abs_whole = last_whole_stamp + int_offset;
double abs_frac = last_frac_stamp + frac_offset;
if(abs_frac > 1.0f) {
abs_frac -= 1.0f;
abs_whole += 1.0f;
}

pmt::pmt_t tstime = pmt::make_tuple(pmt::from_uint64(abs_whole), pmt::from_double(abs_frac));

double tstime = double(abs_sample_cnt * secs_per_sample) + last_whole_stamp + last_frac_stamp;
if(0) std::cout << "HEY WE GOT A STAMP AT " << tstime << " TICKS AT SAMPLE " << ts_sample << " ABS SAMPLE CNT IS " << abs_sample_cnt << std::endl;
return tstime;
}

Expand All @@ -124,7 +139,7 @@ int air_modes::preamble_impl::general_work(int noutput_items,
int mininputs = std::min(ninput_items[0], ninput_items[1]); //they should be matched but let's be safe
//round number of input samples down to nearest d_samples_per_chip
//we also subtract off d_samples_per_chip to allow the bit center finder some leeway
const int ninputs = std::max(mininputs - (mininputs % d_samples_per_chip) - d_samples_per_chip, 0);
const int ninputs = std::max(mininputs - (mininputs % int(d_samples_per_chip)) - int(d_samples_per_chip), 0);
if (ninputs <= 0) { consume_each(0); return 0; }

float *out = (float *) output_items[0];
Expand Down Expand Up @@ -194,22 +209,20 @@ int air_modes::preamble_impl::general_work(int noutput_items,

//all right i'm prepared to call this a preamble
for(int j=0; j<240; j++) {
out[j] = in[i+j*d_samples_per_chip] - inavg[i];
out[j] = in[i+int(j*d_samples_per_chip)] - inavg[i];
}

//get the timestamp of the preamble
double tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_secs_per_sample);
pmt::pmt_t tstamp = tag_to_timestamp(d_timestamp, abs_sample_cnt + i, d_sample_rate);

//now tag the preamble
add_item_tag(0, //stream ID
nitems_written(0), //sample
d_key, //frame_info
pmt::from_double(tstamp),
tstamp,
d_me //block src id
);

//std::cout << "PREAMBLE" << std::endl;

//produce only one output per work call -- TODO this should probably change
if(0) std::cout << "Preamble consumed " << i+240*d_samples_per_chip << "with i=" << i << ", returned 240" << std::endl;

Expand Down
14 changes: 7 additions & 7 deletions lib/preamble_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ class AIR_MODES_API preamble_impl : public preamble
int d_check_width;
int d_chip_rate;
float d_preamble_length_us;
int d_samples_per_chip;
int d_samples_per_symbol;
float d_samples_per_chip;
float d_samples_per_symbol;
float d_threshold_db;
float d_threshold;
pmt::pmt_t d_me, d_key;
gr::tag_t d_timestamp;
double d_secs_per_sample;
pmt::pmt_t d_me, d_key;
int d_sample_rate;

public:
preamble_impl(int channel_rate, float threshold_db);
preamble_impl(float channel_rate, float threshold_db);

int general_work (int noutput_items,
gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items);

void set_rate(int channel_rate);
void set_rate(float channel_rate);
void set_threshold(float threshold_db);
float get_threshold(void);
int get_rate(void);
float get_rate(void);
};

} //namespace air_modes
Expand Down
6 changes: 3 additions & 3 deletions lib/slicer_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,6 @@ int air_modes::slicer_impl::work(int noutput_items,
}
}

rx_packet.timestamp = pmt::to_double(tag_iter->value);

//here you might want to traverse the whole packet and if you find all 0's, just toss it. don't know why these packets turn up, but they pass ECC.
bool zeroes = 1;
for(int m = 0; m < 14; m++) {
Expand All @@ -183,13 +181,15 @@ int air_modes::slicer_impl::work(int noutput_items,
//crc for the other short packets is usually nonzero, so they can't really be trusted that far
if(rx_packet.crc && (rx_packet.message_type == 11 || rx_packet.message_type == 17)) {continue;}

pmt::pmt_t tstamp = tag_iter->value;

d_payload.str("");
for(int m = 0; m < packet_length/8; m++) {
d_payload << std::hex << std::setw(2) << std::setfill('0') << unsigned(rx_packet.data[m]);
}

d_payload << " " << std::setw(6) << rx_packet.crc << " " << std::dec << rx_packet.reference_level
<< " " << std::setprecision(10) << std::setw(10) << rx_packet.timestamp;
<< " " << pmt::to_uint64(pmt::tuple_ref(tstamp, 0)) << " " << std::setprecision(10) << pmt::to_double(pmt::tuple_ref(tstamp, 1));
gr::message::sptr msg = gr::message::make_from_string(std::string(d_payload.str()));
d_queue->handle(msg);
}
Expand Down
1 change: 1 addition & 0 deletions lib/slicer_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class AIR_MODES_API slicer_impl : public slicer
int d_chip_rate;
int d_samples_per_chip;
int d_samples_per_symbol;
gr::tag_t d_timestamp;
gr::msg_queue::sptr d_queue;
std::ostringstream d_payload;

Expand Down
4 changes: 2 additions & 2 deletions python/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,12 +423,12 @@ def parse_TCAS_CRM(data):
def make_parser(pub):
publisher = pub
def publish(message):
[data, ecc, reference, timestamp] = message.split()
[data, ecc, reference, int_timestamp, frac_timestamp] = message.split()
try:
ret = air_modes.modes_report(modes_reply(int(data, 16)),
int(ecc, 16),
10.0*math.log10(max(1e-8,float(reference))),
air_modes.stamp(0, float(timestamp)))
air_modes.stamp(int(int_timestamp), float(frac_timestamp)))
pub["modes_dl"] = ret
pub["type%i_dl" % ret.data.get_type()] = ret
except ADSBError:
Expand Down

0 comments on commit 9bdac2a

Please sign in to comment.