mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 17:27:21 -05:00
Included error correction on P25 TDULC.
Added a new "heuristics" module for P25 that improves the estimation of the symbol (dibit) that corresponds to a given analog signal value. Added a BER (bit error reate) estimation for P25.
This commit is contained in:
@@ -40,12 +40,12 @@ protected:
|
||||
{
|
||||
DSDGolay24 golay24;
|
||||
|
||||
unsigned int trashed_codeword = golay24.adapt_to_codeword(hex, sgp);
|
||||
unsigned int trashed_codeword = golay24.adapt_to_codeword(hex, 6, sgp);
|
||||
|
||||
//printf("[%s]", hex_to_bin24(trashed_codeword));
|
||||
|
||||
int fixed_errors = 0;
|
||||
int many_errors = golay24.decode(hex, sgp, &fixed_errors); // try to correct bit errors
|
||||
int many_errors = golay24.decode_6(hex, sgp, &fixed_errors); // try to correct bit errors
|
||||
|
||||
/*
|
||||
printf(" -> ");
|
||||
@@ -72,6 +72,18 @@ protected:
|
||||
|
||||
//printf("\n");
|
||||
}
|
||||
|
||||
static void check_encode(char* hex, char* expected_parity)
|
||||
{
|
||||
DSDGolay24 golay24;
|
||||
char parity[12];
|
||||
|
||||
golay24.encode_6(hex, parity);
|
||||
|
||||
for(unsigned int i=0; i<12; i++) {
|
||||
EXPECT_EQ(expected_parity[i], parity[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(Golay24Test, Test1)
|
||||
@@ -136,3 +148,27 @@ TEST_F(Golay24Test, Test7)
|
||||
|
||||
fix_golay24(hex, parity, expected, 2);
|
||||
}
|
||||
|
||||
TEST_F(Golay24Test, Test_encode_1)
|
||||
{
|
||||
char hex[6] = { 1, 0, 1, 0, 1, 0};
|
||||
char expected_parity[12] = { 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1};
|
||||
|
||||
check_encode(hex, expected_parity);
|
||||
}
|
||||
|
||||
TEST_F(Golay24Test, Test_encode_2)
|
||||
{
|
||||
char hex[6] = { 0, 0, 1, 0, 0, 0};
|
||||
char expected_parity[12] = { 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0};
|
||||
|
||||
check_encode(hex, expected_parity);
|
||||
}
|
||||
|
||||
TEST_F(Golay24Test, Test_encode_3)
|
||||
{
|
||||
char hex[6] = { 0, 0, 0, 0, 0, 0};
|
||||
char expected_parity[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
check_encode(hex, expected_parity);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ protected:
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
static void check_hamming(int v, int expected_v, int expected_errors)
|
||||
static void check_decode(int v, int expected_v, int expected_errors)
|
||||
{
|
||||
Hamming_10_6_3 hamming;
|
||||
Hamming_10_6_3_TableImpl hamming_table;
|
||||
@@ -43,17 +43,17 @@ protected:
|
||||
//print_debug(v, output_1, error_count_1);
|
||||
|
||||
if (expected_errors != -1) {
|
||||
EXPECT_THAT(expected_errors, error_count_1);
|
||||
EXPECT_EQ(expected_errors, error_count_1);
|
||||
}
|
||||
EXPECT_THAT(error_count_1, error_count_2);
|
||||
EXPECT_EQ(error_count_1, error_count_2);
|
||||
|
||||
if (expected_v != -1) {
|
||||
EXPECT_THAT(expected_v, output_1);
|
||||
EXPECT_EQ(expected_v, output_1);
|
||||
}
|
||||
EXPECT_THAT(output_1, output_2);
|
||||
EXPECT_EQ(output_1, output_2);
|
||||
}
|
||||
|
||||
static void check_hamming(Hamming_Inteface* hamming, char* hex, char* parity, int expected_errors, char* expected)
|
||||
static void check_decode(Hamming_Inteface* hamming, char* hex, char* parity, int expected_errors, char* expected)
|
||||
{
|
||||
int value = Hamming_10_6_3_TableImpl::convert_hex_parity_to_int(hex, parity);
|
||||
int error_count = hamming->decode(hex, parity);
|
||||
@@ -61,12 +61,34 @@ protected:
|
||||
|
||||
//print_debug(value, fixed, error_count);
|
||||
|
||||
EXPECT_THAT(expected_errors, error_count);
|
||||
EXPECT_EQ(expected_errors, error_count);
|
||||
for (unsigned int i=0; i<6; i++) {
|
||||
EXPECT_THAT(expected[i], hex[i]);
|
||||
EXPECT_EQ(expected[i], hex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_encode(Hamming_Inteface* hamming, int input)
|
||||
{
|
||||
int parity = hamming->encode(input);
|
||||
|
||||
// Check it
|
||||
EXPECT_LT(parity, 16);
|
||||
int v = (input << 4) | parity;
|
||||
int output;
|
||||
int error_count = hamming->decode(v, &output);
|
||||
EXPECT_EQ(error_count, 0);
|
||||
EXPECT_EQ(output, input);
|
||||
}
|
||||
|
||||
static void check_encode(Hamming_Inteface* hamming, char* hex)
|
||||
{
|
||||
char parity[4];
|
||||
hamming->encode(hex, parity);
|
||||
|
||||
// Check it
|
||||
int error_count = hamming->decode(hex, parity);
|
||||
EXPECT_EQ(error_count, 0);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(HammingTest, Test1)
|
||||
@@ -74,7 +96,7 @@ TEST_F(HammingTest, Test1)
|
||||
// OK
|
||||
std::bitset<10> value(std::string("1010100110"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 0);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 0);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test2)
|
||||
@@ -82,7 +104,7 @@ TEST_F(HammingTest, Test2)
|
||||
// Error on parity bit 0 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("1010100111"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test3)
|
||||
@@ -90,7 +112,7 @@ TEST_F(HammingTest, Test3)
|
||||
// Error on parity bit 1 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("1010100100"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test4)
|
||||
@@ -98,7 +120,7 @@ TEST_F(HammingTest, Test4)
|
||||
// Error on parity bit 2 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("1010100010"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test5)
|
||||
@@ -106,7 +128,7 @@ TEST_F(HammingTest, Test5)
|
||||
// Error on parity bit 3 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("1010101110"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test6)
|
||||
@@ -114,7 +136,7 @@ TEST_F(HammingTest, Test6)
|
||||
// Error on bit 4 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("1010110110"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test7)
|
||||
@@ -122,7 +144,7 @@ TEST_F(HammingTest, Test7)
|
||||
// Error on bit 5 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("1010000110"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test8)
|
||||
@@ -130,7 +152,7 @@ TEST_F(HammingTest, Test8)
|
||||
// Error on bit 6 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("1011100110"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test9)
|
||||
@@ -138,7 +160,7 @@ TEST_F(HammingTest, Test9)
|
||||
// Error on bit 7 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("1000100110"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test10)
|
||||
@@ -146,7 +168,7 @@ TEST_F(HammingTest, Test10)
|
||||
// Error on bit 8 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("1110100110"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test11)
|
||||
@@ -154,7 +176,7 @@ TEST_F(HammingTest, Test11)
|
||||
// Error on bit 9 (9 is the left-most and 0 is the right-most)
|
||||
std::bitset<10> value(std::string("0010100110"));
|
||||
std::bitset< 6> expected(std::string("101010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test12)
|
||||
@@ -162,7 +184,7 @@ TEST_F(HammingTest, Test12)
|
||||
// Two errors
|
||||
std::bitset<10> value(std::string("0010100111"));
|
||||
std::bitset< 6> expected(std::string("001010"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 2);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 2);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test13)
|
||||
@@ -170,7 +192,7 @@ TEST_F(HammingTest, Test13)
|
||||
// Two errors, in this case they go undetected, thinks it's a parity error
|
||||
std::bitset<10> value(std::string("1011000110"));
|
||||
std::bitset< 6> expected(std::string("101100"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 1);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test14)
|
||||
@@ -178,14 +200,14 @@ TEST_F(HammingTest, Test14)
|
||||
// OK
|
||||
std::bitset<10> value(std::string("0001000111"));
|
||||
std::bitset< 6> expected(std::string("000100"));
|
||||
check_hamming((int)value.to_ulong(), (int)expected.to_ulong(), 0);
|
||||
check_decode((int)value.to_ulong(), (int)expected.to_ulong(), 0);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, TestEveryValue)
|
||||
{
|
||||
// Test every posible value
|
||||
for (int v=0; v<1023; v++) {
|
||||
check_hamming(v, -1, -1);
|
||||
check_decode(v, -1, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,10 +218,10 @@ TEST_F(HammingTest, Test_hex_parity_interface_no_errors)
|
||||
char parity[4] = {1,0,1,1};
|
||||
|
||||
Hamming_10_6_3 hamming;
|
||||
check_hamming(&hamming, hex, parity, 0, fixed);
|
||||
check_decode(&hamming, hex, parity, 0, fixed);
|
||||
|
||||
Hamming_10_6_3_TableImpl hamming_table;
|
||||
check_hamming(&hamming_table, hex, parity, 0, fixed);
|
||||
check_decode(&hamming_table, hex, parity, 0, fixed);
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test_hex_parity_interface_one_error_1)
|
||||
@@ -210,11 +232,11 @@ TEST_F(HammingTest, Test_hex_parity_interface_one_error_1)
|
||||
char parity[4] = {1,0,1,1};
|
||||
|
||||
Hamming_10_6_3 hamming;
|
||||
check_hamming(&hamming, hex_1, parity, 1, fixed);
|
||||
check_decode(&hamming, hex_1, parity, 1, fixed);
|
||||
// hex is modified in place
|
||||
|
||||
Hamming_10_6_3_TableImpl hamming_table;
|
||||
check_hamming(&hamming_table, hex_2, parity, 1, fixed);
|
||||
check_decode(&hamming_table, hex_2, parity, 1, fixed);
|
||||
// hex is modified in place
|
||||
}
|
||||
|
||||
@@ -226,11 +248,11 @@ TEST_F(HammingTest, Test_hex_parity_interface_one_error_2)
|
||||
char parity[4] = {0,0,0,0};
|
||||
|
||||
Hamming_10_6_3 hamming;
|
||||
check_hamming(&hamming, hex_1, parity, 1, fixed);
|
||||
check_decode(&hamming, hex_1, parity, 1, fixed);
|
||||
// hex is modified in place
|
||||
|
||||
Hamming_10_6_3_TableImpl hamming_table;
|
||||
check_hamming(&hamming_table, hex_2, parity, 1, fixed);
|
||||
check_decode(&hamming_table, hex_2, parity, 1, fixed);
|
||||
// hex is modified in place
|
||||
}
|
||||
|
||||
@@ -242,10 +264,41 @@ TEST_F(HammingTest, Test_hex_parity_interface_one_error_3)
|
||||
char parity[4] = {0,0,0,0};
|
||||
|
||||
Hamming_10_6_3 hamming;
|
||||
check_hamming(&hamming, hex_1, parity, 1, fixed);
|
||||
check_decode(&hamming, hex_1, parity, 1, fixed);
|
||||
// hex is modified in place
|
||||
|
||||
Hamming_10_6_3_TableImpl hamming_table;
|
||||
check_hamming(&hamming_table, hex_2, parity, 1, fixed);
|
||||
check_decode(&hamming_table, hex_2, parity, 1, fixed);
|
||||
// hex is modified in place
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test_encoding_1)
|
||||
{
|
||||
Hamming_10_6_3 hamming;
|
||||
Hamming_10_6_3_TableImpl hamming_table;
|
||||
|
||||
for (int i=0; i<64; i++) {
|
||||
check_encode(&hamming, i);
|
||||
check_encode(&hamming_table, i);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(HammingTest, Test_encoding_char)
|
||||
{
|
||||
Hamming_10_6_3 hamming;
|
||||
Hamming_10_6_3_TableImpl hamming_table;
|
||||
|
||||
char hex[6];
|
||||
|
||||
for (int i=0; i<64; i++) {
|
||||
|
||||
// Convert i to char array
|
||||
int input = i;
|
||||
for (int j=5; j>=0; j--) {
|
||||
hex[j] = input & 1;
|
||||
input >>= 1;
|
||||
}
|
||||
check_encode(&hamming, hex);
|
||||
check_encode(&hamming_table, hex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,19 +7,9 @@
|
||||
|
||||
#include "ReedSolomon.hpp"
|
||||
|
||||
static void byte_to_binary(char* b, int x)
|
||||
{
|
||||
int z, i;
|
||||
|
||||
for (z = 32, i=0; z > 0; z >>= 1, i++) {
|
||||
b[i] = ((x & z) != 0) ? 'X' : ' ';
|
||||
}
|
||||
b[6] = 0;
|
||||
}
|
||||
|
||||
TEST(ReedSolomonTest, Test1)
|
||||
{
|
||||
ReedSolomon_63_47_17 rs;
|
||||
ReedSolomon_63<8> rs;
|
||||
int recd[63] = {};
|
||||
int expected[63] = {};
|
||||
int output[63];
|
||||
@@ -90,3 +80,68 @@ TEST(ReedSolomonTest, Test1)
|
||||
|
||||
EXPECT_THAT(expected, testing::ElementsAreArray(output, 63));
|
||||
}
|
||||
|
||||
static void generate_random_bits(char* p, unsigned int count)
|
||||
{
|
||||
for (unsigned int i=0; i<count; i++) {
|
||||
p[i] = (rand() > RAND_MAX/2)? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ReedSolomonTest, Test_encode_24_12_13)
|
||||
{
|
||||
char hex[12*6];
|
||||
char parity[12*6];
|
||||
|
||||
DSDReedSolomon_24_12_13 rs;
|
||||
|
||||
for (unsigned i=0; i<1000; i++) {
|
||||
generate_random_bits((char*)hex, 12*6);
|
||||
|
||||
// Make a copy
|
||||
char expected[12*6];
|
||||
|
||||
memcpy(expected, hex, 12*6);
|
||||
|
||||
|
||||
|
||||
// Encode
|
||||
rs.encode(hex, parity);
|
||||
|
||||
// Decode back, should have the same result and no errors
|
||||
int irrecoverable_errors = rs.decode(hex, parity);
|
||||
|
||||
EXPECT_EQ(0, irrecoverable_errors);
|
||||
|
||||
EXPECT_THAT(expected, testing::ElementsAreArray(hex, 12*6));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ReedSolomonTest, Test_encode_24_16_9)
|
||||
{
|
||||
char hex[16*6];
|
||||
char parity[8*6];
|
||||
|
||||
DSDReedSolomon_24_16_9 rs;
|
||||
|
||||
for (unsigned i=0; i<1000; i++) {
|
||||
generate_random_bits((char*)hex, 16*6);
|
||||
|
||||
// Make a copy
|
||||
char expected[16*6];
|
||||
|
||||
memcpy(expected, hex, 16*6);
|
||||
|
||||
|
||||
|
||||
// Encode
|
||||
rs.encode(hex, parity);
|
||||
|
||||
// Decode back, should have the same result and no errors
|
||||
int irrecoverable_errors = rs.decode(hex, parity);
|
||||
|
||||
EXPECT_EQ(0, irrecoverable_errors);
|
||||
|
||||
EXPECT_THAT(expected, testing::ElementsAreArray(hex, 16*6));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user