From 11cc9ab579c05d089b4ce849ffa25b67d3a3e98b Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 19 Oct 2018 15:54:20 -0400 Subject: [PATCH 1/4] Relocate the qra64 files. --- libm65/CMakeLists.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/libm65/CMakeLists.txt b/libm65/CMakeLists.txt index baf10a761..983fb6ee3 100644 --- a/libm65/CMakeLists.txt +++ b/libm65/CMakeLists.txt @@ -151,14 +151,15 @@ set (CSRCS usleep.c wrapkarn.c - ../../wsjtx/lib/qra/qra64/qra64.c - ../../wsjtx/lib/qra/qra64/qra64_subs.c - ../../wsjtx/lib/qra/qracodes/npfwht.c - ../../wsjtx/lib/qra/qracodes/pdmath.c - ../../wsjtx/lib/qra/qracodes/qra12_63_64_irr_b.c - ../../wsjtx/lib/qra/qracodes/qra13_64_64_irr_e.c - ../../wsjtx/lib/qra/qracodes/qracodes.c - ../../wsjtx/lib/qra/qracodes/normrnd.c + qra64/qra64.c + qra64/qra64_subs.c + qracodes/npfwht.c + qracodes/pdmath.c + qracodes/qra12_63_64_irr_b.c + qracodes/qra13_64_64_irr_e.c + qracodes/qracodes.c + qracodes/normrnd.c + ) if (WIN32) From 436daf17b0f61ac0ef7686f9ae28807684f9ea42 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 19 Oct 2018 15:55:29 -0400 Subject: [PATCH 2/4] Add the qra64 files. --- libm65/qra64/Makefile.Win | 30 + libm65/qra64/fadengauss.c | 302 ++++++++ libm65/qra64/fadenlorentz.c | 304 ++++++++ libm65/qra64/main.c | 746 ++++++++++++++++++ libm65/qra64/qra64.c | 1121 +++++++++++++++++++++++++++ libm65/qra64/qra64.h | 269 +++++++ libm65/qra64/qra64_all.c | 1050 +++++++++++++++++++++++++ libm65/qra64/qra64_subs.c | 65 ++ libm65/qra64/qra64example.txt | 88 +++ libm65/qra64/qra64sim.f90 | 170 ++++ libm65/qracodes/Makefile.Win | 33 + libm65/qracodes/ebno10000.txt | 7 + libm65/qracodes/ebnovalues.txt | 15 + libm65/qracodes/ebnovaluesfast.txt | 11 + libm65/qracodes/main.c | 737 ++++++++++++++++++ libm65/qracodes/normrnd.c | 82 ++ libm65/qracodes/normrnd.h | 51 ++ libm65/qracodes/npfwht.c | 216 ++++++ libm65/qracodes/npfwht.h | 45 ++ libm65/qracodes/pdmath.c | 385 +++++++++ libm65/qracodes/pdmath.h | 85 ++ libm65/qracodes/qra12_63_64_irr_b.c | 534 +++++++++++++ libm65/qracodes/qra12_63_64_irr_b.h | 39 + libm65/qracodes/qra13_64_64_irr_e.c | 534 +++++++++++++ libm65/qracodes/qra13_64_64_irr_e.h | 39 + libm65/qracodes/qracodes.c | 474 +++++++++++ libm65/qracodes/qracodes.h | 79 ++ 27 files changed, 7511 insertions(+) create mode 100644 libm65/qra64/Makefile.Win create mode 100644 libm65/qra64/fadengauss.c create mode 100644 libm65/qra64/fadenlorentz.c create mode 100644 libm65/qra64/main.c create mode 100644 libm65/qra64/qra64.c create mode 100644 libm65/qra64/qra64.h create mode 100644 libm65/qra64/qra64_all.c create mode 100644 libm65/qra64/qra64_subs.c create mode 100644 libm65/qra64/qra64example.txt create mode 100644 libm65/qra64/qra64sim.f90 create mode 100644 libm65/qracodes/Makefile.Win create mode 100644 libm65/qracodes/ebno10000.txt create mode 100644 libm65/qracodes/ebnovalues.txt create mode 100644 libm65/qracodes/ebnovaluesfast.txt create mode 100644 libm65/qracodes/main.c create mode 100644 libm65/qracodes/normrnd.c create mode 100644 libm65/qracodes/normrnd.h create mode 100644 libm65/qracodes/npfwht.c create mode 100644 libm65/qracodes/npfwht.h create mode 100644 libm65/qracodes/pdmath.c create mode 100644 libm65/qracodes/pdmath.h create mode 100644 libm65/qracodes/qra12_63_64_irr_b.c create mode 100644 libm65/qracodes/qra12_63_64_irr_b.h create mode 100644 libm65/qracodes/qra13_64_64_irr_e.c create mode 100644 libm65/qracodes/qra13_64_64_irr_e.h create mode 100644 libm65/qracodes/qracodes.c create mode 100644 libm65/qracodes/qracodes.h diff --git a/libm65/qra64/Makefile.Win b/libm65/qra64/Makefile.Win new file mode 100644 index 000000000..7bd10c2d1 --- /dev/null +++ b/libm65/qra64/Makefile.Win @@ -0,0 +1,30 @@ +FC = gfortran +CC = gcc +CFLAGS = -O2 -Wall -I. -D_WIN32 + +# Default rules +%.o: %.c + ${CC} ${CFLAGS} -c $< +%.o: %.f + ${FC} ${FFLAGS} -c $< +%.o: %.F + ${FC} ${FFLAGS} -c $< +%.o: %.f90 + ${FC} ${FFLAGS} -c $< +%.o: %.F90 + ${FC} ${FFLAGS} -c $< + +all: qra64.exe + +OBJS1 = main.o qra64.o +qra64.exe: $(OBJS1) + ${CC} -o qra64.exe $(OBJS1) ../qracodes/libqra64.a -lm + +OBJS2 = qra64sim.o options.o wavhdr.o +qra64sim.exe: $(OBJS2) + ${FC} -o qra64sim.exe $(OBJS2) ../qracodes/libqra64.a -lm + +.PHONY : clean + +clean: + $(RM) *.o qra64.exe qra64sim.exe diff --git a/libm65/qra64/fadengauss.c b/libm65/qra64/fadengauss.c new file mode 100644 index 000000000..f6ca27253 --- /dev/null +++ b/libm65/qra64/fadengauss.c @@ -0,0 +1,302 @@ +// Gaussian energy fading tables for QRA64 +static const int glen_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 ggauss1[2] = { +0.0296f, 0.9101f +}; +static const float ggauss2[2] = { +0.0350f, 0.8954f +}; +static const float ggauss3[2] = { +0.0411f, 0.8787f +}; +static const float ggauss4[2] = { +0.0483f, 0.8598f +}; +static const float ggauss5[2] = { +0.0566f, 0.8387f +}; +static const float ggauss6[2] = { +0.0660f, 0.8154f +}; +static const float ggauss7[2] = { +0.0767f, 0.7898f +}; +static const float ggauss8[2] = { +0.0886f, 0.7621f +}; +static const float ggauss9[2] = { +0.1017f, 0.7325f +}; +static const float ggauss10[2] = { +0.1159f, 0.7012f +}; +static const float ggauss11[2] = { +0.1310f, 0.6687f +}; +static const float ggauss12[2] = { +0.1465f, 0.6352f +}; +static const float ggauss13[2] = { +0.1621f, 0.6013f +}; +static const float ggauss14[2] = { +0.1771f, 0.5674f +}; +static const float ggauss15[2] = { +0.1911f, 0.5339f +}; +static const float ggauss16[2] = { +0.2034f, 0.5010f +}; +static const float ggauss17[3] = { +0.0299f, 0.2135f, 0.4690f +}; +static const float ggauss18[3] = { +0.0369f, 0.2212f, 0.4383f +}; +static const float ggauss19[3] = { +0.0454f, 0.2263f, 0.4088f +}; +static const float ggauss20[3] = { +0.0552f, 0.2286f, 0.3806f +}; +static const float ggauss21[3] = { +0.0658f, 0.2284f, 0.3539f +}; +static const float ggauss22[3] = { +0.0766f, 0.2258f, 0.3287f +}; +static const float ggauss23[3] = { +0.0869f, 0.2212f, 0.3049f +}; +static const float ggauss24[3] = { +0.0962f, 0.2148f, 0.2826f +}; +static const float ggauss25[4] = { +0.0351f, 0.1041f, 0.2071f, 0.2616f +}; +static const float ggauss26[4] = { +0.0429f, 0.1102f, 0.1984f, 0.2420f +}; +static const float ggauss27[4] = { +0.0508f, 0.1145f, 0.1890f, 0.2237f +}; +static const float ggauss28[4] = { +0.0582f, 0.1169f, 0.1791f, 0.2067f +}; +static const float ggauss29[5] = { +0.0289f, 0.0648f, 0.1176f, 0.1689f, 0.1908f +}; +static const float ggauss30[5] = { +0.0351f, 0.0703f, 0.1168f, 0.1588f, 0.1760f +}; +static const float ggauss31[5] = { +0.0411f, 0.0745f, 0.1146f, 0.1488f, 0.1623f +}; +static const float ggauss32[6] = { +0.0246f, 0.0466f, 0.0773f, 0.1115f, 0.1390f, 0.1497f +}; +static const float ggauss33[6] = { +0.0297f, 0.0512f, 0.0788f, 0.1075f, 0.1295f, 0.1379f +}; +static const float ggauss34[6] = { +0.0345f, 0.0549f, 0.0791f, 0.1029f, 0.1205f, 0.1270f +}; +static const float ggauss35[7] = { +0.0240f, 0.0387f, 0.0575f, 0.0784f, 0.0979f, 0.1118f, 0.1169f +}; +static const float ggauss36[7] = { +0.0281f, 0.0422f, 0.0590f, 0.0767f, 0.0926f, 0.1037f, 0.1076f +}; +static const float ggauss37[8] = { +0.0212f, 0.0318f, 0.0449f, 0.0596f, 0.0744f, 0.0872f, 0.0960f, 0.0991f +}; +static const float ggauss38[8] = { +0.0247f, 0.0348f, 0.0467f, 0.0593f, 0.0716f, 0.0819f, 0.0887f, 0.0911f +}; +static const float ggauss39[9] = { +0.0199f, 0.0278f, 0.0372f, 0.0476f, 0.0584f, 0.0684f, 0.0766f, 0.0819f, +0.0838f +}; +static const float ggauss40[10] = { +0.0166f, 0.0228f, 0.0303f, 0.0388f, 0.0478f, 0.0568f, 0.0649f, 0.0714f, +0.0756f, 0.0771f +}; +static const float ggauss41[10] = { +0.0193f, 0.0254f, 0.0322f, 0.0397f, 0.0474f, 0.0548f, 0.0613f, 0.0664f, +0.0697f, 0.0709f +}; +static const float ggauss42[11] = { +0.0168f, 0.0217f, 0.0273f, 0.0335f, 0.0399f, 0.0464f, 0.0524f, 0.0576f, +0.0617f, 0.0643f, 0.0651f +}; +static const float ggauss43[12] = { +0.0151f, 0.0191f, 0.0237f, 0.0288f, 0.0342f, 0.0396f, 0.0449f, 0.0498f, +0.0540f, 0.0572f, 0.0592f, 0.0599f +}; +static const float ggauss44[13] = { +0.0138f, 0.0171f, 0.0210f, 0.0252f, 0.0297f, 0.0343f, 0.0388f, 0.0432f, +0.0471f, 0.0504f, 0.0529f, 0.0545f, 0.0550f +}; +static const float ggauss45[14] = { +0.0128f, 0.0157f, 0.0189f, 0.0224f, 0.0261f, 0.0300f, 0.0339f, 0.0377f, +0.0412f, 0.0444f, 0.0470f, 0.0489f, 0.0501f, 0.0505f +}; +static const float ggauss46[15] = { +0.0121f, 0.0146f, 0.0173f, 0.0202f, 0.0234f, 0.0266f, 0.0299f, 0.0332f, +0.0363f, 0.0391f, 0.0416f, 0.0437f, 0.0452f, 0.0461f, 0.0464f +}; +static const float ggauss47[17] = { +0.0097f, 0.0116f, 0.0138f, 0.0161f, 0.0186f, 0.0212f, 0.0239f, 0.0267f, +0.0294f, 0.0321f, 0.0346f, 0.0369f, 0.0389f, 0.0405f, 0.0417f, 0.0424f, +0.0427f +}; +static const float ggauss48[18] = { +0.0096f, 0.0113f, 0.0131f, 0.0151f, 0.0172f, 0.0194f, 0.0217f, 0.0241f, +0.0264f, 0.0287f, 0.0308f, 0.0329f, 0.0347f, 0.0362f, 0.0375f, 0.0384f, +0.0390f, 0.0392f +}; +static const float ggauss49[19] = { +0.0095f, 0.0110f, 0.0126f, 0.0143f, 0.0161f, 0.0180f, 0.0199f, 0.0219f, +0.0239f, 0.0258f, 0.0277f, 0.0294f, 0.0310f, 0.0325f, 0.0337f, 0.0347f, +0.0354f, 0.0358f, 0.0360f +}; +static const float ggauss50[21] = { +0.0083f, 0.0095f, 0.0108f, 0.0122f, 0.0136f, 0.0152f, 0.0168f, 0.0184f, +0.0201f, 0.0217f, 0.0234f, 0.0250f, 0.0265f, 0.0279f, 0.0292f, 0.0303f, +0.0313f, 0.0320f, 0.0326f, 0.0329f, 0.0330f +}; +static const float ggauss51[23] = { +0.0074f, 0.0084f, 0.0095f, 0.0106f, 0.0118f, 0.0131f, 0.0144f, 0.0157f, +0.0171f, 0.0185f, 0.0199f, 0.0213f, 0.0227f, 0.0240f, 0.0252f, 0.0263f, +0.0273f, 0.0282f, 0.0290f, 0.0296f, 0.0300f, 0.0303f, 0.0303f +}; +static const float ggauss52[25] = { +0.0068f, 0.0076f, 0.0085f, 0.0094f, 0.0104f, 0.0115f, 0.0126f, 0.0137f, +0.0149f, 0.0160f, 0.0172f, 0.0184f, 0.0196f, 0.0207f, 0.0218f, 0.0228f, +0.0238f, 0.0247f, 0.0255f, 0.0262f, 0.0268f, 0.0273f, 0.0276f, 0.0278f, +0.0279f +}; +static const float ggauss53[27] = { +0.0063f, 0.0070f, 0.0078f, 0.0086f, 0.0094f, 0.0103f, 0.0112f, 0.0121f, +0.0131f, 0.0141f, 0.0151f, 0.0161f, 0.0170f, 0.0180f, 0.0190f, 0.0199f, +0.0208f, 0.0216f, 0.0224f, 0.0231f, 0.0237f, 0.0243f, 0.0247f, 0.0251f, +0.0254f, 0.0255f, 0.0256f +}; +static const float ggauss54[29] = { +0.0060f, 0.0066f, 0.0072f, 0.0079f, 0.0086f, 0.0093f, 0.0101f, 0.0109f, +0.0117f, 0.0125f, 0.0133f, 0.0142f, 0.0150f, 0.0159f, 0.0167f, 0.0175f, +0.0183f, 0.0190f, 0.0197f, 0.0204f, 0.0210f, 0.0216f, 0.0221f, 0.0225f, +0.0228f, 0.0231f, 0.0233f, 0.0234f, 0.0235f +}; +static const float ggauss55[32] = { +0.0053f, 0.0058f, 0.0063f, 0.0068f, 0.0074f, 0.0080f, 0.0086f, 0.0093f, +0.0099f, 0.0106f, 0.0113f, 0.0120f, 0.0127f, 0.0134f, 0.0141f, 0.0148f, +0.0155f, 0.0162f, 0.0168f, 0.0174f, 0.0180f, 0.0186f, 0.0191f, 0.0196f, +0.0201f, 0.0204f, 0.0208f, 0.0211f, 0.0213f, 0.0214f, 0.0215f, 0.0216f +}; +static const float ggauss56[34] = { +0.0052f, 0.0056f, 0.0060f, 0.0065f, 0.0070f, 0.0075f, 0.0080f, 0.0086f, +0.0091f, 0.0097f, 0.0103f, 0.0109f, 0.0115f, 0.0121f, 0.0127f, 0.0133f, +0.0138f, 0.0144f, 0.0150f, 0.0155f, 0.0161f, 0.0166f, 0.0170f, 0.0175f, +0.0179f, 0.0183f, 0.0186f, 0.0189f, 0.0192f, 0.0194f, 0.0196f, 0.0197f, +0.0198f, 0.0198f +}; +static const float ggauss57[37] = { +0.0047f, 0.0051f, 0.0055f, 0.0058f, 0.0063f, 0.0067f, 0.0071f, 0.0076f, +0.0080f, 0.0085f, 0.0090f, 0.0095f, 0.0100f, 0.0105f, 0.0110f, 0.0115f, +0.0120f, 0.0125f, 0.0130f, 0.0134f, 0.0139f, 0.0144f, 0.0148f, 0.0152f, +0.0156f, 0.0160f, 0.0164f, 0.0167f, 0.0170f, 0.0173f, 0.0175f, 0.0177f, +0.0179f, 0.0180f, 0.0181f, 0.0181f, 0.0182f +}; +static const float ggauss58[41] = { +0.0041f, 0.0044f, 0.0047f, 0.0050f, 0.0054f, 0.0057f, 0.0060f, 0.0064f, +0.0068f, 0.0072f, 0.0076f, 0.0080f, 0.0084f, 0.0088f, 0.0092f, 0.0096f, +0.0101f, 0.0105f, 0.0109f, 0.0113f, 0.0117f, 0.0121f, 0.0125f, 0.0129f, +0.0133f, 0.0137f, 0.0140f, 0.0144f, 0.0147f, 0.0150f, 0.0153f, 0.0155f, +0.0158f, 0.0160f, 0.0162f, 0.0163f, 0.0164f, 0.0165f, 0.0166f, 0.0167f, +0.0167f +}; +static const float ggauss59[44] = { +0.0039f, 0.0042f, 0.0044f, 0.0047f, 0.0050f, 0.0053f, 0.0056f, 0.0059f, +0.0062f, 0.0065f, 0.0068f, 0.0072f, 0.0075f, 0.0079f, 0.0082f, 0.0086f, +0.0089f, 0.0093f, 0.0096f, 0.0100f, 0.0104f, 0.0107f, 0.0110f, 0.0114f, +0.0117f, 0.0120f, 0.0124f, 0.0127f, 0.0130f, 0.0132f, 0.0135f, 0.0138f, +0.0140f, 0.0142f, 0.0144f, 0.0146f, 0.0148f, 0.0149f, 0.0150f, 0.0151f, +0.0152f, 0.0153f, 0.0153f, 0.0153f +}; +static const float ggauss60[48] = { +0.0036f, 0.0038f, 0.0040f, 0.0042f, 0.0044f, 0.0047f, 0.0049f, 0.0052f, +0.0055f, 0.0057f, 0.0060f, 0.0063f, 0.0066f, 0.0068f, 0.0071f, 0.0074f, +0.0077f, 0.0080f, 0.0083f, 0.0086f, 0.0089f, 0.0092f, 0.0095f, 0.0098f, +0.0101f, 0.0104f, 0.0107f, 0.0109f, 0.0112f, 0.0115f, 0.0117f, 0.0120f, +0.0122f, 0.0124f, 0.0126f, 0.0128f, 0.0130f, 0.0132f, 0.0134f, 0.0135f, +0.0136f, 0.0137f, 0.0138f, 0.0139f, 0.0140f, 0.0140f, 0.0140f, 0.0140f +}; +static const float ggauss61[52] = { +0.0033f, 0.0035f, 0.0037f, 0.0039f, 0.0041f, 0.0043f, 0.0045f, 0.0047f, +0.0049f, 0.0051f, 0.0053f, 0.0056f, 0.0058f, 0.0060f, 0.0063f, 0.0065f, +0.0068f, 0.0070f, 0.0073f, 0.0075f, 0.0078f, 0.0080f, 0.0083f, 0.0085f, +0.0088f, 0.0090f, 0.0093f, 0.0095f, 0.0098f, 0.0100f, 0.0102f, 0.0105f, +0.0107f, 0.0109f, 0.0111f, 0.0113f, 0.0115f, 0.0116f, 0.0118f, 0.0120f, +0.0121f, 0.0122f, 0.0124f, 0.0125f, 0.0126f, 0.0126f, 0.0127f, 0.0128f, +0.0128f, 0.0129f, 0.0129f, 0.0129f +}; +static const float ggauss62[57] = { +0.0030f, 0.0031f, 0.0033f, 0.0034f, 0.0036f, 0.0038f, 0.0039f, 0.0041f, +0.0043f, 0.0045f, 0.0047f, 0.0048f, 0.0050f, 0.0052f, 0.0054f, 0.0056f, +0.0058f, 0.0060f, 0.0063f, 0.0065f, 0.0067f, 0.0069f, 0.0071f, 0.0073f, +0.0075f, 0.0077f, 0.0080f, 0.0082f, 0.0084f, 0.0086f, 0.0088f, 0.0090f, +0.0092f, 0.0094f, 0.0096f, 0.0097f, 0.0099f, 0.0101f, 0.0103f, 0.0104f, +0.0106f, 0.0107f, 0.0108f, 0.0110f, 0.0111f, 0.0112f, 0.0113f, 0.0114f, +0.0115f, 0.0116f, 0.0116f, 0.0117f, 0.0117f, 0.0118f, 0.0118f, 0.0118f, +0.0118f +}; +static const float ggauss63[62] = { +0.0027f, 0.0029f, 0.0030f, 0.0031f, 0.0032f, 0.0034f, 0.0035f, 0.0037f, +0.0038f, 0.0040f, 0.0041f, 0.0043f, 0.0045f, 0.0046f, 0.0048f, 0.0049f, +0.0051f, 0.0053f, 0.0055f, 0.0056f, 0.0058f, 0.0060f, 0.0062f, 0.0063f, +0.0065f, 0.0067f, 0.0069f, 0.0071f, 0.0072f, 0.0074f, 0.0076f, 0.0078f, +0.0079f, 0.0081f, 0.0083f, 0.0084f, 0.0086f, 0.0088f, 0.0089f, 0.0091f, +0.0092f, 0.0094f, 0.0095f, 0.0096f, 0.0098f, 0.0099f, 0.0100f, 0.0101f, +0.0102f, 0.0103f, 0.0104f, 0.0105f, 0.0105f, 0.0106f, 0.0107f, 0.0107f, +0.0108f, 0.0108f, 0.0108f, 0.0108f, 0.0109f, 0.0109f +}; +static const float ggauss64[65] = { +0.0028f, 0.0029f, 0.0030f, 0.0031f, 0.0032f, 0.0034f, 0.0035f, 0.0036f, +0.0037f, 0.0039f, 0.0040f, 0.0041f, 0.0043f, 0.0044f, 0.0046f, 0.0047f, +0.0048f, 0.0050f, 0.0051f, 0.0053f, 0.0054f, 0.0056f, 0.0057f, 0.0059f, +0.0060f, 0.0062f, 0.0063f, 0.0065f, 0.0066f, 0.0068f, 0.0069f, 0.0071f, +0.0072f, 0.0074f, 0.0075f, 0.0077f, 0.0078f, 0.0079f, 0.0081f, 0.0082f, +0.0083f, 0.0084f, 0.0086f, 0.0087f, 0.0088f, 0.0089f, 0.0090f, 0.0091f, +0.0092f, 0.0093f, 0.0094f, 0.0094f, 0.0095f, 0.0096f, 0.0097f, 0.0097f, +0.0098f, 0.0098f, 0.0099f, 0.0099f, 0.0099f, 0.0099f, 0.0100f, 0.0100f, +0.0100f +}; +static const float *gptr_tab_gauss[64] = { +ggauss1, ggauss2, ggauss3, ggauss4, +ggauss5, ggauss6, ggauss7, ggauss8, +ggauss9, ggauss10, ggauss11, ggauss12, +ggauss13, ggauss14, ggauss15, ggauss16, +ggauss17, ggauss18, ggauss19, ggauss20, +ggauss21, ggauss22, ggauss23, ggauss24, +ggauss25, ggauss26, ggauss27, ggauss28, +ggauss29, ggauss30, ggauss31, ggauss32, +ggauss33, ggauss34, ggauss35, ggauss36, +ggauss37, ggauss38, ggauss39, ggauss40, +ggauss41, ggauss42, ggauss43, ggauss44, +ggauss45, ggauss46, ggauss47, ggauss48, +ggauss49, ggauss50, ggauss51, ggauss52, +ggauss53, ggauss54, ggauss55, ggauss56, +ggauss57, ggauss58, ggauss59, ggauss60, +ggauss61, ggauss62, ggauss63, ggauss64 +}; diff --git a/libm65/qra64/fadenlorentz.c b/libm65/qra64/fadenlorentz.c new file mode 100644 index 000000000..22329f65e --- /dev/null +++ b/libm65/qra64/fadenlorentz.c @@ -0,0 +1,304 @@ +// Lorentz energy fading tables for QRA64 +static const int glen_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 glorentz1[2] = { +0.0214f, 0.9107f +}; +static const float glorentz2[2] = { +0.0244f, 0.9030f +}; +static const float glorentz3[2] = { +0.0280f, 0.8950f +}; +static const float glorentz4[2] = { +0.0314f, 0.8865f +}; +static const float glorentz5[2] = { +0.0349f, 0.8773f +}; +static const float glorentz6[2] = { +0.0388f, 0.8675f +}; +static const float glorentz7[2] = { +0.0426f, 0.8571f +}; +static const float glorentz8[2] = { +0.0463f, 0.8459f +}; +static const float glorentz9[2] = { +0.0500f, 0.8339f +}; +static const float glorentz10[2] = { +0.0538f, 0.8210f +}; +static const float glorentz11[2] = { +0.0579f, 0.8074f +}; +static const float glorentz12[2] = { +0.0622f, 0.7930f +}; +static const float glorentz13[2] = { +0.0668f, 0.7777f +}; +static const float glorentz14[2] = { +0.0715f, 0.7616f +}; +static const float glorentz15[3] = { +0.0196f, 0.0765f, 0.7445f +}; +static const float glorentz16[3] = { +0.0210f, 0.0816f, 0.7267f +}; +static const float glorentz17[3] = { +0.0226f, 0.0870f, 0.7080f +}; +static const float glorentz18[3] = { +0.0242f, 0.0925f, 0.6885f +}; +static const float glorentz19[3] = { +0.0259f, 0.0981f, 0.6682f +}; +static const float glorentz20[3] = { +0.0277f, 0.1039f, 0.6472f +}; +static const float glorentz21[3] = { +0.0296f, 0.1097f, 0.6255f +}; +static const float glorentz22[4] = { +0.0143f, 0.0316f, 0.1155f, 0.6031f +}; +static const float glorentz23[4] = { +0.0153f, 0.0337f, 0.1213f, 0.5803f +}; +static const float glorentz24[4] = { +0.0163f, 0.0358f, 0.1270f, 0.5570f +}; +static const float glorentz25[4] = { +0.0174f, 0.0381f, 0.1325f, 0.5333f +}; +static const float glorentz26[4] = { +0.0186f, 0.0405f, 0.1378f, 0.5095f +}; +static const float glorentz27[5] = { +0.0113f, 0.0198f, 0.0429f, 0.1428f, 0.4855f +}; +static const float glorentz28[5] = { +0.0120f, 0.0211f, 0.0455f, 0.1473f, 0.4615f +}; +static const float glorentz29[5] = { +0.0129f, 0.0225f, 0.0481f, 0.1514f, 0.4376f +}; +static const float glorentz30[5] = { +0.0137f, 0.0239f, 0.0508f, 0.1549f, 0.4140f +}; +static const float glorentz31[6] = { +0.0095f, 0.0147f, 0.0254f, 0.0536f, 0.1578f, 0.3907f +}; +static const float glorentz32[6] = { +0.0101f, 0.0156f, 0.0270f, 0.0564f, 0.1600f, 0.3680f +}; +static const float glorentz33[7] = { +0.0076f, 0.0109f, 0.0167f, 0.0287f, 0.0592f, 0.1614f, 0.3458f +}; +static const float glorentz34[7] = { +0.0081f, 0.0116f, 0.0178f, 0.0305f, 0.0621f, 0.1620f, 0.3243f +}; +static const float glorentz35[7] = { +0.0087f, 0.0124f, 0.0190f, 0.0324f, 0.0649f, 0.1618f, 0.3035f +}; +static const float glorentz36[8] = { +0.0069f, 0.0093f, 0.0133f, 0.0203f, 0.0343f, 0.0676f, 0.1607f, 0.2836f +}; +static const float glorentz37[8] = { +0.0074f, 0.0100f, 0.0142f, 0.0216f, 0.0362f, 0.0702f, 0.1588f, 0.2645f +}; +static const float glorentz38[9] = { +0.0061f, 0.0080f, 0.0107f, 0.0152f, 0.0230f, 0.0382f, 0.0726f, 0.1561f, +0.2464f +}; +static const float glorentz39[10] = { +0.0052f, 0.0066f, 0.0086f, 0.0115f, 0.0162f, 0.0244f, 0.0402f, 0.0747f, +0.1526f, 0.2291f +}; +static const float glorentz40[10] = { +0.0056f, 0.0071f, 0.0092f, 0.0123f, 0.0173f, 0.0259f, 0.0422f, 0.0766f, +0.1484f, 0.2128f +}; +static const float glorentz41[11] = { +0.0049f, 0.0061f, 0.0076f, 0.0098f, 0.0132f, 0.0184f, 0.0274f, 0.0441f, +0.0780f, 0.1437f, 0.1975f +}; +static const float glorentz42[12] = { +0.0044f, 0.0053f, 0.0065f, 0.0082f, 0.0106f, 0.0141f, 0.0196f, 0.0290f, +0.0460f, 0.0791f, 0.1384f, 0.1831f +}; +static const float glorentz43[13] = { +0.0040f, 0.0048f, 0.0057f, 0.0070f, 0.0088f, 0.0113f, 0.0150f, 0.0209f, +0.0305f, 0.0477f, 0.0797f, 0.1327f, 0.1695f +}; +static const float glorentz44[14] = { +0.0037f, 0.0043f, 0.0051f, 0.0062f, 0.0075f, 0.0094f, 0.0121f, 0.0160f, +0.0221f, 0.0321f, 0.0493f, 0.0799f, 0.1267f, 0.1568f +}; +static const float glorentz45[15] = { +0.0035f, 0.0040f, 0.0047f, 0.0055f, 0.0066f, 0.0081f, 0.0101f, 0.0129f, +0.0171f, 0.0234f, 0.0335f, 0.0506f, 0.0795f, 0.1204f, 0.1450f +}; +static const float glorentz46[16] = { +0.0033f, 0.0037f, 0.0043f, 0.0050f, 0.0059f, 0.0071f, 0.0087f, 0.0108f, +0.0138f, 0.0181f, 0.0246f, 0.0349f, 0.0517f, 0.0786f, 0.1141f, 0.1340f +}; +static const float glorentz47[17] = { +0.0031f, 0.0035f, 0.0040f, 0.0046f, 0.0054f, 0.0064f, 0.0077f, 0.0093f, +0.0116f, 0.0147f, 0.0192f, 0.0259f, 0.0362f, 0.0525f, 0.0773f, 0.1076f, +0.1237f +}; +static const float glorentz48[19] = { +0.0027f, 0.0030f, 0.0034f, 0.0038f, 0.0043f, 0.0050f, 0.0058f, 0.0069f, +0.0082f, 0.0100f, 0.0123f, 0.0156f, 0.0203f, 0.0271f, 0.0374f, 0.0530f, +0.0755f, 0.1013f, 0.1141f +}; +static const float glorentz49[20] = { +0.0026f, 0.0029f, 0.0032f, 0.0036f, 0.0041f, 0.0047f, 0.0054f, 0.0063f, +0.0074f, 0.0088f, 0.0107f, 0.0131f, 0.0165f, 0.0213f, 0.0282f, 0.0383f, +0.0531f, 0.0734f, 0.0950f, 0.1053f +}; +static const float glorentz50[22] = { +0.0023f, 0.0025f, 0.0028f, 0.0031f, 0.0035f, 0.0039f, 0.0044f, 0.0050f, +0.0058f, 0.0067f, 0.0079f, 0.0094f, 0.0114f, 0.0139f, 0.0175f, 0.0223f, +0.0292f, 0.0391f, 0.0529f, 0.0709f, 0.0889f, 0.0971f +}; +static const float glorentz51[23] = { +0.0023f, 0.0025f, 0.0027f, 0.0030f, 0.0034f, 0.0037f, 0.0042f, 0.0048f, +0.0054f, 0.0062f, 0.0072f, 0.0085f, 0.0100f, 0.0121f, 0.0148f, 0.0184f, +0.0233f, 0.0301f, 0.0396f, 0.0524f, 0.0681f, 0.0829f, 0.0894f +}; +static const float glorentz52[25] = { +0.0021f, 0.0023f, 0.0025f, 0.0027f, 0.0030f, 0.0033f, 0.0036f, 0.0040f, +0.0045f, 0.0051f, 0.0058f, 0.0067f, 0.0077f, 0.0090f, 0.0107f, 0.0128f, +0.0156f, 0.0192f, 0.0242f, 0.0308f, 0.0398f, 0.0515f, 0.0650f, 0.0772f, +0.0824f +}; +static const float glorentz53[27] = { +0.0019f, 0.0021f, 0.0022f, 0.0024f, 0.0027f, 0.0029f, 0.0032f, 0.0035f, +0.0039f, 0.0044f, 0.0049f, 0.0055f, 0.0062f, 0.0072f, 0.0083f, 0.0096f, +0.0113f, 0.0135f, 0.0164f, 0.0201f, 0.0249f, 0.0314f, 0.0398f, 0.0502f, +0.0619f, 0.0718f, 0.0759f +}; +static const float glorentz54[30] = { +0.0017f, 0.0018f, 0.0019f, 0.0021f, 0.0022f, 0.0024f, 0.0026f, 0.0029f, +0.0031f, 0.0034f, 0.0038f, 0.0042f, 0.0047f, 0.0052f, 0.0059f, 0.0067f, +0.0076f, 0.0088f, 0.0102f, 0.0120f, 0.0143f, 0.0171f, 0.0208f, 0.0256f, +0.0317f, 0.0395f, 0.0488f, 0.0586f, 0.0666f, 0.0698f +}; +static const float glorentz55[32] = { +0.0016f, 0.0017f, 0.0018f, 0.0019f, 0.0021f, 0.0022f, 0.0024f, 0.0026f, +0.0028f, 0.0031f, 0.0034f, 0.0037f, 0.0041f, 0.0045f, 0.0050f, 0.0056f, +0.0063f, 0.0071f, 0.0081f, 0.0094f, 0.0108f, 0.0127f, 0.0149f, 0.0178f, +0.0214f, 0.0261f, 0.0318f, 0.0389f, 0.0470f, 0.0553f, 0.0618f, 0.0643f +}; +static const float glorentz56[35] = { +0.0014f, 0.0015f, 0.0016f, 0.0017f, 0.0018f, 0.0020f, 0.0021f, 0.0023f, +0.0024f, 0.0026f, 0.0028f, 0.0031f, 0.0033f, 0.0036f, 0.0040f, 0.0044f, +0.0049f, 0.0054f, 0.0060f, 0.0067f, 0.0076f, 0.0087f, 0.0099f, 0.0114f, +0.0133f, 0.0156f, 0.0184f, 0.0220f, 0.0264f, 0.0318f, 0.0381f, 0.0451f, +0.0520f, 0.0572f, 0.0591f +}; +static const float glorentz57[38] = { +0.0013f, 0.0014f, 0.0015f, 0.0016f, 0.0017f, 0.0018f, 0.0019f, 0.0020f, +0.0021f, 0.0023f, 0.0024f, 0.0026f, 0.0028f, 0.0031f, 0.0033f, 0.0036f, +0.0039f, 0.0043f, 0.0047f, 0.0052f, 0.0058f, 0.0064f, 0.0072f, 0.0081f, +0.0092f, 0.0104f, 0.0120f, 0.0139f, 0.0162f, 0.0190f, 0.0224f, 0.0265f, +0.0315f, 0.0371f, 0.0431f, 0.0487f, 0.0529f, 0.0544f +}; +static const float glorentz58[41] = { +0.0012f, 0.0013f, 0.0014f, 0.0014f, 0.0015f, 0.0016f, 0.0017f, 0.0018f, +0.0019f, 0.0020f, 0.0022f, 0.0023f, 0.0025f, 0.0026f, 0.0028f, 0.0030f, +0.0033f, 0.0036f, 0.0039f, 0.0042f, 0.0046f, 0.0050f, 0.0056f, 0.0061f, +0.0068f, 0.0076f, 0.0086f, 0.0097f, 0.0110f, 0.0125f, 0.0144f, 0.0167f, +0.0194f, 0.0226f, 0.0265f, 0.0309f, 0.0359f, 0.0409f, 0.0455f, 0.0488f, +0.0500f +}; +static const float glorentz59[45] = { +0.0011f, 0.0012f, 0.0012f, 0.0013f, 0.0013f, 0.0014f, 0.0015f, 0.0016f, +0.0016f, 0.0017f, 0.0018f, 0.0019f, 0.0021f, 0.0022f, 0.0023f, 0.0025f, +0.0026f, 0.0028f, 0.0030f, 0.0033f, 0.0035f, 0.0038f, 0.0041f, 0.0045f, +0.0049f, 0.0054f, 0.0059f, 0.0065f, 0.0072f, 0.0081f, 0.0090f, 0.0102f, +0.0115f, 0.0130f, 0.0149f, 0.0171f, 0.0197f, 0.0227f, 0.0263f, 0.0302f, +0.0345f, 0.0387f, 0.0425f, 0.0451f, 0.0460f +}; +static const float glorentz60[49] = { +0.0010f, 0.0011f, 0.0011f, 0.0012f, 0.0012f, 0.0013f, 0.0013f, 0.0014f, +0.0014f, 0.0015f, 0.0016f, 0.0017f, 0.0018f, 0.0019f, 0.0020f, 0.0021f, +0.0022f, 0.0024f, 0.0025f, 0.0027f, 0.0028f, 0.0030f, 0.0033f, 0.0035f, +0.0038f, 0.0041f, 0.0044f, 0.0048f, 0.0052f, 0.0057f, 0.0063f, 0.0069f, +0.0077f, 0.0085f, 0.0095f, 0.0106f, 0.0119f, 0.0135f, 0.0153f, 0.0174f, +0.0199f, 0.0227f, 0.0259f, 0.0293f, 0.0330f, 0.0365f, 0.0395f, 0.0415f, +0.0423f +}; +static const float glorentz61[53] = { +0.0009f, 0.0010f, 0.0010f, 0.0011f, 0.0011f, 0.0011f, 0.0012f, 0.0012f, +0.0013f, 0.0014f, 0.0014f, 0.0015f, 0.0016f, 0.0016f, 0.0017f, 0.0018f, +0.0019f, 0.0020f, 0.0021f, 0.0023f, 0.0024f, 0.0025f, 0.0027f, 0.0029f, +0.0031f, 0.0033f, 0.0035f, 0.0038f, 0.0041f, 0.0044f, 0.0047f, 0.0051f, +0.0056f, 0.0061f, 0.0067f, 0.0073f, 0.0081f, 0.0089f, 0.0099f, 0.0110f, +0.0124f, 0.0139f, 0.0156f, 0.0176f, 0.0199f, 0.0225f, 0.0253f, 0.0283f, +0.0314f, 0.0343f, 0.0367f, 0.0383f, 0.0389f +}; +static const float glorentz62[57] = { +0.0009f, 0.0009f, 0.0009f, 0.0010f, 0.0010f, 0.0011f, 0.0011f, 0.0011f, +0.0012f, 0.0012f, 0.0013f, 0.0013f, 0.0014f, 0.0015f, 0.0015f, 0.0016f, +0.0017f, 0.0018f, 0.0019f, 0.0020f, 0.0021f, 0.0022f, 0.0023f, 0.0024f, +0.0026f, 0.0027f, 0.0029f, 0.0031f, 0.0033f, 0.0035f, 0.0038f, 0.0040f, +0.0043f, 0.0047f, 0.0050f, 0.0055f, 0.0059f, 0.0064f, 0.0070f, 0.0077f, +0.0085f, 0.0093f, 0.0103f, 0.0114f, 0.0127f, 0.0142f, 0.0158f, 0.0177f, +0.0198f, 0.0221f, 0.0246f, 0.0272f, 0.0297f, 0.0321f, 0.0340f, 0.0353f, +0.0357f +}; +static const float glorentz63[62] = { +0.0008f, 0.0008f, 0.0009f, 0.0009f, 0.0009f, 0.0010f, 0.0010f, 0.0010f, +0.0011f, 0.0011f, 0.0011f, 0.0012f, 0.0012f, 0.0013f, 0.0013f, 0.0014f, +0.0015f, 0.0015f, 0.0016f, 0.0017f, 0.0017f, 0.0018f, 0.0019f, 0.0020f, +0.0021f, 0.0022f, 0.0023f, 0.0025f, 0.0026f, 0.0028f, 0.0029f, 0.0031f, +0.0033f, 0.0035f, 0.0038f, 0.0040f, 0.0043f, 0.0046f, 0.0050f, 0.0053f, +0.0058f, 0.0062f, 0.0068f, 0.0074f, 0.0081f, 0.0088f, 0.0097f, 0.0106f, +0.0117f, 0.0130f, 0.0144f, 0.0159f, 0.0176f, 0.0195f, 0.0216f, 0.0237f, +0.0259f, 0.0280f, 0.0299f, 0.0315f, 0.0325f, 0.0328f +}; +static const float glorentz64[65] = { +0.0008f, 0.0008f, 0.0008f, 0.0009f, 0.0009f, 0.0009f, 0.0010f, 0.0010f, +0.0010f, 0.0011f, 0.0011f, 0.0012f, 0.0012f, 0.0012f, 0.0013f, 0.0013f, +0.0014f, 0.0014f, 0.0015f, 0.0016f, 0.0016f, 0.0017f, 0.0018f, 0.0019f, +0.0020f, 0.0021f, 0.0022f, 0.0023f, 0.0024f, 0.0025f, 0.0027f, 0.0028f, +0.0030f, 0.0031f, 0.0033f, 0.0035f, 0.0038f, 0.0040f, 0.0043f, 0.0046f, +0.0049f, 0.0052f, 0.0056f, 0.0061f, 0.0066f, 0.0071f, 0.0077f, 0.0084f, +0.0091f, 0.0100f, 0.0109f, 0.0120f, 0.0132f, 0.0145f, 0.0159f, 0.0175f, +0.0192f, 0.0209f, 0.0228f, 0.0246f, 0.0264f, 0.0279f, 0.0291f, 0.0299f, +0.0301f +}; +static const float *gptr_tab_lorentz[64] = { +glorentz1, glorentz2, glorentz3, glorentz4, +glorentz5, glorentz6, glorentz7, glorentz8, +glorentz9, glorentz10, glorentz11, glorentz12, +glorentz13, glorentz14, glorentz15, glorentz16, +glorentz17, glorentz18, glorentz19, glorentz20, +glorentz21, glorentz22, glorentz23, glorentz24, +glorentz25, glorentz26, glorentz27, glorentz28, +glorentz29, glorentz30, glorentz31, glorentz32, +glorentz33, glorentz34, glorentz35, glorentz36, +glorentz37, glorentz38, glorentz39, glorentz40, +glorentz41, glorentz42, glorentz43, glorentz44, +glorentz45, glorentz46, glorentz47, glorentz48, +glorentz49, glorentz50, glorentz51, glorentz52, +glorentz53, glorentz54, glorentz55, glorentz56, +glorentz57, glorentz58, glorentz59, glorentz60, +glorentz61, glorentz62, glorentz63, glorentz64 +}; diff --git a/libm65/qra64/main.c b/libm65/qra64/main.c new file mode 100644 index 000000000..b685fd316 --- /dev/null +++ b/libm65/qra64/main.c @@ -0,0 +1,746 @@ +/* +main.c +QRA64 mode encode/decode tests + +(c) 2016 - Nico Palermo, IV3NWV + +Thanks to Andrea Montefusco IW0HDV for his help on adapting the sources +to OSs other than MS Windows + +------------------------------------------------------------------------------ +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. + +Files in this package: + main.c - this file + qra64.c/.h - qra64 mode encode/decoding functions + + ../qracodes/normrnd.{c,h} - random gaussian number generator + ../qracodes/npfwht.{c,h} - Fast Walsh-Hadamard Transforms + ../qracodes/pdmath.{c,h} - Elementary math on probability distributions + ../qracodes/qra12_63_64_irr_b.{c,h} - Tables for a QRA(12,63) irregular RA + code over GF(64) + ../qracodes/qra13_64_64_irr_e.{c,h} - Tables for a QRA(13,64) irregular RA + code over GF(64) + ../qracodes/qracodes.{c,h} - QRA codes encoding/decoding functions + +------------------------------------------------------------------------------- + + 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 . + +----------------------------------------------------------------------------- + +The code used by the QRA64 mode is the code: QRA13_64_64_IRR_E: K=13 +N=64 Q=64 irregular QRA code (defined in qra13_64_64_irr_e.{h,c}). + +This code has been designed to include a CRC as the 13th information +symbol and improve the code UER (Undetected Error Rate). The CRC +symbol is not sent along the channel (the codes are punctured) and the +resulting code is still a (12,63) code with an effective code rate of +R = 12/63. +*/ + +// OS dependent defines and includes ------------------------------------------ + +#if _WIN32 // note the underscore: without it, it's not msdn official! +// Windows (x64 and x86) +#include // required only for GetTickCount(...) +#include // _beginthread +#endif + +#if __linux__ +#include +#include + +unsigned GetTickCount(void) { + struct timespec ts; + unsigned theTick = 0U; + clock_gettime( CLOCK_REALTIME, &ts ); + theTick = ts.tv_nsec / 1000000; + theTick += ts.tv_sec * 1000; + return theTick; +} +#endif + +#if __APPLE__ +#endif + +#include +#include +#include + +#include "qra64.h" +#include "../qracodes/normrnd.h" // gaussian numbers generator + +// ---------------------------------------------------------------------------- + +// channel types +#define CHANNEL_AWGN 0 +#define CHANNEL_RAYLEIGH 1 +#define CHANNEL_FASTFADE 2 + +#define JT65_SNR_EBNO_OFFSET 29.1f // with the synch used in JT65 +#define QRA64_SNR_EBNO_OFFSET 31.0f // with the costas array synch + +void printwordd(char *msg, int *x, int size) +{ + int k; + printf("\n%s ",msg); + for (k=0;k-15) + if (channel_type == CHANNEL_AWGN) + for (k=0;k=0) { // decoded + printf("K1JT rx: received with apcode=%d %s\n",rc, decode_type[rc]); + +// Step 2a: K1JT replies to IV3NWV (with no grid) + printf("K1JT tx: IV3NWV K1JT\n"); + encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT, GRID_BLANK); + qra64_encode(codec_k1jt, y, x); + rx = mfskchannel(y,channel_type,EbNodB); + +// Step 2b: IV3NWV attempts to decode [? ? ?], [IV3NWV ? ?] or [IV3NWV ?] + rc = qra64_decode(codec_iv3nwv, 0, xdec,rx); + if (rc>=0) { // decoded + printf("IV3NWV rx: received with apcode=%d %s\n",rc, decode_type[rc]); + +// Step 3a: IV3NWV replies to K1JT with a 73 + printf("IV3NWV tx: K1JT IV3NWV 73\n"); + encodemsg_jt65(x,CALL_K1JT,CALL_IV3NWV, GRID_73); + qra64_encode(codec_iv3nwv, y, x); + rx = mfskchannel(y,channel_type,EbNodB); + +// Step 3b: K1JT attempts to decode [? ? ?] or [K1JT IV3NWV ?] + rc = qra64_decode(codec_k1jt, 0, xdec,rx); + if (rc>=0) { // decoded + printf("K1JT rx: received with apcode=%d %s\n",rc, decode_type[rc]); + +// Step 4a: K1JT replies to IV3NWV with a 73 + printf("K1JT tx: IV3NWV K1JT 73\n"); + encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT, GRID_73); + qra64_encode(codec_k1jt, y, x); + rx = mfskchannel(y,channel_type,EbNodB); + +// Step 4b: IV3NWV attempts to decode [? ? ?], [IV3NWV ? ?], or [IV3NWV ?] + rc = qra64_decode(codec_iv3nwv, 0, xdec,rx); + if (rc>=0) { // decoded + printf("IV3NWV rx: received with apcode=%d %s\n",rc, decode_type[rc]); + return 0; + } + } + } + } + printf("no decode\n"); + return -1; +} + +int test_proc_2(int channel_type, float EbNodB, int mode) +{ +/* +Here we simulate the decoder of K1JT after K1JT has sent a msg [IV3NWV K1JT] +and IV3NWV sends him the msg [K1JT IV3NWV JN66]. + +If mode=QRA_NOAP, K1JT decoder attempts to decode only msgs of type [? ? ?]. + +If mode=QRA_AUTOP, K1JT decoder will attempt to decode also the msgs +[K1JT IV3NWV] and [K1JT IV3NWV ?]. + +In the case a decode is successful the return code of the qra64_decode function +indicates the amount of a-priori information required to decode the received +message according to this table: + + rc=0 [? ? ?] AP0 + rc=1 [CQ ? ?] AP27 + rc=2 [CQ ? ] AP42 + rc=3 [CALL ? ?] AP29 + rc=4 [CALL ? ] AP44 + rc=5 [CALL CALL ?] AP57 + rc=6 [? CALL ?] AP29 + rc=7 [? CALL ] AP44 + rc=8 [CALL CALL GRID] AP72 + rc=9 [CQ CALL ?] AP55 + rc=10 [CQ CALL ] AP70 + rc=11 [CQ CALL GRID] AP70 + +The return code is <0 when decoding is unsuccessful + +This test simulates the situation ntx times and reports how many times +a particular type decode among the above 6 cases succeded. +*/ + + 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 = 200,ndec=0; + + qra64codec *codec_iv3nwv = qra64_init(mode); // codec for IV3NWV + qra64codec *codec_k1jt = qra64_init(mode); // codec for K1JT + + printf("\nQRA64 Test #2 - Decoding with AP knowledge (SNR-Eb/No offset = %.1f dB)\n\n", + 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); + +// 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); + + + // Dx station IV3NWV calls + 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); + + printf("Simulating K1JT decoder up to AP72\n"); + + 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; +} + +int test_fastfading(float EbNodB, float B90, int fadingModel, int submode, int apmode, int olddec, int channel_type, int ntx) +{ + int x[QRA64_K], xdec[QRA64_K]; + int y[QRA64_N]; + float *rx; + float ebnodbest, ebnodbavg=0; + int rc,k; + float rxolddec[QRA64_N*QRA64_M]; // holds the energies at nominal tone freqs + + int ndecok[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int nundet = 0; + int ndec=0; + + qra64codec *codec_iv3nwv; + qra64codec *codec_k1jt; + + codec_iv3nwv=qra64_init(QRA_NOAP); + codec_k1jt =qra64_init(apmode); + + if (channel_type==2) { // fast-fading case + printf("Simulating the fast-fading channel\n"); + printf("B90=%.2f Hz - Fading Model=%s - Submode=QRA64%c\n",B90,fadingModel?"Lorentz":"Gauss",submode+'A'); + printf("Decoder metric = %s\n",olddec?"AWGN":"Matched to fast-fading signal"); + } + else { + printf("Simulating the %s channel\n",channel_type?"Rayleigh block fading":"AWGN"); + printf("Decoder metric = AWGN\n"); + } + + + printf("\nEncoding msg [K1JT IV3NWV JN66]\n"); + encodemsg_jt65(x,CALL_K1JT,CALL_IV3NWV,GRID_JN66); +// printf("["); +// for (k=0;k<11;k++) printf("%02hX ",x[k]); printf("%02hX]\n",x[11]); + + qra64_encode(codec_iv3nwv, y, x); + printf("%d transmissions will be simulated\n\n",ntx); + + if (apmode==QRA_USERAP) { + // This will enable K1JT's decoder to look for cq/qrz calls [CQ/QRZ ? ?/b] + printf("K1JT decoder enabled for [CQ ? ?/blank]\n"); + qra64_apset(codec_k1jt, CALL_K1JT,0,0,APTYPE_CQQRZ); + + // 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 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 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); + + // 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("\nNow decoding with K1JT's decoder...\n"); +/* + if (channel_type==2) // simulate a fast-faded signal + printf("Simulating a fast-fading channel with given B90 and spread type\n"); + else + printf("Simulating a %s channel\n",channel_type?"Rayleigh block fading":"AWGN"); +*/ + for (k=0;k=0) { + ebnodbavg +=ebnodbest; + if (memcmp(xdec,x,12*sizeof(int))==0) + ndecok[rc]++; + else { + fprintf(stderr,"\nUndetected error with rc=%d\n",rc); + nundet++; + } + } + + } + printf(" %5.1f %%\r",100.0*k/ntx); + + printf("\n\n"); + + printf("Msgs transmitted:%d\nMsg decoded:\n\n",ntx); + for (k=0;k<12;k++) { + printf("rc=%2d %3d with %s\n",k,ndecok[k],decode_type[k]); + ndec += ndecok[k]; + } + printf("\nTotal: %d/%d (%d undetected errors)\n\n",ndec,ntx,nundet); + printf(""); + + if (ndec>0) { + 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"); + printf("2016, Nico Palermo - IV3NWV\n\n"); + printf("---------------------------\n\n"); + printf("Syntax: qra64 [-s] [-c] [-a] [-t] [-h]\n"); + printf("Options: \n"); + printf(" -s : set simulation SNR in 2500 Hz BW (default:-27.5 dB)\n"); + printf(" -c : set channel type 0=AWGN (default) 1=Rayleigh 2=Fast-fading\n"); + 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/awgn/rayliegh decoders performance\n"); + printf(" -n : simulate the transmission of ntx codewords (default=100)\n"); + + printf("Options used only for fast-fading simulations (-c2):\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(" -d : use the old awgn decoder\n"); + printf(" -h: this help\n"); + printf("Example:\n"); + printf(" qra64 -t2 -c2 -a2 -b50 -m1 -q2 -n10000 -s-26\n"); + printf(" runs the error performance test (-t2)\n"); + printf(" with USER_AP (-a2)\n"); + printf(" simulating a fast fading channel (-c2)\n"); + printf(" with B90 = 50 Hz (-b50), Lorentz Doppler (-m1), mode QRA64C (-q2)\n"); + printf(" ntx = 10000 codewords (-n10000) and SNR = -26 dB (-s-26)\n"); + +} + +int main(int argc, char* argv[]) +{ + int k, rc, nok=0; + float SNRdB = -27.5f; + unsigned int channel = CHANNEL_AWGN; + unsigned int mode = QRA_AUTOAP; + unsigned int testtype=0; + int nqso = 100; + float EbNodB; + float B90 = 2.5; + int fadingModel = 1; + int submode = 0; + int olddec = 0; + int ntx = 100; + +// Parse the command line + while(--argc) { + argv++; + + if (strncmp(*argv,"-h",2)==0) { + syntax(); + return 0; + } + else + if (strncmp(*argv,"-n",2)==0) { + ntx = ( int)atoi((*argv)+2); + if (ntx<100 || ntx>1000000) { + printf("Invalid -n option. ntx must be in the range [100..1000000]\n"); + syntax(); + return -1; + } + } + 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<-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_FASTFADE) { + 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 + if (strncmp(*argv,"-d",2)==0) { + olddec = 1; + } + else { + printf("Invalid option\n"); + syntax(); + return -1; + } + } + + if (testtype<2) // old tests + if (channel==CHANNEL_FASTFADE) { + printf("Invalid Option. Test type 0 and 1 supports only AWGN or Rayleigh Channel model\n"); + return -1; + } + + EbNodB = SNRdB+QRA64_SNR_EBNO_OFFSET; + +#if defined(__linux__) || defined(__unix__) + srand48(GetTickCount()); +#endif + + if (testtype==0) { + for (k=0;k. + +----------------------------------------------------------------------------- + +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) + +Codes with K=13 are designed to include a CRC as the 13th information symbol +and improve the code UER (Undetected Error Rate). +The CRC symbol is not sent along the channel (the codes are punctured) and the +resulting code is a (12,63) code +*/ +//---------------------------------------------------------------------------- + +#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 +#define QRA64_NMSG 218 // Must much value indicated in QRA64_CODE.NMSG + +#define QRA64_KC (QRA64_K+1) // Information symbols (crc included) +#define QRA64_NC (QRA64_N+1) // Codeword length (as defined in the code) +#define QRA64_NITER 100 // max number of iterations per decode + +// static functions declarations ---------------------------------------------- +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_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( + const float *rxen, + const float esnometric, + const int submode); + +static void qra64_fastfading_intrinsics( + float *pix, + const float *rxen, + const float *hptr, + const int hlen, + const float sigma, + const float EsNoMetric, + const int submode); + +static float qra64_fastfading_msg_esno( + const int *ydec, + const float *rxen, + const float sigma, + const float EsNoMetric, + const int hlen, + const int submode); + + +// a-priori information masks for fields in JT65-like msgs -------------------- + +// when defined limits the AP masks to reduce the false decode rate +#define LIMIT_AP_MASKS + +#ifdef LIMIT_AP_MASKS +#define MASK_CQQRZ 0xFFFFFFC +#define MASK_CALL1 0xFFFFFFC +#define MASK_CALL2 0xFFFFFFC +#define MASK_GRIDFULL 0x3FFC +#define MASK_GRIDFULL12 0x3FFC +#define MASK_GRIDBIT 0x8000 +#else +#define MASK_CQQRZ 0xFFFFFFC +#define MASK_CALL1 0xFFFFFFF +#define MASK_CALL2 0xFFFFFFF +#define MASK_GRIDFULL 0xFFFF +#define MASK_GRIDFULL12 0x3FFC +#define MASK_GRIDBIT 0x8000 // b[15] is 1 for free text, 0 otherwise +#endif + +// ---------------------------------------------------------------------------- + + + + +qra64codec *qra64_init(int flags) +{ + + // Eb/No value for which we optimize the decoder metric + const float EbNodBMetric = 2.8f; + const float EbNoMetric = (float)pow(10,EbNodBMetric/10); + const float R = 1.0f*(QRA64_KC)/(QRA64_NC); + + qra64codec *pcodec = (qra64codec*)malloc(sizeof(qra64codec)); + + if (!pcodec) + return 0; // can't allocate memory + + pcodec->decEsNoMetric = 1.0f*QRA64_m*R*EbNoMetric; + pcodec->apflags = flags; + + memset(pcodec->apmsg_set,0,APTYPE_SIZE*sizeof(int)); + + if (flags==QRA_NOAP) + return pcodec; + + // for QRA_USERAP and QRA_AUTOAP modes we always enable [CQ/QRZ ? ?] mgs look-up. + // encode CQ/QRZ AP messages + // NOTE: Here we handle only CQ and QRZ msgs. + // 'CQ nnn', 'CQ DX' and 'DE' msgs will be handled by the decoder + // as messages with no a-priori knowledge + qra64_apset(pcodec, CALL_CQ, 0, GRID_BLANK, APTYPE_CQQRZ); + + // initialize masks for decoding with a-priori information + encodemsg_jt65(pcodec->apmask_cqqrz, MASK_CQQRZ, 0, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_cqqrz_ooo, MASK_CQQRZ, 0, MASK_GRIDFULL); + encodemsg_jt65(pcodec->apmask_call1, MASK_CALL1, 0, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_call1_ooo, MASK_CALL1, 0, MASK_GRIDFULL); + encodemsg_jt65(pcodec->apmask_call2, 0, MASK_CALL2, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_call2_ooo, 0, MASK_CALL2, MASK_GRIDFULL); + encodemsg_jt65(pcodec->apmask_call1_call2, MASK_CALL1,MASK_CALL2, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_call1_call2_grid,MASK_CALL1,MASK_CALL2, MASK_GRIDFULL12); + encodemsg_jt65(pcodec->apmask_cq_call2, MASK_CQQRZ, MASK_CALL2, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_cq_call2_ooo, MASK_CQQRZ, MASK_CALL2, MASK_GRIDFULL12); + + return pcodec; +} + +void qra64_close(qra64codec *pcodec) +{ + free(pcodec); +} + +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 +// arguments: +// pcodec = pointer to a qra64codec data structure as returned by qra64_init +// mycall = mycall to look for +// hiscall = hiscall to look for +// grid = grid to look for +// aptype = define and masks the type of AP to be set accordingly to the following: +// APTYPE_CQQRZ set [cq/qrz ? ?/blank] +// APTYPE_MYCALL set [mycall ? ?/blank] +// APTYPE_HISCALL set [? hiscall ?/blank] +// APTYPE_BOTHCALLS set [mycall hiscall ?] +// APTYPE_FULL set [mycall hiscall grid] +// APTYPE_CQHISCALL set [cq/qrz hiscall ?/blank] and [cq/qrz hiscall grid] +// returns: +// 0 on success +// -1 when qra64_init was called with the QRA_NOAP flag +// -2 invalid apytpe + + if (pcodec->apflags==QRA_NOAP) + return -1; + + switch (aptype) { + case APTYPE_CQQRZ: + encodemsg_jt65(pcodec->apmsg_cqqrz, CALL_CQ, 0, GRID_BLANK); + break; + case APTYPE_MYCALL: + encodemsg_jt65(pcodec->apmsg_call1, mycall, 0, GRID_BLANK); + break; + case APTYPE_HISCALL: + encodemsg_jt65(pcodec->apmsg_call2, 0, hiscall, GRID_BLANK); + break; + case APTYPE_BOTHCALLS: + encodemsg_jt65(pcodec->apmsg_call1_call2, mycall, hiscall, GRID_BLANK); + break; + case APTYPE_FULL: + encodemsg_jt65(pcodec->apmsg_call1_call2_grid, mycall, hiscall, grid); + break; + case APTYPE_CQHISCALL: + encodemsg_jt65(pcodec->apmsg_cq_call2, CALL_CQ, hiscall, GRID_BLANK); + encodemsg_jt65(pcodec->apmsg_cq_call2_grid, CALL_CQ, hiscall, grid); + break; + default: + return -2; // invalid ap type + } + + pcodec->apmsg_set[aptype]=1; // signal the decoder to look-up for the specified type + + + return 0; +} +void qra64_apdisable(qra64codec *pcodec, const int aptype) +{ + if (pcodec->apflags==QRA_NOAP) + return; + + if (aptype=APTYPE_SIZE) + return; + + pcodec->apmsg_set[aptype] = 0; // signal the decoder not to look-up to the specified type +} + +void qra64_encode(qra64codec *pcodec, int *y, const int *x) +{ + int encx[QRA64_KC]; // encoder input buffer + int ency[QRA64_NC]; // encoder output buffer + + int hiscall,mycall,grid; + + memcpy(encx,x,QRA64_K*sizeof(int)); // Copy input to encoder buffer + encx[QRA64_K]=calc_crc6(encx,QRA64_K); // Compute and add crc symbol + qra_encode(&QRA64_CODE, ency, encx); // encode msg+crc using given QRA code + + // copy codeword to output puncturing the crc symbol + memcpy(y,ency,QRA64_K*sizeof(int)); // copy information symbols + memcpy(y+QRA64_K,ency+QRA64_KC,QRA64_C*sizeof(int)); // copy parity symbols + + if (pcodec->apflags!=QRA_AUTOAP) + return; + + // Here we handle the QRA_AUTOAP mode -------------------------------------------- + + // When a [hiscall mycall ?] msg is detected we instruct the decoder + // to look for [mycall hiscall ?] msgs + // otherwise when a [cq mycall ?] msg is sent we reset the APTYPE_BOTHCALLS + + // look if the msg sent is a std type message (bit15 of grid field = 0) + if ((x[9]&0x80)==1) + return; // no, it's a text message, nothing to do + + // It's a [hiscall mycall grid] message + + // We assume that mycall is our call (but we don't check it) + // hiscall the station we are calling or a general call (CQ/QRZ/etc..) + decodemsg_jt65(&hiscall,&mycall,&grid,x); + + + if ((hiscall>=CALL_CQ && hiscall<=CALL_CQ999) || hiscall==CALL_CQDX || + hiscall==CALL_DE) { + // tell the decoder to look for msgs directed to us + qra64_apset(pcodec,mycall,0,0,APTYPE_MYCALL); + // We are making a general call and don't know who might reply + // Reset APTYPE_BOTHCALLS so decoder won't look for [mycall hiscall ?] msgs + qra64_apdisable(pcodec,APTYPE_BOTHCALLS); + } else { + // We are replying to someone named hiscall + // Set APTYPE_BOTHCALLS so decoder will try for [mycall hiscall ?] msgs + qra64_apset(pcodec,mycall, hiscall, GRID_BLANK, APTYPE_BOTHCALLS); + } + +} + +#define EBNO_MIN -10.0f // minimum Eb/No value returned by the decoder (in dB) +// AWGN metric decoder +int qra64_decode(qra64codec *pcodec, float *ebno, int *x, const float *rxen) +{ + 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 variance + float msge; // estimated message energy + float ebnoval; // estimated Eb/No + int rc; + + if (QRA64_NMSG!=QRA64_CODE.NMSG) // sanity check + return -16; // QRA64_NMSG define is wrong + + // compute symbols intrinsic probabilities from received energy observations + noisestd = qra_mfskbesselmetric(ix, rxen, QRA64_m, QRA64_N,pcodec->decEsNoMetric); + + // 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;k57.004f) + ebnoval=57.004f; + ebnoval = ebnoval*57.03f/(57.03f-ebnoval); + + // compute value in dB + if (ebnoval<=0) { + ebnoval = EBNO_MIN; // assume a minimum, positive value + } + else { + ebnoval = 10.0f*(float)log10(ebnoval); + if (ebnoval4) + 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 energy weighting taps + hlen = glen_tab_gauss[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = gptr_tab_gauss[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else if (fadingModel==1) { + // point to lorentzian energy weighting taps + hlen = glen_tab_lorentz[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = gptr_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 + noisestd = qra64_fastfading_estim_noise_std(rxen, EsNoMetric, submode); + + // Step 2 ----------------------------------------------------------------------------------- + // Compute message symbols probability distributions + qra64_fastfading_intrinsics(ix, rxen, hptr, hlen, noisestd, EsNoMetric, 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 Eb/N0 conversion + 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 (ebnoval238.0f) + return -18; // B90 out of range + + // compute index to most appropriate energy 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 = glen_tab_gauss[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = gptr_tab_gauss[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else if (fadingModel==1) { + // point to lorentzian weighting taps + hlen = glen_tab_lorentz[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = gptr_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; + + // compute signal bin sigmas + for (n=0;n=0;j--) { + normrnd_s(iq, 2, 0 , sigmasig[j]); + *curi++ += iq[0]; + *curq++ += iq[1]; + } + + } + + // compute total bin energies (S+N) and store in first half of buffer + curi = channel_out; + curq = channel_out+bpm; + for (n=0;nmaxloglh) // keep track of the max loglikelihood + maxloglh = loglh; + curix[k]=loglh; + } + + // scale to likelihoods + sumix = 0.f; + for (k=0;k1 + 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; + + +} + +#ifdef LIMIT_AP_MASKS + +static int call1_match(const int *papmsg, const int *pdec) +{ + // assumes MASK_CALL1 = 0xFFFFFFC + int u = papmsg[4]^pdec[4]; + return (u&0x3C)==0; +} +static int call2_match(const int *papmsg, const int *pdec) +{ + // assumes MASK_CALL2 = 0xFFFFFFC + int u = papmsg[9]^pdec[9]; + return (u&0x30)==0; +} +static int grid_match(const int *papmsg, const int *pdec) +{ + // assumes MASK_GRIDFULL = 0x3FFC + int u = papmsg[11]^pdec[11]; + int rc = (u&0x03)==0; + + u = papmsg[9]^pdec[9]; + + return (u&0x0C)==0 && rc; +} + +#else +#define call1_match(a,b) (1) +#define call2_match(a,b) (1) +#define grid_match(a,b) (1) +#endif + + + + +// 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) + // check that ooo really matches + if (grid_match(pcodec->apmsg_cqqrz,xdec)) + return 2; // decoded [cq/qrz ? 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) + // check that mycall really matches + if (call1_match(pcodec->apmsg_call1,xdec)) + return 3; // decoded [mycall ? ?] + + rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1_ooo, + pcodec->apmsg_call1); + if (rc>=0) + // check that mycall and ooo really match + if (call1_match(pcodec->apmsg_call1,xdec) && + grid_match(pcodec->apmsg_call1,xdec)) + return 4; // decoded [mycall ? ooo] + } + + // attempt to decode [mycall hiscall ?] msgs + if (pcodec->apmsg_set[APTYPE_BOTHCALLS]) { + rc = qra64_do_decode(xdec, ix, pcodec->apmask_call1_call2, + pcodec->apmsg_call1_call2); + if (rc>=0) + // check that mycall and hiscall really match + if (call1_match(pcodec->apmsg_call1_call2,xdec) && + call2_match(pcodec->apmsg_call1_call2,xdec)) + 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) + // check that hiscall really match + if (call2_match(pcodec->apmsg_call2,xdec)) + return 6; // decoded [? hiscall ?] + + rc = qra64_do_decode(xdec, ix, pcodec->apmask_call2_ooo, + pcodec->apmsg_call2); + if (rc>=0) + // check that hiscall and ooo match + if (call2_match(pcodec->apmsg_call2,xdec) && + grid_match(pcodec->apmsg_call2,xdec)) + 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) + // check that hiscall matches + if (call2_match(pcodec->apmsg_call2,xdec)) + 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 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 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 8; // decoded [mycall hiscall grid] + } + } + + // all decoding attempts failed + return -1; +} + + + +// Decode with given a-priori information +static int qra64_do_decode(int *xdec, const float *pix, const int *ap_mask, + const int *ap_x) +{ + int rc; + const float *ixsrc; + float ix_masked[QRA64_NC*QRA64_M]; // Masked intrinsic information + float ex[QRA64_NC*QRA64_M]; // Extrinsic information from the decoder + + float v2cmsg[QRA64_NMSG*QRA64_M]; // buffers for the decoder messages + float c2vmsg[QRA64_NMSG*QRA64_M]; + + if (ap_mask==NULL) { // no a-priori information + ixsrc = pix; // intrinsic source is what passed as argument + } else { + // a-priori information provided + // mask channel observations with a-priori + ix_mask(ix_masked,pix,ap_mask,ap_x); + ixsrc = ix_masked; // intrinsic source is the masked version + } + + // run the decoding algorithm + rc = qra_extrinsic(&QRA64_CODE,ex,ixsrc,QRA64_NITER,v2cmsg,c2vmsg); + if (rc<0) + return -1; // no convergence in given iterations + + // decode + qra_mapdecode(&QRA64_CODE,xdec,ex,ixsrc); + + // verify crc + if (calc_crc6(xdec,QRA64_K)!=xdec[QRA64_K]) // crc doesn't match (detected error) + return -2; // decoding was succesfull but crc doesn't match + + return 0; +} + + +// crc functions -------------------------------------------------------------- +// crc-6 generator polynomial +// g(x) = x^6 + a5*x^5 + ... + a1*x + a0 + +// g(x) = x^6 + x + 1 +#define CRC6_GEN_POL 0x30 // MSB=a0 LSB=a5 + +// g(x) = x^6 + x^2 + x + 1 (See: https://users.ece.cmu.edu/~koopman/crc/) +// #define CRC6_GEN_POL 0x38 // MSB=a0 LSB=a5. Simulation results are similar + +static int calc_crc6(const int *x, int sz) +{ + // todo: compute it faster using a look up table + int k,j,t,sr = 0; + for (k=0;k>1) ^ CRC6_GEN_POL; + else + sr = (sr>>1); + t>>=1; + } + } + return sr; +} + +static void ix_mask(float *dst, const float *src, const int *mask, + const int *x) +{ + // mask intrinsic information (channel observations) with a priori knowledge + + int k,kk, smask; + float *row; + + memcpy(dst,src,(QRA64_NC*QRA64_M)*sizeof(float)); + + for (k=0;k>22)&0x3F; + y[1]= (call1>>16)&0x3F; + y[2]= (call1>>10)&0x3F; + y[3]= (call1>>4)&0x3F; + y[4]= (call1<<2)&0x3F; + + y[4] |= (call2>>26)&0x3F; + y[5]= (call2>>20)&0x3F; + y[6]= (call2>>14)&0x3F; + y[7]= (call2>>8)&0x3F; + y[8]= (call2>>2)&0x3F; + y[9]= (call2<<4)&0x3F; + + y[9] |= (grid>>12)&0x3F; + y[10]= (grid>>6)&0x3F; + y[11]= (grid)&0x3F; + +} +void decodemsg_jt65(int *call1, int *call2, int *grid, const int *x) +{ + int nc1, nc2, ng; + + nc1 = x[4]>>2; + nc1 |= x[3]<<4; + nc1 |= x[2]<<10; + nc1 |= x[1]<<16; + nc1 |= x[0]<<22; + + nc2 = x[9]>>4; + nc2 |= x[8]<<2; + nc2 |= x[7]<<8; + nc2 |= x[6]<<14; + nc2 |= x[5]<<20; + nc2 |= (x[4]&0x03)<<26; + + ng = x[11]; + ng |= x[10]<<6; + ng |= (x[9]&0x0F)<<12; + + *call1 = nc1; + *call2 = nc2; + *grid = ng; +} diff --git a/libm65/qra64/qra64.h b/libm65/qra64/qra64.h new file mode 100644 index 000000000..3b2b5bd3d --- /dev/null +++ b/libm65/qra64/qra64.h @@ -0,0 +1,269 @@ +// qra64.h +// Encoding/decoding functions for the QRA64 mode +// +// (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 . + +#ifndef _qra64_h_ +#define _qra64_h_ + +// qra64_init(...) initialization flags +#define QRA_NOAP 0 // don't use a-priori knowledge +#define QRA_AUTOAP 1 // use auto a-priori knowledge +#define QRA_USERAP 2 // a-priori knowledge messages provided by the user + +// QRA code parameters +#define QRA64_K 12 // information symbols +#define QRA64_N 63 // codeword length +#define QRA64_C 51 // (number of parity checks C=(N-K)) +#define QRA64_M 64 // code alphabet size +#define QRA64_m 6 // bits per symbol + +// packed predefined callsigns and fields as defined in JT65 +#define CALL_CQ 0xFA08319 +#define CALL_QRZ 0xFA0831A +#define CALL_CQ000 0xFA0831B +#define CALL_CQ999 0xFA08702 +#define CALL_CQDX 0x5624C39 +#define CALL_DE 0xFF641D1 +#define GRID_BLANK 0x7E91 + +// Types of a-priori knowledge messages +#define APTYPE_CQQRZ 0 // [cq/qrz ? ?/blank] +#define APTYPE_MYCALL 1 // [mycall ? ?/blank] +#define APTYPE_HISCALL 2 // [? hiscall ?/blank] +#define APTYPE_BOTHCALLS 3 // [mycall hiscall ?] +#define APTYPE_FULL 4 // [mycall hiscall grid] +#define APTYPE_CQHISCALL 5 // [cq/qrz hiscall ?/blank] +#define APTYPE_SIZE (APTYPE_CQHISCALL+1) + +typedef struct { + float decEsNoMetric; + int apflags; + int apmsg_set[APTYPE_SIZE]; // indicate which ap type knowledge has + // been set by the user +// ap messages buffers + int apmsg_cqqrz[12]; // [cq/qrz ? ?/blank] + int apmsg_call1[12]; // [mycall ? ?/blank] + int apmsg_call2[12]; // [? hiscall ?/blank] + int apmsg_call1_call2[12]; // [mycall hiscall ?] + int apmsg_call1_call2_grid[12]; // [mycall hiscall grid] + int apmsg_cq_call2[12]; // [cq hiscall ?/blank] + int apmsg_cq_call2_grid[12]; // [cq hiscall grid] + +// ap messages masks + int apmask_cqqrz[12]; + int apmask_cqqrz_ooo[12]; + int apmask_call1[12]; + int apmask_call1_ooo[12]; + int apmask_call2[12]; + int apmask_call2_ooo[12]; + int apmask_call1_call2[12]; + int apmask_call1_call2_grid[12]; + int apmask_cq_call2[12]; + int apmask_cq_call2_ooo[12]; +} qra64codec; + +#ifdef __cplusplus +extern "C" { +#endif + +qra64codec *qra64_init(int flags); +// QRA64 mode initialization function +// arguments: +// flags: set the decoder mode +// QRA_NOAP use no a-priori information +// QRA_AUTOAP use any relevant previous decodes +// QRA_USERAP use a-priori information provided via qra64_apset(...) +// returns: +// Pointer to initialized qra64codec data structure +// this pointer should be passed to the encoding/decoding functions +// +// 0 if unsuccessful (can't allocate memory) +// ---------------------------------------------------------------------------- + +void qra64_encode(qra64codec *pcodec, int *y, const int *x); +// QRA64 encoder +// arguments: +// pcodec = pointer to a qra64codec data structure as returned by qra64_init +// x = pointer to the message to be encoded, int x[12] +// x must point to an array of integers (i.e. defined as int x[12]) +// y = pointer to encoded message, int y[63]= +// ---------------------------------------------------------------------------- + +int qra64_decode(qra64codec *pcodec, float *ebno, int *x, const float *r); +// QRA64 mode decoder +// arguments: +// pcodec = pointer to a qra64codec data structure as returned by qra64_init +// ebno = pointer to a float where the avg Eb/No (in dB) will be stored +// in case of successfull decoding +// (pass a null pointer if not interested) +// x = pointer to decoded message, int x[12] +// r = pointer to received symbol energies (squared amplitudes) +// r must point to an array of length QRA64_M*QRA64_N (=64*63=4032) +// The first QRA_M entries should be the energies of the first +// symbol in the codeword; the last QRA_M entries should be the +// energies of the last symbol in the codeword +// +// return code: +// +// The return code is <0 when decoding is unsuccessful +// -16 indicates that the definition of QRA64_NMSG does not match what required by the code +// If the decoding process is successfull the return code is accordingly to the following table +// rc=0 [? ? ?] AP0 (decoding with no a-priori) +// rc=1 [CQ ? ?] AP27 +// rc=2 [CQ ? ] AP44 +// rc=3 [CALL ? ?] AP29 +// rc=4 [CALL ? ] AP45 +// rc=5 [CALL CALL ?] AP57 +// rc=6 [? CALL ?] AP29 +// rc=7 [? CALL ] AP45 +// rc=8 [CALL CALL GRID] AP72 (actually a AP68 mask to reduce false decodes) +// rc=9 [CQ CALL ?] AP55 +// rc=10 [CQ CALL ] AP70 (actaully a AP68 mask to reduce false decodes) + +// 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 + const 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 +// arguments: +// pcodec = pointer to a qra64codec data structure as returned by qra64_init +// mycall = mycall to look for +// hiscall = hiscall to look for +// grid = grid to look for +// aptype = define the type of AP to be set: +// APTYPE_CQQRZ set [cq/qrz ? ?/blank] +// APTYPE_MYCALL set [mycall ? ?/blank] +// APTYPE_HISCALL set [? hiscall ?/blank] +// APTYPE_BOTHCALLS set [mycall hiscall ?] +// APTYPE_FULL set [mycall hiscall grid] +// APTYPE_CQHISCALL set [cq/qrz hiscall ?/blank] + +// returns: +// 0 on success +// -1 when qra64_init was called with the QRA_NOAP flag +// -2 invalid apytpe (valid range [APTYPE_CQQRZ..APTYPE_CQHISCALL] +// (APTYPE_CQQRZ [cq/qrz ? ?] is set by default ) + +void qra64_apdisable(qra64codec *pcodec, const int aptype); +// disable specific AP type +// arguments: +// pcodec = pointer to a qra64codec data structure as returned by qra64_init +// aptype = define the type of AP to be disabled +// APTYPE_CQQRZ disable [cq/qrz ? ?/blank] +// APTYPE_MYCALL disable [mycall ? ?/blank] +// APTYPE_HISCALL disable [ ? hiscall ?/blank] +// APTYPE_BOTHCALLS disable [mycall hiscall ? ] +// APTYPE_FULL disable [mycall hiscall grid] +// APTYPE_CQHISCALL set [cq/qrz hiscall ?/blank] + +void qra64_close(qra64codec *pcodec); +// Free memory allocated by qra64_init +// arguments: +// pcodec = pointer to a qra64codec data structure as returned by qra64_init + +// ---------------------------------------------------------------------------- + +// encode/decode std msgs in 12 symbols as done in jt65 +void encodemsg_jt65(int *y, const int call1, const int call2, const int grid); +void decodemsg_jt65(int *call1, int *call2, int *grid, const int *x); + +#ifdef __cplusplus +} +#endif + +#endif // _qra64_h_ diff --git a/libm65/qra64/qra64_all.c b/libm65/qra64/qra64_all.c new file mode 100644 index 000000000..3951c031b --- /dev/null +++ b/libm65/qra64/qra64_all.c @@ -0,0 +1,1050 @@ +/* +qra64.c +Encoding/decoding functions for the QRA64 mode + +(c) 2016 - Nico Palermo, IV3NWV + +------------------------------------------------------------------------------- + + 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 . + +----------------------------------------------------------------------------- + +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) + +Codes with K=13 are designed to include a CRC as the 13th information symbol +and improve the code UER (Undetected Error Rate). +The CRC symbol is not sent along the channel (the codes are punctured) and the +resulting code is a (12,63) code +*/ +//---------------------------------------------------------------------------- + +#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 +#define QRA64_NMSG 218 // Must much value indicated in QRA64_CODE.NMSG + +#define QRA64_KC (QRA64_K+1) // Information symbols (crc included) +#define QRA64_NC (QRA64_N+1) // Codeword length (as defined in the code) +#define QRA64_NITER 100 // max number of iterations per decode + +// static functions declarations ---------------------------------------------- +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_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 +#define MASK_CALL1 0xFFFFFFF +#define MASK_CALL2 0xFFFFFFF +#define MASK_GRIDFULL 0xFFFF +#define MASK_GRIDFULL12 0x3FFC // less aggressive mask (to be used with full AP decoding) +#define MASK_GRIDBIT 0x8000 // b[15] is 1 for free text, 0 otherwise +// ---------------------------------------------------------------------------- + +qra64codec *qra64_init(int flags) +{ + + // Eb/No value for which we optimize the decoder metric + const float EbNodBMetric = 2.8f; + const float EbNoMetric = (float)pow(10,EbNodBMetric/10); + const float R = 1.0f*(QRA64_KC)/(QRA64_NC); + + qra64codec *pcodec = (qra64codec*)malloc(sizeof(qra64codec)); + + if (!pcodec) + return 0; // can't allocate memory + + pcodec->decEsNoMetric = 1.0f*QRA64_m*R*EbNoMetric; + pcodec->apflags = flags; + + memset(pcodec->apmsg_set,0,APTYPE_SIZE*sizeof(int)); + + if (flags==QRA_NOAP) + return pcodec; + + // for QRA_USERAP and QRA_AUTOAP modes we always enable [CQ/QRZ ? ?] mgs look-up. + // encode CQ/QRZ AP messages + // NOTE: Here we handle only CQ and QRZ msgs. + // 'CQ nnn', 'CQ DX' and 'DE' msgs will be handled by the decoder + // as messages with no a-priori knowledge + qra64_apset(pcodec, CALL_CQ, 0, GRID_BLANK, APTYPE_CQQRZ); + + // initialize masks for decoding with a-priori information + encodemsg_jt65(pcodec->apmask_cqqrz, MASK_CQQRZ, 0, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_cqqrz_ooo, MASK_CQQRZ, 0, MASK_GRIDFULL); + encodemsg_jt65(pcodec->apmask_call1, MASK_CALL1, 0, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_call1_ooo, MASK_CALL1, 0, MASK_GRIDFULL); + encodemsg_jt65(pcodec->apmask_call2, 0, MASK_CALL2, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_call2_ooo, 0, MASK_CALL2, MASK_GRIDFULL); + encodemsg_jt65(pcodec->apmask_call1_call2, MASK_CALL1,MASK_CALL2, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_call1_call2_grid,MASK_CALL1,MASK_CALL2, MASK_GRIDFULL12); + encodemsg_jt65(pcodec->apmask_cq_call2, MASK_CQQRZ, MASK_CALL2, MASK_GRIDBIT); + encodemsg_jt65(pcodec->apmask_cq_call2_ooo, MASK_CQQRZ, MASK_CALL2, MASK_GRIDFULL12); + + return pcodec; +} + +void qra64_close(qra64codec *pcodec) +{ + free(pcodec); +} + +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 +// arguments: +// pcodec = pointer to a qra64codec data structure as returned by qra64_init +// mycall = mycall to look for +// hiscall = hiscall to look for +// grid = grid to look for +// aptype = define and masks the type of AP to be set accordingly to the following: +// APTYPE_CQQRZ set [cq/qrz ? ?/blank] +// APTYPE_MYCALL set [mycall ? ?/blank] +// APTYPE_HISCALL set [? hiscall ?/blank] +// APTYPE_BOTHCALLS set [mycall hiscall ?] +// APTYPE_FULL set [mycall hiscall grid] +// APTYPE_CQHISCALL set [cq/qrz hiscall ?/blank] and [cq/qrz hiscall grid] +// returns: +// 0 on success +// -1 when qra64_init was called with the QRA_NOAP flag +// -2 invalid apytpe + + if (pcodec->apflags==QRA_NOAP) + return -1; + + switch (aptype) { + case APTYPE_CQQRZ: + encodemsg_jt65(pcodec->apmsg_cqqrz, CALL_CQ, 0, GRID_BLANK); + break; + case APTYPE_MYCALL: + encodemsg_jt65(pcodec->apmsg_call1, mycall, 0, GRID_BLANK); + break; + case APTYPE_HISCALL: + encodemsg_jt65(pcodec->apmsg_call2, 0, hiscall, GRID_BLANK); + break; + case APTYPE_BOTHCALLS: + encodemsg_jt65(pcodec->apmsg_call1_call2, mycall, hiscall, GRID_BLANK); + break; + case APTYPE_FULL: + encodemsg_jt65(pcodec->apmsg_call1_call2_grid, mycall, hiscall, grid); + break; + case APTYPE_CQHISCALL: + encodemsg_jt65(pcodec->apmsg_cq_call2, CALL_CQ, hiscall, GRID_BLANK); + encodemsg_jt65(pcodec->apmsg_cq_call2_grid, CALL_CQ, hiscall, grid); + break; + default: + return -2; // invalid ap type + } + + pcodec->apmsg_set[aptype]=1; // signal the decoder to look-up for the specified type + + + return 0; +} +void qra64_apdisable(qra64codec *pcodec, const int aptype) +{ + if (pcodec->apflags==QRA_NOAP) + return; + + if (aptype=APTYPE_SIZE) + return; + + pcodec->apmsg_set[aptype] = 0; // signal the decoder not to look-up to the specified type +} + +void qra64_encode(qra64codec *pcodec, int *y, const int *x) +{ + int encx[QRA64_KC]; // encoder input buffer + int ency[QRA64_NC]; // encoder output buffer + + int hiscall,mycall,grid; + + memcpy(encx,x,QRA64_K*sizeof(int)); // Copy input to encoder buffer + encx[QRA64_K]=calc_crc6(encx,QRA64_K); // Compute and add crc symbol + qra_encode(&QRA64_CODE, ency, encx); // encode msg+crc using given QRA code + + // copy codeword to output puncturing the crc symbol + memcpy(y,ency,QRA64_K*sizeof(int)); // copy information symbols + memcpy(y+QRA64_K,ency+QRA64_KC,QRA64_C*sizeof(int)); // copy parity symbols + + if (pcodec->apflags!=QRA_AUTOAP) + return; + + // Here we handle the QRA_AUTOAP mode -------------------------------------------- + + // When a [hiscall mycall ?] msg is detected we instruct the decoder + // to look for [mycall hiscall ?] msgs + // otherwise when a [cq mycall ?] msg is sent we reset the APTYPE_BOTHCALLS + + // look if the msg sent is a std type message (bit15 of grid field = 0) + if ((x[9]&0x80)==1) + return; // no, it's a text message, nothing to do + + // It's a [hiscall mycall grid] message + + // We assume that mycall is our call (but we don't check it) + // hiscall the station we are calling or a general call (CQ/QRZ/etc..) + decodemsg_jt65(&hiscall,&mycall,&grid,x); + + + if ((hiscall>=CALL_CQ && hiscall<=CALL_CQ999) || hiscall==CALL_CQDX || + hiscall==CALL_DE) { + // tell the decoder to look for msgs directed to us + qra64_apset(pcodec,mycall,0,0,APTYPE_MYCALL); + // We are making a general call and don't know who might reply + // Reset APTYPE_BOTHCALLS so decoder won't look for [mycall hiscall ?] msgs + qra64_apdisable(pcodec,APTYPE_BOTHCALLS); + } else { + // We are replying to someone named hiscall + // Set APTYPE_BOTHCALLS so decoder will try for [mycall hiscall ?] msgs + qra64_apset(pcodec,mycall, hiscall, GRID_BLANK, APTYPE_BOTHCALLS); + } + +} + +#define EBNO_MIN -10.0f // minimum Eb/No value returned by the decoder (in dB) +int qra64_decode(qra64codec *pcodec, float *ebno, int *x, const float *rxen) +{ + 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 variance + float msge; // estimated message energy + float ebnoval; // estimated Eb/No + int rc; + + if (QRA64_NMSG!=QRA64_CODE.NMSG) // sanity check + return -16; // QRA64_NMSG define is wrong + + // compute symbols intrinsic probabilities from received energy observations + noisestd = qra_mfskbesselmetric(ix, rxen, QRA64_m, QRA64_N,pcodec->decEsNoMetric); + + // 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;k57.004f) + ebnoval=57.004f; + ebnoval = ebnoval*57.03f/(57.03f-ebnoval); + + // compute value in dB + if (ebnoval<=0) + ebnoval = EBNO_MIN; // assume a minimum, positive value + else + ebnoval = 10.0f*(float)log10(ebnoval); + if (ebnoval4) + 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) +{ + int rc; + const float *ixsrc; + float ix_masked[QRA64_NC*QRA64_M]; // Masked intrinsic information + float ex[QRA64_NC*QRA64_M]; // Extrinsic information from the decoder + + float v2cmsg[QRA64_NMSG*QRA64_M]; // buffers for the decoder messages + float c2vmsg[QRA64_NMSG*QRA64_M]; + + if (ap_mask==NULL) { // no a-priori information + ixsrc = pix; // intrinsic source is what passed as argument + } else { + // a-priori information provided + // mask channel observations with a-priori + ix_mask(ix_masked,pix,ap_mask,ap_x); + ixsrc = ix_masked; // intrinsic source is the masked version + } + + // run the decoding algorithm + rc = qra_extrinsic(&QRA64_CODE,ex,ixsrc,QRA64_NITER,v2cmsg,c2vmsg); + if (rc<0) + return -1; // no convergence in given iterations + + // decode + qra_mapdecode(&QRA64_CODE,xdec,ex,ixsrc); + + // verify crc + if (calc_crc6(xdec,QRA64_K)!=xdec[QRA64_K]) // crc doesn't match (detected error) + return -2; // decoding was succesfull but crc doesn't match + + return 0; +} + + +// crc functions -------------------------------------------------------------- +// crc-6 generator polynomial +// g(x) = x^6 + a5*x^5 + ... + a1*x + a0 + +// g(x) = x^6 + x + 1 +#define CRC6_GEN_POL 0x30 // MSB=a0 LSB=a5 + +// g(x) = x^6 + x^2 + x + 1 (See: https://users.ece.cmu.edu/~koopman/crc/) +// #define CRC6_GEN_POL 0x38 // MSB=a0 LSB=a5. Simulation results are similar + +static int calc_crc6(const int *x, int sz) +{ + // todo: compute it faster using a look up table + int k,j,t,sr = 0; + for (k=0;k>1) ^ CRC6_GEN_POL; + else + sr = (sr>>1); + t>>=1; + } + } + return sr; +} + +static void ix_mask(float *dst, const float *src, const int *mask, + const int *x) +{ + // mask intrinsic information (channel observations) with a priori knowledge + + int k,kk, smask; + float *row; + + memcpy(dst,src,(QRA64_NC*QRA64_M)*sizeof(float)); + + for (k=0;k>22)&0x3F; + y[1]= (call1>>16)&0x3F; + y[2]= (call1>>10)&0x3F; + y[3]= (call1>>4)&0x3F; + y[4]= (call1<<2)&0x3F; + + y[4] |= (call2>>26)&0x3F; + y[5]= (call2>>20)&0x3F; + y[6]= (call2>>14)&0x3F; + y[7]= (call2>>8)&0x3F; + y[8]= (call2>>2)&0x3F; + y[9]= (call2<<4)&0x3F; + + y[9] |= (grid>>12)&0x3F; + y[10]= (grid>>6)&0x3F; + y[11]= (grid)&0x3F; + +} +void decodemsg_jt65(int *call1, int *call2, int *grid, const int *x) +{ + int nc1, nc2, ng; + + nc1 = x[4]>>2; + nc1 |= x[3]<<4; + nc1 |= x[2]<<10; + nc1 |= x[1]<<16; + nc1 |= x[0]<<22; + + nc2 = x[9]>>4; + nc2 |= x[8]<<2; + nc2 |= x[7]<<8; + nc2 |= x[6]<<14; + nc2 |= x[5]<<20; + nc2 |= (x[4]&0x03)<<26; + + ng = x[11]; + ng |= x[10]<<6; + ng |= (x[9]&0x0F)<<12; + + *call1 = nc1; + *call2 = nc2; + *grid = ng; +} diff --git a/libm65/qra64/qra64_subs.c b/libm65/qra64/qra64_subs.c new file mode 100644 index 000000000..b60f9fafa --- /dev/null +++ b/libm65/qra64/qra64_subs.c @@ -0,0 +1,65 @@ +// qra64_subs.c +// Fortran interface routines for QRA64 + +#include "qra64.h" +#include + +static qra64codec *pqra64codec = NULL; + +void qra64_enc_(int x[], int y[]) +{ + if (pqra64codec==NULL) pqra64codec = qra64_init(QRA_USERAP); + qra64_encode(pqra64codec, y, x); +} + +void qra64_dec_(float r[], int* nc1, int* nc2, int* ng2, int* APtype, + int* iset, int* ns0, float* b0, int* nf0, + int xdec[], float* snr, int* rc) +{ +/* + APtype: AP +----------------------------------------------------------------------- + -1 0 (no AP information) + 0 [CQ/QRZ ? ? ] 25/37 + 1 [MyCall ? ? ] 25/37 + 2 [ ? HisCall ? ] 25/37 + 3 [MyCall HisCall ? ] 49/68 + 4 [MyCall HisCall grid] 68 + 5 [CQ/QRZ HisCall ? ] 49/68 + + rc Message format AP APTYPE Comments +------------------------------------------------------------------------ + -16 Failed sanity check + -2 Decoded but CRC failed + -1 No decode + 0 [ ? ? ? ] 0 -1 Decode with no AP info + 1 [CQ/QRZ ? ? ] 25 0 + 2 [CQ/QRZ ? _ ] 37 0 + 3 [MyCall ? ? ] 25 1 + 4 [MyCall ? _ ] 37 1 + 5 [MyCall HisCall ? ] 49 3 + 6 [ ? HisCall ? ] 25 2 Optional + 7 [ ? HisCall _ ] 37 2 Optional + 8 [MyCall HisCall Grid] 68 4 + 9 [CQ/QRZ HisCall ? ] 49 5 Optional (not needed?) + 10 [CQ/QRZ HisCall _ ] 68 5 Optional + 11 [CQ/QRZ HisCall Grid] 68 ? Optional +*/ + + float EbNodBEstimated; + int err=0; + int nSubmode=*ns0; + float b90=*b0; + int nFadingModel=*nf0; + + if(pqra64codec==NULL) pqra64codec = qra64_init(QRA_USERAP); + err=qra64_apset(pqra64codec,*nc1,*nc2,*ng2,*APtype); + if(err<0) printf("ERROR: qra64_apset returned %d\n",err); + + if(*iset==0) { + *rc = qra64_decode_fastfading(pqra64codec,&EbNodBEstimated,xdec,r, + nSubmode,b90,nFadingModel); + *snr = EbNodBEstimated - 31.0; + } +} + diff --git a/libm65/qra64/qra64example.txt b/libm65/qra64/qra64example.txt new file mode 100644 index 000000000..3add33d36 --- /dev/null +++ b/libm65/qra64/qra64example.txt @@ -0,0 +1,88 @@ +$ qra64_nico -h + +QRA64 Mode Tests +2016, Nico Palermo - IV3NWV + +--------------------------- + +Syntax: qra64 [-s] [-c] [-a] [-t] [-h] +Options: + -s : set simulation SNR in 2500 Hz BW (default:-27.5 dB) + -c : set channel type 0=AWGN (default) 1=Rayleigh + -a : set decode type 0=NOAP 1=AUTOAP (default) 2=USERAP + -t: 0=simulate seq of msgs between IV3NWV and K1JT (default) + 1=simulate K1JT receiving K1JT IV3NWV JN66 + 2=simulate fast-fading routines (option -c ignored) +Options used only for fast-fading simulations: + -b : 90% fading bandwidth in Hz [1..230 Hz] (default = 2.5 Hz) + -m : fading model. 0=Gauss, 1=Lorentz (default = Lorentz) + -q : qra64 submode. 0=QRA64A,... 4=QRA64E (default = QRA64A) + -h: this help + + +############################################################################# +Usage example: + +qra64 -c2 -t2 -a2 -b50 -m1 -q2 -s-26.0 -n50000 + +Simulate a fast-fading channel (-c2) +Evaluate decoder performance (-t2) with +USER_AP (-a2) +B90 = 50 Hz (-b50) +Lorentz model (-m1) +submode QRA64C (-q2) +Input SNR = -26.0 dB (-s-26.0) +Simulate 50000 transmissions (-n50000) + +(type qra64 -h for command syntax) + +Command Output: + +Input SNR = -26.0dB ap-mode=USER AP + +Simulating the fast-fading channel +B90=50.00 Hz - Fading Model=Lorentz - Submode=QRA64C +Decoder metric = Matched to fast-fading signal + +Encoding msg [K1JT IV3NWV JN66] +50000 transmissions will be simulated + +K1JT decoder enabled for [CQ ? ?/blank] +K1JT decoder enabled for [K1JT ? ?/blank] +K1JT decoder enabled for [? IV3NWV ?/blank] +K1JT decoder enabled for [K1JT IV3NWV ?] +K1JT decoder enabled for [K1JT IV3NWV JN66] +K1JT decoder enabled for [CQ IV3NWV ?/b/JN66] + +Now decoding with K1JT's decoder... + 5.5 % +Undetected error with rc=6 + 13.1 % +Undetected error with rc=7 + 70.8 % +Undetected error with rc=1 + 75.8 % +Undetected error with rc=9 + 88.9 % +Undetected error with rc=6 + 100.0 % + +Msgs transmitted:50000 +Msg decoded: + +rc= 0 0 with [? ? ?] AP0 +rc= 1 0 with [CQ ? ?] AP27 +rc= 2 0 with [CQ ? ] AP42 +rc= 3 145 with [CALL ? ?] AP29 +rc= 4 0 with [CALL ? ] AP44 +rc= 5 12085 with [CALL CALL ?] AP57 +rc= 6 0 with [? CALL ?] AP29 +rc= 7 0 with [? CALL ] AP44 +rc= 8 24307 with [CALL CALL G] AP72 +rc= 9 0 with [CQ CALL ?] AP55 +rc=10 0 with [CQ CALL ] AP70 +rc=11 0 with [CQ CALL G] AP70 + +Total: 36537/50000 (5 undetected errors) + +Estimated SNR (average in dB) = -26.26 dB diff --git a/libm65/qra64/qra64sim.f90 b/libm65/qra64/qra64sim.f90 new file mode 100644 index 000000000..b7ca2e130 --- /dev/null +++ b/libm65/qra64/qra64sim.f90 @@ -0,0 +1,170 @@ +program qra64sim + +! Generate simulated QRA64 data for testing the decoder. + + use wavhdr + use packjt + parameter (NMAX=54*12000) ! = 648,000 + parameter (NFFT=10*65536,NH=NFFT/2) + type(hdr) h !Header for .wav file + integer*2 iwave(NMAX) !Generated waveform + integer*4 itone(84) !Channel symbols (values 0-63) + real*4 xnoise(NMAX) !Generated random noise + real*4 dat(NMAX) !Generated real data + complex cdat(NMAX) !Generated complex waveform + complex cspread(0:NFFT-1) !Complex amplitude for Rayleigh fading + complex z + real*8 f0,dt,twopi,phi,dphi,baud,fsample,freq + character msg*22,fname*11,csubmode*1,arg*12 + character msgsent*22 + + nargs=iargc() + if(nargs.ne. 7) then + print *, 'Usage: qra64sim "msg" A-E Nsigs fDop DT Nfiles SNR' + print *, 'Example qra64sim "K1ABC W9XYZ EN37" A 10 0.2 0.0 1 0' + go to 999 + endif + call getarg(1,msg) + call getarg(2,csubmode) + mode64=2**(ichar(csubmode)-ichar('A')) + call getarg(3,arg) + read(arg,*) nsigs + call getarg(4,arg) + read(arg,*) fspread + call getarg(5,arg) + read(arg,*) xdt + call getarg(6,arg) + read(arg,*) nfiles + call getarg(7,arg) + read(arg,*) snrdb + + if(mode64.ge.8) nsigs=1 + rms=100. + fsample=12000.d0 !Sample rate (Hz) + dt=1.d0/fsample !Sample interval (s) + twopi=8.d0*atan(1.d0) + npts=54*12000 !Total samples in .wav file + nsps=6912 + baud=12000.d0/nsps !Keying rate = 1.7361111111 + nsym=84 !Number of channel symbols + h=default_header(12000,npts) + dfsig=2000.0/nsigs !Freq spacing between sigs in file (Hz) + ichk=0 + + write(*,1000) +1000 format('File Sig Freq A-E S/N DT Dop Message'/60('-')) + + do ifile=1,nfiles !Loop over requested number of files + write(fname,1002) ifile !Output filename +1002 format('000000_',i4.4) + open(10,file=fname//'.wav',access='stream',status='unknown') + xnoise=0. + cdat=0. + if(snrdb.lt.90) then + do i=1,npts + xnoise(i)=gran() !Generate gaussian noise + enddo + endif + + do isig=1,nsigs !Generate requested number of sigs + if(mod(nsigs,2).eq.0) f0=1500.0 + dfsig*(isig-0.5-nsigs/2) + if(mod(nsigs,2).eq.1) f0=1500.0 + dfsig*(isig-(nsigs+1)/2) + if(nsigs.eq.1) f0=1000.0 + xsnr=snrdb + if(snrdb.eq.0.0) xsnr=-20 - isig + + call genqra64(msg,ichk,msgsent,itone,itype) + + bandwidth_ratio=2500.0/6000.0 + sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*xsnr) + if(xsnr.gt.90.0) sig=1.0 + write(*,1020) ifile,isig,f0,csubmode,xsnr,xdt,fspread,msg +1020 format(i4,i4,f10.3,2x,a1,2x,f5.1,f6.2,f6.1,1x,a22) + + phi=0.d0 + dphi=0.d0 + k=(xdt+1.0)*12000 !Start audio at t = xdt + 1.0 s + isym0=-99 + do i=1,npts !Add this signal into cdat() + isym=i/nsps + 1 + if(isym.gt.nsym) exit + if(isym.ne.isym0) then + freq=f0 + itone(isym)*baud*mode64 + dphi=twopi*freq*dt + isym0=isym + endif + phi=phi + dphi + if(phi.gt.twopi) phi=phi-twopi + xphi=phi + z=cmplx(cos(xphi),sin(xphi)) + k=k+1 + if(k.ge.1) cdat(k)=cdat(k) + sig*z + enddo + enddo + + if(fspread.ne.0) then !Apply specified Doppler spread + df=12000.0/nfft + twopi=8*atan(1.0) + cspread(0)=1.0 + cspread(NH)=0. + b=6.0 !Lorenzian 3/28 onward + do i=1,NH + f=i*df + x=b*f/fspread + z=0. + a=0. + if(x.lt.3.0) then !Cutoff beyond x=3 + a=sqrt(1.111/(1.0+x*x)-0.1) !Lorentzian + call random_number(r1) + phi1=twopi*r1 + z=a*cmplx(cos(phi1),sin(phi1)) + endif + cspread(i)=z + z=0. + if(x.lt.50.0) then + call random_number(r2) + phi2=twopi*r2 + z=a*cmplx(cos(phi2),sin(phi2)) + endif + cspread(NFFT-i)=z + enddo + + do i=0,NFFT-1 + f=i*df + if(i.gt.NH) f=(i-nfft)*df + s=real(cspread(i))**2 + aimag(cspread(i))**2 +! write(13,3000) i,f,s,cspread(i) +!3000 format(i5,f10.3,3f12.6) + enddo +! s=real(cspread(0))**2 + aimag(cspread(0))**2 +! write(13,3000) 1024,0.0,s,cspread(0) + + call four2a(cspread,NFFT,1,1,1) !Transform to time domain + + sum=0. + do i=0,NFFT-1 + p=real(cspread(i))**2 + aimag(cspread(i))**2 + sum=sum+p + enddo + avep=sum/NFFT + fac=sqrt(1.0/avep) + cspread=fac*cspread !Normalize to constant avg power + cdat=cspread(1:npts)*cdat !Apply Rayleigh fading + +! do i=0,NFFT-1 +! p=real(cspread(i))**2 + aimag(cspread(i))**2 +! write(14,3010) i,p,cspread(i) +!3010 format(i8,3f12.6) +! enddo + + endif + + dat=aimag(cdat) + xnoise !Add the generated noise + fac=32767.0/nsigs + if(snrdb.ge.90.0) iwave(1:npts)=nint(fac*dat(1:npts)) + if(snrdb.lt.90.0) iwave(1:npts)=nint(rms*dat(1:npts)) + write(10) h,iwave(1:npts) !Save the .wav file + close(10) + enddo + +999 end program qra64sim diff --git a/libm65/qracodes/Makefile.Win b/libm65/qracodes/Makefile.Win new file mode 100644 index 000000000..fb30504e7 --- /dev/null +++ b/libm65/qracodes/Makefile.Win @@ -0,0 +1,33 @@ +CC = gcc +CFLAGS = -O2 -Wall -I. -D_WIN32 + +# Default rules +%.o: %.c + ${CC} ${CFLAGS} -c $< +%.o: %.f + ${FC} ${FFLAGS} -c $< +%.o: %.F + ${FC} ${FFLAGS} -c $< +%.o: %.f90 + ${FC} ${FFLAGS} -c $< +%.o: %.F90 + ${FC} ${FFLAGS} -c $< + +all: libqra64.a qracodes.exe + +OBJS1 = normrnd.o npfwht.o pdmath.o qra12_63_64_irr_b.o \ + qra13_64_64_irr_e.o qracodes.o + +libqra64.a: $(OBJS1) + ar cr libqra64.a $(OBJS1) + ranlib libqra64.a + +OBJS2 = main.o + +qracodes.exe: $(OBJS2) + ${CC} -o qracodes.exe $(OBJS2) libqra64.a -lm + +.PHONY : clean + +clean: + $(RM) *.o libqra64.a qracodes.exe diff --git a/libm65/qracodes/ebno10000.txt b/libm65/qracodes/ebno10000.txt new file mode 100644 index 000000000..c41174b93 --- /dev/null +++ b/libm65/qracodes/ebno10000.txt @@ -0,0 +1,7 @@ +# Eb/No Values to be used during the code simulation +# Each line of this file indicates the Eb/No value to be simulated (in dB) +# and the number of errors to be detected by the decoder +0.6 10000 +1.1 10000 +1.6 10000 +2.1 10000 diff --git a/libm65/qracodes/ebnovalues.txt b/libm65/qracodes/ebnovalues.txt new file mode 100644 index 000000000..7dba138f0 --- /dev/null +++ b/libm65/qracodes/ebnovalues.txt @@ -0,0 +1,15 @@ +# Eb/No Values to be used during the code simulation +# Each line of this file indicates the Eb/No value to be simulated (in dB) +# and the number of errors to be detected by the decoder +1.1 1000 +1.6 1000 +2.1 1000 +2.6 1000 +3.1 1000 +3.6 1000 +4.1 1000 +4.6 1000 +5.1 500 +5.6 200 +6.1 100 +6.6 50 \ No newline at end of file diff --git a/libm65/qracodes/ebnovaluesfast.txt b/libm65/qracodes/ebnovaluesfast.txt new file mode 100644 index 000000000..b057b312d --- /dev/null +++ b/libm65/qracodes/ebnovaluesfast.txt @@ -0,0 +1,11 @@ +# Eb/No Values to be used during the code simulation +# Each line of this file indicates the Eb/No value to be simulated (in dB) +# and the number of errors to be detected by the decoder +1.1 500 +1.6 500 +2.1 500 +2.6 500 +3.1 500 +3.6 500 +4.1 200 +4.6 50 diff --git a/libm65/qracodes/main.c b/libm65/qracodes/main.c new file mode 100644 index 000000000..5f9f067d4 --- /dev/null +++ b/libm65/qracodes/main.c @@ -0,0 +1,737 @@ +// main.c +// Word Error Rate test example for Q-ary RA codes over GF(64) +// +// (c) 2016 - Nico Palermo, IV3NWV +// +// Thanks to Andrea Montefusco IW0HDV for his help on adapting the sources +// to OSs other than MS Windows +// +// ------------------------------------------------------------------------------ +// 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. +// +// Files in this package: +// main.c - this file +// normrnd.c/.h - random gaussian number generator +// npfwht.c/.h - Fast Walsh-Hadamard Transforms +// pdmath.c/.h - Elementary math on probability distributions +// qra12_63_64_irr_b.c/.h - Tables for a QRA(12,63) irregular RA code over GF(64) +// qra13_64_64_irr_e.c/.h - Tables for a QRA(13,64) irregular RA code " " +// qracodes.c/.h - QRA codes encoding/decoding functions +// +// ------------------------------------------------------------------------------- +// +// 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 . + +// ----------------------------------------------------------------------------- + +// Two codes are available for simulations in this sowftware release: + +// QRA12_63_64_IRR_B: K=12 N=63 Q=64 irregular QRA code (defined in qra12_63_64_irr_b.h /.c) +// QRA13_64_64_IRR_E: K=13 N=64 Q=64 irregular QRA code (defined in qra13_64_64_irr_b.h /.c) + +// Codes with K=13 are designed to include a CRC as the 13th information symbol +// and improve the code UER (Undetected Error Rate). +// The CRC symbol is not sent along the channel (the codes are punctured) and the +// resulting code is still a (12,63) code with an effective code rate of R = 12/63. + +// ------------------------------------------------------------------------------ + +// OS dependent defines and includes -------------------------------------------- + +#if _WIN32 // note the underscore: without it, it's not msdn official! + // Windows (x64 and x86) + #include // required only for GetTickCount(...) + #include // _beginthread +#endif + +#if defined(__linux__) + +// remove unwanted macros +#define __cdecl + +// implements Windows API +#include + + unsigned int GetTickCount(void) { + struct timespec ts; + unsigned int theTick = 0U; + clock_gettime( CLOCK_REALTIME, &ts ); + theTick = ts.tv_nsec / 1000000; + theTick += ts.tv_sec * 1000; + return theTick; +} + +// Convert Windows millisecond sleep +// +// VOID WINAPI Sleep(_In_ DWORD dwMilliseconds); +// +// to Posix usleep (in microseconds) +// +// int usleep(useconds_t usec); +// +#include +#define Sleep(x) usleep(x*1000) + +#endif + +#if defined(__linux__) || ( defined(__MINGW32__) || defined (__MIGW64__) ) +#include +#endif + +#if __APPLE__ +#endif + +#include +#include + +#include "qracodes.h" +#include "normrnd.h" // gaussian numbers generator +#include "pdmath.h" // operations on probability distributions + +// defined codes +#include "qra12_63_64_irr_b.h" +#include "qra13_64_64_irr_e.h" + +// ----------------------------------------------------------------------------------- + +#define NTHREADS_MAX 160 + +// channel types +#define CHANNEL_AWGN 0 +#define CHANNEL_RAYLEIGH 1 + +// amount of a-priori information provided to the decoder +#define AP_NONE 0 +#define AP_28 1 +#define AP_44 2 +#define AP_56 3 + +const char ap_str[4][16] = { + "None", + "28 bit", + "44 bit", + "56 bit" +}; + +const char fnameout_pfx[2][64] = { + "wer-awgn-", + "wer-rayleigh-" +}; +const char fnameout_sfx[4][64] = { + "-ap00.txt", + "-ap28.txt", + "-ap44.txt", + "-ap56.txt" +}; + +const int ap_masks_jt65[4][13] = { +// Each row must be 13 entries long (to handle puntc. codes 13,64) +// The mask of 13th symbol (crc) is alway initializated to 0 + // AP0 - no a-priori knowledge + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + // AP28 - 1st field known [cq ? ?] or [dst ? ?] + {0x3F,0x3F,0x3F,0x3F,0x3C, 0, 0, 0, 0, 0, 0, 0}, + // AP44 - 1st and 3rd fields known [cq ? 0] or [dst ? 0] + {0x3F,0x3F,0x3F,0x3F,0x3C, 0, 0, 0, 0,0x0F,0x3F,0x3F}, + // AP56 - 1st and 2nd fields known [dst src ?] + {0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x30, 0, 0} +}; + +void ix_mask(const qracode *pcode, float *r, const int *mask, const int *x); + +void printword(char *msg, int *x, int size) +{ + int k; + printf("\n%s ",msg); + for (k=0;kc msg buffer + float *qra_c2vmsg; //[qra_NMSG*qra_M]; MP decoder c->v msg buffer + float *rp; // [qra_N*qra_M]; received samples (real component) buffer + float *rq; // [qra_N*qra_M]; received samples (imag component) buffer + float *chp; //[qra_N]; channel gains (real component) buffer + float *chq; //[qra_N]; channel gains (imag component) buffer + float *r; //[qra_N*qra_M]; received samples (amplitude) buffer + float *ix; // [qra_N*qra_M]; // intrinsic information to the MP algorithm + float *ex; // [qra_N*qra_M]; // extrinsic information from the MP algorithm + +} wer_test_ds; + +typedef void( __cdecl *pwer_test_thread)(wer_test_ds*); + +// crc-6 generator polynomial +// g(x) = x^6 + a5*x^5 + ... + a1*x + a0 + +// g(x) = x^6 + x + 1 +#define CRC6_GEN_POL 0x30 // MSB=a0 LSB=a5 + +// g(x) = x^6 + x^2 + x + 1 (as suggested by Joe. See: https://users.ece.cmu.edu/~koopman/crc/) +// #define CRC6_GEN_POL 0x38 // MSB=a0 LSB=a5. Simulation results are similar + +int calc_crc6(int *x, int sz) +{ + int k,j,t,sr = 0; + for (k=0;k>1) ^ CRC6_GEN_POL; + else + sr = (sr>>1); + t>>=1; + } + } + return sr; +} + +void wer_test_thread(wer_test_ds *pdata) +{ + const qracode *pcode=pdata->pcode; + const int qra_K = pcode->K; + const int qra_N = pcode->N; + const int qra_M = pcode->M; + const int qra_m = pcode->m; + const int NSAMPLES = pcode->N*pcode->M; + + const float No = 1.0f; // noise spectral density + const float sigma = (float)sqrt(No/2.0f); // std dev of noise I/Q components + const float sigmach = (float)sqrt(1/2.0f); // std dev of channel I/Q gains + + // Eb/No value for which we optimize the bessel metric + const float EbNodBMetric = 2.8f; + const float EbNoMetric = (float)pow(10,EbNodBMetric/10); + + int k,t,j,diff; + float R; + float EsNoMetric; + float EbNo, EsNo, Es, A; + int channel_type, code_type; + int nt=0; // transmitted codewords + int nerrs = 0; // total number of errors + int nerrsu = 0; // number of undetected errors + int rc; + + + // inizialize pointer to required buffers + int *x=pdata->x; // message buffer + int *y=pdata->y, *ydec=pdata->ydec; // encoded/decoded codeword buffers + float *qra_v2cmsg=pdata->qra_v2cmsg; // table of the v->c messages + float *qra_c2vmsg=pdata->qra_c2vmsg; // table of the c->v messages + float *rp=pdata->rp; // received samples (real component) + float *rq=pdata->rq; // received samples (imag component) + float *chp=pdata->chp; // channel gains (real component) + float *chq=pdata->chq; // channel gains (imag component) + float *r=pdata->r; // received samples amplitudes + float *ix=pdata->ix; // intrinsic information to the MP algorithm + float *ex=pdata->ex; // extrinsic information from the MP algorithm + + channel_type = pdata->channel_type; + code_type = pcode->type; + + // define the (true) code rate accordingly to the code type + switch(code_type) { + case QRATYPE_CRC: + R = 1.0f*(qra_K-1)/qra_N; + break; + case QRATYPE_CRCPUNCTURED: + R = 1.0f*(qra_K-1)/(qra_N-1); + break; + case QRATYPE_NORMAL: + default: + R = 1.0f*(qra_K)/(qra_N); + } + + EsNoMetric = 1.0f*qra_m*R*EbNoMetric; + + EbNo = (float)pow(10,pdata->EbNodB/10); + EsNo = 1.0f*qra_m*R*EbNo; + Es = EsNo*No; + A = (float)sqrt(Es); + + + // encode the input + if (code_type==QRATYPE_CRC || code_type==QRATYPE_CRCPUNCTURED) { + // compute the information message symbol check as the (negated) xor of all the + // information message symbols + for (k=0;k<(qra_K-1);k++) + x[k]=k%qra_M; + x[k]=calc_crc6(x,qra_K-1); + } + else + for (k=0;kstop==0) { + + // simulate the channel + // NOTE: in the case that the code is punctured, for simplicity + // we compute the channel outputs and the metric also for the crc symbol + // then we ignore its observation. + normrnd_s(rp,NSAMPLES,0,sigma); + normrnd_s(rq,NSAMPLES,0,sigma); + + if (channel_type == CHANNEL_AWGN) { + for (k=0;kdone = 1; + return; // unknown channel type + } + + // compute the squares of the amplitudes of the received samples + for (k=0;km,pcode->N,EsNoMetric); + + if (code_type==QRATYPE_CRCPUNCTURED) { + // ignore observations of the CRC symbol as it is not actually sent + // over the channel + pd_init(PD_ROWADDR(ix,qra_M,qra_K),pd_uniform(qra_m),qra_M); + } + + + if (pdata->ap_index!=0) + // mask channel observations with a priori knowledge + ix_mask(pcode,ix,ap_masks_jt65[pdata->ap_index],x); + + + // compute the extrinsic symbols probabilities with the message-passing algorithm + // stop if extrinsic information does not converges to 1 within the given number of iterations + rc = qra_extrinsic(pcode,ex,ix,100,qra_v2cmsg,qra_c2vmsg); + + if (rc>=0) { // the MP algorithm converged to Iex~1 in rc iterations + + // decode the codeword + qra_mapdecode(pcode,ydec,ex,ix); + + // look for undetected errors + if (code_type==QRATYPE_CRC || code_type==QRATYPE_CRCPUNCTURED) { + + j = 0; diff = 0; + for (k=0;k<(qra_K-1);k++) + diff |= (ydec[k]!=x[k]); + t = calc_crc6(ydec,qra_K-1); + if (t!=ydec[k]) // error detected - crc doesn't matches + nerrs += 1; + else + if (diff) { // decoded message is not equal to the transmitted one but + // the crc test passed + // add as undetected error + nerrsu += 1; + nerrs += 1; + // uncomment to see what the undetected error pattern looks like + //printword("U", ydec); + } + } + else + for (k=0;knt=nt; + pdata->nerrs=nerrs; + pdata->nerrsu=nerrsu; + + } + + pdata->done=1; + + #if _WIN32 + _endthread(); + #endif +} + +#if defined(__linux__) || ( defined(__MINGW32__) || defined (__MIGW64__) ) + +void *wer_test_pthread(void *p) +{ + wer_test_thread ((wer_test_ds *)p); + return 0; +} + +#endif + +void ix_mask(const qracode *pcode, float *r, const int *mask, const int *x) +{ + // mask intrinsic information (channel observations) with a priori knowledge + + int k,kk, smask; + const int qra_K=pcode->K; + const int qra_M=pcode->M; + const int qra_m=pcode->m; + + for (k=0;kNTHREADS_MAX) { + printf("Error: nthreads should be <=%d\n",NTHREADS_MAX); + return -1; + } + + sprintf(fnameout,"%s%s%s", + fnameout_pfx[chtype], + pcode->name, + fnameout_sfx[ap_index]); + + fout = fopen(fnameout,"w"); + fprintf(fout,"# Channel (0=AWGN,1=Rayleigh), Eb/No (dB), Transmitted codewords, Errors, Undetected Errors, Avg dec. time (ms), WER\n"); + + printf("\nTesting the code %s over the %s channel\nSimulation data will be saved to %s\n", + pcode->name, + chtype==CHANNEL_AWGN?"AWGN":"Rayleigh", + fnameout); + fflush (stdout); + + // init fixed thread parameters and preallocate buffers + for (j=0;jK*sizeof(int)); + wt[j].y = (int*)malloc(pcode->N*sizeof(int)); + wt[j].ydec = (int*)malloc(pcode->N*sizeof(int)); + wt[j].qra_v2cmsg = (float*)malloc(pcode->NMSG*pcode->M*sizeof(float)); + wt[j].qra_c2vmsg = (float*)malloc(pcode->NMSG*pcode->M*sizeof(float)); + wt[j].rp = (float*)malloc(pcode->N*pcode->M*sizeof(float)); + wt[j].rq = (float*)malloc(pcode->N*pcode->M*sizeof(float)); + wt[j].chp = (float*)malloc(pcode->N*sizeof(float)); + wt[j].chq = (float*)malloc(pcode->N*sizeof(float)); + wt[j].r = (float*)malloc(pcode->N*pcode->M*sizeof(float)); + wt[j].ix = (float*)malloc(pcode->N*pcode->M*sizeof(float)); + wt[j].ex = (float*)malloc(pcode->N*pcode->M*sizeof(float)); + } + + + for (k=0;k=nerrstgt[k]) { + for (j=0;j] [-t] [-c] [-a] [-f[-h]\n"); + printf("Options: \n"); + printf(" -q: code to simulate. 0=qra_12_63_64_irr_b\n"); + printf(" 1=qra_13_64_64_irr_e (default)\n"); + printf(" -t : number of threads to be used for the simulation [1..24]\n"); + printf(" (default=8)\n"); + printf(" -c : channel_type. 0=AWGN 1=Rayleigh \n"); + printf(" (default=AWGN)\n"); + printf(" -a : amount of a-priori information provided to decoder. \n"); + printf(" 0= No a-priori (default)\n"); + printf(" 1= 28 bit \n"); + printf(" 2= 44 bit \n"); + printf(" 3= 56 bit \n"); + printf(" -f : name of the file containing the Eb/No values to be simulated\n"); + printf(" (default=ebnovalues.txt)\n"); + printf(" This file should contain lines in this format:\n"); + printf(" # Eb/No(dB) Target Errors\n"); + printf(" 0.1 5000\n"); + printf(" 0.6 5000\n"); + printf(" 1.1 1000\n"); + printf(" 1.6 1000\n"); + printf(" ...\n"); + printf(" (lines beginning with a # are treated as comments\n\n"); +} + +#define SIM_POINTS_MAX 20 + +int main(int argc, char* argv[]) +{ + + float EbNodB[SIM_POINTS_MAX]; + int nerrstgt[SIM_POINTS_MAX]; + FILE *fin; + + char fnamein[128]= "ebnovalues.txt"; + char buf[128]; + + int nitems = 0; + int code_idx = 1; + int nthreads = 8; + int ch_type = CHANNEL_AWGN; + int ap_index = AP_NONE; + + // parse command line + while(--argc) { + argv++; + if (strncmp(*argv,"-h",2)==0) { + syntax(); + return 0; + } + else + if (strncmp(*argv,"-q",2)==0) { + code_idx = (int)atoi((*argv)+2); + if (code_idx>1) { + printf("Invalid code index\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-t",2)==0) { + nthreads = (int)atoi((*argv)+2); + printf("nthreads = %d\n",nthreads); + if (nthreads>NTHREADS_MAX) { + printf("Invalid number of threads\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-c",2)==0) { + ch_type = (int)atoi((*argv)+2); + if (ch_type>CHANNEL_RAYLEIGH) { + printf("Invalid channel type\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-a",2)==0) { + ap_index = (int)atoi((*argv)+2); + if (ap_index>AP_56) { + printf("Invalid a-priori information index\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-f",2)==0) { + strncpy(fnamein,(*argv)+2,127); + } + else + if (strncmp(*argv,"-h",2)==0) { + syntax(); + return -1; + } + else { + printf("Invalid option\n"); + syntax(); + return -1; + } + } + + // parse points to be simulated from the input file + fin = fopen(fnamein,"r"); + if (!fin) { + printf("Can't open file: %s\n",fnamein); + syntax(); + } + + while (fgets(buf,128,fin)!=0) + if (*buf=='#' || *buf=='\n' ) + continue; + else + if (nitems==SIM_POINTS_MAX) + break; + else + if (sscanf(buf,"%f %u",&EbNodB[nitems],&nerrstgt[nitems])!=2) { + printf("Invalid input file format\n"); + syntax(); + return -1; + } + else + nitems++; + + fclose(fin); + + if (nitems==0) { + printf("No Eb/No point specified in file %s\n",fnamein); + syntax(); + return -1; + } + + printf("\nQ-ary Repeat-Accumulate Code Word Error Rate Simulator\n"); + printf("2016, Nico Palermo - IV3NWV\n\n"); + + printf("Nthreads = %d\n",nthreads); + printf("Channel = %s\n",ch_type==CHANNEL_AWGN?"AWGN":"Rayleigh"); + printf("Codename = %s\n",codetotest[code_idx]->name); + printf("A-priori = %s\n",ap_str[ap_index]); + printf("Eb/No input file = %s\n\n",fnamein); + + wer_test_proc(codetotest[code_idx], nthreads, ch_type, ap_index, EbNodB, nerrstgt, nitems); + + return 0; +} + diff --git a/libm65/qracodes/normrnd.c b/libm65/qracodes/normrnd.c new file mode 100644 index 000000000..90abfa425 --- /dev/null +++ b/libm65/qracodes/normrnd.c @@ -0,0 +1,82 @@ +// normrnd.c +// functions to generate gaussian distributed numbers +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// +// Credits to Andrea Montefusco - IW0HDV for his help on adapting the sources +// to OSs other than MS Windows +// +// ------------------------------------------------------------------------------ +// 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 . + + +#include "normrnd.h" + +#if _WIN32 // note the underscore: without it, it's not msdn official! + // Windows (x64 and x86) + #include // required only for GetTickCount(...) + #define K_RAND_MAX UINT_MAX +#elif _SVID_SOURCE || _XOPEN_SOURCE || __unix__ || (defined (__APPLE__) && defined(__MACH__)) /* POSIX or Unix or Apple */ + #include + #define rand_s(x) (*x)=(unsigned int)lrand48() // returns unsigned integers in the range 0..0x7FFFFFFF + #define K_RAND_MAX 0x7FFFFFFF // that's the max number + // generated by lrand48 +#else + #error "No good quality PRNG found" +#endif + + +// use MS rand_s(...) function +void normrnd_s(float *dst, int nitems, float mean, float stdev) +{ + unsigned int r; + float phi=0, u=0; + int set = 0; + + while (nitems--) + if (set==1) { + *dst++ = (float)sin(phi)*u*stdev+mean; + set = 0; + } + else { + rand_s((unsigned int*)&r); phi = (M_2PI/(1.0f+K_RAND_MAX))*r; + rand_s((unsigned int*)&r); u = (float)sqrt(-2.0f* log( (1.0f/(1.0f+K_RAND_MAX))*(1.0f+r) ) ); + *dst++ = (float)cos(phi)*u*stdev+mean; + set=1; + } +} + +/* NOT USED +// use MS rand() function +void normrnd(float *dst, int nitems, float mean, float stdev) +{ + float phi=0, u=0; + int set = 0; + + while (nitems--) + if (set==1) { + *dst++ = (float)sin(phi)*u*stdev+mean; + set = 0; + } + else { + phi = (M_2PI/(1.0f+RAND_MAX))*rand(); + u = (float)sqrt(-2.0f* log( (1.0f/(1.0f+RAND_MAX))*(1.0f+rand()) ) ); + *dst++ = (float)cos(phi)*u*stdev+mean; + set=1; + } +} +*/ diff --git a/libm65/qracodes/normrnd.h b/libm65/qracodes/normrnd.h new file mode 100644 index 000000000..dd4b65bbe --- /dev/null +++ b/libm65/qracodes/normrnd.h @@ -0,0 +1,51 @@ +// normrnd.h +// Functions to generate gaussian distributed numbers +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// 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 . + +#ifndef _normrnd_h_ +#define _normrnd_h_ + +#define _CRT_RAND_S +#include + +#define _USE_MATH_DEFINES +#include +#define M_2PI (2.0f*(float)M_PI) + +#ifdef __cplusplus +extern "C" { +#endif + +void normrnd_s(float *dst, int nitems, float mean, float stdev); +// generate a random array of numbers with a gaussian distribution of given mean and stdev +// use MS rand_s(...) function + +/* not used +void normrnd(float *dst, int nitems, float mean, float stdev); +// generate a random array of numbers with a gaussian distribution of given mean and stdev +// use MS rand() function +*/ + +#ifdef __cplusplus +} +#endif + +#endif // _normrnd_h_ + diff --git a/libm65/qracodes/npfwht.c b/libm65/qracodes/npfwht.c new file mode 100644 index 000000000..5732ce913 --- /dev/null +++ b/libm65/qracodes/npfwht.c @@ -0,0 +1,216 @@ +// npfwht.c +// Basic implementation of the Fast Walsh-Hadamard Transforms +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// 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 . + +#include "npfwht.h" + +#define WHBFY(dst,src,base,offs,dist) { dst[base+offs]=src[base+offs]+src[base+offs+dist]; dst[base+offs+dist]=src[base+offs]-src[base+offs+dist]; } + +typedef void (*pnp_fwht)(float*,float*); + +static void np_fwht2(float *dst, float *src); + +static void np_fwht1(float *dst, float *src); +static void np_fwht2(float *dst, float *src); +static void np_fwht4(float *dst, float *src); +static void np_fwht8(float *dst, float *src); +static void np_fwht16(float *dst, float *src); +static void np_fwht32(float *dst, float *src); +static void np_fwht64(float *dst, float *src); + +static pnp_fwht np_fwht_tab[7] = { + np_fwht1, + np_fwht2, + np_fwht4, + np_fwht8, + np_fwht16, + np_fwht32, + np_fwht64 +}; + +void np_fwht(int nlogdim, float *dst, float *src) +{ + np_fwht_tab[nlogdim](dst,src); +} + +static void np_fwht1(float *dst, float *src) +{ + dst[0] = src[0]; +} + + +static void np_fwht2(float *dst, float *src) +{ + float t[2]; + + WHBFY(t,src,0,0,1); + dst[0]= t[0]; + dst[1]= t[1]; +} + +static void np_fwht4(float *dst, float *src) +{ + float t[4]; + + // group 1 + WHBFY(t,src,0,0,2); WHBFY(t,src,0,1,2); + // group 2 + WHBFY(dst,t,0,0,1); WHBFY(dst,t,2,0,1); +}; + + +static void np_fwht8(float *dst, float *src) +{ + float t[16]; + float *t1=t, *t2=t+8; + + // group 1 + WHBFY(t1,src,0,0,4); WHBFY(t1,src,0,1,4); WHBFY(t1,src,0,2,4); WHBFY(t1,src,0,3,4); + // group 2 + WHBFY(t2,t1,0,0,2); WHBFY(t2,t1,0,1,2); WHBFY(t2,t1,4,0,2); WHBFY(t2,t1,4,1,2); + // group 3 + WHBFY(dst,t2,0,0,1); WHBFY(dst,t2,2,0,1); WHBFY(dst,t2,4,0,1); WHBFY(dst,t2,6,0,1); +}; + + +static void np_fwht16(float *dst, float *src) +{ + float t[32]; + float *t1=t, *t2=t+16; + + // group 1 + WHBFY(t1,src,0,0,8); WHBFY(t1,src,0,1,8); WHBFY(t1,src,0,2,8); WHBFY(t1,src,0,3,8); + WHBFY(t1,src,0,4,8); WHBFY(t1,src,0,5,8); WHBFY(t1,src,0,6,8); WHBFY(t1,src,0,7,8); + // group 2 + WHBFY(t2,t1,0,0,4); WHBFY(t2,t1,0,1,4); WHBFY(t2,t1,0,2,4); WHBFY(t2,t1,0,3,4); + WHBFY(t2,t1,8,0,4); WHBFY(t2,t1,8,1,4); WHBFY(t2,t1,8,2,4); WHBFY(t2,t1,8,3,4); + // group 3 + WHBFY(t1,t2,0,0,2); WHBFY(t1,t2,0,1,2); WHBFY(t1,t2,4,0,2); WHBFY(t1,t2,4,1,2); + WHBFY(t1,t2,8,0,2); WHBFY(t1,t2,8,1,2); WHBFY(t1,t2,12,0,2); WHBFY(t1,t2,12,1,2); + // group 4 + WHBFY(dst,t1,0,0,1); WHBFY(dst,t1,2,0,1); WHBFY(dst,t1,4,0,1); WHBFY(dst,t1,6,0,1); + WHBFY(dst,t1,8,0,1); WHBFY(dst,t1,10,0,1); WHBFY(dst,t1,12,0,1); WHBFY(dst,t1,14,0,1); + +} + +static void np_fwht32(float *dst, float *src) +{ + float t[64]; + float *t1=t, *t2=t+32; + + // group 1 + WHBFY(t1,src,0,0,16); WHBFY(t1,src,0,1,16); WHBFY(t1,src,0,2,16); WHBFY(t1,src,0,3,16); + WHBFY(t1,src,0,4,16); WHBFY(t1,src,0,5,16); WHBFY(t1,src,0,6,16); WHBFY(t1,src,0,7,16); + WHBFY(t1,src,0,8,16); WHBFY(t1,src,0,9,16); WHBFY(t1,src,0,10,16); WHBFY(t1,src,0,11,16); + WHBFY(t1,src,0,12,16); WHBFY(t1,src,0,13,16); WHBFY(t1,src,0,14,16); WHBFY(t1,src,0,15,16); + + // group 2 + WHBFY(t2,t1,0,0,8); WHBFY(t2,t1,0,1,8); WHBFY(t2,t1,0,2,8); WHBFY(t2,t1,0,3,8); + WHBFY(t2,t1,0,4,8); WHBFY(t2,t1,0,5,8); WHBFY(t2,t1,0,6,8); WHBFY(t2,t1,0,7,8); + WHBFY(t2,t1,16,0,8); WHBFY(t2,t1,16,1,8); WHBFY(t2,t1,16,2,8); WHBFY(t2,t1,16,3,8); + WHBFY(t2,t1,16,4,8); WHBFY(t2,t1,16,5,8); WHBFY(t2,t1,16,6,8); WHBFY(t2,t1,16,7,8); + + // group 3 + WHBFY(t1,t2,0,0,4); WHBFY(t1,t2,0,1,4); WHBFY(t1,t2,0,2,4); WHBFY(t1,t2,0,3,4); + WHBFY(t1,t2,8,0,4); WHBFY(t1,t2,8,1,4); WHBFY(t1,t2,8,2,4); WHBFY(t1,t2,8,3,4); + WHBFY(t1,t2,16,0,4); WHBFY(t1,t2,16,1,4); WHBFY(t1,t2,16,2,4); WHBFY(t1,t2,16,3,4); + WHBFY(t1,t2,24,0,4); WHBFY(t1,t2,24,1,4); WHBFY(t1,t2,24,2,4); WHBFY(t1,t2,24,3,4); + + // group 4 + WHBFY(t2,t1,0,0,2); WHBFY(t2,t1,0,1,2); WHBFY(t2,t1,4,0,2); WHBFY(t2,t1,4,1,2); + WHBFY(t2,t1,8,0,2); WHBFY(t2,t1,8,1,2); WHBFY(t2,t1,12,0,2); WHBFY(t2,t1,12,1,2); + WHBFY(t2,t1,16,0,2); WHBFY(t2,t1,16,1,2); WHBFY(t2,t1,20,0,2); WHBFY(t2,t1,20,1,2); + WHBFY(t2,t1,24,0,2); WHBFY(t2,t1,24,1,2); WHBFY(t2,t1,28,0,2); WHBFY(t2,t1,28,1,2); + + // group 5 + WHBFY(dst,t2,0,0,1); WHBFY(dst,t2,2,0,1); WHBFY(dst,t2,4,0,1); WHBFY(dst,t2,6,0,1); + WHBFY(dst,t2,8,0,1); WHBFY(dst,t2,10,0,1); WHBFY(dst,t2,12,0,1); WHBFY(dst,t2,14,0,1); + WHBFY(dst,t2,16,0,1); WHBFY(dst,t2,18,0,1); WHBFY(dst,t2,20,0,1); WHBFY(dst,t2,22,0,1); + WHBFY(dst,t2,24,0,1); WHBFY(dst,t2,26,0,1); WHBFY(dst,t2,28,0,1); WHBFY(dst,t2,30,0,1); + +} + +static void np_fwht64(float *dst, float *src) +{ + float t[128]; + float *t1=t, *t2=t+64; + + + // group 1 + WHBFY(t1,src,0,0,32); WHBFY(t1,src,0,1,32); WHBFY(t1,src,0,2,32); WHBFY(t1,src,0,3,32); + WHBFY(t1,src,0,4,32); WHBFY(t1,src,0,5,32); WHBFY(t1,src,0,6,32); WHBFY(t1,src,0,7,32); + WHBFY(t1,src,0,8,32); WHBFY(t1,src,0,9,32); WHBFY(t1,src,0,10,32); WHBFY(t1,src,0,11,32); + WHBFY(t1,src,0,12,32); WHBFY(t1,src,0,13,32); WHBFY(t1,src,0,14,32); WHBFY(t1,src,0,15,32); + WHBFY(t1,src,0,16,32); WHBFY(t1,src,0,17,32); WHBFY(t1,src,0,18,32); WHBFY(t1,src,0,19,32); + WHBFY(t1,src,0,20,32); WHBFY(t1,src,0,21,32); WHBFY(t1,src,0,22,32); WHBFY(t1,src,0,23,32); + WHBFY(t1,src,0,24,32); WHBFY(t1,src,0,25,32); WHBFY(t1,src,0,26,32); WHBFY(t1,src,0,27,32); + WHBFY(t1,src,0,28,32); WHBFY(t1,src,0,29,32); WHBFY(t1,src,0,30,32); WHBFY(t1,src,0,31,32); + + // group 2 + WHBFY(t2,t1,0,0,16); WHBFY(t2,t1,0,1,16); WHBFY(t2,t1,0,2,16); WHBFY(t2,t1,0,3,16); + WHBFY(t2,t1,0,4,16); WHBFY(t2,t1,0,5,16); WHBFY(t2,t1,0,6,16); WHBFY(t2,t1,0,7,16); + WHBFY(t2,t1,0,8,16); WHBFY(t2,t1,0,9,16); WHBFY(t2,t1,0,10,16); WHBFY(t2,t1,0,11,16); + WHBFY(t2,t1,0,12,16); WHBFY(t2,t1,0,13,16); WHBFY(t2,t1,0,14,16); WHBFY(t2,t1,0,15,16); + + WHBFY(t2,t1,32,0,16); WHBFY(t2,t1,32,1,16); WHBFY(t2,t1,32,2,16); WHBFY(t2,t1,32,3,16); + WHBFY(t2,t1,32,4,16); WHBFY(t2,t1,32,5,16); WHBFY(t2,t1,32,6,16); WHBFY(t2,t1,32,7,16); + WHBFY(t2,t1,32,8,16); WHBFY(t2,t1,32,9,16); WHBFY(t2,t1,32,10,16); WHBFY(t2,t1,32,11,16); + WHBFY(t2,t1,32,12,16); WHBFY(t2,t1,32,13,16); WHBFY(t2,t1,32,14,16); WHBFY(t2,t1,32,15,16); + + // group 3 + WHBFY(t1,t2,0,0,8); WHBFY(t1,t2,0,1,8); WHBFY(t1,t2,0,2,8); WHBFY(t1,t2,0,3,8); + WHBFY(t1,t2,0,4,8); WHBFY(t1,t2,0,5,8); WHBFY(t1,t2,0,6,8); WHBFY(t1,t2,0,7,8); + WHBFY(t1,t2,16,0,8); WHBFY(t1,t2,16,1,8); WHBFY(t1,t2,16,2,8); WHBFY(t1,t2,16,3,8); + WHBFY(t1,t2,16,4,8); WHBFY(t1,t2,16,5,8); WHBFY(t1,t2,16,6,8); WHBFY(t1,t2,16,7,8); + WHBFY(t1,t2,32,0,8); WHBFY(t1,t2,32,1,8); WHBFY(t1,t2,32,2,8); WHBFY(t1,t2,32,3,8); + WHBFY(t1,t2,32,4,8); WHBFY(t1,t2,32,5,8); WHBFY(t1,t2,32,6,8); WHBFY(t1,t2,32,7,8); + WHBFY(t1,t2,48,0,8); WHBFY(t1,t2,48,1,8); WHBFY(t1,t2,48,2,8); WHBFY(t1,t2,48,3,8); + WHBFY(t1,t2,48,4,8); WHBFY(t1,t2,48,5,8); WHBFY(t1,t2,48,6,8); WHBFY(t1,t2,48,7,8); + + // group 4 + WHBFY(t2,t1,0,0,4); WHBFY(t2,t1,0,1,4); WHBFY(t2,t1,0,2,4); WHBFY(t2,t1,0,3,4); + WHBFY(t2,t1,8,0,4); WHBFY(t2,t1,8,1,4); WHBFY(t2,t1,8,2,4); WHBFY(t2,t1,8,3,4); + WHBFY(t2,t1,16,0,4); WHBFY(t2,t1,16,1,4); WHBFY(t2,t1,16,2,4); WHBFY(t2,t1,16,3,4); + WHBFY(t2,t1,24,0,4); WHBFY(t2,t1,24,1,4); WHBFY(t2,t1,24,2,4); WHBFY(t2,t1,24,3,4); + WHBFY(t2,t1,32,0,4); WHBFY(t2,t1,32,1,4); WHBFY(t2,t1,32,2,4); WHBFY(t2,t1,32,3,4); + WHBFY(t2,t1,40,0,4); WHBFY(t2,t1,40,1,4); WHBFY(t2,t1,40,2,4); WHBFY(t2,t1,40,3,4); + WHBFY(t2,t1,48,0,4); WHBFY(t2,t1,48,1,4); WHBFY(t2,t1,48,2,4); WHBFY(t2,t1,48,3,4); + WHBFY(t2,t1,56,0,4); WHBFY(t2,t1,56,1,4); WHBFY(t2,t1,56,2,4); WHBFY(t2,t1,56,3,4); + + // group 5 + WHBFY(t1,t2,0,0,2); WHBFY(t1,t2,0,1,2); WHBFY(t1,t2,4,0,2); WHBFY(t1,t2,4,1,2); + WHBFY(t1,t2,8,0,2); WHBFY(t1,t2,8,1,2); WHBFY(t1,t2,12,0,2); WHBFY(t1,t2,12,1,2); + WHBFY(t1,t2,16,0,2); WHBFY(t1,t2,16,1,2); WHBFY(t1,t2,20,0,2); WHBFY(t1,t2,20,1,2); + WHBFY(t1,t2,24,0,2); WHBFY(t1,t2,24,1,2); WHBFY(t1,t2,28,0,2); WHBFY(t1,t2,28,1,2); + WHBFY(t1,t2,32,0,2); WHBFY(t1,t2,32,1,2); WHBFY(t1,t2,36,0,2); WHBFY(t1,t2,36,1,2); + WHBFY(t1,t2,40,0,2); WHBFY(t1,t2,40,1,2); WHBFY(t1,t2,44,0,2); WHBFY(t1,t2,44,1,2); + WHBFY(t1,t2,48,0,2); WHBFY(t1,t2,48,1,2); WHBFY(t1,t2,52,0,2); WHBFY(t1,t2,52,1,2); + WHBFY(t1,t2,56,0,2); WHBFY(t1,t2,56,1,2); WHBFY(t1,t2,60,0,2); WHBFY(t1,t2,60,1,2); + + // group 6 + WHBFY(dst,t1,0,0,1); WHBFY(dst,t1,2,0,1); WHBFY(dst,t1,4,0,1); WHBFY(dst,t1,6,0,1); + WHBFY(dst,t1,8,0,1); WHBFY(dst,t1,10,0,1); WHBFY(dst,t1,12,0,1); WHBFY(dst,t1,14,0,1); + WHBFY(dst,t1,16,0,1); WHBFY(dst,t1,18,0,1); WHBFY(dst,t1,20,0,1); WHBFY(dst,t1,22,0,1); + WHBFY(dst,t1,24,0,1); WHBFY(dst,t1,26,0,1); WHBFY(dst,t1,28,0,1); WHBFY(dst,t1,30,0,1); + WHBFY(dst,t1,32,0,1); WHBFY(dst,t1,34,0,1); WHBFY(dst,t1,36,0,1); WHBFY(dst,t1,38,0,1); + WHBFY(dst,t1,40,0,1); WHBFY(dst,t1,42,0,1); WHBFY(dst,t1,44,0,1); WHBFY(dst,t1,46,0,1); + WHBFY(dst,t1,48,0,1); WHBFY(dst,t1,50,0,1); WHBFY(dst,t1,52,0,1); WHBFY(dst,t1,54,0,1); + WHBFY(dst,t1,56,0,1); WHBFY(dst,t1,58,0,1); WHBFY(dst,t1,60,0,1); WHBFY(dst,t1,62,0,1); +} \ No newline at end of file diff --git a/libm65/qracodes/npfwht.h b/libm65/qracodes/npfwht.h new file mode 100644 index 000000000..9452e2077 --- /dev/null +++ b/libm65/qracodes/npfwht.h @@ -0,0 +1,45 @@ +// np_fwht.h +// Basic implementation of the Fast Walsh-Hadamard Transforms +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// 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 . + +#ifndef _npfwht_h_ +#define _npfwht_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +void np_fwht(int nlogdim, float *dst, float *src); +// Compute the Walsh-Hadamard transform of the given data up to a +// 64-dimensional transform +// +// Input parameters: +// nlogdim: log2 of the transform size. Must be in the range [0..6] +// src : pointer to the input data buffer. +// dst : pointer to the output data buffer. +// +// src and dst must point to preallocated data buffers of size 2^nlogdim*sizeof(float) +// src and dst buffers can overlap + +#ifdef __cplusplus +} +#endif + +#endif // _npfwht_ diff --git a/libm65/qracodes/pdmath.c b/libm65/qracodes/pdmath.c new file mode 100644 index 000000000..47ecab917 --- /dev/null +++ b/libm65/qracodes/pdmath.c @@ -0,0 +1,385 @@ +// pdmath.c +// Elementary math on probability distributions +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// 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 . + +#include "pdmath.h" + +typedef const float *ppd_uniform; +typedef void (*ppd_imul)(float*,const float*); +typedef float (*ppd_norm)(float*); + +// define vector size in function of its logarithm in base 2 +static const int pd_log2dim[7] = { + 1,2,4,8,16,32,64 +}; + +// define uniform distributions of given size +static const float pd_uniform1[1] = { + 1. +}; +static const float pd_uniform2[2] = { + 1./2., 1./2. +}; +static const float pd_uniform4[4] = { + 1./4., 1./4.,1./4., 1./4. +}; +static const float pd_uniform8[8] = { + 1./8., 1./8.,1./8., 1./8.,1./8., 1./8.,1./8., 1./8. +}; +static const float pd_uniform16[16] = { + 1./16., 1./16., 1./16., 1./16.,1./16., 1./16.,1./16., 1./16., + 1./16., 1./16., 1./16., 1./16.,1./16., 1./16.,1./16., 1./16. +}; +static const float pd_uniform32[32] = { + 1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32., + 1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32., + 1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32., + 1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32. +}; +static const float pd_uniform64[64] = { + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64. + +}; + +static const ppd_uniform pd_uniform_tab[7] = { + pd_uniform1, + pd_uniform2, + pd_uniform4, + pd_uniform8, + pd_uniform16, + pd_uniform32, + pd_uniform64 +}; + +// returns a pointer to the uniform distribution of the given logsize +const float *pd_uniform(int nlogdim) +{ + return pd_uniform_tab[nlogdim]; +} + +// in-place multiplication functions +// compute dst = dst*src for any element of the distrib + +static void pd_imul1(float *dst, const float *src) +{ + dst[0] *= src[0]; +} + +static void pd_imul2(float *dst, const float *src) +{ + dst[0] *= src[0]; dst[1] *= src[1]; +} +static void pd_imul4(float *dst, const float *src) +{ + dst[0] *= src[0]; dst[1] *= src[1]; + dst[2] *= src[2]; dst[3] *= src[3]; +} +static void pd_imul8(float *dst, const float *src) +{ + dst[0] *= src[0]; dst[1] *= src[1]; dst[2] *= src[2]; dst[3] *= src[3]; + dst[4] *= src[4]; dst[5] *= src[5]; dst[6] *= src[6]; dst[7] *= src[7]; +} +static void pd_imul16(float *dst, const float *src) +{ + dst[0] *= src[0]; dst[1] *= src[1]; dst[2] *= src[2]; dst[3] *= src[3]; + dst[4] *= src[4]; dst[5] *= src[5]; dst[6] *= src[6]; dst[7] *= src[7]; + dst[8] *= src[8]; dst[9] *= src[9]; dst[10]*= src[10]; dst[11]*= src[11]; + dst[12]*= src[12]; dst[13]*= src[13]; dst[14]*= src[14]; dst[15]*= src[15]; +} +static void pd_imul32(float *dst, const float *src) +{ + pd_imul16(dst,src); + pd_imul16(dst+16,src+16); +} +static void pd_imul64(float *dst, const float *src) +{ + pd_imul16(dst, src); + pd_imul16(dst+16, src+16); + pd_imul16(dst+32, src+32); + pd_imul16(dst+48, src+48); +} + +static const ppd_imul pd_imul_tab[7] = { + pd_imul1, + pd_imul2, + pd_imul4, + pd_imul8, + pd_imul16, + pd_imul32, + pd_imul64 +}; + +// in place multiplication +// compute dst = dst*src for any element of the distrib give their log2 size +// arguments must be pointers to array of floats of the given size +void pd_imul(float *dst, const float *src, int nlogdim) +{ + pd_imul_tab[nlogdim](dst,src); +} + +static float pd_norm1(float *ppd) +{ + float t = ppd[0]; + ppd[0] = 1.f; + return t; +} + +static float pd_norm2(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; + + if (t<=0) { + pd_init(ppd,pd_uniform(1),pd_log2dim[1]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; + return to; + +} + +static float pd_norm4(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + + if (t<=0) { + pd_init(ppd,pd_uniform(2),pd_log2dim[2]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + return to; +} + +static float pd_norm8(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7]; + + if (t<=0) { + pd_init(ppd,pd_uniform(3),pd_log2dim[3]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t; + return to; +} +static float pd_norm16(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7]; + t +=ppd[8]; t +=ppd[9]; t +=ppd[10]; t +=ppd[11]; + t +=ppd[12]; t +=ppd[13]; t +=ppd[14]; t +=ppd[15]; + + if (t<=0) { + pd_init(ppd,pd_uniform(4),pd_log2dim[4]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t; + ppd[8] *=t; ppd[9] *=t; ppd[10] *=t; ppd[11] *=t; + ppd[12] *=t; ppd[13] *=t; ppd[14] *=t; ppd[15] *=t; + + return to; +} +static float pd_norm32(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7]; + t +=ppd[8]; t +=ppd[9]; t +=ppd[10]; t +=ppd[11]; + t +=ppd[12]; t +=ppd[13]; t +=ppd[14]; t +=ppd[15]; + t +=ppd[16]; t +=ppd[17]; t +=ppd[18]; t +=ppd[19]; + t +=ppd[20]; t +=ppd[21]; t +=ppd[22]; t +=ppd[23]; + t +=ppd[24]; t +=ppd[25]; t +=ppd[26]; t +=ppd[27]; + t +=ppd[28]; t +=ppd[29]; t +=ppd[30]; t +=ppd[31]; + + if (t<=0) { + pd_init(ppd,pd_uniform(5),pd_log2dim[5]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t; + ppd[8] *=t; ppd[9] *=t; ppd[10] *=t; ppd[11] *=t; + ppd[12] *=t; ppd[13] *=t; ppd[14] *=t; ppd[15] *=t; + ppd[16] *=t; ppd[17] *=t; ppd[18] *=t; ppd[19] *=t; + ppd[20] *=t; ppd[21] *=t; ppd[22] *=t; ppd[23] *=t; + ppd[24] *=t; ppd[25] *=t; ppd[26] *=t; ppd[27] *=t; + ppd[28] *=t; ppd[29] *=t; ppd[30] *=t; ppd[31] *=t; + + return to; +} + +static float pd_norm64(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7]; + t +=ppd[8]; t +=ppd[9]; t +=ppd[10]; t +=ppd[11]; + t +=ppd[12]; t +=ppd[13]; t +=ppd[14]; t +=ppd[15]; + t +=ppd[16]; t +=ppd[17]; t +=ppd[18]; t +=ppd[19]; + t +=ppd[20]; t +=ppd[21]; t +=ppd[22]; t +=ppd[23]; + t +=ppd[24]; t +=ppd[25]; t +=ppd[26]; t +=ppd[27]; + t +=ppd[28]; t +=ppd[29]; t +=ppd[30]; t +=ppd[31]; + + t +=ppd[32]; t +=ppd[33]; t +=ppd[34]; t +=ppd[35]; + t +=ppd[36]; t +=ppd[37]; t +=ppd[38]; t +=ppd[39]; + t +=ppd[40]; t +=ppd[41]; t +=ppd[42]; t +=ppd[43]; + t +=ppd[44]; t +=ppd[45]; t +=ppd[46]; t +=ppd[47]; + t +=ppd[48]; t +=ppd[49]; t +=ppd[50]; t +=ppd[51]; + t +=ppd[52]; t +=ppd[53]; t +=ppd[54]; t +=ppd[55]; + t +=ppd[56]; t +=ppd[57]; t +=ppd[58]; t +=ppd[59]; + t +=ppd[60]; t +=ppd[61]; t +=ppd[62]; t +=ppd[63]; + + if (t<=0) { + pd_init(ppd,pd_uniform(6),pd_log2dim[6]); + return t; + } + + to = t; + t = 1.0f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t; + ppd[8] *=t; ppd[9] *=t; ppd[10] *=t; ppd[11] *=t; + ppd[12] *=t; ppd[13] *=t; ppd[14] *=t; ppd[15] *=t; + ppd[16] *=t; ppd[17] *=t; ppd[18] *=t; ppd[19] *=t; + ppd[20] *=t; ppd[21] *=t; ppd[22] *=t; ppd[23] *=t; + ppd[24] *=t; ppd[25] *=t; ppd[26] *=t; ppd[27] *=t; + ppd[28] *=t; ppd[29] *=t; ppd[30] *=t; ppd[31] *=t; + + ppd[32] *=t; ppd[33] *=t; ppd[34] *=t; ppd[35] *=t; + ppd[36] *=t; ppd[37] *=t; ppd[38] *=t; ppd[39] *=t; + ppd[40] *=t; ppd[41] *=t; ppd[42] *=t; ppd[43] *=t; + ppd[44] *=t; ppd[45] *=t; ppd[46] *=t; ppd[47] *=t; + ppd[48] *=t; ppd[49] *=t; ppd[50] *=t; ppd[51] *=t; + ppd[52] *=t; ppd[53] *=t; ppd[54] *=t; ppd[55] *=t; + ppd[56] *=t; ppd[57] *=t; ppd[58] *=t; ppd[59] *=t; + ppd[60] *=t; ppd[61] *=t; ppd[62] *=t; ppd[63] *=t; + + return to; +} + + +static const ppd_norm pd_norm_tab[7] = { + pd_norm1, + pd_norm2, + pd_norm4, + pd_norm8, + pd_norm16, + pd_norm32, + pd_norm64 +}; + +float pd_norm(float *pd, int nlogdim) +{ + return pd_norm_tab[nlogdim](pd); +} + +void pd_memset(float *dst, const float *src, int ndim, int nitems) +{ + int size = PD_SIZE(ndim); + while(nitems--) { + memcpy(dst,src,size); + dst +=ndim; + } +} + +void pd_fwdperm(float *dst, float *src, const int *perm, int ndim) +{ + // TODO: non-loop implementation + while (ndim--) + dst[ndim] = src[perm[ndim]]; +} + +void pd_bwdperm(float *dst, float *src, const int *perm, int ndim) +{ + // TODO: non-loop implementation + while (ndim--) + dst[perm[ndim]] = src[ndim]; +} + +float pd_max(float *src, int ndim) +{ + // TODO: faster implementation + + float cmax=0; // we assume that prob distributions are always positive + float cval; + + while (ndim--) { + cval = src[ndim]; + if (cval>=cmax) { + cmax = cval; + } + } + + return cmax; +} + +int pd_argmax(float *pmax, float *src, int ndim) +{ + // TODO: faster implementation + + float cmax=0; // we assume that prob distributions are always positive + float cval; + int idxmax=-1; // indicates that all pd elements are <0 + + while (ndim--) { + cval = src[ndim]; + if (cval>=cmax) { + cmax = cval; + idxmax = ndim; + } + } + + if (pmax) + *pmax = cmax; + + return idxmax; +} diff --git a/libm65/qracodes/pdmath.h b/libm65/qracodes/pdmath.h new file mode 100644 index 000000000..bbd1210c4 --- /dev/null +++ b/libm65/qracodes/pdmath.h @@ -0,0 +1,85 @@ +// pdmath.h +// Elementary math on probability distributions +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// 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 . + + +#ifndef _pdmath_h_ +#define _pdmath_h_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PD_NDIM(nlogdim) ((1<<(nlogdim)) +#define PD_SIZE(ndim) ((ndim)*sizeof(float)) +#define PD_ROWADDR(fp,ndim,idx) (fp+((ndim)*(idx))) + +const float *pd_uniform(int nlogdim); +// Returns a pointer to a (constant) uniform distribution of the given log2 size + +#define pd_init(dst,src,ndim) memcpy(dst,src,PD_SIZE(ndim)) +// Distribution copy + +void pd_memset(float *dst, const float *src, int ndim, int nitems); +// Copy the distribution pointed by src to the array of distributions dst +// src is a pointer to the input distribution (a vector of size ndim) +// dst is a pointer to a linear array of distributions (a vector of size ndim*nitems) + +void pd_imul(float *dst, const float *src, int nlogdim); +// In place multiplication +// Compute dst = dst*src for any element of the distrib give their log2 size +// src and dst arguments must be pointers to array of floats of the given size + +float pd_norm(float *pd, int nlogdim); +// In place normalizazion +// Normalizes the input vector so that the sum of its components are one +// pd must be a pointer to an array of floats of the given size. +// If the norm of the input vector is non-positive the vector components +// are replaced with a uniform distribution +// Returns the norm of the distribution prior to the normalization + +void pd_fwdperm(float *dst, float *src, const int *perm, int ndim); +// Forward permutation of a distribution +// Computes dst[k] = src[perm[k]] for every element in the distribution +// perm must be a pointer to an array of integers of length ndim + +void pd_bwdperm(float *dst, float *src, const int *perm, int ndim); +// Backward permutation of a distribution +// Computes dst[perm[k]] = src[k] for every element in the distribution +// perm must be a pointer to an array of integers of length ndim + +float pd_max(float *src, int ndim); +// Return the maximum of the elements of the given distribution +// Assumes that the input vector is a probability distribution and that each element in the +// distribution is non negative + +int pd_argmax(float *pmax, float *src, int ndim); +// Return the index of the maximum element of the given distribution +// The maximum is stored in the variable pointed by pmax if pmax is not null +// Same note of pd_max applies. +// Return -1 if all the elements in the distribution are negative + +#ifdef __cplusplus +} +#endif + +#endif // _pdmath_h_ diff --git a/libm65/qracodes/qra12_63_64_irr_b.c b/libm65/qracodes/qra12_63_64_irr_b.c new file mode 100644 index 000000000..d69443b89 --- /dev/null +++ b/libm65/qracodes/qra12_63_64_irr_b.c @@ -0,0 +1,534 @@ +// qra12_63_64_irr_b.c +// Encoding/Decoding tables for Q-ary RA code (12,63) over GF(64) +// Code Name: qra12_63_64_irr_b +// (12,63) RA Code over GF(64) - RF=333344455567 + +// (c) 2016 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy + +// 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 . + +#include "qra12_63_64_irr_b.h" + +#define qra_K 12 // number of information symbols +#define qra_N 63 // codeword length in symbols +#define qra_m 6 // bits/symbol +#define qra_M 64 // Symbol alphabet cardinality +#define qra_a 1 // grouping factor +#define qra_NC 51 // number of check symbols (N-K) + +// Defines used by the message passing decoder -------- + +#define qra_V 63 // number of variables in the code graph (N) +#define qra_C 115 // number of factors in the code graph (N +(N-K)+1) +#define qra_NMSG 217 // number of msgs in the code graph +#define qra_MAXVDEG 8 // maximum variable degree +#define qra_MAXCDEG 3 // maximum factor degree +#define qra_R 0.19048f // code rate (K/N) +#define CODE_NAME "qra_12_63_64_irr_b" + + +// table of the systematic symbols indexes in the accumulator chain +static const int qra_acc_input_idx[qra_NC+1] = { + 3, 11, 0, 1, 7, 8, 6, 5, 10, 4, + 11, 9, 0, 2, 6, 7, 8, 4, 11, 5, + 10, 2, 1, 9, 3, 8, 4, 11, 5, 7, + 10, 9, 6, 3, 11, 5, 8, 10, 0, 7, + 9, 11, 4, 2, 10, 6, 8, 1, 9, 7, + 11, 10 +}; + +// table of the systematic symbols weight logarithms over GF(M) +static const int qra_acc_input_wlog[qra_NC+1] = { + 39, 0, 34, 16, 25, 0, 34, 48, 19, 13, + 29, 56, 0, 5, 39, 42, 31, 0, 10, 0, + 57, 62, 33, 43, 0, 14, 22, 48, 28, 20, + 5, 45, 16, 43, 17, 4, 32, 0, 31, 0, + 0, 28, 57, 0, 18, 0, 60, 0, 10, 31, + 57, 27 +}; + +// table of the logarithms of the elements of GF(M) (log(0) never used) +static const int qra_log[qra_M] = { + -1, 0, 1, 6, 2, 12, 7, 26, 3, 32, + 13, 35, 8, 48, 27, 18, 4, 24, 33, 16, + 14, 52, 36, 54, 9, 45, 49, 38, 28, 41, + 19, 56, 5, 62, 25, 11, 34, 31, 17, 47, + 15, 23, 53, 51, 37, 44, 55, 40, 10, 61, + 46, 30, 50, 22, 39, 43, 29, 60, 42, 21, + 20, 59, 57, 58 +}; + +// table of GF(M) elements given their logarithm +static const int qra_exp[qra_M-1] = { + 1, 2, 4, 8, 16, 32, 3, 6, 12, 24, + 48, 35, 5, 10, 20, 40, 19, 38, 15, 30, + 60, 59, 53, 41, 17, 34, 7, 14, 28, 56, + 51, 37, 9, 18, 36, 11, 22, 44, 27, 54, + 47, 29, 58, 55, 45, 25, 50, 39, 13, 26, + 52, 43, 21, 42, 23, 46, 31, 62, 63, 61, + 57, 49, 33 +}; + +// table of the messages weight logarithms over GF(M) +static const int qra_msgw[qra_NMSG] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 39, 0, 34, 16, 25, 0, 34, + 48, 19, 13, 29, 56, 0, 5, 39, 42, 31, + 0, 10, 0, 57, 62, 33, 43, 0, 14, 22, + 48, 28, 20, 5, 45, 16, 43, 17, 4, 32, + 0, 31, 0, 0, 28, 57, 0, 18, 0, 60, + 0, 10, 31, 57, 27, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 +}; + +// table of the degrees of the variable nodes +static const int qra_vdeg[qra_V] = { + 4, 4, 4, 4, 5, 5, 5, 6, 6, 6, + 7, 8, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3 +}; + +// table of the degrees of the factor nodes +static const int qra_cdeg[qra_C] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 2 +}; + +// table (uncompressed) of the v->c message indexes (-1=unused entry) +static const int qra_v2cmidx[qra_V*qra_MAXVDEG] = { + 0, 65, 75, 101, -1, -1, -1, -1, + 1, 66, 85, 110, -1, -1, -1, -1, + 2, 76, 84, 106, -1, -1, -1, -1, + 3, 63, 87, 96, -1, -1, -1, -1, + 4, 72, 80, 89, 105, -1, -1, -1, + 5, 70, 82, 91, 98, -1, -1, -1, + 6, 69, 77, 95, 108, -1, -1, -1, + 7, 67, 78, 92, 102, 112, -1, -1, + 8, 68, 79, 88, 99, 109, -1, -1, + 9, 74, 86, 94, 103, 111, -1, -1, + 10, 71, 83, 93, 100, 107, 114, -1, + 11, 64, 73, 81, 90, 97, 104, 113, + 12, 115, 116, -1, -1, -1, -1, -1, + 13, 117, 118, -1, -1, -1, -1, -1, + 14, 119, 120, -1, -1, -1, -1, -1, + 15, 121, 122, -1, -1, -1, -1, -1, + 16, 123, 124, -1, -1, -1, -1, -1, + 17, 125, 126, -1, -1, -1, -1, -1, + 18, 127, 128, -1, -1, -1, -1, -1, + 19, 129, 130, -1, -1, -1, -1, -1, + 20, 131, 132, -1, -1, -1, -1, -1, + 21, 133, 134, -1, -1, -1, -1, -1, + 22, 135, 136, -1, -1, -1, -1, -1, + 23, 137, 138, -1, -1, -1, -1, -1, + 24, 139, 140, -1, -1, -1, -1, -1, + 25, 141, 142, -1, -1, -1, -1, -1, + 26, 143, 144, -1, -1, -1, -1, -1, + 27, 145, 146, -1, -1, -1, -1, -1, + 28, 147, 148, -1, -1, -1, -1, -1, + 29, 149, 150, -1, -1, -1, -1, -1, + 30, 151, 152, -1, -1, -1, -1, -1, + 31, 153, 154, -1, -1, -1, -1, -1, + 32, 155, 156, -1, -1, -1, -1, -1, + 33, 157, 158, -1, -1, -1, -1, -1, + 34, 159, 160, -1, -1, -1, -1, -1, + 35, 161, 162, -1, -1, -1, -1, -1, + 36, 163, 164, -1, -1, -1, -1, -1, + 37, 165, 166, -1, -1, -1, -1, -1, + 38, 167, 168, -1, -1, -1, -1, -1, + 39, 169, 170, -1, -1, -1, -1, -1, + 40, 171, 172, -1, -1, -1, -1, -1, + 41, 173, 174, -1, -1, -1, -1, -1, + 42, 175, 176, -1, -1, -1, -1, -1, + 43, 177, 178, -1, -1, -1, -1, -1, + 44, 179, 180, -1, -1, -1, -1, -1, + 45, 181, 182, -1, -1, -1, -1, -1, + 46, 183, 184, -1, -1, -1, -1, -1, + 47, 185, 186, -1, -1, -1, -1, -1, + 48, 187, 188, -1, -1, -1, -1, -1, + 49, 189, 190, -1, -1, -1, -1, -1, + 50, 191, 192, -1, -1, -1, -1, -1, + 51, 193, 194, -1, -1, -1, -1, -1, + 52, 195, 196, -1, -1, -1, -1, -1, + 53, 197, 198, -1, -1, -1, -1, -1, + 54, 199, 200, -1, -1, -1, -1, -1, + 55, 201, 202, -1, -1, -1, -1, -1, + 56, 203, 204, -1, -1, -1, -1, -1, + 57, 205, 206, -1, -1, -1, -1, -1, + 58, 207, 208, -1, -1, -1, -1, -1, + 59, 209, 210, -1, -1, -1, -1, -1, + 60, 211, 212, -1, -1, -1, -1, -1, + 61, 213, 214, -1, -1, -1, -1, -1, + 62, 215, 216, -1, -1, -1, -1, -1 +}; + +// table (uncompressed) of the c->v message indexes (-1=unused entry) +static const int qra_c2vmidx[qra_C*qra_MAXCDEG] = { + 0, -1, -1, 1, -1, -1, 2, -1, -1, 3, -1, -1, + 4, -1, -1, 5, -1, -1, 6, -1, -1, 7, -1, -1, + 8, -1, -1, 9, -1, -1, 10, -1, -1, 11, -1, -1, + 12, -1, -1, 13, -1, -1, 14, -1, -1, 15, -1, -1, + 16, -1, -1, 17, -1, -1, 18, -1, -1, 19, -1, -1, + 20, -1, -1, 21, -1, -1, 22, -1, -1, 23, -1, -1, + 24, -1, -1, 25, -1, -1, 26, -1, -1, 27, -1, -1, + 28, -1, -1, 29, -1, -1, 30, -1, -1, 31, -1, -1, + 32, -1, -1, 33, -1, -1, 34, -1, -1, 35, -1, -1, + 36, -1, -1, 37, -1, -1, 38, -1, -1, 39, -1, -1, + 40, -1, -1, 41, -1, -1, 42, -1, -1, 43, -1, -1, + 44, -1, -1, 45, -1, -1, 46, -1, -1, 47, -1, -1, + 48, -1, -1, 49, -1, -1, 50, -1, -1, 51, -1, -1, + 52, -1, -1, 53, -1, -1, 54, -1, -1, 55, -1, -1, + 56, -1, -1, 57, -1, -1, 58, -1, -1, 59, -1, -1, + 60, -1, -1, 61, -1, -1, 62, -1, -1, 63, 115, -1, + 64, 116, 117, 65, 118, 119, 66, 120, 121, 67, 122, 123, + 68, 124, 125, 69, 126, 127, 70, 128, 129, 71, 130, 131, + 72, 132, 133, 73, 134, 135, 74, 136, 137, 75, 138, 139, + 76, 140, 141, 77, 142, 143, 78, 144, 145, 79, 146, 147, + 80, 148, 149, 81, 150, 151, 82, 152, 153, 83, 154, 155, + 84, 156, 157, 85, 158, 159, 86, 160, 161, 87, 162, 163, + 88, 164, 165, 89, 166, 167, 90, 168, 169, 91, 170, 171, + 92, 172, 173, 93, 174, 175, 94, 176, 177, 95, 178, 179, + 96, 180, 181, 97, 182, 183, 98, 184, 185, 99, 186, 187, +100, 188, 189, 101, 190, 191, 102, 192, 193, 103, 194, 195, +104, 196, 197, 105, 198, 199, 106, 200, 201, 107, 202, 203, +108, 204, 205, 109, 206, 207, 110, 208, 209, 111, 210, 211, +112, 212, 213, 113, 214, 215, 114, 216, -1 +}; + +// permutation matrix to compute Prob(x*alfa^logw) +static const int qra_pmat[qra_M*qra_M] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 33, 1, 32, 2, 35, 3, 34, 4, 37, 5, 36, 6, 39, 7, 38, + 8, 41, 9, 40, 10, 43, 11, 42, 12, 45, 13, 44, 14, 47, 15, 46, + 16, 49, 17, 48, 18, 51, 19, 50, 20, 53, 21, 52, 22, 55, 23, 54, + 24, 57, 25, 56, 26, 59, 27, 58, 28, 61, 29, 60, 30, 63, 31, 62, + 0, 49, 33, 16, 1, 48, 32, 17, 2, 51, 35, 18, 3, 50, 34, 19, + 4, 53, 37, 20, 5, 52, 36, 21, 6, 55, 39, 22, 7, 54, 38, 23, + 8, 57, 41, 24, 9, 56, 40, 25, 10, 59, 43, 26, 11, 58, 42, 27, + 12, 61, 45, 28, 13, 60, 44, 29, 14, 63, 47, 30, 15, 62, 46, 31, + 0, 57, 49, 8, 33, 24, 16, 41, 1, 56, 48, 9, 32, 25, 17, 40, + 2, 59, 51, 10, 35, 26, 18, 43, 3, 58, 50, 11, 34, 27, 19, 42, + 4, 61, 53, 12, 37, 28, 20, 45, 5, 60, 52, 13, 36, 29, 21, 44, + 6, 63, 55, 14, 39, 30, 22, 47, 7, 62, 54, 15, 38, 31, 23, 46, + 0, 61, 57, 4, 49, 12, 8, 53, 33, 28, 24, 37, 16, 45, 41, 20, + 1, 60, 56, 5, 48, 13, 9, 52, 32, 29, 25, 36, 17, 44, 40, 21, + 2, 63, 59, 6, 51, 14, 10, 55, 35, 30, 26, 39, 18, 47, 43, 22, + 3, 62, 58, 7, 50, 15, 11, 54, 34, 31, 27, 38, 19, 46, 42, 23, + 0, 63, 61, 2, 57, 6, 4, 59, 49, 14, 12, 51, 8, 55, 53, 10, + 33, 30, 28, 35, 24, 39, 37, 26, 16, 47, 45, 18, 41, 22, 20, 43, + 1, 62, 60, 3, 56, 7, 5, 58, 48, 15, 13, 50, 9, 54, 52, 11, + 32, 31, 29, 34, 25, 38, 36, 27, 17, 46, 44, 19, 40, 23, 21, 42, + 0, 62, 63, 1, 61, 3, 2, 60, 57, 7, 6, 56, 4, 58, 59, 5, + 49, 15, 14, 48, 12, 50, 51, 13, 8, 54, 55, 9, 53, 11, 10, 52, + 33, 31, 30, 32, 28, 34, 35, 29, 24, 38, 39, 25, 37, 27, 26, 36, + 16, 46, 47, 17, 45, 19, 18, 44, 41, 23, 22, 40, 20, 42, 43, 21, + 0, 31, 62, 33, 63, 32, 1, 30, 61, 34, 3, 28, 2, 29, 60, 35, + 57, 38, 7, 24, 6, 25, 56, 39, 4, 27, 58, 37, 59, 36, 5, 26, + 49, 46, 15, 16, 14, 17, 48, 47, 12, 19, 50, 45, 51, 44, 13, 18, + 8, 23, 54, 41, 55, 40, 9, 22, 53, 42, 11, 20, 10, 21, 52, 43, + 0, 46, 31, 49, 62, 16, 33, 15, 63, 17, 32, 14, 1, 47, 30, 48, + 61, 19, 34, 12, 3, 45, 28, 50, 2, 44, 29, 51, 60, 18, 35, 13, + 57, 23, 38, 8, 7, 41, 24, 54, 6, 40, 25, 55, 56, 22, 39, 9, + 4, 42, 27, 53, 58, 20, 37, 11, 59, 21, 36, 10, 5, 43, 26, 52, + 0, 23, 46, 57, 31, 8, 49, 38, 62, 41, 16, 7, 33, 54, 15, 24, + 63, 40, 17, 6, 32, 55, 14, 25, 1, 22, 47, 56, 30, 9, 48, 39, + 61, 42, 19, 4, 34, 53, 12, 27, 3, 20, 45, 58, 28, 11, 50, 37, + 2, 21, 44, 59, 29, 10, 51, 36, 60, 43, 18, 5, 35, 52, 13, 26, + 0, 42, 23, 61, 46, 4, 57, 19, 31, 53, 8, 34, 49, 27, 38, 12, + 62, 20, 41, 3, 16, 58, 7, 45, 33, 11, 54, 28, 15, 37, 24, 50, + 63, 21, 40, 2, 17, 59, 6, 44, 32, 10, 55, 29, 14, 36, 25, 51, + 1, 43, 22, 60, 47, 5, 56, 18, 30, 52, 9, 35, 48, 26, 39, 13, + 0, 21, 42, 63, 23, 2, 61, 40, 46, 59, 4, 17, 57, 44, 19, 6, + 31, 10, 53, 32, 8, 29, 34, 55, 49, 36, 27, 14, 38, 51, 12, 25, + 62, 43, 20, 1, 41, 60, 3, 22, 16, 5, 58, 47, 7, 18, 45, 56, + 33, 52, 11, 30, 54, 35, 28, 9, 15, 26, 37, 48, 24, 13, 50, 39, + 0, 43, 21, 62, 42, 1, 63, 20, 23, 60, 2, 41, 61, 22, 40, 3, + 46, 5, 59, 16, 4, 47, 17, 58, 57, 18, 44, 7, 19, 56, 6, 45, + 31, 52, 10, 33, 53, 30, 32, 11, 8, 35, 29, 54, 34, 9, 55, 28, + 49, 26, 36, 15, 27, 48, 14, 37, 38, 13, 51, 24, 12, 39, 25, 50, + 0, 52, 43, 31, 21, 33, 62, 10, 42, 30, 1, 53, 63, 11, 20, 32, + 23, 35, 60, 8, 2, 54, 41, 29, 61, 9, 22, 34, 40, 28, 3, 55, + 46, 26, 5, 49, 59, 15, 16, 36, 4, 48, 47, 27, 17, 37, 58, 14, + 57, 13, 18, 38, 44, 24, 7, 51, 19, 39, 56, 12, 6, 50, 45, 25, + 0, 26, 52, 46, 43, 49, 31, 5, 21, 15, 33, 59, 62, 36, 10, 16, + 42, 48, 30, 4, 1, 27, 53, 47, 63, 37, 11, 17, 20, 14, 32, 58, + 23, 13, 35, 57, 60, 38, 8, 18, 2, 24, 54, 44, 41, 51, 29, 7, + 61, 39, 9, 19, 22, 12, 34, 56, 40, 50, 28, 6, 3, 25, 55, 45, + 0, 13, 26, 23, 52, 57, 46, 35, 43, 38, 49, 60, 31, 18, 5, 8, + 21, 24, 15, 2, 33, 44, 59, 54, 62, 51, 36, 41, 10, 7, 16, 29, + 42, 39, 48, 61, 30, 19, 4, 9, 1, 12, 27, 22, 53, 56, 47, 34, + 63, 50, 37, 40, 11, 6, 17, 28, 20, 25, 14, 3, 32, 45, 58, 55, + 0, 39, 13, 42, 26, 61, 23, 48, 52, 19, 57, 30, 46, 9, 35, 4, + 43, 12, 38, 1, 49, 22, 60, 27, 31, 56, 18, 53, 5, 34, 8, 47, + 21, 50, 24, 63, 15, 40, 2, 37, 33, 6, 44, 11, 59, 28, 54, 17, + 62, 25, 51, 20, 36, 3, 41, 14, 10, 45, 7, 32, 16, 55, 29, 58, + 0, 50, 39, 21, 13, 63, 42, 24, 26, 40, 61, 15, 23, 37, 48, 2, + 52, 6, 19, 33, 57, 11, 30, 44, 46, 28, 9, 59, 35, 17, 4, 54, + 43, 25, 12, 62, 38, 20, 1, 51, 49, 3, 22, 36, 60, 14, 27, 41, + 31, 45, 56, 10, 18, 32, 53, 7, 5, 55, 34, 16, 8, 58, 47, 29, + 0, 25, 50, 43, 39, 62, 21, 12, 13, 20, 63, 38, 42, 51, 24, 1, + 26, 3, 40, 49, 61, 36, 15, 22, 23, 14, 37, 60, 48, 41, 2, 27, + 52, 45, 6, 31, 19, 10, 33, 56, 57, 32, 11, 18, 30, 7, 44, 53, + 46, 55, 28, 5, 9, 16, 59, 34, 35, 58, 17, 8, 4, 29, 54, 47, + 0, 45, 25, 52, 50, 31, 43, 6, 39, 10, 62, 19, 21, 56, 12, 33, + 13, 32, 20, 57, 63, 18, 38, 11, 42, 7, 51, 30, 24, 53, 1, 44, + 26, 55, 3, 46, 40, 5, 49, 28, 61, 16, 36, 9, 15, 34, 22, 59, + 23, 58, 14, 35, 37, 8, 60, 17, 48, 29, 41, 4, 2, 47, 27, 54, + 0, 55, 45, 26, 25, 46, 52, 3, 50, 5, 31, 40, 43, 28, 6, 49, + 39, 16, 10, 61, 62, 9, 19, 36, 21, 34, 56, 15, 12, 59, 33, 22, + 13, 58, 32, 23, 20, 35, 57, 14, 63, 8, 18, 37, 38, 17, 11, 60, + 42, 29, 7, 48, 51, 4, 30, 41, 24, 47, 53, 2, 1, 54, 44, 27, + 0, 58, 55, 13, 45, 23, 26, 32, 25, 35, 46, 20, 52, 14, 3, 57, + 50, 8, 5, 63, 31, 37, 40, 18, 43, 17, 28, 38, 6, 60, 49, 11, + 39, 29, 16, 42, 10, 48, 61, 7, 62, 4, 9, 51, 19, 41, 36, 30, + 21, 47, 34, 24, 56, 2, 15, 53, 12, 54, 59, 1, 33, 27, 22, 44, + 0, 29, 58, 39, 55, 42, 13, 16, 45, 48, 23, 10, 26, 7, 32, 61, + 25, 4, 35, 62, 46, 51, 20, 9, 52, 41, 14, 19, 3, 30, 57, 36, + 50, 47, 8, 21, 5, 24, 63, 34, 31, 2, 37, 56, 40, 53, 18, 15, + 43, 54, 17, 12, 28, 1, 38, 59, 6, 27, 60, 33, 49, 44, 11, 22, + 0, 47, 29, 50, 58, 21, 39, 8, 55, 24, 42, 5, 13, 34, 16, 63, + 45, 2, 48, 31, 23, 56, 10, 37, 26, 53, 7, 40, 32, 15, 61, 18, + 25, 54, 4, 43, 35, 12, 62, 17, 46, 1, 51, 28, 20, 59, 9, 38, + 52, 27, 41, 6, 14, 33, 19, 60, 3, 44, 30, 49, 57, 22, 36, 11, + 0, 54, 47, 25, 29, 43, 50, 4, 58, 12, 21, 35, 39, 17, 8, 62, + 55, 1, 24, 46, 42, 28, 5, 51, 13, 59, 34, 20, 16, 38, 63, 9, + 45, 27, 2, 52, 48, 6, 31, 41, 23, 33, 56, 14, 10, 60, 37, 19, + 26, 44, 53, 3, 7, 49, 40, 30, 32, 22, 15, 57, 61, 11, 18, 36, + 0, 27, 54, 45, 47, 52, 25, 2, 29, 6, 43, 48, 50, 41, 4, 31, + 58, 33, 12, 23, 21, 14, 35, 56, 39, 60, 17, 10, 8, 19, 62, 37, + 55, 44, 1, 26, 24, 3, 46, 53, 42, 49, 28, 7, 5, 30, 51, 40, + 13, 22, 59, 32, 34, 57, 20, 15, 16, 11, 38, 61, 63, 36, 9, 18, + 0, 44, 27, 55, 54, 26, 45, 1, 47, 3, 52, 24, 25, 53, 2, 46, + 29, 49, 6, 42, 43, 7, 48, 28, 50, 30, 41, 5, 4, 40, 31, 51, + 58, 22, 33, 13, 12, 32, 23, 59, 21, 57, 14, 34, 35, 15, 56, 20, + 39, 11, 60, 16, 17, 61, 10, 38, 8, 36, 19, 63, 62, 18, 37, 9, + 0, 22, 44, 58, 27, 13, 55, 33, 54, 32, 26, 12, 45, 59, 1, 23, + 47, 57, 3, 21, 52, 34, 24, 14, 25, 15, 53, 35, 2, 20, 46, 56, + 29, 11, 49, 39, 6, 16, 42, 60, 43, 61, 7, 17, 48, 38, 28, 10, + 50, 36, 30, 8, 41, 63, 5, 19, 4, 18, 40, 62, 31, 9, 51, 37, + 0, 11, 22, 29, 44, 39, 58, 49, 27, 16, 13, 6, 55, 60, 33, 42, + 54, 61, 32, 43, 26, 17, 12, 7, 45, 38, 59, 48, 1, 10, 23, 28, + 47, 36, 57, 50, 3, 8, 21, 30, 52, 63, 34, 41, 24, 19, 14, 5, + 25, 18, 15, 4, 53, 62, 35, 40, 2, 9, 20, 31, 46, 37, 56, 51, + 0, 36, 11, 47, 22, 50, 29, 57, 44, 8, 39, 3, 58, 30, 49, 21, + 27, 63, 16, 52, 13, 41, 6, 34, 55, 19, 60, 24, 33, 5, 42, 14, + 54, 18, 61, 25, 32, 4, 43, 15, 26, 62, 17, 53, 12, 40, 7, 35, + 45, 9, 38, 2, 59, 31, 48, 20, 1, 37, 10, 46, 23, 51, 28, 56, + 0, 18, 36, 54, 11, 25, 47, 61, 22, 4, 50, 32, 29, 15, 57, 43, + 44, 62, 8, 26, 39, 53, 3, 17, 58, 40, 30, 12, 49, 35, 21, 7, + 27, 9, 63, 45, 16, 2, 52, 38, 13, 31, 41, 59, 6, 20, 34, 48, + 55, 37, 19, 1, 60, 46, 24, 10, 33, 51, 5, 23, 42, 56, 14, 28, + 0, 9, 18, 27, 36, 45, 54, 63, 11, 2, 25, 16, 47, 38, 61, 52, + 22, 31, 4, 13, 50, 59, 32, 41, 29, 20, 15, 6, 57, 48, 43, 34, + 44, 37, 62, 55, 8, 1, 26, 19, 39, 46, 53, 60, 3, 10, 17, 24, + 58, 51, 40, 33, 30, 23, 12, 5, 49, 56, 35, 42, 21, 28, 7, 14, + 0, 37, 9, 44, 18, 55, 27, 62, 36, 1, 45, 8, 54, 19, 63, 26, + 11, 46, 2, 39, 25, 60, 16, 53, 47, 10, 38, 3, 61, 24, 52, 17, + 22, 51, 31, 58, 4, 33, 13, 40, 50, 23, 59, 30, 32, 5, 41, 12, + 29, 56, 20, 49, 15, 42, 6, 35, 57, 28, 48, 21, 43, 14, 34, 7, + 0, 51, 37, 22, 9, 58, 44, 31, 18, 33, 55, 4, 27, 40, 62, 13, + 36, 23, 1, 50, 45, 30, 8, 59, 54, 5, 19, 32, 63, 12, 26, 41, + 11, 56, 46, 29, 2, 49, 39, 20, 25, 42, 60, 15, 16, 35, 53, 6, + 47, 28, 10, 57, 38, 21, 3, 48, 61, 14, 24, 43, 52, 7, 17, 34, + 0, 56, 51, 11, 37, 29, 22, 46, 9, 49, 58, 2, 44, 20, 31, 39, + 18, 42, 33, 25, 55, 15, 4, 60, 27, 35, 40, 16, 62, 6, 13, 53, + 36, 28, 23, 47, 1, 57, 50, 10, 45, 21, 30, 38, 8, 48, 59, 3, + 54, 14, 5, 61, 19, 43, 32, 24, 63, 7, 12, 52, 26, 34, 41, 17, + 0, 28, 56, 36, 51, 47, 11, 23, 37, 57, 29, 1, 22, 10, 46, 50, + 9, 21, 49, 45, 58, 38, 2, 30, 44, 48, 20, 8, 31, 3, 39, 59, + 18, 14, 42, 54, 33, 61, 25, 5, 55, 43, 15, 19, 4, 24, 60, 32, + 27, 7, 35, 63, 40, 52, 16, 12, 62, 34, 6, 26, 13, 17, 53, 41, + 0, 14, 28, 18, 56, 54, 36, 42, 51, 61, 47, 33, 11, 5, 23, 25, + 37, 43, 57, 55, 29, 19, 1, 15, 22, 24, 10, 4, 46, 32, 50, 60, + 9, 7, 21, 27, 49, 63, 45, 35, 58, 52, 38, 40, 2, 12, 30, 16, + 44, 34, 48, 62, 20, 26, 8, 6, 31, 17, 3, 13, 39, 41, 59, 53, + 0, 7, 14, 9, 28, 27, 18, 21, 56, 63, 54, 49, 36, 35, 42, 45, + 51, 52, 61, 58, 47, 40, 33, 38, 11, 12, 5, 2, 23, 16, 25, 30, + 37, 34, 43, 44, 57, 62, 55, 48, 29, 26, 19, 20, 1, 6, 15, 8, + 22, 17, 24, 31, 10, 13, 4, 3, 46, 41, 32, 39, 50, 53, 60, 59, + 0, 34, 7, 37, 14, 44, 9, 43, 28, 62, 27, 57, 18, 48, 21, 55, + 56, 26, 63, 29, 54, 20, 49, 19, 36, 6, 35, 1, 42, 8, 45, 15, + 51, 17, 52, 22, 61, 31, 58, 24, 47, 13, 40, 10, 33, 3, 38, 4, + 11, 41, 12, 46, 5, 39, 2, 32, 23, 53, 16, 50, 25, 59, 30, 60, + 0, 17, 34, 51, 7, 22, 37, 52, 14, 31, 44, 61, 9, 24, 43, 58, + 28, 13, 62, 47, 27, 10, 57, 40, 18, 3, 48, 33, 21, 4, 55, 38, + 56, 41, 26, 11, 63, 46, 29, 12, 54, 39, 20, 5, 49, 32, 19, 2, + 36, 53, 6, 23, 35, 50, 1, 16, 42, 59, 8, 25, 45, 60, 15, 30, + 0, 41, 17, 56, 34, 11, 51, 26, 7, 46, 22, 63, 37, 12, 52, 29, + 14, 39, 31, 54, 44, 5, 61, 20, 9, 32, 24, 49, 43, 2, 58, 19, + 28, 53, 13, 36, 62, 23, 47, 6, 27, 50, 10, 35, 57, 16, 40, 1, + 18, 59, 3, 42, 48, 25, 33, 8, 21, 60, 4, 45, 55, 30, 38, 15, + 0, 53, 41, 28, 17, 36, 56, 13, 34, 23, 11, 62, 51, 6, 26, 47, + 7, 50, 46, 27, 22, 35, 63, 10, 37, 16, 12, 57, 52, 1, 29, 40, + 14, 59, 39, 18, 31, 42, 54, 3, 44, 25, 5, 48, 61, 8, 20, 33, + 9, 60, 32, 21, 24, 45, 49, 4, 43, 30, 2, 55, 58, 15, 19, 38, + 0, 59, 53, 14, 41, 18, 28, 39, 17, 42, 36, 31, 56, 3, 13, 54, + 34, 25, 23, 44, 11, 48, 62, 5, 51, 8, 6, 61, 26, 33, 47, 20, + 7, 60, 50, 9, 46, 21, 27, 32, 22, 45, 35, 24, 63, 4, 10, 49, + 37, 30, 16, 43, 12, 55, 57, 2, 52, 15, 1, 58, 29, 38, 40, 19, + 0, 60, 59, 7, 53, 9, 14, 50, 41, 21, 18, 46, 28, 32, 39, 27, + 17, 45, 42, 22, 36, 24, 31, 35, 56, 4, 3, 63, 13, 49, 54, 10, + 34, 30, 25, 37, 23, 43, 44, 16, 11, 55, 48, 12, 62, 2, 5, 57, + 51, 15, 8, 52, 6, 58, 61, 1, 26, 38, 33, 29, 47, 19, 20, 40, + 0, 30, 60, 34, 59, 37, 7, 25, 53, 43, 9, 23, 14, 16, 50, 44, + 41, 55, 21, 11, 18, 12, 46, 48, 28, 2, 32, 62, 39, 57, 27, 5, + 17, 15, 45, 51, 42, 52, 22, 8, 36, 58, 24, 6, 31, 1, 35, 61, + 56, 38, 4, 26, 3, 29, 63, 33, 13, 19, 49, 47, 54, 40, 10, 20, + 0, 15, 30, 17, 60, 51, 34, 45, 59, 52, 37, 42, 7, 8, 25, 22, + 53, 58, 43, 36, 9, 6, 23, 24, 14, 1, 16, 31, 50, 61, 44, 35, + 41, 38, 55, 56, 21, 26, 11, 4, 18, 29, 12, 3, 46, 33, 48, 63, + 28, 19, 2, 13, 32, 47, 62, 49, 39, 40, 57, 54, 27, 20, 5, 10, + 0, 38, 15, 41, 30, 56, 17, 55, 60, 26, 51, 21, 34, 4, 45, 11, + 59, 29, 52, 18, 37, 3, 42, 12, 7, 33, 8, 46, 25, 63, 22, 48, + 53, 19, 58, 28, 43, 13, 36, 2, 9, 47, 6, 32, 23, 49, 24, 62, + 14, 40, 1, 39, 16, 54, 31, 57, 50, 20, 61, 27, 44, 10, 35, 5, + 0, 19, 38, 53, 15, 28, 41, 58, 30, 13, 56, 43, 17, 2, 55, 36, + 60, 47, 26, 9, 51, 32, 21, 6, 34, 49, 4, 23, 45, 62, 11, 24, + 59, 40, 29, 14, 52, 39, 18, 1, 37, 54, 3, 16, 42, 57, 12, 31, + 7, 20, 33, 50, 8, 27, 46, 61, 25, 10, 63, 44, 22, 5, 48, 35, + 0, 40, 19, 59, 38, 14, 53, 29, 15, 39, 28, 52, 41, 1, 58, 18, + 30, 54, 13, 37, 56, 16, 43, 3, 17, 57, 2, 42, 55, 31, 36, 12, + 60, 20, 47, 7, 26, 50, 9, 33, 51, 27, 32, 8, 21, 61, 6, 46, + 34, 10, 49, 25, 4, 44, 23, 63, 45, 5, 62, 22, 11, 35, 24, 48, + 0, 20, 40, 60, 19, 7, 59, 47, 38, 50, 14, 26, 53, 33, 29, 9, + 15, 27, 39, 51, 28, 8, 52, 32, 41, 61, 1, 21, 58, 46, 18, 6, + 30, 10, 54, 34, 13, 25, 37, 49, 56, 44, 16, 4, 43, 63, 3, 23, + 17, 5, 57, 45, 2, 22, 42, 62, 55, 35, 31, 11, 36, 48, 12, 24, + 0, 10, 20, 30, 40, 34, 60, 54, 19, 25, 7, 13, 59, 49, 47, 37, + 38, 44, 50, 56, 14, 4, 26, 16, 53, 63, 33, 43, 29, 23, 9, 3, + 15, 5, 27, 17, 39, 45, 51, 57, 28, 22, 8, 2, 52, 62, 32, 42, + 41, 35, 61, 55, 1, 11, 21, 31, 58, 48, 46, 36, 18, 24, 6, 12, + 0, 5, 10, 15, 20, 17, 30, 27, 40, 45, 34, 39, 60, 57, 54, 51, + 19, 22, 25, 28, 7, 2, 13, 8, 59, 62, 49, 52, 47, 42, 37, 32, + 38, 35, 44, 41, 50, 55, 56, 61, 14, 11, 4, 1, 26, 31, 16, 21, + 53, 48, 63, 58, 33, 36, 43, 46, 29, 24, 23, 18, 9, 12, 3, 6, + 0, 35, 5, 38, 10, 41, 15, 44, 20, 55, 17, 50, 30, 61, 27, 56, + 40, 11, 45, 14, 34, 1, 39, 4, 60, 31, 57, 26, 54, 21, 51, 16, + 19, 48, 22, 53, 25, 58, 28, 63, 7, 36, 2, 33, 13, 46, 8, 43, + 59, 24, 62, 29, 49, 18, 52, 23, 47, 12, 42, 9, 37, 6, 32, 3, + 0, 48, 35, 19, 5, 53, 38, 22, 10, 58, 41, 25, 15, 63, 44, 28, + 20, 36, 55, 7, 17, 33, 50, 2, 30, 46, 61, 13, 27, 43, 56, 8, + 40, 24, 11, 59, 45, 29, 14, 62, 34, 18, 1, 49, 39, 23, 4, 52, + 60, 12, 31, 47, 57, 9, 26, 42, 54, 6, 21, 37, 51, 3, 16, 32, + 0, 24, 48, 40, 35, 59, 19, 11, 5, 29, 53, 45, 38, 62, 22, 14, + 10, 18, 58, 34, 41, 49, 25, 1, 15, 23, 63, 39, 44, 52, 28, 4, + 20, 12, 36, 60, 55, 47, 7, 31, 17, 9, 33, 57, 50, 42, 2, 26, + 30, 6, 46, 54, 61, 37, 13, 21, 27, 3, 43, 51, 56, 32, 8, 16, + 0, 12, 24, 20, 48, 60, 40, 36, 35, 47, 59, 55, 19, 31, 11, 7, + 5, 9, 29, 17, 53, 57, 45, 33, 38, 42, 62, 50, 22, 26, 14, 2, + 10, 6, 18, 30, 58, 54, 34, 46, 41, 37, 49, 61, 25, 21, 1, 13, + 15, 3, 23, 27, 63, 51, 39, 43, 44, 32, 52, 56, 28, 16, 4, 8, + 0, 6, 12, 10, 24, 30, 20, 18, 48, 54, 60, 58, 40, 46, 36, 34, + 35, 37, 47, 41, 59, 61, 55, 49, 19, 21, 31, 25, 11, 13, 7, 1, + 5, 3, 9, 15, 29, 27, 17, 23, 53, 51, 57, 63, 45, 43, 33, 39, + 38, 32, 42, 44, 62, 56, 50, 52, 22, 16, 26, 28, 14, 8, 2, 4, + 0, 3, 6, 5, 12, 15, 10, 9, 24, 27, 30, 29, 20, 23, 18, 17, + 48, 51, 54, 53, 60, 63, 58, 57, 40, 43, 46, 45, 36, 39, 34, 33, + 35, 32, 37, 38, 47, 44, 41, 42, 59, 56, 61, 62, 55, 52, 49, 50, + 19, 16, 21, 22, 31, 28, 25, 26, 11, 8, 13, 14, 7, 4, 1, 2, + 0, 32, 3, 35, 6, 38, 5, 37, 12, 44, 15, 47, 10, 42, 9, 41, + 24, 56, 27, 59, 30, 62, 29, 61, 20, 52, 23, 55, 18, 50, 17, 49, + 48, 16, 51, 19, 54, 22, 53, 21, 60, 28, 63, 31, 58, 26, 57, 25, + 40, 8, 43, 11, 46, 14, 45, 13, 36, 4, 39, 7, 34, 2, 33, 1, + 0, 16, 32, 48, 3, 19, 35, 51, 6, 22, 38, 54, 5, 21, 37, 53, + 12, 28, 44, 60, 15, 31, 47, 63, 10, 26, 42, 58, 9, 25, 41, 57, + 24, 8, 56, 40, 27, 11, 59, 43, 30, 14, 62, 46, 29, 13, 61, 45, + 20, 4, 52, 36, 23, 7, 55, 39, 18, 2, 50, 34, 17, 1, 49, 33, + 0, 8, 16, 24, 32, 40, 48, 56, 3, 11, 19, 27, 35, 43, 51, 59, + 6, 14, 22, 30, 38, 46, 54, 62, 5, 13, 21, 29, 37, 45, 53, 61, + 12, 4, 28, 20, 44, 36, 60, 52, 15, 7, 31, 23, 47, 39, 63, 55, + 10, 2, 26, 18, 42, 34, 58, 50, 9, 1, 25, 17, 41, 33, 57, 49, + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, + 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, + 6, 2, 14, 10, 22, 18, 30, 26, 38, 34, 46, 42, 54, 50, 62, 58, + 5, 1, 13, 9, 21, 17, 29, 25, 37, 33, 45, 41, 53, 49, 61, 57, + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, + 3, 1, 7, 5, 11, 9, 15, 13, 19, 17, 23, 21, 27, 25, 31, 29, + 35, 33, 39, 37, 43, 41, 47, 45, 51, 49, 55, 53, 59, 57, 63, 61 +}; + +const qracode qra_12_63_64_irr_b = { + qra_K, + qra_N, + qra_m, + qra_M, + qra_a, + qra_NC, + qra_V, + qra_C, + qra_NMSG, + qra_MAXVDEG, + qra_MAXCDEG, + QRATYPE_NORMAL, + qra_R, + CODE_NAME, + qra_acc_input_idx, + qra_acc_input_wlog, + qra_log, + qra_exp, + qra_msgw, + qra_vdeg, + qra_cdeg, + qra_v2cmidx, + qra_c2vmidx, + qra_pmat +}; + +#undef qra_K +#undef qra_N +#undef qra_m +#undef qra_M +#undef qra_a +#undef qra_NC +#undef qra_V +#undef qra_C +#undef qra_NMSG +#undef qra_MAXVDEG +#undef qra_MAXCDEG +#undef qra_R +#undef CODE_NAME \ No newline at end of file diff --git a/libm65/qracodes/qra12_63_64_irr_b.h b/libm65/qracodes/qra12_63_64_irr_b.h new file mode 100644 index 000000000..bf70b3605 --- /dev/null +++ b/libm65/qracodes/qra12_63_64_irr_b.h @@ -0,0 +1,39 @@ +// qra12_63_64_irr_b.h +// Code tables and defines for Q-ary RA code (12,63) over GF(64) +// Code Name: qra12_63_64_irr_b +// (12,63) RA Code over GF(64) - RF=333344455567 + +// (c) 2016 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy + +// 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 . + +#ifndef _qra12_63_64_irr_b_h +#define _qra12_63_64_irr_b_h + +#include "qracodes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const qracode qra_12_63_64_irr_b; + +#ifdef __cplusplus +} +#endif + +#endif // _qra12_63_64_irr_b_h diff --git a/libm65/qracodes/qra13_64_64_irr_e.c b/libm65/qracodes/qra13_64_64_irr_e.c new file mode 100644 index 000000000..7adf22fea --- /dev/null +++ b/libm65/qracodes/qra13_64_64_irr_e.c @@ -0,0 +1,534 @@ +// qra13_64_64_irr_e.c +// Encoding/Decoding tables for Q-ary RA code (13,64) over GF(64) +// Code Name: qra13_64_64_irr_e +// (13,64) RA Code over GF(64) RF=[3x4 4x4 6x1 3x2 5x1 7x1]/18 + +// (c) 2016 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy + +// 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 . + +#include "qra13_64_64_irr_e.h" + +#define qra_K 13 // number of information symbols +#define qra_N 64 // codeword length in symbols +#define qra_m 6 // bits/symbol +#define qra_M 64 // Symbol alphabet cardinality +#define qra_a 1 // grouping factor +#define qra_NC 51 // number of check symbols (N-K) + +// Defines used by the message passing decoder -------- + +#define qra_V 64 // number of variables in the code graph (N) +#define qra_C 116 // number of factors in the code graph (N +(N-K)+1) +#define qra_NMSG 218 // number of msgs in the code graph +#define qra_MAXVDEG 8 // maximum variable degree +#define qra_MAXCDEG 3 // maximum factor degree +#define qra_R 0.20313f // code rate (K/N) +#define CODE_NAME "qra_13_64_64_irr_e" + +// table of the systematic symbols indexes in the accumulator chain +static const int qra_acc_input_idx[qra_NC+1] = { + 12, 4, 3, 9, 0, 11, 6, 8, 12, 1, + 2, 7, 4, 11, 3, 5, 9, 8, 12, 7, + 2, 4, 10, 3, 5, 11, 12, 8, 9, 6, + 7, 2, 5, 4, 12, 8, 11, 1, 6, 7, + 0, 10, 12, 8, 11, 5, 6, 1, 0, 10, + 12, 8 +}; + +// table of the systematic symbols weight logarithms over GF(M) +static const int qra_acc_input_wlog[qra_NC+1] = { + 0, 27, 0, 0, 0, 31, 28, 61, 31, 0, + 0, 52, 22, 7, 19, 47, 44, 62, 32, 50, + 52, 42, 48, 56, 40, 50, 51, 37, 37, 0, + 5, 14, 0, 0, 18, 2, 0, 45, 21, 0, + 62, 8, 11, 60, 36, 32, 17, 9, 5, 0, + 53, 0 +}; + +// table of the logarithms of the elements of GF(M) (log(0) never used) +static const int qra_log[qra_M] = { + -1, 0, 1, 6, 2, 12, 7, 26, 3, 32, + 13, 35, 8, 48, 27, 18, 4, 24, 33, 16, + 14, 52, 36, 54, 9, 45, 49, 38, 28, 41, + 19, 56, 5, 62, 25, 11, 34, 31, 17, 47, + 15, 23, 53, 51, 37, 44, 55, 40, 10, 61, + 46, 30, 50, 22, 39, 43, 29, 60, 42, 21, + 20, 59, 57, 58 +}; + +// table of GF(M) elements given their logarithm +static const int qra_exp[qra_M-1] = { + 1, 2, 4, 8, 16, 32, 3, 6, 12, 24, + 48, 35, 5, 10, 20, 40, 19, 38, 15, 30, + 60, 59, 53, 41, 17, 34, 7, 14, 28, 56, + 51, 37, 9, 18, 36, 11, 22, 44, 27, 54, + 47, 29, 58, 55, 45, 25, 50, 39, 13, 26, + 52, 43, 21, 42, 23, 46, 31, 62, 63, 61, + 57, 49, 33 +}; + +// table of the messages weight logarithms over GF(M) +static const int qra_msgw[qra_NMSG] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 27, 0, 0, 0, 31, + 28, 61, 31, 0, 0, 52, 22, 7, 19, 47, + 44, 62, 32, 50, 52, 42, 48, 56, 40, 50, + 51, 37, 37, 0, 5, 14, 0, 0, 18, 2, + 0, 45, 21, 0, 62, 8, 11, 60, 36, 32, + 17, 9, 5, 0, 53, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +// table of the degrees of the variable nodes +static const int qra_vdeg[qra_V] = { + 4, 4, 4, 4, 5, 5, 5, 5, 7, 4, + 4, 6, 8, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3 +}; + +// table of the degrees of the factor nodes +static const int qra_cdeg[qra_C] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 2 +}; + +// table (uncompressed) of the v->c message indexes (-1=unused entry) +static const int qra_v2cmidx[qra_V*qra_MAXVDEG] = { + 0, 68, 104, 112, -1, -1, -1, -1, + 1, 73, 101, 111, -1, -1, -1, -1, + 2, 74, 84, 95, -1, -1, -1, -1, + 3, 66, 78, 87, -1, -1, -1, -1, + 4, 65, 76, 85, 97, -1, -1, -1, + 5, 79, 88, 96, 109, -1, -1, -1, + 6, 70, 93, 102, 110, -1, -1, -1, + 7, 75, 83, 94, 103, -1, -1, -1, + 8, 71, 81, 91, 99, 107, 115, -1, + 9, 67, 80, 92, -1, -1, -1, -1, + 10, 86, 105, 113, -1, -1, -1, -1, + 11, 69, 77, 89, 100, 108, -1, -1, + 12, 64, 72, 82, 90, 98, 106, 114, + 13, 116, 117, -1, -1, -1, -1, -1, + 14, 118, 119, -1, -1, -1, -1, -1, + 15, 120, 121, -1, -1, -1, -1, -1, + 16, 122, 123, -1, -1, -1, -1, -1, + 17, 124, 125, -1, -1, -1, -1, -1, + 18, 126, 127, -1, -1, -1, -1, -1, + 19, 128, 129, -1, -1, -1, -1, -1, + 20, 130, 131, -1, -1, -1, -1, -1, + 21, 132, 133, -1, -1, -1, -1, -1, + 22, 134, 135, -1, -1, -1, -1, -1, + 23, 136, 137, -1, -1, -1, -1, -1, + 24, 138, 139, -1, -1, -1, -1, -1, + 25, 140, 141, -1, -1, -1, -1, -1, + 26, 142, 143, -1, -1, -1, -1, -1, + 27, 144, 145, -1, -1, -1, -1, -1, + 28, 146, 147, -1, -1, -1, -1, -1, + 29, 148, 149, -1, -1, -1, -1, -1, + 30, 150, 151, -1, -1, -1, -1, -1, + 31, 152, 153, -1, -1, -1, -1, -1, + 32, 154, 155, -1, -1, -1, -1, -1, + 33, 156, 157, -1, -1, -1, -1, -1, + 34, 158, 159, -1, -1, -1, -1, -1, + 35, 160, 161, -1, -1, -1, -1, -1, + 36, 162, 163, -1, -1, -1, -1, -1, + 37, 164, 165, -1, -1, -1, -1, -1, + 38, 166, 167, -1, -1, -1, -1, -1, + 39, 168, 169, -1, -1, -1, -1, -1, + 40, 170, 171, -1, -1, -1, -1, -1, + 41, 172, 173, -1, -1, -1, -1, -1, + 42, 174, 175, -1, -1, -1, -1, -1, + 43, 176, 177, -1, -1, -1, -1, -1, + 44, 178, 179, -1, -1, -1, -1, -1, + 45, 180, 181, -1, -1, -1, -1, -1, + 46, 182, 183, -1, -1, -1, -1, -1, + 47, 184, 185, -1, -1, -1, -1, -1, + 48, 186, 187, -1, -1, -1, -1, -1, + 49, 188, 189, -1, -1, -1, -1, -1, + 50, 190, 191, -1, -1, -1, -1, -1, + 51, 192, 193, -1, -1, -1, -1, -1, + 52, 194, 195, -1, -1, -1, -1, -1, + 53, 196, 197, -1, -1, -1, -1, -1, + 54, 198, 199, -1, -1, -1, -1, -1, + 55, 200, 201, -1, -1, -1, -1, -1, + 56, 202, 203, -1, -1, -1, -1, -1, + 57, 204, 205, -1, -1, -1, -1, -1, + 58, 206, 207, -1, -1, -1, -1, -1, + 59, 208, 209, -1, -1, -1, -1, -1, + 60, 210, 211, -1, -1, -1, -1, -1, + 61, 212, 213, -1, -1, -1, -1, -1, + 62, 214, 215, -1, -1, -1, -1, -1, + 63, 216, 217, -1, -1, -1, -1, -1 +}; + +// table (uncompressed) of the c->v message indexes (-1=unused entry) +static const int qra_c2vmidx[qra_C*qra_MAXCDEG] = { + 0, -1, -1, 1, -1, -1, 2, -1, -1, 3, -1, -1, + 4, -1, -1, 5, -1, -1, 6, -1, -1, 7, -1, -1, + 8, -1, -1, 9, -1, -1, 10, -1, -1, 11, -1, -1, + 12, -1, -1, 13, -1, -1, 14, -1, -1, 15, -1, -1, + 16, -1, -1, 17, -1, -1, 18, -1, -1, 19, -1, -1, + 20, -1, -1, 21, -1, -1, 22, -1, -1, 23, -1, -1, + 24, -1, -1, 25, -1, -1, 26, -1, -1, 27, -1, -1, + 28, -1, -1, 29, -1, -1, 30, -1, -1, 31, -1, -1, + 32, -1, -1, 33, -1, -1, 34, -1, -1, 35, -1, -1, + 36, -1, -1, 37, -1, -1, 38, -1, -1, 39, -1, -1, + 40, -1, -1, 41, -1, -1, 42, -1, -1, 43, -1, -1, + 44, -1, -1, 45, -1, -1, 46, -1, -1, 47, -1, -1, + 48, -1, -1, 49, -1, -1, 50, -1, -1, 51, -1, -1, + 52, -1, -1, 53, -1, -1, 54, -1, -1, 55, -1, -1, + 56, -1, -1, 57, -1, -1, 58, -1, -1, 59, -1, -1, + 60, -1, -1, 61, -1, -1, 62, -1, -1, 63, -1, -1, + 64, 116, -1, 65, 117, 118, 66, 119, 120, 67, 121, 122, + 68, 123, 124, 69, 125, 126, 70, 127, 128, 71, 129, 130, + 72, 131, 132, 73, 133, 134, 74, 135, 136, 75, 137, 138, + 76, 139, 140, 77, 141, 142, 78, 143, 144, 79, 145, 146, + 80, 147, 148, 81, 149, 150, 82, 151, 152, 83, 153, 154, + 84, 155, 156, 85, 157, 158, 86, 159, 160, 87, 161, 162, + 88, 163, 164, 89, 165, 166, 90, 167, 168, 91, 169, 170, + 92, 171, 172, 93, 173, 174, 94, 175, 176, 95, 177, 178, + 96, 179, 180, 97, 181, 182, 98, 183, 184, 99, 185, 186, +100, 187, 188, 101, 189, 190, 102, 191, 192, 103, 193, 194, +104, 195, 196, 105, 197, 198, 106, 199, 200, 107, 201, 202, +108, 203, 204, 109, 205, 206, 110, 207, 208, 111, 209, 210, +112, 211, 212, 113, 213, 214, 114, 215, 216, 115, 217, -1 +}; + +// permutation matrix to compute Prob(x*alfa^logw) +static const int qra_pmat[qra_M*qra_M] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 33, 1, 32, 2, 35, 3, 34, 4, 37, 5, 36, 6, 39, 7, 38, + 8, 41, 9, 40, 10, 43, 11, 42, 12, 45, 13, 44, 14, 47, 15, 46, + 16, 49, 17, 48, 18, 51, 19, 50, 20, 53, 21, 52, 22, 55, 23, 54, + 24, 57, 25, 56, 26, 59, 27, 58, 28, 61, 29, 60, 30, 63, 31, 62, + 0, 49, 33, 16, 1, 48, 32, 17, 2, 51, 35, 18, 3, 50, 34, 19, + 4, 53, 37, 20, 5, 52, 36, 21, 6, 55, 39, 22, 7, 54, 38, 23, + 8, 57, 41, 24, 9, 56, 40, 25, 10, 59, 43, 26, 11, 58, 42, 27, + 12, 61, 45, 28, 13, 60, 44, 29, 14, 63, 47, 30, 15, 62, 46, 31, + 0, 57, 49, 8, 33, 24, 16, 41, 1, 56, 48, 9, 32, 25, 17, 40, + 2, 59, 51, 10, 35, 26, 18, 43, 3, 58, 50, 11, 34, 27, 19, 42, + 4, 61, 53, 12, 37, 28, 20, 45, 5, 60, 52, 13, 36, 29, 21, 44, + 6, 63, 55, 14, 39, 30, 22, 47, 7, 62, 54, 15, 38, 31, 23, 46, + 0, 61, 57, 4, 49, 12, 8, 53, 33, 28, 24, 37, 16, 45, 41, 20, + 1, 60, 56, 5, 48, 13, 9, 52, 32, 29, 25, 36, 17, 44, 40, 21, + 2, 63, 59, 6, 51, 14, 10, 55, 35, 30, 26, 39, 18, 47, 43, 22, + 3, 62, 58, 7, 50, 15, 11, 54, 34, 31, 27, 38, 19, 46, 42, 23, + 0, 63, 61, 2, 57, 6, 4, 59, 49, 14, 12, 51, 8, 55, 53, 10, + 33, 30, 28, 35, 24, 39, 37, 26, 16, 47, 45, 18, 41, 22, 20, 43, + 1, 62, 60, 3, 56, 7, 5, 58, 48, 15, 13, 50, 9, 54, 52, 11, + 32, 31, 29, 34, 25, 38, 36, 27, 17, 46, 44, 19, 40, 23, 21, 42, + 0, 62, 63, 1, 61, 3, 2, 60, 57, 7, 6, 56, 4, 58, 59, 5, + 49, 15, 14, 48, 12, 50, 51, 13, 8, 54, 55, 9, 53, 11, 10, 52, + 33, 31, 30, 32, 28, 34, 35, 29, 24, 38, 39, 25, 37, 27, 26, 36, + 16, 46, 47, 17, 45, 19, 18, 44, 41, 23, 22, 40, 20, 42, 43, 21, + 0, 31, 62, 33, 63, 32, 1, 30, 61, 34, 3, 28, 2, 29, 60, 35, + 57, 38, 7, 24, 6, 25, 56, 39, 4, 27, 58, 37, 59, 36, 5, 26, + 49, 46, 15, 16, 14, 17, 48, 47, 12, 19, 50, 45, 51, 44, 13, 18, + 8, 23, 54, 41, 55, 40, 9, 22, 53, 42, 11, 20, 10, 21, 52, 43, + 0, 46, 31, 49, 62, 16, 33, 15, 63, 17, 32, 14, 1, 47, 30, 48, + 61, 19, 34, 12, 3, 45, 28, 50, 2, 44, 29, 51, 60, 18, 35, 13, + 57, 23, 38, 8, 7, 41, 24, 54, 6, 40, 25, 55, 56, 22, 39, 9, + 4, 42, 27, 53, 58, 20, 37, 11, 59, 21, 36, 10, 5, 43, 26, 52, + 0, 23, 46, 57, 31, 8, 49, 38, 62, 41, 16, 7, 33, 54, 15, 24, + 63, 40, 17, 6, 32, 55, 14, 25, 1, 22, 47, 56, 30, 9, 48, 39, + 61, 42, 19, 4, 34, 53, 12, 27, 3, 20, 45, 58, 28, 11, 50, 37, + 2, 21, 44, 59, 29, 10, 51, 36, 60, 43, 18, 5, 35, 52, 13, 26, + 0, 42, 23, 61, 46, 4, 57, 19, 31, 53, 8, 34, 49, 27, 38, 12, + 62, 20, 41, 3, 16, 58, 7, 45, 33, 11, 54, 28, 15, 37, 24, 50, + 63, 21, 40, 2, 17, 59, 6, 44, 32, 10, 55, 29, 14, 36, 25, 51, + 1, 43, 22, 60, 47, 5, 56, 18, 30, 52, 9, 35, 48, 26, 39, 13, + 0, 21, 42, 63, 23, 2, 61, 40, 46, 59, 4, 17, 57, 44, 19, 6, + 31, 10, 53, 32, 8, 29, 34, 55, 49, 36, 27, 14, 38, 51, 12, 25, + 62, 43, 20, 1, 41, 60, 3, 22, 16, 5, 58, 47, 7, 18, 45, 56, + 33, 52, 11, 30, 54, 35, 28, 9, 15, 26, 37, 48, 24, 13, 50, 39, + 0, 43, 21, 62, 42, 1, 63, 20, 23, 60, 2, 41, 61, 22, 40, 3, + 46, 5, 59, 16, 4, 47, 17, 58, 57, 18, 44, 7, 19, 56, 6, 45, + 31, 52, 10, 33, 53, 30, 32, 11, 8, 35, 29, 54, 34, 9, 55, 28, + 49, 26, 36, 15, 27, 48, 14, 37, 38, 13, 51, 24, 12, 39, 25, 50, + 0, 52, 43, 31, 21, 33, 62, 10, 42, 30, 1, 53, 63, 11, 20, 32, + 23, 35, 60, 8, 2, 54, 41, 29, 61, 9, 22, 34, 40, 28, 3, 55, + 46, 26, 5, 49, 59, 15, 16, 36, 4, 48, 47, 27, 17, 37, 58, 14, + 57, 13, 18, 38, 44, 24, 7, 51, 19, 39, 56, 12, 6, 50, 45, 25, + 0, 26, 52, 46, 43, 49, 31, 5, 21, 15, 33, 59, 62, 36, 10, 16, + 42, 48, 30, 4, 1, 27, 53, 47, 63, 37, 11, 17, 20, 14, 32, 58, + 23, 13, 35, 57, 60, 38, 8, 18, 2, 24, 54, 44, 41, 51, 29, 7, + 61, 39, 9, 19, 22, 12, 34, 56, 40, 50, 28, 6, 3, 25, 55, 45, + 0, 13, 26, 23, 52, 57, 46, 35, 43, 38, 49, 60, 31, 18, 5, 8, + 21, 24, 15, 2, 33, 44, 59, 54, 62, 51, 36, 41, 10, 7, 16, 29, + 42, 39, 48, 61, 30, 19, 4, 9, 1, 12, 27, 22, 53, 56, 47, 34, + 63, 50, 37, 40, 11, 6, 17, 28, 20, 25, 14, 3, 32, 45, 58, 55, + 0, 39, 13, 42, 26, 61, 23, 48, 52, 19, 57, 30, 46, 9, 35, 4, + 43, 12, 38, 1, 49, 22, 60, 27, 31, 56, 18, 53, 5, 34, 8, 47, + 21, 50, 24, 63, 15, 40, 2, 37, 33, 6, 44, 11, 59, 28, 54, 17, + 62, 25, 51, 20, 36, 3, 41, 14, 10, 45, 7, 32, 16, 55, 29, 58, + 0, 50, 39, 21, 13, 63, 42, 24, 26, 40, 61, 15, 23, 37, 48, 2, + 52, 6, 19, 33, 57, 11, 30, 44, 46, 28, 9, 59, 35, 17, 4, 54, + 43, 25, 12, 62, 38, 20, 1, 51, 49, 3, 22, 36, 60, 14, 27, 41, + 31, 45, 56, 10, 18, 32, 53, 7, 5, 55, 34, 16, 8, 58, 47, 29, + 0, 25, 50, 43, 39, 62, 21, 12, 13, 20, 63, 38, 42, 51, 24, 1, + 26, 3, 40, 49, 61, 36, 15, 22, 23, 14, 37, 60, 48, 41, 2, 27, + 52, 45, 6, 31, 19, 10, 33, 56, 57, 32, 11, 18, 30, 7, 44, 53, + 46, 55, 28, 5, 9, 16, 59, 34, 35, 58, 17, 8, 4, 29, 54, 47, + 0, 45, 25, 52, 50, 31, 43, 6, 39, 10, 62, 19, 21, 56, 12, 33, + 13, 32, 20, 57, 63, 18, 38, 11, 42, 7, 51, 30, 24, 53, 1, 44, + 26, 55, 3, 46, 40, 5, 49, 28, 61, 16, 36, 9, 15, 34, 22, 59, + 23, 58, 14, 35, 37, 8, 60, 17, 48, 29, 41, 4, 2, 47, 27, 54, + 0, 55, 45, 26, 25, 46, 52, 3, 50, 5, 31, 40, 43, 28, 6, 49, + 39, 16, 10, 61, 62, 9, 19, 36, 21, 34, 56, 15, 12, 59, 33, 22, + 13, 58, 32, 23, 20, 35, 57, 14, 63, 8, 18, 37, 38, 17, 11, 60, + 42, 29, 7, 48, 51, 4, 30, 41, 24, 47, 53, 2, 1, 54, 44, 27, + 0, 58, 55, 13, 45, 23, 26, 32, 25, 35, 46, 20, 52, 14, 3, 57, + 50, 8, 5, 63, 31, 37, 40, 18, 43, 17, 28, 38, 6, 60, 49, 11, + 39, 29, 16, 42, 10, 48, 61, 7, 62, 4, 9, 51, 19, 41, 36, 30, + 21, 47, 34, 24, 56, 2, 15, 53, 12, 54, 59, 1, 33, 27, 22, 44, + 0, 29, 58, 39, 55, 42, 13, 16, 45, 48, 23, 10, 26, 7, 32, 61, + 25, 4, 35, 62, 46, 51, 20, 9, 52, 41, 14, 19, 3, 30, 57, 36, + 50, 47, 8, 21, 5, 24, 63, 34, 31, 2, 37, 56, 40, 53, 18, 15, + 43, 54, 17, 12, 28, 1, 38, 59, 6, 27, 60, 33, 49, 44, 11, 22, + 0, 47, 29, 50, 58, 21, 39, 8, 55, 24, 42, 5, 13, 34, 16, 63, + 45, 2, 48, 31, 23, 56, 10, 37, 26, 53, 7, 40, 32, 15, 61, 18, + 25, 54, 4, 43, 35, 12, 62, 17, 46, 1, 51, 28, 20, 59, 9, 38, + 52, 27, 41, 6, 14, 33, 19, 60, 3, 44, 30, 49, 57, 22, 36, 11, + 0, 54, 47, 25, 29, 43, 50, 4, 58, 12, 21, 35, 39, 17, 8, 62, + 55, 1, 24, 46, 42, 28, 5, 51, 13, 59, 34, 20, 16, 38, 63, 9, + 45, 27, 2, 52, 48, 6, 31, 41, 23, 33, 56, 14, 10, 60, 37, 19, + 26, 44, 53, 3, 7, 49, 40, 30, 32, 22, 15, 57, 61, 11, 18, 36, + 0, 27, 54, 45, 47, 52, 25, 2, 29, 6, 43, 48, 50, 41, 4, 31, + 58, 33, 12, 23, 21, 14, 35, 56, 39, 60, 17, 10, 8, 19, 62, 37, + 55, 44, 1, 26, 24, 3, 46, 53, 42, 49, 28, 7, 5, 30, 51, 40, + 13, 22, 59, 32, 34, 57, 20, 15, 16, 11, 38, 61, 63, 36, 9, 18, + 0, 44, 27, 55, 54, 26, 45, 1, 47, 3, 52, 24, 25, 53, 2, 46, + 29, 49, 6, 42, 43, 7, 48, 28, 50, 30, 41, 5, 4, 40, 31, 51, + 58, 22, 33, 13, 12, 32, 23, 59, 21, 57, 14, 34, 35, 15, 56, 20, + 39, 11, 60, 16, 17, 61, 10, 38, 8, 36, 19, 63, 62, 18, 37, 9, + 0, 22, 44, 58, 27, 13, 55, 33, 54, 32, 26, 12, 45, 59, 1, 23, + 47, 57, 3, 21, 52, 34, 24, 14, 25, 15, 53, 35, 2, 20, 46, 56, + 29, 11, 49, 39, 6, 16, 42, 60, 43, 61, 7, 17, 48, 38, 28, 10, + 50, 36, 30, 8, 41, 63, 5, 19, 4, 18, 40, 62, 31, 9, 51, 37, + 0, 11, 22, 29, 44, 39, 58, 49, 27, 16, 13, 6, 55, 60, 33, 42, + 54, 61, 32, 43, 26, 17, 12, 7, 45, 38, 59, 48, 1, 10, 23, 28, + 47, 36, 57, 50, 3, 8, 21, 30, 52, 63, 34, 41, 24, 19, 14, 5, + 25, 18, 15, 4, 53, 62, 35, 40, 2, 9, 20, 31, 46, 37, 56, 51, + 0, 36, 11, 47, 22, 50, 29, 57, 44, 8, 39, 3, 58, 30, 49, 21, + 27, 63, 16, 52, 13, 41, 6, 34, 55, 19, 60, 24, 33, 5, 42, 14, + 54, 18, 61, 25, 32, 4, 43, 15, 26, 62, 17, 53, 12, 40, 7, 35, + 45, 9, 38, 2, 59, 31, 48, 20, 1, 37, 10, 46, 23, 51, 28, 56, + 0, 18, 36, 54, 11, 25, 47, 61, 22, 4, 50, 32, 29, 15, 57, 43, + 44, 62, 8, 26, 39, 53, 3, 17, 58, 40, 30, 12, 49, 35, 21, 7, + 27, 9, 63, 45, 16, 2, 52, 38, 13, 31, 41, 59, 6, 20, 34, 48, + 55, 37, 19, 1, 60, 46, 24, 10, 33, 51, 5, 23, 42, 56, 14, 28, + 0, 9, 18, 27, 36, 45, 54, 63, 11, 2, 25, 16, 47, 38, 61, 52, + 22, 31, 4, 13, 50, 59, 32, 41, 29, 20, 15, 6, 57, 48, 43, 34, + 44, 37, 62, 55, 8, 1, 26, 19, 39, 46, 53, 60, 3, 10, 17, 24, + 58, 51, 40, 33, 30, 23, 12, 5, 49, 56, 35, 42, 21, 28, 7, 14, + 0, 37, 9, 44, 18, 55, 27, 62, 36, 1, 45, 8, 54, 19, 63, 26, + 11, 46, 2, 39, 25, 60, 16, 53, 47, 10, 38, 3, 61, 24, 52, 17, + 22, 51, 31, 58, 4, 33, 13, 40, 50, 23, 59, 30, 32, 5, 41, 12, + 29, 56, 20, 49, 15, 42, 6, 35, 57, 28, 48, 21, 43, 14, 34, 7, + 0, 51, 37, 22, 9, 58, 44, 31, 18, 33, 55, 4, 27, 40, 62, 13, + 36, 23, 1, 50, 45, 30, 8, 59, 54, 5, 19, 32, 63, 12, 26, 41, + 11, 56, 46, 29, 2, 49, 39, 20, 25, 42, 60, 15, 16, 35, 53, 6, + 47, 28, 10, 57, 38, 21, 3, 48, 61, 14, 24, 43, 52, 7, 17, 34, + 0, 56, 51, 11, 37, 29, 22, 46, 9, 49, 58, 2, 44, 20, 31, 39, + 18, 42, 33, 25, 55, 15, 4, 60, 27, 35, 40, 16, 62, 6, 13, 53, + 36, 28, 23, 47, 1, 57, 50, 10, 45, 21, 30, 38, 8, 48, 59, 3, + 54, 14, 5, 61, 19, 43, 32, 24, 63, 7, 12, 52, 26, 34, 41, 17, + 0, 28, 56, 36, 51, 47, 11, 23, 37, 57, 29, 1, 22, 10, 46, 50, + 9, 21, 49, 45, 58, 38, 2, 30, 44, 48, 20, 8, 31, 3, 39, 59, + 18, 14, 42, 54, 33, 61, 25, 5, 55, 43, 15, 19, 4, 24, 60, 32, + 27, 7, 35, 63, 40, 52, 16, 12, 62, 34, 6, 26, 13, 17, 53, 41, + 0, 14, 28, 18, 56, 54, 36, 42, 51, 61, 47, 33, 11, 5, 23, 25, + 37, 43, 57, 55, 29, 19, 1, 15, 22, 24, 10, 4, 46, 32, 50, 60, + 9, 7, 21, 27, 49, 63, 45, 35, 58, 52, 38, 40, 2, 12, 30, 16, + 44, 34, 48, 62, 20, 26, 8, 6, 31, 17, 3, 13, 39, 41, 59, 53, + 0, 7, 14, 9, 28, 27, 18, 21, 56, 63, 54, 49, 36, 35, 42, 45, + 51, 52, 61, 58, 47, 40, 33, 38, 11, 12, 5, 2, 23, 16, 25, 30, + 37, 34, 43, 44, 57, 62, 55, 48, 29, 26, 19, 20, 1, 6, 15, 8, + 22, 17, 24, 31, 10, 13, 4, 3, 46, 41, 32, 39, 50, 53, 60, 59, + 0, 34, 7, 37, 14, 44, 9, 43, 28, 62, 27, 57, 18, 48, 21, 55, + 56, 26, 63, 29, 54, 20, 49, 19, 36, 6, 35, 1, 42, 8, 45, 15, + 51, 17, 52, 22, 61, 31, 58, 24, 47, 13, 40, 10, 33, 3, 38, 4, + 11, 41, 12, 46, 5, 39, 2, 32, 23, 53, 16, 50, 25, 59, 30, 60, + 0, 17, 34, 51, 7, 22, 37, 52, 14, 31, 44, 61, 9, 24, 43, 58, + 28, 13, 62, 47, 27, 10, 57, 40, 18, 3, 48, 33, 21, 4, 55, 38, + 56, 41, 26, 11, 63, 46, 29, 12, 54, 39, 20, 5, 49, 32, 19, 2, + 36, 53, 6, 23, 35, 50, 1, 16, 42, 59, 8, 25, 45, 60, 15, 30, + 0, 41, 17, 56, 34, 11, 51, 26, 7, 46, 22, 63, 37, 12, 52, 29, + 14, 39, 31, 54, 44, 5, 61, 20, 9, 32, 24, 49, 43, 2, 58, 19, + 28, 53, 13, 36, 62, 23, 47, 6, 27, 50, 10, 35, 57, 16, 40, 1, + 18, 59, 3, 42, 48, 25, 33, 8, 21, 60, 4, 45, 55, 30, 38, 15, + 0, 53, 41, 28, 17, 36, 56, 13, 34, 23, 11, 62, 51, 6, 26, 47, + 7, 50, 46, 27, 22, 35, 63, 10, 37, 16, 12, 57, 52, 1, 29, 40, + 14, 59, 39, 18, 31, 42, 54, 3, 44, 25, 5, 48, 61, 8, 20, 33, + 9, 60, 32, 21, 24, 45, 49, 4, 43, 30, 2, 55, 58, 15, 19, 38, + 0, 59, 53, 14, 41, 18, 28, 39, 17, 42, 36, 31, 56, 3, 13, 54, + 34, 25, 23, 44, 11, 48, 62, 5, 51, 8, 6, 61, 26, 33, 47, 20, + 7, 60, 50, 9, 46, 21, 27, 32, 22, 45, 35, 24, 63, 4, 10, 49, + 37, 30, 16, 43, 12, 55, 57, 2, 52, 15, 1, 58, 29, 38, 40, 19, + 0, 60, 59, 7, 53, 9, 14, 50, 41, 21, 18, 46, 28, 32, 39, 27, + 17, 45, 42, 22, 36, 24, 31, 35, 56, 4, 3, 63, 13, 49, 54, 10, + 34, 30, 25, 37, 23, 43, 44, 16, 11, 55, 48, 12, 62, 2, 5, 57, + 51, 15, 8, 52, 6, 58, 61, 1, 26, 38, 33, 29, 47, 19, 20, 40, + 0, 30, 60, 34, 59, 37, 7, 25, 53, 43, 9, 23, 14, 16, 50, 44, + 41, 55, 21, 11, 18, 12, 46, 48, 28, 2, 32, 62, 39, 57, 27, 5, + 17, 15, 45, 51, 42, 52, 22, 8, 36, 58, 24, 6, 31, 1, 35, 61, + 56, 38, 4, 26, 3, 29, 63, 33, 13, 19, 49, 47, 54, 40, 10, 20, + 0, 15, 30, 17, 60, 51, 34, 45, 59, 52, 37, 42, 7, 8, 25, 22, + 53, 58, 43, 36, 9, 6, 23, 24, 14, 1, 16, 31, 50, 61, 44, 35, + 41, 38, 55, 56, 21, 26, 11, 4, 18, 29, 12, 3, 46, 33, 48, 63, + 28, 19, 2, 13, 32, 47, 62, 49, 39, 40, 57, 54, 27, 20, 5, 10, + 0, 38, 15, 41, 30, 56, 17, 55, 60, 26, 51, 21, 34, 4, 45, 11, + 59, 29, 52, 18, 37, 3, 42, 12, 7, 33, 8, 46, 25, 63, 22, 48, + 53, 19, 58, 28, 43, 13, 36, 2, 9, 47, 6, 32, 23, 49, 24, 62, + 14, 40, 1, 39, 16, 54, 31, 57, 50, 20, 61, 27, 44, 10, 35, 5, + 0, 19, 38, 53, 15, 28, 41, 58, 30, 13, 56, 43, 17, 2, 55, 36, + 60, 47, 26, 9, 51, 32, 21, 6, 34, 49, 4, 23, 45, 62, 11, 24, + 59, 40, 29, 14, 52, 39, 18, 1, 37, 54, 3, 16, 42, 57, 12, 31, + 7, 20, 33, 50, 8, 27, 46, 61, 25, 10, 63, 44, 22, 5, 48, 35, + 0, 40, 19, 59, 38, 14, 53, 29, 15, 39, 28, 52, 41, 1, 58, 18, + 30, 54, 13, 37, 56, 16, 43, 3, 17, 57, 2, 42, 55, 31, 36, 12, + 60, 20, 47, 7, 26, 50, 9, 33, 51, 27, 32, 8, 21, 61, 6, 46, + 34, 10, 49, 25, 4, 44, 23, 63, 45, 5, 62, 22, 11, 35, 24, 48, + 0, 20, 40, 60, 19, 7, 59, 47, 38, 50, 14, 26, 53, 33, 29, 9, + 15, 27, 39, 51, 28, 8, 52, 32, 41, 61, 1, 21, 58, 46, 18, 6, + 30, 10, 54, 34, 13, 25, 37, 49, 56, 44, 16, 4, 43, 63, 3, 23, + 17, 5, 57, 45, 2, 22, 42, 62, 55, 35, 31, 11, 36, 48, 12, 24, + 0, 10, 20, 30, 40, 34, 60, 54, 19, 25, 7, 13, 59, 49, 47, 37, + 38, 44, 50, 56, 14, 4, 26, 16, 53, 63, 33, 43, 29, 23, 9, 3, + 15, 5, 27, 17, 39, 45, 51, 57, 28, 22, 8, 2, 52, 62, 32, 42, + 41, 35, 61, 55, 1, 11, 21, 31, 58, 48, 46, 36, 18, 24, 6, 12, + 0, 5, 10, 15, 20, 17, 30, 27, 40, 45, 34, 39, 60, 57, 54, 51, + 19, 22, 25, 28, 7, 2, 13, 8, 59, 62, 49, 52, 47, 42, 37, 32, + 38, 35, 44, 41, 50, 55, 56, 61, 14, 11, 4, 1, 26, 31, 16, 21, + 53, 48, 63, 58, 33, 36, 43, 46, 29, 24, 23, 18, 9, 12, 3, 6, + 0, 35, 5, 38, 10, 41, 15, 44, 20, 55, 17, 50, 30, 61, 27, 56, + 40, 11, 45, 14, 34, 1, 39, 4, 60, 31, 57, 26, 54, 21, 51, 16, + 19, 48, 22, 53, 25, 58, 28, 63, 7, 36, 2, 33, 13, 46, 8, 43, + 59, 24, 62, 29, 49, 18, 52, 23, 47, 12, 42, 9, 37, 6, 32, 3, + 0, 48, 35, 19, 5, 53, 38, 22, 10, 58, 41, 25, 15, 63, 44, 28, + 20, 36, 55, 7, 17, 33, 50, 2, 30, 46, 61, 13, 27, 43, 56, 8, + 40, 24, 11, 59, 45, 29, 14, 62, 34, 18, 1, 49, 39, 23, 4, 52, + 60, 12, 31, 47, 57, 9, 26, 42, 54, 6, 21, 37, 51, 3, 16, 32, + 0, 24, 48, 40, 35, 59, 19, 11, 5, 29, 53, 45, 38, 62, 22, 14, + 10, 18, 58, 34, 41, 49, 25, 1, 15, 23, 63, 39, 44, 52, 28, 4, + 20, 12, 36, 60, 55, 47, 7, 31, 17, 9, 33, 57, 50, 42, 2, 26, + 30, 6, 46, 54, 61, 37, 13, 21, 27, 3, 43, 51, 56, 32, 8, 16, + 0, 12, 24, 20, 48, 60, 40, 36, 35, 47, 59, 55, 19, 31, 11, 7, + 5, 9, 29, 17, 53, 57, 45, 33, 38, 42, 62, 50, 22, 26, 14, 2, + 10, 6, 18, 30, 58, 54, 34, 46, 41, 37, 49, 61, 25, 21, 1, 13, + 15, 3, 23, 27, 63, 51, 39, 43, 44, 32, 52, 56, 28, 16, 4, 8, + 0, 6, 12, 10, 24, 30, 20, 18, 48, 54, 60, 58, 40, 46, 36, 34, + 35, 37, 47, 41, 59, 61, 55, 49, 19, 21, 31, 25, 11, 13, 7, 1, + 5, 3, 9, 15, 29, 27, 17, 23, 53, 51, 57, 63, 45, 43, 33, 39, + 38, 32, 42, 44, 62, 56, 50, 52, 22, 16, 26, 28, 14, 8, 2, 4, + 0, 3, 6, 5, 12, 15, 10, 9, 24, 27, 30, 29, 20, 23, 18, 17, + 48, 51, 54, 53, 60, 63, 58, 57, 40, 43, 46, 45, 36, 39, 34, 33, + 35, 32, 37, 38, 47, 44, 41, 42, 59, 56, 61, 62, 55, 52, 49, 50, + 19, 16, 21, 22, 31, 28, 25, 26, 11, 8, 13, 14, 7, 4, 1, 2, + 0, 32, 3, 35, 6, 38, 5, 37, 12, 44, 15, 47, 10, 42, 9, 41, + 24, 56, 27, 59, 30, 62, 29, 61, 20, 52, 23, 55, 18, 50, 17, 49, + 48, 16, 51, 19, 54, 22, 53, 21, 60, 28, 63, 31, 58, 26, 57, 25, + 40, 8, 43, 11, 46, 14, 45, 13, 36, 4, 39, 7, 34, 2, 33, 1, + 0, 16, 32, 48, 3, 19, 35, 51, 6, 22, 38, 54, 5, 21, 37, 53, + 12, 28, 44, 60, 15, 31, 47, 63, 10, 26, 42, 58, 9, 25, 41, 57, + 24, 8, 56, 40, 27, 11, 59, 43, 30, 14, 62, 46, 29, 13, 61, 45, + 20, 4, 52, 36, 23, 7, 55, 39, 18, 2, 50, 34, 17, 1, 49, 33, + 0, 8, 16, 24, 32, 40, 48, 56, 3, 11, 19, 27, 35, 43, 51, 59, + 6, 14, 22, 30, 38, 46, 54, 62, 5, 13, 21, 29, 37, 45, 53, 61, + 12, 4, 28, 20, 44, 36, 60, 52, 15, 7, 31, 23, 47, 39, 63, 55, + 10, 2, 26, 18, 42, 34, 58, 50, 9, 1, 25, 17, 41, 33, 57, 49, + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, + 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, + 6, 2, 14, 10, 22, 18, 30, 26, 38, 34, 46, 42, 54, 50, 62, 58, + 5, 1, 13, 9, 21, 17, 29, 25, 37, 33, 45, 41, 53, 49, 61, 57, + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, + 3, 1, 7, 5, 11, 9, 15, 13, 19, 17, 23, 21, 27, 25, 31, 29, + 35, 33, 39, 37, 43, 41, 47, 45, 51, 49, 55, 53, 59, 57, 63, 61 +}; + +const qracode qra_13_64_64_irr_e = { + qra_K, + qra_N, + qra_m, + qra_M, + qra_a, + qra_NC, + qra_V, + qra_C, + qra_NMSG, + qra_MAXVDEG, + qra_MAXCDEG, + QRATYPE_CRCPUNCTURED, + qra_R, + CODE_NAME, + qra_acc_input_idx, + qra_acc_input_wlog, + qra_log, + qra_exp, + qra_msgw, + qra_vdeg, + qra_cdeg, + qra_v2cmidx, + qra_c2vmidx, + qra_pmat +}; + +#undef qra_K +#undef qra_N +#undef qra_m +#undef qra_M +#undef qra_a +#undef qra_NC +#undef qra_V +#undef qra_C +#undef qra_NMSG +#undef qra_MAXVDEG +#undef qra_MAXCDEG +#undef qra_R +#undef CODE_NAME \ No newline at end of file diff --git a/libm65/qracodes/qra13_64_64_irr_e.h b/libm65/qracodes/qra13_64_64_irr_e.h new file mode 100644 index 000000000..d24421d2f --- /dev/null +++ b/libm65/qracodes/qra13_64_64_irr_e.h @@ -0,0 +1,39 @@ +// qra13_64_64_irr_e.h +// Code tables and defines for Q-ary RA code (13,64) over GF(64) +// Code Name: qra13_64_64_irr_e +// (13,64) RA Code over GF(64) RF=[3x4 4x4 6x1 3x2 5x1 7x1]/18 + +// (c) 2016 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy + +// 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 . + +#ifndef _qra13_64_64_irr_e_h +#define _qra13_64_64_irr_e_h + +#include "qracodes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const qracode qra_13_64_64_irr_e; + +#ifdef __cplusplus +} +#endif + +#endif // _qra13_64_64_irr_e_h diff --git a/libm65/qracodes/qracodes.c b/libm65/qracodes/qracodes.c new file mode 100644 index 000000000..748a9c9cd --- /dev/null +++ b/libm65/qracodes/qracodes.c @@ -0,0 +1,474 @@ +// qracodes.c +// Q-ary RA codes encoding/decoding functions +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// 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 . + +#include +#include + +#include "npfwht.h" +#include "pdmath.h" + +#include "qracodes.h" + +int qra_encode(const qracode *pcode, int *y, const int *x) +{ + int k,j,kk,jj; + int t, chk = 0; + + const int K = pcode->K; + const int M = pcode->M; + const int NC= pcode->NC; + const int a = pcode->a; + const int *acc_input_idx = pcode->acc_input_idx; + const int *acc_input_wlog = pcode->acc_input_wlog; + const int *gflog = pcode->gflog; + const int *gfexp = pcode->gfexp; + + // copy the systematic symbols to destination + memcpy(y,x,K*sizeof(int)); + + y = y+K; // point to check symbols + + // compute the code check symbols as a weighted accumulation of a permutated + // sequence of the (repeated) systematic input symbols: + // chk(k+1) = x(idx(k))*alfa^(logw(k)) + chk(k) + // (all operations performed over GF(M)) + + if (a==1) { // grouping factor = 1 + for (k=0;k 1 + for (k=0;k80.f) // avoid floating point exp() overflows + v=80.f; + + src[nitems] = (float)exp(v); + } +} + + +float qra_mfskbesselmetric(float *pix, const float *rsq, const int m, const int N, float EsNoMetric) +{ + // Computes the codeword symbols intrinsic probabilities + // given the square of the received input amplitudes. + + // The input vector rqs must be a linear array of size M*N, where M=2^m, + // containing the squared amplitudes (rp*rp+rq*rq) of the input samples + + // First symbol amplitudes should be stored in the first M positions, + // second symbol amplitudes stored at positions [M ... 2*M-1], and so on. + + // Output vector is the intrinsic symbol metric (the probability distribution) + // assuming that symbols are transmitted using a M-FSK modulation + // and incoherent demodulation. + + // As the input Es/No is generally unknown (as it cannot be exstimated accurately + // when the codeword length is few tens symbols) but an exact metric requires it + // we simply fix it to a predefined EsNoMetric value so that the metric is what + // expected at that specific value. + // The metric computed in this way is optimal only at this predefined Es/No value, + // nevertheless it is usually better than a generic parameter-free metric which + // makes no assumptions on the input Es/No. + + // returns the estimated noise standard deviation + + int k; + float rsum = 0.f; + float sigmaest, cmetric; + + const int M = 1<M; + const int qra_m = pcode->m; + const int qra_V = pcode->V; + const int qra_MAXVDEG = pcode->MAXVDEG; + const int *qra_vdeg = pcode->vdeg; + const int qra_C = pcode->C; + const int qra_MAXCDEG = pcode->MAXCDEG; + const int *qra_cdeg = pcode->cdeg; + const int *qra_v2cmidx = pcode->v2cmidx; + const int *qra_c2vmidx = pcode->c2vmidx; + const int *qra_pmat = pcode->gfpmat; + const int *qra_msgw = pcode->msgw; + +// float msgout[qra_M]; // buffer to store temporary results + float msgout[QRACODE_MAX_M]; // we use a fixed size in order to avoid mallocs + + float totex; // total extrinsic information + int nit; // current iteration + int nv; // current variable + int nc; // current check + int k,kk; // loop indexes + + int ndeg; // current node degree + int msgbase; // current offset in the table of msg indexes + int imsg; // current message index + int wmsg; // current message weight + + int rc = -1; // rc>=0 extrinsic converged to 1 at iteration rc (rc=0..maxiter-1) + // rc=-1 no convergence in the given number of iterations + // rc=-2 error in the code tables (code checks degrees must be >1) + // rc=-3 M is larger than QRACODE_MAX_M + + + + if (qra_M>QRACODE_MAX_M) + return -3; + + // message initialization ------------------------------------------------------- + + // init c->v variable intrinsic msgs + pd_init(C2VMSG(0),pix,qra_M*qra_V); + + // init the v->c messages directed to code factors (k=1..ndeg) with the intrinsic info + for (nv=0;nvc + for (k=1;kv step ----------------------------------------------------- + // Computes messages from code checks to code variables. + // As the first qra_V checks are associated with intrinsic information + // (the code tables have been constructed in this way) + // we need to do this step only for code checks in the range [qra_V..qra_C) + + // The convolutions of probability distributions over the alphabet of a finite field GF(qra_M) + // are performed with a fast convolution algorithm over the given field. + // + // I.e. given the code check x1+x2+x3 = 0 (with x1,x2,x3 in GF(2^m)) + // and given Prob(x2) and Prob(x3), we have that: + // Prob(x1=X1) = Prob((x2+x3)=X1) = sum((Prob(x2=X2)*Prob(x3=(X1+X2))) for all the X2s in the field + // This translates to Prob(x1) = IWHT(WHT(Prob(x2))*WHT(Prob(x3))) + // where WHT and IWHT are the direct and inverse Walsh-Hadamard transforms of the argument. + // Note that the WHT and the IWHF differs only by a multiplicative coefficent and since in this step + // we don't need that the output distribution is normalized we use the relationship + // Prob(x1) =(proportional to) WH(WH(Prob(x2))*WH(Prob(x3))) + + // In general given the check code x1+x2+x3+..+xm = 0 + // the output distribution of a variable given the distributions of the other m-1 variables + // is the inverse WHT of the product of the WHTs of the distribution of the other m-1 variables + // The complexity of this algorithm scales with M*log2(M) instead of the M^2 complexity of + // the brute force approach (M=size of the alphabet) + + for (nc=qra_V;nc1) + return -2; // bad code tables + + msgbase = nc*qra_MAXCDEG; // base to msg index row for the current node + + // transforms inputs in the Walsh-Hadamard "frequency" domain + // v->c -> fwht(v->c) + for (k=0;kv = prod(fwht(v->c)) + // TODO: we assume that checks degrees are not larger than three but + // if they are larger the products can be computed more efficiently + for (kk=0;kkc steps when multipling + // small fp numbers + msgout[0]+=1E-7f; // TODO: define the bias accordingly to the field size + + np_fwht(qra_m,msgout,msgout); + + // inverse weight and output + imsg = qra_c2vmidx[msgbase+k]; // current output msg index + wmsg = qra_msgw[imsg]; // current msg weight + + if (wmsg==0) + pd_init(C2VMSG(imsg),msgout,qra_M); + else + // output p(alfa^(-w)*x) + pd_bwdperm(C2VMSG(imsg),msgout, MSGPERM(wmsg), qra_M); + + } // for (k=0;kc step ----------------------------------------------------- + for (nv=0;nvc msg = prod(c->v) + // TODO: factor factors to reduce the number of computations for high degree nodes + for (kk=0;kkc are null + // normalize output to a probability distribution + if (pd_norm(msgout,qra_m)<=0) { + // dump msgin; + printf("warning: v->c pd with invalid norm. nit=%d nv=%d k=%d\n",nit,nv,k); + for (kk=0;kk(1.*(qra_V)-0.01)) { + // the total maximum extrinsic information of each symbol in the codeword + // is very close to one. This means that we have reached the (1,1) point in the + // code EXIT chart(s) and we have successfully decoded the input. + rc = nit; + break; // remove the break to evaluate the decoder speed performance as a function of the max iterations number) + } + + } // for (nit=0;nitM; + const int qra_m = pcode->m; + const int qra_K = pcode->K; + + int k; + + for (k=0;k. + +#ifndef _qracodes_h_ +#define _qracodes_h_ + +// type of codes +#define QRATYPE_NORMAL 0x00 // normal code +#define QRATYPE_CRC 0x01 // code with crc - last information symbol is a CRC +#define QRATYPE_CRCPUNCTURED 0x02 // the CRC symbol is punctured (not sent along the channel) + + +typedef struct { + // code parameters + const int K; // number of information symbols + const int N; // codeword length in symbols + const int m; // bits/symbol + const int M; // Symbol alphabet cardinality (2^m) + const int a; // code grouping factor + const int NC; // number of check symbols (N-K) + const int V; // number of variables in the code graph (N) + const int C; // number of factors in the code graph (N +(N-K)+1) + const int NMSG; // number of msgs in the code graph + const int MAXVDEG; // maximum variable degree + const int MAXCDEG; // maximum factor degree + const int type; // see QRATYPE_xx defines + const float R; // code rate (K/N) + const char name[64]; // code name + // tables used by the encoder + const int *acc_input_idx; + const int *acc_input_wlog; + const int *gflog; + const int *gfexp; + // tables used by the decoder ------------------------- + const int *msgw; + const int *vdeg; + const int *cdeg; + const int *v2cmidx; + const int *c2vmidx; + const int *gfpmat; +} qracode; +// Uncomment the header file of the code which needs to be tested + +//#include "qra12_63_64_irr_b.h" // irregular code (12,63) over GF(64) +//#include "qra13_64_64_irr_e.h" // irregular code with good performance and best UER protection at AP56 +//#include "qra13_64_64_reg_a.h" // regular code with good UER but perf. inferior to that of code qra12_63_64_irr_b + +#ifdef __cplusplus +extern "C" { +#endif + +int qra_encode(const qracode *pcode, int *y, const int *x); +float qra_mfskbesselmetric(float *pix, const float *rsq, const int m, const int N, float EsNoMetric); +int qra_extrinsic(const qracode *pcode, float *pex, const float *pix, int maxiter,float *qra_v2cmsg,float *qra_c2vmsg); +void qra_mapdecode(const qracode *pcode, int *xdec, float *pex, const float *pix); + +#ifdef __cplusplus +} +#endif + +#endif // _qracodes_h_ From 3c5b346fe50f04fae626dd2b14affb7135e7c12c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 8 Nov 2020 10:08:16 -0500 Subject: [PATCH 3/4] Commit a Makefile that builds libm65.a m65 mapsim libastro.a on Linux. Build MAP65 from QtCreator. --- libm65/Makefile | 185 ++++++++++++++++++++------------- libm65/Makefile.jtsdk | 232 +++++++++++++++++++++++------------------- 2 files changed, 240 insertions(+), 177 deletions(-) diff --git a/libm65/Makefile b/libm65/Makefile index ba2e88aa8..7ff2357ff 100644 --- a/libm65/Makefile +++ b/libm65/Makefile @@ -1,71 +1,114 @@ -CC = gcc -CXX = g++ -FC = gfortran - -FFLAGS = -O2 -fbounds-check -Wall -Wno-conversion -CFLAGS = -O2 -I. - -# Default rules -%.o: %.c - ${CC} ${CFLAGS} -c $< -%.o: %.f - ${FC} ${FFLAGS} -c $< -%.o: %.F - ${FC} ${FFLAGS} -c $< -%.o: %.f90 - ${FC} ${FFLAGS} -c $< -%.o: %.F90 - ${FC} ${FFLAGS} -c $< - -#all: qratest.exe tplt.exe -all: qra64d.exe - -OBJS1 = qratest.o qra64a.o sync64.o four2a.o smo.o smo121.o averms.o \ - packjt.o twkfreq.o spec64.o fmtmsg.o pctile.o \ - grid2deg.o deg2grid.o shell.o badmsg.o qra64_subs.o \ - qracodes.o npfwht.o pdmath.o qra12_63_64_irr_b.o \ - qra13_64_64_irr_e.o qra64.o \ - lorentzian.o fchisq0.o peakup.o - -qra64_subs.o: ../../wsjtx/lib/qra/qra64/qra64_subs.c - gcc -c -O2 -o qra64_subs.o ../../wsjtx/lib/qra/qra64/qra64_subs.c - -qracodes.o: ../../wsjtx/lib/qra/qracodes/qracodes.c - gcc -c -O2 -o qracodes.o ../../wsjtx/lib/qra/qracodes/qracodes.c - -qra64.o: ../../wsjtx/lib/qra/qra64/qra64.c - gcc -c -O2 -o qra64.o ../../wsjtx/lib/qra/qra64/qra64.c - -npfwht.o: ../../wsjtx/lib/qra/qracodes/npfwht.c - gcc -c -O2 -o npfwht.o ../../wsjtx/lib/qra/qracodes/npfwht.c - -pdmath.o: ../../wsjtx/lib/qra/qracodes/pdmath.c - gcc -c -O2 -o pdmath.o ../../wsjtx/lib/qra/qracodes/pdmath.c - -qra12_63_64_irr_b.o: ../../wsjtx/lib/qra/qracodes/qra12_63_64_irr_b.c - gcc -c -O2 -o qra12_63_64_irr_b.o ../../wsjtx/lib/qra/qracodes/qra12_63_64_irr_b.c - -qra13_64_64_irr_e.o: ../../wsjtx/lib/qra/qracodes/qra13_64_64_irr_e.c - gcc -c -O2 -o qra13_64_64_irr_e.o ../../wsjtx/lib/qra/qracodes/qra13_64_64_irr_e.c - -qratest.exe: $(OBJS1) - $(FC) -o qratest.exe $(OBJS1) C:\JTSDK\fftw3f\libfftw3f-3.dll - -OBJS2 = tplt.o zplt64.o image.o -tplt.exe: $(OBJS2) - $(FC) -o tplt.exe $(OBJS2) - -OBJS3 = qra64d.o qra64c.o qra64zap.o sync64.o four2a.o smo.o averms.o \ - timer.o packjt.o twkfreq.o spec64.o fmtmsg.o pctile.o dpol.o \ - grid2deg.o deg2grid.o shell.o badmsg.o moondop.o moon2.o \ - geocentric.o toxyz.o dot.o dcoord.o \ - qra64_subs.o qracodes.o npfwht.o pdmath.o qra12_63_64_irr_b.o \ - qra13_64_64_irr_e.o qra64.o lorentzian.o fchisq0.o - -qra64d.exe: $(OBJS3) - $(FC) -o qra64d.exe $(OBJS3) C:\JTSDK\fftw3f\libfftw3f-3.dll - -.PHONY : clean - -clean: - $(RM) *.o qratest.exe tplt.exe +# Makefile for Linux +CC = gcc +FC = gfortran +CXX = g++ + +FFLAGS = -O2 -fbounds-check -Wall -Wno-precision-loss -fno-second-underscore +# For ptt_unix: +CFLAGS = -I. -fbounds-check -DHAVE_STDLIB_H=1 -DHAVE_STDIO_H=1 \ + -DHAVE_FCNTL_H=1 -DHAVE_SYS_IOCTL_H=1 + +# Default rules +%.o: %.c + ${CC} ${CFLAGS} -c $< +%.o: %.f + ${FC} ${FFLAGS} -c $< +%.o: %.F + ${FC} ${FFLAGS} -c $< +%.o: %.f90 + ${FC} ${FFLAGS} -c $< +%.o: %.F90 + ${FC} ${FFLAGS} -c $< + +all: packjt.o libm65.a m65 mapsim libastro.a + +OBJS1 = trimlist.o display.o getdphi.o pctile.o ccf65.o \ + decode1a.o sort.o filbig.o fil6521.o afc65b.o \ + twkfreq.o decode65b.o indexx.o ssort.o fchisq.o setup65.o \ + extract.o deep65.o ccf2.o demod64a.o chkhist.o graycode.o \ + interleave63.o encode65.o igray.o set.o shell.o qra64_subs.o \ + grid2k.o getpfx2.o qra64b.o qra64c.o twkfreq_xy.o qra64zap.o \ + deg2grid.o getpfx1.o k2grid.o ftrsd2.o graycode65.o \ + wrapkarn.o nchar.o init_rs.o encode_rs.o decode_rs.o \ + four2a.o rfile3a.o grid2deg.o pfxdump.o dpol.o sync64.o spec64.o \ + astro.o tm2.o sun.o moondop.o coord.o tmoonsub.o \ + geocentric.o moon2.o toxyz.o dot.o dcoord.o f77_wisdom.o \ + gen65.o chkmsg.o astrosub.o astro0.o recvpkt.o symspec.o \ + iqcal.o iqfix.o timf2.o s3avg.o packjt.o badmsg.o fmtmsg.o \ + qracodes.o qra64.o smo.o averms.o lorentzian.o npfwht.o pdmath.o \ + qra13_64_64_irr_e.o fchisq0.o genqra64a.o ptt_unix.o + +packjt.o: packjt.f90 + $(FC) -c packjt.f90 + +libm65.a: $(OBJS1) + ar cr libm65.a $(OBJS1) + ranlib libm65.a + +qra64_subs.o: ./qra64/qra64_subs.c + gcc -c -O2 -o qra64_subs.o ./qra64/qra64_subs.c + +qracodes.o: ./qracodes/qracodes.c + gcc -c -O2 -o qracodes.o ./qracodes/qracodes.c + +qra64.o: ./qra64/qra64.c + gcc -c -O2 -o qra64.o ./qra64/qra64.c + +qra13_64_64_irr_e.o: ./qracodes/qra13_64_64_irr_e.c + gcc -c -O2 -o qra13_64_64_irr_e.o ./qracodes/qra13_64_64_irr_e.c + +npfwht.o: ./qracodes/npfwht.c + gcc -c -O2 -o npfwht.o ./qracodes/npfwht.c + +pdmath.o: ./qracodes/pdmath.c + gcc -c -O2 -o pdmath.o ./qracodes/pdmath.c + +OBJS3 = m65.o m65a.o map65a.o symspec.o decode0.o ftninit.o ftnquit.o \ + timer.o ipcomm.o sec_midn.o usleep.o + +m65: $(OBJS3) libm65.a + $(CXX) -o m65 $(OBJS3) libm65.a -lfftw3f -lQt5Core -lfftw3f -lgfortran + cp m65 ../../map65_install + +OBJS7 = astrosub.o astro0.o astro.o tm2.o grid2deg.o sun.o moondop.o \ + coord.o dot.o moon2.o tmoonsub.o toxyz.o geocentric.o \ + dcoord.o + +libastro.a: $(OBJS7) + ar cr libastro.a $(OBJS7) + ranlib libastro.a + +OBJS6 = mapsim.o cgen65.o noisegen.o gran.o +mapsim: $(OBJS6) libm65.a + $(FC) -o mapsim $(OBJS6) libm65.a + +INCPATH = -I. -I'/usr/include/x86_64-linux-gnu/qt5' \ + -I'/usr/include/x86_64-linux-gnu/qt5/QtCore' + +ipcomm.o: ipcomm.cpp + $(CXX) -c $(INCPATH) -fPIC ipcomm.cpp + +sec_midn.o: sec_midn.f90 + $(FC) -c -fno-second-underscore sec_midn.f90 + +OBJS4 = tastro.o astro0.o libm65.a +tastro: $(OBJS4) + $(FC) $(FFLAGS) -o tastro $(OBJS4) libm65.a + +OBJS5 = t1.o timer.o libm65.a +t1: $(OBJS5) + $(FC) $(FFLAGS) -o t1 $(OBJS5) libm65.a + +init_rs.o: init_rs.c + $(CC) -c -DBIGSYM=1 -o init_rs.o init_rs.c + +encode_rs.o: encode_rs.c + $(CC) -c -DBIGSYM=1 -o encode_rs.o encode_rs.c + +decode_rs.o: decode_rs.c + $(CC) -c -DBIGSYM=1 -o decode_rs.o decode_rs.c + +.PHONY : clean + +clean: + rm -f *.o *.mod libm65.a m65 diff --git a/libm65/Makefile.jtsdk b/libm65/Makefile.jtsdk index 74f527ec1..5e4efb353 100644 --- a/libm65/Makefile.jtsdk +++ b/libm65/Makefile.jtsdk @@ -1,106 +1,126 @@ -# Makefile for MinGW on Windows -CC = c:/JTSDK-QT/Qt5/Tools/mingw48_32/bin/gcc -FC = c:/JTSDK-QT/Qt5/Tools/mingw48_32/bin/gfortran -CXX = c:/JTSDK-QT/Qt5/Tools/mingw48_32/bin/g++ - -FFLAGS = -O2 -fbounds-check -Wall -Wno-precision-loss -fno-second-underscore -CFLAGS = -I. -fbounds-check - -# Default rules -%.o: %.c - ${CC} ${CFLAGS} -c $< -%.o: %.f - ${FC} ${FFLAGS} -c $< -%.o: %.F - ${FC} ${FFLAGS} -c $< -%.o: %.f90 - ${FC} ${FFLAGS} -c $< -%.o: %.F90 - ${FC} ${FFLAGS} -c $< - -all: libm65.a m65.exe JT65code.exe mapsim.exe libastro.a - -OBJS1 = trimlist.o display.o getdphi.o pctile.o ccf65.o \ - decode1a.o sort.o filbig.o fil6521.o afc65b.o \ - twkfreq.o decode65b.o indexx.o ssort.o fchisq.o setup65.o \ - extract.o deep65.o ccf2.o demod64a.o chkhist.o graycode.o \ - interleave63.o unpackmsg.o encode65.o igray.o set.o unpackcall.o \ - unpackgrid.o grid2k.o unpacktext.o getpfx2.o packmsg.o \ - deg2grid.o packtext.o getpfx1.o packcall.o k2grid.o packgrid.o \ - wrapkarn.o nchar.o init_rs.o encode_rs.o decode_rs.o \ - four2a.o rfile3a.o grid2deg.o pfxdump.o dpol.o \ - astro.o tm2.o sun.o moondop.o coord.o tmoonsub.o \ - geocentric.o moon2.o toxyz.o dot.o dcoord.o f77_wisdom.o \ - gen65.o chkmsg.o ptt.o astrosub.o astro0.o recvpkt.o symspec.o \ - iqcal.o iqfix.o timf2.o s3avg.o - -libm65.a: $(OBJS1) - ar cr libm65.a $(OBJS1) - ranlib libm65.a - -OBJS3 = m65.o m65a.o map65a.o symspec.o decode0.o ftninit.o ftnquit.o \ - timer.o ipcomm.o sec_midn.o usleep.o -# cutil.o - -LIBS3 = -L'C:/JTSDK-QT/Qt5/5.2.1/mingw48_32/lib' -lQt5Core - -m65.exe: $(OBJS3) libm65.a - $(CXX) -o m65.exe $(OBJS3) $(LIBS3) libm65.a ../libfftw3f_win.a \ - -lgfortran - cp m65.exe ../../map65_install - -OBJS2 = JT65code.o -JT65code.exe: $(OBJS2) libm65.a - $(FC) -o JT65code.exe $(OBJS2) libm65.a - -OBJS7 = astrosub.o astro0.o astro.o tm2.o grid2deg.o sun.o moondop.o \ - coord.o dot.o moon2.o tmoonsub.o toxyz.o geocentric.o \ - dcoord.o - -libastro.a: $(OBJS7) - ar cr libastro.a $(OBJS7) - ranlib libastro.a - -OBJS6 = mapsim.o cgen65.o noisegen.o gran.o -mapsim.exe: $(OBJS6) libm65.a - $(FC) -o mapsim.exe $(OBJS6) libm65.a - -INCPATH = -I'C:/JTSDK-QT/Qt5/5.2.1/mingw48_32/include/QtCore' \ - -I'C:/JTSDK-QT/Qt5/5.2.1/mingw48_32/include' - -ipcomm.o: ipcomm.cpp - $(CXX) -c $(INCPATH) ipcomm.cpp - -#m65a.o: m65a.f90 -# $(FC) -c -fno-second-underscore -cpp m65a.f90 - -sec_midn.o: sec_midn.f90 - $(FC) -c -fno-second-underscore sec_midn.f90 - -#symspec.o: ../symspec.f90 -# $(FC) -c $(FFLAGS) -o symspec.o ../symspec.f90 - -OBJS4 = tastro.o astro0.o libm65.a -tastro.exe: $(OBJS4) - $(FC) $(FFLAGS) -o tastro.exe $(OBJS4) libm65.a - -OBJS5 = t1.o timer.o libm65.a -t1.exe: $(OBJS5) - $(FC) $(FFLAGS) -o t1.exe $(OBJS5) libm65.a - -#astro0.o: ../astro0.f90 -# $(FC) -c $(FFLAGS) -o astro0.o ../astro0.f90 - -init_rs.o: init_rs.c - $(CC) -c -DBIGSYM=1 -o init_rs.o init_rs.c - -encode_rs.o: encode_rs.c - $(CC) -c -DBIGSYM=1 -o encode_rs.o encode_rs.c - -decode_rs.o: decode_rs.c - $(CC) -c -DBIGSYM=1 -o decode_rs.o decode_rs.c - -.PHONY : clean - -clean: - rm -f *.o libm65.a m65.exe jt65code.exe +# Makefile for MinGW on Windows +CC = c:/JTSDK/Qt55/Tools/mingw492_32/bin/gcc +FC = c:/JTSDK/Qt55/Tools/mingw492_32/bin/gfortran +CXX = c:/JTSDK/Qt55/Tools/mingw492_32/bin/g++ + +FFLAGS = -O2 -fbounds-check -Wall -Wno-precision-loss -fno-second-underscore +CFLAGS = -I. -fbounds-check + +# Default rules +%.o: %.c + ${CC} ${CFLAGS} -c $< +%.o: %.f + ${FC} ${FFLAGS} -c $< +%.o: %.F + ${FC} ${FFLAGS} -c $< +%.o: %.f90 + ${FC} ${FFLAGS} -c $< +%.o: %.F90 + ${FC} ${FFLAGS} -c $< + +all: packjt.o libm65.a m65.exe mapsim.exe libastro.a + +OBJS1 = trimlist.o display.o getdphi.o pctile.o ccf65.o \ + decode1a.o sort.o filbig.o fil6521.o afc65b.o \ + twkfreq.o decode65b.o indexx.o ssort.o fchisq.o setup65.o \ + extract.o deep65.o ccf2.o demod64a.o chkhist.o graycode.o \ + interleave63.o encode65.o igray.o set.o shell.o qra64_subs.o \ + grid2k.o getpfx2.o qra64b.o qra64c.o twkfreq_xy.o qra64zap.o \ + deg2grid.o getpfx1.o k2grid.o ftrsd2.o graycode65.o \ + wrapkarn.o nchar.o init_rs.o encode_rs.o decode_rs.o \ + four2a.o rfile3a.o grid2deg.o pfxdump.o dpol.o sync64.o spec64.o \ + astro.o tm2.o sun.o moondop.o coord.o tmoonsub.o \ + geocentric.o moon2.o toxyz.o dot.o dcoord.o f77_wisdom.o \ + gen65.o chkmsg.o ptt.o astrosub.o astro0.o recvpkt.o symspec.o \ + iqcal.o iqfix.o timf2.o s3avg.o packjt.o badmsg.o fmtmsg.o \ + qracodes.o qra64.o smo.o averms.o lorentzian.o npfwht.o pdmath.o \ + qra13_64_64_irr_e.o fchisq0.o genqra64a.o + +packjt.o: packjt.f90 + $(FC) -c packjt.f90 + +libm65.a: $(OBJS1) + ar cr libm65.a $(OBJS1) + ranlib libm65.a + +qra64_subs.o: ./qra64/qra64_subs.c + gcc -c -O2 -o qra64_subs.o ./qra64/qra64_subs.c + +qracodes.o: ../../wsjtx/lib/qra/qracodes/qracodes.c + gcc -c -O2 -o qracodes.o ../../wsjtx/lib/qra/qracodes/qracodes.c + +qra64.o: ../../wsjtx/lib/qra/qra64/qra64.c + gcc -c -O2 -o qra64.o ../../wsjtx/lib/qra/qra64/qra64.c + +qra13_64_64_irr_e.o: ../../wsjtx/lib/qra/qracodes/qra13_64_64_irr_e.c + gcc -c -O2 -o qra13_64_64_irr_e.o \ + ../../wsjtx/lib/qra/qracodes/qra13_64_64_irr_e.c + +npfwht.o: ../../wsjtx/lib/qra/qracodes/npfwht.c + gcc -c -O2 -o npfwht.o ../../wsjtx/lib/qra/qracodes/npfwht.c + +pdmath.o: ../../wsjtx/lib/qra/qracodes/pdmath.c + gcc -c -O2 -o pdmath.o ../../wsjtx/lib/qra/qracodes/pdmath.c + +OBJS3 = m65.o m65a.o map65a.o symspec.o decode0.o ftninit.o ftnquit.o \ + timer.o ipcomm.o sec_midn.o usleep.o +# cutil.o + +LIBS3 = -L'C:/JTSDK/Qt55/5.5/mingw492_32/lib' -lQt5Core + +m65.exe: $(OBJS3) libm65.a + $(CXX) -o m65.exe $(OBJS3) $(LIBS3) libm65.a ../libfftw3f_win.a \ + -lgfortran + cp m65.exe ../../map65_install + +OBJS7 = astrosub.o astro0.o astro.o tm2.o grid2deg.o sun.o moondop.o \ + coord.o dot.o moon2.o tmoonsub.o toxyz.o geocentric.o \ + dcoord.o + +libastro.a: $(OBJS7) + ar cr libastro.a $(OBJS7) + ranlib libastro.a + +OBJS6 = mapsim.o cgen65.o noisegen.o gran.o +mapsim.exe: $(OBJS6) libm65.a + $(FC) -o mapsim.exe $(OBJS6) libm65.a + +INCPATH = -I'C:/JTSDK/Qt55/5.5/mingw492_32/include/QtCore' \ + -I'C:/JTSDK/Qt55/5.5/mingw492_32/include' + +ipcomm.o: ipcomm.cpp + $(CXX) -c $(INCPATH) ipcomm.cpp + +#m65a.o: m65a.f90 +# $(FC) -c -fno-second-underscore -cpp m65a.f90 + +sec_midn.o: sec_midn.f90 + $(FC) -c -fno-second-underscore sec_midn.f90 + +#symspec.o: ../symspec.f90 +# $(FC) -c $(FFLAGS) -o symspec.o ../symspec.f90 + +OBJS4 = tastro.o astro0.o libm65.a +tastro.exe: $(OBJS4) + $(FC) $(FFLAGS) -o tastro.exe $(OBJS4) libm65.a + +OBJS5 = t1.o timer.o libm65.a +t1.exe: $(OBJS5) + $(FC) $(FFLAGS) -o t1.exe $(OBJS5) libm65.a + +#astro0.o: ../astro0.f90 +# $(FC) -c $(FFLAGS) -o astro0.o ../astro0.f90 + +init_rs.o: init_rs.c + $(CC) -c -DBIGSYM=1 -o init_rs.o init_rs.c + +encode_rs.o: encode_rs.c + $(CC) -c -DBIGSYM=1 -o encode_rs.o encode_rs.c + +decode_rs.o: decode_rs.c + $(CC) -c -DBIGSYM=1 -o decode_rs.o decode_rs.c + +.PHONY : clean + +clean: + rm -f *.o *.mod libm65.a m65.exe From 091f7f52c21acf25f38f50fc578c21f17b713a38 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 8 Nov 2020 10:14:42 -0500 Subject: [PATCH 4/4] Fix the program title line by removing SVN information. --- mainwindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mainwindow.cpp b/mainwindow.cpp index 1c04014a7..627834186 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -33,8 +33,7 @@ TxTune* g_pTxTune = NULL; QSharedMemory mem_m65("mem_m65"); QString rev="$Rev$"; //Must update by hand ???? -QString Program_Title_Version=" MAP65 v2.7, r" + rev.mid(6,4) + - " by K1JT"; +QString Program_Title_Version=" MAP65 v2.7 by K1JT"; extern const int RxDataFrequency = 96000; extern const int TxDataFrequency = 11025;