Add work on the Galileo E6 message decoding up to HAS page CRC check

This commit is contained in:
Carles Fernandez 2020-11-08 14:10:43 +01:00
parent b8862f8d7d
commit 76bbd3c3bb
No known key found for this signature in database
GPG Key ID: 4C583C52B0C3877D
7 changed files with 270 additions and 26 deletions

View File

@ -27,8 +27,9 @@ SPDX-FileCopyrightText: 2011-2020 Carles Fernandez-Prades <carles.fernandez@cttc
- Added the Galileo E6 B/C signal structure based on E6-B/C Codes Technical
Note, Issue 1, January 2019, including Acquisition and Tracking blocks. The
structure of the Galileo CNAV message has not been made public, so the decoder
is empty.
Telemetry Decoder is still empty (only the CRC is checked, based on Galileo
High Accuracy Service E6-B Signal-In-Space Message Specification v1.2, April
2020).
### Improvements in Maintainability:

View File

@ -22,7 +22,7 @@
#include "galileo_telemetry_decoder_gs.h"
#include "Galileo_E1.h" // for GALILEO_E1_CODE_PERIOD_MS
#include "Galileo_E5a.h" // for GALILEO_E5A_CODE_PERIO...
#include "Galileo_E5a.h" // for GALILEO_E5A_CODE_PERIOD_MS
#include "Galileo_E5b.h" // for GALILEO_E5B_CODE_PERIOD_MS
#include "Galileo_E6.h" // for GALILEO_E6_CODE_PERIOD_MS
#include "convolutional.h"
@ -112,15 +112,15 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs(
case 3: // CNAV
{
d_PRN_code_period_ms = static_cast<uint32_t>(GALILEO_E6_CODE_PERIOD_MS);
d_bits_per_preamble = 16; // Not available
d_samples_per_preamble = 16; // Not available
d_preamble_period_symbols = 1000; // Not available
d_required_symbols = 1000 + d_samples_per_preamble; // Not available
d_preamble_samples.reserve(d_samples_per_preamble); // Not available
d_frame_length_symbols = d_preamble_period_symbols - d_samples_per_preamble; // Not available
d_codelength = d_preamble_period_symbols - d_samples_per_preamble; // Not available
d_datalength = (d_codelength / d_nn) - d_mm; // Not available
d_max_symbols_without_valid_frame = d_preamble_period_symbols * 10; // Not available
d_bits_per_preamble = GALILEO_CNAV_PREAMBLE_LENGTH_BITS;
d_samples_per_preamble = GALILEO_CNAV_PREAMBLE_LENGTH_BITS;
d_preamble_period_symbols = GALILEO_CNAV_SYMBOLS_PER_PAGE;
d_required_symbols = static_cast<uint32_t>(GALILEO_CNAV_SYMBOLS_PER_PAGE) + d_samples_per_preamble;
d_preamble_samples.reserve(d_samples_per_preamble);
d_frame_length_symbols = GALILEO_CNAV_SYMBOLS_PER_PAGE - GALILEO_CNAV_PREAMBLE_LENGTH_BITS;
d_codelength = GALILEO_CNAV_SYMBOLS_PER_PAGE - GALILEO_CNAV_PREAMBLE_LENGTH_BITS;
d_datalength = (d_codelength / d_nn) - d_mm;
d_max_symbols_without_valid_frame = GALILEO_CNAV_SYMBOLS_PER_PAGE * 60;
break;
}
default:
@ -167,8 +167,14 @@ galileo_telemetry_decoder_gs::galileo_telemetry_decoder_gs(
}
case 3: // CNAV for E6
{
// TODO
d_preamble_samples[i] = 1;
if (GALILEO_CNAV_PREAMBLE[i] == '1')
{
d_preamble_samples[i] = 1;
}
else
{
d_preamble_samples[i] = -1;
}
break;
}
}
@ -256,14 +262,14 @@ void galileo_telemetry_decoder_gs::decode_INAV_word(float *page_part_symbols, in
page_part_symbols_deint[i] = -page_part_symbols_deint[i];
}
}
std::vector<int32_t> page_part_bits(frame_length / 2);
const int32_t decoded_length = frame_length / 2;
std::vector<int32_t> page_part_bits(decoded_length);
viterbi_decoder(page_part_symbols_deint.data(), page_part_bits.data());
// 3. Call the Galileo page decoder
std::string page_String;
page_String.reserve(frame_length / 2);
for (int32_t i = 0; i < (frame_length / 2); i++)
page_String.reserve(decoded_length);
for (int32_t i = 0; i < decoded_length; i++)
{
if (page_part_bits[i] > 0)
{
@ -391,13 +397,15 @@ void galileo_telemetry_decoder_gs::decode_FNAV_word(float *page_symbols, int32_t
page_symbols_deint[i] = -page_symbols_deint[i];
}
}
std::vector<int32_t> page_bits(frame_length / 2);
const int32_t decoded_length = frame_length / 2;
std::vector<int32_t> page_bits(decoded_length);
viterbi_decoder(page_symbols_deint.data(), page_bits.data());
// 3. Call the Galileo page decoder
std::string page_String;
page_String.reserve(frame_length);
for (int32_t i = 0; i < frame_length; i++)
page_String.reserve(decoded_length);
for (int32_t i = 0; i < decoded_length; i++)
{
if (page_bits[i] > 0)
{
@ -442,9 +450,55 @@ void galileo_telemetry_decoder_gs::decode_FNAV_word(float *page_symbols, int32_t
}
void galileo_telemetry_decoder_gs::decode_CNAV_word(float *page_symbols __attribute__((unused)), int32_t frame_length __attribute__((unused)))
void galileo_telemetry_decoder_gs::decode_CNAV_word(float *page_symbols, int32_t page_length)
{
// 1. De-interleave
std::vector<float> page_symbols_deint(page_length);
deinterleaver(GALILEO_CNAV_INTERLEAVER_ROWS, GALILEO_CNAV_INTERLEAVER_COLS, page_symbols, page_symbols_deint.data());
// 2. Viterbi decoder
// 2.1 Take into account the NOT gate in G2 polynomial (Galileo ICD Figure 13, FEC encoder)
// 2.2 Take into account the possible inversion of the polarity due to PLL lock at 180 degrees
for (int32_t i = 0; i < page_length; i++)
{
if ((i + 1) % 2 == 0)
{
page_symbols_deint[i] = -page_symbols_deint[i];
}
}
const int32_t decoded_length = page_length / 2;
std::vector<int32_t> page_bits(decoded_length);
viterbi_decoder(page_symbols_deint.data(), page_bits.data());
// 3. Call the Galileo page decoder
std::string page_String;
page_String.reserve(decoded_length);
for (int32_t i = 0; i < decoded_length; i++)
{
if (page_bits[i] > 0)
{
page_String.push_back('1');
}
else
{
page_String.push_back('0');
}
}
d_cnav_nav.read_HAS_page(page_String);
// 4. Check CRC
if (d_cnav_nav.get_flag_CRC_test() == true)
{
DLOG(INFO) << "Galileo E6B CRC correct in channel " << d_channel << " from satellite " << d_satellite;
}
else
{
DLOG(INFO) << "Galileo E6B CRC error in channel " << d_channel << " from satellite " << d_satellite;
}
// TODO
// Get full HAS message from different pages
// Reed Solomon decoding
// Retrieve data from message
}
@ -679,7 +733,7 @@ int galileo_telemetry_decoder_gs::general_work(int noutput_items __attribute__((
else
{
d_CRC_error_counter++;
if (d_CRC_error_counter > CRC_ERROR_LIMIT)
if ((d_CRC_error_counter > CRC_ERROR_LIMIT) and (d_frame_type != 3))
{
DLOG(INFO) << "Lost of frame sync SAT " << this->d_satellite;
d_flag_frame_sync = false;

View File

@ -23,7 +23,7 @@
#ifndef GNSS_SDR_GALILEO_TELEMETRY_DECODER_GS_H
#define GNSS_SDR_GALILEO_TELEMETRY_DECODER_GS_H
#include "galileo_cnav_message.h"
#include "galileo_fnav_message.h"
#include "galileo_inav_message.h"
#include "gnss_block_interface.h"
@ -104,6 +104,7 @@ private:
Gnss_Satellite d_satellite;
// navigation message vars
Galileo_Cnav_Message d_cnav_nav;
Galileo_Inav_Message d_inav_nav;
Galileo_Fnav_Message d_fnav_nav;

View File

@ -16,11 +16,12 @@ set(SYSTEM_PARAMETERS_SOURCES
galileo_utc_model.cc
galileo_ephemeris.cc
galileo_almanac_helper.cc
galileo_cnav_message.cc
galileo_fnav_message.cc
galileo_inav_message.cc
beidou_dnav_navigation_message.cc
beidou_dnav_ephemeris.cc
sbas_ephemeris.cc
galileo_fnav_message.cc
gps_cnav_ephemeris.cc
gps_cnav_navigation_message.cc
glonass_gnav_ephemeris.cc
@ -43,12 +44,14 @@ set(SYSTEM_PARAMETERS_HEADERS
galileo_ephemeris.h
galileo_almanac.h
galileo_almanac_helper.h
Galileo_CNAV.h
Galileo_FNAV.h
Galileo_INAV.h
galileo_iono.h
galileo_cnav_message.h
galileo_fnav_message.h
galileo_inav_message.h
sbas_ephemeris.h
galileo_fnav_message.h
gps_cnav_ephemeris.h
gps_cnav_navigation_message.h
gps_cnav_iono.h

View File

@ -0,0 +1,53 @@
/*!
* \file Galileo_CNAV.h
* \brief Galileo CNAV mesage constants. Data from:
* Galileo High Accuracy Service E6-B Signal-In-Space Message Specification v1.2
* (April 2020).
* \author Carles Fernandez-Prades, 2020. cfernandez(at)cttc.es
*
*
* -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2020 (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.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_GALILEO_CNAV_H
#define GNSS_SDR_GALILEO_CNAV_H
#include <cstdint>
/** \addtogroup Core
* \{ */
/** \addtogroup System_Parameters
* \{ */
// Galileo CNAV message structure
constexpr int32_t GALILEO_CNAV_SYMBOLS_PER_PAGE = 1000; //!< Total numer of symbols per HAS page including the sync pattern
constexpr int32_t GALILEO_CNAV_PREAMBLE_PERIOD_SYMBOLS = 1000;
constexpr int32_t GALILEO_CNAV_PAGE_MS = 1; //!< Duration in ms of a CNAV page
constexpr int32_t GALILEO_CNAV_INTERLEAVER_ROWS = 8;
constexpr int32_t GALILEO_CNAV_INTERLEAVER_COLS = 123;
constexpr int32_t GALILEO_CNAV_TELEMETRY_RATE_BITS_SECOND = 1000; // bps
constexpr int32_t GALILEO_CNAV_HAS_PAGE_DATA_BITS = 448;
constexpr int32_t GALILEO_CNAV_PAGE_RESERVED_BITS = 14;
constexpr int32_t GALILEO_CNAV_BITS_FOR_CRC = GALILEO_CNAV_HAS_PAGE_DATA_BITS + GALILEO_CNAV_PAGE_RESERVED_BITS; // 462
constexpr int32_t GALILEO_CNAV_BYTES_FOR_CRC = 60;
constexpr int32_t GALILEO_CNAV_MESSAGE_BITS_PER_PAGE = 424;
constexpr int32_t GALILEO_CNAV_PAGE_HEADER_BITS = 24;
constexpr int32_t GALILEO_CNAV_PREAMBLE_LENGTH_BITS = 16;
constexpr char GALILEO_CNAV_PREAMBLE[17] = "1011011101110000";
/** \} */
/** \} */
#endif // GNSS_SDR_GALILEO_CNAV_H

View File

@ -0,0 +1,71 @@
/*!
* \file galileo_cnav_message.cc
* \brief Implementation of a Galileo CNAV Data message as described in
* Galileo High Accuracy Service E6-B Signal-In-Space Message Specification v1.2
* (April 2020)
* \author Carles Fernandez-Prades, 2020 cfernandez(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2020 (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.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#include "galileo_cnav_message.h"
#include <boost/crc.hpp> // for boost::crc_basic, boost::crc_optimal
#include <boost/dynamic_bitset.hpp> // for boost::dynamic_bitset
#include <algorithm> // for reverse
using CRC_Galileo_CNAV_type = boost::crc_optimal<24, 0x1864CFBU, 0x0, 0x0, false, false>;
bool Galileo_Cnav_Message::CRC_test(std::bitset<GALILEO_CNAV_BITS_FOR_CRC> bits, uint32_t checksum) const
{
CRC_Galileo_CNAV_type CRC_Galileo;
// Galileo CNAV frame for CRC is not an integer multiple of bytes
// it needs to be filled with zeroes at the start of the frame.
// This operation is done in the transformation from bits to bytes
// using boost::dynamic_bitset.
boost::dynamic_bitset<unsigned char> frame_bits(std::string(bits.to_string()));
std::vector<unsigned char> bytes;
boost::to_block_range(frame_bits, std::back_inserter(bytes));
std::reverse(bytes.begin(), bytes.end());
CRC_Galileo.process_bytes(bytes.data(), GALILEO_CNAV_BYTES_FOR_CRC);
const uint32_t crc_computed = CRC_Galileo.checksum();
if (checksum == crc_computed)
{
return true;
}
return false;
}
void Galileo_Cnav_Message::read_HAS_page(const std::string& page_string)
{
const std::string has_page_bits = page_string.substr(0, GALILEO_CNAV_BITS_FOR_CRC);
const std::string CRC_data = page_string.substr(GALILEO_CNAV_BITS_FOR_CRC, 24);
const std::bitset<GALILEO_CNAV_BITS_FOR_CRC> Word_for_CRC_bits(has_page_bits);
const std::bitset<24> checksum(CRC_data);
if (CRC_test(Word_for_CRC_bits, checksum.to_ulong()) == true)
{
flag_CRC_test = true;
// CRC correct: Read HAS page header
}
else
{
flag_CRC_test = false;
}
}

View File

@ -0,0 +1,61 @@
/*!
* \file galileo_cnav_message.h
* \brief Implementation of a Galileo CNAV Data message as described in
* Galileo High Accuracy Service E6-B Signal-In-Space Message Specification v1.2
* (April 2020)
* \author Carles Fernandez-Prades, 2020 cfernandez(at)cttc.es
*
* -----------------------------------------------------------------------------
*
* Copyright (C) 2010-2020 (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.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* -----------------------------------------------------------------------------
*/
#ifndef GNSS_SDR_GALILEO_CNAV_MESSAGE_H
#define GNSS_SDR_GALILEO_CNAV_MESSAGE_H
#include "Galileo_CNAV.h"
#include <bitset>
#include <cstdint>
#include <string>
/** \addtogroup Core
* \{ */
/** \addtogroup System_Parameters
* \{ */
/*!
* \brief This class handles the Galileo CNAV Data message, as described in the
* Galileo High Accuracy Service E6-B Signal-In-Space Message Specification v1.2
* (April 2020)
*/
class Galileo_Cnav_Message
{
public:
Galileo_Cnav_Message() = default;
void read_HAS_page(const std::string& page_string);
inline bool get_flag_CRC_test() const
{
return flag_CRC_test;
}
private:
bool CRC_test(std::bitset<GALILEO_CNAV_BITS_FOR_CRC> bits, uint32_t checksum) const;
bool flag_CRC_test{};
};
/** \} */
/** \} */
#endif // GNSS_SDR_GALILEO_CNAV_MESSAGE_H