Add code for QRA64 with fast fading.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@7295 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Joe Taylor 2016-11-06 00:53:47 +00:00
parent 5152778813
commit 8390bcd798
7 changed files with 1602 additions and 170 deletions

View File

@ -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

327
lib/qra/qra64/fadampgauss.c Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
-----------------------------------------------------------------------------
*/
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
};

View File

@ -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 <http://www.gnu.org/licenses/>.
-----------------------------------------------------------------------------
*/
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
};

View File

@ -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<QRA64_N;k++)
rp[k*QRA64_M+x[k]]+=A;
else
if (channel_type == CHANNEL_RAYLEIGH) {
normrnd_s(chp,QRA64_N,0,sigmach);
normrnd_s(chq,QRA64_N,0,sigmach);
for (k=0;k<QRA64_N;k++) {
rp[k*QRA64_M+x[k]]+=A*chp[k];
rq[k*QRA64_M+x[k]]+=A*chq[k];
}
}
else {
return 0; // unknown channel type
}
if(EbNodB>-15)
if (channel_type == CHANNEL_AWGN)
for (k=0;k<QRA64_N;k++)
rp[k*QRA64_M+x[k]]+=A;
else
if (channel_type == CHANNEL_RAYLEIGH) {
normrnd_s(chp,QRA64_N,0,sigmach);
normrnd_s(chq,QRA64_N,0,sigmach);
for (k=0;k<QRA64_N;k++) {
rp[k*QRA64_M+x[k]]+=A*chp[k];
rq[k*QRA64_M+x[k]]+=A*chq[k];
}
}
else {
return 0; // unknown channel type
}
// compute the squares of the amplitudes of the received samples
for (k=0;k<NSAMPLES;k++)
@ -342,7 +343,7 @@ a particular type decode among the above 6 cases succeded.
int ndecok[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int nundet = 0;
int ntx = 100,ndec=0;
int ntx = 200,ndec=0;
qra64codec *codec_iv3nwv = qra64_init(mode); // codec for IV3NWV
qra64codec *codec_k1jt = qra64_init(mode); // codec for K1JT
@ -351,16 +352,16 @@ a particular type decode among the above 6 cases succeded.
QRA64_SNR_EBNO_OFFSET);
// This will enable K1JT's decoder to look for calls directed to him [K1JT ? ?/b]
printf("K1JT decoder enabled for [K1JT ? ?/blank]\n");
qra64_apset(codec_k1jt, CALL_K1JT,0,0,APTYPE_MYCALL);
// printf("K1JT decoder enabled for [K1JT ? ?/blank]\n");
// qra64_apset(codec_k1jt, CALL_K1JT,0,0,APTYPE_MYCALL);
// This will enable K1JT's decoder to look for IV3NWV calls directed to him [K1JT IV3NWV ?/b]
printf("K1JT decoder enabled for [K1JT IV3NWV ?]\n");
qra64_apset(codec_k1jt, CALL_K1JT,CALL_IV3NWV,0,APTYPE_BOTHCALLS);
// printf("K1JT decoder enabled for [K1JT IV3NWV ?]\n");
// qra64_apset(codec_k1jt, CALL_CQ,CALL_IV3NWV,0,APTYPE_BOTHCALLS);
// This will enable K1JT's decoder to look for msges sent by IV3NWV [? IV3NWV ?]
printf("K1JT decoder enabled for [? IV3NWV ?/blank]\n");
qra64_apset(codec_k1jt, 0,CALL_IV3NWV,GRID_BLANK,APTYPE_HISCALL);
// printf("K1JT decoder enabled for [? IV3NWV ?/blank]\n");
// qra64_apset(codec_k1jt, 0,CALL_IV3NWV,GRID_BLANK,APTYPE_HISCALL);
// This will enable K1JT's decoder to look for full-knowledge [K1JT IV3NWV JN66] msgs
printf("K1JT decoder enabled for [K1JT IV3NWV JN66]\n");
@ -372,8 +373,12 @@ a particular type decode among the above 6 cases succeded.
// Dx station IV3NWV calls
printf("\nIV3NWV encoder sends msg: [CQ IV3NWV JN66]\n\n");
printf("\nIV3NWV encoder sends msg: [K1JT IV3NWV JN66]\n\n");
encodemsg_jt65(x,CALL_CQ,CALL_IV3NWV,GRID_JN66);
// printf("\nIV3NWV encoder sends msg: [CQ IV3NWV JN66]\n\n");
// encodemsg_jt65(x,CALL_CQ,CALL_IV3NWV,GRID_JN66);
// printf("\nIV3NWV encoder sends msg: [CQ IV3NWV]\n\n");
// encodemsg_jt65(x,CALL_CQ,CALL_IV3NWV,GRID_BLANK);
qra64_encode(codec_iv3nwv, y, x);
@ -409,6 +414,88 @@ a particular type decode among the above 6 cases succeded.
return 0;
}
int test_fastfading(float EbNodB, float B90, int fadingModel, int submode, int apmode)
{
int x[QRA64_K], xdec[QRA64_K];
int y[QRA64_N];
float *rx;
float ebnodbest, ebnodbavg=0;
int rc,k;
int ndecok[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int nundet = 0;
int ntx = 100,ndec=0;
qra64codec *codec_iv3nwv;
qra64codec *codec_k1jt;
codec_iv3nwv=qra64_init(QRA_NOAP);
codec_k1jt =qra64_init(apmode);
printf("\nSimulating the QRA64 decoder with fast-fading metric\n");
printf("B90=%.2f Hz - Fading Model=%s - Submode=QRA64%c\n\n",B90,fadingModel?"Lorentz":"Gauss",submode+'A');
if (apmode==QRA_USERAP) {
// This will enable K1JT's decoder to look for calls directed to him [K1JT ? ?/b]
printf("K1JT decoder enabled for [K1JT ? ?/blank]\n");
qra64_apset(codec_k1jt, CALL_K1JT,0,0,APTYPE_MYCALL);
// This will enable K1JT's decoder to look for IV3NWV calls directed to him [K1JT IV3NWV ?/b]
printf("K1JT decoder enabled for [K1JT IV3NWV ?]\n");
qra64_apset(codec_k1jt, CALL_CQ,CALL_IV3NWV,0,APTYPE_BOTHCALLS);
// This will enable K1JT's decoder to look for msges sent by IV3NWV [? IV3NWV ?]
printf("K1JT decoder enabled for [? IV3NWV ?/blank]\n");
qra64_apset(codec_k1jt, 0,CALL_IV3NWV,GRID_BLANK,APTYPE_HISCALL);
// This will enable K1JT's decoder to look for full-knowledge [K1JT IV3NWV JN66] msgs
printf("K1JT decoder enabled for [K1JT IV3NWV JN66]\n");
qra64_apset(codec_k1jt, CALL_K1JT,CALL_IV3NWV,GRID_JN66,APTYPE_FULL);
// This will enable K1JT's decoder to look for calls from IV3NWV [CQ IV3NWV ?/b] msgs
printf("K1JT decoder enabled for [CQ IV3NWV ?/b/JN66]\n");
qra64_apset(codec_k1jt, 0,CALL_IV3NWV,GRID_JN66,APTYPE_CQHISCALL);
}
printf("\nEncoding msg: [K1JT IV3NWV JN66]\n");
encodemsg_jt65(x,CALL_K1JT,CALL_IV3NWV,GRID_JN66);
qra64_encode(codec_iv3nwv, y, x);
printf("Decoding with K1JT's decoder\n");
for (k=0;k<ntx;k++) {
printf(".");
rc = qra64_fastfading_channel(&rx,y,submode,EbNodB,B90,fadingModel);
if (rc<0) {
printf("qra64_fastfading_channel error. rc=%d\n",rc);
return -1;
}
rc = qra64_decode_fastfading(codec_k1jt,&ebnodbest,xdec,rx,submode,B90,fadingModel);
if (rc>=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<ap-type> : set decode type 0=NOAP 1=AUTOAP (default) 2=USERAP\n");
printf(" -t<testtype>: 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<nqso;k++) {
printf("\n\n------------------------\n");
rc = test_proc_1(channel, EbNodB, mode);
if (rc==0)
nok++;
}
printf("\n\n%d/%d QSOs to end without repetitions\n",nok,nqso);
} else {
test_proc_2(channel, EbNodB, mode);
}
printf("Input SNR = %.1fdB channel=%s ap-mode=%s\n\n",
for (k=0;k<nqso;k++) {
printf("\n\n------------------------\n");
rc = test_proc_1(channel, EbNodB, mode);
if (rc==0)
nok++;
}
printf("\n\n%d/%d QSOs to end without repetitions\n",nok,nqso);
printf("Input SNR = %.1fdB channel=%s ap-mode=%s\n\n",
SNRdB,
channel==CHANNEL_AWGN?"AWGN":"RAYLEIGH",
apmode_type[mode]
);
}
else if (testtype==1) {
test_proc_2(channel, EbNodB, mode);
printf("Input SNR = %.1fdB channel=%s ap-mode=%s\n\n",
SNRdB,
channel==CHANNEL_AWGN?"AWGN":"RAYLEIGH",
apmode_type[mode]
);
}
else {
test_fastfading(EbNodB,B90,fadingModel,submode,mode);
printf("Input SNR = %.1fdB ap-mode=%s\n\n",
SNRdB,
channel==CHANNEL_AWGN?"AWGN":"RAYLEIGH",
apmode_type[mode]
);
}
return 0;
}

View File

@ -21,7 +21,7 @@ Encoding/decoding functions for the QRA64 mode
-----------------------------------------------------------------------------
Code used in this sowftware release:
QRA code used in this sowftware release:
QRA13_64_64_IRR_E: K=13 N=64 Q=64 irregular QRA code (defined in
qra13_64_64_irr_e.h /.c)
@ -34,13 +34,13 @@ resulting code is a (12,63) code
//----------------------------------------------------------------------------
#include <stdlib.h>
#include <math.h>
#include <string.h>
#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;k<QRA64_C;k++) {
pd_init(dsttmp,srctmp,QRA64_M);
dsttmp -=QRA64_M;
srctmp -=QRA64_M;
}
// Initialize crc prob to a uniform distribution
pd_init(dsttmp,pd_uniform(QRA64_m),QRA64_M);
// Step 4 ---------------------------------------------------------------------------
// Attempt to decode
rc = qra64_decode_attempts(pcodec, xdec, ix);
if (rc<0)
return rc; // no success
// copy decoded message (without crc) to output buffer
memcpy(x,xdec,QRA64_K*sizeof(int));
// Step 5 ----------------------------------------------------------------------------
// Estimate the message Eb/No
if (ebno==0) // null pointer indicates we are not interested in the Eb/No estimate
return rc;
// reencode message to estimate Eb/No
qra_encode(&QRA64_CODE, ydec, xdec);
// puncture crc
memmove(ydec+QRA64_K,ydec+QRA64_KC,QRA64_C*sizeof(int));
// compute Es/N0 of decoded message
esno = qra64_fastfading_msg_esno(ydec,rxen,noisestd, EsNoMetric, hlen,submode);
// as the weigthing function include about 90% of the energy
// we could compute the unbiased esno with:
// esno = esno/0.9;
// this would be the exact value if the noisestd were not overestimated at high Eb/No
ebnoval = 1.0f/(1.0f*QRA64_K/QRA64_N*QRA64_m)*esno;
// compute value in dB
if (ebnoval<=0)
ebnoval = EBNO_MIN; // assume a minimum, positive value
else
ebnoval = 10.0f*(float)log10(ebnoval);
if (ebnoval<EBNO_MIN)
ebnoval = EBNO_MIN;
*ebno = ebnoval;
return rc;
}
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 and non coherent detection
// Set 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
static float *channel_out = NULL;
static int channel_submode = -1;
int bpt = (1<<submode); // bins per tone
int bps = QRA64_M*(2+bpt); // total number of bins per symbols
int bpm = bps*QRA64_N; // total number of bins in a message
int n,j,hidx, hlen;
const float *hptr;
float *cursym,*curtone;
float iq[2];
float *curi, *curq;
// float tote=0; // debug
float N0, EsN0, Es, A, sigmanoise, sigmasig;
if (rxen==NULL)
return -1; // rxen must be a non-null ptr
// allocate output buffer if not yet done or if submode changed
if (channel_out==NULL || submode!=channel_submode) {
// unallocate previous buffer
if (channel_out)
free(channel_out);
// allocate new buffer
// we allocate twice the mem so that we can store/compute complex amplitudes
channel_out = (float*)malloc(bpm*sizeof(float)*2);
if (channel_out==NULL)
return -2; // error allocating memory
channel_submode = 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 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<QRA64_N;n++) {
cursym = channel_out+n*bps + QRA64_M; // point to n-th symbol
curtone = cursym+xmsg[n]*bpt; // point to encoded tone
curi = curtone-hlen+1; // point to real part of first bin
curq = curtone-hlen+1+bpm; // point to imag part of first bin
// generate Rayleigh faded bins with given average energy and add to noise
for (j=0;j<hlen;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
}
for (j=hlen-2;j>=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<bpm;n++)
channel_out[n] = curi[n]*curi[n] + curq[n]*curq[n];
// set rxen to point to the channel output energies
*rxen = channel_out;
return 0;
}
// Static functions definitions ----------------------------------------------
// fast-fading static functions --------------------------------------------------------------
static float qra64_fastfading_estim_noise_std(float *rxen, const float esnometric, const int submode)
{
// estimate the noise standard deviation from nominal frequency symbol bins
// transform energies to amplitudes
// rxen = message symbols energies (overwritten with symbols amplitudes)
// esnometric = Es/No at nominal frequency bin for which we compute the decoder metric
// submode = submode used (0=A...4=E)
int bpt = (1<<submode); // bins per tone
int bps = QRA64_M*(2+bpt); // total number of bins per symbols
int bpm = bps*QRA64_N; // total number of bins in a message
int k;
float sigmaest;
// estimate noise std
sigmaest = 0;
for (k=0;k<bpm;k++) {
sigmaest += rxen[k];
// convert energies to amplitudes for later use
rxen[k] = (float)sqrt(rxen[k]); // we do it in place to avoid memory allocations
}
sigmaest = sigmaest/bpm;
sigmaest = (float)sqrt(sigmaest/(1.0f+esnometric/bps)/2.0f);
// Note: sigma is overestimated by the (unknown) factor sqrt((1+esno(true)/bps)/(1+esnometric/bps))
return sigmaest;
}
static void qra64_fastfading_intrinsics(
float *pix,
const float *rxamp,
const float *hptr,
const int hlen,
const float cmetric,
const int submode)
{
// For each symbol in a message:
// a) Compute tones loglikelihoods as a sum of products between of the expected
// amplitude fading coefficient and received amplitudes.
// Each product is computed as log(I0(hk*xk*cmetric)) where hk is the average fading amplitude,
// xk is the received amplitude at bin offset k, and cmetric is a constant dependend on the
// Eb/N0 value for which the metric is optimized
// The function y = log(I0(x)) is approximated as y = x^2/(x+e)
// b) Compute intrinsic symbols probability distributions from symbols loglikelihoods
int n,k,j, bps, bpt;
const float *cursym, *curbin;
float *curix;
float u, maxloglh, loglh, sumix;
bpt = 1<<submode; // bins per tone
bps = QRA64_M*(2+bpt); // bins per symbol
for (n=0;n<QRA64_N;n++) { // for each symbol in the message
cursym = rxamp+n*bps + QRA64_M; // point to current symbol nominal bin
maxloglh = 0;
curix = pix+n*QRA64_M;
for (k=0;k<QRA64_M;k++) { // for each tone in the current symbol
curbin = cursym + k*bpt -hlen+1; // ptr to lowest bin of the current tone
// compute tone loglikelihood as a weighted sum of bins loglikelihoods
loglh = 0.f;
for (j=0;j<hlen;j++) {
u = *curbin++ * hptr[j]*cmetric;
u = u*u/(u+(float)M_E); // log(I0(u)) approx.
loglh = loglh + u;
}
for (j=hlen-2;j>=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<QRA64_M;k++) {
u = (float)exp(curix[k]-maxloglh);
curix[k]=u;
sumix +=u;
}
// scale to probabilities
sumix = 1.0f/sumix;
for (k=0;k<QRA64_M;k++)
curix[k] = curix[k]*sumix;
}
}
static float qra64_fastfading_msg_esno(
const int *ydec,
const float *rxamp,
const float sigma,
const float EsNoMetric,
const int hlen,
const int submode)
{
// Estimate msg Es/N0
int n,j, bps, bpt;
const float *cursym, *curtone, *curbin;
float u, msgsn,esno;
int tothlen = 2*hlen-1;
bpt = 1<<submode; // bins per tone
bps = QRA64_M*(2+bpt); // bins per symbol
msgsn = 0;
for (n=0;n<QRA64_N;n++) {
cursym = rxamp+n*bps + QRA64_M; // point to n-th symbol amplitudes
curtone = cursym+ydec[n]*bpt; // point to decoded tone amplitudes
curbin = curtone-hlen+1; // point to first bin amplitude
// sum bin energies
for (j=0;j<hlen;j++) {
u = *curbin++;
msgsn += u*u;
}
for (j=hlen-2;j>=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/tot hlen
if (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

View File

@ -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

View File

@ -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