Preamble now passes tags to framer.

Note: Using set_history cocks up the nitems_written() call.
This commit is contained in:
Nick Foster
2010-11-20 16:34:44 -08:00
parent 6af11394d1
commit cd394e1863
5 changed files with 88 additions and 83 deletions

View File

@@ -28,6 +28,9 @@
#include <gr_io_signature.h>
#include <air_modes_types.h>
#include <modes_energy.h>
#include <gr_tag_info.h>
#include <iostream>
#include <string.h>
air_modes_framer_sptr air_make_modes_framer(int channel_rate)
{
@@ -36,16 +39,16 @@ air_modes_framer_sptr air_make_modes_framer(int channel_rate)
air_modes_framer::air_modes_framer(int channel_rate) :
gr_sync_block ("modes_framer",
gr_make_io_signature2 (2, 2, sizeof(float), sizeof(unsigned char)), //stream 0 is received data, stream 1 is binary preamble detector output
gr_make_io_signature (1, 1, sizeof(float)), //stream 0 is received data
gr_make_io_signature (1, 1, sizeof(unsigned char))) //output is [0, 1, 2]: [no frame, short frame, long frame]
{
//initialize private data here
d_chip_rate = 2000000; //2Mchips per second
d_samples_per_chip = channel_rate / d_chip_rate; //must be integer number of samples per chip to work
d_samples_per_symbol = d_samples_per_chip * 2;
d_check_width = 120 * d_samples_per_symbol; //gotta be able to look at two long frame lengths at a time in the event that FRUIT occurs near the end of the first frame
set_output_multiple(1+d_check_width*2);
d_check_width = 120 * d_samples_per_symbol; //gotta be able to look at two long frame lengths at a time
//in the event that FRUIT occurs near the end of the first frame
//set_history(d_check_width*2);
}
int air_modes_framer::work(int noutput_items,
@@ -54,60 +57,56 @@ int air_modes_framer::work(int noutput_items,
{
//do things!
const float *inraw = (const float *) input_items[0];
const unsigned char *inattrib = (const unsigned char *) input_items[1];
//float *outraw = (float *) output_items[0];
unsigned char *outattrib = (unsigned char *) output_items[0];
int size = noutput_items - d_check_width; //need to be able to look ahead a full frame
float reference_level = 0;
int size = noutput_items - d_check_width*2;
float reference_level;
framer_packet_type packet_attrib;
for(int i = 0; i < size; i++) {
packet_attrib = No_Packet;
if(!inattrib[i]) {
outattrib[i] = packet_attrib;
continue; //if there's no preamble marker, forget it, move on
}
std::vector<pmt::pmt_t> tags;
uint64_t abs_sample_cnt = nitems_read(0);
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + size, pmt::pmt_string_to_symbol("preamble_found"));
std::vector<pmt::pmt_t>::iterator tag_iter;
memset(outattrib, 0x00, size * sizeof(unsigned char));
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
uint64_t i = gr_tags::get_nitems(*tag_iter) - abs_sample_cnt;
//first, assume we have a long packet
packet_attrib = Long_Packet;
//let's use the preamble marker to get a reference level for the packet
reference_level = (bit_energy(&inraw[i], d_samples_per_chip)
+ bit_energy(&inraw[i+int(1.0*d_samples_per_symbol)], d_samples_per_chip)
+ bit_energy(&inraw[i+int(3.5*d_samples_per_symbol)], d_samples_per_chip)
+ bit_energy(&inraw[i+int(4.5*d_samples_per_symbol)], d_samples_per_chip)) / 4;
+ bit_energy(&inraw[i+int(1.0*d_samples_per_symbol)], d_samples_per_chip)
+ bit_energy(&inraw[i+int(3.5*d_samples_per_symbol)], d_samples_per_chip)
+ bit_energy(&inraw[i+int(4.5*d_samples_per_symbol)], d_samples_per_chip)) / 4;
//armed with our reference level, let's look for marks within 3dB of the reference level in bits 57-62 (65-70, see above)
//if bits 57-62 have marks in either chip, we've got a long packet
//otherwise we have a short packet
//NOTE: you can change the default here to be short packet, and then check for a long packet. don't know which way is better.
for(int j = (65 * d_samples_per_symbol); j < (70 * d_samples_per_symbol); j += d_samples_per_symbol) {
float t_max = (bit_energy(&inraw[i+j], d_samples_per_chip) > bit_energy(&inraw[i+j+d_samples_per_chip], d_samples_per_chip)) ? bit_energy(&inraw[i+j], d_samples_per_chip) : bit_energy(&inraw[i+j+d_samples_per_chip], d_samples_per_chip);
if(t_max < (reference_level / 2)) packet_attrib = Short_Packet;
float t_max = std::max(bit_energy(&inraw[i+j], d_samples_per_chip),
bit_energy(&inraw[i+j+d_samples_per_chip], d_samples_per_chip)
);
if(t_max < (reference_level / 2.0)) packet_attrib = Short_Packet;
}
//BUT: we must also loop through the entire packet to make sure it is clear of additional preamble markers! if it has another preamble marker, it's been FRUITed, and we must only
//BUT: we must also loop through the entire packet to make sure it is clear of additional preamble markers!
//if it has another preamble marker, it's been FRUITed, and we must only
//mark the new packet (i.e., just continue).
int lookahead;
if(packet_attrib == Long_Packet) lookahead = 112;
else lookahead = 56;
for(int j = i+1; j < i+(lookahead * d_samples_per_symbol); j++) {
if(inattrib[j]) packet_attrib = Fruited_Packet; //FRUITed by mode S! in this case, we drop this first packet
//if(inraw[j] > (reference_level * 2)) packet_attrib = Fruited_Packet; //catches strong Mode A/C fruit inside the packet
//but good error correction should cope with that
}
if(packet_attrib == Long_Packet) lookahead = 112 * d_samples_per_symbol;
else lookahead = 56 * d_samples_per_symbol;
//ok we have to re-do lookahead for this tagged version.
//we can do this by looking for tags that fall within that window
std::vector<pmt::pmt_t> fruit_tags;
get_tags_in_range(fruit_tags, 0, abs_sample_cnt+i+1, abs_sample_cnt+i+lookahead, pmt::pmt_string_to_symbol("preamble_found"));
if(fruit_tags.size() > 0) packet_attrib = Fruited_Packet;
outattrib[i] = packet_attrib;
}
return size;

View File

@@ -27,6 +27,8 @@
#include <air_modes_preamble.h>
#include <gr_io_signature.h>
#include <modes_energy.h>
#include <string.h>
#include <iostream>
air_modes_preamble_sptr air_make_modes_preamble(int channel_rate, float threshold_db)
{
@@ -36,9 +38,8 @@ air_modes_preamble_sptr air_make_modes_preamble(int channel_rate, float threshol
air_modes_preamble::air_modes_preamble(int channel_rate, float threshold_db) :
gr_sync_block ("modes_preamble",
gr_make_io_signature2 (2, 2, sizeof(float), sizeof(float)), //stream 0 is received data, stream 1 is moving average for reference
gr_make_io_signature (1, 1, sizeof(unsigned char)))
gr_make_io_signature (1, 1, sizeof(float))) //the original data. we pass it out in order to use tags.
{
//initialize private data here
d_chip_rate = 2000000; //2Mchips per second
d_samples_per_chip = channel_rate / d_chip_rate; //must be integer number of samples per chip to work
d_samples_per_symbol = d_samples_per_chip * 2;
@@ -46,6 +47,11 @@ air_modes_preamble::air_modes_preamble(int channel_rate, float threshold_db) :
d_threshold_db = threshold_db;
d_threshold = powf(10., threshold_db/10.); //the level that the sample must be above the moving average in order to qualify as a pulse
set_output_multiple(1+d_check_width*2);
std::stringstream str;
str << name() << unique_id();
d_me = pmt::pmt_string_to_symbol(str.str());
d_key = pmt::pmt_string_to_symbol("preamble_found");
//set_history(d_check_width);
}
int air_modes_preamble::work(int noutput_items,
@@ -56,12 +62,15 @@ int air_modes_preamble::work(int noutput_items,
const float *inraw = (const float *) input_items[0];
const float *inavg = (const float *) input_items[1];
//float *outraw = (float *) output_items[0];
unsigned char *outattrib = (unsigned char *) output_items[0];
float *outraw = (float *) output_items[0];
int size = noutput_items - d_check_width;
int pulse_offsets[4];
float bit_energies[4];
memcpy(outraw, inraw, size * sizeof(float));
uint64_t abs_out_sample_cnt = nitems_written(0);
for(int i = d_samples_per_chip; i < size; i++) {
float pulse_threshold = bit_energy(&inavg[i], d_samples_per_chip) * d_threshold;
@@ -69,22 +78,10 @@ int air_modes_preamble::work(int noutput_items,
float gate_sum_now = 0, gate_sum_early = 0, gate_sum_late = 0;
if(bit_energy(&inraw[i], d_samples_per_chip) > pulse_threshold) { //if the sample is greater than the reference level by the specified amount
//while(inraw[i+1] > inraw[i]) i++;
//if(inraw[i+1] > inraw[i]) continue; //we're still coming up on the pulse peak, so let's just fall out and look at it next time around
//if(inraw[i-1] > inraw[i]) continue; //we're past the peak, so it's no longer a valid pulse
//a note on the above. this simple early/late gate system works for decim = 16, but doesn't work so great for decim = 8. the extra samples, subject to noise,
//mean the peak is not necessarily the center of the bit, and you get fooled into sampling at strange bit edges. the solution is an area integral, a real early/late gate
//system, computing the area of a bit and maximizing so you sample at the center of the bit shape for any decimation. for decim = 16 it won't really matter since you only have
//one possible bit center.
int gate_sum = early_late(&inraw[i], d_samples_per_chip); //see modes_energy.cc
if(gate_sum != 0) continue; //if either the early gate or the late gate had greater energy, keep moving.
// if(gate_sum_late > gate_sum_now) continue;
//the packets are so short we choose not to do any sort of closed-loop synchronization after this simple gating. if we get a good center sample, the drift should be negligible.
//the packets are so short we choose not to do any sort of closed-loop synchronization after this simple gating.
//if we get a good center sample, the drift should be negligible.
pulse_offsets[0] = 0;
pulse_offsets[1] = int(1.0 * d_samples_per_symbol);
pulse_offsets[2] = int(3.5 * d_samples_per_symbol);
@@ -112,43 +109,52 @@ int air_modes_preamble::work(int noutput_items,
for(int j = 5 * d_samples_per_symbol; j <= 7.5 * d_samples_per_symbol; j+=d_samples_per_chip)
if(bit_energy(&inraw[i+j], d_samples_per_chip) > space_threshold) valid_preamble = false;
//make sure all four peaks are within 2dB of each other
float minpeak = avgpeak * 0.631; //-2db
float maxpeak = avgpeak * 1.585; //2db
//make sure all four peaks are within 3dB of each other
float minpeak = avgpeak * 0.5;//-3db, was 0.631; //-2db
float maxpeak = avgpeak * 2.0;//3db, was 1.585; //2db
if(bit_energies[0] < minpeak || bit_energies[0] > maxpeak) continue;
if(bit_energies[1] < minpeak || bit_energies[1] > maxpeak) continue;
if(bit_energies[2] < minpeak || bit_energies[2] > maxpeak) continue;
if(bit_energies[3] < minpeak || bit_energies[3] > maxpeak) continue;
}
//just for kicks, after validating a preamble, you might want to use all four peaks to form a more accurate "average" center sample time, so that if noise corrupts the first leading edge
//sample, you don't mis-sample the entire packet.
//this could also be done in a separate block, although it probably saves CPU to do it here
//for the 2 samples per chip case, you can just add up the peaks at the expected peak times, then do the same for +1.
if(valid_preamble) {
i--;
//get a more accurate chip center by finding the energy peak across all four preamble peaks
//there's some weirdness in the early part, so i ripped it out.
bool early, late;
do {
i++;
early = late = false;
gate_sum_early= bit_energy(&inraw[i+pulse_offsets[0]-1], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[1]-1], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[2]-1], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[3]-1], d_samples_per_chip);
gate_sum_now = bit_energy(&inraw[i+pulse_offsets[0]], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[1]], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[2]], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[3]], d_samples_per_chip);
gate_sum_late = bit_energy(&inraw[i+pulse_offsets[0]+1], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[1]+1], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[2]+1], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[3]+1], d_samples_per_chip);
} while(gate_sum_late > gate_sum_now);
outattrib[i] = 1;
gate_sum_late = bit_energy(&inraw[i+pulse_offsets[0]+1], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[1]+1], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[2]+1], d_samples_per_chip)
+ bit_energy(&inraw[i+pulse_offsets[3]+1], d_samples_per_chip);
} else outattrib[i] = 0;
early = (gate_sum_early > gate_sum_now);
late = (gate_sum_late > gate_sum_now);
if(late) i++;
//else if(early) i--;
//if(early && late) early = late = false;
} while(late);
//finally after all this, let's post the preamble!
add_item_tag(0, //stream ID
nitems_written(0)+i, //sample
d_key, //preamble_found
pmt::PMT_T, //meaningless for us
d_me //block src id
);
}
}
return size;
}

View File

@@ -47,6 +47,7 @@ private:
int d_samples_per_symbol;
float d_threshold_db;
float d_threshold;
pmt::pmt_t d_me, d_key;
public:
int work (int noutput_items,

View File

@@ -86,8 +86,6 @@ int air_modes_slicer::work(int noutput_items,
int packet_length = 112;
if(inattrib[i] == framer_packet_type(Short_Packet)) packet_length = 56;
//printf("Packet received from framer w/length %i\n", packet_length);
rx_packet.type = framer_packet_type(inattrib[i]);
memset(&rx_packet.data, 0x00, 14 * sizeof(unsigned char));
memset(&rx_packet.lowconfbits, 0x00, 24 * sizeof(unsigned char));

View File

@@ -73,12 +73,14 @@ class adsb_rx_block (gr.top_block):
print "Setting gain to %i" % (options.gain,)
self.u.set_gain(options.gain)
print "Gain is %i" % (self.u.get_gain(),)
else:
rate = options.rate
self.u = gr.file_source(gr.sizeof_gr_complex, options.filename)
print "Rate is %i" % (rate,)
pass_all = 0
if options.output_all :
pass_all = 1
@@ -113,8 +115,7 @@ class adsb_rx_block (gr.top_block):
self.connect(self.demod, self.avg)
self.connect(self.demod, (self.preamble, 0))
self.connect(self.avg, (self.preamble, 1))
self.connect(self.demod, (self.framer, 0))
self.connect(self.preamble, (self.framer, 1))
self.connect((self.preamble, 0), (self.framer, 0))
self.connect(self.demod, (self.slicer, 0))
self.connect(self.framer, (self.slicer, 1))