/* main.c QRA64 mode encode/decode test (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 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=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 = 100,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_K1JT,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: [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; } 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\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(" -h: this help\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; // Parse the command line while(--argc) { argv++; if (strncmp(*argv,"-h",2)==0) { syntax(); return 0; } else { if (strncmp(*argv,"-a",2)==0) { mode = ( int)atoi((*argv)+2); if (mode>2) { printf("Invalid decoding mode\n"); syntax(); return -1; } } else { if (strncmp(*argv,"-s",2)==0) { SNRdB = (float)atof((*argv)+2); if (SNRdB>20 || SNRdB<-40) { printf("SNR should be in the range [-40..20]\n"); syntax(); return -1; } } else { if (strncmp(*argv,"-t",2)==0) { testtype = ( int)atoi((*argv)+2); if (testtype>1) { printf("Invalid test type\n"); syntax(); return -1; } } else { if (strncmp(*argv,"-c",2)==0) { channel = ( int)atoi((*argv)+2); if (channel>CHANNEL_RAYLEIGH) { printf("Invalid channel type\n"); syntax(); return -1; } } else { printf("Invalid option\n"); syntax(); return -1; } } } } } } EbNodB = SNRdB+QRA64_SNR_EBNO_OFFSET; #if defined(__linux__) || defined(__unix__) srand48(GetTickCount()); #endif if (testtype==0) { for (k=0;k