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