mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-29 07:39:43 -05:00
Some cleanup and reformatting of QRA65 code (with apologies to Nico).
I've tried to make code "pretty print" and easier to follow, at least for me. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@6808 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
db820683ff
commit
dd2e5fbdda
@ -1,58 +1,62 @@
|
|||||||
// main.c
|
/*
|
||||||
// QRA65 mode encode/decode test
|
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
|
(c) 2016 - Nico Palermo, IV3NWV
|
||||||
// along with qracodes source distribution.
|
|
||||||
// If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
Thanks to Andrea Montefusco IW0HDV for his help on adapting the sources
|
||||||
|
to OSs other than MS Windows
|
||||||
|
|
||||||
// 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 file is part of the qracodes project, a Forward Error Control
|
||||||
// This code has been designed to include a CRC as the 13th information symbol
|
encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes.
|
||||||
// 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.
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------
|
Files in this package:
|
||||||
|
main.c - this file
|
||||||
|
qra65.c/.h - qra65 mode encode/decoding functions
|
||||||
|
|
||||||
// OS dependent defines and includes --------------------------------------------
|
../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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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!
|
#if _WIN32 // note the underscore: without it, it's not msdn official!
|
||||||
// Windows (x64 and x86)
|
// Windows (x64 and x86)
|
||||||
#include <windows.h> // required only for GetTickCount(...)
|
#include <windows.h> // required only for GetTickCount(...)
|
||||||
#include <process.h> // _beginthread
|
#include <process.h> // _beginthread
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if __linux__
|
#if __linux__
|
||||||
@ -79,7 +83,7 @@ unsigned GetTickCount(void) {
|
|||||||
#include "qra65.h"
|
#include "qra65.h"
|
||||||
#include "../qracodes/normrnd.h" // gaussian numbers generator
|
#include "../qracodes/normrnd.h" // gaussian numbers generator
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
// channel types
|
// channel types
|
||||||
#define CHANNEL_AWGN 0
|
#define CHANNEL_AWGN 0
|
||||||
@ -87,19 +91,19 @@ unsigned GetTickCount(void) {
|
|||||||
|
|
||||||
void printwordd(char *msg, int *x, int size)
|
void printwordd(char *msg, int *x, int size)
|
||||||
{
|
{
|
||||||
int k;
|
int k;
|
||||||
printf("\n%s ",msg);
|
printf("\n%s ",msg);
|
||||||
for (k=0;k<size;k++)
|
for (k=0;k<size;k++)
|
||||||
printf("%2d ",x[k]);
|
printf("%2d ",x[k]);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
void printwordh(char *msg, int *x, int size)
|
void printwordh(char *msg, int *x, int size)
|
||||||
{
|
{
|
||||||
int k;
|
int k;
|
||||||
printf("\n%s ",msg);
|
printf("\n%s ",msg);
|
||||||
for (k=0;k<size;k++)
|
for (k=0;k<size;k++)
|
||||||
printf("%02hx ",x[k]);
|
printf("%02hx ",x[k]);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#define NSAMPLES (QRA65_N*QRA65_M)
|
#define NSAMPLES (QRA65_N*QRA65_M)
|
||||||
@ -112,51 +116,53 @@ static float r[NSAMPLES];
|
|||||||
|
|
||||||
float *mfskchannel(int *x, int channel_type, float EbNodB)
|
float *mfskchannel(int *x, int channel_type, float EbNodB)
|
||||||
{
|
{
|
||||||
// simulate a MFSK channel (AWGN or Rayleigh)
|
/*
|
||||||
// x is a pointer to the transmitted codeword (an array of QRA65_N integers in the range 0..63)
|
Simulate an MFSK channel, either AWGN or Rayleigh.
|
||||||
//
|
|
||||||
// the function returns the received symbol energies (squared amplitudes)
|
|
||||||
// as an array of (QRA65_M*QRA65_N) float numbers
|
|
||||||
// the first QRA65_M entries of this array are the energies of the first symbol in the codeword
|
|
||||||
// the second QRA65_M entries are those of the second symbol
|
|
||||||
// and so on up to the last codeword symbol
|
|
||||||
|
|
||||||
const float No = 1.0f; // noise spectral density
|
x is a pointer to the transmitted codeword, an array of QRA65_N
|
||||||
const float sigma = (float)sqrt(No/2.0f); // std dev of noise I/Q components
|
integers in the range 0..63.
|
||||||
const float sigmach = (float)sqrt(1/2.0f); // std dev of channel I/Q gains
|
|
||||||
const float R = 1.0f*QRA65_K/QRA65_N;
|
|
||||||
|
|
||||||
float EbNo = (float)pow(10,EbNodB/10);
|
Returns the received symbol energies (squared amplitudes) as an array of
|
||||||
float EsNo = 1.0f*QRA65_m*R*EbNo;
|
(QRA65_M*QRA65_N) floats. The first QRA65_M entries of this array are
|
||||||
float Es = EsNo*No;
|
the energies of the first symbol in the codeword. The second QRA65_M
|
||||||
float A = (float)sqrt(Es);
|
entries are those of the second symbol, and so on up to the last codeword
|
||||||
int k;
|
symbol.
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
const float R = 1.0f*QRA65_K/QRA65_N;
|
||||||
|
|
||||||
normrnd_s(rp,NSAMPLES,0,sigma);
|
float EbNo = (float)pow(10,EbNodB/10);
|
||||||
normrnd_s(rq,NSAMPLES,0,sigma);
|
float EsNo = 1.0f*QRA65_m*R*EbNo;
|
||||||
|
float Es = EsNo*No;
|
||||||
|
float A = (float)sqrt(Es);
|
||||||
|
int k;
|
||||||
|
|
||||||
if (channel_type == CHANNEL_AWGN)
|
normrnd_s(rp,NSAMPLES,0,sigma);
|
||||||
for (k=0;k<QRA65_N;k++)
|
normrnd_s(rq,NSAMPLES,0,sigma);
|
||||||
rp[k*QRA65_M+x[k]]+=A;
|
|
||||||
else
|
|
||||||
if (channel_type == CHANNEL_RAYLEIGH) {
|
|
||||||
normrnd_s(chp,QRA65_N,0,sigmach);
|
|
||||||
normrnd_s(chq,QRA65_N,0,sigmach);
|
|
||||||
for (k=0;k<QRA65_N;k++) {
|
|
||||||
rp[k*QRA65_M+x[k]]+=A*chp[k];
|
|
||||||
rq[k*QRA65_M+x[k]]+=A*chq[k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 0; // unknown channel type
|
|
||||||
}
|
|
||||||
|
|
||||||
// compute the squares of the amplitudes of the received samples
|
if (channel_type == CHANNEL_AWGN)
|
||||||
for (k=0;k<NSAMPLES;k++)
|
for (k=0;k<QRA65_N;k++)
|
||||||
r[k] = rp[k]*rp[k] + rq[k]*rq[k];
|
rp[k*QRA65_M+x[k]]+=A;
|
||||||
|
else
|
||||||
|
if (channel_type == CHANNEL_RAYLEIGH) {
|
||||||
|
normrnd_s(chp,QRA65_N,0,sigmach);
|
||||||
|
normrnd_s(chq,QRA65_N,0,sigmach);
|
||||||
|
for (k=0;k<QRA65_N;k++) {
|
||||||
|
rp[k*QRA65_M+x[k]]+=A*chp[k];
|
||||||
|
rq[k*QRA65_M+x[k]]+=A*chq[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0; // unknown channel type
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
// compute the squares of the amplitudes of the received samples
|
||||||
|
for (k=0;k<NSAMPLES;k++)
|
||||||
|
r[k] = rp[k]*rp[k] + rq[k]*rq[k];
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
// These defines are some packed fields as computed by JT65
|
// These defines are some packed fields as computed by JT65
|
||||||
@ -166,276 +172,287 @@ float *mfskchannel(int *x, int channel_type, float EbNodB)
|
|||||||
#define GRID_73 0x7ED0 // 73
|
#define GRID_73 0x7ED0 // 73
|
||||||
|
|
||||||
char decode_type[6][32] = {
|
char decode_type[6][32] = {
|
||||||
"[? ? ?] AP0",
|
"[? ? ?] AP0",
|
||||||
"[CQ ? ?] AP27",
|
"[CQ ? ?] AP27",
|
||||||
"[CQ ? ] AP44",
|
"[CQ ? ] AP42",
|
||||||
"[CALL ? ?] AP29",
|
"[CALL ? ?] AP29",
|
||||||
"[CALL ? ] AP45",
|
"[CALL ? ] AP44",
|
||||||
"[CALL CALL ?] AP57"
|
"[CALL CALL ?] AP57"
|
||||||
};
|
};
|
||||||
|
|
||||||
int test_proc_1(int channel_type, float EbNodB, int mode)
|
int test_proc_1(int channel_type, float EbNodB, int mode)
|
||||||
{
|
{
|
||||||
// Here we simulate the following (dummy) QSO:
|
/*
|
||||||
//
|
Here we simulate the following (dummy) QSO:
|
||||||
// 1) CQ IV3NWV
|
|
||||||
// 2) IV3NWV K1JT
|
|
||||||
// 3) K1JT IV3NWV 73
|
|
||||||
// 4) IV3NWV K1JT 73
|
|
||||||
//
|
|
||||||
// No message repetition is attempted
|
|
||||||
// The QSO is counted as successfull if IV3NWV received the last message
|
|
||||||
// When mode=QRA_AUTOAP each decoder attempts to decode the message sent
|
|
||||||
// by the other station using the a-priori information derived by what
|
|
||||||
// has been already decoded in a previous phase of the QSO if
|
|
||||||
// decoding with no a-priori information has not been successful.
|
|
||||||
// I.e. at step 1) K1JT's decoder first attempts to decode msgs of type [? ? ?] and if this
|
|
||||||
// attempt fails, it attempts to decode [CQ/QRZ ? ?] or [[CQ/QRZ ?] msgs
|
|
||||||
// At step 2) if IV3NWV's decoder is unable to decode K1JT's without AP it attempts to decode
|
|
||||||
// messages of the type [IV3NWV ? ?] and [IV3NWV ?].
|
|
||||||
// At step 3) K1JT's decoder attempts to decode [? ? ?] and [K1JT IV3NWV ?] (this last decode
|
|
||||||
// type has been enabled by K1JT's encoder at step 2)
|
|
||||||
// At step 4) IV3NWV's decoder attempts to decode [? ? ?] and [IV3NWV K1JT ?] (this last decode
|
|
||||||
// type has been enabled by IV3NWV's encoder at step 3)
|
|
||||||
|
|
||||||
// At each step the simulation reports if a decode was successful.
|
1) CQ IV3NWV
|
||||||
// In this case it also reports the type of decode (see table decode_type above)
|
2) IV3NWV K1JT
|
||||||
|
3) K1JT IV3NWV 73
|
||||||
|
4) IV3NWV K1JT 73
|
||||||
|
|
||||||
// When mode=QRA_NOAP, only [? ? ?] decodes are attempted and no a-priori information
|
No message repetition is attempted
|
||||||
// is used by the decoder
|
|
||||||
|
|
||||||
// The function returns 0 if all of the four messages have been decoded by their recipients
|
The QSO is counted as successfull if IV3NWV received the last message
|
||||||
// (with no retries) and -1 if any of them could not be decoded
|
When mode=QRA_AUTOAP each decoder attempts to decode the message sent
|
||||||
|
by the other station using the a-priori information derived by what
|
||||||
|
has been already decoded in a previous phase of the QSO if decoding
|
||||||
|
with no a-priori information has not been successful.
|
||||||
|
|
||||||
|
Step 1) K1JT's decoder first attempts to decode msgs of type [? ? ?]
|
||||||
|
and if this attempt fails, it attempts to decode [CQ/QRZ ? ?] or
|
||||||
|
[CQ/QRZ ?] msgs
|
||||||
|
|
||||||
int x[QRA65_K], xdec[QRA65_K];
|
Step 2) if IV3NWV's decoder is unable to decode K1JT's without AP it
|
||||||
int y[QRA65_N];
|
attempts to decode messages of the type [IV3NWV ? ?] and [IV3NWV ?].
|
||||||
float *rx;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
// each simulated station must use its own codec
|
Step 3) K1JT's decoder attempts to decode [? ? ?] and [K1JT IV3NWV ?]
|
||||||
// as it might work with different a-priori information
|
(this last decode type has been enabled by K1JT's encoder at step 2)
|
||||||
qra65codec *codec_iv3nwv = qra65_init(mode,CALL_IV3NWV); // codec for IV3NWV
|
|
||||||
qra65codec *codec_k1jt = qra65_init(mode,CALL_K1JT); // codec for K1JT
|
|
||||||
|
|
||||||
|
Step 4) IV3NWV's decoder attempts to decode [? ? ?] and [IV3NWV K1JT
|
||||||
|
?] (this last decode type has been enabled by IV3NWV's encoder at step
|
||||||
|
3)
|
||||||
|
|
||||||
// IV3NWV makes a CQ call (with no grid)
|
At each step the simulation reports if a decode was successful. In
|
||||||
printf("IV3NWV tx: CQ IV3NWV\n");
|
this case it also reports the type of decode (see table decode_type
|
||||||
encodemsg_jt65(x,CALL_CQ,CALL_IV3NWV,GRID_BLANK);
|
above)
|
||||||
qra65_encode(codec_iv3nwv, y, x);
|
|
||||||
|
When mode=QRA_NOAP, only [? ? ?] decodes are attempted and no a-priori
|
||||||
|
information is used by the decoder
|
||||||
|
|
||||||
|
The function returns 0 if all of the four messages have been decoded
|
||||||
|
by their recipients (with no retries) and -1 if any of them could not
|
||||||
|
be decoded
|
||||||
|
*/
|
||||||
|
|
||||||
|
int x[QRA65_K], xdec[QRA65_K];
|
||||||
|
int y[QRA65_N];
|
||||||
|
float *rx;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
// Each simulated station must use its own codec, since it might work with
|
||||||
|
// different a-priori information.
|
||||||
|
qra65codec *codec_iv3nwv = qra65_init(mode,CALL_IV3NWV); // codec for IV3NWV
|
||||||
|
qra65codec *codec_k1jt = qra65_init(mode,CALL_K1JT); // codec for K1JT
|
||||||
|
|
||||||
|
// Step 1a: IV3NWV makes a CQ call (with no grid)
|
||||||
|
printf("IV3NWV tx: CQ IV3NWV\n");
|
||||||
|
encodemsg_jt65(x,CALL_CQ,CALL_IV3NWV,GRID_BLANK);
|
||||||
|
qra65_encode(codec_iv3nwv, y, x);
|
||||||
|
rx = mfskchannel(y,channel_type,EbNodB);
|
||||||
|
|
||||||
|
// Step 1b: K1JT attempts to decode [? ? ?], [CQ/QRZ ? ?] or [CQ/QRZ ?]
|
||||||
|
rc = qra65_decode(codec_k1jt, xdec,rx);
|
||||||
|
if (rc>=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);
|
||||||
|
qra65_encode(codec_k1jt, y, x);
|
||||||
|
rx = mfskchannel(y,channel_type,EbNodB);
|
||||||
|
|
||||||
|
// Step 2b: IV3NWV attempts to decode [? ? ?], [IV3NWV ? ?] or [IV3NWV ?]
|
||||||
|
rc = qra65_decode(codec_iv3nwv, 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);
|
||||||
|
qra65_encode(codec_iv3nwv, y, x);
|
||||||
|
rx = mfskchannel(y,channel_type,EbNodB);
|
||||||
|
|
||||||
|
// Step 3b: K1JT attempts to decode [? ? ?] or [K1JT IV3NWV ?]
|
||||||
|
rc = qra65_decode(codec_k1jt, 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);
|
||||||
|
qra65_encode(codec_k1jt, y, x);
|
||||||
rx = mfskchannel(y,channel_type,EbNodB);
|
rx = mfskchannel(y,channel_type,EbNodB);
|
||||||
|
|
||||||
// K1JT attempts to decode
|
// Step 4b: IV3NWV attempts to decode [? ? ?], [IV3NWV ? ?], or [IV3NWV ?]
|
||||||
rc = qra65_decode(codec_k1jt, xdec,rx);
|
rc = qra65_decode(codec_iv3nwv, xdec,rx);
|
||||||
if (rc>=0) { // decoded
|
if (rc>=0) { // decoded
|
||||||
printf("K1JT rx: received with apcode=%d %s\n",rc, decode_type[rc]);
|
printf("IV3NWV rx: received with apcode=%d %s\n",rc, decode_type[rc]);
|
||||||
// K1JT replies to IV3NWV (with no grid)
|
return 0;
|
||||||
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);
|
}
|
||||||
|
printf("the other party did not decode\n");
|
||||||
// IV3NWV attempts to decode
|
return -1;
|
||||||
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)
|
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].
|
||||||
|
|
||||||
// Here we simulate the decoder of K1JT after K1JT has sent a msg [IV3NWV K1JT]
|
If mode=QRA_NOAP, K1JT decoder attempts to decode only msgs of type [? ? ?].
|
||||||
// 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
|
If mode=QRA_AUTOP, K1JT decoder will attempt to decode also the msgs
|
||||||
// indicates the amount of a-priori information required to decode the received message
|
[K1JT IV3NWV] and [K1JT IV3NWV ?].
|
||||||
// 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
|
In the case a decode is successful the return code of the qra65_decode function
|
||||||
// a particular type decode among the above 6 cases succeded.
|
indicates the amount of a-priori information required to decode the received
|
||||||
|
message according to this table:
|
||||||
|
|
||||||
int x[QRA65_K], xdec[QRA65_K];
|
rc=0 [? ? ?] AP0
|
||||||
int y[QRA65_N];
|
rc=1 [CQ ? ?] AP27
|
||||||
float *rx;
|
rc=2 [CQ ? ] AP42
|
||||||
int rc,k;
|
rc=3 [CALL ? ?] AP29
|
||||||
|
rc=4 [CALL ? ] AP44
|
||||||
|
rc=5 [CALL CALL ?] AP57
|
||||||
|
|
||||||
int ndecok[6] = { 0, 0, 0, 0, 0, 0};
|
The return code is <0 when decoding is unsuccessful
|
||||||
int ntx = 100,ndec=0;
|
|
||||||
|
|
||||||
qra65codec *codec_iv3nwv = qra65_init(mode,CALL_IV3NWV); // codec for IV3NWV
|
This test simulates the situation ntx times and reports how many times
|
||||||
qra65codec *codec_k1jt = qra65_init(mode,CALL_K1JT); // codec for K1JT
|
a particular type decode among the above 6 cases succeded.
|
||||||
|
*/
|
||||||
|
|
||||||
// this will enable k1jt's decoder to look for iv3nwv calls
|
int x[QRA65_K], xdec[QRA65_K];
|
||||||
encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT,GRID_BLANK);
|
int y[QRA65_N];
|
||||||
qra65_encode(codec_k1jt, y, x);
|
float *rx;
|
||||||
printf("K1JT tx: IV3NWV K1JT\n");
|
int rc,k;
|
||||||
|
|
||||||
// iv3nwv reply to k1jt
|
int ndecok[6] = { 0, 0, 0, 0, 0, 0};
|
||||||
printf("IV3NWV tx: K1JT IV3NWV JN66\n");
|
int ntx = 100,ndec=0;
|
||||||
encodemsg_jt65(x,CALL_K1JT,CALL_IV3NWV,GRID_JN66);
|
|
||||||
qra65_encode(codec_iv3nwv, y, x);
|
|
||||||
|
|
||||||
printf("Simulating decodes by K1JT up to AP56 ...");
|
qra65codec *codec_iv3nwv = qra65_init(mode,CALL_IV3NWV); // codec for IV3NWV
|
||||||
|
qra65codec *codec_k1jt = qra65_init(mode,CALL_K1JT); // codec for K1JT
|
||||||
|
|
||||||
for (k=0;k<ntx;k++) {
|
// This will enable K1JT's decoder to look for IV3NWV calls
|
||||||
printf(".");
|
encodemsg_jt65(x,CALL_IV3NWV,CALL_K1JT,GRID_BLANK);
|
||||||
rx = mfskchannel(y,channel_type,EbNodB);
|
qra65_encode(codec_k1jt, y, x);
|
||||||
rc = qra65_decode(codec_k1jt, xdec,rx);
|
printf("K1JT tx: IV3NWV K1JT\n");
|
||||||
if (rc>=0)
|
|
||||||
ndecok[rc]++;
|
|
||||||
}
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
printf("Transimtted:%d - Decoded:\n",ntx);
|
// IV3NWV reply to K1JT
|
||||||
for (k=0;k<6;k++) {
|
printf("IV3NWV tx: K1JT IV3NWV JN66\n");
|
||||||
printf("%3d with %s\n",ndecok[k],decode_type[k]);
|
encodemsg_jt65(x,CALL_K1JT,CALL_IV3NWV,GRID_JN66);
|
||||||
ndec += ndecok[k];
|
qra65_encode(codec_iv3nwv, y, x);
|
||||||
}
|
|
||||||
printf("Total: %d/%d\n",ndec,ntx);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
return 0;
|
printf("Simulating decodes by K1JT up to AP56 ...");
|
||||||
|
|
||||||
|
for (k=0;k<ntx;k++) {
|
||||||
|
printf(".");
|
||||||
|
rx = mfskchannel(y,channel_type,EbNodB);
|
||||||
|
rc = qra65_decode(codec_k1jt, xdec,rx);
|
||||||
|
if (rc>=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)
|
void syntax(void)
|
||||||
{
|
{
|
||||||
printf("\nQRA65 Mode Tests\n");
|
printf("\nQRA65 Mode Tests\n");
|
||||||
printf("2016, Nico Palermo - IV3NWV\n\n");
|
printf("2016, Nico Palermo - IV3NWV\n\n");
|
||||||
printf("---------------------------\n\n");
|
printf("---------------------------\n\n");
|
||||||
printf("Syntax: qra65 [-s<snrdb>] [-c<channel>] [-a<ap-type>] [-t<testtype>] [-h]\n");
|
printf("Syntax: qra65 [-s<snrdb>] [-c<channel>] [-a<ap-type>] [-t<testtype>] [-h]\n");
|
||||||
printf("Options: \n");
|
printf("Options: \n");
|
||||||
printf(" -s<snrdb> : set simulation SNR in 2500 Hz BW (default:-27.5 dB)\n");
|
printf(" -s<snrdb> : set simulation SNR in 2500 Hz BW (default:-27.5 dB)\n");
|
||||||
printf(" -c<channel> : set channel type 0=AWGN (default) 1=Rayleigh\n");
|
printf(" -c<channel> : set channel type 0=AWGN (default) 1=Rayleigh\n");
|
||||||
printf(" -a<ap-type> : set decode type 0=NO_AP 1=AUTO_AP (default)\n");
|
printf(" -a<ap-type> : set decode type 0=NO_AP 1=AUTO_AP (default)\n");
|
||||||
printf(" -t<testtype>: 0=simulate seq of msgs between IV3NWV and K1JT (default)\n");
|
printf(" -t<testtype>: 0=simulate seq of msgs between IV3NWV and K1JT (default)\n");
|
||||||
printf(" 1=simulate K1JT receiving K1JT IV3NWV JN66\n");
|
printf(" 1=simulate K1JT receiving K1JT IV3NWV JN66\n");
|
||||||
printf(" -h: this help\n");
|
printf(" -h: this help\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
int k, rc, nok=0;
|
int k, rc, nok=0;
|
||||||
|
float SNRdB = -27.5f;
|
||||||
float SNRdB = -27.5f;
|
unsigned int channel = CHANNEL_AWGN;
|
||||||
unsigned int channel = CHANNEL_AWGN;
|
unsigned int mode = QRA_AUTOAP;
|
||||||
unsigned int mode = QRA_AUTOAP;
|
unsigned int testtype=0;
|
||||||
unsigned int testtype=0;
|
int nqso = 100;
|
||||||
int nqso = 100;
|
float EbNodB;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
// 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>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__)
|
#if defined(__linux__) || defined(__unix__)
|
||||||
srand48(GetTickCount());
|
srand48(GetTickCount());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (testtype==0) {
|
if (testtype==0) {
|
||||||
for (k=0;k<nqso;k++) {
|
for (k=0;k<nqso;k++) {
|
||||||
printf("\n\n------------------------\n");
|
printf("\n\n------------------------\n");
|
||||||
rc = test_proc_1(channel, EbNodB, mode);
|
rc = test_proc_1(channel, EbNodB, mode);
|
||||||
if (rc==0)
|
if (rc==0)
|
||||||
nok++;
|
nok++;
|
||||||
}
|
}
|
||||||
printf("\n\n%d/%d QSOs to end without repetitions\n",nok,nqso);
|
printf("\n\n%d/%d QSOs to end without repetitions\n",nok,nqso);
|
||||||
}
|
} else {
|
||||||
else
|
test_proc_2(channel, EbNodB, mode);
|
||||||
test_proc_2(channel, EbNodB, mode);
|
}
|
||||||
|
|
||||||
printf("SNR = %.1fdB channel=%s ap-mode=%s\n\n",
|
printf("SNR = %.1fdB channel=%s ap-mode=%s\n\n",
|
||||||
SNRdB,
|
SNRdB,
|
||||||
channel==CHANNEL_AWGN?"AWGN":"RAYLEIGH",
|
channel==CHANNEL_AWGN?"AWGN":"RAYLEIGH",
|
||||||
mode==QRA_NOAP?"NO_AP":"AUTO_AP"
|
mode==QRA_NOAP?"NO_AP":"AUTO_AP"
|
||||||
);
|
);
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,35 +1,37 @@
|
|||||||
// qra65.c
|
/*
|
||||||
// Encoding/decoding functions for the QRA65 mode
|
qra65.c
|
||||||
//
|
Encoding/decoding functions for the QRA65 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
|
(c) 2016 - Nico Palermo, IV3NWV
|
||||||
// along with qracodes source distribution.
|
|
||||||
// If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Code used in this sowftware release:
|
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.
|
||||||
|
|
||||||
// QRA13_64_64_IRR_E: K=13 N=64 Q=64 irregular QRA code (defined in qra13_64_64_irr_e.h /.c)
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with qracodes source distribution.
|
||||||
|
If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------
|
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 <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
@ -41,304 +43,305 @@
|
|||||||
|
|
||||||
// Code parameters of the QRA65 mode
|
// Code parameters of the QRA65 mode
|
||||||
#define QRA65_CODE qra_13_64_64_irr_e
|
#define QRA65_CODE qra_13_64_64_irr_e
|
||||||
#define QRA65_NMSG 218 // this must much the value indicated in QRA65_CODE.NMSG
|
#define QRA65_NMSG 218 // Must much value indicated in QRA65_CODE.NMSG
|
||||||
|
|
||||||
#define QRA65_KC (QRA65_K+1) // information symbols crc included (as defined in the code)
|
#define QRA65_KC (QRA65_K+1) // Information symbols (crc included)
|
||||||
#define QRA65_NC (QRA65_N+1) // codeword length (as defined in the code)
|
#define QRA65_NC (QRA65_N+1) // Codeword length (as defined in the code)
|
||||||
#define QRA65_NITER 100 // max number of iterations per decode
|
#define QRA65_NITER 100 // max number of iterations per decode
|
||||||
|
|
||||||
|
// static functions declarations ----------------------------------------------
|
||||||
|
|
||||||
// static functions declarations -------------------------------------------------
|
|
||||||
static int calc_crc6(const int *x, int sz);
|
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 void ix_mask(float *dst, const float *src, const int *mask,
|
||||||
static int qra65_do_decode(int *x, const float *pix, const int *ap_mask, const int *ap_x);
|
const int *x);
|
||||||
|
static int qra65_do_decode(int *x, const float *pix, const int *ap_mask,
|
||||||
// a-priori information masks for fields in jt65-like msgs -----------------------
|
const int *ap_x);
|
||||||
|
|
||||||
|
// a-priori information masks for fields in JT65-like msgs --------------------
|
||||||
#define MASK_CQQRZ 0xFFFFFFC // CQ/QRZ calls common bits
|
#define MASK_CQQRZ 0xFFFFFFC // CQ/QRZ calls common bits
|
||||||
#define MASK_CALL1 0xFFFFFFF
|
#define MASK_CALL1 0xFFFFFFF
|
||||||
#define MASK_CALL2 0xFFFFFFF
|
#define MASK_CALL2 0xFFFFFFF
|
||||||
#define MASK_GRIDFULL 0xFFFF
|
#define MASK_GRIDFULL 0xFFFF
|
||||||
#define MASK_GRIDBIT 0x8000 // b[15] is 0 for all the messages which are not text
|
#define MASK_GRIDBIT 0x8000 // b[15] is 1 for free text, 0 otherwise
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
// -------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
qra65codec *qra65_init(int flags, const int mycall)
|
qra65codec *qra65_init(int flags, const int mycall)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Eb/No value for which we optimize the decoder metric
|
// Eb/No value for which we optimize the decoder metric
|
||||||
const float EbNodBMetric = 2.8f;
|
const float EbNodBMetric = 2.8f;
|
||||||
const float EbNoMetric = (float)pow(10,EbNodBMetric/10);
|
const float EbNoMetric = (float)pow(10,EbNodBMetric/10);
|
||||||
const float R = 1.0f*(QRA65_KC)/(QRA65_NC);
|
const float R = 1.0f*(QRA65_KC)/(QRA65_NC);
|
||||||
|
|
||||||
qra65codec *pcodec = (qra65codec*)malloc(sizeof(qra65codec));
|
qra65codec *pcodec = (qra65codec*)malloc(sizeof(qra65codec));
|
||||||
|
|
||||||
if (!pcodec)
|
if (!pcodec)
|
||||||
return 0; // can't allocate memory
|
return 0; // can't allocate memory
|
||||||
|
|
||||||
pcodec->decEsNoMetric = 1.0f*QRA65_m*R*EbNoMetric;
|
|
||||||
pcodec->apflags = flags;
|
|
||||||
|
|
||||||
if (flags!=QRA_AUTOAP)
|
pcodec->decEsNoMetric = 1.0f*QRA65_m*R*EbNoMetric;
|
||||||
return pcodec;
|
pcodec->apflags = flags;
|
||||||
|
|
||||||
// initialize messages and mask for decoding with a-priori information
|
if (flags!=QRA_AUTOAP)
|
||||||
|
return pcodec;
|
||||||
|
|
||||||
pcodec->apmycall = mycall;
|
// initialize messages and mask for decoding with a-priori information
|
||||||
pcodec->apsrccall = 0;
|
|
||||||
|
|
||||||
// encode CQ/QRZ messages and masks
|
pcodec->apmycall = mycall;
|
||||||
// NOTE: Here we handle only CQ and QRZ msgs
|
pcodec->apsrccall = 0;
|
||||||
// 'CQ nnn', 'CQ DX' and 'DE' msgs
|
|
||||||
// will be handled by the decoder as messages with no a-priori knowledge
|
|
||||||
encodemsg_jt65(pcodec->apmsg_cqqrz, CALL_CQ, 0, GRID_BLANK);
|
|
||||||
encodemsg_jt65(pcodec->apmask_cqqrz, MASK_CQQRZ,0, MASK_GRIDBIT); // AP27 (26+1)
|
|
||||||
encodemsg_jt65(pcodec->apmask_cqqrz_ooo, MASK_CQQRZ,0, MASK_GRIDFULL); // AP42 (26+16)
|
|
||||||
|
|
||||||
// encode [mycall ? x] messages and set masks
|
// encode CQ/QRZ messages and masks
|
||||||
encodemsg_jt65(pcodec->apmsg_call1, mycall, 0, GRID_BLANK);
|
// NOTE: Here we handle only CQ and QRZ msgs
|
||||||
encodemsg_jt65(pcodec->apmask_call1, MASK_CALL1, 0, MASK_GRIDBIT); // AP29 (28+1)
|
// 'CQ nnn', 'CQ DX' and 'DE' msgs
|
||||||
encodemsg_jt65(pcodec->apmask_call1_ooo, MASK_CALL1, 0, MASK_GRIDFULL); // AP44 (28+16)
|
// will be handled by the decoder as messages with no a-priori knowledge
|
||||||
|
encodemsg_jt65(pcodec->apmsg_cqqrz, CALL_CQ, 0, GRID_BLANK);
|
||||||
|
encodemsg_jt65(pcodec->apmask_cqqrz, MASK_CQQRZ,0, MASK_GRIDBIT); // AP27
|
||||||
|
encodemsg_jt65(pcodec->apmask_cqqrz_ooo, MASK_CQQRZ,0, MASK_GRIDFULL);// AP42
|
||||||
|
|
||||||
// set mask for [mycall srccall ?] messages
|
// encode [mycall ? x] messages and set masks
|
||||||
encodemsg_jt65(pcodec->apmask_call1_call2,MASK_CALL1, MASK_CALL2, MASK_GRIDBIT); // AP56 (28+28)
|
encodemsg_jt65(pcodec->apmsg_call1, mycall, 0, GRID_BLANK);
|
||||||
|
encodemsg_jt65(pcodec->apmask_call1, MASK_CALL1, 0, MASK_GRIDBIT); // AP29
|
||||||
|
encodemsg_jt65(pcodec->apmask_call1_ooo, MASK_CALL1,0, MASK_GRIDFULL);// AP44
|
||||||
|
|
||||||
return pcodec;
|
// set mask for [mycall srccall ?] messages
|
||||||
|
encodemsg_jt65(pcodec->apmask_call1_call2,MASK_CALL1,MASK_CALL2,
|
||||||
|
MASK_GRIDBIT); // AP56
|
||||||
|
return pcodec;
|
||||||
}
|
}
|
||||||
|
|
||||||
void qra65_encode(qra65codec *pcodec, int *y, const int *x)
|
void qra65_encode(qra65codec *pcodec, int *y, const int *x)
|
||||||
{
|
{
|
||||||
int encx[QRA65_KC]; // encoder input buffer
|
int encx[QRA65_KC]; // encoder input buffer
|
||||||
int ency[QRA65_NC]; // encoder output buffer
|
int ency[QRA65_NC]; // encoder output buffer
|
||||||
|
|
||||||
int call1,call2,grid;
|
int call1,call2,grid;
|
||||||
|
|
||||||
memcpy(encx,x,QRA65_K*sizeof(int)); // copy input to the encoder buffer
|
memcpy(encx,x,QRA65_K*sizeof(int)); // Copy input to encoder buffer
|
||||||
encx[QRA65_K]=calc_crc6(encx,QRA65_K); // compute and add the crc symbol
|
encx[QRA65_K]=calc_crc6(encx,QRA65_K); // Compute and add crc symbol
|
||||||
|
qra_encode(&QRA65_CODE, ency, encx); // encode msg+crc using given QRA code
|
||||||
|
|
||||||
qra_encode(&QRA65_CODE, ency, encx); // encode msg+crc using the given QRA code
|
// copy codeword to output puncturing the crc symbol
|
||||||
|
memcpy(y,ency,QRA65_K*sizeof(int)); // copy information symbols
|
||||||
|
memcpy(y+QRA65_K,ency+QRA65_KC,QRA65_C*sizeof(int)); // copy parity symbols
|
||||||
|
|
||||||
// copy codeword to output puncturing the crc symbol
|
if (pcodec->apflags!=QRA_AUTOAP)
|
||||||
memcpy(y,ency,QRA65_K*sizeof(int)); // copy the information symbols
|
return;
|
||||||
memcpy(y+QRA65_K,ency+QRA65_KC,QRA65_C*sizeof(int)); // copy the parity check symbols
|
|
||||||
|
|
||||||
if (pcodec->apflags!=QRA_AUTOAP)
|
// look if the msg sent is a std type message (bit15 of grid field = 0)
|
||||||
return;
|
if ((x[9]&0x80)==1)
|
||||||
|
return; // no, it's a text message
|
||||||
|
|
||||||
// look if the msg sent is a std type message (bit15 of grid field = 0)
|
// It's a [call1 call2 grid] message
|
||||||
if ((x[9]&0x80)==1)
|
|
||||||
return; // no, it's a text message
|
|
||||||
|
|
||||||
// it's a [call1 call2 grid] message
|
// We assume that call2 is our call (but we don't check it)
|
||||||
|
// call1 the station callsign we are calling or indicates a general call (CQ/QRZ/etc..)
|
||||||
// we assume that call2 is our call (but we don't check it)
|
decodemsg_jt65(&call1,&call2,&grid,x);
|
||||||
// call1 the station callsign we are calling or indicates a general call (CQ/QRZ/etc..)
|
|
||||||
decodemsg_jt65(&call1,&call2,&grid,x);
|
|
||||||
|
|
||||||
if ((call1>=CALL_CQ && call1<=CALL_CQ999) || call1==CALL_CQDX || call1==CALL_DE) {
|
if ((call1>=CALL_CQ && call1<=CALL_CQ999) || call1==CALL_CQDX ||
|
||||||
// we are making a general call, so we still don't know who can reply us (srccall)
|
call1==CALL_DE) {
|
||||||
// reset apsrccall to 0 so that the decoder won't look for [mycall srccall ?] msgs
|
// We are making a general call; don't know who might reply (srccall)
|
||||||
pcodec->apsrccall = 0;
|
// Reset apsrccall to 0 so decoder won't look for [mycall srccall ?] msgs
|
||||||
}
|
pcodec->apsrccall = 0;
|
||||||
else {
|
} else {
|
||||||
// we are replying someone named call1
|
// We are replying to someone named call1
|
||||||
// set apmsg_call1_call2 so that the decoder will attempt to decode [mycall call1 ?] msgs
|
// Set apmsg_call1_call2 so decoder will try for [mycall call1 ?] msgs
|
||||||
pcodec->apsrccall = call1;
|
pcodec->apsrccall = call1;
|
||||||
encodemsg_jt65(pcodec->apmsg_call1_call2, pcodec->apmycall, pcodec->apsrccall, 0);
|
encodemsg_jt65(pcodec->apmsg_call1_call2, pcodec->apmycall,
|
||||||
}
|
pcodec->apsrccall, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int qra65_decode(qra65codec *pcodec, int *x, const float *rxen)
|
int qra65_decode(qra65codec *pcodec, int *x, const float *rxen)
|
||||||
{
|
{
|
||||||
int k;
|
int k;
|
||||||
float *srctmp, *dsttmp;
|
float *srctmp, *dsttmp;
|
||||||
float ix[QRA65_NC*QRA65_M]; // (depunctured) intrisic information to the decoder
|
float ix[QRA65_NC*QRA65_M]; // (depunctured) intrisic information
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
if (QRA65_NMSG!=QRA65_CODE.NMSG) // sanity check
|
||||||
|
return -16; // QRA65_NMSG define is wrong
|
||||||
|
|
||||||
// sanity check
|
// compute symbols intrinsic probabilities from received energy observations
|
||||||
if (QRA65_NMSG!=QRA65_CODE.NMSG)
|
qra_mfskbesselmetric(ix, rxen, QRA65_m, QRA65_N,pcodec->decEsNoMetric);
|
||||||
return -16; // QRA65_NMSG define is wrong
|
|
||||||
|
|
||||||
// compute symbols intrinsic probabilities from received energy observations
|
// de-puncture observations adding a uniform distribution for the crc symbol
|
||||||
qra_mfskbesselmetric(ix, rxen, QRA65_m, QRA65_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,QRA65_M, QRA65_NC-1); //Point to last symbol prob dist
|
||||||
|
srctmp = dsttmp-QRA65_M; // source is the previous pd
|
||||||
|
for (k=0;k<QRA65_C;k++) {
|
||||||
|
pd_init(dsttmp,srctmp,QRA65_M);
|
||||||
|
dsttmp -=QRA65_M;
|
||||||
|
srctmp -=QRA65_M;
|
||||||
|
}
|
||||||
|
// Initialize crc prob to a uniform distribution
|
||||||
|
pd_init(dsttmp,pd_uniform(QRA65_m),QRA65_M);
|
||||||
|
|
||||||
// move check symbols distributions one symbol towards the end
|
// Attempt to decode without a-priori info --------------------------------
|
||||||
dsttmp = PD_ROWADDR(ix,QRA65_M, QRA65_NC-1); // point to the last symbol prob dist
|
rc = qra65_do_decode(x, ix, NULL, NULL);
|
||||||
srctmp = dsttmp-QRA65_M; // source is the previous pd
|
if (rc>=0) return 0; // successfull decode with AP0
|
||||||
for (k=0;k<QRA65_C;k++) {
|
|
||||||
pd_init(dsttmp,srctmp,QRA65_M);
|
|
||||||
dsttmp -=QRA65_M;
|
|
||||||
srctmp -=QRA65_M;
|
|
||||||
}
|
|
||||||
// init crc prob to a uniform distribution
|
|
||||||
pd_init(dsttmp,pd_uniform(QRA65_m),QRA65_M);
|
|
||||||
|
|
||||||
// attempt to decode without a-priori --------------------------------------------------
|
if (pcodec->apflags!=QRA_AUTOAP) return rc; // rc<0 = unsuccessful decode
|
||||||
rc = qra65_do_decode(x, ix, NULL, NULL);
|
|
||||||
if (rc>=0) return 0; // successfull decode with 0 ap
|
|
||||||
|
|
||||||
if (pcodec->apflags!=QRA_AUTOAP) return rc; // rc<0 = unsuccessful decode
|
// Attempt to decode CQ calls
|
||||||
|
rc = qra65_do_decode(x,ix,pcodec->apmask_cqqrz, pcodec->apmsg_cqqrz); // AP27
|
||||||
|
if (rc>=0) return 1; // decoded [cq/qrz ? ?]
|
||||||
|
|
||||||
// attempt to decode CQ calls
|
rc = qra65_do_decode(x, ix, pcodec->apmask_cqqrz_ooo,
|
||||||
rc = qra65_do_decode(x, ix, pcodec->apmask_cqqrz, pcodec->apmsg_cqqrz); // 27 bit AP
|
pcodec->apmsg_cqqrz); // AP42
|
||||||
if (rc>=0) return 1; // decoded [cq/qrz ? ?]
|
if (rc>=0) return 2; // decoded [cq ? ooo]
|
||||||
rc = qra65_do_decode(x, ix, pcodec->apmask_cqqrz_ooo, pcodec->apmsg_cqqrz); // 44 bit AP
|
|
||||||
if (rc>=0) return 2; // decoded [cq ? ooo]
|
|
||||||
|
|
||||||
// attempt to decode calls directed to us (mycall)
|
// attempt to decode calls directed to us (mycall)
|
||||||
rc = qra65_do_decode(x, ix, pcodec->apmask_call1, pcodec->apmsg_call1); // 29 bit AP
|
rc = qra65_do_decode(x, ix, pcodec->apmask_call1,
|
||||||
if (rc>=0) return 3; // decoded [mycall ? ?]
|
pcodec->apmsg_call1); // AP29
|
||||||
rc = qra65_do_decode(x, ix, pcodec->apmask_call1_ooo, pcodec->apmsg_call1); // 45 bit AP
|
if (rc>=0) return 3; // decoded [mycall ? ?]
|
||||||
if (rc>=0) return 4; // decoded [mycall ? ooo]
|
|
||||||
|
|
||||||
// if apsrccall is set attempt to decode [mycall srccall ?] msgs
|
rc = qra65_do_decode(x, ix, pcodec->apmask_call1_ooo,
|
||||||
if (pcodec->apsrccall==0) return rc; // nothing more to do
|
pcodec->apmsg_call1); // AP44
|
||||||
|
if (rc>=0) return 4; // decoded [mycall ? ooo]
|
||||||
|
|
||||||
rc = qra65_do_decode(x, ix, pcodec->apmask_call1_call2, pcodec->apmsg_call1_call2); // 57 bit AP
|
// if apsrccall is set attempt to decode [mycall srccall ?] msgs
|
||||||
if (rc>=0) return 5; // decoded [mycall srccall ?]
|
if (pcodec->apsrccall==0) return rc; // nothing more to do
|
||||||
|
|
||||||
return rc;
|
rc = qra65_do_decode(x, ix, pcodec->apmask_call1_call2,
|
||||||
|
pcodec->apmsg_call1_call2); // AP57
|
||||||
|
if (rc>=0) return 5; // decoded [mycall srccall ?]
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// static functions definitions ----------------------------------------------------------------
|
// Static functions definitions ----------------------------------------------
|
||||||
|
|
||||||
// decode with given a-priori information
|
// Decode with given a-priori information
|
||||||
static int qra65_do_decode(int *x, const float *pix, const int *ap_mask, const int *ap_x)
|
static int qra65_do_decode(int *x, const float *pix, const int *ap_mask,
|
||||||
|
const int *ap_x)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
const float *ixsrc;
|
const float *ixsrc;
|
||||||
float ix_masked[QRA65_NC*QRA65_M]; // (masked) intrinsic information to the decoder
|
float ix_masked[QRA65_NC*QRA65_M]; // Masked intrinsic information
|
||||||
float ex[QRA65_NC*QRA65_M]; // extrinsic information from the decoder
|
float ex[QRA65_NC*QRA65_M]; // Extrinsic information from the decoder
|
||||||
|
|
||||||
float v2cmsg[QRA65_NMSG*QRA65_M]; // buffers for the decoder messages
|
float v2cmsg[QRA65_NMSG*QRA65_M]; // buffers for the decoder messages
|
||||||
float c2vmsg[QRA65_NMSG*QRA65_M];
|
float c2vmsg[QRA65_NMSG*QRA65_M];
|
||||||
int xdec[QRA65_KC];
|
int xdec[QRA65_KC];
|
||||||
|
|
||||||
if (ap_mask==NULL) { // no a-priori information
|
if (ap_mask==NULL) { // no a-priori information
|
||||||
ixsrc = pix; // intrinsic source is what passed as argument
|
ixsrc = pix; // intrinsic source is what passed as argument
|
||||||
}
|
} else {
|
||||||
else { // a-priori information provided
|
// a-priori information provided
|
||||||
// mask channel observations with a-priori
|
// mask channel observations with a-priori
|
||||||
ix_mask(ix_masked,pix,ap_mask,ap_x);
|
ix_mask(ix_masked,pix,ap_mask,ap_x);
|
||||||
ixsrc = ix_masked; // intrinsic source is the masked version
|
ixsrc = ix_masked; // intrinsic source is the masked version
|
||||||
}
|
}
|
||||||
|
|
||||||
// run the decoding algorithm
|
// run the decoding algorithm
|
||||||
rc = qra_extrinsic(&QRA65_CODE,ex,ixsrc,QRA65_NITER,v2cmsg,c2vmsg);
|
rc = qra_extrinsic(&QRA65_CODE,ex,ixsrc,QRA65_NITER,v2cmsg,c2vmsg);
|
||||||
if (rc<0)
|
if (rc<0)
|
||||||
return -1; // no convergence in given iterations
|
return -1; // no convergence in given iterations
|
||||||
|
|
||||||
// decode
|
// decode
|
||||||
qra_mapdecode(&QRA65_CODE,xdec,ex,ixsrc);
|
qra_mapdecode(&QRA65_CODE,xdec,ex,ixsrc);
|
||||||
|
|
||||||
// verify crc
|
// verify crc
|
||||||
if (calc_crc6(xdec,QRA65_K)!=xdec[QRA65_K]) // crc doesn't match (detected error)
|
if (calc_crc6(xdec,QRA65_K)!=xdec[QRA65_K]) // crc doesn't match (detected error)
|
||||||
return -2; // decoding was succesfull but crc doesn't match
|
return -2; // decoding was succesfull but crc doesn't match
|
||||||
|
|
||||||
// success. copy decoded message to output buffer
|
// success. copy decoded message to output buffer
|
||||||
memcpy(x,xdec,QRA65_K*sizeof(int));
|
memcpy(x,xdec,QRA65_K*sizeof(int));
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
// crc functions -------------------------------------------------------------------------------
|
// crc functions --------------------------------------------------------------
|
||||||
// crc-6 generator polynomial
|
// crc-6 generator polynomial
|
||||||
// g(x) = x^6 + a5*x^5 + ... + a1*x + a0
|
// g(x) = x^6 + a5*x^5 + ... + a1*x + a0
|
||||||
|
|
||||||
// g(x) = x^6 + x + 1
|
// g(x) = x^6 + x + 1
|
||||||
#define CRC6_GEN_POL 0x30 // MSB=a0 LSB=a5
|
#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/)
|
// 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
|
// #define CRC6_GEN_POL 0x38 // MSB=a0 LSB=a5. Simulation results are similar
|
||||||
|
|
||||||
static int calc_crc6(const int *x, int sz)
|
static int calc_crc6(const int *x, int sz)
|
||||||
{
|
{
|
||||||
// todo: compute it faster using a look up table
|
// todo: compute it faster using a look up table
|
||||||
int k,j,t,sr = 0;
|
int k,j,t,sr = 0;
|
||||||
for (k=0;k<sz;k++) {
|
for (k=0;k<sz;k++) {
|
||||||
t = x[k];
|
t = x[k];
|
||||||
for (j=0;j<6;j++) {
|
for (j=0;j<6;j++) {
|
||||||
if ((t^sr)&0x01)
|
if ((t^sr)&0x01)
|
||||||
sr = (sr>>1) ^ CRC6_GEN_POL;
|
sr = (sr>>1) ^ CRC6_GEN_POL;
|
||||||
else
|
else
|
||||||
sr = (sr>>1);
|
sr = (sr>>1);
|
||||||
t>>=1;
|
t>>=1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sr;
|
return sr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ix_mask(float *dst, const float *src, const int *mask, const int *x)
|
static void ix_mask(float *dst, const float *src, const int *mask,
|
||||||
|
const int *x)
|
||||||
{
|
{
|
||||||
// mask intrinsic information (channel observations) with a priori knowledge
|
// mask intrinsic information (channel observations) with a priori knowledge
|
||||||
|
|
||||||
int k,kk, smask;
|
int k,kk, smask;
|
||||||
float *row;
|
float *row;
|
||||||
|
|
||||||
memcpy(dst,src,(QRA65_NC*QRA65_M)*sizeof(float));
|
memcpy(dst,src,(QRA65_NC*QRA65_M)*sizeof(float));
|
||||||
|
|
||||||
for (k=0;k<QRA65_K;k++) { // we can mask only information symbols distrib
|
for (k=0;k<QRA65_K;k++) { // we can mask only information symbols distrib
|
||||||
smask = mask[k];
|
smask = mask[k];
|
||||||
row = PD_ROWADDR(dst,QRA65_M,k);
|
row = PD_ROWADDR(dst,QRA65_M,k);
|
||||||
if (smask) {
|
if (smask) {
|
||||||
for (kk=0;kk<QRA65_M;kk++)
|
for (kk=0;kk<QRA65_M;kk++)
|
||||||
if (((kk^x[k])&smask)!=0)
|
if (((kk^x[k])&smask)!=0)
|
||||||
*(row+kk) = 0.f;
|
*(row+kk) = 0.f;
|
||||||
|
|
||||||
pd_norm(row,QRA65_m);
|
pd_norm(row,QRA65_m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// encode/decode msgs as done in JT65
|
// encode/decode msgs as done in JT65
|
||||||
void encodemsg_jt65(int *y, const int call1, const int call2, const int grid)
|
void encodemsg_jt65(int *y, const int call1, const int call2, const int grid)
|
||||||
{
|
{
|
||||||
y[0]= (call1>>22)&0x3F;
|
y[0]= (call1>>22)&0x3F;
|
||||||
y[1]= (call1>>16)&0x3F;
|
y[1]= (call1>>16)&0x3F;
|
||||||
y[2]= (call1>>10)&0x3F;
|
y[2]= (call1>>10)&0x3F;
|
||||||
y[3]= (call1>>4)&0x3F;
|
y[3]= (call1>>4)&0x3F;
|
||||||
y[4]= (call1<<2)&0x3F;
|
y[4]= (call1<<2)&0x3F;
|
||||||
|
|
||||||
y[4] |= (call2>>26)&0x3F;
|
y[4] |= (call2>>26)&0x3F;
|
||||||
y[5]= (call2>>20)&0x3F;
|
y[5]= (call2>>20)&0x3F;
|
||||||
y[6]= (call2>>14)&0x3F;
|
y[6]= (call2>>14)&0x3F;
|
||||||
y[7]= (call2>>8)&0x3F;
|
y[7]= (call2>>8)&0x3F;
|
||||||
y[8]= (call2>>2)&0x3F;
|
y[8]= (call2>>2)&0x3F;
|
||||||
y[9]= (call2<<4)&0x3F;
|
y[9]= (call2<<4)&0x3F;
|
||||||
|
|
||||||
y[9] |= (grid>>12)&0x3F;
|
y[9] |= (grid>>12)&0x3F;
|
||||||
y[10]= (grid>>6)&0x3F;
|
y[10]= (grid>>6)&0x3F;
|
||||||
y[11]= (grid)&0x3F;
|
y[11]= (grid)&0x3F;
|
||||||
|
|
||||||
}
|
}
|
||||||
void decodemsg_jt65(int *call1, int *call2, int *grid, const int *x)
|
void decodemsg_jt65(int *call1, int *call2, int *grid, const int *x)
|
||||||
{
|
{
|
||||||
int nc1, nc2, ng;
|
int nc1, nc2, ng;
|
||||||
|
|
||||||
nc1 = x[4]>>2;
|
nc1 = x[4]>>2;
|
||||||
nc1 |= x[3]<<4;
|
nc1 |= x[3]<<4;
|
||||||
nc1 |= x[2]<<10;
|
nc1 |= x[2]<<10;
|
||||||
nc1 |= x[1]<<16;
|
nc1 |= x[1]<<16;
|
||||||
nc1 |= x[0]<<22;
|
nc1 |= x[0]<<22;
|
||||||
|
|
||||||
nc2 = x[9]>>4;
|
nc2 = x[9]>>4;
|
||||||
nc2 |= x[8]<<2;
|
nc2 |= x[8]<<2;
|
||||||
nc2 |= x[7]<<8;
|
nc2 |= x[7]<<8;
|
||||||
nc2 |= x[6]<<14;
|
nc2 |= x[6]<<14;
|
||||||
nc2 |= x[5]<<20;
|
nc2 |= x[5]<<20;
|
||||||
nc2 |= (x[4]&0x03)<<26;
|
nc2 |= (x[4]&0x03)<<26;
|
||||||
|
|
||||||
ng = x[11];
|
ng = x[11];
|
||||||
ng |= x[10]<<6;
|
ng |= x[10]<<6;
|
||||||
ng |= (x[9]&0x0F)<<12;
|
ng |= (x[9]&0x0F)<<12;
|
||||||
|
|
||||||
*call1 = nc1;
|
*call1 = nc1;
|
||||||
*call2 = nc2;
|
*call2 = nc2;
|
||||||
*grid = ng;
|
*grid = ng;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,18 +43,18 @@
|
|||||||
#define GRID_BLANK 0x7E91
|
#define GRID_BLANK 0x7E91
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float decEsNoMetric;
|
float decEsNoMetric;
|
||||||
int apflags;
|
int apflags;
|
||||||
int apmycall;
|
int apmycall;
|
||||||
int apsrccall;
|
int apsrccall;
|
||||||
int apmsg_cqqrz[12]; // [cq/qrz ? blank]
|
int apmsg_cqqrz[12]; // [cq/qrz ? blank]
|
||||||
int apmsg_call1[12]; // [mycall ? blank]
|
int apmsg_call1[12]; // [mycall ? blank]
|
||||||
int apmsg_call1_call2[12]; // [mycall srccall ?]
|
int apmsg_call1_call2[12]; // [mycall srccall ?]
|
||||||
int apmask_cqqrz[12];
|
int apmask_cqqrz[12];
|
||||||
int apmask_cqqrz_ooo[12];
|
int apmask_cqqrz_ooo[12];
|
||||||
int apmask_call1[12];
|
int apmask_call1[12];
|
||||||
int apmask_call1_ooo[12];
|
int apmask_call1_ooo[12];
|
||||||
int apmask_call1_call2[12];
|
int apmask_call1_call2[12];
|
||||||
} qra65codec;
|
} qra65codec;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -11,20 +11,32 @@ void qra65_enc_(int x[], int y[])
|
|||||||
qra65_encode(codec, y, x);
|
qra65_encode(codec, y, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void qra65_dec_(float r[], int xdec[], int* rc)
|
void qra65_dec_(float r[], int* nmycall, int xdec[], int* rc)
|
||||||
{
|
{
|
||||||
// Return codes:
|
// Return codes:
|
||||||
// rc<0 no decode
|
// rc=-16 failed sanity check
|
||||||
|
// rc=-2 decoded, but crc check failed
|
||||||
|
// rc=-1 no decode
|
||||||
// rc=0 [? ? ?] AP0 (decoding with no a-priori information)
|
// rc=0 [? ? ?] AP0 (decoding with no a-priori information)
|
||||||
// rc=1 [CQ ? ?] AP27
|
// rc=1 [CQ ? ?] AP27
|
||||||
// rc=2 [CQ ? ] AP44
|
// rc=2 [CQ ? ] AP42
|
||||||
// rc=3 [CALL ? ?] AP29
|
// rc=3 [CALL ? ?] AP29
|
||||||
// rc=4 [CALL ? ] AP45
|
// rc=4 [CALL ? ] AP44
|
||||||
// rc=5 [CALL CALL ?] AP57
|
// rc=5 [CALL CALL ?] AP57
|
||||||
|
|
||||||
int ncall=0xf70c238; //K1ABC
|
static int ncall0=0;
|
||||||
// int ncall=0x890c60c; //KA1ABC
|
int ncall;
|
||||||
int i;
|
int x[63],y[12];
|
||||||
|
|
||||||
|
ncall = *nmycall;
|
||||||
qra65codec *codec = qra65_init(1,ncall); //codec for ncall
|
qra65codec *codec = qra65_init(1,ncall); //codec for ncall
|
||||||
|
/*
|
||||||
|
if(ncall != ncall0) {
|
||||||
|
memset(y,0,sizeof(y));
|
||||||
|
qra65_encode(codec, y, x);
|
||||||
|
printf("Updated codec %d\n",ncall);
|
||||||
|
}
|
||||||
|
ncall0=ncall;
|
||||||
|
*/
|
||||||
*rc = qra65_decode(codec,xdec,r);
|
*rc = qra65_decode(codec,xdec,r);
|
||||||
}
|
}
|
||||||
|
@ -121,6 +121,8 @@ program qra65sim
|
|||||||
h=default_header(12000,npts)
|
h=default_header(12000,npts)
|
||||||
dfsig=2000.0/nsigs !Freq spacing between sigs in file (Hz)
|
dfsig=2000.0/nsigs !Freq spacing between sigs in file (Hz)
|
||||||
|
|
||||||
|
print*,'A',nsigs,nfiles
|
||||||
|
|
||||||
do ifile=1,nfiles !Loop over requested number of files
|
do ifile=1,nfiles !Loop over requested number of files
|
||||||
write(fname,1002) ifile !Output filename
|
write(fname,1002) ifile !Output filename
|
||||||
1002 format('000000_',i4.4)
|
1002 format('000000_',i4.4)
|
||||||
@ -146,9 +148,8 @@ program qra65sim
|
|||||||
call packmsg(msg,dgen,itype) !Pack message into 12 six-bit bytes
|
call packmsg(msg,dgen,itype) !Pack message into 12 six-bit bytes
|
||||||
call qra65_enc(dgen,sent) !Encode using QRA65
|
call qra65_enc(dgen,sent) !Encode using QRA65
|
||||||
! call qra65_dec(sent,dgen,ierr) !Decode (### for test only ###)
|
! call qra65_dec(sent,dgen,ierr) !Decode (### for test only ###)
|
||||||
|
! write(*,3001) sent
|
||||||
write(*,3001) sent
|
!3001 format(21i3)
|
||||||
3001 format(21i3)
|
|
||||||
|
|
||||||
k=0
|
k=0
|
||||||
do j=1,nsym !Insert sync and data into itone()
|
do j=1,nsym !Insert sync and data into itone()
|
||||||
|
Loading…
Reference in New Issue
Block a user