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:
		| @@ -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( | ||||
|   | ||||
| @@ -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_; | ||||
| } | ||||
|  | ||||
| @@ -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 | ||||
| @@ -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( | ||||
|   | ||||
| @@ -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); | ||||
| } | ||||
| @@ -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 | ||||
| @@ -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( | ||||
|   | ||||
							
								
								
									
										598
									
								
								src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										598
									
								
								src/algorithms/telemetry_decoder/libs/viterbi_decoder.cc
									
									
									
									
									
										Normal 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; | ||||
| } | ||||
							
								
								
									
										114
									
								
								src/algorithms/telemetry_decoder/libs/viterbi_decoder.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										114
									
								
								src/algorithms/telemetry_decoder/libs/viterbi_decoder.h
									
									
									
									
									
										Normal 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_ */ | ||||
		Reference in New Issue
	
	Block a user
	 Carles Fernandez
					Carles Fernandez