diff --git a/CMakeLists.txt b/CMakeLists.txt index 19e72db17..83b451918 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -494,6 +494,7 @@ set (qra_CSRCS lib/qra/qracodes/qra12_63_64_irr_b.c lib/qra/qracodes/qra13_64_64_irr_e.c lib/qra/qracodes/qracodes.c + lib/qra/qracodes/normrnd.c ) set (wsjt_CSRCS diff --git a/lib/qra/qra64/fadampgauss.c b/lib/qra/qra64/fadampgauss.c new file mode 100644 index 000000000..36093260a --- /dev/null +++ b/lib/qra/qra64/fadampgauss.c @@ -0,0 +1,327 @@ +/* +fadampgauss.c +Gaussian fading tables for QRA64 modes + +(c) 2016 - Nico Palermo, IV3NWV + +This file is part of the qracodes project, a Forward Error Control +encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +------------------------------------------------------------------------------- + + qracodes 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. + qracodes 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 qracodes source distribution. + If not, see . + +----------------------------------------------------------------------------- + +*/ +static const int hlen_tab_gauss[64] = { + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 8, 8, 9, 10, + 10, 11, 12, 13, 14, 15, 17, 18, + 19, 21, 23, 25, 27, 29, 32, 34, + 37, 41, 44, 48, 52, 57, 62, 65 +}; +static const float hgauss1[2] = { +0.1722f, 0.9540f +}; +static const float hgauss2[2] = { +0.1870f, 0.9463f +}; +static const float hgauss3[2] = { +0.2028f, 0.9374f +}; +static const float hgauss4[2] = { +0.2198f, 0.9273f +}; +static const float hgauss5[2] = { +0.2378f, 0.9158f +}; +static const float hgauss6[2] = { +0.2569f, 0.9030f +}; +static const float hgauss7[2] = { +0.2769f, 0.8887f +}; +static const float hgauss8[2] = { +0.2977f, 0.8730f +}; +static const float hgauss9[2] = { +0.3190f, 0.8559f +}; +static const float hgauss10[2] = { +0.3405f, 0.8374f +}; +static const float hgauss11[2] = { +0.3619f, 0.8177f +}; +static const float hgauss12[2] = { +0.3828f, 0.7970f +}; +static const float hgauss13[2] = { +0.4026f, 0.7755f +}; +static const float hgauss14[2] = { +0.4208f, 0.7533f +}; +static const float hgauss15[2] = { +0.4371f, 0.7307f +}; +static const float hgauss16[2] = { +0.4510f, 0.7078f +}; +static const float hgauss17[3] = { +0.1729f, 0.4621f, 0.6849f +}; +static const float hgauss18[3] = { +0.1920f, 0.4704f, 0.6620f +}; +static const float hgauss19[3] = { +0.2131f, 0.4757f, 0.6393f +}; +static const float hgauss20[3] = { +0.2350f, 0.4782f, 0.6170f +}; +static const float hgauss21[3] = { +0.2565f, 0.4779f, 0.5949f +}; +static const float hgauss22[3] = { +0.2767f, 0.4752f, 0.5733f +}; +static const float hgauss23[3] = { +0.2948f, 0.4703f, 0.5522f +}; +static const float hgauss24[3] = { +0.3102f, 0.4635f, 0.5316f +}; +static const float hgauss25[4] = { +0.1874f, 0.3226f, 0.4551f, 0.5115f +}; +static const float hgauss26[4] = { +0.2071f, 0.3319f, 0.4454f, 0.4919f +}; +static const float hgauss27[4] = { +0.2253f, 0.3383f, 0.4347f, 0.4730f +}; +static const float hgauss28[4] = { +0.2413f, 0.3419f, 0.4232f, 0.4546f +}; +static const float hgauss29[5] = { +0.1701f, 0.2546f, 0.3429f, 0.4110f, 0.4368f +}; +static const float hgauss30[5] = { +0.1874f, 0.2652f, 0.3417f, 0.3985f, 0.4196f +}; +static const float hgauss31[5] = { +0.2028f, 0.2729f, 0.3386f, 0.3857f, 0.4029f +}; +static const float hgauss32[6] = { +0.1569f, 0.2158f, 0.2780f, 0.3338f, 0.3728f, 0.3868f +}; +static const float hgauss33[6] = { +0.1723f, 0.2263f, 0.2807f, 0.3278f, 0.3599f, 0.3713f +}; +static const float hgauss34[6] = { +0.1857f, 0.2343f, 0.2812f, 0.3207f, 0.3471f, 0.3564f +}; +static const float hgauss35[7] = { +0.1550f, 0.1968f, 0.2398f, 0.2799f, 0.3128f, 0.3344f, 0.3420f +}; +static const float hgauss36[7] = { +0.1677f, 0.2055f, 0.2430f, 0.2770f, 0.3043f, 0.3220f, 0.3281f +}; +static const float hgauss37[8] = { +0.1456f, 0.1783f, 0.2118f, 0.2442f, 0.2728f, 0.2953f, 0.3098f, 0.3147f +}; +static const float hgauss38[8] = { +0.1572f, 0.1866f, 0.2160f, 0.2436f, 0.2675f, 0.2861f, 0.2979f, 0.3019f +}; +static const float hgauss39[9] = { +0.1410f, 0.1667f, 0.1928f, 0.2182f, 0.2416f, 0.2615f, 0.2767f, 0.2863f, +0.2895f +}; +static const float hgauss40[10] = { +0.1288f, 0.1511f, 0.1741f, 0.1970f, 0.2187f, 0.2383f, 0.2547f, 0.2672f, +0.2750f, 0.2776f +}; +static const float hgauss41[10] = { +0.1391f, 0.1592f, 0.1795f, 0.1992f, 0.2176f, 0.2340f, 0.2476f, 0.2578f, +0.2641f, 0.2662f +}; +static const float hgauss42[11] = { +0.1298f, 0.1475f, 0.1654f, 0.1830f, 0.1999f, 0.2153f, 0.2289f, 0.2401f, +0.2484f, 0.2535f, 0.2552f +}; +static const float hgauss43[12] = { +0.1227f, 0.1382f, 0.1540f, 0.1696f, 0.1848f, 0.1991f, 0.2120f, 0.2232f, +0.2324f, 0.2391f, 0.2433f, 0.2447f +}; +static const float hgauss44[13] = { +0.1173f, 0.1309f, 0.1448f, 0.1587f, 0.1722f, 0.1851f, 0.1971f, 0.2078f, +0.2171f, 0.2246f, 0.2301f, 0.2334f, 0.2346f +}; +static const float hgauss45[14] = { +0.1132f, 0.1253f, 0.1375f, 0.1497f, 0.1617f, 0.1732f, 0.1841f, 0.1941f, +0.2030f, 0.2106f, 0.2167f, 0.2212f, 0.2239f, 0.2248f +}; +static const float hgauss46[15] = { +0.1102f, 0.1208f, 0.1315f, 0.1423f, 0.1529f, 0.1632f, 0.1730f, 0.1821f, +0.1904f, 0.1978f, 0.2040f, 0.2089f, 0.2126f, 0.2148f, 0.2155f +}; +static const float hgauss47[17] = { +0.0987f, 0.1079f, 0.1173f, 0.1267f, 0.1362f, 0.1455f, 0.1546f, 0.1634f, +0.1716f, 0.1792f, 0.1861f, 0.1921f, 0.1972f, 0.2012f, 0.2042f, 0.2059f, +0.2065f +}; +static const float hgauss48[18] = { +0.0980f, 0.1062f, 0.1145f, 0.1228f, 0.1311f, 0.1393f, 0.1474f, 0.1551f, +0.1624f, 0.1693f, 0.1756f, 0.1813f, 0.1862f, 0.1904f, 0.1936f, 0.1960f, +0.1975f, 0.1979f +}; +static const float hgauss49[19] = { +0.0976f, 0.1049f, 0.1122f, 0.1195f, 0.1268f, 0.1341f, 0.1411f, 0.1479f, +0.1544f, 0.1606f, 0.1663f, 0.1715f, 0.1762f, 0.1802f, 0.1836f, 0.1862f, +0.1881f, 0.1893f, 0.1897f +}; +static const float hgauss50[21] = { +0.0911f, 0.0974f, 0.1038f, 0.1103f, 0.1167f, 0.1232f, 0.1295f, 0.1357f, +0.1417f, 0.1474f, 0.1529f, 0.1580f, 0.1627f, 0.1670f, 0.1708f, 0.1741f, +0.1768f, 0.1790f, 0.1805f, 0.1815f, 0.1818f +}; +static const float hgauss51[23] = { +0.0861f, 0.0916f, 0.0973f, 0.1029f, 0.1086f, 0.1143f, 0.1199f, 0.1255f, +0.1309f, 0.1361f, 0.1412f, 0.1460f, 0.1505f, 0.1548f, 0.1587f, 0.1622f, +0.1653f, 0.1679f, 0.1702f, 0.1719f, 0.1732f, 0.1739f, 0.1742f +}; +static const float hgauss52[25] = { +0.0823f, 0.0872f, 0.0922f, 0.0971f, 0.1021f, 0.1071f, 0.1121f, 0.1170f, +0.1219f, 0.1266f, 0.1312f, 0.1356f, 0.1398f, 0.1438f, 0.1476f, 0.1511f, +0.1543f, 0.1572f, 0.1597f, 0.1619f, 0.1637f, 0.1651f, 0.1661f, 0.1667f, +0.1669f +}; +static const float hgauss53[27] = { +0.0795f, 0.0838f, 0.0882f, 0.0925f, 0.0969f, 0.1013f, 0.1057f, 0.1101f, +0.1144f, 0.1186f, 0.1227f, 0.1267f, 0.1306f, 0.1343f, 0.1378f, 0.1411f, +0.1442f, 0.1471f, 0.1497f, 0.1520f, 0.1541f, 0.1558f, 0.1573f, 0.1585f, +0.1593f, 0.1598f, 0.1599f +}; +static const float hgauss54[29] = { +0.0774f, 0.0812f, 0.0850f, 0.0889f, 0.0928f, 0.0966f, 0.1005f, 0.1043f, +0.1081f, 0.1119f, 0.1155f, 0.1191f, 0.1226f, 0.1259f, 0.1292f, 0.1322f, +0.1351f, 0.1379f, 0.1404f, 0.1428f, 0.1449f, 0.1468f, 0.1485f, 0.1499f, +0.1511f, 0.1520f, 0.1527f, 0.1531f, 0.1532f +}; +static const float hgauss55[32] = { +0.0726f, 0.0759f, 0.0792f, 0.0826f, 0.0860f, 0.0894f, 0.0928f, 0.0962f, +0.0996f, 0.1029f, 0.1062f, 0.1094f, 0.1126f, 0.1157f, 0.1187f, 0.1217f, +0.1245f, 0.1271f, 0.1297f, 0.1321f, 0.1343f, 0.1364f, 0.1383f, 0.1401f, +0.1416f, 0.1430f, 0.1442f, 0.1451f, 0.1459f, 0.1464f, 0.1467f, 0.1468f +}; +static const float hgauss56[34] = { +0.0718f, 0.0747f, 0.0777f, 0.0807f, 0.0836f, 0.0866f, 0.0896f, 0.0926f, +0.0956f, 0.0985f, 0.1014f, 0.1043f, 0.1071f, 0.1098f, 0.1125f, 0.1151f, +0.1176f, 0.1201f, 0.1224f, 0.1246f, 0.1267f, 0.1287f, 0.1305f, 0.1322f, +0.1338f, 0.1352f, 0.1365f, 0.1376f, 0.1385f, 0.1393f, 0.1399f, 0.1403f, +0.1406f, 0.1407f +}; +static const float hgauss57[37] = { +0.0687f, 0.0712f, 0.0738f, 0.0765f, 0.0791f, 0.0817f, 0.0843f, 0.0870f, +0.0896f, 0.0922f, 0.0948f, 0.0973f, 0.0998f, 0.1023f, 0.1047f, 0.1071f, +0.1094f, 0.1117f, 0.1138f, 0.1159f, 0.1179f, 0.1199f, 0.1217f, 0.1234f, +0.1250f, 0.1265f, 0.1279f, 0.1292f, 0.1304f, 0.1314f, 0.1323f, 0.1330f, +0.1337f, 0.1341f, 0.1345f, 0.1347f, 0.1348f +}; +static const float hgauss58[41] = { +0.0640f, 0.0663f, 0.0686f, 0.0709f, 0.0732f, 0.0755f, 0.0778f, 0.0801f, +0.0824f, 0.0847f, 0.0870f, 0.0893f, 0.0915f, 0.0938f, 0.0960f, 0.0982f, +0.1003f, 0.1024f, 0.1044f, 0.1064f, 0.1083f, 0.1102f, 0.1120f, 0.1137f, +0.1154f, 0.1170f, 0.1185f, 0.1199f, 0.1212f, 0.1224f, 0.1236f, 0.1246f, +0.1255f, 0.1264f, 0.1271f, 0.1277f, 0.1282f, 0.1286f, 0.1289f, 0.1291f, +0.1291f +}; +static const float hgauss59[44] = { +0.0625f, 0.0645f, 0.0665f, 0.0685f, 0.0705f, 0.0726f, 0.0746f, 0.0767f, +0.0787f, 0.0807f, 0.0827f, 0.0847f, 0.0867f, 0.0887f, 0.0907f, 0.0926f, +0.0945f, 0.0964f, 0.0982f, 0.1000f, 0.1017f, 0.1034f, 0.1051f, 0.1067f, +0.1083f, 0.1097f, 0.1112f, 0.1125f, 0.1138f, 0.1151f, 0.1162f, 0.1173f, +0.1183f, 0.1192f, 0.1201f, 0.1208f, 0.1215f, 0.1221f, 0.1226f, 0.1230f, +0.1233f, 0.1235f, 0.1237f, 0.1237f +}; +static const float hgauss60[48] = { +0.0596f, 0.0614f, 0.0631f, 0.0649f, 0.0667f, 0.0685f, 0.0703f, 0.0721f, +0.0738f, 0.0756f, 0.0774f, 0.0792f, 0.0810f, 0.0827f, 0.0845f, 0.0862f, +0.0879f, 0.0896f, 0.0912f, 0.0929f, 0.0945f, 0.0960f, 0.0976f, 0.0991f, +0.1005f, 0.1019f, 0.1033f, 0.1046f, 0.1059f, 0.1071f, 0.1083f, 0.1094f, +0.1105f, 0.1115f, 0.1124f, 0.1133f, 0.1141f, 0.1149f, 0.1156f, 0.1162f, +0.1167f, 0.1172f, 0.1176f, 0.1179f, 0.1182f, 0.1184f, 0.1185f, 0.1185f +}; +static const float hgauss61[52] = { +0.0575f, 0.0590f, 0.0606f, 0.0621f, 0.0637f, 0.0652f, 0.0668f, 0.0684f, +0.0700f, 0.0715f, 0.0731f, 0.0747f, 0.0762f, 0.0778f, 0.0793f, 0.0809f, +0.0824f, 0.0839f, 0.0854f, 0.0868f, 0.0883f, 0.0897f, 0.0911f, 0.0925f, +0.0938f, 0.0951f, 0.0964f, 0.0976f, 0.0988f, 0.1000f, 0.1011f, 0.1022f, +0.1033f, 0.1043f, 0.1053f, 0.1062f, 0.1070f, 0.1079f, 0.1086f, 0.1093f, +0.1100f, 0.1106f, 0.1112f, 0.1116f, 0.1121f, 0.1125f, 0.1128f, 0.1131f, +0.1133f, 0.1134f, 0.1135f, 0.1135f +}; +static const float hgauss62[57] = { +0.0545f, 0.0558f, 0.0572f, 0.0586f, 0.0599f, 0.0613f, 0.0627f, 0.0641f, +0.0654f, 0.0668f, 0.0682f, 0.0696f, 0.0710f, 0.0723f, 0.0737f, 0.0751f, +0.0764f, 0.0778f, 0.0791f, 0.0804f, 0.0817f, 0.0830f, 0.0843f, 0.0855f, +0.0868f, 0.0880f, 0.0892f, 0.0903f, 0.0915f, 0.0926f, 0.0937f, 0.0948f, +0.0958f, 0.0968f, 0.0977f, 0.0987f, 0.0996f, 0.1004f, 0.1013f, 0.1020f, +0.1028f, 0.1035f, 0.1042f, 0.1048f, 0.1054f, 0.1059f, 0.1064f, 0.1068f, +0.1072f, 0.1076f, 0.1079f, 0.1082f, 0.1084f, 0.1085f, 0.1087f, 0.1087f, +0.1088f +}; +static const float hgauss63[62] = { +0.0522f, 0.0534f, 0.0546f, 0.0558f, 0.0570f, 0.0582f, 0.0594f, 0.0606f, +0.0619f, 0.0631f, 0.0643f, 0.0655f, 0.0667f, 0.0679f, 0.0691f, 0.0703f, +0.0715f, 0.0727f, 0.0739f, 0.0751f, 0.0763f, 0.0774f, 0.0786f, 0.0797f, +0.0808f, 0.0819f, 0.0830f, 0.0841f, 0.0851f, 0.0861f, 0.0872f, 0.0882f, +0.0891f, 0.0901f, 0.0910f, 0.0919f, 0.0928f, 0.0936f, 0.0944f, 0.0952f, +0.0960f, 0.0967f, 0.0974f, 0.0981f, 0.0987f, 0.0994f, 0.0999f, 0.1005f, +0.1010f, 0.1014f, 0.1019f, 0.1023f, 0.1026f, 0.1030f, 0.1033f, 0.1035f, +0.1037f, 0.1039f, 0.1040f, 0.1041f, 0.1042f, 0.1042f +}; +static const float hgauss64[65] = { +0.0526f, 0.0537f, 0.0547f, 0.0558f, 0.0569f, 0.0579f, 0.0590f, 0.0601f, +0.0611f, 0.0622f, 0.0633f, 0.0643f, 0.0654f, 0.0665f, 0.0675f, 0.0686f, +0.0696f, 0.0707f, 0.0717f, 0.0727f, 0.0737f, 0.0748f, 0.0758f, 0.0767f, +0.0777f, 0.0787f, 0.0796f, 0.0806f, 0.0815f, 0.0824f, 0.0833f, 0.0842f, +0.0850f, 0.0859f, 0.0867f, 0.0875f, 0.0883f, 0.0891f, 0.0898f, 0.0905f, +0.0912f, 0.0919f, 0.0925f, 0.0932f, 0.0938f, 0.0943f, 0.0949f, 0.0954f, +0.0959f, 0.0964f, 0.0968f, 0.0972f, 0.0976f, 0.0979f, 0.0983f, 0.0986f, +0.0988f, 0.0991f, 0.0993f, 0.0994f, 0.0996f, 0.0997f, 0.0998f, 0.0998f, +0.0998f +}; +static const float *hptr_tab_gauss[64] = { +hgauss1, hgauss2, hgauss3, hgauss4, +hgauss5, hgauss6, hgauss7, hgauss8, +hgauss9, hgauss10, hgauss11, hgauss12, +hgauss13, hgauss14, hgauss15, hgauss16, +hgauss17, hgauss18, hgauss19, hgauss20, +hgauss21, hgauss22, hgauss23, hgauss24, +hgauss25, hgauss26, hgauss27, hgauss28, +hgauss29, hgauss30, hgauss31, hgauss32, +hgauss33, hgauss34, hgauss35, hgauss36, +hgauss37, hgauss38, hgauss39, hgauss40, +hgauss41, hgauss42, hgauss43, hgauss44, +hgauss45, hgauss46, hgauss47, hgauss48, +hgauss49, hgauss50, hgauss51, hgauss52, +hgauss53, hgauss54, hgauss55, hgauss56, +hgauss57, hgauss58, hgauss59, hgauss60, +hgauss61, hgauss62, hgauss63, hgauss64 +}; diff --git a/lib/qra/qra64/fadamplorentz.c b/lib/qra/qra64/fadamplorentz.c new file mode 100644 index 000000000..d57312d3c --- /dev/null +++ b/lib/qra/qra64/fadamplorentz.c @@ -0,0 +1,329 @@ +/* +fadamplorentz.c +Lorentz fading tables for QRA64 modes + +(c) 2016 - Nico Palermo, IV3NWV + +This file is part of the qracodes project, a Forward Error Control +encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +------------------------------------------------------------------------------- + + qracodes 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. + qracodes 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 qracodes source distribution. + If not, see . + +----------------------------------------------------------------------------- +*/ + +static const int hlen_tab_lorentz[64] = { + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 3, 4, 4, 4, + 4, 4, 5, 5, 5, 5, 6, 6, + 7, 7, 7, 8, 8, 9, 10, 10, + 11, 12, 13, 14, 15, 16, 17, 19, + 20, 22, 23, 25, 27, 30, 32, 35, + 38, 41, 45, 49, 53, 57, 62, 65 +}; +static const float hlorentz1[2] = { +0.1464f, 0.9543f +}; +static const float hlorentz2[2] = { +0.1563f, 0.9503f +}; +static const float hlorentz3[2] = { +0.1672f, 0.9461f +}; +static const float hlorentz4[2] = { +0.1773f, 0.9415f +}; +static const float hlorentz5[2] = { +0.1868f, 0.9367f +}; +static const float hlorentz6[2] = { +0.1970f, 0.9314f +}; +static const float hlorentz7[2] = { +0.2063f, 0.9258f +}; +static const float hlorentz8[2] = { +0.2151f, 0.9197f +}; +static const float hlorentz9[2] = { +0.2236f, 0.9132f +}; +static const float hlorentz10[2] = { +0.2320f, 0.9061f +}; +static const float hlorentz11[2] = { +0.2406f, 0.8986f +}; +static const float hlorentz12[2] = { +0.2494f, 0.8905f +}; +static const float hlorentz13[2] = { +0.2584f, 0.8819f +}; +static const float hlorentz14[2] = { +0.2674f, 0.8727f +}; +static const float hlorentz15[3] = { +0.1400f, 0.2765f, 0.8629f +}; +static const float hlorentz16[3] = { +0.1451f, 0.2857f, 0.8525f +}; +static const float hlorentz17[3] = { +0.1504f, 0.2949f, 0.8414f +}; +static const float hlorentz18[3] = { +0.1557f, 0.3041f, 0.8298f +}; +static const float hlorentz19[3] = { +0.1611f, 0.3133f, 0.8174f +}; +static const float hlorentz20[3] = { +0.1666f, 0.3223f, 0.8045f +}; +static const float hlorentz21[3] = { +0.1721f, 0.3312f, 0.7909f +}; +static const float hlorentz22[4] = { +0.1195f, 0.1778f, 0.3399f, 0.7766f +}; +static const float hlorentz23[4] = { +0.1235f, 0.1835f, 0.3483f, 0.7618f +}; +static const float hlorentz24[4] = { +0.1277f, 0.1893f, 0.3564f, 0.7463f +}; +static const float hlorentz25[4] = { +0.1319f, 0.1952f, 0.3641f, 0.7303f +}; +static const float hlorentz26[4] = { +0.1362f, 0.2011f, 0.3712f, 0.7138f +}; +static const float hlorentz27[5] = { +0.1062f, 0.1407f, 0.2071f, 0.3779f, 0.6967f +}; +static const float hlorentz28[5] = { +0.1097f, 0.1452f, 0.2132f, 0.3839f, 0.6793f +}; +static const float hlorentz29[5] = { +0.1134f, 0.1499f, 0.2193f, 0.3891f, 0.6615f +}; +static const float hlorentz30[5] = { +0.1172f, 0.1546f, 0.2254f, 0.3936f, 0.6434f +}; +static const float hlorentz31[6] = { +0.0974f, 0.1211f, 0.1595f, 0.2314f, 0.3973f, 0.6251f +}; +static const float hlorentz32[6] = { +0.1007f, 0.1251f, 0.1645f, 0.2374f, 0.4000f, 0.6066f +}; +static const float hlorentz33[7] = { +0.0872f, 0.1042f, 0.1292f, 0.1695f, 0.2434f, 0.4017f, 0.5880f +}; +static const float hlorentz34[7] = { +0.0902f, 0.1077f, 0.1335f, 0.1747f, 0.2491f, 0.4025f, 0.5694f +}; +static const float hlorentz35[7] = { +0.0934f, 0.1114f, 0.1379f, 0.1799f, 0.2547f, 0.4022f, 0.5509f +}; +static const float hlorentz36[8] = { +0.0832f, 0.0967f, 0.1152f, 0.1423f, 0.1851f, 0.2600f, 0.4008f, 0.5325f +}; +static const float hlorentz37[8] = { +0.0862f, 0.1001f, 0.1192f, 0.1469f, 0.1903f, 0.2649f, 0.3985f, 0.5143f +}; +static const float hlorentz38[9] = { +0.0784f, 0.0893f, 0.1036f, 0.1232f, 0.1515f, 0.1955f, 0.2694f, 0.3950f, +0.4964f +}; +static const float hlorentz39[10] = { +0.0724f, 0.0813f, 0.0925f, 0.1072f, 0.1273f, 0.1562f, 0.2005f, 0.2733f, +0.3906f, 0.4787f +}; +static const float hlorentz40[10] = { +0.0751f, 0.0842f, 0.0958f, 0.1109f, 0.1315f, 0.1609f, 0.2054f, 0.2767f, +0.3853f, 0.4614f +}; +static const float hlorentz41[11] = { +0.0703f, 0.0779f, 0.0873f, 0.0992f, 0.1148f, 0.1358f, 0.1656f, 0.2101f, +0.2794f, 0.3790f, 0.4444f +}; +static const float hlorentz42[12] = { +0.0665f, 0.0730f, 0.0808f, 0.0905f, 0.1027f, 0.1187f, 0.1401f, 0.1702f, +0.2145f, 0.2813f, 0.3720f, 0.4278f +}; +static const float hlorentz43[13] = { +0.0634f, 0.0690f, 0.0757f, 0.0838f, 0.0938f, 0.1063f, 0.1226f, 0.1444f, +0.1747f, 0.2185f, 0.2824f, 0.3643f, 0.4117f +}; +static const float hlorentz44[14] = { +0.0609f, 0.0658f, 0.0716f, 0.0785f, 0.0869f, 0.0971f, 0.1100f, 0.1266f, +0.1487f, 0.1791f, 0.2220f, 0.2826f, 0.3559f, 0.3960f +}; +static const float hlorentz45[15] = { +0.0588f, 0.0632f, 0.0683f, 0.0743f, 0.0814f, 0.0900f, 0.1005f, 0.1137f, +0.1306f, 0.1529f, 0.1831f, 0.2250f, 0.2820f, 0.3470f, 0.3808f +}; +static const float hlorentz46[16] = { +0.0571f, 0.0611f, 0.0657f, 0.0709f, 0.0771f, 0.0844f, 0.0932f, 0.1040f, +0.1175f, 0.1346f, 0.1570f, 0.1869f, 0.2274f, 0.2804f, 0.3377f, 0.3660f +}; +static const float hlorentz47[17] = { +0.0557f, 0.0594f, 0.0635f, 0.0682f, 0.0736f, 0.0800f, 0.0875f, 0.0965f, +0.1076f, 0.1212f, 0.1385f, 0.1609f, 0.1903f, 0.2292f, 0.2781f, 0.3281f, +0.3517f +}; +static const float hlorentz48[19] = { +0.0516f, 0.0546f, 0.0579f, 0.0617f, 0.0659f, 0.0708f, 0.0764f, 0.0829f, +0.0906f, 0.0999f, 0.1111f, 0.1249f, 0.1423f, 0.1645f, 0.1933f, 0.2302f, +0.2748f, 0.3182f, 0.3379f +}; +static const float hlorentz49[20] = { +0.0509f, 0.0537f, 0.0567f, 0.0602f, 0.0640f, 0.0684f, 0.0734f, 0.0792f, +0.0859f, 0.0938f, 0.1032f, 0.1146f, 0.1286f, 0.1460f, 0.1679f, 0.1957f, +0.2305f, 0.2709f, 0.3082f, 0.3245f +}; +static const float hlorentz50[22] = { +0.0480f, 0.0504f, 0.0529f, 0.0558f, 0.0589f, 0.0625f, 0.0665f, 0.0710f, +0.0761f, 0.0821f, 0.0889f, 0.0970f, 0.1066f, 0.1181f, 0.1321f, 0.1494f, +0.1709f, 0.1976f, 0.2300f, 0.2662f, 0.2981f, 0.3115f +}; +static const float hlorentz51[23] = { +0.0477f, 0.0499f, 0.0523f, 0.0550f, 0.0580f, 0.0612f, 0.0649f, 0.0690f, +0.0736f, 0.0789f, 0.0850f, 0.0920f, 0.1002f, 0.1099f, 0.1215f, 0.1355f, +0.1526f, 0.1735f, 0.1989f, 0.2288f, 0.2609f, 0.2880f, 0.2991f +}; +static const float hlorentz52[25] = { +0.0456f, 0.0475f, 0.0496f, 0.0519f, 0.0544f, 0.0572f, 0.0602f, 0.0636f, +0.0673f, 0.0715f, 0.0763f, 0.0817f, 0.0879f, 0.0951f, 0.1034f, 0.1132f, +0.1248f, 0.1387f, 0.1554f, 0.1755f, 0.1995f, 0.2268f, 0.2550f, 0.2779f, +0.2870f +}; +static const float hlorentz53[27] = { +0.0438f, 0.0456f, 0.0474f, 0.0494f, 0.0516f, 0.0539f, 0.0565f, 0.0594f, +0.0625f, 0.0660f, 0.0698f, 0.0742f, 0.0790f, 0.0846f, 0.0909f, 0.0981f, +0.1065f, 0.1164f, 0.1279f, 0.1416f, 0.1579f, 0.1771f, 0.1994f, 0.2242f, +0.2487f, 0.2680f, 0.2754f +}; +static const float hlorentz54[30] = { +0.0410f, 0.0424f, 0.0440f, 0.0456f, 0.0474f, 0.0493f, 0.0513f, 0.0536f, +0.0560f, 0.0587f, 0.0616f, 0.0648f, 0.0684f, 0.0724f, 0.0768f, 0.0818f, +0.0874f, 0.0938f, 0.1011f, 0.1096f, 0.1194f, 0.1308f, 0.1442f, 0.1599f, +0.1781f, 0.1987f, 0.2208f, 0.2421f, 0.2582f, 0.2643f +}; +static const float hlorentz55[32] = { +0.0400f, 0.0413f, 0.0427f, 0.0441f, 0.0457f, 0.0474f, 0.0492f, 0.0512f, +0.0533f, 0.0557f, 0.0582f, 0.0609f, 0.0639f, 0.0672f, 0.0709f, 0.0749f, +0.0795f, 0.0845f, 0.0902f, 0.0967f, 0.1041f, 0.1125f, 0.1222f, 0.1334f, +0.1464f, 0.1614f, 0.1785f, 0.1973f, 0.2169f, 0.2351f, 0.2485f, 0.2535f +}; +static const float hlorentz56[35] = { +0.0380f, 0.0391f, 0.0403f, 0.0416f, 0.0429f, 0.0444f, 0.0459f, 0.0475f, +0.0493f, 0.0512f, 0.0532f, 0.0554f, 0.0578f, 0.0604f, 0.0632f, 0.0663f, +0.0697f, 0.0734f, 0.0775f, 0.0821f, 0.0873f, 0.0930f, 0.0995f, 0.1069f, +0.1153f, 0.1248f, 0.1358f, 0.1483f, 0.1624f, 0.1782f, 0.1952f, 0.2125f, +0.2280f, 0.2391f, 0.2432f +}; +static const float hlorentz57[38] = { +0.0364f, 0.0374f, 0.0384f, 0.0395f, 0.0407f, 0.0419f, 0.0432f, 0.0446f, +0.0461f, 0.0477f, 0.0494f, 0.0512f, 0.0531f, 0.0552f, 0.0575f, 0.0599f, +0.0626f, 0.0655f, 0.0686f, 0.0721f, 0.0759f, 0.0801f, 0.0848f, 0.0899f, +0.0957f, 0.1022f, 0.1095f, 0.1178f, 0.1271f, 0.1377f, 0.1496f, 0.1629f, +0.1774f, 0.1926f, 0.2076f, 0.2207f, 0.2299f, 0.2332f +}; +static const float hlorentz58[41] = { +0.0351f, 0.0360f, 0.0369f, 0.0379f, 0.0389f, 0.0400f, 0.0411f, 0.0423f, +0.0436f, 0.0450f, 0.0464f, 0.0479f, 0.0496f, 0.0513f, 0.0532f, 0.0552f, +0.0573f, 0.0596f, 0.0621f, 0.0648f, 0.0678f, 0.0710f, 0.0745f, 0.0784f, +0.0826f, 0.0873f, 0.0925f, 0.0983f, 0.1048f, 0.1120f, 0.1201f, 0.1291f, +0.1392f, 0.1505f, 0.1628f, 0.1759f, 0.1894f, 0.2023f, 0.2134f, 0.2209f, +0.2237f +}; +static const float hlorentz59[45] = { +0.0333f, 0.0341f, 0.0349f, 0.0357f, 0.0366f, 0.0375f, 0.0384f, 0.0394f, +0.0405f, 0.0416f, 0.0428f, 0.0440f, 0.0453f, 0.0467f, 0.0482f, 0.0498f, +0.0515f, 0.0532f, 0.0552f, 0.0572f, 0.0594f, 0.0618f, 0.0643f, 0.0671f, +0.0701f, 0.0734f, 0.0770f, 0.0809f, 0.0851f, 0.0898f, 0.0950f, 0.1008f, +0.1071f, 0.1142f, 0.1221f, 0.1307f, 0.1403f, 0.1508f, 0.1621f, 0.1739f, +0.1857f, 0.1968f, 0.2060f, 0.2123f, 0.2145f +}; +static const float hlorentz60[49] = { +0.0319f, 0.0325f, 0.0332f, 0.0339f, 0.0347f, 0.0355f, 0.0363f, 0.0371f, +0.0380f, 0.0390f, 0.0400f, 0.0410f, 0.0421f, 0.0432f, 0.0444f, 0.0457f, +0.0471f, 0.0485f, 0.0500f, 0.0517f, 0.0534f, 0.0552f, 0.0572f, 0.0593f, +0.0615f, 0.0640f, 0.0666f, 0.0694f, 0.0724f, 0.0757f, 0.0793f, 0.0833f, +0.0875f, 0.0922f, 0.0974f, 0.1030f, 0.1093f, 0.1161f, 0.1237f, 0.1319f, +0.1409f, 0.1506f, 0.1608f, 0.1713f, 0.1816f, 0.1910f, 0.1987f, 0.2038f, +0.2056f +}; +static const float hlorentz61[53] = { +0.0307f, 0.0313f, 0.0319f, 0.0325f, 0.0332f, 0.0338f, 0.0346f, 0.0353f, +0.0361f, 0.0369f, 0.0377f, 0.0386f, 0.0395f, 0.0405f, 0.0415f, 0.0426f, +0.0437f, 0.0449f, 0.0462f, 0.0475f, 0.0489f, 0.0504f, 0.0519f, 0.0536f, +0.0553f, 0.0572f, 0.0592f, 0.0614f, 0.0637f, 0.0661f, 0.0688f, 0.0716f, +0.0747f, 0.0780f, 0.0816f, 0.0856f, 0.0898f, 0.0945f, 0.0996f, 0.1051f, +0.1111f, 0.1177f, 0.1249f, 0.1327f, 0.1410f, 0.1499f, 0.1590f, 0.1683f, +0.1771f, 0.1851f, 0.1915f, 0.1957f, 0.1971f +}; +static const float hlorentz62[57] = { +0.0297f, 0.0302f, 0.0308f, 0.0313f, 0.0319f, 0.0325f, 0.0332f, 0.0338f, +0.0345f, 0.0352f, 0.0359f, 0.0367f, 0.0375f, 0.0384f, 0.0392f, 0.0401f, +0.0411f, 0.0421f, 0.0432f, 0.0443f, 0.0454f, 0.0466f, 0.0479f, 0.0493f, +0.0507f, 0.0522f, 0.0538f, 0.0555f, 0.0573f, 0.0592f, 0.0613f, 0.0635f, +0.0658f, 0.0683f, 0.0710f, 0.0738f, 0.0769f, 0.0803f, 0.0839f, 0.0878f, +0.0920f, 0.0965f, 0.1015f, 0.1069f, 0.1127f, 0.1190f, 0.1258f, 0.1330f, +0.1406f, 0.1486f, 0.1568f, 0.1648f, 0.1724f, 0.1791f, 0.1844f, 0.1878f, +0.1890f +}; +static const float hlorentz63[62] = { +0.0284f, 0.0289f, 0.0294f, 0.0299f, 0.0304f, 0.0309f, 0.0315f, 0.0320f, +0.0326f, 0.0332f, 0.0338f, 0.0345f, 0.0352f, 0.0359f, 0.0366f, 0.0374f, +0.0382f, 0.0390f, 0.0399f, 0.0408f, 0.0417f, 0.0427f, 0.0437f, 0.0448f, +0.0459f, 0.0471f, 0.0484f, 0.0497f, 0.0511f, 0.0525f, 0.0541f, 0.0557f, +0.0575f, 0.0593f, 0.0612f, 0.0633f, 0.0655f, 0.0679f, 0.0704f, 0.0731f, +0.0760f, 0.0791f, 0.0824f, 0.0859f, 0.0898f, 0.0939f, 0.0984f, 0.1032f, +0.1083f, 0.1139f, 0.1198f, 0.1261f, 0.1328f, 0.1398f, 0.1469f, 0.1541f, +0.1610f, 0.1675f, 0.1731f, 0.1774f, 0.1802f, 0.1811f +}; +static const float hlorentz64[65] = { +0.0283f, 0.0287f, 0.0291f, 0.0296f, 0.0301f, 0.0306f, 0.0311f, 0.0316f, +0.0322f, 0.0327f, 0.0333f, 0.0339f, 0.0345f, 0.0352f, 0.0359f, 0.0366f, +0.0373f, 0.0381f, 0.0388f, 0.0397f, 0.0405f, 0.0414f, 0.0423f, 0.0433f, +0.0443f, 0.0454f, 0.0465f, 0.0476f, 0.0489f, 0.0501f, 0.0515f, 0.0529f, +0.0544f, 0.0560f, 0.0576f, 0.0594f, 0.0613f, 0.0632f, 0.0653f, 0.0676f, +0.0699f, 0.0724f, 0.0751f, 0.0780f, 0.0811f, 0.0843f, 0.0879f, 0.0916f, +0.0956f, 0.0999f, 0.1046f, 0.1095f, 0.1147f, 0.1202f, 0.1261f, 0.1321f, +0.1384f, 0.1447f, 0.1510f, 0.1569f, 0.1624f, 0.1670f, 0.1706f, 0.1728f, +0.1736f +}; +static const float *hptr_tab_lorentz[64] = { +hlorentz1, hlorentz2, hlorentz3, hlorentz4, +hlorentz5, hlorentz6, hlorentz7, hlorentz8, +hlorentz9, hlorentz10, hlorentz11, hlorentz12, +hlorentz13, hlorentz14, hlorentz15, hlorentz16, +hlorentz17, hlorentz18, hlorentz19, hlorentz20, +hlorentz21, hlorentz22, hlorentz23, hlorentz24, +hlorentz25, hlorentz26, hlorentz27, hlorentz28, +hlorentz29, hlorentz30, hlorentz31, hlorentz32, +hlorentz33, hlorentz34, hlorentz35, hlorentz36, +hlorentz37, hlorentz38, hlorentz39, hlorentz40, +hlorentz41, hlorentz42, hlorentz43, hlorentz44, +hlorentz45, hlorentz46, hlorentz47, hlorentz48, +hlorentz49, hlorentz50, hlorentz51, hlorentz52, +hlorentz53, hlorentz54, hlorentz55, hlorentz56, +hlorentz57, hlorentz58, hlorentz59, hlorentz60, +hlorentz61, hlorentz62, hlorentz63, hlorentz64 +}; diff --git a/lib/qra/qra64/main.c b/lib/qra/qra64/main.c index e5608db25..96ff24778 100644 --- a/lib/qra/qra64/main.c +++ b/lib/qra/qra64/main.c @@ -1,6 +1,6 @@ /* main.c -QRA64 mode encode/decode test +QRA64 mode encode/decode tests (c) 2016 - Nico Palermo, IV3NWV @@ -145,21 +145,22 @@ symbol. normrnd_s(rp,NSAMPLES,0,sigma); normrnd_s(rq,NSAMPLES,0,sigma); - if (channel_type == CHANNEL_AWGN) - for (k=0;k-15) + if (channel_type == CHANNEL_AWGN) + for (k=0;k=0) { + ebnodbavg +=ebnodbest; + if (memcmp(xdec,x,12*sizeof(int))==0) + ndecok[rc]++; + else + nundet++; + } + } + printf("\n\n"); + + printf("Transimtted msgs:%d\nDecoded msgs:\n\n",ntx); + for (k=0;k<12;k++) { + printf("%3d with %s\n",ndecok[k],decode_type[k]); + ndec += ndecok[k]; + } + printf("\nTotal: %d/%d (%d undetected errors)\n\n",ndec,ntx,nundet); + printf(""); + + ebnodbavg/=(ndec+nundet); + printf("Estimated SNR (average in dB) = %.2f dB\n\n",ebnodbavg-QRA64_SNR_EBNO_OFFSET); + + return 0; +} + + + void syntax(void) { printf("\nQRA64 Mode Tests\n"); @@ -421,6 +508,11 @@ void syntax(void) printf(" -a : set decode type 0=NOAP 1=AUTOAP (default) 2=USERAP\n"); printf(" -t: 0=simulate seq of msgs between IV3NWV and K1JT (default)\n"); printf(" 1=simulate K1JT receiving K1JT IV3NWV JN66\n"); + printf(" 2=simulate fast-fading routines (option -c ignored)\n"); + printf("Options used only for fast-fading simulations:\n"); + printf(" -b : 90%% fading bandwidth in Hz [1..230 Hz] (default = 2.5 Hz)\n"); + printf(" -m : fading model. 0=Gauss, 1=Lorentz (default = Lorentz)\n"); + printf(" -q : qra64 submode. 0=QRA64A,... 4=QRA64E (default = QRA64A)\n"); printf(" -h: this help\n"); } @@ -433,55 +525,88 @@ int main(int argc, char* argv[]) unsigned int testtype=0; int nqso = 100; float EbNodB; + float B90 = 2.5; + int fadingModel = 1; + int submode = 0; // Parse the command line while(--argc) { argv++; + if (strncmp(*argv,"-h",2)==0) { syntax(); return 0; - } else { - if (strncmp(*argv,"-a",2)==0) { - mode = ( int)atoi((*argv)+2); - if (mode>2) { - printf("Invalid decoding mode\n"); - syntax(); - return -1; - } - } else { + } + else + if (strncmp(*argv,"-a",2)==0) { + mode = ( int)atoi((*argv)+2); + if (mode>2) { + printf("Invalid decoding mode\n"); + syntax(); + return -1; + } + } + else if (strncmp(*argv,"-s",2)==0) { - SNRdB = (float)atof((*argv)+2); - if (SNRdB>20 || SNRdB<-40) { - printf("SNR should be in the range [-40..20]\n"); + SNRdB = (float)atof((*argv)+2); + if (SNRdB>20 || SNRdB<-50) { + printf("SNR should be in the range [-50..20]\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-t",2)==0) { + testtype = ( int)atoi((*argv)+2); + if (testtype>2) { + printf("Invalid test type\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-c",2)==0) { + channel = ( int)atoi((*argv)+2); + if (channel>CHANNEL_RAYLEIGH) { + printf("Invalid channel type\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-b",2)==0) { + B90 = (float)atof((*argv)+2); + if (B90<1 || B90>230) { + printf("Invalid B90\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-m",2)==0) { + fadingModel = (int)atoi((*argv)+2); + if (fadingModel<0 || fadingModel>1) { + printf("Invalid fading model\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-q",2)==0) { + submode = (int)atoi((*argv)+2); + if (submode<0 || submode>4) { + printf("Invalid submode\n"); + syntax(); + return -1; + } + } + else { + printf("Invalid option\n"); syntax(); return -1; - } - } else { - if (strncmp(*argv,"-t",2)==0) { - testtype = ( int)atoi((*argv)+2); - if (testtype>1) { - printf("Invalid test type\n"); - syntax(); - return -1; } - } else { - if (strncmp(*argv,"-c",2)==0) { - channel = ( int)atoi((*argv)+2); - if (channel>CHANNEL_RAYLEIGH) { - printf("Invalid channel type\n"); - syntax(); - return -1; - } - } else { - printf("Invalid option\n"); - syntax(); - return -1; - } - } } - } - } - } + EbNodB = SNRdB+QRA64_SNR_EBNO_OFFSET; @@ -490,21 +615,33 @@ int main(int argc, char* argv[]) #endif if (testtype==0) { - for (k=0;k -#include #include #include "qra64.h" #include "../qracodes/qracodes.h" #include "../qracodes/qra13_64_64_irr_e.h" #include "../qracodes/pdmath.h" +#include "../qracodes/normrnd.h" // Code parameters of the QRA64 mode #define QRA64_CODE qra_13_64_64_irr_e @@ -54,8 +54,28 @@ resulting code is a (12,63) code static int calc_crc6(const int *x, int sz); static void ix_mask(float *dst, const float *src, const int *mask, const int *x); -static int qra64_do_decode(int *x, const float *pix, const int *ap_mask, +static int qra64_decode_attempts(qra64codec *pcodec, int *xdec, const float *ix); +static int qra64_do_decode(int *x, const float *pix, const int *ap_mask, const int *ap_x); +static float qra64_fastfading_estim_noise_std( + float *rxen, + const float esnometric, + const int submode); +static void qra64_fastfading_intrinsics( + float *pix, + const float *rxamp, + const float *hptr, + const int hlen, + const float cmetric, + const int submode); +static float qra64_fastfading_msg_esno( + const int *ydec, + const float *rxamp, + const float sigma, + const float EsNoMetric, + const int hlen, + const int submode); + // a-priori information masks for fields in JT65-like msgs -------------------- #define MASK_CQQRZ 0xFFFFFFC // CQ/QRZ calls common bits @@ -259,101 +279,13 @@ int qra64_decode(qra64codec *pcodec, float *ebno, int *x, const float *rxen) // Initialize crc prob to a uniform distribution pd_init(dsttmp,pd_uniform(QRA64_m),QRA64_M); - // Attempt to decode without a-priori info -------------------------------- - rc = qra64_do_decode(xdec, ix, NULL, NULL); - if (rc>=0) { - rc = 0; // successfull decode with AP0 - goto decode_end; - } - else - if (pcodec->apflags==QRA_NOAP) - // nothing more to do - return rc; // rc<0 = unsuccessful decode + // Try to decode using all AP cases if required + rc = qra64_decode_attempts(pcodec, xdec, ix); - // Here we handle decoding with AP knowledge + if (rc<0) + return rc; // no success - // Attempt to decode CQ calls - rc = qra64_do_decode(xdec,ix,pcodec->apmask_cqqrz, pcodec->apmsg_cqqrz); - if (rc>=0) { rc = 1; goto decode_end; }; // decoded [cq/qrz ? ?] - rc = qra64_do_decode(xdec, ix, pcodec->apmask_cqqrz_ooo, - pcodec->apmsg_cqqrz); - if (rc>=0) { rc = 2; goto decode_end; }; // decoded [cq ? ooo] - - // attempt to decode calls directed to us - if (pcodec->apmsg_set[APTYPE_MYCALL]) { - rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1, - pcodec->apmsg_call1); - if (rc>=0) { rc = 3; goto decode_end; }; // decoded [mycall ? ?] - rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1_ooo, - pcodec->apmsg_call1); - if (rc>=0) { rc = 4; goto decode_end; }; // decoded [mycall ? ooo] - } - - // attempt to decode [mycall srccall ?] msgs - if (pcodec->apmsg_set[APTYPE_BOTHCALLS]) { - rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1_call2, - pcodec->apmsg_call1_call2); - if (rc>=0) { rc = 5; goto decode_end; }; // decoded [mycall srccall ?] - } - - // attempt to decode [? hiscall ?/b] msgs - if (pcodec->apmsg_set[APTYPE_HISCALL]) { - rc = qra64_do_decode(xdec, ix, pcodec->apmask_call2, - pcodec->apmsg_call2); - if (rc>=0) { rc = 6; goto decode_end; }; // decoded [? hiscall ?] - rc = qra64_do_decode(xdec, ix, pcodec->apmask_call2_ooo, - pcodec->apmsg_call2); - if (rc>=0) { rc = 7; goto decode_end; }; // decoded [? hiscall ooo] - } - - // attempt to decode [cq/qrz hiscall ?/b/grid] msgs - if (pcodec->apmsg_set[APTYPE_CQHISCALL]) { - - rc = qra64_do_decode(xdec, ix, pcodec->apmask_cq_call2, - pcodec->apmsg_cq_call2); - if (rc>=0) { rc = 9; goto decode_end; }; // decoded [cq/qrz hiscall ?] - - rc = qra64_do_decode(xdec, ix, pcodec->apmask_cq_call2_ooo, - pcodec->apmsg_cq_call2_grid); - if (rc>=0) { - // Full AP mask need special handling - // To minimize false decodes we check the decoded message - // with what passed in the ap_set call - if (memcmp(pcodec->apmsg_cq_call2_grid,xdec, QRA64_K*sizeof(int))!=0) - return -1; - rc = 11; goto decode_end; - }; // decoded [cq/qrz hiscall grid] - - rc = qra64_do_decode(xdec, ix, pcodec->apmask_cq_call2_ooo, - pcodec->apmsg_cq_call2); - if (rc>=0) { - // Full AP mask need special handling - // To minimize false decodes we check the decoded message - // with what passed in the ap_set call - if (memcmp(pcodec->apmsg_cq_call2,xdec, QRA64_K*sizeof(int))!=0) - return -1; - rc = 10; goto decode_end; }; // decoded [cq/qrz hiscall ] - } - - // attempt to decode [mycall hiscall grid] - if (pcodec->apmsg_set[APTYPE_FULL]) { - rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1_call2_grid, - pcodec->apmsg_call1_call2_grid); - if (rc>=0) { - // Full AP mask need special handling - // All the three msg fields were given. - // To minimize false decodes we check the decoded message - // with what passed in the ap_set call - if (memcmp(pcodec->apmsg_call1_call2_grid,xdec, QRA64_K*sizeof(int))!=0) - return -1; - rc = 8; goto decode_end; - }; // decoded [mycall hiscall grid] - } - - // all decoding attempts failed - return rc; - -decode_end: // successfull decode + // successfull decode -------------------------------- // copy decoded message (without crc) to output buffer memcpy(x,xdec,QRA64_K*sizeof(int)); @@ -404,8 +336,585 @@ decode_end: // successfull decode return rc; } +// Tables of fading amplitudes coefficients for QRA64 (Ts=6912/12000) +// As the fading is assumed to be symmetric around the nominal frequency +// only the leftmost and the central coefficient are stored in the tables. +// (files have been generated with the Matlab code efgengauss.m and efgenlorentz.m) +#include "fadampgauss.c" +#include "fadamplorentz.c" + +int qra64_decode_fastfading( + qra64codec *pcodec, // ptr to the codec structure + float *ebno, // ptr to where the estimated Eb/No value will be saved + int *x, // ptr to decoded message + float *rxen, // ptr to received symbol energies array + const int submode, // submode idx (0=QRA64A ... 4=QRA64E) + const float B90, // spread bandwidth (90% fractional energy) + const int fadingModel) // 0=Gaussian 1=Lorentzian fade model + +// Decode a QRA64 msg using a fast-fading metric +// +// rxen: The array of the received bin energies +// Bins must be spaced by integer multiples of the symbol rate (1/Ts Hz) +// The array must be an array of total length U = L x N where: +// L: is the number of frequency bins per message symbol (see after) +// N: is the number of symbols in a QRA64 msg (63) + +// The number of bins/symbol L depends on the selected submode accordingly to +// the following rule: +// L = (64+64*2^submode+64) = 64*(2+2^submode) +// Tone 0 is always supposed to be at offset 64 in the array. +// The m-th tone nominal frequency is located at offset 64 + m*2^submode (m=0..63) +// +// Submode A: (2^submode = 1) +// L = 64*3 = 196 bins/symbol +// Total length of the energies array: U = 192*63 = 12096 floats +// +// Submode B: (2^submode = 2) +// L = 64*4 = 256 bins/symbol +// Total length of the energies array: U = 256*63 = 16128 floats +// +// Submode C: (2^submode = 4) +// L = 64*6 = 384 bins/symbol +// Total length of the energies array: U = 384*63 = 24192 floats +// +// Submode D: (2^submode = 8) +// L = 64*10 = 640 bins/symbol +// Total length of the energies array: U = 640*63 = 40320 floats +// +// Submode E: (2^submode = 16) +// L = 64*18 = 1152 bins/symbol +// Total length of the energies array: U = 1152*63 = 72576 floats +// +// Note: The rxen array is modified and reused for internal calculations. +// +// +// B90: spread fading bandwidth in Hz (90% fractional average energy) +// +// B90 should be in the range 1 Hz ... 238 Hz +// The value passed to the call is rounded to the closest value among the +// 64 available values: +// B = 1.09^k Hz, with k=0,1,...,63 +// +// I.e. B90=27 Hz will be approximated in this way: +// k = rnd(log(27)/log(1.09)) = 38 +// B90 = 1.09^k = 1.09^38 = 26.4 Hz +// +// For any input value the maximum rounding error is not larger than +/- 5% +// + +{ + + int k; + float *srctmp, *dsttmp; + float ix[QRA64_NC*QRA64_M]; // (depunctured) intrisic information + int xdec[QRA64_KC]; // decoded message (with crc) + int ydec[QRA64_NC]; // re-encoded message (for snr calculations) + float noisestd; // estimated noise std + float esno,ebnoval; // estimated Eb/No + float tempf; + float EsNoMetric, cmetric; + int rc; + int hidx, hlen; + const float *hptr; + + if (QRA64_NMSG!=QRA64_CODE.NMSG) + return -16; // QRA64_NMSG define is wrong + + if (submode<0 || submode>4) + return -17; // invalid submode + + if (B90<1.0f || B90>238.0f) + return -18; // B90 out of range + + // compute index to most appropriate amplitude weighting function coefficients + hidx = (int)(log((float)B90)/log(1.09f) - 0.499f); + + if (hidx<0 || hidx > 64) + return -19; // index of weighting function out of range + + if (fadingModel==0) { // gaussian fading model + // point to gaussian weighting taps + hlen = hlen_tab_gauss[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = hptr_tab_gauss[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else if (fadingModel==1) { + // point to lorentzian weighting taps + hlen = hlen_tab_lorentz[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = hptr_tab_lorentz[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else + return -20; // invalid fading model index + + + // compute (euristically) the optimal decoder metric accordingly the given spread amount + // We assume that the decoder threshold is: + // Es/No(dB) = Es/No(AWGN)(dB) + 8*log(B90)/log(240)(dB) + // that's to say, at the maximum Doppler spread bandwidth (240 Hz) there's a ~8 dB Es/No degradation + // over the AWGN case + tempf = 8.0f*(float)log((float)B90)/(float)log(240.0f); + EsNoMetric = pcodec->decEsNoMetric*(float)pow(10.0f,tempf/10.0f); + + // Step 1 ----------------------------------------------------------------------------------- + // Evaluate the noise stdev from the received energies at nominal tone frequencies + // and transform energies to amplitudes + tempf = hptr[hlen-1]; // amplitude weigth at nominal freq; + tempf = tempf*tempf; // fractional energy at nominal freq. bin + + noisestd = qra64_fastfading_estim_noise_std(rxen, EsNoMetric, submode); + cmetric = (float)sqrt(M_PI_2*EsNoMetric)/noisestd; + + // Step 2 ----------------------------------------------------------------------------------- + // Compute message symbols probability distributions + qra64_fastfading_intrinsics(ix, rxen, hptr, hlen, cmetric, submode); + + // Step 3 --------------------------------------------------------------------------- + // De-puncture observations adding a uniform distribution for the crc symbol + // Move check symbols distributions one symbol towards the end + dsttmp = PD_ROWADDR(ix,QRA64_M, QRA64_NC-1); //Point to last symbol prob dist + srctmp = dsttmp-QRA64_M; // source is the previous pd + for (k=0;k238.0f) + return -18; // B90 out of range + + // compute index to most appropriate amplitude weighting function coefficients + hidx = (int)(log((float)B90)/log(1.09f) - 0.499f); + + if (hidx<0 || hidx > 64) + return -19; // index of weighting function out of range + + if (fadingModel==0) { // gaussian fading model + // point to gaussian weighting taps + hlen = hlen_tab_gauss[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = hptr_tab_gauss[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else if (fadingModel==1) { + // point to lorentzian weighting taps + hlen = hlen_tab_lorentz[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = hptr_tab_lorentz[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else + return -20; // invalid fading model index + + + // Compute the unfaded tone amplitudes from the Eb/No value passed to the call + N0 = 1.0f; // assume unitary noise PSD + sigmanoise = (float)sqrt(N0/2); + EsN0 = (float)pow(10.0f,EbN0dB/10.0f)*QRA64_m*QRA64_K/QRA64_N; // Es/No = m*R*Eb/No + Es = EsN0*N0; + A = (float)sqrt(Es/2.0f); // unfaded tone amplitude (i^2+q^2 = Es/2+Es/2 = Es) + + + // Generate gaussian noise iq components + normrnd_s(channel_out, bpm*2, 0 , sigmanoise); + + // Add message symbols energies + for (n=0;n=0;j--) { + sigmasig = A*hptr[j]; + normrnd_s(iq, 2, 0 , sigmasig); +// iq[0]=sigmasig*sqrt(2); iq[1]=0; debug: used to verify Eb/No + *curi++ += iq[0]; + *curq++ += iq[1]; +// tote +=iq[0]*iq[0]+iq[1]*iq[1]; // debug + } + + } + +// tote = tote/QRA64_N; // debug + + // compute total bin energies (S+N) and store in first half of buffer + curi = channel_out; + curq = channel_out+bpm; + for (n=0;n=0;j--) { + u = *curbin++ * hptr[j]*cmetric; + u = u*u/(u+(float)M_E); // log(I0(u)) approx. + loglh = loglh + u; + } + if (loglh>maxloglh) // keep track of the max loglikelihood + maxloglh = loglh; + curix[k]=loglh; + } + // scale to likelihoods + sumix = 0.f; + for (k=0;k=0;j--) { + u = *curbin++; + msgsn += u*u; + } + + } + + msgsn = msgsn/(QRA64_N*tothlen); // avg msg energy per bin (noise included) + + // as sigma is overestimated (sigmatrue = sigma*sqrt((1+EsNoMetric/bps)/(1+EsNo/bps)) + // we have: msgsn = (1+x/hlen)/(1+x/bps)*2*sigma^2*(1+EsnoMetric/bps), where x = Es/N0(true) + // + // we can then write: + // u = msgsn/2.0f/(sigma*sigma)/(1.0f+EsNoMetric/bps); + // (1+x/hlen)/(1+x/bps) = u + + u = msgsn/(2.0f*sigma*sigma)/(1.0f+EsNoMetric/bps); + + // check u>1 + if (u<1) + return 0.f; + + // check u(bps/tothlen)) + return 10000.f; + + // solve for Es/No + esno = (u-1.0f)/(1.0f/tothlen-u/bps); + + return esno; + + +} + + +// Attempt to decode given intrisic information +static int qra64_decode_attempts(qra64codec *pcodec, int *xdec, const float *ix) +{ + int rc; + + // Attempt to decode without a-priori info -------------------------------- + rc = qra64_do_decode(xdec, ix, NULL, NULL); + if (rc>=0) + return 0; // successfull decode with AP0 + else + if (pcodec->apflags==QRA_NOAP) + // nothing more to do + return rc; // rc<0 = unsuccessful decode + + // Here we handle decoding with AP knowledge + + // Attempt to decode CQ calls + rc = qra64_do_decode(xdec,ix,pcodec->apmask_cqqrz, pcodec->apmsg_cqqrz); + if (rc>=0) return 1; // decoded [cq/qrz ? ?] + + rc = qra64_do_decode(xdec, ix, pcodec->apmask_cqqrz_ooo, + pcodec->apmsg_cqqrz); + if (rc>=0) return 2; // decoded [cq ? ooo] + + // attempt to decode calls directed to us + if (pcodec->apmsg_set[APTYPE_MYCALL]) { + rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1, + pcodec->apmsg_call1); + if (rc>=0) return 3; // decoded [mycall ? ?] + rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1_ooo, + pcodec->apmsg_call1); + if (rc>=0) return 4; // decoded [mycall ? ooo] + } + + // attempt to decode [mycall srccall ?] msgs + if (pcodec->apmsg_set[APTYPE_BOTHCALLS]) { + rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1_call2, + pcodec->apmsg_call1_call2); + if (rc>=0) return 5; // decoded [mycall srccall ?] + } + + // attempt to decode [? hiscall ?/b] msgs + if (pcodec->apmsg_set[APTYPE_HISCALL]) { + rc = qra64_do_decode(xdec, ix, pcodec->apmask_call2, + pcodec->apmsg_call2); + if (rc>=0) return 6; // decoded [? hiscall ?] + rc = qra64_do_decode(xdec, ix, pcodec->apmask_call2_ooo, + pcodec->apmsg_call2); + if (rc>=0) return 7; // decoded [? hiscall ooo] + } + + // attempt to decode [cq/qrz hiscall ?/b/grid] msgs + if (pcodec->apmsg_set[APTYPE_CQHISCALL]) { + + rc = qra64_do_decode(xdec, ix, pcodec->apmask_cq_call2, + pcodec->apmsg_cq_call2); + if (rc>=0) return 9; // decoded [cq/qrz hiscall ?] + + rc = qra64_do_decode(xdec, ix, pcodec->apmask_cq_call2_ooo, + pcodec->apmsg_cq_call2_grid); + if (rc>=0) { + // Full AP mask need special handling + // To minimize false decodes we check the decoded message + // with what passed in the ap_set call + if (memcmp(pcodec->apmsg_cq_call2_grid,xdec, QRA64_K*sizeof(int))!=0) + return -1; + else + return 11; // decoded [cq/qrz hiscall grid] + }; + + rc = qra64_do_decode(xdec, ix, pcodec->apmask_cq_call2_ooo, + pcodec->apmsg_cq_call2); + if (rc>=0) { + // Full AP mask need special handling + // To minimize false decodes we check the decoded message + // with what passed in the ap_set call + if (memcmp(pcodec->apmsg_cq_call2,xdec, QRA64_K*sizeof(int))!=0) + return -1; + else + return 10; // decoded [cq/qrz hiscall ] + } + } + + // attempt to decode [mycall hiscall grid] + if (pcodec->apmsg_set[APTYPE_FULL]) { + rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1_call2_grid, + pcodec->apmsg_call1_call2_grid); + if (rc>=0) { + // Full AP mask need special handling + // All the three msg fields were given. + // To minimize false decodes we check the decoded message + // with what passed in the ap_set call + if (memcmp(pcodec->apmsg_call1_call2_grid,xdec, QRA64_K*sizeof(int))!=0) + return -1; + else + return 8; // decoded [mycall hiscall grid] + } + } + + // all decoding attempts failed + return rc; +} + + + // Decode with given a-priori information static int qra64_do_decode(int *xdec, const float *pix, const int *ap_mask, const int *ap_x) @@ -441,6 +950,8 @@ static int qra64_do_decode(int *xdec, const float *pix, const int *ap_mask, return 0; } + + // crc functions -------------------------------------------------------------- // crc-6 generator polynomial // g(x) = x^6 + a5*x^5 + ... + a1*x + a0 diff --git a/lib/qra/qra64/qra64.h b/lib/qra/qra64/qra64.h index e4b431872..e3c60e43a 100644 --- a/lib/qra/qra64/qra64.h +++ b/lib/qra/qra64/qra64.h @@ -140,6 +140,83 @@ int qra64_decode(qra64codec *pcodec, float *ebno, int *x, const float *r); // return codes in the range 1-10 indicate the amount and the type of a-priori // information was required to decode the received message. + +// Decode a QRA64 msg using a fast-fading metric +int qra64_decode_fastfading( + qra64codec *pcodec, // ptr to the codec structure + float *ebno, // ptr to where the estimated Eb/No value will be saved + int *x, // ptr to decoded message + float *rxen, // ptr to received symbol energies array + const int submode, // submode idx (0=QRA64A ... 4=QRA64E) + const float B90, // spread bandwidth (90% fractional energy) + const int fadingModel); // 0=Gaussian 1=Lorentzian fade model +// +// rxen: The array of the received bin energies +// Bins must be spaced by integer multiples of the symbol rate (1/Ts Hz) +// The array must be an array of total length U = L x N where: +// L: is the number of frequency bins per message symbol (see after) +// N: is the number of symbols in a QRA64 msg (63) +// +// The number of bins/symbol L depends on the selected submode accordingly to +// the following rule: +// L = (64+64*2^submode+64) = 64*(2+2^submode) +// Tone 0 is always supposed to be at offset 64 in the array. +// The m-th tone nominal frequency is located at offset 64 + m*2^submode (m=0..63) +// +// Submode A: (2^submode = 1) +// L = 64*3 = 196 bins/symbol +// Total length of the energies array: U = 192*63 = 12096 floats +// +// Submode B: (2^submode = 2) +// L = 64*4 = 256 bins/symbol +// Total length of the energies array: U = 256*63 = 16128 floats +// +// Submode C: (2^submode = 4) +// L = 64*6 = 384 bins/symbol +// Total length of the energies array: U = 384*63 = 24192 floats +// +// Submode D: (2^submode = 8) +// L = 64*10 = 640 bins/symbol +// Total length of the energies array: U = 640*63 = 40320 floats +// +// Submode E: (2^submode = 16) +// L = 64*18 = 1152 bins/symbol +// Total length of the energies array: U = 1152*63 = 72576 floats +// +// Note: The rxen array is modified and reused for internal calculations. +// +// +// B90: spread fading bandwidth in Hz (90% fractional average energy) +// +// B90 should be in the range 1 Hz ... 238 Hz +// The value passed to the call is rounded to the closest value among the +// 64 available values: +// B = 1.09^k Hz, with k=0,1,...,63 +// +// I.e. B90=27 Hz will be approximated in this way: +// k = rnd(log(27)/log(1.09)) = 38 +// B90 = 1.09^k = 1.09^38 = 26.4 Hz +// +// For any input value the maximum rounding error is not larger than +/- 5% +// +// return codes: same return codes of qra64_decode (+some additional error codes) + + +// Simulate the fast-fading channel (to be used with qra64_decode_fastfading) +int qra64_fastfading_channel( + float **rxen, + const int *xmsg, + const int submode, + const float EbN0dB, + const float B90, + const int fadingModel); +// Simulate transmission over a fading channel with given B90, fading model and submode +// and non coherent detection. +// Sets rxen to point to an array of bin energies formatted as required +// by the (fast-fading) decoding routine. +// returns 0 on success or negative values on error conditions + + int qra64_apset(qra64codec *pcodec, const int mycall, const int hiscall, const int grid, const int aptype); // Set decoder a-priori knowledge accordingly to the type of the message to // look up for diff --git a/lib/qra/qra64/qra64example.txt b/lib/qra/qra64/qra64example.txt new file mode 100644 index 000000000..b815a134a --- /dev/null +++ b/lib/qra/qra64/qra64example.txt @@ -0,0 +1,50 @@ +Example: + +qra64 -a2 -t2 -b10.0 -m1 -q2 -s-28.0 + +Simulate fast-fading decoding (-t2) with +USER_AP (-a2) +B90 = 10.0 Hz (-b10.0) +Lorentz model (-m1) +submode QRA64C (-q2) +Input SNR = -28.0 dB (-s-28.0) + +(type qra64 -h for command syntax) + +Command Output: + +Simulating the QRA64 decoder with fast-fading metric +B90=10.00 Hz - Fading Model=Lorentz - Submode=QRA64C + +K1JT decoder enabled for [K1JT ? ?/blank] +K1JT decoder enabled for [K1JT IV3NWV ?] +K1JT decoder enabled for [? IV3NWV ?/blank] +K1JT decoder enabled for [K1JT IV3NWV JN66] +K1JT decoder enabled for [CQ IV3NWV ?/b/JN66] + +Encoding msg: [K1JT IV3NWV JN66] +Decoding with K1JT's decoder +.................................................................................................... + +Transimtted msgs:100 +Decoded msgs: + + 0 with [? ? ?] AP0 + 0 with [CQ ? ?] AP27 + 0 with [CQ ? ] AP42 + 4 with [CALL ? ?] AP29 + 0 with [CALL ? ] AP44 + 0 with [CALL CALL ?] AP57 + 2 with [? CALL ?] AP29 + 0 with [? CALL ] AP44 + 91 with [CALL CALL G] AP72 + 0 with [CQ CALL ?] AP55 + 0 with [CQ CALL ] AP70 + 0 with [CQ CALL G] AP70 + +Total: 97/100 (0 undetected errors) + +Estimated SNR (average in dB) = -28.39 dB + +Input SNR = -28.0dB ap-mode=USER AP +