Everything changed.
* Rewrote preamble detector. Uses integrate-and-dump along with correlator to perform optimal receive. * No longer using framer. Determining packet length via header. Missing some anti-FRUIT stuff. * Pulled out the slicer logic into its own function. Lots of todos and fixmes.
This commit is contained in:
+10
-10
@@ -60,8 +60,8 @@ int air_modes_framer::work(int noutput_items,
|
|||||||
gr_vector_void_star &output_items)
|
gr_vector_void_star &output_items)
|
||||||
{
|
{
|
||||||
//do things!
|
//do things!
|
||||||
const float *inraw = (const float *) input_items[0];
|
const float *in = (const float *) input_items[0];
|
||||||
float *outraw = (float *) output_items[0];
|
float *out = (float *) output_items[0];
|
||||||
//unsigned char *outattrib = (unsigned char *) output_items[0];
|
//unsigned char *outattrib = (unsigned char *) output_items[0];
|
||||||
int size = noutput_items - d_check_width*2;
|
int size = noutput_items - d_check_width*2;
|
||||||
if(size < 0) return 0;
|
if(size < 0) return 0;
|
||||||
@@ -73,7 +73,7 @@ int air_modes_framer::work(int noutput_items,
|
|||||||
get_tags_in_range(tags, 0, abs_sample_cnt, abs_sample_cnt + size, pmt::pmt_string_to_symbol("preamble_found"));
|
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;
|
std::vector<pmt::pmt_t>::iterator tag_iter;
|
||||||
|
|
||||||
memcpy(outraw, inraw, size * sizeof(float));
|
memcpy(out, in, size * sizeof(float));
|
||||||
|
|
||||||
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
||||||
uint64_t i = gr_tags::get_nitems(*tag_iter) - abs_sample_cnt;
|
uint64_t i = gr_tags::get_nitems(*tag_iter) - abs_sample_cnt;
|
||||||
@@ -81,18 +81,18 @@ int air_modes_framer::work(int noutput_items,
|
|||||||
packet_attrib = Long_Packet;
|
packet_attrib = Long_Packet;
|
||||||
|
|
||||||
//let's use the preamble marker to get a reference level for the packet
|
//let's use the preamble marker to get a reference level for the packet
|
||||||
reference_level = (inraw[i]
|
reference_level = (in[i]
|
||||||
+ inraw[i+int(1.0*d_samples_per_symbol)]
|
+ in[i+2]
|
||||||
+ inraw[i+int(3.5*d_samples_per_symbol)]
|
+ in[i+7]
|
||||||
+ inraw[i+int(4.5*d_samples_per_symbol)]) / 4;
|
+ in[i+9]) / 4.0;
|
||||||
|
|
||||||
//armed with our reference level, let's look for marks within 3dB of the reference level in bits 57-62 (65-70, see above)
|
//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
|
//if bits 57-62 have marks in either chip, we've got a long packet
|
||||||
//otherwise we have a short 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.
|
//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) {
|
for(int j = (65 * d_samples_per_symbol); j < (70 * d_samples_per_symbol); j += d_samples_per_symbol) {
|
||||||
float t_max = std::max(inraw[i+j],
|
float t_max = std::max(in[i+j],
|
||||||
inraw[i+j+d_samples_per_chip]
|
in[i+j+d_samples_per_chip]
|
||||||
);
|
);
|
||||||
if(t_max < (reference_level / 2.0)) packet_attrib = Short_Packet;
|
if(t_max < (reference_level / 2.0)) packet_attrib = Short_Packet;
|
||||||
}
|
}
|
||||||
@@ -114,7 +114,7 @@ int air_modes_framer::work(int noutput_items,
|
|||||||
//insert tag here
|
//insert tag here
|
||||||
add_item_tag(0, //stream ID
|
add_item_tag(0, //stream ID
|
||||||
nitems_written(0)+i, //sample
|
nitems_written(0)+i, //sample
|
||||||
d_key, //preamble_found
|
d_key, //frame_info
|
||||||
pmt::pmt_from_long((long)packet_attrib),
|
pmt::pmt_from_long((long)packet_attrib),
|
||||||
d_me //block src id
|
d_me //block src id
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -35,17 +35,19 @@ 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) :
|
air_modes_preamble::air_modes_preamble(int channel_rate, float threshold_db) :
|
||||||
gr_sync_block ("modes_preamble",
|
gr_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_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(float))) //the original data. we pass it out in order to use tags.
|
gr_make_io_signature (1, 1, sizeof(float))) //the output packets
|
||||||
{
|
{
|
||||||
d_chip_rate = 2000000; //2Mchips per second
|
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_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_samples_per_symbol = d_samples_per_chip * 2;
|
||||||
d_check_width = 7.5 * d_samples_per_symbol; //only search to this far from the end of the stream buffer
|
d_check_width = 120 * d_samples_per_symbol; //only search to this far from the end of the stream buffer
|
||||||
d_threshold_db = 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
|
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);
|
set_output_multiple(1+d_check_width*2);
|
||||||
|
|
||||||
std::stringstream str;
|
std::stringstream str;
|
||||||
str << name() << unique_id();
|
str << name() << unique_id();
|
||||||
d_me = pmt::pmt_string_to_symbol(str.str());
|
d_me = pmt::pmt_string_to_symbol(str.str());
|
||||||
@@ -59,111 +61,110 @@ static int early_late(const float *data) {
|
|||||||
else return 0;
|
else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int air_modes_preamble::work(int noutput_items,
|
static void integrate_and_dump(float *out, const float *in, int chips, int samps_per_chip) {
|
||||||
|
for(int i=0; i<chips; i++) {
|
||||||
|
float acc = 0;
|
||||||
|
for(int j=0; j<samps_per_chip; j++) {
|
||||||
|
acc += in[i*samps_per_chip+j];
|
||||||
|
}
|
||||||
|
out[i] = acc/samps_per_chip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//the preamble pattern in bits
|
||||||
|
//fixme goes in .h
|
||||||
|
static const bool preamble_bits[] = {1, 0, 1, 0, 0, 0, 0, 1, 0, 1};
|
||||||
|
static double correlate_preamble(const float *in, int samples_per_chip) {
|
||||||
|
double corr = 0.0;
|
||||||
|
for(int i=0; i<10; i++) {
|
||||||
|
for(int j=0; j<samples_per_chip;j++)
|
||||||
|
if(preamble_bits[i]) corr += in[i*samples_per_chip+j];
|
||||||
|
}
|
||||||
|
return corr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int air_modes_preamble::general_work(int noutput_items,
|
||||||
|
gr_vector_int &ninput_items,
|
||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items)
|
gr_vector_void_star &output_items)
|
||||||
{
|
{
|
||||||
//do things!
|
|
||||||
const float *in = (const float *) input_items[0];
|
const float *in = (const float *) input_items[0];
|
||||||
const float *inavg = (const float *) input_items[1];
|
const float *inavg = (const float *) input_items[1];
|
||||||
|
const int ninputs = std::min(ninput_items[0], ninput_items[1]); //just in case
|
||||||
float *out = (float *) output_items[0];
|
float *out = (float *) output_items[0];
|
||||||
|
|
||||||
int size = noutput_items;
|
//fixme move into .h
|
||||||
const int pulse_offsets[4] = {0,
|
const int pulse_offsets[4] = {0,
|
||||||
int(1.0 * d_samples_per_symbol),
|
int(1.0 * d_samples_per_symbol),
|
||||||
int(3.5 * d_samples_per_symbol),
|
int(3.5 * d_samples_per_symbol),
|
||||||
int(4.5 * d_samples_per_symbol)
|
int(4.5 * d_samples_per_symbol)
|
||||||
};
|
};
|
||||||
|
|
||||||
float preamble_pulses[4];
|
|
||||||
|
|
||||||
memcpy(out, in, size * sizeof(float));
|
|
||||||
|
|
||||||
uint64_t abs_out_sample_cnt = nitems_written(0);
|
uint64_t abs_out_sample_cnt = nitems_written(0);
|
||||||
|
|
||||||
for(int i = d_samples_per_chip; i < size; i++) {
|
for(int i=0; i < ninputs; i++) {
|
||||||
float pulse_threshold = inavg[i] * d_threshold;
|
float pulse_threshold = inavg[i] * d_threshold;
|
||||||
bool valid_preamble = false;
|
if(in[i] > pulse_threshold) { //hey we got a candidate
|
||||||
float gate_sum_now = 0, gate_sum_early = 0, gate_sum_late = 0;
|
if(in[i+1] > in[i]) continue; //wait for the peak
|
||||||
|
//check to see the rest of the pulses are there
|
||||||
|
if( in[i+pulse_offsets[1]] < pulse_threshold ) continue;
|
||||||
|
if( in[i+pulse_offsets[2]] < pulse_threshold ) continue;
|
||||||
|
if( in[i+pulse_offsets[3]] < pulse_threshold ) continue;
|
||||||
|
|
||||||
if(in[i] > pulse_threshold) { //if the sample is greater than the reference level by the specified amount
|
//get a more accurate bit center by finding the correlation peak across all four preamble bits
|
||||||
int gate_sum = early_late(&in[i]);
|
bool late = false;
|
||||||
if(gate_sum != 0) continue; //if either the early gate or the late gate had greater energy, keep moving.
|
|
||||||
//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.
|
|
||||||
preamble_pulses[0] = in[i+pulse_offsets[0]];
|
|
||||||
preamble_pulses[1] = in[i+pulse_offsets[1]];
|
|
||||||
preamble_pulses[2] = in[i+pulse_offsets[2]];
|
|
||||||
preamble_pulses[3] = in[i+pulse_offsets[3]];
|
|
||||||
|
|
||||||
//search for the rest of the pulses at their expected positions
|
|
||||||
if( preamble_pulses[1] < pulse_threshold ) continue;
|
|
||||||
if( preamble_pulses[2] < pulse_threshold ) continue;
|
|
||||||
if( preamble_pulses[3] < pulse_threshold ) continue;
|
|
||||||
|
|
||||||
valid_preamble = true; //this gets falsified by the following statements to disqualify a preamble
|
|
||||||
|
|
||||||
float avgpeak = (preamble_pulses[0] + preamble_pulses[1] + preamble_pulses[2] + preamble_pulses[3]) / 4;
|
|
||||||
|
|
||||||
//set the threshold requirement for spaces (0 chips) to
|
|
||||||
//threshold dB below the current peak
|
|
||||||
float space_threshold = preamble_pulses[0] / d_threshold;
|
|
||||||
//search between pulses and all the way out to 8.0us to make
|
|
||||||
//sure there are no pulses inside the "0" chips. make sure
|
|
||||||
//all the samples are <= (in[peak] * d_threshold).
|
|
||||||
//so 0.5us has to be < space_threshold, as does (1.5-3), 4, (5-7.5) in order to qualify.
|
|
||||||
for(int j = 1.5 * d_samples_per_symbol; j <= 3 * d_samples_per_symbol; j+=d_samples_per_chip)
|
|
||||||
if(in[i+j] > space_threshold) valid_preamble = false;
|
|
||||||
for(int j = 5 * d_samples_per_symbol; j <= 7.5 * d_samples_per_symbol; j+=d_samples_per_chip)
|
|
||||||
if(in[i+j] > space_threshold) valid_preamble = false;
|
|
||||||
|
|
||||||
//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(preamble_pulses[0] < minpeak || preamble_pulses[0] > maxpeak) continue;
|
|
||||||
if(preamble_pulses[1] < minpeak || preamble_pulses[1] > maxpeak) continue;
|
|
||||||
if(preamble_pulses[2] < minpeak || preamble_pulses[2] > maxpeak) continue;
|
|
||||||
if(preamble_pulses[3] < minpeak || preamble_pulses[3] > maxpeak) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(valid_preamble) {
|
|
||||||
//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 {
|
do {
|
||||||
early = late = false;
|
double now_corr = correlate_preamble(in+i, d_samples_per_chip);
|
||||||
//gate_sum_early= in[i+pulse_offsets[0]-1]
|
double late_corr = correlate_preamble(in+i+1, d_samples_per_chip);
|
||||||
// + in[i+pulse_offsets[1]-1]
|
late = (late_corr > now_corr);
|
||||||
// + in[i+pulse_offsets[2]-1]
|
|
||||||
// + in[i+pulse_offsets[3]-1];
|
|
||||||
|
|
||||||
gate_sum_now = in[i+pulse_offsets[0]]
|
|
||||||
+ in[i+pulse_offsets[1]]
|
|
||||||
+ in[i+pulse_offsets[2]]
|
|
||||||
+ in[i+pulse_offsets[3]];
|
|
||||||
|
|
||||||
gate_sum_late = in[i+pulse_offsets[0]+1]
|
|
||||||
+ in[i+pulse_offsets[1]+1]
|
|
||||||
+ in[i+pulse_offsets[2]+1]
|
|
||||||
+ in[i+pulse_offsets[3]+1];
|
|
||||||
|
|
||||||
early = (gate_sum_early > gate_sum_now);
|
|
||||||
late = (gate_sum_late > gate_sum_now);
|
|
||||||
if(late) i++;
|
if(late) i++;
|
||||||
//else if(early) i--;
|
|
||||||
//if(early && late) early = late = false;
|
|
||||||
} while(late);
|
} while(late);
|
||||||
|
|
||||||
//finally after all this, let's post the preamble!
|
//now check to see that the rest of the chips in the preamble
|
||||||
|
//are below the peaks by threshold dB
|
||||||
|
float avgpeak = ( in[i+pulse_offsets[0]]
|
||||||
|
+ in[i+pulse_offsets[1]]
|
||||||
|
+ in[i+pulse_offsets[2]]
|
||||||
|
+ in[i+pulse_offsets[3]]) / 4.0;
|
||||||
|
|
||||||
|
float space_threshold = inavg[i] + (avgpeak - inavg[i])/d_threshold;
|
||||||
|
bool valid_preamble = true; //f'in c++
|
||||||
|
for( int j=1.5*d_samples_per_symbol; j<=3*d_samples_per_symbol; j++)
|
||||||
|
if(in[i+j] > space_threshold) valid_preamble = false;
|
||||||
|
for( int j=5*d_samples_per_symbol; j<=7.5*d_samples_per_symbol; j++)
|
||||||
|
if(in[i+j] > space_threshold) valid_preamble = false;
|
||||||
|
if(!valid_preamble) continue;
|
||||||
|
|
||||||
|
//be sure we've got enough room in the input buffer to copy out a whole packet
|
||||||
|
if(ninputs-i < 240*d_samples_per_chip) {
|
||||||
|
consume_each(i);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//all right i'm prepared to call this a preamble
|
||||||
|
//let's integrate and dump the output
|
||||||
|
i -= d_samples_per_chip-1;
|
||||||
|
integrate_and_dump(out, &in[i], 240, d_samples_per_chip);
|
||||||
|
// out[0] = 1.0; //for debug
|
||||||
|
// out[1] = out[2] = out[3] = out[4] = avgpeak;
|
||||||
|
// out[5] = out[6] = out[7] = out[8] = space_threshold;
|
||||||
|
// out[9] = 0.0;
|
||||||
|
|
||||||
|
//now tag the preamble
|
||||||
add_item_tag(0, //stream ID
|
add_item_tag(0, //stream ID
|
||||||
nitems_written(0)+i, //sample
|
nitems_written(0), //sample
|
||||||
d_key, //preamble_found
|
d_key, //frame_info
|
||||||
pmt::PMT_T, //meaningless for us
|
pmt::pmt_from_double((double) space_threshold),
|
||||||
d_me //block src id
|
d_me //block src id
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//produce only one output per work call
|
||||||
|
consume_each(i+240*d_samples_per_chip);
|
||||||
|
return 240; //fixme debug should be 240
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return size;
|
|
||||||
|
//didn't get anything this time
|
||||||
|
consume_each(ninputs);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
#ifndef INCLUDED_AIR_MODES_PREAMBLE_H
|
#ifndef INCLUDED_AIR_MODES_PREAMBLE_H
|
||||||
#define INCLUDED_AIR_MODES_PREAMBLE_H
|
#define INCLUDED_AIR_MODES_PREAMBLE_H
|
||||||
|
|
||||||
#include <gr_sync_block.h>
|
#include <gr_block.h>
|
||||||
|
|
||||||
class air_modes_preamble;
|
class air_modes_preamble;
|
||||||
typedef boost::shared_ptr<air_modes_preamble> air_modes_preamble_sptr;
|
typedef boost::shared_ptr<air_modes_preamble> air_modes_preamble_sptr;
|
||||||
@@ -34,7 +34,7 @@ air_modes_preamble_sptr air_make_modes_preamble(int channel_rate, float threshol
|
|||||||
* \brief mode select preamble detection
|
* \brief mode select preamble detection
|
||||||
* \ingroup block
|
* \ingroup block
|
||||||
*/
|
*/
|
||||||
class air_modes_preamble : public gr_sync_block
|
class air_modes_preamble : public gr_block
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
friend air_modes_preamble_sptr air_make_modes_preamble(int channel_rate, float threshold_db);
|
friend air_modes_preamble_sptr air_make_modes_preamble(int channel_rate, float threshold_db);
|
||||||
@@ -50,7 +50,8 @@ private:
|
|||||||
pmt::pmt_t d_me, d_key;
|
pmt::pmt_t d_me, d_key;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int work (int noutput_items,
|
int general_work (int noutput_items,
|
||||||
|
gr_vector_int &ninput_items,
|
||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items);
|
gr_vector_void_star &output_items);
|
||||||
};
|
};
|
||||||
|
|||||||
+72
-62
@@ -31,6 +31,7 @@
|
|||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <modes_parity.h>
|
#include <modes_parity.h>
|
||||||
#include <gr_tag_info.h>
|
#include <gr_tag_info.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@@ -50,7 +51,7 @@ air_modes_slicer::air_modes_slicer(int channel_rate, gr_msg_queue_sptr queue) :
|
|||||||
{
|
{
|
||||||
//initialize private data here
|
//initialize private data here
|
||||||
d_chip_rate = 2000000; //2Mchips per second
|
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_chip = 2;//FIXME this is constant now channel_rate / d_chip_rate;
|
||||||
d_samples_per_symbol = d_samples_per_chip * 2;
|
d_samples_per_symbol = d_samples_per_chip * 2;
|
||||||
d_check_width = 120 * d_samples_per_symbol; //how far you will have to look ahead
|
d_check_width = 120 * d_samples_per_symbol; //how far you will have to look ahead
|
||||||
d_queue = queue;
|
d_queue = queue;
|
||||||
@@ -66,6 +67,44 @@ static bool pmtcompare(pmt::pmt_t x, pmt::pmt_t y)
|
|||||||
t_y = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(y, 0));
|
t_y = pmt::pmt_to_uint64(pmt::pmt_tuple_ref(y, 0));
|
||||||
return t_x < t_y;
|
return t_x < t_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//this slicer is courtesy of Lincoln Labs. supposedly it is more resistant to mode A/C FRUIT.
|
||||||
|
//see http://adsb.tc.faa.gov/WG3_Meetings/Meeting8/Squitter-Lon.pdf
|
||||||
|
static bool slicer(const float bit0, const float bit1, const float ref) {
|
||||||
|
bool slice, confidence;
|
||||||
|
|
||||||
|
//3dB limits for bit slicing and confidence measurement
|
||||||
|
float highlimit=ref*2;
|
||||||
|
float lowlimit=ref*0.5;
|
||||||
|
|
||||||
|
bool firstchip_inref = ((bit0 > lowlimit) && (bit0 < highlimit));
|
||||||
|
bool secondchip_inref = ((bit1 > lowlimit) && (bit1 < highlimit));
|
||||||
|
|
||||||
|
if(firstchip_inref && !secondchip_inref) {
|
||||||
|
slice = 1;
|
||||||
|
confidence = 1;
|
||||||
|
}
|
||||||
|
else if(secondchip_inref && !firstchip_inref) {
|
||||||
|
slice = 0;
|
||||||
|
confidence = 1;
|
||||||
|
}
|
||||||
|
else if(firstchip_inref && secondchip_inref) {
|
||||||
|
slice = bit0 > bit1;
|
||||||
|
confidence = 0;
|
||||||
|
}
|
||||||
|
else if(!firstchip_inref && !secondchip_inref) { //in this case, we determine the bit by whichever is larger, and we determine high confidence if the low chip is 6dB below reference.
|
||||||
|
slice = bit0 > bit1;
|
||||||
|
if(slice) {
|
||||||
|
if(bit1 < lowlimit * 0.5) confidence = 1;
|
||||||
|
else confidence = 0;
|
||||||
|
} else {
|
||||||
|
if(bit0 < lowlimit * 0.5) confidence = 1;
|
||||||
|
else confidence = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slice;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
static double pmt_to_timestamp(pmt::pmt_t tstamp, uint64_t sample_cnt, double secs_per_sample) {
|
static double pmt_to_timestamp(pmt::pmt_t tstamp, uint64_t sample_cnt, double secs_per_sample) {
|
||||||
double frac;
|
double frac;
|
||||||
@@ -85,92 +124,63 @@ int air_modes_slicer::work(int noutput_items,
|
|||||||
gr_vector_const_void_star &input_items,
|
gr_vector_const_void_star &input_items,
|
||||||
gr_vector_void_star &output_items)
|
gr_vector_void_star &output_items)
|
||||||
{
|
{
|
||||||
//do things!
|
const float *in = (const float *) input_items[0];
|
||||||
const float *inraw = (const float *) input_items[0];
|
|
||||||
int size = noutput_items - d_check_width; //since it's a sync block, i assume that it runs with ninput_items = noutput_items
|
int size = noutput_items - d_check_width; //since it's a sync block, i assume that it runs with ninput_items = noutput_items
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
std::vector<pmt::pmt_t> tags;
|
std::vector<pmt::pmt_t> tags;
|
||||||
uint64_t abs_sample_cnt = nitems_read(0);
|
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("frame_info"));
|
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;
|
std::vector<pmt::pmt_t>::iterator tag_iter;
|
||||||
|
|
||||||
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
for(tag_iter = tags.begin(); tag_iter != tags.end(); tag_iter++) {
|
||||||
uint64_t i = gr_tags::get_nitems(*tag_iter) - abs_sample_cnt;
|
uint64_t i = gr_tags::get_nitems(*tag_iter) - abs_sample_cnt;
|
||||||
modes_packet rx_packet;
|
modes_packet rx_packet;
|
||||||
framer_packet_type packet_type = framer_packet_type(pmt::pmt_to_long(gr_tags::get_value(*tag_iter)));
|
|
||||||
|
|
||||||
int packet_length;
|
|
||||||
packet_length = packet_type == framer_packet_type(Short_Packet) ? 56 : 112;
|
|
||||||
|
|
||||||
rx_packet.type = packet_type;
|
|
||||||
memset(&rx_packet.data, 0x00, 14 * sizeof(unsigned char));
|
memset(&rx_packet.data, 0x00, 14 * sizeof(unsigned char));
|
||||||
memset(&rx_packet.lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
memset(&rx_packet.lowconfbits, 0x00, 24 * sizeof(unsigned char));
|
||||||
rx_packet.numlowconf = 0;
|
rx_packet.numlowconf = 0;
|
||||||
|
|
||||||
//let's use the preamble marker to get a reference level for the packet
|
//let's use the preamble to get a reference level for the packet
|
||||||
rx_packet.reference_level = (inraw[i]
|
//fixme: a better thing to do is create a bi-level avg 1 and avg 0
|
||||||
+ inraw[i+int(1.0*d_samples_per_symbol)]
|
//through simple statistics, then take the median for your slice level
|
||||||
+ inraw[i+int(3.5*d_samples_per_symbol)]
|
//this won't improve decoding but will improve confidence
|
||||||
+ inraw[i+int(4.5*d_samples_per_symbol)]) / 4;
|
rx_packet.reference_level = (in[i]
|
||||||
|
+ in[i+2]
|
||||||
|
+ in[i+7]
|
||||||
|
+ in[i+9]) / 4.0;
|
||||||
|
|
||||||
i += 8 * d_samples_per_symbol; //move to the center of the first bit of the data
|
i += 16; //move on up to the first bit of the packet data
|
||||||
|
//now let's slice the header so we can determine if it's a short pkt or a long pkt
|
||||||
|
unsigned char pkt_hdr = 0;
|
||||||
|
for(int j=0; j < 5; j++) {
|
||||||
|
bool slice = slicer(in[i+j*2], in[i+j*2+1], rx_packet.reference_level);
|
||||||
|
if(slice) pkt_hdr += 1 << (4-j);
|
||||||
|
}
|
||||||
|
//std::cout << "SLICER: TYPE " << int(pkt_hdr) << std::endl;
|
||||||
|
|
||||||
//here we calculate the total energy contained in each chip of the symbol
|
if(pkt_hdr == 17) rx_packet.type = Long_Packet;
|
||||||
|
else rx_packet.type = Short_Packet;
|
||||||
|
|
||||||
|
int packet_length;
|
||||||
|
packet_length = (rx_packet.type == framer_packet_type(Short_Packet)) ? 56 : 112;
|
||||||
|
|
||||||
|
//it's slice time!
|
||||||
|
//TODO: don't repeat your work here, you already have the first 5 bits
|
||||||
for(int j = 0; j < packet_length; j++) {
|
for(int j = 0; j < packet_length; j++) {
|
||||||
int firstchip = i+j*d_samples_per_symbol;
|
bool slice = slicer(in[i+j*2], in[i+j*2+1], rx_packet.reference_level);
|
||||||
int secondchip = firstchip + d_samples_per_chip;
|
|
||||||
bool slice, confidence;
|
|
||||||
float firstchip_energy=0, secondchip_energy=0;
|
|
||||||
|
|
||||||
firstchip_energy = inraw[firstchip];
|
//put the data into the packet
|
||||||
secondchip_energy = inraw[secondchip];
|
|
||||||
|
|
||||||
//3dB limits for bit slicing and confidence measurement
|
|
||||||
float highlimit=rx_packet.reference_level*2;
|
|
||||||
float lowlimit=rx_packet.reference_level*0.5;
|
|
||||||
bool firstchip_inref = ((firstchip_energy > lowlimit) && (firstchip_energy < highlimit));
|
|
||||||
bool secondchip_inref = ((secondchip_energy > lowlimit) && (secondchip_energy < highlimit));
|
|
||||||
|
|
||||||
//these two lines for a super simple naive slicer.
|
|
||||||
// slice = firstchip_energy > secondchip_energy;
|
|
||||||
// confidence = bool(int(firstchip_inref) + int(secondchip_inref)); //one and only one chip in the reference zone
|
|
||||||
|
|
||||||
//below is the Lincoln Labs slicer. it may produce greater bit errors. supposedly it is more resistant to mode A/C FRUIT.
|
|
||||||
//see http://adsb.tc.faa.gov/WG3_Meetings/Meeting8/Squitter-Lon.pdf
|
|
||||||
if(firstchip_inref && !secondchip_inref) {
|
|
||||||
slice = 1;
|
|
||||||
confidence = 1;
|
|
||||||
}
|
|
||||||
else if(secondchip_inref && !firstchip_inref) {
|
|
||||||
slice = 0;
|
|
||||||
confidence = 1;
|
|
||||||
}
|
|
||||||
else if(firstchip_inref && secondchip_inref) {
|
|
||||||
slice = firstchip_energy > secondchip_energy;
|
|
||||||
confidence = 0;
|
|
||||||
}
|
|
||||||
else if(!firstchip_inref && !secondchip_inref) { //in this case, we determine the bit by whichever is larger, and we determine high confidence if the low chip is 6dB below reference.
|
|
||||||
slice = firstchip_energy > secondchip_energy;
|
|
||||||
if(slice) {
|
|
||||||
if(secondchip_energy < lowlimit * 0.5) confidence = 1;
|
|
||||||
else confidence = 0;
|
|
||||||
} else {
|
|
||||||
if(firstchip_energy < lowlimit * 0.5) confidence = 1;
|
|
||||||
else confidence = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//put the data into the packet
|
|
||||||
if(slice) {
|
if(slice) {
|
||||||
rx_packet.data[j/8] += 1 << (7-(j%8));
|
rx_packet.data[j/8] += 1 << (7-(j%8));
|
||||||
}
|
}
|
||||||
//put the confidence decision into the packet
|
//put the confidence decision into the packet
|
||||||
if(confidence) {
|
// if(confidence) {
|
||||||
//rx_packet.confidence[j/8] += 1 << (7-(j%8));
|
//rx_packet.confidence[j/8] += 1 << (7-(j%8));
|
||||||
} else {
|
// } else {
|
||||||
if(rx_packet.numlowconf < 24) rx_packet.lowconfbits[rx_packet.numlowconf++] = j;
|
// if(rx_packet.numlowconf < 24) rx_packet.lowconfbits[rx_packet.numlowconf++] = j;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************** BEGIN TIMESTAMP BS ******************/
|
/******************** BEGIN TIMESTAMP BS ******************/
|
||||||
|
|||||||
+9
-20
@@ -19,9 +19,9 @@
|
|||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
#
|
#
|
||||||
|
|
||||||
#my_position = [37.76225, -122.44254]
|
my_position = [37.76225, -122.44254]
|
||||||
#my_position = [37.409066,-122.077836]
|
#my_position = [37.409066,-122.077836]
|
||||||
my_position = None
|
#my_position = None
|
||||||
|
|
||||||
from gnuradio import gr, gru, optfir, eng_notation, blks2, air
|
from gnuradio import gr, gru, optfir, eng_notation, blks2, air
|
||||||
from gnuradio import uhd
|
from gnuradio import uhd
|
||||||
@@ -92,32 +92,21 @@ class adsb_rx_block (gr.top_block):
|
|||||||
|
|
||||||
#the DBSRX especially tends to be spur-prone; the LPF keeps out the
|
#the DBSRX especially tends to be spur-prone; the LPF keeps out the
|
||||||
#spur multiple that shows up at 2MHz
|
#spur multiple that shows up at 2MHz
|
||||||
# self.filtcoeffs = gr.firdes.low_pass(1, rate, 1.8e6, 200e3)
|
#self.lpfiltcoeffs = gr.firdes.low_pass(1, rate, 1.8e6, 200e3)
|
||||||
# self.filter = gr.fir_filter_fff(1, self.filtcoeffs)
|
#self.lpfilter = gr.fir_filter_fff(1, self.lpfiltcoeffs)
|
||||||
|
|
||||||
#this is an integrate-and-dump filter to act as a matched filter
|
|
||||||
#for the essentially rectangular Mode S pulses.
|
|
||||||
#if a particular Mode S transponder is using a pulse shaping filter,
|
|
||||||
#this will not be optimal.
|
|
||||||
self.filtcoeffs = list()
|
|
||||||
for i in range(int(rate/4e6)):
|
|
||||||
self.filtcoeffs.append(1.0 / (rate/4e6))
|
|
||||||
|
|
||||||
#i think downstream blocks can therefore process at 2Msps -- try this
|
|
||||||
#self.filter = gr.fir_filter_fff(int(rate/2e6), self.filtcoeffs)
|
|
||||||
self.filter = gr.fir_filter_fff(1, self.filtcoeffs)
|
self.filter = gr.fir_filter_fff(1, self.filtcoeffs)
|
||||||
#rate = int(2e6)
|
#rate = int(2e6)
|
||||||
|
|
||||||
self.preamble = air.modes_preamble(rate, options.threshold)
|
self.preamble = air.modes_preamble(rate, options.threshold)
|
||||||
self.framer = air.modes_framer(rate)
|
#self.framer = air.modes_framer(rate)
|
||||||
self.slicer = air.modes_slicer(rate, queue)
|
self.slicer = air.modes_slicer(rate, queue)
|
||||||
|
|
||||||
self.connect(self.u, self.demod, self.filter)
|
self.connect(self.u, self.demod)
|
||||||
self.connect(self.filter, self.avg)
|
self.connect(self.demod, self.avg)
|
||||||
self.connect(self.filter, (self.preamble, 0))
|
self.connect(self.demod, (self.preamble, 0))
|
||||||
self.connect(self.avg, (self.preamble, 1))
|
self.connect(self.avg, (self.preamble, 1))
|
||||||
self.connect((self.preamble, 0), (self.framer, 0))
|
self.connect((self.preamble, 0), (self.slicer, 0))
|
||||||
self.connect(self.framer, self.slicer)
|
|
||||||
|
|
||||||
def tune(self, freq):
|
def tune(self, freq):
|
||||||
result = self.u.set_center_freq(freq, 0)
|
result = self.u.set_center_freq(freq, 0)
|
||||||
|
|||||||
Reference in New Issue
Block a user