From 7333f0ce733508082ec784aae388ab1d0c2d5a5a Mon Sep 17 00:00:00 2001 From: "Alexander V. Joura" Date: Fri, 9 Sep 2022 15:43:59 +0300 Subject: [PATCH] - Added Hamming code correction method - Added google tests for this method --- src/core/system_parameters/GLONASS_L1_L2_CA.h | 3 + .../glonass_gnav_navigation_message.cc | 95 ++++++++++++++++++- .../glonass_gnav_navigation_message.h | 6 ++ .../glonass_gnav_nav_message_test.cc | 67 +++++++++++++ 4 files changed, 168 insertions(+), 3 deletions(-) diff --git a/src/core/system_parameters/GLONASS_L1_L2_CA.h b/src/core/system_parameters/GLONASS_L1_L2_CA.h index e893f7df7..2d31aa140 100644 --- a/src/core/system_parameters/GLONASS_L1_L2_CA.h +++ b/src/core/system_parameters/GLONASS_L1_L2_CA.h @@ -239,6 +239,9 @@ const std::vector GLONASS_GNAV_CRC_N_INDEX{35, 36, 37, 38, 39, 40, 41, const std::vector GLONASS_GNAV_CRC_P_INDEX{66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85}; const std::vector GLONASS_GNAV_CRC_Q_INDEX{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85}; +const std::vector> GLONASS_GNAV_HAMMING_INDEX{GLONASS_GNAV_CRC_I_INDEX, GLONASS_GNAV_CRC_J_INDEX, GLONASS_GNAV_CRC_K_INDEX, GLONASS_GNAV_CRC_L_INDEX, + GLONASS_GNAV_CRC_M_INDEX, GLONASS_GNAV_CRC_N_INDEX, GLONASS_GNAV_CRC_P_INDEX, GLONASS_GNAV_CRC_Q_INDEX}; + // GLONASS GNAV NAVIGATION MESSAGE STRUCTURE // NAVIGATION MESSAGE FIELDS POSITIONS diff --git a/src/core/system_parameters/glonass_gnav_navigation_message.cc b/src/core/system_parameters/glonass_gnav_navigation_message.cc index 3f1bcd12e..5b02162a6 100644 --- a/src/core/system_parameters/glonass_gnav_navigation_message.cc +++ b/src/core/system_parameters/glonass_gnav_navigation_message.cc @@ -133,6 +133,95 @@ bool Glonass_Gnav_Navigation_Message::CRC_test(const std::bitset& bits_io) const +{ + std::vector bits(GLONASS_GNAV_STRING_BITS); + + // Populate data and Hamming code vectors + for (size_t i = 0; i < bits.size(); i++) + { + bits[i] = static_cast(bits_io[i]); + } + + std::vector C(GLONASS_GNAV_HAMMING_CODE_BITS, 0); + int sum_bits; + for (size_t m = 0; m < GLONASS_GNAV_HAMMING_CODE_BITS; ++m) + { + sum_bits = 0; + for (int i : GLONASS_GNAV_HAMMING_INDEX[m]) + sum_bits += bits[i - 1]; + C[m] = bits[m] ^ (sum_bits % 2); + } + + int sum_hamming = 0; + for (int i = 0; i < GLONASS_GNAV_HAMMING_CODE_BITS; ++i) + { + sum_hamming += bits[i]; + } + + C[GLONASS_GNAV_HAMMING_CODE_BITS - 1] = (sum_hamming % 2) ^ (sum_bits % 2); + + int shortSumC = 0; + for (size_t m = 0; m < GLONASS_GNAV_HAMMING_CODE_BITS - 1; ++m) + { + shortSumC += C[m]; + } + + if (C[GLONASS_GNAV_HAMMING_CODE_BITS - 1] == 0) + { + if (shortSumC == 0) + { + // (A1) All checksums (C1, ..., C7 and C_Sigma) are equal to zero (all information + // bits and check bits are valid) + return true; + } + } + else + { + int highestNonZeroIdx = -1; + for (int i = 0; i < GLONASS_GNAV_HAMMING_CODE_BITS - 1; ++i) // C_Sigma should not be taken into account + { + if (C[i] != 0) + highestNonZeroIdx = i + 1; // 1-based indices + } + + if (shortSumC == 1) + { + // (A2) Only one of the checksums (C1, ..., C7) is equal to 1 and C_Sigma = 1 (all + // information bits are valid and there is an error in one (!) of the check bits. + bits_io[highestNonZeroIdx - 1] = 1 - bits_io[highestNonZeroIdx - 1]; + return true; + } + + if (highestNonZeroIdx == -1) + { + // Error only in parity bit (C_Sigma = 1) + bits_io[GLONASS_GNAV_HAMMING_CODE_BITS - 1] = 1 - bits_io[GLONASS_GNAV_HAMMING_CODE_BITS - 1]; + return true; + } + + int idx = C[GLONASS_GNAV_HAMMING_CODE_BITS - 2]; + for (int i = GLONASS_GNAV_HAMMING_CODE_BITS - 3; i >= 0; --i) + { + idx <<= 1; + idx += C[i]; + } + + int position = idx + GLONASS_GNAV_HAMMING_CODE_BITS - highestNonZeroIdx - 1; + + if (position < GLONASS_GNAV_STRING_BITS) + { + // (B) Error only in a single information bit + bits_io[position] = 1 - bits_io[position]; + return true; + } + } + + // Irrecoverable error in information bits + return false; +} + + bool Glonass_Gnav_Navigation_Message::read_navigation_bool(const std::bitset& bits, const std::vector>& parameter) const { bool value; @@ -238,10 +327,10 @@ int32_t Glonass_Gnav_Navigation_Message::string_decoder(const std::string& frame uint64_t P_1_tmp = 0; // Unpack bytes to bits - const std::bitset string_bits(frame_string); + std::bitset string_bits(frame_string); - // Perform data verification and exit code if error in bit sequence - flag_CRC_test = CRC_test(string_bits); + // Perform data correction and exit code if error in bit sequence is irrecoverable + flag_CRC_test = hamming_correct(string_bits); if (flag_CRC_test == false) { return 0; diff --git a/src/core/system_parameters/glonass_gnav_navigation_message.h b/src/core/system_parameters/glonass_gnav_navigation_message.h index fcad9c79f..7f1dbf163 100644 --- a/src/core/system_parameters/glonass_gnav_navigation_message.h +++ b/src/core/system_parameters/glonass_gnav_navigation_message.h @@ -57,6 +57,12 @@ public: */ bool CRC_test(const std::bitset& bits) const; + /*! + * \brief Check and (if needed and possible) correct information bits for GLONASS GNAV strings + * \param[in,out] bits_io Bits of the string message (information and Hamming codes) + */ + bool hamming_correct(std::bitset& bits_io) const; + /*! * \brief Computes the frame number being decoded given the satellite slot number * \param satellite_slot_number [in] Satellite slot number identifier diff --git a/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc b/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc index 1af57d484..6892a180d 100644 --- a/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc +++ b/src/tests/unit-tests/system-parameters/glonass_gnav_nav_message_test.cc @@ -20,6 +20,9 @@ #include "glonass_gnav_navigation_message.h" #include "gnss_signal_replica.h" +// A valid GLONASS GNAV message string +std::string valid_msg("0001110000000001001101001110100011111011010011001101001101110110010011110011100100011"); + /*! * \brief Testing CRC computation for GLONASS GNAV data bits of a string * \test The provided string was generated with a version of MATLAB GNSS-SDR that @@ -60,6 +63,70 @@ TEST(GlonassGnavNavigationMessageTest, CRCTestFailure) ASSERT_FALSE(test_result); } +/*! + * \brief Testing Hamming code correction method for GLONASS GNAV data. + * \test A single-bit error is introduced into each bit of a valid string + * and the result of error correction is compared to the original string + */ +TEST(GlonassGnavNavigationMessageTest, hamming_correct_1bit) +{ + bool test_result; + std::bitset bits(valid_msg); + const std::bitset bits_original = bits; + + auto gnav_nav_message = Glonass_Gnav_Navigation_Message(); + + test_result = gnav_nav_message.hamming_correct(bits); + + // check correct return value for a valid string + ASSERT_TRUE(test_result); + + // check that a valid string is not being changed + ASSERT_EQ(bits, bits_original); + + for (int i = 0; i < GLONASS_GNAV_STRING_BITS; ++i) + { + bits[i] = 1 - bits[i]; + test_result = gnav_nav_message.hamming_correct(bits); + + // check correct return value for a string with a single bit error + ASSERT_TRUE(test_result); + + // check that a string is restored correctly + ASSERT_EQ(bits, bits_original); + } +} + +/*! + * \brief Testing Hamming code correction method for GLONASS GNAV data. + * \test A two-bit error is introduced into each possible pair of bits of + * a valid string in order to check that the error correction method + * returns correction result as 'false'. + */ +TEST(GlonassGnavNavigationMessageTest, hamming_correct_2bits) +{ + std::bitset bits(valid_msg); + auto gnav_nav_message = Glonass_Gnav_Navigation_Message(); + + for (int i = 0; i < GLONASS_GNAV_STRING_BITS - 1; ++i) + { + bits[i] = 1 - bits[i]; + for (int j = i + 1; j < GLONASS_GNAV_STRING_BITS; ++j) + { + bits[j] = 1 - bits[j]; + std::bitset bits_with_errors = bits; + bool test_result = gnav_nav_message.hamming_correct(bits); + + // check correct return value for a string with 2 wrong bits + ASSERT_FALSE(test_result); + + // check that a string with 2 wrong bits is not being changed + ASSERT_EQ(bits, bits_with_errors); + bits[j] = 1 - bits[j]; + } + bits[i] = 1 - bits[i]; + } +} /*! * \brief Testing string decoding for GLONASS GNAV messages