1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2025-10-31 07:13:03 +00:00

SBAS stuff developed by Daniel Fehr during GSOC 2013

git-svn-id: https://svn.code.sf.net/p/gnss-sdr/code/trunk@436 64b25241-fba3-4117-9849-534c7e92360d
This commit is contained in:
Carles Fernandez
2013-11-09 22:03:42 +00:00
parent a8619337be
commit 601e5fa2c9
19 changed files with 4563 additions and 1 deletions

View File

@@ -19,6 +19,7 @@
set(TELEMETRY_DECODER_ADAPTER_SOURCES
gps_l1_ca_telemetry_decoder.cc
galileo_e1b_telemetry_decoder.cc
sbas_l1_telemetry_decoder.cc
)
include_directories(

View File

@@ -0,0 +1,118 @@
/*!
* \file sbas_l1_telemetry_decoder.cc
* \brief Implementation of an adapter of a SBAS telemtry data decoder block
* to a TelemetryDecoderInterface
* \author Daniel Fehr 2013. daniel.co(at)bluewin.ch
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2013 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR 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 GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "sbas_l1_telemetry_decoder.h"
#include "configuration_interface.h"
#include "sbas_l1_telemetry_decoder_cc.h"
#include <gnuradio/io_signature.h>
#include <glog/log_severity.h>
#include <glog/logging.h>
#include "sbas_telemetry_data.h"
#include "sbas_ionospheric_correction.h"
#include "sbas_satellite_correction.h"
#include "sbas_ephemeris.h"
extern concurrent_queue<Sbas_Raw_Msg> global_sbas_raw_msg_queue;
extern concurrent_queue<Sbas_Ionosphere_Correction> global_sbas_iono_queue;
extern concurrent_queue<Sbas_Satellite_Correction> global_sbas_sat_corr_queue;
extern concurrent_queue<Sbas_Ephemeris> global_sbas_ephemeris_queue;
using google::LogMessage;
SbasL1TelemetryDecoder::SbasL1TelemetryDecoder(ConfigurationInterface* configuration,
std::string role,
unsigned int in_streams,
unsigned int out_streams,
boost::shared_ptr<gr::msg_queue> queue) :
role_(role),
in_streams_(in_streams),
out_streams_(out_streams),
queue_(queue)
{
std::string default_item_type = "gr_complex";
std::string default_dump_filename = "./navigation.dat";
DLOG(INFO) << "role " << role;
DLOG(INFO) << "vector length " << vector_length_;
vector_length_ = configuration->property(role + ".vector_length", 2048);
dump_ = configuration->property(role + ".dump", false);
dump_filename_ = configuration->property(role + ".dump_filename", default_dump_filename);
int fs_in;
fs_in = configuration->property("GNSS-SDR.internal_fs_hz", 2048000);
// make telemetry decoder object
telemetry_decoder_ = sbas_l1_make_telemetry_decoder_cc(satellite_, 0, (long)fs_in, vector_length_, queue_, dump_); // TODO fix me
DLOG(INFO) << "telemetry_decoder(" << telemetry_decoder_->unique_id() << ")";
// set the queues;
telemetry_decoder_->set_raw_msg_queue(&global_sbas_raw_msg_queue);
telemetry_decoder_->set_iono_queue(&global_sbas_iono_queue);
telemetry_decoder_->set_sat_corr_queue(&global_sbas_sat_corr_queue);
telemetry_decoder_->set_ephemeris_queue(&global_sbas_ephemeris_queue);
}
SbasL1TelemetryDecoder::~SbasL1TelemetryDecoder()
{}
void SbasL1TelemetryDecoder::set_satellite(Gnss_Satellite satellite)
{
satellite_ = Gnss_Satellite(satellite.get_system(), satellite.get_PRN());
telemetry_decoder_->set_satellite(satellite_);
DLOG(INFO) << "SBAS TELEMETRY DECODER: satellite set to " << satellite_;
}
void SbasL1TelemetryDecoder::connect(gr::top_block_sptr top_block)
{
// Nothing to connect internally
DLOG(INFO) << "nothing to connect internally";
}
void SbasL1TelemetryDecoder::disconnect(gr::top_block_sptr top_block)
{
// Nothing to disconnect
}
gr::basic_block_sptr SbasL1TelemetryDecoder::get_left_block()
{
return telemetry_decoder_;
}
gr::basic_block_sptr SbasL1TelemetryDecoder::get_right_block()
{
return telemetry_decoder_;
}

View File

@@ -0,0 +1,94 @@
/*!
* \file sbas_l1_telemetry_decoder.h
* \brief Interface of an adapter of a SBAS telemtry data decoder block
* to a TelemetryDecoderInterface
* \author Daniel Fehr 2013. daniel.co(at)bluewin.ch
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2013 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR 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 GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_SBAS_L1_TELEMETRY_DECODER_H_
#define GNSS_SDR_SBAS_L1_TELEMETRY_DECODER_H_
#include "telemetry_decoder_interface.h"
#include "sbas_l1_telemetry_decoder_cc.h"
#include <gnuradio/msg_queue.h>
class ConfigurationInterface;
/*!
* \brief This class implements a NAV data decoder for SBAS frames in L1 radio link
*/
class SbasL1TelemetryDecoder : public TelemetryDecoderInterface
{
public:
SbasL1TelemetryDecoder(ConfigurationInterface* configuration,
std::string role,
unsigned int in_streams,
unsigned int out_streams,
boost::shared_ptr<gr::msg_queue> queue);
virtual ~SbasL1TelemetryDecoder();
std::string role()
{
return role_;
}
std::string implementation()
{
return "SBAS_L1_Telemetry_Decoder";
}
void connect(gr::top_block_sptr top_block);
void disconnect(gr::top_block_sptr top_block);
gr::basic_block_sptr get_left_block();
gr::basic_block_sptr get_right_block();
void set_satellite(Gnss_Satellite satellite);
void set_channel(int channel){ telemetry_decoder_->set_channel(channel); }
void reset()
{
return;
}
size_t item_size()
{
return 0;
}
private:
sbas_l1_telemetry_decoder_cc_sptr telemetry_decoder_;
Gnss_Satellite satellite_;
int channel_;
unsigned int vector_length_;
std::string item_type_;
bool dump_;
std::string dump_filename_;
std::string role_;
unsigned int in_streams_;
unsigned int out_streams_;
boost::shared_ptr<gr::msg_queue> queue_;
};
#endif

View File

@@ -19,6 +19,7 @@
set(TELEMETRY_DECODER_GR_BLOCKS_SOURCES
gps_l1_ca_telemetry_decoder_cc.cc
galileo_e1b_telemetry_decoder_cc.cc
sbas_l1_telemetry_decoder_cc.cc
)
include_directories(

View File

@@ -0,0 +1,563 @@
/*!
* \file sbas_l1_telemetry_decoder_cc.cc
* \brief Implementation of a SBAS telemetry data decoder block
* \author Daniel Fehr 2013. daniel.co(at)bluewin.ch
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2013 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR 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 GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include <iostream>
#include <sstream>
#include <gnuradio/io_signature.h>
#include <glog/log_severity.h>
#include <glog/logging.h>
#include <boost/lexical_cast.hpp>
#include "control_message_factory.h"
#include "gnss_synchro.h"
#include "sbas_l1_telemetry_decoder_cc.h"
using google::LogMessage;
// logging levels
#define EVENT 2 // logs important events which don't occur every block
#define FLOW 3 // logs the function calls of block processing functions
#define SAMP_SYNC 4 // about 1 log entry per sample -> high output
#define LMORE 5 //
sbas_l1_telemetry_decoder_cc_sptr
sbas_l1_make_telemetry_decoder_cc(Gnss_Satellite satellite, long if_freq, long fs_in, unsigned
int vector_length, boost::shared_ptr<gr::msg_queue> queue, bool dump)
{
return sbas_l1_telemetry_decoder_cc_sptr(new sbas_l1_telemetry_decoder_cc(satellite, if_freq,
fs_in, vector_length, queue, dump));
}
sbas_l1_telemetry_decoder_cc::sbas_l1_telemetry_decoder_cc(
Gnss_Satellite satellite,
long if_freq,
long fs_in,
unsigned
int vector_length,
boost::shared_ptr<gr::msg_queue> queue,
bool dump) :
gr::block("sbas_l1_telemetry_decoder_cc", gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)),
gr::io_signature::make(1, 1, sizeof(Gnss_Synchro)))
{
// initialize internal vars
d_dump = dump;
d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN());
DLOG(INFO) << "SBAS L1 TELEMETRY PROCESSING: satellite " << d_satellite;
d_fs_in = fs_in;
d_block_size = d_samples_per_symbol * d_symbols_per_bit * d_block_size_in_bits;
set_output_multiple (1);
}
sbas_l1_telemetry_decoder_cc::~sbas_l1_telemetry_decoder_cc()
{
d_dump_file.close();
}
void sbas_l1_telemetry_decoder_cc::forecast (int noutput_items, gr_vector_int &ninput_items_required)
{
unsigned ninputs = ninput_items_required.size ();
for (unsigned i = 0; i < ninputs; i++)
ninput_items_required[i] = noutput_items;
VLOG(LMORE) << "forecast(): " << "noutput_items=" << noutput_items << "\tninput_items_required ninput_items_required.size()=" << ninput_items_required.size();
}
int sbas_l1_telemetry_decoder_cc::general_work (int noutput_items, gr_vector_int &ninput_items,
gr_vector_const_void_star &input_items, gr_vector_void_star &output_items)
{
VLOG(FLOW) << "general_work(): " << "noutput_items=" << noutput_items << "\toutput_items real size=" << output_items.size() << "\tninput_items size=" << ninput_items.size() << "\tinput_items real size=" << input_items.size() << "\tninput_items[0]=" << ninput_items[0];
// get pointers on in- and output gnss-synchro objects
const Gnss_Synchro *in = (const Gnss_Synchro *) input_items[0]; // input
Gnss_Synchro *out = (Gnss_Synchro *) output_items[0]; // output
// store the time stamp of the first sample in the processed sample block
double sample_stamp = in[0].Tracking_timestamp_secs;
// copy correlation samples into samples vector
for (int i = 0; i < noutput_items; i++)
{
// check if channel is in tracking state
//if(in[i].Prompt_I != in[i].Prompt_Q) // TODO: check for real condition
{
d_sample_buf.push_back(in[i].Prompt_I);
}
}
// decode only if enough samples in buffer
if(d_sample_buf.size() >= d_block_size)
{
// align correlation samples in pairs
// and obtain the symbols by summing the paired correlation samples
std::vector<double> symbols;
bool sample_alignment = d_sample_aligner.get_symbols(d_sample_buf, symbols);
// align symbols in pairs
// and obtain the bits by decoding the symbol pairs
std::vector<int> bits;
bool symbol_alignment = d_symbol_aligner_and_decoder.get_bits(symbols, bits);
// search for preambles
// and extract the corresponding message candidates
std::vector<msg_candiate_int_t> msg_candidates;
d_frame_detector.get_frame_candidates(bits, msg_candidates);
// verify checksum
// and return the valid messages
std::vector<msg_candiate_char_t> valid_msgs;
d_crc_verifier.get_valid_frames(msg_candidates, valid_msgs);
// compute message sample stamp
// and fill messages in SBAS raw message objects
std::vector<Sbas_Raw_Msg> sbas_raw_msgs;
for(std::vector<msg_candiate_char_t>::const_iterator it = valid_msgs.begin();
it != valid_msgs.end(); ++it)
{
int message_sample_offset =
(sample_alignment?0:-1)
+ d_samples_per_symbol*(symbol_alignment?-1:0)
+ d_samples_per_symbol * d_symbols_per_bit * it->first;
double message_sample_stamp = sample_stamp + ((double)message_sample_offset)/1000;
VLOG(EVENT) << "message_sample_stamp=" << message_sample_stamp
<< " (sample_stamp=" << sample_stamp
<< " sample_alignment=" << sample_alignment
<< " symbol_alignment=" << symbol_alignment
<< " relative_preamble_start=" << it->first
<< " message_sample_offset=" << message_sample_offset
<< ")";
Sbas_Raw_Msg sbas_raw_msg(message_sample_stamp, this->d_satellite.get_PRN(), it->second);
sbas_raw_msgs.push_back(sbas_raw_msg);
}
// parse messages
// and send them to the SBAS raw message queue
for(std::vector<Sbas_Raw_Msg>::iterator it = sbas_raw_msgs.begin(); it != sbas_raw_msgs.end(); it++)
{
std::cout << "SBAS message type " << it->get_msg_type() << " from PRN" << it->get_prn() << " received" << std::endl;
sbas_telemetry_data.update(*it);
}
// clear all processed samples in the input buffer
d_sample_buf.clear();
}
// UPDATE GNSS SYNCHRO DATA
// actually the SBAS telemetry decoder doesn't support ranging
Gnss_Synchro * current_synchro_data = out; //structure to save the synchronization information and send the output object to the next block
for (int i = 0; i < noutput_items; i++)
{
//1. Copy the current tracking output
current_synchro_data[i] = in[i];
//2. Add the telemetry decoder information
current_synchro_data[i].Flag_valid_word = false; // indicate to observable block that this synchro object isn't valid for pseudorange computation
}
consume_each(noutput_items); // tell scheduler input items consumed
return noutput_items; // tell scheduler output items produced
}
void sbas_l1_telemetry_decoder_cc::set_satellite(Gnss_Satellite satellite)
{
d_satellite = Gnss_Satellite(satellite.get_system(), satellite.get_PRN());
DLOG(INFO) << "SBAS telemetry decoder in channel " << this->d_channel << " set to satellite " << d_satellite;
}
void sbas_l1_telemetry_decoder_cc::set_channel(int channel)
{
d_channel = channel;
DLOG(INFO) << "SBAS channel set to " << channel;
}
// ### helper class for sample alignment ###
sbas_l1_telemetry_decoder_cc::sample_aligner::sample_aligner()
{
d_n_smpls_in_history = 3;
d_iir_par = 0.05;
reset();
}
sbas_l1_telemetry_decoder_cc::sample_aligner::~sample_aligner()
{
}
void sbas_l1_telemetry_decoder_cc::sample_aligner::reset()
{
d_past_sample = 0;
d_corr_paired = 0;
d_corr_shifted = 0;
d_aligned = true;
}
/*
* samples length must be a multiple of two
*/
bool sbas_l1_telemetry_decoder_cc::sample_aligner::get_symbols(const std::vector<double> samples, std::vector<double> &symbols)
{
double smpls[d_n_smpls_in_history];
double corr_diff;
bool stand_by = true;
double sym;
VLOG(FLOW) << "get_symbols(): " << "d_past_sample=" << d_past_sample << "\tsamples size=" << samples.size();
for (unsigned int i_sym = 0; i_sym < samples.size()/sbas_l1_telemetry_decoder_cc::d_samples_per_symbol; i_sym++)
{
// get the next samples
for (int i = 0; i < d_n_smpls_in_history; i++)
{
smpls[i] = ((int)i_sym)*sbas_l1_telemetry_decoder_cc::d_samples_per_symbol+i-1 == -1 ? d_past_sample : samples[i_sym*sbas_l1_telemetry_decoder_cc::d_samples_per_symbol+i-1];
}
// update the pseudo correlations (IIR method) of the two possible alignments
d_corr_paired = d_iir_par*smpls[1]*smpls[2] + (1-d_iir_par)*d_corr_paired;
d_corr_shifted = d_iir_par*smpls[0]*smpls[1] + (1-d_iir_par)*d_corr_shifted;
// decide which alignment is the correct one
corr_diff = std::abs(d_corr_paired-d_corr_shifted);
stand_by = d_aligned ? corr_diff < d_corr_paired/2 : corr_diff < d_corr_shifted/2;
if (!stand_by)
{
d_aligned = d_corr_paired >= d_corr_shifted;
}
// sum the correct pair of samples to a symbol, depending on the current alignment d_align
sym = smpls[0+int(d_aligned)*2] + smpls[1];
symbols.push_back(sym);
// sample alignment debug output
VLOG(SAMP_SYNC) << std::setprecision(5)
<< "smplp: " << std::setw(6) << smpls[0] << " " << "smpl0: " << std::setw(6) << smpls[1] << " " << "smpl1: " << std::setw(6) << smpls[2] << "\t"
//<< "Flag_valid_tracking: " << std::setw(1) << in[0][0].Flag_valid_tracking << " " << std::setw(1) << in[0][0].Flag_valid_tracking << "\t"
<< "d_corr_paired: " << std::setw(10) << d_corr_paired << "\t"
<< "d_corr_shifted: " << std::setw(10) << d_corr_shifted << "\t"
<< "corr_diff: " << std::setw(10) << corr_diff << "\t"
<< "stand_by: " << std::setw(1) << stand_by << "\t"
<< "d_aligned: " << std::setw(1) << d_aligned << "\t"
<< "sym: " << std::setw(10) << sym << "\t";
}
// save last sample for next block
double temp;
temp = samples.back();
d_past_sample = (temp);
return d_aligned;
}
// ### helper class for symbol alignment and viterbi decoding ###
sbas_l1_telemetry_decoder_cc::symbol_aligner_and_decoder::symbol_aligner_and_decoder()
{
// convolutional code properties
d_KK = 7;
int nn = 2;
int g_encoder[nn];
g_encoder[0] = 121;
g_encoder[1] = 91;
d_vd1 = new Viterbi_Decoder(g_encoder, d_KK, nn);
d_vd2 = new Viterbi_Decoder(g_encoder, d_KK, nn);
d_past_symbol = 0;
}
sbas_l1_telemetry_decoder_cc::symbol_aligner_and_decoder::~symbol_aligner_and_decoder()
{
delete d_vd1;
delete d_vd2;
}
void sbas_l1_telemetry_decoder_cc::symbol_aligner_and_decoder::reset()
{
d_past_symbol = 0;
d_vd1->reset();
d_vd2->reset();
}
bool sbas_l1_telemetry_decoder_cc::symbol_aligner_and_decoder::
get_bits(const std::vector<double> symbols, std::vector<int> &bits)
{
const int traceback_depth = 5*d_KK;
int nbits_requested = symbols.size()/d_symbols_per_bit;
int nbits_decoded;
// fill two vectors with the two possible symbol alignments
std::vector<double> symbols_vd1(symbols); // aligned symbol vector -> copy input symbol vector
std::vector<double> symbols_vd2; // shifted symbol vector -> add past sample in front of input vector
symbols_vd1.push_back(d_past_symbol);
for (std::vector<double>::const_iterator symbol_it = symbols.begin(); symbol_it != symbols.end()-1; ++symbol_it)
{
symbols_vd2.push_back(*symbol_it);
}
// arrays for decoded bits
int * bits_vd1 = new int[nbits_requested];
int * bits_vd2 = new int[nbits_requested];
// decode
float metric_vd1 = d_vd1->decode_continuous(symbols_vd1.data(), traceback_depth, bits_vd1, nbits_requested, nbits_decoded);
float metric_vd2 = d_vd2->decode_continuous(symbols_vd2.data(), traceback_depth, bits_vd2, nbits_requested, nbits_decoded);
// choose the bits with the better metric
for (int i = 0; i<nbits_decoded; i++)
{
if (metric_vd1 > metric_vd2)
{// symbols aligned
bits.push_back(bits_vd1[i]);
}
else
{// symbols shifted
bits.push_back(bits_vd2[i]);
}
}
d_past_symbol = symbols.back();
delete[] bits_vd1;
delete[] bits_vd2;
return metric_vd1 > metric_vd2;
}
// ### helper class for detecting the preamble and collect the corresponding message candidates ###
void sbas_l1_telemetry_decoder_cc::frame_detector::reset()
{
d_buffer.clear();
}
void sbas_l1_telemetry_decoder_cc::frame_detector::
get_frame_candidates(const std::vector<int> bits, std::vector<std::pair<int,std::vector<int>>> &msg_candidates)
{
std::stringstream ss;
unsigned int sbas_msg_length = 250;
std::vector<std::vector<int>> preambles = {{0, 1, 0, 1, 0, 0, 1 ,1},
{1, 0, 0, 1, 1, 0, 1, 0},
{1, 1, 0, 0, 0, 1, 1, 0}};
VLOG(FLOW) << "get_frame_candidates(): " << "d_buffer.size()=" << d_buffer.size() << "\tbits.size()=" << bits.size();
ss << "copy bits ";
int count = 0;
// copy new bits into the working buffer
for (std::vector<int>::const_iterator bit_it = bits.begin(); bit_it < bits.end(); ++bit_it)
{
d_buffer.push_back(*bit_it);
ss << *bit_it;
count++;
}
VLOG(SAMP_SYNC) << ss.str() << " into working buffer (" << count << " bits)";
int relative_preamble_start = 0;
while(d_buffer.size() >= sbas_msg_length)
{
// compare with all preambles
for (std::vector<std::vector<int>>::iterator preample_it = preambles.begin(); preample_it < preambles.end(); ++preample_it)
{
bool preamble_detected = true;
bool inv_preamble_detected = true;
// compare the buffer bits with the preamble bits
for (std::vector<int>::iterator preample_bit_it = preample_it->begin(); preample_bit_it < preample_it->end(); ++preample_bit_it)
{
preamble_detected = *preample_bit_it == d_buffer[preample_bit_it-preample_it->begin()] ? preamble_detected : false ;
inv_preamble_detected = *preample_bit_it != d_buffer[preample_bit_it-preample_it->begin()] ? inv_preamble_detected : false ;
}
if (preamble_detected || inv_preamble_detected)
{
// copy candidate
std::vector<int> candidate;
std::copy(d_buffer.begin(), d_buffer.begin()+sbas_msg_length, std::back_inserter(candidate));
if(inv_preamble_detected)
{
// invert bits
for (std::vector<int>::iterator candidate_bit_it = candidate.begin(); candidate_bit_it != candidate.end(); candidate_bit_it++)
*candidate_bit_it = *candidate_bit_it == 0 ? 1:0;
}
msg_candidates.push_back(std::pair<int,std::vector<int>>(relative_preamble_start,candidate));
ss.str("");
ss << "preamble " << preample_it - preambles.begin() << (inv_preamble_detected?" inverted":" normal") << " detected! candidate=";
for (std::vector<int>::iterator bit_it = candidate.begin(); bit_it < candidate.end(); ++bit_it)
ss << *bit_it;
VLOG(EVENT) << ss.str();
}
}
relative_preamble_start++;
// remove bit in front
d_buffer.pop_front();
}
}
// ### helper class for checking the CRC of the message candidates ###
void sbas_l1_telemetry_decoder_cc::crc_verifier::reset()
{
}
void sbas_l1_telemetry_decoder_cc::crc_verifier::
get_valid_frames(const std::vector<msg_candiate_int_t> msg_candidates, std::vector<msg_candiate_char_t> &valid_msgs)
{
std::stringstream ss;
VLOG(FLOW) << "get_valid_frames(): " << "msg_candidates.size()=" << msg_candidates.size();
// for each candidate
for (std::vector<msg_candiate_int_t>::const_iterator candidate_it = msg_candidates.begin(); candidate_it < msg_candidates.end(); ++candidate_it)
{
// convert to bytes
std::vector<unsigned char> candidate_bytes;
zerropad_back_and_convert_to_bytes(candidate_it->second, candidate_bytes);
// verify CRC
d_checksum_agent.reset(0);
d_checksum_agent.process_bytes(candidate_bytes.data(), candidate_bytes.size());
unsigned int crc = d_checksum_agent.checksum();
VLOG(SAMP_SYNC) << "candidate " << candidate_it - msg_candidates.begin() << ": final crc remainder= " << std::hex << crc
<< std::setfill(' ') << std::resetiosflags(std::ios::hex);
// the final remainder must be zero for a valid message, because the CRC is done over the received CRC value
if (crc == 0)
{
valid_msgs.push_back(msg_candiate_char_t(candidate_it->first,candidate_bytes));
ss << "Valid message found!";
}
else
{
ss << "Not a valid message.";
}
ss << " Relbitoffset=" << candidate_it->first << " content=";
for (std::vector<unsigned char>::iterator byte_it = candidate_bytes.begin(); byte_it < candidate_bytes.end(); ++byte_it)
{
ss << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)(*byte_it);
}
VLOG(SAMP_SYNC) << ss.str() << std::setfill(' ') << std::resetiosflags(std::ios::hex) << std::endl;
}
}
void sbas_l1_telemetry_decoder_cc::crc_verifier::
zerropad_back_and_convert_to_bytes(const std::vector<int> msg_candidate, std::vector<unsigned char> &bytes)
{
std::stringstream ss;
const size_t bits_per_byte = 8;
unsigned char byte = 0;
VLOG(LMORE) << "zerropad_back_and_convert_to_bytes():" << byte;
for (std::vector<int>::const_iterator candidate_bit_it = msg_candidate.begin(); candidate_bit_it < msg_candidate.end(); ++candidate_bit_it)
{
int idx_bit = candidate_bit_it - msg_candidate.begin();
int bit_pos_in_current_byte = (bits_per_byte-1)-(idx_bit % bits_per_byte);
byte |= (unsigned char)(*candidate_bit_it) << bit_pos_in_current_byte;
ss << *candidate_bit_it;
if (idx_bit % bits_per_byte == bits_per_byte-1)
{
bytes.push_back(byte);
VLOG(LMORE) << ss.str() << " -> byte=" << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)byte; ss.str("");
byte = 0;
}
}
bytes.push_back(byte); // implies: insert 6 zeros at the end to fit the 250bits into a multiple of bytes
VLOG(LMORE) << " -> byte=" << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)byte
<< std::setfill(' ') << std::resetiosflags(std::ios::hex);
}
void sbas_l1_telemetry_decoder_cc::crc_verifier::
zerropad_front_and_convert_to_bytes(const std::vector<int> msg_candidate, std::vector<unsigned char> &bytes)
{
std::stringstream ss;
const size_t bits_per_byte = 8;
unsigned char byte = 0;
int idx_bit = 6; // insert 6 zeros at the front to fit the 250bits into a multiple of bytes
VLOG(LMORE) << "zerropad_front_and_convert_to_bytes():" << byte;
for (std::vector<int>::const_iterator candidate_bit_it = msg_candidate.begin(); candidate_bit_it < msg_candidate.end(); ++candidate_bit_it)
{
int bit_pos_in_current_byte = (bits_per_byte-1)-(idx_bit % bits_per_byte);
byte |= (unsigned char)(*candidate_bit_it) << bit_pos_in_current_byte;
ss << *candidate_bit_it;
if (idx_bit % bits_per_byte == bits_per_byte-1)
{
bytes.push_back(byte);
VLOG(LMORE) << ss.str() << " -> byte=" << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)byte; ss.str("");
byte = 0;
}
idx_bit++;
}
VLOG(LMORE) << " -> byte=" << std::setw(2) << std::setfill('0') << std::hex << (unsigned int)byte
<< std::setfill(' ') << std::resetiosflags(std::ios::hex);
}
void sbas_l1_telemetry_decoder_cc::set_raw_msg_queue(concurrent_queue<Sbas_Raw_Msg> *raw_msg_queue)
{
sbas_telemetry_data.set_raw_msg_queue(raw_msg_queue);
}
void sbas_l1_telemetry_decoder_cc::set_iono_queue(concurrent_queue<Sbas_Ionosphere_Correction> *iono_queue)
{
sbas_telemetry_data.set_iono_queue(iono_queue);
}
void sbas_l1_telemetry_decoder_cc::set_sat_corr_queue(concurrent_queue<Sbas_Satellite_Correction> *sat_corr_queue)
{
sbas_telemetry_data.set_sat_corr_queue(sat_corr_queue);
}
void sbas_l1_telemetry_decoder_cc::set_ephemeris_queue(concurrent_queue<Sbas_Ephemeris> *ephemeris_queue)
{
sbas_telemetry_data.set_ephemeris_queue(ephemeris_queue);
}

View File

@@ -0,0 +1,174 @@
/*!
* \file sbas_l1_telemetry_decoder_cc.h
* \brief Interface of a SBAS telemetry data decoder block
* \author Daniel Fehr 2013. daniel.co(at)bluewin.ch
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2013 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR 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 GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_SBAS_L1_TELEMETRY_DECODER_CC_H
#define GNSS_SDR_SBAS_L1_TELEMETRY_DECODER_CC_H
#include <fstream>
#include <gnuradio/block.h>
#include <gnuradio/msg_queue.h>
#include <boost/crc.hpp>
#include "gnss_satellite.h"
#include "viterbi_decoder.h"
#include "sbas_telemetry_data.h"
class sbas_l1_telemetry_decoder_cc;
typedef boost::shared_ptr<sbas_l1_telemetry_decoder_cc> sbas_l1_telemetry_decoder_cc_sptr;
sbas_l1_telemetry_decoder_cc_sptr
sbas_l1_make_telemetry_decoder_cc(Gnss_Satellite satellite, long if_freq, long fs_in, unsigned
int vector_length, boost::shared_ptr<gr::msg_queue> queue, bool dump);
/*!
* \brief This class implements a block that decodes the SBAS integrity and corrections data defined in RTCA MOPS DO-229
*
*/
class sbas_l1_telemetry_decoder_cc : public gr::block
{
public:
~sbas_l1_telemetry_decoder_cc();
void set_satellite(Gnss_Satellite satellite); //!< Set satellite PRN
void set_channel(int channel); //!< Set receiver's channel
// queues to communicate broadcasted SBAS data to other blocks of GNSS-SDR
void set_raw_msg_queue(concurrent_queue<Sbas_Raw_Msg> *raw_msg_queue);
void set_iono_queue(concurrent_queue<Sbas_Ionosphere_Correction> *iono_queue);
void set_sat_corr_queue(concurrent_queue<Sbas_Satellite_Correction> *sat_corr_queue);
void set_ephemeris_queue(concurrent_queue<Sbas_Ephemeris> *ephemeris_queue);
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 forecast (int noutput_items, gr_vector_int &ninput_items_required);
private:
friend sbas_l1_telemetry_decoder_cc_sptr
sbas_l1_make_telemetry_decoder_cc(Gnss_Satellite satellite, long if_freq, long fs_in,unsigned
int vector_length, boost::shared_ptr<gr::msg_queue> queue, bool dump);
sbas_l1_telemetry_decoder_cc(Gnss_Satellite satellite, long if_freq, long fs_in, unsigned
int vector_length, boost::shared_ptr<gr::msg_queue> queue, bool dump);
void viterbi_decoder(double *page_part_symbols, int *page_part_bits);
void align_samples();
static const int d_samples_per_symbol = 2;
static const int d_symbols_per_bit = 2;
static const int d_block_size_in_bits = 30;
long d_fs_in;
bool d_dump;
Gnss_Satellite d_satellite;
int d_channel;
std::string d_dump_filename;
std::ofstream d_dump_file;
size_t d_block_size; //!< number of samples which are processed during one invocation of the algorithms
std::vector<double> d_sample_buf; //!< input buffer holding the samples to be processed in one block
typedef std::pair<int,std::vector<int>> msg_candiate_int_t;
typedef std::pair<int,std::vector<unsigned char>> msg_candiate_char_t;
// helper class for sample alignment
class sample_aligner
{
public:
sample_aligner();
~sample_aligner();
void reset();
/*
* samples length must be a multiple of two
* for block operation the
*/
bool get_symbols(const std::vector<double> samples, std::vector<double> &symbols);
private:
int d_n_smpls_in_history ;
double d_iir_par;
double d_corr_paired;
double d_corr_shifted;
bool d_aligned;
double d_past_sample;
} d_sample_aligner;
// helper class for symbol alignment and viterbi decoding
class symbol_aligner_and_decoder
{
public:
symbol_aligner_and_decoder();
~symbol_aligner_and_decoder();
void reset();
bool get_bits(const std::vector<double> symbols, std::vector<int> &bits);
private:
int d_KK;
Viterbi_Decoder * d_vd1;
Viterbi_Decoder * d_vd2;
double d_past_symbol;
} d_symbol_aligner_and_decoder;
// helper class for detecting the preamble and collect the corresponding message candidates
class frame_detector
{
public:
void reset();
void get_frame_candidates(const std::vector<int> bits, std::vector<std::pair<int, std::vector<int>>> &msg_candidates);
private:
std::deque<int> d_buffer;
} d_frame_detector;
// helper class for checking the CRC of the message candidates
class crc_verifier
{
public:
void reset();
void get_valid_frames(const std::vector<msg_candiate_int_t> msg_candidates, std::vector<msg_candiate_char_t> &valid_msgs);
private:
typedef boost::crc_optimal<24, 0x1864CFBu, 0x0, 0x0, false, false> crc_24_q_type;
crc_24_q_type d_checksum_agent;
void zerropad_front_and_convert_to_bytes(const std::vector<int> msg_candidate, std::vector<unsigned char> &bytes);
void zerropad_back_and_convert_to_bytes(const std::vector<int> msg_candidate, std::vector<unsigned char> &bytes);
} d_crc_verifier;
Sbas_Telemetry_Data sbas_telemetry_data;
};
#endif

View File

@@ -17,7 +17,8 @@
#
set(TELEMETRY_DECODER_LIB_SOURCES
gps_l1_ca_subframe_fsm.cc
gps_l1_ca_subframe_fsm.cc
viterbi_decoder.cc
)
include_directories(

View File

@@ -0,0 +1,598 @@
/*!
* \file viterbi_decoder.cc
* \brief Implementation of a Viterbi decoder class based on the Iterative Solutions
* Coded Modulation Library by Matthew C. Valenti
* \author Daniel Fehr 2013. daniel.co(at)bluewin.ch
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2013 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR 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 GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#include "viterbi_decoder.h"
#include <iostream>
#include <glog/log_severity.h>
#include <glog/logging.h>
// logging
#define EVENT 2 // logs important events which don't occur every block
#define FLOW 3 // logs the function calls of block processing functions
#define BLOCK 4 // once per block
#define SAMPLE 5 // about one log entry per sample
#define LMORE 6 // many entries per sample / very specific stuff
#define MAXLOG 1e7 /* Define infinity */
Viterbi_Decoder::Viterbi_Decoder(const int g_encoder[], const int KK, const int nn)
{
d_nn = nn; //Coding rate 1/n
d_KK = KK; //Constraint Length
// derived code properties
d_mm = d_KK - 1;
d_states = 1 << d_mm; /* 2^mm */
d_number_symbols = 1 << d_nn; /* 2^nn */
/* create appropriate transition matrices (trellis) */
d_out0 = new int[d_states];
d_out1 = new int[d_states];
d_state0 = new int[d_states];
d_state1 = new int[d_states];
nsc_transit(d_out0, d_state0, 0, g_encoder, d_KK, d_nn);
nsc_transit(d_out1, d_state1, 1, g_encoder, d_KK, d_nn);
// initialise trellis state
d_trellis_state_is_initialised = false;
Viterbi_Decoder::init_trellis_state();
}
Viterbi_Decoder::~Viterbi_Decoder()
{
// trellis definition
delete[] d_out0;
delete[] d_out1;
delete[] d_state0;
delete[] d_state1;
// init trellis state
delete[] d_pm_t;
delete[] d_rec_array;
delete[] d_metric_c;
}
void
Viterbi_Decoder::reset()
{
init_trellis_state();
}
/* Function decode_block()
Description: Uses the Viterbi algorithm to perform hard-decision decoding of a convolutional code.
Input parameters:
r[] The received signal in LLR-form. For BPSK, must be in form r = 2*a*y/(sigma^2).
LL The number of data bits to be decoded (doen't inlcude the mm zero-tail-bits)
Output parameters:
output_u_int[] Hard decisions on the data bits (without the mm zero-tail-bits)
*/
float
Viterbi_Decoder::decode_block(const double input_c[], int output_u_int[], const int LL)
{
int state;
int decoding_length_mismatch;
VLOG(FLOW) << "decode_block(): LL=" << LL;
// init
init_trellis_state();
// do add compare select
do_acs(input_c, LL+d_mm);
// tail, no need to output -> traceback, but don't decode
state = do_traceback(d_mm);
// traceback and decode
decoding_length_mismatch = do_tb_and_decode(d_mm, LL, state, output_u_int, d_indicator_metric);
VLOG(FLOW) << "decoding length mismatch: " << decoding_length_mismatch;
return d_indicator_metric;
}
float
Viterbi_Decoder::decode_continuous(const double sym[], const int traceback_depth, int bits[],
const int nbits_requested, int &nbits_decoded)
{
int state;
int decoding_length_mismatch;
VLOG(FLOW) << "decode_continuous(): nbits_requested=" << nbits_requested;
// do add compare select
do_acs(sym, nbits_requested);
// the ML sequence in the newest part of the trellis can not be decoded
// since it depends on the future values -> traceback, but don't decode
state = do_traceback(traceback_depth);
// traceback and decode
decoding_length_mismatch = do_tb_and_decode(traceback_depth, nbits_requested, state, bits,
d_indicator_metric);
nbits_decoded = nbits_requested + decoding_length_mismatch;
VLOG(FLOW) << "decoding length mismatch (continuous decoding): "
<< decoding_length_mismatch;
return d_indicator_metric;
}
void
Viterbi_Decoder::init_trellis_state()
{
int state;
// if trellis state has been initialised, free old state memory
if(d_trellis_state_is_initialised)
{
// init trellis state
delete[] d_pm_t;
delete[] d_rec_array;
delete[] d_metric_c;
}
// reserve new trellis state memory
d_pm_t = new float[d_states];
d_trellis_paths = std::deque<Prev>();
d_rec_array = new float[d_nn];
d_metric_c = new float[d_number_symbols];
d_trellis_state_is_initialised = true;
/* initialize trellis */
for (state = 0; state < d_states; state++)
{
d_pm_t[state] = -MAXLOG;
//d_pm_t_next[state] = -MAXLOG;
}
d_pm_t[0] = 0; /* start in all-zeros state */
d_indicator_metric = 0;
}
int
Viterbi_Decoder::do_acs(const double sym[], int nbits)
{
int t, i, state_at_t;
float metric;
float max_val;
float * pm_t_next = new float[d_states];
/* t:
* - state: state at t
* - d_prev_section[state_at_t]: path metric at t for state state_at_t
* - d_out0[state_at_t]: sent symbols for a data bit 0 if state is state_at_t at time t
*
*/
for (state_at_t = 0; state_at_t < d_states; state_at_t++)
{
pm_t_next[state_at_t] = -MAXLOG;
}
/* go through trellis */
for (t = 0; t < nbits; t++)
{
/* Temporarily store the received symbols current decoding step */
for (i = 0; i < d_nn; i++)
d_rec_array[i] = (float) sym[d_nn * t + i];
/* precompute all possible branch metrics */
for (i = 0; i < d_number_symbols; i++)
{
d_metric_c[i] = gamma(d_rec_array, i, d_nn);
VLOG(LMORE) << "metric for (tx_sym=" << i << "|ry_sym=(" << d_rec_array[0] << ", " << d_rec_array[1] << ") = " << d_metric_c[i];
}
// find the survivor branches leading the trellis states at t+1
Prev next_trellis_states(d_states, t+1);
/* step through all states */
for (state_at_t = 0; state_at_t < d_states; state_at_t++)
{
int next_state_if_0 = d_state0[state_at_t];
int next_state_if_1 = d_state1[state_at_t];
/* hypothesis: info bit is a zero */
int bm_0 = d_metric_c[d_out0[state_at_t]];
metric = d_pm_t[state_at_t] + bm_0; // path metric + zerobranch metric
/* store new metric if more than metric in storage */
if (metric > pm_t_next[next_state_if_0])
{
pm_t_next[next_state_if_0] = metric;
next_trellis_states.set_current_state_as_ancestor_of_next_state(next_state_if_0, state_at_t);
next_trellis_states.set_decoded_bit_for_next_state(next_state_if_0, 0);
next_trellis_states.set_survivor_branch_metric_of_next_state(next_state_if_0, bm_0);
}
/* hypothesis: info bit is a one */
int bm_1 = d_metric_c[d_out1[state_at_t]];
metric = d_pm_t[state_at_t] + bm_1; // path metric + onebranch metric
/* store new metric if more than metric in storage */
if (metric > pm_t_next[next_state_if_1])
{
pm_t_next[next_state_if_1] = metric;
next_trellis_states.set_current_state_as_ancestor_of_next_state(next_state_if_1, state_at_t);
next_trellis_states.set_decoded_bit_for_next_state(next_state_if_1, 1);
next_trellis_states.set_survivor_branch_metric_of_next_state(next_state_if_1, bm_1);
}
}
d_trellis_paths.push_front(next_trellis_states);
/* normalize -> afterwards, the largest metric value is always 0 */
//max_val = 0;
max_val = -MAXLOG;
for (state_at_t = 0; state_at_t < d_states; state_at_t++)
{
if (pm_t_next[state_at_t] > max_val)
{
max_val = pm_t_next[state_at_t];
}
}
VLOG(LMORE) << "max_val at t=" << t << ": " << max_val;
for (state_at_t = 0; state_at_t < d_states; state_at_t++)
{
d_pm_t[state_at_t] = pm_t_next[state_at_t] - max_val;
pm_t_next[state_at_t] = -MAXLOG;
}
}
delete[] pm_t_next;
return t;
}
int
Viterbi_Decoder::do_traceback(size_t traceback_length)
{
// traceback_length is in bits
int state;
std::deque<Prev>::iterator it;
VLOG(FLOW) << "do_traceback(): traceback_length=" << traceback_length << std::endl;
if (d_trellis_paths.size() < traceback_length)
{
traceback_length = d_trellis_paths.size();
}
state = 0; // maybe start not at state 0, but at state with best metric
for (it = d_trellis_paths.begin(); it < d_trellis_paths.begin() + traceback_length; ++it)
{
state = it->get_anchestor_state_of_current_state(state);
}
return state;
}
int
Viterbi_Decoder::do_tb_and_decode(int traceback_length, int requested_decoding_length, int state, int output_u_int[], float& indicator_metric)
{
int n_of_branches_for_indicator_metric = 500;
int t_out;
std::deque<Prev>::iterator it;
int decoding_length_mismatch;
int overstep_length;
int n_im=0;
VLOG(FLOW) << "do_tb_and_decode(): requested_decoding_length=" << requested_decoding_length;
// decode only decode_length bits -> overstep newer bits which are too much
decoding_length_mismatch = d_trellis_paths.size() - (traceback_length + requested_decoding_length);
VLOG(BLOCK) << "decoding_length_mismatch=" << decoding_length_mismatch;
overstep_length = decoding_length_mismatch >= 0 ? decoding_length_mismatch : 0;
VLOG(BLOCK) << "overstep_length=" << overstep_length;
for (it = d_trellis_paths.begin() + traceback_length; it < d_trellis_paths.begin()+traceback_length + overstep_length; ++it)
{
state = it->get_anchestor_state_of_current_state(state);
}
t_out = d_trellis_paths.end()-(d_trellis_paths.begin() + traceback_length + overstep_length)-1;//requested_decoding_length-1;
indicator_metric = 0;
for (it = d_trellis_paths.begin() + traceback_length + overstep_length; it < d_trellis_paths.end(); ++it)
{
//VLOG(SAMPLE)<< "@t_out=" << t_out;
//VLOG(SAMPLE) << "tb&dec: @t=" << it->get_t() << " bit=" << it->get_bit_of_current_state(state) << " bm=" << it->get_metric_of_current_state(state);
if(it - (d_trellis_paths.begin() + traceback_length + overstep_length) < n_of_branches_for_indicator_metric)
{
n_im++;
indicator_metric += it->get_metric_of_current_state(state);
VLOG(SAMPLE) << "@t=" << it->get_t() << " b=" << it->get_bit_of_current_state(state) << " sm=" << indicator_metric << " d=" << it->get_metric_of_current_state(state);
}
output_u_int[t_out] = it->get_bit_of_current_state(state);
state = it->get_anchestor_state_of_current_state(state);
t_out--;
}
indicator_metric/=n_im;
VLOG(BLOCK) << "indicator metric: " << indicator_metric;
// remove old states
if (d_trellis_paths.begin() + traceback_length+overstep_length <= d_trellis_paths.end())
{
d_trellis_paths.erase(d_trellis_paths.begin()+traceback_length+overstep_length, d_trellis_paths.end());
}
return decoding_length_mismatch;
}
/* function Gamma()
Description: Computes the branch metric used for decoding.
Output parameters:
(returned float) The metric between the hypothetical symbol and the recevieved vector
Input parameters:
rec_array The received vector, of length nn
symbol The hypothetical symbol
nn The length of the received vector
This function is used by siso() */
float
Viterbi_Decoder::gamma(float rec_array[], int symbol, int nn)
{
float rm = 0;
int i;
int mask;
float txsym;
mask = 1;
for (i = 0; i < nn; i++)
{
//if (symbol & mask) rm += rec_array[nn - i - 1];
txsym = symbol & mask ? 1 : -1;
rm += txsym * rec_array[nn - i - 1];
mask = mask << 1;
}
//rm = rm > 50 ? rm : -1000;
return (rm);
}
/* function that creates the transit and output vectors */
void
Viterbi_Decoder::nsc_transit(int output_p[], int trans_p[], int input, const int g[],
int KK, int nn)
{
int nextstate[1];
int state, states;
states = (1 << (KK - 1)); /* The number of states: 2^mm */
/* Determine the output and next state for each possible starting state */
for (state = 0; state < states; state++)
{
output_p[state] = nsc_enc_bit(nextstate, input, state, g, KK, nn);
trans_p[state] = nextstate[0];
}
return;
}
/* Function nsc_enc_bit()
Description: Convolutionally encodes a single bit using a rate 1/n encoder.
Takes in one input bit at a time, and produces a n-bit output.
Input parameters:
input The input data bit (i.e. a 0 or 1).
state_in The starting state of the encoder (an int from 0 to 2^m-1).
g[] An n-element vector containing the code generators in binary form.
KK The constraint length of the convolutional code.
nn number of symbols bits per input bits (rate 1/nn)
Output parameters:
output_p[] An n-element vector containing the encoded bits.
state_out_p[] An integer containing the final state of the encoder
(i.e. the state after encoding this bit)
This function is used by rsc_encode(), nsc_transit(), rsc_transit(), and nsc_transit() */
int
Viterbi_Decoder::nsc_enc_bit(int state_out_p[], int input, int state_in,
const int g[], int KK, int nn)
{
/* declare variables */
int state, i;
int out = 0;
/* create a word made up of state and new input */
state = (input << (KK - 1)) ^ state_in;
/* AND the word with the generators */
for (i = 0; i < nn; i++)
{
/* update output symbol */
out = (out << 1) + parity_counter(state & g[i], KK);
}
/* shift the state to make the new state */
state_out_p[0] = state >> 1;
return (out);
}
/* function parity_counter()
Description: Determines if a symbol has odd (1) or even (0) parity
Output parameters:
(returned int): The symbol's parity = 1 for odd and 0 for even
Input parameters:
symbol: The integer-valued symbol
length: The highest bit position in the symbol
This function is used by nsc_enc_bit(), rsc_enc_bit(), and rsc_tail() */
int
Viterbi_Decoder::parity_counter(int symbol, int length)
{
int counter;
int temp_parity = 0;
for (counter = 0; counter < length; counter++)
{
temp_parity = temp_parity ^ (symbol & 1);
symbol = symbol >> 1;
}
return (temp_parity);
}
// prev helper class
Viterbi_Decoder::Prev::Prev(int states, int t)
{
this->t = t;
state = new int[states];
bit = new int[states];
metric = new float[states];
refcount = new int;
*refcount = 1;
//std::cout << "Prev(" << states << ", " << t << ")" << " constructor" << std::endl;
}
// copy constructor
Viterbi_Decoder::Prev::Prev(const Prev& prev)
{
refcount = prev.refcount;
(*refcount)++;
t = prev.t;
state = prev.state;
bit = prev.bit;
metric = prev.metric;
VLOG(LMORE) << "Prev(" << "?" << ", " << t << ")" << " copy, new refcount = " << *refcount;
}
// assignment constructor
Viterbi_Decoder::Prev& Viterbi_Decoder::Prev::operator=(const Prev& other)
{
// check for self-assignment
if(&other == this)
{
return *this;
}
// handle old resources
if(*refcount==1)
{ // if they are not used anymore -> unallocate them
delete[] state;
delete[] bit;
delete[] metric;
delete refcount;
}
else
{ // this object is not anymore using them
(*refcount)--;
}
// increase ref counter for this resource set
refcount = other.refcount;
(*refcount)++;
// take over resources
t = other.t;
state = other.state;
bit = other.bit;
metric = other.metric;
VLOG(LMORE) << "Prev(" << "?" << ", " << t << ")" << " assignment, new refcount = " << *refcount;
return *this;
}
Viterbi_Decoder::Prev::~Prev()
{
if (*refcount == 1)
{
delete[] state;
delete[] bit;
delete[] metric;
delete refcount;
//std::cout << "~Prev(" << "?" << ", " << t << ")" << " destructor with delete" << std::endl;
}
else
{
(*refcount)--;
VLOG(LMORE) << "~Prev(" << "?" << ", " << t << ")" << " destructor after copy, new refcount = " << *refcount;
}
}
int Viterbi_Decoder::Prev::get_anchestor_state_of_current_state(int current_state)
{
//std::cout << "get prev state: for state " << current_state << " at time " << t << ", the prev state at time " << t-1 << " is " << state[current_state] << std::endl;
return state[current_state];
}
int Viterbi_Decoder::Prev::get_bit_of_current_state(int current_state)
{
//std::cout << "get prev bit : for state " << current_state << " at time " << t << ", the send bit is " << bit[current_state] << std::endl;
return bit[current_state];
}
float Viterbi_Decoder::Prev::get_metric_of_current_state(int current_state)
{
return metric[current_state];
}
int Viterbi_Decoder::Prev::get_t()
{
return t;
}
void Viterbi_Decoder::Prev::set_current_state_as_ancestor_of_next_state(int next_state, int current_state)
{
state[next_state] = current_state;
}
void Viterbi_Decoder::Prev::set_decoded_bit_for_next_state(int next_state, int bit)
{
this->bit[next_state] = bit;
}
void Viterbi_Decoder::Prev::set_survivor_branch_metric_of_next_state(int next_state, float metric)
{
this->metric[next_state] = metric;
}

View File

@@ -0,0 +1,114 @@
/*!
* \file viterbi_decoder.h
* \brief Interface of a Viterbi decoder class based on the Iterative Solutions
* Coded Modulation Library by Matthew C. Valenti
* \author Daniel Fehr 2013. daniel.co(at)bluewin.ch
*
* -------------------------------------------------------------------------
*
* Copyright (C) 2010-2013 (see AUTHORS file for a list of contributors)
*
* GNSS-SDR is a software defined Global Navigation
* Satellite Systems receiver
*
* This file is part of GNSS-SDR.
*
* GNSS-SDR is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* GNSS-SDR 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 GNSS-SDR. If not, see <http://www.gnu.org/licenses/>.
*
* -------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_VITERBIDECODER_H_
#define GNSS_SDR_VITERBIDECODER_H_
#include <deque>
#include <iostream>
class Viterbi_Decoder
{
public:
Viterbi_Decoder(const int g_encoder[], const int KK, const int nn);
~Viterbi_Decoder();
void reset();
float decode_block(const double input_c[], int* output_u_int, const int LL);
float decode_continuous(const double sym[], const int traceback_depth, int output_u_int[],
const int nbits_requested, int &nbits_decoded);
private:
class Prev
{
public:
Prev(int states, int t);
Prev(const Prev& prev);
Prev& operator=(const Prev& other);
~Prev();
int get_anchestor_state_of_current_state(int current_state);
int get_bit_of_current_state(int current_state);
float get_metric_of_current_state(int current_state);
int get_t();
void set_current_state_as_ancestor_of_next_state(int next_state, int current_state);
void set_decoded_bit_for_next_state(int next_state, int bit);
void set_survivor_branch_metric_of_next_state(int next_state, float metric);
private:
int t;
int * state;
int * bit;
float * metric;
int * refcount;
};
// code properties
int d_KK;
int d_nn;
// derived code properties
int d_mm;
int d_states;
int d_number_symbols;
// trellis definition
int* d_out0;
int* d_state0;
int* d_out1;
int* d_state1;
// trellis state
float *d_pm_t;
std::deque<Prev> d_trellis_paths;
float *d_metric_c; /* Set of all possible branch metrics */
float *d_rec_array; /* Received values for one trellis section */
bool d_trellis_state_is_initialised;
// measures
float d_indicator_metric;
// operations on the trellis (change decoder state)
void init_trellis_state();
int do_acs(const double sym[], int nbits);
int do_traceback(size_t traceback_length);
int do_tb_and_decode(int traceback_length, int requested_decoding_length, int state, int bits[], float& indicator_metric);
// branch metric function
float gamma(float rec_array[], int symbol, int nn);
// trellis generation
void nsc_transit(int output_p[], int trans_p[], int input, const int g[], int KK, int nn);
int nsc_enc_bit(int state_out_p[], int input, int state_in, const int g[], int KK, int nn);
int parity_counter(int symbol, int length);
};
#endif /* GNSS_SDR_VITERBIDECODER_H_ */