// main.c // QRA65 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 // qra65.c/.h - qra65 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 " " // ../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 QRA65 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 "qra65.h" #include "../qracodes/normrnd.h" // gaussian numbers generator // ----------------------------------------------------------------------------------- // channel types #define CHANNEL_AWGN 0 #define CHANNEL_RAYLEIGH 1 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]); // K1JT replies to IV3NWV (with no grid) printf("K1JT tx: IV3NWV K1JT\n"); encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT, GRID_BLANK); qra65_encode(codec_k1jt, y, x); rx = mfskchannel(y,channel_type,EbNodB); // IV3NWV attempts to decode rc = qra65_decode(codec_iv3nwv, xdec,rx); if (rc>=0) { // decoded printf("IV3NWV rx: received with apcode=%d %s\n",rc, decode_type[rc]); // IV3NWV replies to K1JT with a 73 printf("IV3NWV tx: K1JT IV3NWV 73\n"); encodemsg_jt65(x,CALL_K1JT,CALL_IV3NWV, GRID_73); qra65_encode(codec_iv3nwv, y, x); rx = mfskchannel(y,channel_type,EbNodB); // K1JT attempts to decode rc = qra65_decode(codec_k1jt, xdec,rx); if (rc>=0) { // decoded printf("K1JT rx: received with apcode=%d %s\n",rc, decode_type[rc]); // K1JT replies to IV3NWV with a 73 printf("K1JT tx: IV3NWV K1JT 73\n"); encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT, GRID_73); qra65_encode(codec_k1jt, y, x); rx = mfskchannel(y,channel_type,EbNodB); // IV3NWV attempts to decode rc = qra65_decode(codec_iv3nwv, xdec,rx); if (rc>=0) { // decoded printf("IV3NWV rx: received with apcode=%d %s\n",rc, decode_type[rc]); return 0; } } } } printf("the other party did not 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 qra65_decode function // indicates the amount of a-priori information required to decode the received message // accordingly to this table: // rc=0 [? ? ?] AP0 // rc=1 [CQ ? ?] AP27 // rc=2 [CQ ? ] AP44 // rc=3 [CALL ? ?] AP29 // rc=4 [CALL ? ] AP45 // rc=5 [CALL CALL ?] AP57 // 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[QRA65_K], xdec[QRA65_K]; int y[QRA65_N]; float *rx; int rc,k; int ndecok[6] = { 0, 0, 0, 0, 0, 0}; int ntx = 100,ndec=0; qra65codec *codec_iv3nwv = qra65_init(mode,CALL_IV3NWV); // codec for IV3NWV qra65codec *codec_k1jt = qra65_init(mode,CALL_K1JT); // codec for K1JT // this will enable k1jt's decoder to look for iv3nwv calls encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT,GRID_BLANK); qra65_encode(codec_k1jt, y, x); printf("K1JT tx: IV3NWV K1JT\n"); // iv3nwv reply to k1jt printf("IV3NWV tx: K1JT IV3NWV JN66\n"); encodemsg_jt65(x,CALL_K1JT,CALL_IV3NWV,GRID_JN66); qra65_encode(codec_iv3nwv, y, x); printf("Simulating decodes by K1JT up to AP56 ..."); for (k=0;k=0) ndecok[rc]++; } printf("\n"); printf("Transimtted:%d - Decoded:\n",ntx); for (k=0;k<6;k++) { printf("%3d with %s\n",ndecok[k],decode_type[k]); ndec += ndecok[k]; } printf("Total: %d/%d\n",ndec,ntx); printf("\n"); return 0; } void syntax(void) { printf("\nQRA65 Mode Tests\n"); printf("2016, Nico Palermo - IV3NWV\n\n"); printf("---------------------------\n\n"); printf("Syntax: qra65 [-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=NO_AP 1=AUTO_AP (default)\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 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>1) { printf("Invalid decoding mode\n"); syntax(); return -1; } } else if (strncmp(*argv,"-s",2)==0) { SNRdB = (float)atof((*argv)+2); if (SNRdB>0 || SNRdB<-40) { printf("SNR should be in the range [-40..0]\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+29.1f; #if defined(__linux__) || defined(__unix__) srand48(GetTickCount()); #endif if (testtype==0) { for (k=0;k