Compare commits
329 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e9aa4203b5 | |||
| 418e071a8d | |||
| 4ca8ac338e | |||
| acbd1080d5 | |||
| ae62a73b58 | |||
| 95cd09c7f2 | |||
| 0b49dc0398 | |||
| 4b28f9eca5 | |||
| 5a18b3f9fb | |||
| 8b9042e2d6 | |||
| 826b829941 | |||
| a36ed10fe2 | |||
| 8d0d93d10e | |||
| ca537f5e9f | |||
| e0c3592868 | |||
| 3a9750015d | |||
| 38ddf11479 | |||
| 15ee95360f | |||
| 308a45efe0 | |||
| ad060dad81 | |||
| 35139c6d84 | |||
| 942d960a90 | |||
| b4c95e4313 | |||
| 293781079a | |||
| 003120d998 | |||
| 57f84c8e2b | |||
| 231c75715a | |||
| 0a1a08a1a5 | |||
| 775008be48 | |||
| b0937ffe18 | |||
| ea9cc62329 | |||
| f6c59d33bd | |||
| 6725df3d26 | |||
| dfdf23315b | |||
| 3a139fc87a | |||
| 04e3dc9c3e | |||
| ca66c6401c | |||
| 1ca079041f | |||
| e922df7635 | |||
| f30cf20400 | |||
| d4155ff348 | |||
| 75fded07d3 | |||
| 61cddd5ba4 | |||
| 24e9b15e42 | |||
| 9bbaba3f72 | |||
| 8c8218bdd8 | |||
| b8c3b4ce91 | |||
| bf7d057d6e | |||
| c4db1a9a00 | |||
| ecfbbe5219 | |||
| 2620435e92 | |||
| 0886dc1995 | |||
| 9a3d7dd992 | |||
| 6224c9cf75 | |||
| a5e1d0206b | |||
| c5531a5177 | |||
| 536f017fd4 | |||
| 5c313af3ab | |||
| 046fe83193 | |||
| e861308d70 | |||
| 6dcf4b96d2 | |||
| f00f5e23c1 | |||
| 2e8cde4193 | |||
| 7caa7c83b8 | |||
| 08d8beed64 | |||
| e5347eb4b6 | |||
| 64022c18b6 | |||
| 42c8d1c0bb | |||
| 6ab3d32e3b | |||
| 2b62734437 | |||
| 95a91fb526 | |||
| 081bc0380b | |||
| 77715347c7 | |||
| 712580d08c | |||
| 084765f271 | |||
| d2b7229815 | |||
| 63739b9d31 | |||
| d1b239201c | |||
| f06df77db2 | |||
| 2250589f83 | |||
| 65a19e4707 | |||
| c8c4f98610 | |||
| 0ecbbd0da1 | |||
| b5cebe41e8 | |||
| 83b05df312 | |||
| 541bd8bca3 | |||
| 565bdb5690 | |||
| 7868c3fe70 | |||
| adcc728492 | |||
| 2fa1fcd4f8 | |||
| 8eb0fc327d | |||
| e6f83e999b | |||
| b10ccc370f | |||
| 121ffb48f6 | |||
| 4698db27f6 | |||
| fe1463b730 | |||
| ad154cb2e6 | |||
| 5166b1e0dd | |||
| 5d0e91a5ed | |||
| c01238f5e0 | |||
| 726484a05a | |||
| b7d2a370f8 | |||
| 6c8902d802 | |||
| 1002dcbc1b | |||
| f2ca9caec7 | |||
| 96ca7786e5 | |||
| eecde27cd8 | |||
| d4bb4cf49a | |||
| db74c22890 | |||
| 69b90b243a | |||
| 9bac05c86c | |||
| fde19eebd8 | |||
| 6b4390fe5c | |||
| ad4e567392 | |||
| 612df625ed | |||
| 9475ea7461 | |||
| 5fad5497d2 | |||
| 9815c4dde9 | |||
| 60c0f24ef8 | |||
| e74e20680a | |||
| ee44e2e5d7 | |||
| 43574b10b1 | |||
| 08f046c289 | |||
| 5f4a66e916 | |||
| bc97c96a5b | |||
| 3b1519c603 | |||
| f30c2e3858 | |||
| c60efba4ca | |||
| 5694b96f55 | |||
| 52b6cea883 | |||
| fded3b5003 | |||
| de713e86fc | |||
| ed9228d196 | |||
| 08357c4b11 | |||
| 94d7b94f56 | |||
| d3b593c953 | |||
| 8c8ddb533c | |||
| c042a72d0d | |||
| a5b6984ede | |||
| 8b07b56250 | |||
| ca2436c11d | |||
| b3c0901de7 | |||
| df5b228ddc | |||
| 7a42fac9d9 | |||
| aa59cc547f | |||
| 49224f5b81 | |||
| c779bf4ca0 | |||
| 917e4f0771 | |||
| 3444bcaa17 | |||
| 935708dd5e | |||
| 0353724f1a | |||
| 899a914a88 | |||
| f4688b44d3 | |||
| 7037baa0a6 | |||
| e91e93c349 | |||
| 10d706e9fa | |||
| 80ed587514 | |||
| edf85a1e5f | |||
| 4520cdd48d | |||
| 6b3591df88 | |||
| af913532c5 | |||
| e51cc6c3b5 | |||
| 2989c20175 | |||
| d2ad5ee893 | |||
| 330eb3a57e | |||
| c0cfac10dc | |||
| 4eba12b2a2 | |||
| 27fe5a3d28 | |||
| be8b4c18ee | |||
| bf0ebf227b | |||
| 5215e6764f | |||
| 54862b9115 | |||
| 9e6b647139 | |||
| 0755634366 | |||
| fed71cb75c | |||
| a08858a3f1 | |||
| aa9014f2f5 | |||
| 9c98e01458 | |||
| 45032cfdd8 | |||
| 085a81ca18 | |||
| a81f9602a9 | |||
| 80767c5dd0 | |||
| 9444b5c4d1 | |||
| d303cbfe67 | |||
| 07118dac49 | |||
| ebf30b38ef | |||
| c1e1d3864f | |||
| 334b6ef443 | |||
| 3e67f4ef1f | |||
| 3318fa1005 | |||
| ba0a2fe52d | |||
| e2f06a629d | |||
| 88ad573de9 | |||
| db9f969dcc | |||
| 2e41454e6b | |||
| 26581ca8af | |||
| 049694365e | |||
| e3ae807c85 | |||
| c1b374b858 | |||
| 16a744d55e | |||
| 883cb99c0f | |||
| c2bda71da5 | |||
| 627367223b | |||
| a3c5431000 | |||
| 7a155a4820 | |||
| 172e1df31d | |||
| b7b7167d85 | |||
| 5f3ca913b7 | |||
| e649a375cf | |||
| eb7882e253 | |||
| 96f7b9fd66 | |||
| 479d647456 | |||
| e316554b68 | |||
| 323c4e888f | |||
| 7942bf3a4d | |||
| 5a5e37f119 | |||
| 7ff43be5f3 | |||
| 3a5707992c | |||
| a47d722901 | |||
| 3e19b2c98d | |||
| 62c449669f | |||
| f0de2f2ba1 | |||
| 0a7c4a68de | |||
| e1530c147c | |||
| ff77effb3e | |||
| 5238e1ade8 | |||
| 5d64ac37c5 | |||
| 1df975f274 | |||
| 565f4d9321 | |||
| 62899069bf | |||
| 8f8772f1bd | |||
| f09132f6b4 | |||
| bf57a67c43 | |||
| 091b3b3ee8 | |||
| 17033f1044 | |||
| 7c656fac71 | |||
| a6771b81c3 | |||
| eca184bac6 | |||
| 6ad2417804 | |||
| 21e87d8b6f | |||
| 52a5650a74 | |||
| 2158722ebc | |||
| bf11d66f60 | |||
| 371aa1e20c | |||
| 8348f61a94 | |||
| bf28918096 | |||
| 571aa6446d | |||
| 4290dd6e2f | |||
| de66664635 | |||
| 9e9c996813 | |||
| f67ea3803d | |||
| fa00e0dfd6 | |||
| ceaa76c497 | |||
| 9c9a5c2d8b | |||
| d611d83bb9 | |||
| 253b60217f | |||
| 39a536bb91 | |||
| 115a9d65f7 | |||
| 796920cb6b | |||
| c1c7d85195 | |||
| c5a6f76b1e | |||
| 5b198351be | |||
| 246d53201c | |||
| 999a239e67 | |||
| f091cb28ef | |||
| f415b0c94f | |||
| 0bf2afa5f8 | |||
| 706a9b1ebd | |||
| 4cec8b80a3 | |||
| 9e68b8c402 | |||
| 478ba82df7 | |||
| 7aef92dd68 | |||
| 01249bd115 | |||
| 9bee00c5dd | |||
| b9b274f2d6 | |||
| 4a17062487 | |||
| 1c73ce2c90 | |||
| 07a29c7f1d | |||
| f7a941406c | |||
| adecb88c29 | |||
| 857e19ed94 | |||
| f47224979e | |||
| c0833aa753 | |||
| 20d931a9ca | |||
| 1b2f8a1c6c | |||
| 95e75741ed | |||
| dc75c08081 | |||
| 8c204e317b | |||
| a672668c3a | |||
| 8638b53e45 | |||
| 394a6d045f | |||
| 29bbedcc8f | |||
| d66b4ffb37 | |||
| c0c4693782 | |||
| 9223d3da40 | |||
| 83e3f5ddbc | |||
| 0f4057aa97 | |||
| 591629e369 | |||
| 4a96ab3b13 | |||
| e955cff24f | |||
| fe405cfba8 | |||
| 92117aa791 | |||
| d4c2d9a871 | |||
| b2e2b91d31 | |||
| fa864c50cd | |||
| 1c6d1babe6 | |||
| ac27d1a9b6 | |||
| 28eb082655 | |||
| 9a945c156d | |||
| 83c742f7ec | |||
| 7a788c05c8 | |||
| 7b409a6ff4 | |||
| 87a631f5f0 | |||
| efd6b54ba7 | |||
| 553f2400e5 | |||
| 5c84e79e5b | |||
| 052b81ec8f | |||
| 7ecc550bc2 | |||
| b8267372e4 | |||
| 512dffabf4 | |||
| 50a3a56d2d | |||
| deb228948d | |||
| 58032b6ae4 | |||
| 7845736c05 | |||
| 77eb65d6b3 | |||
| 252c21b818 | |||
| 82c3b23e44 | |||
| 5764170975 | |||
| a2c85256e8 |
@@ -1,3 +1,2 @@
|
||||
TAGS
|
||||
tags
|
||||
.svn
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
#ifndef WSJTX_MESSAGE_AGGREGATOR_MAIN_WINDOW_MODEL_HPP__
|
||||
#define WSJTX_MESSAGE_AGGREGATOR_MAIN_WINDOW_MODEL_HPP__
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QHash>
|
||||
#include <QString>
|
||||
|
||||
#include "MessageServer.hpp"
|
||||
|
||||
class QDateTime;
|
||||
class QStandardItemModel;
|
||||
class QMenu;
|
||||
class DecodesModel;
|
||||
class BeaconsModel;
|
||||
class QLineEdit;
|
||||
class QTableView;
|
||||
class ClientWidget;
|
||||
|
||||
using Frequency = MessageServer::Frequency;
|
||||
|
||||
class MessageAggregatorMainWindow
|
||||
: public QMainWindow
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
MessageAggregatorMainWindow ();
|
||||
|
||||
Q_SLOT void log_qso (QString const& /*id*/, QDateTime timeOff, QString const& dx_call, QString const& dx_grid
|
||||
, Frequency dial_frequency, QString const& mode, QString const& report_sent
|
||||
, QString const& report_received, QString const& tx_power, QString const& comments
|
||||
, QString const& name, QDateTime timeOn);
|
||||
|
||||
private:
|
||||
void add_client (QString const& id, QString const& version, QString const& revision);
|
||||
void remove_client (QString const& id);
|
||||
|
||||
QStandardItemModel * log_;
|
||||
QMenu * view_menu_;
|
||||
DecodesModel * decodes_model_;
|
||||
BeaconsModel * beacons_model_;
|
||||
MessageServer * server_;
|
||||
QLineEdit * multicast_group_line_edit_;
|
||||
QTableView * log_table_view_;
|
||||
|
||||
// maps client id to widgets
|
||||
using ClientsDictionary = QHash<QString, ClientWidget *>;
|
||||
ClientsDictionary dock_widgets_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,5 +0,0 @@
|
||||
kern.sysv.shmmax=33554432
|
||||
kern.sysv.shmmin=1
|
||||
kern.sysv.shmmni=128
|
||||
kern.sysv.shmseg=32
|
||||
kern.sysv.shmall=8192
|
||||
@@ -1,166 +0,0 @@
|
||||
/* ALIST-TO-PCHK.C - Convert a parity check matrix to alist format. */
|
||||
|
||||
/* Copyright (c) 1995-2012 by Radford M. Neal.
|
||||
*
|
||||
* Permission is granted for anyone to copy, use, modify, and distribute
|
||||
* these programs and accompanying documents for any purpose, provided
|
||||
* this copyright notice is retained and prominently displayed, and note
|
||||
* is made of any changes made to these programs. These programs and
|
||||
* documents are distributed without any warranty, express or implied.
|
||||
* As the programs were written for research purposes only, they have not
|
||||
* been tested to the degree that would be advisable in any important
|
||||
* application. All use of these programs is entirely at the user's own
|
||||
* risk.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "alloc.h"
|
||||
#include "open.h"
|
||||
#include "mod2sparse.h"
|
||||
#include "mod2dense.h"
|
||||
#include "mod2convert.h"
|
||||
#include "rcode.h"
|
||||
|
||||
|
||||
void usage(void);
|
||||
|
||||
|
||||
/* MAIN PROGRAM. */
|
||||
|
||||
int main
|
||||
( int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
char *alist_file, *pchk_file;
|
||||
FILE *af, *pf;
|
||||
int mxrw, mxcw;
|
||||
int *rw, *cw;
|
||||
int i, j, k;
|
||||
mod2entry *e;
|
||||
int trans;
|
||||
int nozeros;
|
||||
int last;
|
||||
|
||||
trans = 0;
|
||||
nozeros = 0;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (argc>1 && strcmp(argv[1],"-t")==0)
|
||||
{ trans = 1;
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
}
|
||||
else if (argc>1 && strcmp(argv[1],"-z")==0)
|
||||
{ nozeros = 1;
|
||||
argc -= 1;
|
||||
argv += 1;
|
||||
}
|
||||
else
|
||||
{ break;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc!=3)
|
||||
{ usage();
|
||||
}
|
||||
|
||||
pchk_file = argv[1];
|
||||
alist_file = argv[2];
|
||||
|
||||
read_pchk(pchk_file);
|
||||
|
||||
if (trans)
|
||||
{ mod2sparse *HT;
|
||||
HT = H;
|
||||
H = mod2sparse_allocate(N,M);
|
||||
mod2sparse_transpose(HT,H);
|
||||
M = mod2sparse_rows(H);
|
||||
N = mod2sparse_cols(H);
|
||||
}
|
||||
|
||||
af = open_file_std(alist_file,"wb");
|
||||
|
||||
if (af==NULL)
|
||||
{ fprintf(stderr,"Can't create alist file: %s\n",alist_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(af,"%d %d\n",M,N);
|
||||
|
||||
rw = (int *) chk_alloc (M, sizeof *rw);
|
||||
mxrw = 0;
|
||||
|
||||
for (i = 0; i<M; i++)
|
||||
{ rw[i] = mod2sparse_count_row(H,i);
|
||||
if (rw[i]>mxrw)
|
||||
{ mxrw = rw[i];
|
||||
}
|
||||
}
|
||||
|
||||
cw = (int *) chk_alloc (N, sizeof *cw);
|
||||
mxcw = 0;
|
||||
|
||||
for (j = 0; j<N; j++)
|
||||
{ cw[j] = mod2sparse_count_col(H,j);
|
||||
if (cw[j]>mxcw)
|
||||
{ mxcw = cw[j];
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(af,"%d %d\n",mxrw,mxcw);
|
||||
|
||||
for (i = 0; i<M; i++)
|
||||
{ fprintf(af,"%d%c",rw[i],i==M-1?'\n':' ');
|
||||
}
|
||||
|
||||
for (j = 0; j<N; j++)
|
||||
{ fprintf(af,"%d%c",cw[j],j==N-1?'\n':' ');
|
||||
}
|
||||
|
||||
for (i = 0; i<M; i++)
|
||||
{ e = mod2sparse_first_in_row(H,i);
|
||||
last = 0;
|
||||
for (k = 0; !last; k++)
|
||||
{ last = nozeros ? k==rw[i]-1 : k==mxrw-1;
|
||||
fprintf (af, "%d%c", mod2sparse_at_end(e)?0:mod2sparse_col(e)+1,
|
||||
last?'\n':' ');
|
||||
if (!mod2sparse_at_end(e))
|
||||
{ e = mod2sparse_next_in_row(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j<N; j++)
|
||||
{ e = mod2sparse_first_in_col(H,j);
|
||||
last = 0;
|
||||
for (k = 0; !last; k++)
|
||||
{ last = nozeros ? k==cw[j]-1 : k==mxcw-1;
|
||||
fprintf (af, "%d%c", mod2sparse_at_end(e)?0:mod2sparse_row(e)+1,
|
||||
last?'\n':' ');
|
||||
if (!mod2sparse_at_end(e))
|
||||
{ e = mod2sparse_next_in_col(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(af) || fclose(af)!=0)
|
||||
{ fprintf(stderr,"Error writing to alist file %s\n",alist_file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* PRINT USAGE MESSAGE AND EXIT. */
|
||||
|
||||
void usage(void)
|
||||
{ fprintf(stderr,"Usage: pchk-to-alist [ -t ] [ -z ] pchk-file alist-file\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
#include "decodedtext.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QRegularExpression>
|
||||
|
||||
extern "C" {
|
||||
bool stdmsg_(const char* msg, int len);
|
||||
}
|
||||
|
||||
DecodedText::DecodedText (QString const& the_string)
|
||||
: string_ {the_string}
|
||||
, padding_ {the_string.indexOf (" ") > 4 ? 2 : 0} // allow for
|
||||
// seconds
|
||||
, message_ {string_.mid (column_qsoText + padding_).trimmed ()}
|
||||
, is_standard_ {false}
|
||||
{
|
||||
if (message_.length() >= 1)
|
||||
{
|
||||
message_ = message_.left (22).remove (QRegularExpression {"[<>]"});
|
||||
int i1 = message_.indexOf ('\r');
|
||||
if (i1 > 0)
|
||||
{
|
||||
message_ = message_.left (i1 - 1);
|
||||
}
|
||||
// stdmsg is a fortran routine that packs the text, unpacks it and compares the result
|
||||
is_standard_ = stdmsg_ ((message_ + " ").toLatin1 ().constData (),22);
|
||||
}
|
||||
};
|
||||
|
||||
void DecodedText::removeAddedInfo ()
|
||||
{
|
||||
if (string_.indexOf (" CQ ") > 0) {
|
||||
// TODO this magic 37 characters is also referenced in DisplayText::_appendDXCCWorkedB4()
|
||||
auto eom_pos = string_.indexOf (' ', 37);
|
||||
if (eom_pos < 37) eom_pos = string_.size () - 1; // we always want at least the characters
|
||||
// to position 37
|
||||
string_ = string_.left (eom_pos + 1); // remove DXCC entity and worked B4 status. TODO need a better way to do this
|
||||
}
|
||||
}
|
||||
|
||||
QString DecodedText::CQersCall() const
|
||||
{
|
||||
QRegularExpression callsign_re {R"(^(CQ|DE|QRZ)(\s?DX|\s([A-Z]{2}|\d{3}))?\s(?<callsign>[A-Z0-9/]{2,})(\s[A-R]{2}[0-9]{2})?)"};
|
||||
return callsign_re.match (message_).captured ("callsign");
|
||||
}
|
||||
|
||||
|
||||
bool DecodedText::isJT65() const
|
||||
{
|
||||
return string_.indexOf("#") == column_mode + padding_;
|
||||
}
|
||||
|
||||
bool DecodedText::isJT9() const
|
||||
{
|
||||
return string_.indexOf("@") == column_mode + padding_;
|
||||
}
|
||||
|
||||
bool DecodedText::isTX() const
|
||||
{
|
||||
int i = string_.indexOf("Tx");
|
||||
return (i >= 0 && i < 15); // TODO guessing those numbers. Does Tx ever move?
|
||||
}
|
||||
|
||||
bool DecodedText::isLowConfidence () const
|
||||
{
|
||||
return QChar {'?'} == string_.mid (padding_ + column_qsoText + 21, 1);
|
||||
}
|
||||
|
||||
int DecodedText::frequencyOffset() const
|
||||
{
|
||||
return string_.mid(column_freq + padding_,4).toInt();
|
||||
}
|
||||
|
||||
int DecodedText::snr() const
|
||||
{
|
||||
int i1=string_.indexOf(" ")+1;
|
||||
return string_.mid(i1,3).toInt();
|
||||
}
|
||||
|
||||
float DecodedText::dt() const
|
||||
{
|
||||
return string_.mid(column_dt + padding_,5).toFloat();
|
||||
}
|
||||
|
||||
/*
|
||||
2343 -11 0.8 1259 # YV6BFE F6GUU R-08
|
||||
2343 -19 0.3 718 # VE6WQ SQ2NIJ -14
|
||||
2343 -7 0.3 815 # KK4DSD W7VP -16
|
||||
2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02
|
||||
|
||||
0605 Tx 1259 # CQ VK3ACF QF22
|
||||
*/
|
||||
|
||||
// find and extract any report. Returns true if this is a standard message
|
||||
bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report) const
|
||||
{
|
||||
if (message_.size () < 1) return false;
|
||||
|
||||
QStringList const& w = message_.split(" ",QString::SkipEmptyParts);
|
||||
if (w.size ()
|
||||
&& is_standard_ && (w[0] == myBaseCall
|
||||
|| w[0].endsWith ("/" + myBaseCall)
|
||||
|| w[0].startsWith (myBaseCall + "/")
|
||||
|| (w.size () > 1 && !dxBaseCall.isEmpty ()
|
||||
&& (w[1] == dxBaseCall
|
||||
|| w[1].endsWith ("/" + dxBaseCall)
|
||||
|| w[1].startsWith (dxBaseCall + "/")))))
|
||||
{
|
||||
QString tt="";
|
||||
if(w.size() > 2) tt=w[2];
|
||||
bool ok;
|
||||
auto i1=tt.toInt(&ok);
|
||||
if (ok and i1>=-50 and i1<50)
|
||||
{
|
||||
report = tt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tt.mid(0,1)=="R")
|
||||
{
|
||||
i1=tt.mid(1).toInt(&ok);
|
||||
if(ok and i1>=-50 and i1<50)
|
||||
{
|
||||
report = tt.mid(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return is_standard_;
|
||||
}
|
||||
|
||||
// get the first text word, usually the call
|
||||
QString DecodedText::call() const
|
||||
{
|
||||
auto call = string_;
|
||||
call = call.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
|
||||
int i = call.indexOf(" ");
|
||||
return call.mid(0,i);
|
||||
}
|
||||
|
||||
// get the second word, most likely the de call and the third word, most likely grid
|
||||
void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid) const
|
||||
{
|
||||
auto msg = string_;
|
||||
if(msg.mid(4,1)!=" ") msg=msg.mid(0,4)+msg.mid(6,-1); //Remove seconds from UTC
|
||||
msg = msg.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
|
||||
int i1 = msg.indexOf (" ");
|
||||
call = msg.mid (i1 + 1);
|
||||
int i2 = call.indexOf (" ");
|
||||
if (" R " == call.mid (i2, 3)) // MSK144 contest mode report
|
||||
{
|
||||
grid = call.mid (i2 + 3, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
grid = call.mid (i2 + 1, 4);
|
||||
}
|
||||
call = call.left (i2).replace (">", "");
|
||||
}
|
||||
|
||||
int DecodedText::timeInSeconds() const
|
||||
{
|
||||
return 60*string_.mid(column_time,2).toInt() + string_.mid(2,2).toInt();
|
||||
}
|
||||
|
||||
/*
|
||||
2343 -11 0.8 1259 # YV6BFE F6GUU R-08
|
||||
2343 -19 0.3 718 # VE6WQ SQ2NIJ -14
|
||||
2343 -7 0.3 815 # KK4DSD W7VP -16
|
||||
2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02
|
||||
|
||||
0605 Tx 1259 # CQ VK3ACF QF22
|
||||
*/
|
||||
|
||||
QString DecodedText::report() const // returns a string of the SNR field with a leading + or - followed by two digits
|
||||
{
|
||||
int sr = snr();
|
||||
if (sr<-50)
|
||||
sr = -50;
|
||||
else
|
||||
if (sr > 49)
|
||||
sr = 49;
|
||||
|
||||
QString rpt;
|
||||
rpt.sprintf("%d",abs(sr));
|
||||
if (sr > 9)
|
||||
rpt = "+" + rpt;
|
||||
else
|
||||
if (sr >= 0)
|
||||
rpt = "+0" + rpt;
|
||||
else
|
||||
if (sr >= -9)
|
||||
rpt = "-0" + rpt;
|
||||
else
|
||||
rpt = "-" + rpt;
|
||||
return rpt;
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2011-07-07T08:39:24
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += network multimedia
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
CONFIG += thread
|
||||
#CONFIG += console
|
||||
|
||||
TARGET = wsjtx
|
||||
VERSION = "Not for Release"
|
||||
TEMPLATE = app
|
||||
DEFINES = QT5
|
||||
QMAKE_CXXFLAGS += -std=c++11
|
||||
DEFINES += PROJECT_MANUAL="'\"http://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/wsjtx-main.html\"'"
|
||||
|
||||
isEmpty (DESTDIR) {
|
||||
DESTDIR = ../wsjtx_exp_install
|
||||
}
|
||||
|
||||
isEmpty (HAMLIB_DIR) {
|
||||
HAMLIB_DIR = ../../hamlib3/mingw32
|
||||
}
|
||||
|
||||
isEmpty (FFTW3_DIR) {
|
||||
FFTW3_DIR = .
|
||||
}
|
||||
|
||||
F90 = gfortran
|
||||
gfortran.output = ${QMAKE_FILE_BASE}.o
|
||||
gfortran.commands = $$F90 -c -O2 -o ${QMAKE_FILE_OUT} ${QMAKE_FILE_NAME}
|
||||
gfortran.input = F90_SOURCES
|
||||
QMAKE_EXTRA_COMPILERS += gfortran
|
||||
|
||||
win32 {
|
||||
DEFINES += WIN32
|
||||
QT += axcontainer
|
||||
TYPELIBS = $$system(dumpcpp -getfile {4FE359C5-A58F-459D-BE95-CA559FB4F270})
|
||||
}
|
||||
|
||||
unix {
|
||||
DEFINES += UNIX
|
||||
}
|
||||
|
||||
#
|
||||
# Order matters here as the link is in this order so referrers need to be after referred
|
||||
#
|
||||
SOURCES += \
|
||||
logbook/adif.cpp \
|
||||
logbook/countrydat.cpp \
|
||||
logbook/countriesworked.cpp \
|
||||
logbook/logbook.cpp \
|
||||
astro.cpp Radio.cpp NetworkServerLookup.cpp revision_utils.cpp \
|
||||
Transceiver.cpp TransceiverBase.cpp TransceiverFactory.cpp \
|
||||
PollingTransceiver.cpp EmulateSplitTransceiver.cpp LettersSpinBox.cpp \
|
||||
HRDTransceiver.cpp DXLabSuiteCommanderTransceiver.cpp \
|
||||
HamlibTransceiver.cpp FrequencyLineEdit.cpp Bands.cpp \
|
||||
FrequencyList.cpp StationList.cpp ForeignKeyDelegate.cpp \
|
||||
FrequencyItemDelegate.cpp LiveFrequencyValidator.cpp \
|
||||
Configuration.cpp psk_reporter.cpp AudioDevice.cpp \
|
||||
Modulator.cpp Detector.cpp logqso.cpp displaytext.cpp \
|
||||
getfile.cpp soundout.cpp soundin.cpp meterwidget.cpp signalmeter.cpp \
|
||||
WFPalette.cpp plotter.cpp widegraph.cpp about.cpp WsprTxScheduler.cpp mainwindow.cpp \
|
||||
main.cpp decodedtext.cpp wsprnet.cpp messageaveraging.cpp \
|
||||
echoplot.cpp echograph.cpp fastgraph.cpp fastplot.cpp Modes.cpp \
|
||||
WSPRBandHopping.cpp MessageAggregator.cpp SampleDownloader.cpp qt_helpers.cpp\
|
||||
MultiSettings.cpp PhaseEqualizationDialog.cpp
|
||||
|
||||
HEADERS += qt_helpers.hpp \
|
||||
pimpl_h.hpp pimpl_impl.hpp \
|
||||
Radio.hpp NetworkServerLookup.hpp revision_utils.hpp \
|
||||
mainwindow.h plotter.h soundin.h soundout.h astro.h \
|
||||
about.h WFPalette.hpp widegraph.h getfile.h decodedtext.h \
|
||||
commons.h sleep.h displaytext.h logqso.h LettersSpinBox.hpp \
|
||||
Bands.hpp FrequencyList.hpp StationList.hpp ForeignKeyDelegate.hpp FrequencyItemDelegate.hpp LiveFrequencyValidator.hpp \
|
||||
FrequencyLineEdit.hpp AudioDevice.hpp Detector.hpp Modulator.hpp psk_reporter.h \
|
||||
Transceiver.hpp TransceiverBase.hpp TransceiverFactory.hpp PollingTransceiver.hpp \
|
||||
EmulateSplitTransceiver.hpp DXLabSuiteCommanderTransceiver.hpp HamlibTransceiver.hpp \
|
||||
Configuration.hpp wsprnet.h signalmeter.h meterwidget.h \
|
||||
logbook/logbook.h logbook/countrydat.h logbook/countriesworked.h logbook/adif.h \
|
||||
messageaveraging.h echoplot.h echograph.h fastgraph.h fastplot.h Modes.hpp WSPRBandHopping.hpp \
|
||||
WsprTxScheduler.h SampleDownloader.hpp MultiSettings.hpp PhaseEqualizationDialog.hpp
|
||||
|
||||
INCLUDEPATH += qmake_only
|
||||
|
||||
win32 {
|
||||
SOURCES += killbyname.cpp OmniRigTransceiver.cpp
|
||||
HEADERS += OmniRigTransceiver.hpp
|
||||
}
|
||||
|
||||
FORMS += mainwindow.ui about.ui Configuration.ui widegraph.ui astro.ui \
|
||||
logqso.ui wf_palette_design_dialog.ui messageaveraging.ui echograph.ui \
|
||||
fastgraph.ui
|
||||
|
||||
RC_FILE = wsjtx.rc
|
||||
RESOURCES = wsjtx.qrc
|
||||
|
||||
unix {
|
||||
LIBS += -L lib -ljt9
|
||||
LIBS += -lhamlib
|
||||
LIBS += -lfftw3f $$system($$F90 -print-file-name=libgfortran.so)
|
||||
}
|
||||
|
||||
win32 {
|
||||
INCLUDEPATH += $${HAMLIB_DIR}/include
|
||||
INCLUDEPATH += C:\JTSDK\wsjtx_exp\build\Release
|
||||
INCLUDEPATH += C:\JTSDK\hamlib3\include
|
||||
INCLUDEPATH += C:\JTSDK\qt5\5.2.1\mingw48_32\include\QtSerialPort
|
||||
|
||||
LIBS += -L$${HAMLIB_DIR}/lib -lhamlib
|
||||
LIBS += -L./lib -lastro -ljt9
|
||||
LIBS += -L$${FFTW3_DIR} -lfftw3f-3
|
||||
LIBS += -lws2_32
|
||||
LIBS += $$system($$F90 -print-file-name=libgfortran.a)
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
subroutine pctile(x,npts,npct,xpct)
|
||||
|
||||
parameter (NMAX=100000)
|
||||
real*4 x(npts)
|
||||
real*4 tmp(NMAX)
|
||||
|
||||
if(npts.le.0) then
|
||||
xpct=1.0
|
||||
go to 900
|
||||
endif
|
||||
if(npts.gt.NMAX) stop
|
||||
|
||||
tmp(1:npts)=x
|
||||
call shell(npts,tmp)
|
||||
j=nint(npts*0.01*npct)
|
||||
if(j.lt.1) j=1
|
||||
if(j.gt.npts) j=npts
|
||||
xpct=tmp(j)
|
||||
|
||||
900 continue
|
||||
return
|
||||
end subroutine pctile
|
||||
@@ -1,98 +0,0 @@
|
||||
For this step and the next, you may want to pretend you are K1JT
|
||||
by entering that callsign temporarily as *My Call* on the
|
||||
*Settings | General* tab. Your results should then be identical to
|
||||
those shown in the screen shot below.
|
||||
|
||||
.Open a Wave File:
|
||||
|
||||
- Select *File | Open* and select the file
|
||||
+...\save\samples\JT9\130418_1742.wav+. When the file opens you should
|
||||
see something similar to the following screen shot:
|
||||
|
||||
[[X12]]
|
||||
image::main-ui.png[align="center",alt="Main UI and Wide Graph"]
|
||||
|
||||
.Decoding Overview
|
||||
|
||||
Decoding takes place at the end of a receive sequence and proceeds in
|
||||
two steps. The first decode is done at the selected Rx frequency,
|
||||
indicated by the U-shaped green marker on the waterfall scale.
|
||||
Results appear in both the left (*Band Activity*) and right (*Rx
|
||||
Frequency*) text windows on the main screen. The program then finds
|
||||
and decodes all signals in the selected mode over the displayed
|
||||
frequency range. The red marker on the waterfall scale indicates your
|
||||
Tx frequency.
|
||||
|
||||
Seven JT9 signals are present in the example file, all decodable.
|
||||
When this file was recorded KF4RWA was finishing a QSO with K1JT.
|
||||
Since the green marker was placed at his audio frequency, 1224 Hz, his
|
||||
message `K1JT KF4RWA 73` is decoded first and appears in the *Rx
|
||||
Frequency* window. The *Band Activity* window shows this message plus
|
||||
all decodes at other frequencies. By default lines containing `CQ`
|
||||
are highlighted in green, and lines with *My Call* (in this case K1JT)
|
||||
in red.
|
||||
|
||||
[[X13]]
|
||||
.Decoding Controls
|
||||
|
||||
To gain some feeling for controls frequently used when making QSOs,
|
||||
try clicking with the mouse on the decoded text lines and on the
|
||||
waterfall spectral display. You should be able to confirm the
|
||||
following behavior:
|
||||
|
||||
- Double-click on either of the decoded lines highlighted in
|
||||
green. This action produces the following results:
|
||||
|
||||
** Callsign and locator of a station calling CQ are copied to the *DX
|
||||
Call* and *DX Grid* entry fields.
|
||||
|
||||
** Messages are generated for a standard minimal QSO.
|
||||
|
||||
** The *Tx even* box is checked or cleared appropriately, so that you
|
||||
will transmit in the proper (odd or even) minutes.
|
||||
|
||||
** The Rx and Tx frequency markers are moved to the frequency of the
|
||||
CQing station.
|
||||
|
||||
** The *Gen Msg* ("`generated message`") radio button at bottom right
|
||||
of the main window is selected.
|
||||
|
||||
** If you had checked *Double-click on call sets Tx Enable* on the
|
||||
*Setup* menu, *Enable Tx* would be activated and a transmission would
|
||||
start automatically at the proper time.
|
||||
|
||||
- Double-click on the decoded message `K1JT N5KDV EM41`,
|
||||
highlighted in red. Results will be similar to those in the
|
||||
previous step, except the Tx frequency (red marker) is not
|
||||
moved. Such messages are usually in response to your own CQ, or from
|
||||
a tail-ender, and you probably want your Tx frequency to stay where it
|
||||
was.
|
||||
|
||||
- By holding down the *Ctrl* key when double-clicking on a decoded
|
||||
line you can cause both Tx and Rx frequencies to be moved. This
|
||||
behavior can also be forced by checking *Lock Tx=Rx*.
|
||||
|
||||
- Double-click on the message from KF4RWA in either window. He is
|
||||
sending `73` to K1JT, signifying that the QSO is over. Most likely
|
||||
you want to send 73 to him, so the message `KF4RWA K1JT 73` is
|
||||
automatically generated and selected for your next transmission.
|
||||
(Alternatively, you might choose to send a free-text message or to
|
||||
call CQ again.)
|
||||
|
||||
- Click somewhere on the waterfall to set Rx frequency (green marker
|
||||
on waterfall scale).
|
||||
|
||||
- Shift-click on the waterfall to set Tx frequency (red marker).
|
||||
|
||||
- Ctrl-click on the waterfall to set both Rx and Tx frequencies.
|
||||
|
||||
- Double-click on a signal in the waterfall to set Rx frequency and
|
||||
start a narrow-band decode there. Decoded text will appear in the
|
||||
right window only.
|
||||
|
||||
- Ctrl-double-click on a signal to set both Rx and Tx frequencies and
|
||||
decode at the new frequency.
|
||||
|
||||
- Click *Erase* to clear the right window.
|
||||
|
||||
- Double-click *Erase* to clear both text windows.
|
||||
@@ -1,241 +0,0 @@
|
||||
#include "displaytext.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QDateTime>
|
||||
#include <QTextCharFormat>
|
||||
#include <QTextCursor>
|
||||
#include <QTextBlock>
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
|
||||
#include "qt_helpers.hpp"
|
||||
|
||||
#include "moc_displaytext.cpp"
|
||||
|
||||
DisplayText::DisplayText(QWidget *parent)
|
||||
: QTextEdit(parent)
|
||||
, erase_action_ {new QAction {tr ("&Erase"), this}}
|
||||
{
|
||||
setReadOnly (true);
|
||||
viewport ()->setCursor (Qt::ArrowCursor);
|
||||
setWordWrapMode (QTextOption::NoWrap);
|
||||
|
||||
// max lines to limit heap usage
|
||||
document ()->setMaximumBlockCount (5000);
|
||||
|
||||
// context menu erase action
|
||||
setContextMenuPolicy (Qt::CustomContextMenu);
|
||||
connect (this, &DisplayText::customContextMenuRequested, [this] (QPoint const& position) {
|
||||
auto * menu = createStandardContextMenu (position);
|
||||
menu->addAction (erase_action_);
|
||||
menu->exec (mapToGlobal (position));
|
||||
delete menu;
|
||||
});
|
||||
connect (erase_action_, &QAction::triggered, this, &DisplayText::erase);
|
||||
}
|
||||
|
||||
void DisplayText::erase ()
|
||||
{
|
||||
clear ();
|
||||
Q_EMIT erased ();
|
||||
}
|
||||
|
||||
void DisplayText::setContentFont(QFont const& font)
|
||||
{
|
||||
char_font_ = font;
|
||||
selectAll ();
|
||||
auto cursor = textCursor ();
|
||||
cursor.beginEditBlock ();
|
||||
auto char_format = cursor.charFormat ();
|
||||
char_format.setFont (char_font_);
|
||||
cursor.mergeCharFormat (char_format);
|
||||
cursor.clearSelection ();
|
||||
cursor.movePosition (QTextCursor::End);
|
||||
|
||||
// position so viewport scrolled to left
|
||||
cursor.movePosition (QTextCursor::Up);
|
||||
cursor.movePosition (QTextCursor::StartOfLine);
|
||||
cursor.endEditBlock ();
|
||||
|
||||
setTextCursor (cursor);
|
||||
ensureCursorVisible ();
|
||||
}
|
||||
|
||||
void DisplayText::mouseDoubleClickEvent(QMouseEvent *e)
|
||||
{
|
||||
bool ctrl = (e->modifiers() & Qt::ControlModifier);
|
||||
bool alt = (e->modifiers() & Qt::AltModifier);
|
||||
emit(selectCallsign(alt,ctrl));
|
||||
QTextEdit::mouseDoubleClickEvent(e);
|
||||
}
|
||||
|
||||
void DisplayText::insertLineSpacer(QString const& line)
|
||||
{
|
||||
appendText (line, "#d3d3d3");
|
||||
}
|
||||
|
||||
void DisplayText::appendText(QString const& text, QColor bg)
|
||||
{
|
||||
auto cursor = textCursor ();
|
||||
cursor.movePosition (QTextCursor::End);
|
||||
auto block_format = cursor.blockFormat ();
|
||||
block_format.setBackground (bg);
|
||||
if (0 == cursor.position ())
|
||||
{
|
||||
cursor.setBlockFormat (block_format);
|
||||
auto char_format = cursor.charFormat ();
|
||||
char_format.setFont (char_font_);
|
||||
cursor.setCharFormat (char_format);
|
||||
}
|
||||
else
|
||||
{
|
||||
cursor.insertBlock (block_format);
|
||||
}
|
||||
cursor.insertText (text);
|
||||
|
||||
// position so viewport scrolled to left
|
||||
cursor.movePosition (QTextCursor::StartOfLine);
|
||||
setTextCursor (cursor);
|
||||
ensureCursorVisible ();
|
||||
document ()->setMaximumBlockCount (document ()->maximumBlockCount ());
|
||||
}
|
||||
|
||||
|
||||
QString DisplayText::appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg,
|
||||
LogBook const& logBook, QColor color_CQ,
|
||||
QColor color_DXCC,
|
||||
QColor color_NewCall)
|
||||
{
|
||||
// allow for seconds
|
||||
int padding {message.indexOf (" ") > 4 ? 2 : 0};
|
||||
QString call = callsign;
|
||||
QString countryName;
|
||||
bool callWorkedBefore;
|
||||
bool countryWorkedBefore;
|
||||
|
||||
if(call.length()==2) {
|
||||
int i0=message.indexOf("CQ "+call);
|
||||
call=message.mid(i0+6,-1);
|
||||
i0=call.indexOf(" ");
|
||||
call=call.mid(0,i0);
|
||||
}
|
||||
if(call.length()<3) return message;
|
||||
if(!call.contains(QRegExp("[0-9]|[A-Z]"))) return message;
|
||||
|
||||
logBook.match(/*in*/call,/*out*/countryName,callWorkedBefore,countryWorkedBefore);
|
||||
|
||||
message = message.trimmed ();
|
||||
QString appendage;
|
||||
if (!countryWorkedBefore) // therefore not worked call either
|
||||
{
|
||||
appendage += "!";
|
||||
*bg = color_DXCC;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!callWorkedBefore) // but have worked the country
|
||||
{
|
||||
appendage += "~";
|
||||
*bg = color_NewCall;
|
||||
}
|
||||
else
|
||||
{
|
||||
appendage += " "; // have worked this call before
|
||||
*bg = color_CQ;
|
||||
}
|
||||
}
|
||||
|
||||
// do some obvious abbreviations
|
||||
countryName.replace ("Islands", "Is.");
|
||||
countryName.replace ("Island", "Is.");
|
||||
countryName.replace ("North ", "N. ");
|
||||
countryName.replace ("Northern ", "N. ");
|
||||
countryName.replace ("South ", "S. ");
|
||||
countryName.replace ("East ", "E. ");
|
||||
countryName.replace ("Eastern ", "E. ");
|
||||
countryName.replace ("West ", "W. ");
|
||||
countryName.replace ("Western ", "W. ");
|
||||
countryName.replace ("Central ", "C. ");
|
||||
countryName.replace (" and ", " & ");
|
||||
countryName.replace ("Republic", "Rep.");
|
||||
countryName.replace ("United States", "U.S.A.");
|
||||
countryName.replace ("Fed. Rep. of ", "");
|
||||
countryName.replace ("French ", "Fr.");
|
||||
countryName.replace ("Asiatic", "AS");
|
||||
countryName.replace ("European", "EU");
|
||||
countryName.replace ("African", "AF");
|
||||
|
||||
appendage += countryName;
|
||||
|
||||
// use a nbsp to save the start of appended text so we can find
|
||||
// it again later, align appended data at a fixed column if
|
||||
// there is space otherwise let it float to the right
|
||||
int space_count {40 + padding - message.size ()};
|
||||
if (space_count > 0)
|
||||
{
|
||||
message += QString {space_count, QChar {' '}};
|
||||
}
|
||||
message += QChar::Nbsp + appendage;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void DisplayText::displayDecodedText(DecodedText const& decodedText, QString const& myCall,
|
||||
bool displayDXCCEntity, LogBook const& logBook,
|
||||
QColor color_CQ, QColor color_MyCall,
|
||||
QColor color_DXCC, QColor color_NewCall)
|
||||
{
|
||||
QColor bg {Qt::white};
|
||||
bool CQcall = false;
|
||||
if (decodedText.string ().contains (" CQ ")
|
||||
|| decodedText.string ().contains (" CQDX ")
|
||||
|| decodedText.string ().contains (" QRZ "))
|
||||
{
|
||||
CQcall = true;
|
||||
bg = color_CQ;
|
||||
}
|
||||
if (myCall != "" and (
|
||||
decodedText.indexOf (" " + myCall + " ") >= 0
|
||||
or decodedText.indexOf (" " + myCall + "/") >= 0
|
||||
or decodedText.indexOf ("/" + myCall + " ") >= 0
|
||||
or decodedText.indexOf ("<" + myCall + " ") >= 0
|
||||
or decodedText.indexOf (" " + myCall + ">") >= 0)) {
|
||||
bg = color_MyCall;
|
||||
}
|
||||
auto message = decodedText.string ();
|
||||
message = message.left (message.indexOf (QChar::Nbsp)); // strip appended info
|
||||
if (displayDXCCEntity && CQcall)
|
||||
// if enabled add the DXCC entity and B4 status to the end of the
|
||||
// preformated text line t1
|
||||
message = appendDXCCWorkedB4 (message, decodedText.CQersCall (), &bg, logBook, color_CQ,
|
||||
color_DXCC, color_NewCall);
|
||||
appendText (message.trimmed (), bg);
|
||||
}
|
||||
|
||||
|
||||
void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
|
||||
QColor color_TxMsg, bool bFastMode)
|
||||
{
|
||||
QString t1=" @ ";
|
||||
if(modeTx=="FT8") t1=" ~ ";
|
||||
if(modeTx=="JT4") t1=" $ ";
|
||||
if(modeTx=="JT65") t1=" # ";
|
||||
if(modeTx=="MSK144") t1=" & ";
|
||||
QString t2;
|
||||
t2.sprintf("%4d",txFreq);
|
||||
QString t;
|
||||
if(bFastMode or modeTx=="FT8") {
|
||||
t = QDateTime::currentDateTimeUtc().toString("hhmmss") + \
|
||||
" Tx " + t2 + t1 + text;
|
||||
} else {
|
||||
t = QDateTime::currentDateTimeUtc().toString("hhmm") + \
|
||||
" Tx " + t2 + t1 + text;
|
||||
}
|
||||
appendText (t, color_TxMsg);
|
||||
}
|
||||
|
||||
void DisplayText::displayQSY(QString text)
|
||||
{
|
||||
QString t = QDateTime::currentDateTimeUtc().toString("hhmmss") + " " + text;
|
||||
appendText (t, "hotpink");
|
||||
}
|
||||
|
Before Width: | Height: | Size: 87 KiB |
@@ -1,41 +0,0 @@
|
||||
// -*- Mode: C++ -*-
|
||||
#ifndef DISPLAYTEXT_H
|
||||
#define DISPLAYTEXT_H
|
||||
|
||||
#include <QTextEdit>
|
||||
#include <QFont>
|
||||
|
||||
#include "logbook/logbook.h"
|
||||
#include "decodedtext.h"
|
||||
|
||||
class DisplayText
|
||||
: public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DisplayText(QWidget *parent = 0);
|
||||
|
||||
void setContentFont (QFont const&);
|
||||
void insertLineSpacer(QString const&);
|
||||
void displayDecodedText(DecodedText const& decodedText, QString const& myCall, bool displayDXCCEntity,
|
||||
LogBook const& logBook, QColor color_CQ, QColor color_MyCall,
|
||||
QColor color_DXCC, QColor color_NewCall);
|
||||
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
|
||||
QColor color_TxMsg, bool bFastMode);
|
||||
void displayQSY(QString text);
|
||||
|
||||
Q_SIGNAL void selectCallsign (bool alt, bool ctrl);
|
||||
|
||||
Q_SLOT void appendText (QString const& text, QColor bg = Qt::white);
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent *e);
|
||||
|
||||
private:
|
||||
QString appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg, LogBook const& logBook,
|
||||
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
|
||||
|
||||
QFont char_font_;
|
||||
};
|
||||
|
||||
#endif // DISPLAYTEXT_H
|
||||
@@ -1,261 +0,0 @@
|
||||
#ifndef CONFIGURATION_HPP_
|
||||
#define CONFIGURATION_HPP_
|
||||
|
||||
#include <QObject>
|
||||
#include <QFont>
|
||||
|
||||
#include "Radio.hpp"
|
||||
#include "IARURegions.hpp"
|
||||
#include "AudioDevice.hpp"
|
||||
#include "Transceiver.hpp"
|
||||
|
||||
#include "pimpl_h.hpp"
|
||||
|
||||
class QSettings;
|
||||
class QWidget;
|
||||
class QAudioDeviceInfo;
|
||||
class QString;
|
||||
class QDir;
|
||||
class Bands;
|
||||
class FrequencyList;
|
||||
class StationList;
|
||||
class QStringListModel;
|
||||
class QHostAddress;
|
||||
|
||||
//
|
||||
// Class Configuration
|
||||
//
|
||||
// Encapsulates the control, access and, persistence of user defined
|
||||
// settings for the wsjtx GUI. Setting values are accessed through a
|
||||
// QDialog window containing concept orientated tab windows.
|
||||
//
|
||||
// Responsibilities
|
||||
//
|
||||
// Provides management of the CAT and PTT rig interfaces, providing
|
||||
// control access via a minimal generic set of Qt slots and status
|
||||
// updates via Qt signals. Internally the rig control capability is
|
||||
// farmed out to a separate thread since many of the rig control
|
||||
// functions are blocking.
|
||||
//
|
||||
// All user settings required by the wsjtx GUI are exposed through
|
||||
// query methods. Settings only become visible once they have been
|
||||
// accepted by the user which is done by clicking the "OK" button on
|
||||
// the settings dialog.
|
||||
//
|
||||
// The QSettings instance passed to the constructor is used to read
|
||||
// and write user settings.
|
||||
//
|
||||
// Pointers to three QAbstractItemModel objects are provided to give
|
||||
// access to amateur band information, user working frequencies and,
|
||||
// user operating band information. These porovide consistent data
|
||||
// models that can be used in GUI lists or tables or simply queried
|
||||
// for user defined bands, default operating frequencies and, station
|
||||
// descriptions.
|
||||
//
|
||||
class Configuration final
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS (DataMode Type2MsgGen)
|
||||
|
||||
public:
|
||||
using MODE = Transceiver::MODE;
|
||||
using TransceiverState = Transceiver::TransceiverState;
|
||||
using Frequency = Radio::Frequency;
|
||||
using port_type = quint16;
|
||||
|
||||
enum DataMode {data_mode_none, data_mode_USB, data_mode_data};
|
||||
Q_ENUM (DataMode)
|
||||
enum Type2MsgGen {type_2_msg_1_full, type_2_msg_3_full, type_2_msg_5_only};
|
||||
Q_ENUM (Type2MsgGen)
|
||||
|
||||
explicit Configuration (QDir const& temp_directory, QSettings * settings,
|
||||
QWidget * parent = nullptr);
|
||||
~Configuration ();
|
||||
|
||||
int exec ();
|
||||
bool is_active () const;
|
||||
|
||||
QDir temp_dir () const;
|
||||
QDir doc_dir () const;
|
||||
QDir data_dir () const;
|
||||
QDir writeable_data_dir () const;
|
||||
|
||||
QAudioDeviceInfo const& audio_input_device () const;
|
||||
AudioDevice::Channel audio_input_channel () const;
|
||||
QAudioDeviceInfo const& audio_output_device () const;
|
||||
AudioDevice::Channel audio_output_channel () const;
|
||||
|
||||
// These query methods should be used after a call to exec() to
|
||||
// determine if either the audio input or audio output stream
|
||||
// parameters have changed. The respective streams should be
|
||||
// re-opened if they return true.
|
||||
bool restart_audio_input () const;
|
||||
bool restart_audio_output () const;
|
||||
|
||||
QString my_callsign () const;
|
||||
QString my_grid () const;
|
||||
QFont decoded_text_font () const;
|
||||
qint32 id_interval () const;
|
||||
qint32 ntrials() const;
|
||||
qint32 aggressive() const;
|
||||
qint32 RxBandwidth() const;
|
||||
double degrade() const;
|
||||
double txDelay() const;
|
||||
bool id_after_73 () const;
|
||||
bool tx_QSY_allowed () const;
|
||||
bool spot_to_psk_reporter () const;
|
||||
bool monitor_off_at_startup () const;
|
||||
bool monitor_last_used () const;
|
||||
bool log_as_RTTY () const;
|
||||
bool report_in_comments () const;
|
||||
bool prompt_to_log () const;
|
||||
bool insert_blank () const;
|
||||
bool DXCC () const;
|
||||
bool clear_DX () const;
|
||||
bool miles () const;
|
||||
bool quick_call () const;
|
||||
bool disable_TX_on_73 () const;
|
||||
int watchdog () const;
|
||||
bool TX_messages () const;
|
||||
bool split_mode () const;
|
||||
bool enable_VHF_features () const;
|
||||
bool decode_at_52s () const;
|
||||
bool single_decode () const;
|
||||
bool twoPass() const;
|
||||
bool x2ToneSpacing() const;
|
||||
bool contestMode() const;
|
||||
bool realTimeDecode() const;
|
||||
bool MyDx() const;
|
||||
bool CQMyN() const;
|
||||
bool NDxG() const;
|
||||
bool NN() const;
|
||||
bool EMEonly() const;
|
||||
bool post_decodes () const;
|
||||
QString udp_server_name () const;
|
||||
port_type udp_server_port () const;
|
||||
bool accept_udp_requests () const;
|
||||
bool udpWindowToFront () const;
|
||||
bool udpWindowRestore () const;
|
||||
Bands * bands ();
|
||||
Bands const * bands () const;
|
||||
IARURegions::Region region () const;
|
||||
FrequencyList * frequencies ();
|
||||
FrequencyList const * frequencies () const;
|
||||
StationList * stations ();
|
||||
StationList const * stations () const;
|
||||
QStringListModel * macros ();
|
||||
QStringListModel const * macros () const;
|
||||
QDir save_directory () const;
|
||||
QDir azel_directory () const;
|
||||
QString rig_name () const;
|
||||
Type2MsgGen type_2_msg_gen () const;
|
||||
QColor color_CQ () const;
|
||||
QColor color_MyCall () const;
|
||||
QColor color_TxMsg () const;
|
||||
QColor color_DXCC () const;
|
||||
QColor color_NewCall () const;
|
||||
bool pwrBandTxMemory () const;
|
||||
bool pwrBandTuneMemory () const;
|
||||
// This method queries if a CAT and PTT connection is operational.
|
||||
bool is_transceiver_online () const;
|
||||
|
||||
// Start the rig connection, safe and normal to call when rig is
|
||||
// already open.
|
||||
bool transceiver_online ();
|
||||
|
||||
// check if a real rig is configured
|
||||
bool is_dummy_rig () const;
|
||||
|
||||
// Frequency resolution of the rig
|
||||
//
|
||||
// 0 - 1Hz
|
||||
// 1 - 10Hz rounded
|
||||
// -1 - 10Hz truncated
|
||||
// 2 - 100Hz rounded
|
||||
// -2 - 100Hz truncated
|
||||
int transceiver_resolution () const;
|
||||
|
||||
// Close down connection to rig.
|
||||
void transceiver_offline ();
|
||||
|
||||
// Set transceiver frequency in Hertz.
|
||||
Q_SLOT void transceiver_frequency (Frequency);
|
||||
|
||||
// Setting a non zero TX frequency means split operation
|
||||
// rationalise_mode means ensure TX uses same mode as RX.
|
||||
Q_SLOT void transceiver_tx_frequency (Frequency = 0u);
|
||||
|
||||
// Set transceiver mode.
|
||||
//
|
||||
// Rationalise means ensure TX uses same mode as RX.
|
||||
Q_SLOT void transceiver_mode (MODE);
|
||||
|
||||
// Set/unset PTT.
|
||||
//
|
||||
// Note that this must be called even if VOX PTT is selected since
|
||||
// the "Emulate Split" mode requires PTT information to coordinate
|
||||
// frequency changes.
|
||||
Q_SLOT void transceiver_ptt (bool = true);
|
||||
|
||||
// Attempt to (re-)synchronise transceiver state.
|
||||
//
|
||||
// Force signal guarantees either a transceiver_update or a
|
||||
// transceiver_failure signal.
|
||||
//
|
||||
// The enforce_mode_and_split parameter ensures that future
|
||||
// transceiver updates have the correct mode and split setting
|
||||
// i.e. the transceiver is ready for use.
|
||||
Q_SLOT void sync_transceiver (bool force_signal = false, bool enforce_mode_and_split = false);
|
||||
|
||||
|
||||
//
|
||||
// This signal indicates that a font has been selected and accepted
|
||||
// for the decoded text.
|
||||
//
|
||||
Q_SIGNAL void decoded_text_font_changed (QFont);
|
||||
|
||||
//
|
||||
// This signal is emitted when the UDP server changes
|
||||
//
|
||||
Q_SIGNAL void udp_server_changed (QString const& udp_server);
|
||||
Q_SIGNAL void udp_server_port_changed (port_type server_port);
|
||||
|
||||
|
||||
//
|
||||
// These signals are emitted and reflect transceiver state changes
|
||||
//
|
||||
|
||||
// signals a change in one of the TransceiverState members
|
||||
Q_SIGNAL void transceiver_update (Transceiver::TransceiverState const&) const;
|
||||
|
||||
// Signals a failure of a control rig CAT or PTT connection.
|
||||
//
|
||||
// A failed rig CAT or PTT connection is fatal and the underlying
|
||||
// connections are closed automatically. The connections can be
|
||||
// re-established with a call to transceiver_online(true) assuming
|
||||
// the fault condition has been rectified or is transient.
|
||||
Q_SIGNAL void transceiver_failure (QString const& reason) const;
|
||||
|
||||
private:
|
||||
class impl;
|
||||
pimpl<impl> m_;
|
||||
};
|
||||
|
||||
#if QT_VERSION < 0x050500
|
||||
Q_DECLARE_METATYPE (Configuration::DataMode);
|
||||
Q_DECLARE_METATYPE (Configuration::Type2MsgGen);
|
||||
#endif
|
||||
|
||||
#if !defined (QT_NO_DEBUG_STREAM)
|
||||
ENUM_QDEBUG_OPS_DECL (Configuration, DataMode);
|
||||
ENUM_QDEBUG_OPS_DECL (Configuration, Type2MsgGen);
|
||||
#endif
|
||||
|
||||
ENUM_QDATASTREAM_OPS_DECL (Configuration, DataMode);
|
||||
ENUM_QDATASTREAM_OPS_DECL (Configuration, Type2MsgGen);
|
||||
|
||||
ENUM_CONVERSION_OPS_DECL (Configuration, DataMode);
|
||||
ENUM_CONVERSION_OPS_DECL (Configuration, Type2MsgGen);
|
||||
|
||||
#endif
|
||||
@@ -1,96 +0,0 @@
|
||||
#include "IARURegions.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QModelIndex>
|
||||
#include <QMetaType>
|
||||
|
||||
#include "moc_IARURegions.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
// human readable strings for each Region enumeration value
|
||||
char const * const region_names[] =
|
||||
{
|
||||
"All",
|
||||
"Region 1",
|
||||
"Region 2",
|
||||
"Region 3",
|
||||
};
|
||||
std::size_t constexpr region_names_size = sizeof (region_names) / sizeof (region_names[0]);
|
||||
}
|
||||
|
||||
IARURegions::IARURegions (QObject * parent)
|
||||
: QAbstractListModel {parent}
|
||||
{
|
||||
static_assert (region_names_size == SENTINAL,
|
||||
"region_names array must match Region enumeration");
|
||||
}
|
||||
|
||||
char const * IARURegions::name (Region r)
|
||||
{
|
||||
return region_names[static_cast<int> (r)];
|
||||
}
|
||||
|
||||
auto IARURegions::value (int r) -> Region
|
||||
{
|
||||
if (r < 0 || r + 1 >= SENTINAL) return ALL;
|
||||
return static_cast<Region> (r);
|
||||
}
|
||||
|
||||
QVariant IARURegions::data (QModelIndex const& index, int role) const
|
||||
{
|
||||
QVariant item;
|
||||
|
||||
if (index.isValid ())
|
||||
{
|
||||
auto const& row = index.row ();
|
||||
switch (role)
|
||||
{
|
||||
case Qt::ToolTipRole:
|
||||
case Qt::AccessibleDescriptionRole:
|
||||
item = tr ("IARU Region");
|
||||
break;
|
||||
|
||||
case Qt::EditRole:
|
||||
item = static_cast<Region> (row);
|
||||
break;
|
||||
|
||||
case Qt::DisplayRole:
|
||||
case Qt::AccessibleTextRole:
|
||||
item = region_names[row];
|
||||
break;
|
||||
|
||||
case Qt::TextAlignmentRole:
|
||||
item = Qt::AlignHCenter + Qt::AlignVCenter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
QVariant IARURegions::headerData (int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
QVariant result;
|
||||
|
||||
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
|
||||
{
|
||||
result = tr ("IARU Region");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = QAbstractListModel::headerData (section, orientation, role);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined (QT_NO_DEBUG_STREAM)
|
||||
ENUM_QDEBUG_OPS_IMPL (IARURegions, Region);
|
||||
#endif
|
||||
|
||||
ENUM_QDATASTREAM_OPS_IMPL (IARURegions, Region);
|
||||
ENUM_CONVERSION_OPS_IMPL (IARURegions, Region);
|
||||
@@ -1,6 +1,23 @@
|
||||
module crc
|
||||
use, intrinsic :: iso_c_binding, only: c_int, c_loc, c_int8_t, c_bool, c_short
|
||||
interface
|
||||
|
||||
function crc14 (data, length) bind (C, name="crc14")
|
||||
use, intrinsic :: iso_c_binding, only: c_short, c_ptr, c_int
|
||||
implicit none
|
||||
integer (c_short) :: crc14
|
||||
type (c_ptr), value :: data
|
||||
integer (c_int), value :: length
|
||||
end function crc14
|
||||
|
||||
function crc14_check (data, length) bind (C, name="crc16_check")
|
||||
use, intrinsic :: iso_c_binding, only: c_bool, c_ptr, c_int
|
||||
implicit none
|
||||
logical (c_bool) :: crc14_check
|
||||
type (c_ptr), value :: data
|
||||
integer (c_int), value :: length
|
||||
end function crc14_check
|
||||
|
||||
function crc12 (data, length) bind (C, name="crc12")
|
||||
use, intrinsic :: iso_c_binding, only: c_short, c_ptr, c_int
|
||||
implicit none
|
||||
|
Before Width: | Height: | Size: 3.7 KiB |
@@ -45,16 +45,32 @@ when double-clicking.
|
||||
|
||||
NOTE: To avoid QRM from competing callers, it is frequently desirable
|
||||
to answer a CQ on a different frequency from that of the CQing
|
||||
station. Choose a Tx frequency that appears to be not in use. The
|
||||
same is true when you tail-end another QSO.
|
||||
station. The same is true when you tail-end another QSO. Choose a Tx
|
||||
frequency that appears to be not in use.
|
||||
|
||||
NOTE: The FT8 decoder can often copy several overlapping signals at
|
||||
nearly the same frequency. Keyboard shortcuts *Shift+F11* and
|
||||
*Shift+F12* provide an easy way to move your Tx frequency down or up
|
||||
in 60 Hz steps.
|
||||
NOTE: Keyboard shortcuts *Shift+F11* and *Shift+F12* provide an easy
|
||||
way to move your Tx frequency down or up in 60 Hz steps.
|
||||
|
||||
NOTE: Further helpful tips on FT8 operating procedures are available
|
||||
{ft8_tips}. Thanks to ZL2IFB!
|
||||
|
||||
.FT8 DXpedition Mode:
|
||||
|
||||
This special operating mode enables DXpeditions to make FT8 QSOs at
|
||||
very high rates. Both stations must use _WSJT-X_ Version 1.9 or
|
||||
later. Detailed operating instructions for {ft8_DXped} are available
|
||||
online. Do not try to use DXpedition mode without reading these
|
||||
instructions carefully!
|
||||
|
||||
IMPORTANT: FT8 DXpedition mode is intended for use by rare-entity
|
||||
DXpeditions and other unusual circumstances in which sustained QSO
|
||||
rates well above 100/hour are expected. Do not use the multi-signal
|
||||
capability unless you satisfy this requirement, and do not use
|
||||
DXpedition Mode in the conventional FT8 sub-bands. If you are
|
||||
contemplating operation as Fox using DXpedition Mode, find a suitable
|
||||
dial frequency consistent with regional band plans and publicize it
|
||||
for the operators you hope to work. Remember that on-the-air signal
|
||||
frequencies will be higher than the dial frequency by up to 4 kHz.
|
||||
|
||||
IMPORTANT: When finished with this Tutorial, don't forget to re-enter
|
||||
your own callsign as *My Call* on the *Settings | General* tab.
|
||||
@@ -1,7 +1,7 @@
|
||||
subroutine encode174(message,codeword)
|
||||
! Encode an 101-bit message and return a 174-bit codeword.
|
||||
! The generator matrix has dimensions (73,101).
|
||||
! The code is a (174,101) regular ldpc code with column weight 3.
|
||||
! Encode an 87-bit message and return a 174-bit codeword.
|
||||
! The generator matrix has dimensions (87,87).
|
||||
! The code is a (174,87) regular ldpc code with column weight 3.
|
||||
! The code was generated using the PEG algorithm.
|
||||
! After creating the codeword, the columns are re-ordered according to
|
||||
! "colorder" to make the codeword compatible with the parity-check matrix
|
||||
@@ -1,99 +0,0 @@
|
||||
#include "IARURegions.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include "moc_IARURegions.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
// human readable strings for each Region enumeration value
|
||||
char const * const region_names[] =
|
||||
{
|
||||
"All",
|
||||
"Region 1",
|
||||
"Region 2",
|
||||
"Region 3",
|
||||
};
|
||||
std::size_t constexpr region_names_size = sizeof (region_names) / sizeof (region_names[0]);
|
||||
}
|
||||
|
||||
IARURegions::IARURegions (QObject * parent)
|
||||
: QAbstractListModel {parent}
|
||||
{
|
||||
static_assert (region_names_size == REGIONS_END_SENTINAL_AND_COUNT,
|
||||
"region_names array must match Region enumeration");
|
||||
}
|
||||
|
||||
char const * IARURegions::name (Region r)
|
||||
{
|
||||
return region_names[static_cast<int> (r)];
|
||||
}
|
||||
|
||||
auto IARURegions::value (QString const& s) -> Region
|
||||
{
|
||||
auto end = region_names + region_names_size;
|
||||
auto p = std::find_if (region_names, end
|
||||
, [&s] (char const * const name) {
|
||||
return name == s;
|
||||
});
|
||||
return p != end ? static_cast<Region> (p - region_names) : ALL;
|
||||
}
|
||||
|
||||
QVariant IARURegions::data (QModelIndex const& index, int role) const
|
||||
{
|
||||
QVariant item;
|
||||
|
||||
if (index.isValid ())
|
||||
{
|
||||
auto const& row = index.row ();
|
||||
switch (role)
|
||||
{
|
||||
case Qt::ToolTipRole:
|
||||
case Qt::AccessibleDescriptionRole:
|
||||
item = tr ("IARU Region");
|
||||
break;
|
||||
|
||||
case Qt::EditRole:
|
||||
item = static_cast<Region> (row);
|
||||
break;
|
||||
|
||||
case Qt::DisplayRole:
|
||||
case Qt::AccessibleTextRole:
|
||||
item = region_names[row];
|
||||
break;
|
||||
|
||||
case Qt::TextAlignmentRole:
|
||||
item = Qt::AlignHCenter + Qt::AlignVCenter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
QVariant IARURegions::headerData (int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
QVariant result;
|
||||
|
||||
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
|
||||
{
|
||||
result = tr ("IARU Region");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = QAbstractListModel::headerData (section, orientation, role);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined (QT_NO_DEBUG_STREAM)
|
||||
ENUM_QDEBUG_OPS_IMPL (IARURegions, Region);
|
||||
#endif
|
||||
|
||||
ENUM_QDATASTREAM_OPS_IMPL (IARURegions, Region);
|
||||
ENUM_CONVERSION_OPS_IMPL (IARURegions, Region);
|
||||
@@ -48,7 +48,7 @@ message (STATUS "Building ${CMAKE_PROJECT_NAME}-${wsjtx_VERSION}")
|
||||
set (PROJECT_NAME "WSJT-X")
|
||||
set (PROJECT_VENDOR "Joe Taylor, K1JT")
|
||||
set (PROJECT_CONTACT "Joe Taylor <k1jt@arrl.net>")
|
||||
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2017 by Joe Taylor, K1JT")
|
||||
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2018 by Joe Taylor, K1JT")
|
||||
set (PROJECT_HOMEPAGE http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html)
|
||||
set (PROJECT_MANUAL wsjtx-main)
|
||||
set (PROJECT_MANUAL_DIRECTORY_URL http://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/)
|
||||
@@ -366,12 +366,12 @@ set (wsjt_FSRCS
|
||||
lib/averms.f90
|
||||
lib/azdist.f90
|
||||
lib/badmsg.f90
|
||||
lib/fsk4hf/baseline.f90
|
||||
lib/ft8/baseline.f90
|
||||
lib/bpdecode40.f90
|
||||
lib/bpdecode144.f90
|
||||
lib/fsk4hf/bpdecode120.f90
|
||||
lib/fsk4hf/bpdecode168.f90
|
||||
lib/fsk4hf/bpdecode174.f90
|
||||
lib/ft8/bpdecode174.f90
|
||||
lib/fsk4hf/bpdecode300.f90
|
||||
lib/baddata.f90
|
||||
lib/calibrate.f90
|
||||
@@ -379,11 +379,12 @@ set (wsjt_FSRCS
|
||||
lib/ccf65.f90
|
||||
lib/fsk4hf/chkcrc10.f90
|
||||
lib/fsk4hf/chkcrc12.f90
|
||||
lib/fsk4hf/chkcrc12a.f90
|
||||
lib/ft8/chkcrc12a.f90
|
||||
lib/chkcall.f90
|
||||
lib/chkhist.f90
|
||||
lib/chkmsg.f90
|
||||
lib/chkss2.f90
|
||||
lib/ft8/compress.f90
|
||||
lib/coord.f90
|
||||
lib/fsk4hf/cpolyfit.f90
|
||||
lib/fsk4hf/cpolyfitw.f90
|
||||
@@ -405,7 +406,7 @@ set (wsjt_FSRCS
|
||||
lib/encode_msk144.f90
|
||||
lib/fsk4hf/encode120.f90
|
||||
lib/fsk4hf/encode168.f90
|
||||
lib/fsk4hf/encode174.f90
|
||||
lib/ft8/encode174.f90
|
||||
lib/fsk4hf/encode300.f90
|
||||
lib/entail.f90
|
||||
lib/ephem.f90
|
||||
@@ -413,7 +414,7 @@ set (wsjt_FSRCS
|
||||
lib/extract4.f90
|
||||
lib/extractmessage144.f90
|
||||
lib/fsk4hf/extractmessage168.f90
|
||||
lib/fsk4hf/extractmessage174.f90
|
||||
lib/ft8/extractmessage174.f90
|
||||
lib/fano232.f90
|
||||
lib/fast9.f90
|
||||
lib/fast_decode.f90
|
||||
@@ -425,6 +426,7 @@ set (wsjt_FSRCS
|
||||
lib/fil4.f90
|
||||
lib/fil6521.f90
|
||||
lib/filbig.f90
|
||||
lib/ft8/filt8.f90
|
||||
lib/fitcal.f90
|
||||
lib/fix_contest_msg.f90
|
||||
lib/flat1.f90
|
||||
@@ -436,19 +438,23 @@ set (wsjt_FSRCS
|
||||
lib/fmtmsg.f90
|
||||
lib/foldspec9f.f90
|
||||
lib/four2a.f90
|
||||
lib/ft8/foxfilt.f90
|
||||
lib/ft8/foxgen.f90
|
||||
lib/ft8/foxgen_wrap.f90
|
||||
lib/fqso_first.f90
|
||||
lib/freqcal.f90
|
||||
lib/fsk4hf/fsk4hf.f90
|
||||
lib/fsk4hf/ft8apset.f90
|
||||
lib/fsk4hf/ft8b.f90
|
||||
lib/fsk4hf/ft8_downsample.f90
|
||||
lib/fsk4hf/ft8sim.f90
|
||||
lib/ft8/ft8apset.f90
|
||||
lib/ft8/ft8b.f90
|
||||
lib/ft8/ft8code.f90
|
||||
lib/ft8/ft8_downsample.f90
|
||||
lib/ft8/ft8sim.f90
|
||||
lib/gen4.f90
|
||||
lib/gen65.f90
|
||||
lib/gen9.f90
|
||||
lib/geniscat.f90
|
||||
lib/fsk4hf/genfsk4hf.f90
|
||||
lib/fsk4hf/genft8.f90
|
||||
lib/ft8/genft8.f90
|
||||
lib/genmsk144.f90
|
||||
lib/genmsk40.f90
|
||||
lib/fsk4hf/genmskhf.f90
|
||||
@@ -459,7 +465,7 @@ set (wsjt_FSRCS
|
||||
lib/fsk4hf/getfc1w.f90
|
||||
lib/fsk4hf/getfc2w.f90
|
||||
lib/genqra64.f90
|
||||
lib/fsk4hf/genft8refsig.f90
|
||||
lib/ft8/genft8refsig.f90
|
||||
lib/genwspr.f90
|
||||
lib/geodist.f90
|
||||
lib/getlags.f90
|
||||
@@ -468,6 +474,7 @@ set (wsjt_FSRCS
|
||||
lib/graycode65.f90
|
||||
lib/grayline.f90
|
||||
lib/grid2deg.f90
|
||||
lib/ft8/h1.f90
|
||||
lib/hash.f90
|
||||
lib/hint65.f90
|
||||
lib/hspec.f90
|
||||
@@ -484,7 +491,7 @@ set (wsjt_FSRCS
|
||||
lib/ldpcsim144.f90
|
||||
lib/fsk4hf/ldpcsim120.f90
|
||||
lib/fsk4hf/ldpcsim168.f90
|
||||
lib/fsk4hf/ldpcsim174.f90
|
||||
lib/ft8/ldpcsim174.f90
|
||||
lib/fsk4hf/ldpcsim300.f90
|
||||
lib/ldpcsim40.f90
|
||||
lib/libration.f90
|
||||
@@ -512,11 +519,12 @@ set (wsjt_FSRCS
|
||||
lib/mskrtd.f90
|
||||
lib/fsk4hf/msksoftsym.f90
|
||||
lib/fsk4hf/msksoftsymw.f90
|
||||
lib/fsk4hf/osd174.f90
|
||||
lib/ft8/osd174.f90
|
||||
lib/fsk4hf/osd300.f90
|
||||
lib/pctile.f90
|
||||
lib/peakdt9.f90
|
||||
lib/peakup.f90
|
||||
lib/plotsave.f90
|
||||
lib/polyfit.f90
|
||||
lib/fsk4hf/polyfit4.f90
|
||||
lib/prog_args.f90
|
||||
@@ -543,7 +551,7 @@ set (wsjt_FSRCS
|
||||
lib/spec9f.f90
|
||||
lib/stdmsg.f90
|
||||
lib/subtract65.f90
|
||||
lib/fsk4hf/subtractft8.f90
|
||||
lib/ft8/subtractft8.f90
|
||||
lib/sun.f90
|
||||
lib/symspec.f90
|
||||
lib/symspec2.f90
|
||||
@@ -551,8 +559,8 @@ set (wsjt_FSRCS
|
||||
lib/sync4.f90
|
||||
lib/sync64.f90
|
||||
lib/sync65.f90
|
||||
lib/fsk4hf/sync8.f90
|
||||
lib/fsk4hf/sync8d.f90
|
||||
lib/ft8/sync8.f90
|
||||
lib/ft8/sync8d.f90
|
||||
lib/sync9.f90
|
||||
lib/sync9f.f90
|
||||
lib/sync9w.f90
|
||||
@@ -561,12 +569,12 @@ set (wsjt_FSRCS
|
||||
lib/to_contest_msg.f90
|
||||
lib/tweak1.f90
|
||||
lib/twkfreq.f90
|
||||
lib/fsk4hf/twkfreq1.f90
|
||||
lib/ft8/twkfreq1.f90
|
||||
lib/twkfreq65.f90
|
||||
lib/unpackmsg144.f90
|
||||
lib/update_recent_calls.f90
|
||||
lib/update_hasharray.f90
|
||||
lib/fsk4hf/watterson.f90
|
||||
lib/ft8/watterson.f90
|
||||
lib/wav11.f90
|
||||
lib/wav12.f90
|
||||
lib/xcor.f90
|
||||
@@ -582,6 +590,9 @@ set (wsjt_FSRCS
|
||||
lib/zplot9.f90
|
||||
)
|
||||
|
||||
# temporary workaround for a gfortran v7.3 ICE on Fedora 27 64-bit
|
||||
set_source_files_properties (lib/slasubs.f PROPERTIES COMPILE_FLAGS -O2)
|
||||
|
||||
set (ka9q_CSRCS
|
||||
lib/ftrsd/decode_rs.c
|
||||
lib/ftrsd/encode_rs.c
|
||||
@@ -602,7 +613,7 @@ set (qra_CSRCS
|
||||
|
||||
set (wsjt_CSRCS
|
||||
${ka9q_CSRCS}
|
||||
lib/ftrsd/ftrsd2.c
|
||||
lib/ftrsd/ftrsdap.c
|
||||
lib/sgran.c
|
||||
lib/golay24_table.c
|
||||
lib/gran.c
|
||||
@@ -675,6 +686,7 @@ set (message_aggregator_CXXSRCS
|
||||
UDPExamples/DecodesModel.cpp
|
||||
UDPExamples/BeaconsModel.cpp
|
||||
UDPExamples/ClientWidget.cpp
|
||||
MaidenheadLocatorValidator.cpp
|
||||
)
|
||||
|
||||
set (message_aggregator_STYLESHEETS
|
||||
@@ -943,7 +955,7 @@ if (Fortran_COMPILER_NAME MATCHES "gfortran.*")
|
||||
set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -isysroot ${CMAKE_OSX_SYSROOT}")
|
||||
endif (CMAKE_OSX_SYSROOT)
|
||||
|
||||
set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -funroll-all-loops -fno-f2c ${General_FFLAGS}")
|
||||
set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -fbounds-check -funroll-all-loops -fno-f2c ${General_FFLAGS}")
|
||||
set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fbounds-check -fno-f2c ${General_FFLAGS}")
|
||||
elseif (Fortran_COMPILER_NAME MATCHES "ifort.*")
|
||||
# ifort (untested)
|
||||
@@ -1162,8 +1174,8 @@ target_link_libraries (jt65sim wsjt_fort wsjt_cxx)
|
||||
add_executable (qra64sim lib/qra/qra64/qra64sim.f90 wsjtx.rc)
|
||||
target_link_libraries (qra64sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (jt9sim lib/jt9sim.f90 wsjtx.rc)
|
||||
target_link_libraries (jt9sim wsjt_fort wsjt_cxx)
|
||||
add_executable (jt49sim lib/jt49sim.f90 wsjtx.rc)
|
||||
target_link_libraries (jt49sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (allsim lib/allsim.f90 wsjtx.rc)
|
||||
target_link_libraries (allsim wsjt_fort wsjt_cxx)
|
||||
@@ -1202,8 +1214,8 @@ target_link_libraries (ldpcsim40 wsjt_fort wsjt_cxx)
|
||||
add_executable (ldpcsim120 lib/fsk4hf/ldpcsim120.f90 wsjtx.rc)
|
||||
target_link_libraries (ldpcsim120 wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (ldpcsim300 lib/fsk4hf/ldpcsim300.f90 wsjtx.rc)
|
||||
target_link_libraries (ldpcsim300 wsjt_fort wsjt_cxx)
|
||||
add_executable (ldpcsim174 lib/ft8/ldpcsim174.f90 wsjtx.rc)
|
||||
target_link_libraries (ldpcsim174 wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (ldpcsim144 lib/ldpcsim144.f90 wsjtx.rc)
|
||||
target_link_libraries (ldpcsim144 wsjt_fort wsjt_cxx)
|
||||
@@ -1214,7 +1226,10 @@ target_link_libraries (ldpcsim168 wsjt_fort wsjt_cxx)
|
||||
add_executable (fsk4hf lib/fsk4hf/fsk4hf.f90 wsjtx.rc)
|
||||
target_link_libraries (fsk4hf wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (ft8sim lib/fsk4hf/ft8sim.f90 wsjtx.rc)
|
||||
add_executable (ft8code lib/ft8/ft8code.f90 wsjtx.rc)
|
||||
target_link_libraries (ft8code wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (ft8sim lib/ft8/ft8sim.f90 wsjtx.rc)
|
||||
target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (wsprlfsim lib/fsk4hf/wsprlfsim.f90 wsjtx.rc)
|
||||
@@ -1296,12 +1311,14 @@ if (WSJT_CREATE_WINMAIN)
|
||||
endif (WSJT_CREATE_WINMAIN)
|
||||
|
||||
set_target_properties (wsjtx PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
|
||||
MACOSX_BUNDLE_INFO_STRING "${WSJTX_DESCRIPTION_SUMMARY}"
|
||||
MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${wsjtx_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "v${wsjtx_VERSION}"
|
||||
MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${wsjtx_VERSION}"
|
||||
MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}"
|
||||
MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
|
||||
MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
|
||||
)
|
||||
@@ -1347,7 +1364,7 @@ set_target_properties (wsjtx_udp-static PROPERTIES
|
||||
)
|
||||
target_compile_definitions (wsjtx_udp-static PUBLIC UDP_STATIC_DEFINE)
|
||||
#qt5_use_modules (wsjtx_udp Network)
|
||||
qt5_use_modules (wsjtx_udp-static Network)
|
||||
qt5_use_modules (wsjtx_udp-static Network Gui)
|
||||
generate_export_header (wsjtx_udp-static BASE_NAME udp)
|
||||
|
||||
add_executable (udp_daemon UDPExamples/UDPDaemon.cpp UDPExamples/udp_daemon.rc ${WSJTX_ICON_FILE})
|
||||
@@ -1409,7 +1426,7 @@ install (TARGETS udp_daemon message_aggregator
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
)
|
||||
|
||||
install (TARGETS jt9 jt65code qra64code qra64sim jt9code jt4code
|
||||
install (TARGETS jt9 ft8code jt65code qra64code qra64sim jt9code jt4code
|
||||
msk144code wsprd wspr_fsk8d fmtave fcal fmeasure
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
|
||||
@@ -1471,9 +1488,13 @@ add_custom_target (uninstall
|
||||
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
|
||||
|
||||
|
||||
# creates svnversion.h using cmake script
|
||||
# creates or updates ${PROJECT_BINARY_DIR}/scs_version.h using cmake script
|
||||
add_custom_target (revisiontag
|
||||
COMMAND ${CMAKE_COMMAND} -D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -D OUTPUT_DIR=${PROJECT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/getsvn.cmake
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
|
||||
-D BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
|
||||
-D OUTPUT_DIR=${PROJECT_BINARY_DIR}
|
||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/getsvn.cmake
|
||||
COMMENT "Generating Subversion revision information"
|
||||
VERBATIM
|
||||
)
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
#Sov Mil Order of Malta: 15: 28: EU: 41.90: -12.43: -1.0: 1A:
|
||||
#1A;
|
||||
#Spratly Islands: 26: 50: AS: 9.88: -114.23: -8.0: 1S:
|
||||
#1S,9M0,BV9S;
|
||||
#Monaco: 14: 27: EU: 43.73: -7.40: -1.0: 3A:
|
||||
#3A;
|
||||
#Heard Island: 39: 68: AF: -53.08: -73.50: -5.0: VK0H:
|
||||
#=VK0IR;
|
||||
#Macquarie Island: 30: 60: OC: -54.60: -158.88: -10.0: VK0M:
|
||||
#=VK0KEV;
|
||||
#Cocos-Keeling: 29: 54: OC: -12.15: -96.82: -6.5: VK9C:
|
||||
#AX9C,AX9Y,VH9C,VH9Y,VI9C,VI9Y,VJ9C,VJ9Y,VK9C,VK9Y,VL9C,VL9Y,VM9C,VM9Y,
|
||||
#VN9C,VN9Y,VZ9C,VZ9Y,=VK9AA;
|
||||
*/
|
||||
|
||||
|
||||
#include "countrydat.h"
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
|
||||
void CountryDat::init(const QString filename)
|
||||
{
|
||||
_filename = filename;
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
QString CountryDat::_extractName(const QString line)
|
||||
{
|
||||
int s1 = line.indexOf(':');
|
||||
if (s1>=0)
|
||||
{
|
||||
QString name = line.mid(0,s1);
|
||||
return name;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void CountryDat::_removeBrackets(QString &line, const QString a, const QString b)
|
||||
{
|
||||
int s1 = line.indexOf(a);
|
||||
while (s1 >= 0)
|
||||
{
|
||||
int s2 = line.indexOf(b);
|
||||
line = line.mid(0,s1) + line.mid(s2+1,-1);
|
||||
s1 = line.indexOf(a);
|
||||
}
|
||||
}
|
||||
|
||||
QStringList CountryDat::_extractPrefix(QString &line, bool &more)
|
||||
{
|
||||
line = line.remove(" \n");
|
||||
line = line.replace("=","");
|
||||
line = line.replace(" ","");
|
||||
|
||||
_removeBrackets(line,"(",")");
|
||||
_removeBrackets(line,"[","]");
|
||||
_removeBrackets(line,"<",">");
|
||||
_removeBrackets(line,"~","~");
|
||||
|
||||
int s1 = line.indexOf(';');
|
||||
more = true;
|
||||
if (s1 >= 0)
|
||||
{
|
||||
line = line.mid(0,s1);
|
||||
more = false;
|
||||
}
|
||||
|
||||
QStringList r = line.split(',');
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void CountryDat::load()
|
||||
{
|
||||
_data.clear();
|
||||
_countryNames.clear(); //used by countriesWorked
|
||||
|
||||
QFile inputFile(_filename);
|
||||
if (inputFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QTextStream in(&inputFile);
|
||||
while ( !in.atEnd() )
|
||||
{
|
||||
QString line1 = in.readLine();
|
||||
if ( !in.atEnd() )
|
||||
{
|
||||
QString line2 = in.readLine();
|
||||
|
||||
QString name = _extractName(line1);
|
||||
if (name.length()>0)
|
||||
{
|
||||
_countryNames << name;
|
||||
bool more = true;
|
||||
QStringList prefixs;
|
||||
while (more)
|
||||
{
|
||||
QStringList p = _extractPrefix(line2,more);
|
||||
prefixs += p;
|
||||
if (more)
|
||||
line2 = in.readLine();
|
||||
}
|
||||
|
||||
QString p;
|
||||
foreach(p,prefixs)
|
||||
{
|
||||
if (p.length() > 0)
|
||||
_data.insert(p,name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inputFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
// return country name else ""
|
||||
QString CountryDat::find(QString prefix)
|
||||
{
|
||||
prefix = prefix.toUpper ();
|
||||
auto pf = prefix;
|
||||
while (pf.size () >= 1)
|
||||
{
|
||||
if (_data.contains (pf))
|
||||
{
|
||||
QString country {_data.value (pf)};
|
||||
|
||||
//
|
||||
// deal with special rules that cty.dat does not cope with
|
||||
//
|
||||
|
||||
// KG4 2x1 and 2x3 calls that map to Gitmo are mainland US not Gitmo
|
||||
if (prefix.startsWith ("KG4") && prefix.size () != 5)
|
||||
{
|
||||
country.replace ("Guantanamo Bay", "United States");
|
||||
}
|
||||
|
||||
return country;
|
||||
}
|
||||
pf = pf.left (pf.size () - 1);
|
||||
}
|
||||
return QString {};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,180 +0,0 @@
|
||||
48 128
|
||||
12 4
|
||||
11 11 11 11 11 11 11 11 11 11 11 11 11 10 11 11 11 10 10 11 10 11 10 11 10 10 10 10 10 11 10 12 11 11 10 11 11 11 11 11 10 10 11 10 10 11 11 10
|
||||
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
|
||||
1 13 26 38 51 62 75 86 99 111 124 0
|
||||
2 13 27 39 49 63 76 87 100 112 121 0
|
||||
3 14 27 40 52 64 74 88 101 104 123 0
|
||||
2 15 28 41 53 65 77 89 102 113 125 0
|
||||
4 16 26 41 54 66 71 90 101 114 122 0
|
||||
5 15 29 40 55 67 78 91 98 110 126 0
|
||||
6 17 30 42 56 63 79 90 103 115 124 0
|
||||
7 18 25 43 56 68 80 87 104 113 122 0
|
||||
7 13 29 44 52 69 81 92 102 114 127 0
|
||||
8 14 29 42 57 66 77 86 97 116 119 0
|
||||
9 19 26 45 56 69 76 93 97 110 128 0
|
||||
9 14 28 46 54 68 82 91 99 112 118 0
|
||||
8 20 31 47 49 69 78 88 105 109 124 0
|
||||
1 20 32 42 52 70 76 94 106 117 0 0
|
||||
10 15 33 48 52 62 80 93 100 118 119 0
|
||||
11 18 31 39 48 67 83 94 97 114 125 0
|
||||
12 15 34 37 49 64 73 85 99 116 127 0
|
||||
2 21 25 45 55 64 83 92 103 119 0 0
|
||||
4 22 33 46 55 65 84 86 107 108 0 0
|
||||
11 16 27 45 53 70 79 95 107 111 126 0
|
||||
6 13 33 45 57 68 85 96 101 120 0 0
|
||||
12 17 25 38 58 67 76 96 107 118 123 0
|
||||
5 18 30 44 59 71 77 93 106 120 0 0
|
||||
6 20 28 43 50 72 83 86 95 121 127 0
|
||||
11 23 28 38 59 73 81 88 108 115 0 0
|
||||
10 19 32 49 60 67 75 89 101 108 0 0
|
||||
5 22 27 48 54 69 73 96 103 113 0 0
|
||||
12 23 35 47 50 62 79 97 106 122 0 0
|
||||
3 18 26 47 53 61 82 85 98 108 0 0
|
||||
9 22 31 41 58 60 72 87 106 115 116 0
|
||||
10 16 30 50 58 65 73 91 104 109 0 0
|
||||
10 24 36 41 57 61 78 94 103 111 123 127
|
||||
4 17 29 43 59 74 85 89 109 112 128 0
|
||||
3 21 34 38 60 63 77 95 105 114 128 0
|
||||
7 24 37 46 53 71 74 96 105 110 0 0
|
||||
6 19 34 47 51 70 81 91 100 123 125 0
|
||||
2 24 31 40 56 66 81 84 95 118 120 0
|
||||
1 14 30 37 48 72 78 92 107 122 128 0
|
||||
3 23 24 42 55 68 75 93 109 121 125 0
|
||||
12 22 32 43 51 71 82 88 102 119 126 0
|
||||
1 23 36 44 58 64 80 90 110 112 0 0
|
||||
7 19 35 40 59 65 82 90 111 117 0 0
|
||||
9 17 36 39 50 66 75 92 105 117 126 0
|
||||
4 21 35 39 57 70 80 98 99 115 0 0
|
||||
8 25 33 37 54 60 79 94 98 121 0 0
|
||||
8 16 34 46 61 62 83 87 102 117 120 0
|
||||
11 21 32 44 61 72 74 84 100 113 124 0
|
||||
5 20 35 36 51 63 84 89 104 116 0 0
|
||||
1 14 38 41
|
||||
2 4 18 37
|
||||
3 29 34 39
|
||||
5 19 33 44
|
||||
6 23 27 48
|
||||
7 21 24 36
|
||||
8 9 35 42
|
||||
10 13 45 46
|
||||
11 12 30 43
|
||||
15 26 31 32
|
||||
16 20 25 47
|
||||
17 22 28 40
|
||||
1 2 9 21
|
||||
3 10 12 38
|
||||
4 6 15 17
|
||||
5 20 31 46
|
||||
7 22 33 43
|
||||
8 16 23 29
|
||||
11 26 36 42
|
||||
13 14 24 48
|
||||
18 34 44 47
|
||||
19 27 30 40
|
||||
25 28 39 41
|
||||
32 35 37 39
|
||||
8 18 22 45
|
||||
1 5 11 29
|
||||
2 3 20 27
|
||||
4 12 24 25
|
||||
6 9 10 33
|
||||
7 23 31 38
|
||||
13 16 30 37
|
||||
14 26 40 47
|
||||
15 19 21 45
|
||||
17 34 36 46
|
||||
28 42 44 48
|
||||
32 41 43 48
|
||||
17 35 38 45
|
||||
1 22 25 34
|
||||
2 16 43 44
|
||||
3 6 37 42
|
||||
4 5 30 32
|
||||
7 10 14 39
|
||||
8 24 33 40
|
||||
9 23 41 47
|
||||
11 18 20 21
|
||||
12 19 35 46
|
||||
13 28 29 36
|
||||
15 16 27 38
|
||||
2 13 17 26
|
||||
24 28 31 43
|
||||
1 36 40 48
|
||||
3 9 14 15
|
||||
4 20 29 35
|
||||
5 12 27 45
|
||||
6 18 19 39
|
||||
7 8 11 37
|
||||
10 21 32 44
|
||||
22 30 31 41
|
||||
23 25 33 42
|
||||
26 30 34 45
|
||||
29 32 46 47
|
||||
1 15 28 46
|
||||
2 7 34 48
|
||||
3 17 18 41
|
||||
4 19 31 42
|
||||
5 10 37 43
|
||||
6 16 22 26
|
||||
8 12 21 39
|
||||
9 11 13 27
|
||||
14 20 36 44
|
||||
5 23 35 40
|
||||
24 30 38 47
|
||||
17 25 27 31
|
||||
3 33 35 47
|
||||
1 26 39 43
|
||||
2 11 14 22
|
||||
4 10 23 34
|
||||
6 13 32 38
|
||||
7 20 28 45
|
||||
8 15 41 44
|
||||
9 25 36 37
|
||||
12 29 40 42
|
||||
16 18 24 46
|
||||
19 37 47 48
|
||||
17 21 29 33
|
||||
1 10 19 24
|
||||
2 8 30 46
|
||||
3 13 25 40
|
||||
4 26 33 48
|
||||
5 7 41 42
|
||||
6 12 31 36
|
||||
9 18 38 43
|
||||
11 15 23 39
|
||||
14 16 32 45
|
||||
20 24 34 37
|
||||
21 22 27 35
|
||||
10 11 16 28
|
||||
6 29 44 45
|
||||
1 12 17 44
|
||||
2 15 36 47
|
||||
3 5 21 26
|
||||
4 9 40 46
|
||||
7 18 27 32
|
||||
3 8 31 48
|
||||
13 34 35 43
|
||||
14 23 28 30
|
||||
19 20 22 38
|
||||
19 25 26 29
|
||||
13 31 33 39
|
||||
6 11 35 41
|
||||
1 20 32 42
|
||||
2 12 33 41
|
||||
4 8 27 47
|
||||
5 9 16 34
|
||||
7 25 30 44
|
||||
10 17 30 48
|
||||
14 42 43 46
|
||||
12 15 22 37
|
||||
10 15 18 40
|
||||
21 23 37 46
|
||||
2 24 39 45
|
||||
5 8 28 38
|
||||
3 22 32 36
|
||||
1 7 13 47
|
||||
4 16 36 39
|
||||
6 20 40 43
|
||||
9 17 24 32
|
||||
11 33 34 38
|
||||
@@ -1,242 +0,0 @@
|
||||
// This is a comment line, anything with // is ignored at process time.
|
||||
= WSJT-X User Guide
|
||||
Joseph H Taylor, Jr, K1JT
|
||||
:revnumber: {VERSION}
|
||||
// For web-pages, adding :badges: is ok, but is a security issue for
|
||||
// package building .deb, .rpm, etc as it exposes the IP address and the images
|
||||
// are non-free, so can't be included as part of the Debian package.
|
||||
// :badges:
|
||||
:docinfo1:
|
||||
:imagesdir: {docdir}/images
|
||||
:icons: font
|
||||
:numbered:
|
||||
:keywords: amateur radio weak signal communication K1JT WSJT JT65 JT9
|
||||
:description: Software for Amateur Radio Weak-Signal Communication
|
||||
:prog: WSJT-X
|
||||
|
||||
// use global link file
|
||||
include::../../common/links.adoc[]
|
||||
|
||||
// These [[xxxx]] labels are HTML anchors, and can be used to
|
||||
// navigate though the document easily: <<INTRO,See Introduction>> will
|
||||
// place a hyper-link in your text to take you too the anchored section.
|
||||
// All major sections or points of interest should have one.
|
||||
|
||||
// == is level (2), section 1.0, === would mean section 1.1, === would
|
||||
// be section 1.1.1. This method is used throughout the document.
|
||||
|
||||
[[INTRO]]
|
||||
== Introduction
|
||||
include::introduction.adoc[]
|
||||
|
||||
[[NEW_FEATURES]]
|
||||
include::new_features.adoc[]
|
||||
|
||||
[[SYSREQ]]
|
||||
== System Requirements
|
||||
include::system-requirements.adoc[]
|
||||
|
||||
[[INSTALL]]
|
||||
== Installation
|
||||
|
||||
Installation packages for released versions on Windows, Linux, and OS
|
||||
X are found on the {homepage}. Click on the _WSJT-X_ link at the
|
||||
left margin and select the appropriate package for your operating
|
||||
system.
|
||||
|
||||
[[INSTALL_WIN]]
|
||||
=== Windows
|
||||
include::install-windows.adoc[]
|
||||
|
||||
[[INSTALL_LINUX]]
|
||||
=== Linux
|
||||
include::install-linux.adoc[]
|
||||
|
||||
[[INSTALL_OSX]]
|
||||
=== OS X and macOS
|
||||
include::install-mac.adoc[]
|
||||
|
||||
////
|
||||
[[SRC_CODE]]
|
||||
=== Source Code
|
||||
include::install-from-source.adoc[]
|
||||
////
|
||||
|
||||
[[CONFIG]]
|
||||
== Settings
|
||||
|
||||
Select *Settings* from the *File* menu or by typing *F2*. (On
|
||||
Macintosh select *Preferences* from the _WSJT-X_ menu, or use the
|
||||
keyboard shortcut *Cmd+,*). The following sections describe setup
|
||||
options available on each of seven tabs selectable near the top of the
|
||||
window.
|
||||
|
||||
[[GENERAL]]
|
||||
=== General
|
||||
include::settings-general.adoc[]
|
||||
|
||||
[[RADIO]]
|
||||
=== Radio
|
||||
include::settings-radio.adoc[]
|
||||
|
||||
[[AUDIO]]
|
||||
=== Audio
|
||||
include::settings-audio.adoc[]
|
||||
|
||||
[[TXMACROS]]
|
||||
=== Tx Macros
|
||||
include::settings-txmacros.adoc[]
|
||||
|
||||
[[REPORTING]]
|
||||
=== Reporting
|
||||
include::settings-reporting.adoc[]
|
||||
|
||||
[[BAND_SETTINGS]]
|
||||
=== Frequencies
|
||||
include::settings-frequencies.adoc[]
|
||||
|
||||
[[COLORS]]
|
||||
=== Colors
|
||||
include::settings-colors.adoc[]
|
||||
|
||||
[[ADVANCED]]
|
||||
=== Advanced
|
||||
include::settings-advanced.adoc[]
|
||||
|
||||
[[TRANSCEIVER]]
|
||||
== Transceiver Setup
|
||||
include::transceiver-setup.adoc[]
|
||||
|
||||
[[TUTORIAL]]
|
||||
== Basic Operating Tutorial
|
||||
|
||||
<<TUT_MAIN,Sections 6.1>> through <<TUT_EX2,6.4>> introduce basic user
|
||||
controls and program behavior of _WSJT-X_. We suggest that new users
|
||||
should go through the full HF-oriented tutorial, preferably while at
|
||||
your radio. Subsequent sections cover additional details on
|
||||
<<MAKE_QSOS,Making QSOs>>, <<WSPR,WSPR mode>> and <<VHF_AND_UP,VHF+
|
||||
Features>>.
|
||||
|
||||
[[TUT_MAIN]]
|
||||
=== Main Window Settings
|
||||
include::tutorial-main-window.adoc[]
|
||||
|
||||
[[TUT_WIDE_GRAPH]]
|
||||
=== Wide Graph Settings
|
||||
include::tutorial-wide-graph-settings.adoc[]
|
||||
|
||||
[[TUT_EX1]]
|
||||
=== JT9
|
||||
include::tutorial-example1.adoc[]
|
||||
|
||||
[[TUT_EX2]]
|
||||
=== JT9+JT65
|
||||
include::tutorial-example2.adoc[]
|
||||
|
||||
[[TUT_EX3]]
|
||||
=== FT8
|
||||
include::tutorial-example3.adoc[]
|
||||
|
||||
[[MAKE_QSOS]]
|
||||
== Making QSOs
|
||||
include::make-qso.adoc[]
|
||||
|
||||
[[VHF_AND_UP]]
|
||||
== VHF+ Features
|
||||
include::vhf-features.adoc[]
|
||||
|
||||
[[WSPR]]
|
||||
== WSPR Mode
|
||||
include::wspr.adoc[]
|
||||
|
||||
[[COMMAND_REF]]
|
||||
== On-Screen Controls
|
||||
|
||||
[[MENUS]]
|
||||
=== Menus
|
||||
include::controls-functions-menus.adoc[]
|
||||
|
||||
[[CONTROLS_MAIN]]
|
||||
=== Button Row
|
||||
include::controls-functions-main-window.adoc[]
|
||||
|
||||
[[CONTROLS_LEFT]]
|
||||
=== Left
|
||||
include::controls-functions-left.adoc[]
|
||||
|
||||
[[CONTROLS_CENTER]]
|
||||
=== Center
|
||||
include::controls-functions-center.adoc[]
|
||||
|
||||
[[CONTROLS_MSGS]]
|
||||
=== Tx Messages
|
||||
include::controls-functions-messages.adoc[]
|
||||
|
||||
[[STATUS_BAR]]
|
||||
=== Status Bar
|
||||
include::controls-functions-status-bar.adoc[]
|
||||
|
||||
[[CONTROLS_WIDE]]
|
||||
=== Wide Graph
|
||||
include::controls-functions-wide-graph.adoc[]
|
||||
|
||||
[[LOGGING]]
|
||||
== Logging
|
||||
include::logging.adoc[]
|
||||
|
||||
[[ODDS_AND_ENDS]]
|
||||
== Odds and Ends
|
||||
include::odds_and_ends.adoc[]
|
||||
|
||||
[[COOP_PGMS]]
|
||||
== Cooperating Programs
|
||||
include::cooperating-programs.adoc[]
|
||||
|
||||
[[PLATFORM]]
|
||||
== Platform Dependencies
|
||||
include::platform-dependencies.adoc[]
|
||||
|
||||
|
||||
[[FAQ]]
|
||||
== Frequently Asked Questions
|
||||
include::faq.adoc[]
|
||||
|
||||
[[PROTOCOLS]]
|
||||
== Protocol Specifications
|
||||
include::protocols.adoc[]
|
||||
|
||||
[[ASTRODATA]]
|
||||
== Astronomical Data
|
||||
include::astro_data.adoc[]
|
||||
|
||||
[[UTIL]]
|
||||
== Utility Programs
|
||||
include::utilities.adoc[]
|
||||
|
||||
////
|
||||
[[TXRX]]
|
||||
== Implementation Details
|
||||
include::implementation.adoc[]
|
||||
|
||||
[[TROUBLE_SHOOTING]]
|
||||
== Troubleshooting
|
||||
To be added (?) ...
|
||||
|
||||
////
|
||||
|
||||
[[SUPPORT]]
|
||||
== Support
|
||||
include::support.adoc[]
|
||||
|
||||
[[ACK]]
|
||||
== Acknowledgements
|
||||
include::acknowledgements.adoc[]
|
||||
|
||||
[[LICENSE]]
|
||||
== License
|
||||
include::../../common/license.adoc[]
|
||||
|
||||
ifeval::["{backend}" != "html5"]
|
||||
[index]
|
||||
== Index
|
||||
endif::[]
|
||||
@@ -1,106 +0,0 @@
|
||||
#include "Modes.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QModelIndex>
|
||||
|
||||
#include "moc_Modes.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
// human readable strings for each Mode enumeration value
|
||||
char const * const mode_names[] =
|
||||
{
|
||||
"",
|
||||
"JT65",
|
||||
"JT9",
|
||||
"JT4",
|
||||
"WSPR",
|
||||
"Echo",
|
||||
"ISCAT",
|
||||
"MSK144",
|
||||
"QRA64",
|
||||
"FreqCal",
|
||||
"FT8"
|
||||
};
|
||||
std::size_t constexpr mode_names_size = sizeof (mode_names) / sizeof (mode_names[0]);
|
||||
}
|
||||
|
||||
Modes::Modes (QObject * parent)
|
||||
: QAbstractListModel {parent}
|
||||
{
|
||||
static_assert (mode_names_size == MODES_END_SENTINAL_AND_COUNT,
|
||||
"mode_names array must match Mode enumeration");
|
||||
}
|
||||
|
||||
char const * Modes::name (Mode m)
|
||||
{
|
||||
return mode_names[static_cast<int> (m)];
|
||||
}
|
||||
|
||||
auto Modes::value (QString const& s) -> Mode
|
||||
{
|
||||
auto end = mode_names + mode_names_size;
|
||||
auto p = std::find_if (mode_names, end
|
||||
, [&s] (char const * const name) {
|
||||
return name == s;
|
||||
});
|
||||
return p != end ? static_cast<Mode> (p - mode_names) : NULL_MODE;
|
||||
}
|
||||
|
||||
QVariant Modes::data (QModelIndex const& index, int role) const
|
||||
{
|
||||
QVariant item;
|
||||
|
||||
if (index.isValid ())
|
||||
{
|
||||
auto const& row = index.row ();
|
||||
switch (role)
|
||||
{
|
||||
case Qt::ToolTipRole:
|
||||
case Qt::AccessibleDescriptionRole:
|
||||
item = tr ("Mode");
|
||||
break;
|
||||
|
||||
case Qt::EditRole:
|
||||
item = static_cast<Mode> (row);
|
||||
break;
|
||||
|
||||
case Qt::DisplayRole:
|
||||
case Qt::AccessibleTextRole:
|
||||
item = mode_names[row];
|
||||
break;
|
||||
|
||||
case Qt::TextAlignmentRole:
|
||||
item = Qt::AlignHCenter + Qt::AlignVCenter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
QVariant Modes::headerData (int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
QVariant result;
|
||||
|
||||
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
|
||||
{
|
||||
result = tr ("Mode");
|
||||
}
|
||||
else
|
||||
{
|
||||
result = QAbstractListModel::headerData (section, orientation, role);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined (QT_NO_DEBUG_STREAM)
|
||||
ENUM_QDEBUG_OPS_IMPL (Modes, Mode);
|
||||
#endif
|
||||
|
||||
ENUM_QDATASTREAM_OPS_IMPL (Modes, Mode);
|
||||
ENUM_CONVERSION_OPS_IMPL (Modes, Mode);
|
||||
@@ -0,0 +1,52 @@
|
||||
subroutine filt8(f0,nslots,width,wave)
|
||||
|
||||
parameter (NFFT=180000,NH=NFFT/2)
|
||||
real wave(NFFT)
|
||||
real x(NFFT)
|
||||
real s1(0:NH)
|
||||
real s2(0:NH)
|
||||
complex cx(0:NH)
|
||||
equivalence (x,cx)
|
||||
|
||||
x=wave
|
||||
call four2a(x,NFFT,1,-1,0) !r2c
|
||||
df=12000.0/NFFT
|
||||
fa=f0 - 0.5*6.25
|
||||
fb=f0 + 7.5*6.25 + (nslots-1)*60.0
|
||||
ia2=nint(fa/df)
|
||||
ib1=nint(fb/df)
|
||||
ia1=nint(ia2-width/df)
|
||||
ib2=nint(ib1+width/df)
|
||||
pi=4.0*atan(1.0)
|
||||
do i=ia1,ia2
|
||||
fil=(1.0 + cos(pi*df*(i-ia2)/width))/2.0
|
||||
cx(i)=fil*cx(i)
|
||||
enddo
|
||||
do i=ib1,ib2
|
||||
fil=(1.0 + cos(pi*df*(i-ib1)/width))/2.0
|
||||
cx(i)=fil*cx(i)
|
||||
enddo
|
||||
cx(0:ia1-1)=0.
|
||||
cx(ib2+1:)=0.
|
||||
|
||||
call four2a(cx,nfft,1,1,-1) !c2r
|
||||
wave=x/nfft
|
||||
|
||||
!###
|
||||
if(nslots.ne.99) return
|
||||
x=wave
|
||||
call four2a(x,NFFT,1,-1,0) !r2c
|
||||
do i=0,NH
|
||||
s1(i)=real(cx(i))**2 + aimag(cx(i))**2
|
||||
enddo
|
||||
nadd=20
|
||||
call smo(s1,NH+1,s2,nadd)
|
||||
do i=0,NH
|
||||
freq=i*df
|
||||
write(29,3101) freq,db(s2(i)) - 72.0
|
||||
3101 format(2f12.3)
|
||||
enddo
|
||||
!###
|
||||
|
||||
return
|
||||
end subroutine filt8
|
||||
@@ -1,318 +0,0 @@
|
||||
program jt9
|
||||
|
||||
! Decoder for JT9. Can run stand-alone, reading data from *.wav files;
|
||||
! or as the back end of wsjt-x, with data placed in a shared memory region.
|
||||
|
||||
use options
|
||||
use prog_args
|
||||
use, intrinsic :: iso_c_binding
|
||||
use FFTW3
|
||||
use timer_module, only: timer
|
||||
use timer_impl, only: init_timer, fini_timer
|
||||
use readwav
|
||||
|
||||
include 'jt9com.f90'
|
||||
|
||||
integer(C_INT) iret
|
||||
type(wav_header) wav
|
||||
real*4 s(NSMAX)
|
||||
character c
|
||||
character(len=500) optarg, infile
|
||||
character wisfile*80
|
||||
!### ndepth was defined as 60001. Why???
|
||||
integer :: arglen,stat,offset,remain,mode=0,flow=200,fsplit=2700, &
|
||||
fhigh=4000,nrxfreq=1500,ntrperiod=1,ndepth=1,nexp_decode=0
|
||||
logical :: read_files = .true., tx9 = .false., display_help = .false.
|
||||
type (option) :: long_options(25) = [ &
|
||||
option ('help', .false., 'h', 'Display this help message', ''), &
|
||||
option ('shmem',.true.,'s','Use shared memory for sample data','KEY'), &
|
||||
option ('tr-period', .true., 'p', 'Tx/Rx period, default MINUTES=1', &
|
||||
'MINUTES'), &
|
||||
option ('executable-path', .true., 'e', &
|
||||
'Location of subordinate executables (KVASD) default PATH="."', &
|
||||
'PATH'), &
|
||||
option ('data-path', .true., 'a', &
|
||||
'Location of writeable data files, default PATH="."', 'PATH'), &
|
||||
option ('temp-path', .true., 't', &
|
||||
'Temporary files path, default PATH="."', 'PATH'), &
|
||||
option ('lowest', .true., 'L', &
|
||||
'Lowest frequency decoded (JT65), default HERTZ=200', 'HERTZ'), &
|
||||
option ('highest', .true., 'H', &
|
||||
'Highest frequency decoded, default HERTZ=4007', 'HERTZ'), &
|
||||
option ('split', .true., 'S', &
|
||||
'Lowest JT9 frequency decoded, default HERTZ=2700', 'HERTZ'), &
|
||||
option ('rx-frequency', .true., 'f', &
|
||||
'Receive frequency offset, default HERTZ=1500', 'HERTZ'), &
|
||||
option ('patience', .true., 'w', &
|
||||
'FFTW3 planing patience (0-4), default PATIENCE=1', 'PATIENCE'), &
|
||||
option ('fft-threads', .true., 'm', &
|
||||
'Number of threads to process large FFTs, default THREADS=1', &
|
||||
'THREADS'), &
|
||||
option ('jt65', .false., '6', 'JT65 mode', ''), &
|
||||
option ('jt9', .false., '9', 'JT9 mode', ''), &
|
||||
option ('ft8', .false., '8', 'FT8 mode', ''), &
|
||||
option ('jt4', .false., '4', 'JT4 mode', ''), &
|
||||
option ('qra64', .false., 'q', 'QRA64 mode', ''), &
|
||||
option ('sub-mode', .true., 'b', 'Sub mode, default SUBMODE=A', 'A'), &
|
||||
option ('depth', .true., 'd', &
|
||||
'JT9 decoding depth (1-3), default DEPTH=1', 'DEPTH'), &
|
||||
option ('tx-jt9', .false., 'T', 'Tx mode is JT9', ''), &
|
||||
option ('my-call', .true., 'c', 'my callsign', 'CALL'), &
|
||||
option ('my-grid', .true., 'G', 'my grid locator', 'GRID'), &
|
||||
option ('his-call', .true., 'x', 'his callsign', 'CALL'), &
|
||||
option ('his-grid', .true., 'g', 'his grid locator', 'GRID'), &
|
||||
option ('experience-decode', .true., 'X', &
|
||||
'experience based decoding flags (1..n), default FLAGS=0', &
|
||||
'FLAGS') ]
|
||||
|
||||
type(dec_data), allocatable :: shared_data
|
||||
character(len=12) :: mycall, hiscall
|
||||
character(len=6) :: mygrid, hisgrid
|
||||
common/patience/npatience,nthreads
|
||||
common/decstats/ntry65a,ntry65b,n65a,n65b,num9,numfano
|
||||
data npatience/1/,nthreads/1/
|
||||
|
||||
nsubmode = 0
|
||||
|
||||
do
|
||||
call getopt('hs:e:a:b:r:m:p:d:f:w:t:9864qTL:S:H:c:G:x:g:X:', &
|
||||
long_options,c,optarg,arglen,stat,offset,remain,.true.)
|
||||
if (stat .ne. 0) then
|
||||
exit
|
||||
end if
|
||||
select case (c)
|
||||
case ('h')
|
||||
display_help = .true.
|
||||
case ('s')
|
||||
read_files = .false.
|
||||
shm_key = optarg(:arglen)
|
||||
case ('e')
|
||||
exe_dir = optarg(:arglen)
|
||||
case ('a')
|
||||
data_dir = optarg(:arglen)
|
||||
case ('b')
|
||||
nsubmode = ichar (optarg(:1)) - ichar ('A')
|
||||
case ('t')
|
||||
temp_dir = optarg(:arglen)
|
||||
case ('m')
|
||||
read (optarg(:arglen), *) nthreads
|
||||
case ('p')
|
||||
read (optarg(:arglen), *) ntrperiod
|
||||
case ('d')
|
||||
read (optarg(:arglen), *) ndepth
|
||||
case ('f')
|
||||
read (optarg(:arglen), *) nrxfreq
|
||||
case ('L')
|
||||
read (optarg(:arglen), *) flow
|
||||
case ('S')
|
||||
read (optarg(:arglen), *) fsplit
|
||||
case ('H')
|
||||
read (optarg(:arglen), *) fhigh
|
||||
case ('q')
|
||||
mode = 164
|
||||
case ('4')
|
||||
mode = 4
|
||||
case ('6')
|
||||
if (mode.lt.65) mode = mode + 65
|
||||
case ('9')
|
||||
if (mode.lt.9.or.mode.eq.65) mode = mode + 9
|
||||
case ('8')
|
||||
mode = 8
|
||||
case ('T')
|
||||
tx9 = .true.
|
||||
case ('w')
|
||||
read (optarg(:arglen), *) npatience
|
||||
case ('c')
|
||||
read (optarg(:arglen), *) mycall
|
||||
case ('G')
|
||||
read (optarg(:arglen), *) mygrid
|
||||
case ('x')
|
||||
read (optarg(:arglen), *) hiscall
|
||||
case ('g')
|
||||
read (optarg(:arglen), *) hisgrid
|
||||
case ('X')
|
||||
read (optarg(:arglen), *) nexp_decode
|
||||
end select
|
||||
end do
|
||||
|
||||
if (display_help .or. stat .lt. 0 &
|
||||
.or. (.not. read_files .and. remain .gt. 0) &
|
||||
.or. (read_files .and. remain .lt. 1)) then
|
||||
|
||||
print *, 'Usage: jt9 [OPTIONS] file1 [file2 ...]'
|
||||
print *, ' Reads data from *.wav files.'
|
||||
print *, ''
|
||||
print *, ' jt9 -s <key> [-w patience] [-m threads] [-e path] [-a path] [-t path]'
|
||||
print *, ' Gets data from shared memory region with key==<key>'
|
||||
print *, ''
|
||||
print *, 'OPTIONS:'
|
||||
print *, ''
|
||||
do i = 1, size (long_options)
|
||||
call long_options(i) % print (6)
|
||||
end do
|
||||
go to 999
|
||||
endif
|
||||
|
||||
iret=fftwf_init_threads() !Initialize FFTW threading
|
||||
|
||||
! Default to 1 thread, but use nthreads for the big ones
|
||||
call fftwf_plan_with_nthreads(1)
|
||||
|
||||
! Import FFTW wisdom, if available
|
||||
wisfile=trim(data_dir)//'/jt9_wisdom.dat'// C_NULL_CHAR
|
||||
iret=fftwf_import_wisdom_from_filename(wisfile)
|
||||
|
||||
ntry65a=0
|
||||
ntry65b=0
|
||||
n65a=0
|
||||
n65b=0
|
||||
num9=0
|
||||
numfano=0
|
||||
|
||||
if (.not. read_files) then
|
||||
call jt9a() !We're running under control of WSJT-X
|
||||
go to 999
|
||||
endif
|
||||
|
||||
allocate(shared_data)
|
||||
nflatten=0
|
||||
|
||||
do iarg = offset + 1, offset + remain
|
||||
call get_command_argument (iarg, optarg, arglen)
|
||||
infile = optarg(:arglen)
|
||||
call wav%read (infile)
|
||||
nfsample=wav%audio_format%sample_rate
|
||||
i1=index(infile,'.wav')
|
||||
if(i1.lt.1) i1=index(infile,'.WAV')
|
||||
if(infile(i1-5:i1-5).eq.'_') then
|
||||
read(infile(i1-4:i1-1),*,err=1) nutc
|
||||
else
|
||||
read(infile(i1-6:i1-3),*,err=1) nutc
|
||||
endif
|
||||
go to 2
|
||||
1 nutc=0
|
||||
2 nsps=0
|
||||
if(ntrperiod.eq.1) then
|
||||
nsps=6912
|
||||
shared_data%params%nzhsym=181
|
||||
else if(ntrperiod.eq.2) then
|
||||
nsps=15360
|
||||
shared_data%params%nzhsym=178
|
||||
else if(ntrperiod.eq.5) then
|
||||
nsps=40960
|
||||
shared_data%params%nzhsym=172
|
||||
else if(ntrperiod.eq.10) then
|
||||
nsps=82944
|
||||
shared_data%params%nzhsym=171
|
||||
else if(ntrperiod.eq.30) then
|
||||
nsps=252000
|
||||
shared_data%params%nzhsym=167
|
||||
endif
|
||||
if(nsps.eq.0) stop 'Error: bad TRperiod'
|
||||
|
||||
kstep=nsps/2
|
||||
k=0
|
||||
nhsym0=-999
|
||||
npts=(60*ntrperiod-6)*12000
|
||||
if(iarg .eq. offset + 1) then
|
||||
call init_timer (trim(data_dir)//'/timer.out')
|
||||
call timer('jt9 ',0)
|
||||
endif
|
||||
|
||||
shared_data%id2=0 !??? Why is this necessary ???
|
||||
|
||||
do iblk=1,npts/kstep
|
||||
k=iblk*kstep
|
||||
if(mode.eq.8 .and. k.gt.179712) exit
|
||||
call timer('read_wav',0)
|
||||
read(unit=wav%lun,end=3) shared_data%id2(k-kstep+1:k)
|
||||
go to 4
|
||||
3 call timer('read_wav',1)
|
||||
print*,'EOF on input file ',infile
|
||||
exit
|
||||
4 call timer('read_wav',1)
|
||||
nhsym=(k-2048)/kstep
|
||||
if(nhsym.ge.1 .and. nhsym.ne.nhsym0) then
|
||||
if(mode.eq.9 .or. mode.eq.74) then
|
||||
! Compute rough symbol spectra for the JT9 decoder
|
||||
ingain=0
|
||||
call timer('symspec ',0)
|
||||
nminw=1
|
||||
call symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3, &
|
||||
ihsym,npts8)
|
||||
call timer('symspec ',1)
|
||||
endif
|
||||
nhsym0=nhsym
|
||||
if(nhsym.ge.181) exit
|
||||
endif
|
||||
enddo
|
||||
close(unit=wav%lun)
|
||||
shared_data%params%nutc=nutc
|
||||
shared_data%params%ndiskdat=.true.
|
||||
shared_data%params%ntr=60
|
||||
shared_data%params%nfqso=nrxfreq
|
||||
shared_data%params%newdat=.true.
|
||||
shared_data%params%npts8=74736
|
||||
shared_data%params%nfa=flow
|
||||
shared_data%params%nfsplit=fsplit
|
||||
shared_data%params%nfb=fhigh
|
||||
shared_data%params%ntol=20
|
||||
shared_data%params%kin=64800
|
||||
shared_data%params%nzhsym=181
|
||||
shared_data%params%ndepth=ndepth
|
||||
shared_data%params%dttol=3.
|
||||
|
||||
shared_data%params%minsync=0 !### TEST ONLY
|
||||
! shared_data%params%nfqso=1500 !### TEST ONLY
|
||||
! mycall="G3WDG " !### TEST ONLY
|
||||
! hiscall="VK7MO " !### TEST ONLY
|
||||
! hisgrid="QE37 " !### TEST ONLY
|
||||
if(mode.eq.164 .and. nsubmode.lt.100) nsubmode=nsubmode+100
|
||||
|
||||
shared_data%params%naggressive=0
|
||||
shared_data%params%n2pass=2
|
||||
! shared_data%params%nranera=8 !### ntrials=10000
|
||||
shared_data%params%nranera=6 !### ntrials=3000
|
||||
shared_data%params%nrobust=.false.
|
||||
shared_data%params%nexp_decode=nexp_decode
|
||||
shared_data%params%mycall=mycall
|
||||
shared_data%params%mygrid=mygrid
|
||||
shared_data%params%hiscall=hiscall
|
||||
shared_data%params%hisgrid=hisgrid
|
||||
if (shared_data%params%mycall == '') shared_data%params%mycall='K1ABC'
|
||||
if (shared_data%params%hiscall == '') shared_data%params%hiscall='W9XYZ'
|
||||
if (shared_data%params%hisgrid == '') shared_data%params%hiscall='EN37'
|
||||
if (tx9) then
|
||||
shared_data%params%ntxmode=9
|
||||
else
|
||||
shared_data%params%ntxmode=65
|
||||
end if
|
||||
if (mode.eq.0) then
|
||||
shared_data%params%nmode=65+9
|
||||
else
|
||||
shared_data%params%nmode=mode
|
||||
end if
|
||||
shared_data%params%nsubmode=nsubmode
|
||||
shared_data%params%datetime="2013-Apr-16 15:13" !### Temp
|
||||
if(mode.eq.9 .and. fsplit.ne.2700) shared_data%params%nfa=fsplit
|
||||
call multimode_decoder(shared_data%ss,shared_data%id2,shared_data%params,nfsample)
|
||||
enddo
|
||||
|
||||
call timer('jt9 ',1)
|
||||
call timer('jt9 ',101)
|
||||
|
||||
999 continue
|
||||
! Output decoder statistics
|
||||
call fini_timer ()
|
||||
! open (unit=12, file=trim(data_dir)//'/timer.out', status='unknown', position='append')
|
||||
! write(12,1100) n65a,ntry65a,n65b,ntry65b,numfano,num9
|
||||
!1100 format(58('-')/' JT65_1 Tries_1 JT65_2 Tries_2 JT9 Tries'/ &
|
||||
! 58('-')/6i8)
|
||||
|
||||
! Save wisdom and free memory
|
||||
iret=fftwf_export_wisdom_to_filename(wisfile)
|
||||
call four2a(a,-1,1,1,1)
|
||||
call filbig(a,-1,1,0.0,0,0,0,0,0) !used for FFT plans
|
||||
call fftwf_cleanup_threads()
|
||||
call fftwf_cleanup()
|
||||
end program jt9
|
||||
@@ -29,7 +29,7 @@ program wspr5d
|
||||
complex c(0:NZ-1) !Complex waveform
|
||||
complex cd(0:NZ-1) !Complex waveform
|
||||
complex ca(0:NZ-1) !Complex waveform
|
||||
complex zz
|
||||
complex zz,zzsum
|
||||
real*8 fMHz
|
||||
real rxdata(ND),llr(ND) !Soft symbols
|
||||
real pp(32) !Shaped pulse for OQPSK
|
||||
@@ -44,6 +44,7 @@ program wspr5d
|
||||
integer*1 idat(7)
|
||||
integer*1 decoded(KK),apmask(ND),cw(ND)
|
||||
integer*1 hbits(412),bits(13)
|
||||
logical reset
|
||||
data ib13/1,1,1,1,1,-1,-1,1,1,-1,1,-1,1/
|
||||
|
||||
nargs=iargc()
|
||||
@@ -131,41 +132,57 @@ program wspr5d
|
||||
fb=150.0
|
||||
fs400=400.0
|
||||
call getfc1(c400,fs400,fa,fb,fc1,xsnr) !First approx for freq
|
||||
!write(*,*) datetime,'initial guess ',fc1
|
||||
npeaks=5
|
||||
call getfc2(c400,npeaks,fs400,fc1,fpks) !Refined freq
|
||||
|
||||
do idf=1,npeaks ! consider the top npeak peaks
|
||||
fc2=fpks(idf)
|
||||
! do idf=1,npeaks ! consider the top npeak peaks
|
||||
do idf=1,1 ! for genie-aided sync
|
||||
fc1=125.0 ! genie provided
|
||||
fc2=0.0 ! from the genie
|
||||
! fc2=fpks(idf)
|
||||
call downsample(c400,fc1+fc2,cd)
|
||||
s2=sum(cd*conjg(cd))/(16*412)
|
||||
cd=cd/sqrt(s2)
|
||||
do is=0,8 ! dt search range is narrow, to save time.
|
||||
do is=0,0 ! dt search range is zeroed for genie-aided sync
|
||||
idt=is/2
|
||||
if( mod(is,2).eq. 1 ) idt=-(is+1)/2
|
||||
xdt=real(22+idt)/22.222 - 1.0
|
||||
ca=cshift(cd,22+idt)
|
||||
do iseq=1,3 ! try sequence estimation lengths of 3, 6, and 9 bits.
|
||||
zzsum=0.0
|
||||
do iseq=3,4
|
||||
if(iseq.eq.4) then
|
||||
k=1-2*3
|
||||
nseq=9
|
||||
istep=3*4
|
||||
else
|
||||
k=1-2*iseq
|
||||
nseq=iseq*3
|
||||
do i=1,408,iseq*4
|
||||
k=k+iseq*2
|
||||
istep=iseq*4
|
||||
endif
|
||||
do i=1,408,istep
|
||||
j=(i+1)*16
|
||||
call mskseqdet(nseq,ca(j),pp,id(k),softbits,1,phase)
|
||||
hbits(i:i+iseq*4)=bits
|
||||
sbits(i:i+iseq*4)=bits
|
||||
|
||||
if(iseq.eq.4) then
|
||||
! phase=-1.18596900
|
||||
! For now, average complex corr. coeffs over the entire frame to
|
||||
! estimate phase
|
||||
phase=atan2(imag(zzsum),real(zzsum))
|
||||
k=k+3*2
|
||||
call mskcohdet(nseq,ca(j),pp,id(k),softbits,phase)
|
||||
else
|
||||
k=k+iseq*2
|
||||
call mskseqdet(nseq,ca(j),pp,id(k),softbits,1,zz)
|
||||
zzsum=zzsum+zz
|
||||
endif
|
||||
sbits(i+1)=softbits(1)
|
||||
sbits(i+2)=softbits(2)
|
||||
if( id(k+1) .ne. 0 ) sbits(i+2)=id(k+1)*25
|
||||
sbits(i+3)=softbits(3)
|
||||
|
||||
if( iseq .ge. 2 ) then
|
||||
sbits(i+5)=softbits(4)
|
||||
sbits(i+6)=softbits(5)
|
||||
if( id(k+3) .ne. 0 ) sbits(i+6)=id(k+3)*25
|
||||
sbits(i+7)=softbits(6)
|
||||
if( iseq .eq. 3 ) then
|
||||
if( iseq .ge. 3 ) then
|
||||
sbits(i+9)=softbits(7)
|
||||
sbits(i+10)=softbits(8)
|
||||
if( id(k+5) .ne. 0 ) sbits(i+10)=id(k+5)*25
|
||||
@@ -188,18 +205,21 @@ program wspr5d
|
||||
rx2av=sum(rxdata*rxdata)/ND
|
||||
rxsig=sqrt(rx2av-rxav*rxav)
|
||||
rxdata=rxdata/rxsig
|
||||
! sigma=0.84
|
||||
sigma=1.20
|
||||
llr=2*rxdata/(sigma*sigma)
|
||||
apmask=0
|
||||
max_iterations=40
|
||||
|
||||
ifer=0
|
||||
nbadcrc=0
|
||||
call bpdecode300(llr,apmask,max_iterations,decoded,niterations,cw)
|
||||
! niterations will be equal to the Hamming distance between hard received word and the codeword
|
||||
if(niterations.lt.0) call osd300(llr,3,decoded,niterations,cw)
|
||||
if(niterations.ge.0) call chkcrc10(decoded,nbadcrc)
|
||||
if(niterations.lt.0 .or. nbadcrc.ne.0) ifer=1
|
||||
nhardmin=0
|
||||
if(niterations.lt.0) call osd300(llr,apmask,5,decoded,cw,nhardmin,dmin)
|
||||
if(nhardmin.gt.0) niterations=nhardmin
|
||||
nbadcrc=0
|
||||
call chkcrc10(decoded,nbadcrc)
|
||||
if(nbadcrc.ne.0) ifer=1
|
||||
|
||||
if( ifer.eq.0 ) then
|
||||
write(cbits,1200) decoded(1:50)
|
||||
1200 format(50i1)
|
||||
@@ -208,12 +228,14 @@ program wspr5d
|
||||
idat(7)=ishft(idat(7),6)
|
||||
call wqdecode(idat,message,itype)
|
||||
nsnr=nint(xsnr)
|
||||
freq=fMHz + 1.d-6*(fc1+fc2)
|
||||
! freq=fMHz + 1.d-6*(fc1+fc2)
|
||||
freq=fc1+fc2
|
||||
nfdot=0
|
||||
write(13,1210) datetime,0,nsnr,xdt,freq,message,nfdot
|
||||
1210 format(a11,2i4,f6.2,f12.7,2x,a22,i3)
|
||||
write(*,1212) datetime(8:11),nsnr,xdt,freq,nfdot,message,'*',idf,nseq,is,niterations
|
||||
1212 format(a4,i4,f5.1,f11.6,i3,2x,a22,a1,i3,i3,i3,i4)
|
||||
write(*,1212) datetime(8:11),nsnr,xdt,freq,nfdot,message,'*',idf,nseq,is,iseq,niterations
|
||||
!1212 format(a4,i4,f5.1,f11.6,i3,2x,a22,a1,i3,i3,i3,i4)
|
||||
1212 format(a4,i4,f8.3,f8.3,i3,2x,a22,a1,i3,i3,i3,i3,i4)
|
||||
goto 888
|
||||
endif
|
||||
enddo !iseq
|
||||
@@ -239,7 +261,7 @@ subroutine getmetric(ib,ps,xmet)
|
||||
return
|
||||
end subroutine getmetric
|
||||
|
||||
subroutine mskseqdet(ns,cdat,pp,bsync,softbits,ncoh,phase)
|
||||
subroutine mskseqdet(ns,cdat,pp,bsync,softbits,ncoh,zz)
|
||||
!
|
||||
! Detect sequences of 3, 6, or 9 bits (ns).
|
||||
! Sync bits are assumed to be known.
|
||||
@@ -259,7 +281,7 @@ np=2**ns-1
|
||||
idfmax=40
|
||||
if( ncoh .eq. 1 ) idfmax=0
|
||||
do idf=0,idfmax
|
||||
if( mod(idf,2).eq.1 ) deltaf=idf/2*0.02
|
||||
if( mod(idf,2).eq.0 ) deltaf=idf/2*0.02
|
||||
if( mod(idf,2).eq.1 ) deltaf=-(idf+1)/2*0.02
|
||||
dphi=twopi*deltaf*dt
|
||||
cfac=cmplx(cos(dphi),sin(dphi))
|
||||
@@ -325,7 +347,6 @@ do idf=0,idfmax
|
||||
cbest=cideal
|
||||
fbest=deltaf
|
||||
zz=sum(cdat*conjg(cbest))/1.e3
|
||||
phase=atan2(imag(zz),real(zz))
|
||||
endif
|
||||
enddo
|
||||
if( ibflag .eq. 1 ) then ! new best found
|
||||
@@ -348,6 +369,29 @@ if( ns .ge. 6 ) then
|
||||
endif
|
||||
end subroutine mskseqdet
|
||||
|
||||
subroutine mskcohdet(ns,cdat,pp,bsync,softbits,phase)
|
||||
!
|
||||
! Coherent demodulate blocks of 9 bits (ns).
|
||||
!
|
||||
complex cdat(16*12),crot(16*12)
|
||||
real pp(32),softbits(9)
|
||||
|
||||
np=2**ns-1
|
||||
|
||||
softbits=0.0
|
||||
crot=cdat*cmplx(cos(phase),-sin(phase))
|
||||
softbits(1)=sum(imag(crot(1:32)*pp))
|
||||
softbits(2)=sum(real(crot(17:48)*pp))
|
||||
softbits(3)=sum(imag(crot(33:64)*pp))
|
||||
softbits(4)=sum(imag(crot(65:96)*pp))
|
||||
softbits(5)=sum(real(crot(81:112)*pp))
|
||||
softbits(6)=sum(imag(crot(97:128)*pp))
|
||||
softbits(7)=sum(imag(crot(129:160)*pp))
|
||||
softbits(8)=sum(real(crot(145:176)*pp))
|
||||
softbits(9)=sum(imag(crot(161:192)*pp))
|
||||
softbits=softbits/64.
|
||||
end subroutine mskcohdet
|
||||
|
||||
subroutine downsample(ci,f0,co)
|
||||
parameter(NI=412*288,NO=NI/18)
|
||||
complex ci(0:NI-1),ct(0:NI-1)
|
||||
@@ -359,7 +403,8 @@ subroutine downsample(ci,f0,co)
|
||||
i0=nint(f0/df)
|
||||
co=0.0
|
||||
co(0)=ct(i0)
|
||||
b=3.0
|
||||
! b=3.0 !optimized for sequence detection
|
||||
b=6.0
|
||||
do i=1,NO/2
|
||||
arg=(i*df/b)**2
|
||||
filt=exp(-arg)
|
||||
@@ -1,238 +0,0 @@
|
||||
program ldpcsim174
|
||||
! End to end test of the (174,75)/crc12 encoder and decoder.
|
||||
use crc
|
||||
use packjt
|
||||
|
||||
parameter(NRECENT=10)
|
||||
character*12 recent_calls(NRECENT)
|
||||
character*22 msg,msgsent,msgreceived
|
||||
character*8 arg
|
||||
integer*1, allocatable :: codeword(:), decoded(:), message(:)
|
||||
integer*1, target:: i1Msg8BitBytes(11)
|
||||
integer*1 msgbits(87)
|
||||
integer*1 apmask(174), cw(174)
|
||||
integer*2 checksum
|
||||
integer*4 i4Msg6BitWords(13)
|
||||
integer colorder(174)
|
||||
integer nerrtot(174),nerrdec(174),nmpcbad(87)
|
||||
logical checksumok,fsk,bpsk
|
||||
real*8, allocatable :: rxdata(:)
|
||||
real, allocatable :: llr(:)
|
||||
|
||||
data colorder/ &
|
||||
0, 1, 2, 3, 30, 4, 5, 6, 7, 8, 9, 10, 11, 32, 12, 40, 13, 14, 15, 16,&
|
||||
17, 18, 37, 45, 29, 19, 20, 21, 41, 22, 42, 31, 33, 34, 44, 35, 47, 51, 50, 43,&
|
||||
36, 52, 63, 46, 25, 55, 27, 24, 23, 53, 39, 49, 59, 38, 48, 61, 60, 57, 28, 62,&
|
||||
56, 58, 65, 66, 26, 70, 64, 69, 68, 67, 74, 71, 54, 76, 72, 75, 78, 77, 80, 79,&
|
||||
73, 83, 84, 81, 82, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,&
|
||||
100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,&
|
||||
120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,&
|
||||
140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,&
|
||||
160,161,162,163,164,165,166,167,168,169,170,171,172,173/
|
||||
|
||||
do i=1,NRECENT
|
||||
recent_calls(i)=' '
|
||||
enddo
|
||||
nerrtot=0
|
||||
nerrdec=0
|
||||
nmpcbad=0 ! Used to collect the number of errors in the message+crc part of the codeword
|
||||
|
||||
nargs=iargc()
|
||||
if(nargs.ne.4) then
|
||||
print*,'Usage: ldpcsim niter ndepth #trials s '
|
||||
print*,'eg: ldpcsim 10 2 1000 0.84'
|
||||
print*,'belief propagation iterations: niter, ordered-statistics depth: ndepth'
|
||||
print*,'If s is negative, then value is ignored and sigma is calculated from SNR.'
|
||||
return
|
||||
endif
|
||||
call getarg(1,arg)
|
||||
read(arg,*) max_iterations
|
||||
call getarg(2,arg)
|
||||
read(arg,*) ndepth
|
||||
call getarg(3,arg)
|
||||
read(arg,*) ntrials
|
||||
call getarg(4,arg)
|
||||
read(arg,*) s
|
||||
|
||||
fsk=.false.
|
||||
bpsk=.true.
|
||||
|
||||
! don't count crc bits as data bits
|
||||
N=174
|
||||
K=87
|
||||
! scale Eb/No for a (174,87) code
|
||||
rate=real(K)/real(N)
|
||||
|
||||
write(*,*) "rate: ",rate
|
||||
write(*,*) "niter= ",max_iterations," s= ",s
|
||||
|
||||
allocate ( codeword(N), decoded(K), message(K) )
|
||||
allocate ( rxdata(N), llr(N) )
|
||||
|
||||
msg="K1JT K9AN EN50"
|
||||
! msg="G4WJS K9AN EN50"
|
||||
call packmsg(msg,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes
|
||||
call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent
|
||||
write(*,*) "message sent ",msgsent
|
||||
|
||||
i4=0
|
||||
ik=0
|
||||
im=0
|
||||
do i=1,12
|
||||
nn=i4Msg6BitWords(i)
|
||||
do j=1, 6
|
||||
ik=ik+1
|
||||
i4=i4+i4+iand(1,ishft(nn,j-6))
|
||||
i4=iand(i4,255)
|
||||
if(ik.eq.8) then
|
||||
im=im+1
|
||||
! if(i4.gt.127) i4=i4-256
|
||||
i1Msg8BitBytes(im)=i4
|
||||
ik=0
|
||||
endif
|
||||
enddo
|
||||
enddo
|
||||
|
||||
i1Msg8BitBytes(10:11)=0
|
||||
checksum = crc12 (c_loc (i1Msg8BitBytes), 11)
|
||||
! For reference, the next 3 lines show how to check the CRC
|
||||
i1Msg8BitBytes(10)=checksum/256
|
||||
i1Msg8BitBytes(11)=iand (checksum,255)
|
||||
checksumok = crc12_check(c_loc (i1Msg8BitBytes), 11)
|
||||
if( checksumok ) write(*,*) 'Good checksum'
|
||||
|
||||
! K=87, For now:
|
||||
! msgbits(1:72) JT message bits
|
||||
! msgbits(73:75) 3 free message bits (set to 0)
|
||||
! msgbits(76:87) CRC12
|
||||
mbit=0
|
||||
do i=1, 9
|
||||
i1=i1Msg8BitBytes(i)
|
||||
do ibit=1,8
|
||||
mbit=mbit+1
|
||||
msgbits(mbit)=iand(1,ishft(i1,ibit-8))
|
||||
enddo
|
||||
enddo
|
||||
msgbits(73:75)=0 ! the three extra message bits go here
|
||||
i1=i1Msg8BitBytes(10) ! First 4 bits of crc12 are LSB of this byte
|
||||
do ibit=1,4
|
||||
msgbits(75+ibit)=iand(1,ishft(i1,ibit-4))
|
||||
enddo
|
||||
i1=i1Msg8BitBytes(11) ! Now shift in last 8 bits of the CRC
|
||||
do ibit=1,8
|
||||
msgbits(79+ibit)=iand(1,ishft(i1,ibit-8))
|
||||
enddo
|
||||
|
||||
write(*,*) 'message'
|
||||
write(*,'(11(8i1,1x))') msgbits
|
||||
|
||||
call encode174(msgbits,codeword)
|
||||
call init_random_seed()
|
||||
! call sgran()
|
||||
|
||||
write(*,*) 'codeword'
|
||||
write(*,'(22(8i1,1x))') codeword
|
||||
|
||||
write(*,*) "Es/N0 SNR2500 ngood nundetected nbadcrc sigma"
|
||||
do idb = 20,-10,-1
|
||||
!do idb = -3,-3,-1
|
||||
db=idb/2.0-1.0
|
||||
sigma=1/sqrt( 2*(10**(db/10.0)) )
|
||||
ngood=0
|
||||
nue=0
|
||||
nbadcrc=0
|
||||
nberr=0
|
||||
do itrial=1, ntrials
|
||||
! Create a realization of a noisy received word
|
||||
do i=1,N
|
||||
if( bpsk ) then
|
||||
rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran()
|
||||
elseif( fsk ) then
|
||||
if( codeword(i) .eq. 1 ) then
|
||||
r1=(1.0 + sigma*gran())**2 + (sigma*gran())**2
|
||||
r2=(sigma*gran())**2 + (sigma*gran())**2
|
||||
elseif( codeword(i) .eq. 0 ) then
|
||||
r2=(1.0 + sigma*gran())**2 + (sigma*gran())**2
|
||||
r1=(sigma*gran())**2 + (sigma*gran())**2
|
||||
endif
|
||||
! rxdata(i)=0.35*(sqrt(r1)-sqrt(r2))
|
||||
! rxdata(i)=0.35*(exp(r1)-exp(r2))
|
||||
rxdata(i)=0.12*(log(r1)-log(r2))
|
||||
endif
|
||||
enddo
|
||||
nerr=0
|
||||
do i=1,N
|
||||
if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1
|
||||
enddo
|
||||
nerrtot(nerr)=nerrtot(nerr)+1
|
||||
nberr=nberr+nerr
|
||||
|
||||
! Correct signal normalization is important for this decoder.
|
||||
rxav=sum(rxdata)/N
|
||||
rx2av=sum(rxdata*rxdata)/N
|
||||
rxsig=sqrt(rx2av-rxav*rxav)
|
||||
rxdata=rxdata/rxsig
|
||||
! To match the metric to the channel, s should be set to the noise standard deviation.
|
||||
! For now, set s to the value that optimizes decode probability near threshold.
|
||||
! The s parameter can be tuned to trade a few tenth's dB of threshold for an order of
|
||||
! magnitude in UER
|
||||
if( s .lt. 0 ) then
|
||||
ss=sigma
|
||||
else
|
||||
ss=s
|
||||
endif
|
||||
|
||||
llr=2.0*rxdata/(ss*ss)
|
||||
nap=0 ! number of AP bits
|
||||
llr(colorder(174-87+1:174-87+nap)+1)=5*(2.0*msgbits(1:nap)-1.0)
|
||||
apmask=0
|
||||
apmask(colorder(174-87+1:174-87+nap)+1)=1
|
||||
|
||||
! max_iterations is max number of belief propagation iterations
|
||||
call bpdecode174(llr, apmask, max_iterations, decoded, cw, nharderrors,niterations)
|
||||
if( ndepth .ge. 0 .and. nharderrors .lt. 0 ) call osd174(llr, apmask, ndepth, decoded, cw, nharderrors, dmin)
|
||||
! If the decoder finds a valid codeword, nharderrors will be .ge. 0.
|
||||
if( nharderrors .ge. 0 ) then
|
||||
call extractmessage174(decoded,msgreceived,ncrcflag,recent_calls,nrecent)
|
||||
if( ncrcflag .ne. 1 ) then
|
||||
nbadcrc=nbadcrc+1
|
||||
endif
|
||||
|
||||
nueflag=0
|
||||
nerrmpc=0
|
||||
do i=1,K ! find number of errors in message+crc part of codeword
|
||||
if( msgbits(i) .ne. decoded(i) ) then
|
||||
nueflag=1
|
||||
nerrmpc=nerrmpc+1
|
||||
endif
|
||||
enddo
|
||||
nmpcbad(nerrmpc)=nmpcbad(nerrmpc)+1
|
||||
if( ncrcflag .eq. 1 ) then
|
||||
if( nueflag .eq. 0 ) then
|
||||
ngood=ngood+1
|
||||
nerrdec(nerr)=nerrdec(nerr)+1
|
||||
else if( nueflag .eq. 1 ) then
|
||||
nue=nue+1;
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
enddo
|
||||
baud=12000/1920
|
||||
snr2500=db+10.0*log10((baud/2500.0))
|
||||
pberr=real(nberr)/(real(ntrials*N))
|
||||
write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2,8x,e10.3)") db,snr2500,ngood,nue,nbadcrc,ss,pberr
|
||||
|
||||
enddo
|
||||
|
||||
open(unit=23,file='nerrhisto.dat',status='unknown')
|
||||
do i=1,174
|
||||
write(23,'(i4,2x,i10,i10,f10.2)') i,nerrdec(i),nerrtot(i),real(nerrdec(i))/real(nerrtot(i)+1e-10)
|
||||
enddo
|
||||
close(23)
|
||||
open(unit=25,file='nmpcbad.dat',status='unknown')
|
||||
do i=1,87
|
||||
write(25,'(i4,2x,i10)') i,nmpcbad(i)
|
||||
enddo
|
||||
close(25)
|
||||
|
||||
end program ldpcsim174
|
||||
@@ -22,8 +22,8 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
|
||||
m_settings (settings),
|
||||
m_palettes_path {":/Palettes"},
|
||||
m_ntr0 {0},
|
||||
m_bHaveTransmitted {false},
|
||||
m_n {0}
|
||||
m_n {0},
|
||||
m_bHaveTransmitted {false}
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
@@ -169,12 +169,16 @@ void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dat
|
||||
int i=int(ui->widePlot->startFreq()/df3 + 0.5);
|
||||
int jz=5000.0/(nbpp*df3);
|
||||
if(jz>MAX_SCREENSIZE) jz=MAX_SCREENSIZE;
|
||||
m_jz=jz;
|
||||
for (int j=0; j<jz; j++) {
|
||||
float ss=0;
|
||||
float ss=0.0;
|
||||
float smax=0;
|
||||
for (int k=0; k<nbpp; k++) {
|
||||
if(splot[i]>ss) ss=splot[i];
|
||||
i++;
|
||||
float sp=splot[i++];
|
||||
ss += sp;
|
||||
smax=qMax(smax,sp);
|
||||
}
|
||||
// swide[j]=nbpp*smax;
|
||||
swide[j]=nbpp*ss;
|
||||
}
|
||||
|
||||
@@ -184,9 +188,12 @@ void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dat
|
||||
if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && ntr<m_ntr0)) {
|
||||
float flagValue=1.0e30;
|
||||
if(m_bHaveTransmitted) flagValue=2.0e30;
|
||||
for (int i=0; i<2048; i++) {
|
||||
for(int i=0; i<MAX_SCREENSIZE; i++) {
|
||||
swide[i] = flagValue;
|
||||
}
|
||||
for(int i=0; i<NSMAX; i++) {
|
||||
splot[i] = flagValue;
|
||||
}
|
||||
m_bHaveTransmitted=false;
|
||||
}
|
||||
m_ntr0=ntr;
|
||||
@@ -322,7 +329,7 @@ void WideGraph::on_spec2dComboBox_currentIndexChanged(const QString &arg1)
|
||||
if(arg1=="Reference") {
|
||||
ui->widePlot->setReference(true);
|
||||
}
|
||||
if(ui->widePlot->scaleOK ()) ui->widePlot->draw(swide,false,false);
|
||||
replot();
|
||||
}
|
||||
|
||||
void WideGraph::on_fSplitSpinBox_valueChanged(int n) //fSplit
|
||||
@@ -387,6 +394,7 @@ void WideGraph::on_paletteComboBox_activated (QString const& palette) //palet
|
||||
{
|
||||
m_waterfallPalette = palette;
|
||||
readPalette();
|
||||
replot();
|
||||
}
|
||||
|
||||
void WideGraph::on_cbFlatten_toggled(bool b) //Flatten On/Off
|
||||
@@ -441,14 +449,21 @@ bool WideGraph::useRef() //Flatten
|
||||
return m_bRef;
|
||||
}
|
||||
|
||||
void WideGraph::replot()
|
||||
{
|
||||
if(ui->widePlot->scaleOK()) ui->widePlot->replot();
|
||||
}
|
||||
|
||||
void WideGraph::on_gainSlider_valueChanged(int value) //Gain
|
||||
{
|
||||
ui->widePlot->setPlotGain(value);
|
||||
replot();
|
||||
}
|
||||
|
||||
void WideGraph::on_zeroSlider_valueChanged(int value) //Zero
|
||||
{
|
||||
ui->widePlot->setPlotZero(value);
|
||||
replot();
|
||||
}
|
||||
|
||||
void WideGraph::on_gain2dSlider_valueChanged(int value) //Gain2
|
||||
@@ -1,9 +1,12 @@
|
||||
// Status=review
|
||||
The following buttons appear just under the decoded text windows on
|
||||
The following controls appear just under the decoded text windows on
|
||||
the main screen:
|
||||
|
||||
//.Main UI
|
||||
image::main-ui-controls.png[align="left",width=650,alt="Main UI Controls"]
|
||||
image::main-ui-controls.png[align="center",width=650,alt="Main UI Controls"]
|
||||
|
||||
* When *CQ only* is checked, only messages from stations calling CQ will
|
||||
be displayed in the left text panel.
|
||||
|
||||
* *Log QSO* raises a dialog window pre-filled with known information
|
||||
about a QSO you have nearly completed. You can edit or add to this
|
||||
@@ -62,3 +65,5 @@ Toggle the button a second time or click *Halt Tx* to terminate the
|
||||
*Tune* process. Note that activating *Tune* interrupts a receive
|
||||
sequence and will prevent decoding during that sequence.
|
||||
|
||||
* Uncheck the box *Menus* to make the top-of-window menus disappear,
|
||||
leaving more vertical space for decoded messages.
|
||||
@@ -66,8 +66,9 @@ program jt9
|
||||
'FLAGS') ]
|
||||
|
||||
type(dec_data), allocatable :: shared_data
|
||||
character(len=12) :: mycall, hiscall
|
||||
character(len=6) :: mygrid, hisgrid
|
||||
character(len=20) :: datetime=''
|
||||
character(len=12) :: mycall='K1ABC', hiscall='W9XYZ'
|
||||
character(len=6) :: mygrid='', hisgrid='EN37'
|
||||
common/patience/npatience,nthreads
|
||||
common/decstats/ntry65a,ntry65b,n65a,n65b,num9,numfano
|
||||
data npatience/1/,nthreads/1/
|
||||
@@ -260,7 +261,8 @@ program jt9
|
||||
shared_data%params%kin=64800
|
||||
shared_data%params%nzhsym=181
|
||||
shared_data%params%ndepth=ndepth
|
||||
shared_data%params%lapon=.true.
|
||||
shared_data%params%lft8apon=.true.
|
||||
shared_data%params%ljt65apon=.true.
|
||||
shared_data%params%napwid=75
|
||||
shared_data%params%dttol=3.
|
||||
|
||||
@@ -277,13 +279,10 @@ program jt9
|
||||
shared_data%params%nranera=6 !### ntrials=3000
|
||||
shared_data%params%nrobust=.false.
|
||||
shared_data%params%nexp_decode=nexp_decode
|
||||
shared_data%params%mycall=mycall
|
||||
shared_data%params%mygrid=mygrid
|
||||
shared_data%params%hiscall=hiscall
|
||||
shared_data%params%hisgrid=hisgrid
|
||||
if (shared_data%params%mycall == '') shared_data%params%mycall='K1ABC'
|
||||
if (shared_data%params%hiscall == '') shared_data%params%hiscall='W9XYZ'
|
||||
if (shared_data%params%hisgrid == '') shared_data%params%hiscall='EN37'
|
||||
shared_data%params%mycall=transfer(mycall,shared_data%params%mycall)
|
||||
shared_data%params%mygrid=transfer(mygrid,shared_data%params%mygrid)
|
||||
shared_data%params%hiscall=transfer(hiscall,shared_data%params%hiscall)
|
||||
shared_data%params%hisgrid=transfer(hisgrid,shared_data%params%hisgrid)
|
||||
if (tx9) then
|
||||
shared_data%params%ntxmode=9
|
||||
else
|
||||
@@ -295,7 +294,8 @@ program jt9
|
||||
shared_data%params%nmode=mode
|
||||
end if
|
||||
shared_data%params%nsubmode=nsubmode
|
||||
shared_data%params%datetime="2013-Apr-16 15:13" !### Temp
|
||||
datetime="2013-Apr-16 15:13" !### Temp
|
||||
shared_data%params%datetime=transfer(datetime,shared_data%params%datetime)
|
||||
if(mode.eq.9 .and. fsplit.ne.2700) shared_data%params%nfa=fsplit
|
||||
call multimode_decoder(shared_data%ss,shared_data%id2,shared_data%params,nfsample)
|
||||
enddo
|
||||
@@ -1,31 +0,0 @@
|
||||
#ifndef PHASE_EQUALIZATION_DIALOG_HPP__
|
||||
#define PHASE_EQUALIZATION_DIALOG_HPP__
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "pimpl_h.hpp"
|
||||
|
||||
class QWidget;
|
||||
class QSettings;
|
||||
class QDir;
|
||||
|
||||
class PhaseEqualizationDialog
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PhaseEqualizationDialog (QSettings *
|
||||
, QDir const& data_directory
|
||||
, QVector<double> const& coefficients
|
||||
, QWidget * = nullptr);
|
||||
Q_SLOT void show ();
|
||||
|
||||
Q_SIGNAL void phase_equalization_changed (QVector<double> const&);
|
||||
|
||||
private:
|
||||
class impl;
|
||||
pimpl<impl> m_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef LIVE_FREQUENCY_VALIDATOR_HPP__
|
||||
#define LIVE_FREQUENCY_VALIDATOR_HPP__
|
||||
|
||||
#include <QObject>
|
||||
#include <QRegExpValidator>
|
||||
|
||||
#include "Radio.hpp"
|
||||
|
||||
class Bands;
|
||||
class FrequencyList;
|
||||
class QComboBox;
|
||||
class QWidget;
|
||||
|
||||
//
|
||||
// Class LiveFrequencyValidator
|
||||
//
|
||||
// QLineEdit validator that controls input to an editable
|
||||
// QComboBox where the user can enter a valid band or a valid
|
||||
// frequency in megahetz.
|
||||
//
|
||||
// Collabrations
|
||||
//
|
||||
// Implements the QRegExpValidator interface. Validates input
|
||||
// from the supplied QComboBox as either a valid frequency in
|
||||
// megahertz or a valid band as defined by the supplied column of
|
||||
// the supplied QAbstractItemModel.
|
||||
//
|
||||
class LiveFrequencyValidator final
|
||||
: public QRegExpValidator
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
using Frequency = Radio::Frequency;
|
||||
|
||||
LiveFrequencyValidator (QComboBox * combo_box // associated combo box
|
||||
, Bands const * bands // bands model
|
||||
, FrequencyList const * frequencies // working
|
||||
// frequencies
|
||||
// model
|
||||
, Frequency const * nominal_frequency
|
||||
, QWidget * parent = nullptr);
|
||||
|
||||
State validate (QString& input, int& pos) const override;
|
||||
void fixup (QString& input) const override;
|
||||
|
||||
Q_SIGNAL void valid (Frequency) const;
|
||||
|
||||
private:
|
||||
Bands const * bands_;
|
||||
FrequencyList const * frequencies_;
|
||||
Frequency const * nominal_frequency_;
|
||||
QComboBox * combo_box_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,200 +0,0 @@
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/* Free software: Progressive edge-growth (PEG) algorithm */
|
||||
/* Created by Xiaoyu Hu */
|
||||
/* Evangelos Eletheriou */
|
||||
/* Dieter Arnold */
|
||||
/* IBM Research, Zurich Research Lab., Switzerland */
|
||||
/* */
|
||||
/* The C++ sources files have been compiled using xlC compiler */
|
||||
/* at IBM RS/6000 running AIX. For other compilers and platforms,*/
|
||||
/* minor changes might be needed. */
|
||||
/* */
|
||||
/* Bug reporting to: xhu@zurich.ibm.com */
|
||||
/**********************************************************************/
|
||||
|
||||
////
|
||||
// Modified by F. P. Beekhof; 2008 / 08 / 19
|
||||
////
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
#include "BigGirth.h"
|
||||
#include "Random.h"
|
||||
#include "CyclesOfGraph.h"
|
||||
|
||||
const double EPS = 1e-6;
|
||||
|
||||
using namespace std;
|
||||
|
||||
void usage()
|
||||
{
|
||||
cout<<"*******************************************************************************************"<<endl;
|
||||
cout<<" Usage Reminder: MainPEG -numM M -numN N -codeName CodeName -degFileName DegFileName " <<endl;
|
||||
cout<<" option: -sglConcent SglConcent " <<endl;
|
||||
cout<<" sglConcent==0 ----- strictly concentrated parity-check " <<endl;
|
||||
cout<<" degree distribution (including regular graphs)" <<endl;
|
||||
cout<<" sglConcent==1 ----- Best-effort concentrated (DEFAULT) " <<endl;
|
||||
cout<<" option: -tgtGirth TgtGirth " <<endl;
|
||||
cout<<" TgtGirth==4, 6 ...; if very large, then greedy PEG (DEFAULT) " <<endl;
|
||||
cout<<" IF sglConcent==0, TgtGirth is recommended to be set relatively small" <<endl;
|
||||
cout<<" option: -q " <<endl;
|
||||
cout<<" Quiet mode. Produces less output to the screen. " <<endl;
|
||||
cout<<" option: -outputMode <0,1,2> " <<endl;
|
||||
cout<<" Specifies output format. " <<endl;
|
||||
cout<<" '0': H in compressed format (default) " <<endl;
|
||||
cout<<" '1': H in un-compressed format " <<endl;
|
||||
cout<<" '2': G and H in compressed format " <<endl;
|
||||
cout<<" " <<endl;
|
||||
cout<<" Remarks: File CodeName stores the generated PEG Tanner graph. The first line contains"<<endl;
|
||||
cout<<" the block length, N. The second line defines the number of parity-checks, M."<<endl;
|
||||
cout<<" The third line defines the number of columns of the compressed parity-check "<<endl;
|
||||
cout<<" matrix. The following M lines are then the compressed parity-check matrix. "<<endl;
|
||||
cout<<" Each of the M rows contains the indices (1 ... N) of 1's in the compressed "<<endl;
|
||||
cout<<" row of parity-check matrix. If not all column entries are used, the column "<<endl;
|
||||
cout<<" is filled up with 0's. "<<endl;
|
||||
cout<<" "<<endl;
|
||||
cout<<" If both G and H are in the output, (outMode 2), the first line contains"<<endl;
|
||||
cout<<" N, the 2nd line K, the number of message bits, the 3rd line M, the 4th line"<<endl;
|
||||
cout<<" contains the number of rows of the compressed generator matrix; the 5th"<<endl;
|
||||
cout<<" defines the number of columns of the compressed parity-check matrix. The"<<endl;
|
||||
cout<<" format of G is almost like that of H, but vertical -- i.e. the padding"<<endl;
|
||||
cout<<" zeroes are on the bottom. "<<endl;
|
||||
|
||||
cout<<" "<<endl;
|
||||
cout<<" File DegFileName is the input file to specify the degree distribution (node "<<endl;
|
||||
cout<<" perspective). The first line contains the number of various degrees. The second"<<endl;
|
||||
cout<<" defines the row vector of degree sequence in the increasing order. The vector"<<endl;
|
||||
cout<<" of fractions of the corresponding degree is defined in the last line. "<<endl;
|
||||
cout<<" "<<endl;
|
||||
cout<<" A log file called 'leftHandGirth.dat' will also be generated and stored in the"<<endl;
|
||||
cout<<" current directory, which gives the girth of the left-hand subgraph of j, where"<<endl;
|
||||
cout<<" 1<=j<=N. The left-hand subgraph of j is defined as all the edges emanating from"<<endl;
|
||||
cout<<" bit nodes {1 ... j} and their associated nodes. "<<endl;
|
||||
cout<<" "<<endl;
|
||||
cout<<" The last point is, when strictly concentrated parity-check degree distribution"<<endl;
|
||||
cout<<" is invoked, i.e. sglConcent==0, the girth might be weaken to some extent as "<<endl;
|
||||
cout<<" compared to the generic PEG algorithm. "<<endl;
|
||||
cout<<"**********************************************************************************************"<<endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
int main(int argc, char * argv[]){
|
||||
int sglConcent=1; // default to non-strictly concentrated parity-check distribution
|
||||
int targetGirth=100000; // default to greedy PEG version
|
||||
std::string codeName, degFileName;
|
||||
int M = -1, N = -1;
|
||||
bool verbose = true;
|
||||
|
||||
const int OUTPUT_MODE_H_COMPRESSED = 0;
|
||||
const int OUTPUT_MODE_H = 1;
|
||||
const int OUTPUT_MODE_G_H_COMPRESSED = 2;
|
||||
int output_mode = OUTPUT_MODE_H_COMPRESSED; // default
|
||||
|
||||
if (argc<9) {
|
||||
usage();
|
||||
}else {
|
||||
for(int i=1;i<argc;++i){
|
||||
if (strcmp(argv[i], "-numM")==0) {
|
||||
if (++i >= argc) usage();
|
||||
M=atoi(argv[i]);
|
||||
} else if(strcmp(argv[i], "-numN")==0) {
|
||||
if (++i >= argc) usage();
|
||||
N=atoi(argv[i]);
|
||||
} else if(strcmp(argv[i], "-codeName")==0) {
|
||||
if (++i >= argc) usage();
|
||||
codeName = argv[i];
|
||||
} else if(strcmp(argv[i], "-degFileName")==0) {
|
||||
if (++i >= argc) usage();
|
||||
degFileName = argv[i];
|
||||
} else if(strcmp(argv[i], "-sglConcent")==0) {
|
||||
if (++i >= argc) usage();
|
||||
sglConcent=atoi(argv[i]);
|
||||
} else if(strcmp(argv[i], "-tgtGirth")==0) {
|
||||
if (++i >= argc) usage();
|
||||
targetGirth=atoi(argv[i]);
|
||||
} else if(strcmp(argv[i], "-outputMode")==0) {
|
||||
if (++i >= argc) usage();
|
||||
output_mode=atoi(argv[i]);
|
||||
} else if(strcmp(argv[i], "-q")==0) {
|
||||
verbose=false;
|
||||
} else{
|
||||
usage();
|
||||
}
|
||||
}
|
||||
if (M == -1 || N == -1) {
|
||||
cout<<"Error: M or N not specified!"<<endl;
|
||||
exit(-1);
|
||||
}
|
||||
if (M>N) {
|
||||
cout<<"Error: M must be smaller than N!"<<endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<int> degSeq(N);
|
||||
|
||||
ifstream infn(degFileName.c_str());
|
||||
if (!infn) {cout << "\nCannot open file " << degFileName << endl; exit(-1); }
|
||||
int m;
|
||||
infn >>m;
|
||||
std::vector<int> deg(m);
|
||||
std::vector<double> degFrac(m);
|
||||
for(int i=0;i<m;i++) infn>>deg[i];
|
||||
for(int i=0;i<m;i++) infn>>degFrac[i];
|
||||
infn.close();
|
||||
double dtmp=0.0;
|
||||
for(int i=0;i<m;i++) dtmp+=degFrac[i];
|
||||
cout.setf(ios::fixed, ios::floatfield);
|
||||
if(abs(dtmp-1.0)>EPS) {
|
||||
cout.setf(ios::fixed, ios::floatfield);
|
||||
cout <<"\n Invalid degree distribution (node perspective): sum != 1.0 but "<<setprecision(10)<<dtmp<<endl; exit(-1);
|
||||
}
|
||||
for(int i=1;i<m;++i) degFrac[i]+=degFrac[i-1];
|
||||
for(int i=0;i<N;++i) {
|
||||
dtmp=double(i)/double(N);
|
||||
int j;
|
||||
for(j=m-1;j>=0;--j) {
|
||||
if(dtmp>degFrac[j]) break;
|
||||
}
|
||||
if(dtmp<degFrac[0]) degSeq[i]=deg[0];
|
||||
else degSeq[i]=deg[j+1];
|
||||
}
|
||||
|
||||
BigGirth bigGirth(M, N, °Seq[0], codeName.c_str(),
|
||||
sglConcent, targetGirth, verbose);
|
||||
|
||||
switch(output_mode)
|
||||
{
|
||||
case OUTPUT_MODE_H_COMPRESSED: bigGirth.writeToFile_Hcompressed(); break;
|
||||
case OUTPUT_MODE_H: // different output format
|
||||
bigGirth.writeToFile_Hmatrix(); break;
|
||||
case OUTPUT_MODE_G_H_COMPRESSED:
|
||||
// different output format: including generator matrix (compressed)
|
||||
bigGirth.writeToFile(); break;
|
||||
default:
|
||||
cout << "Error: invalid output mode specified." << endl << endl;
|
||||
usage();
|
||||
}
|
||||
|
||||
//computing local girth distribution
|
||||
|
||||
if (verbose && N<10000) {
|
||||
cout<<" Now computing the local girth on the global Tanner graph setting. "<<endl;
|
||||
cout<<" might take a bit long time. Please wait ... "<<endl;
|
||||
bigGirth.loadH();
|
||||
CyclesOfGraph cog(M, N, bigGirth.H);
|
||||
cog.getCyclesTable();
|
||||
cog.printCyclesTable();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 86 KiB |
@@ -1,186 +0,0 @@
|
||||
subroutine osd174(llr,apmask,norder,decoded,cw,nhardmin,dmin)
|
||||
!
|
||||
! An ordered-statistics decoder for the (174,87) code.
|
||||
!
|
||||
include "ldpc_174_87_params.f90"
|
||||
|
||||
integer*1 apmask(N),apmaskr(N)
|
||||
integer*1 gen(K,N)
|
||||
integer*1 genmrb(K,N),g2(N,K)
|
||||
integer*1 temp(K),m0(K),me(K),mi(K)
|
||||
integer indices(N),nxor(N)
|
||||
integer*1 cw(N),ce(N),c0(N),hdec(N)
|
||||
integer*1 decoded(K)
|
||||
integer indx(N)
|
||||
real llr(N),rx(N),absrx(N)
|
||||
logical first
|
||||
data first/.true./
|
||||
|
||||
save first,gen
|
||||
|
||||
if( first ) then ! fill the generator matrix
|
||||
gen=0
|
||||
do i=1,M
|
||||
do j=1,22
|
||||
read(g(i)(j:j),"(Z1)") istr
|
||||
do jj=1, 4
|
||||
irow=(j-1)*4+jj
|
||||
if( btest(istr,4-jj) ) gen(irow,i)=1
|
||||
enddo
|
||||
enddo
|
||||
enddo
|
||||
do irow=1,K
|
||||
gen(irow,M+irow)=1
|
||||
enddo
|
||||
first=.false.
|
||||
endif
|
||||
|
||||
! re-order received vector to place systematic msg bits at the end
|
||||
rx=llr(colorder+1)
|
||||
apmaskr=apmask(colorder+1)
|
||||
|
||||
|
||||
! hard decode the received word
|
||||
hdec=0
|
||||
where(rx .ge. 0) hdec=1
|
||||
|
||||
! use magnitude of received symbols as a measure of reliability.
|
||||
absrx=abs(rx)
|
||||
call indexx(absrx,N,indx)
|
||||
|
||||
! re-order the columns of the generator matrix in order of decreasing reliability.
|
||||
do i=1,N
|
||||
genmrb(1:K,i)=gen(1:K,indx(N+1-i))
|
||||
indices(i)=indx(N+1-i)
|
||||
enddo
|
||||
|
||||
! do gaussian elimination to create a generator matrix with the most reliable
|
||||
! received bits in positions 1:K in order of decreasing reliability (more or less).
|
||||
! reliability will not be strictly decreasing because column re-ordering is needed
|
||||
! to put the generator matrix in systematic form. the "indices" array tracks
|
||||
! column permutations caused by reliability sorting and gaussian elimination.
|
||||
do id=1,K ! diagonal element indices
|
||||
do icol=id,K+20 ! The 20 is ad hoc - beware
|
||||
iflag=0
|
||||
if( genmrb(id,icol) .eq. 1 ) then
|
||||
iflag=1
|
||||
if( icol .ne. id ) then ! reorder column
|
||||
temp(1:K)=genmrb(1:K,id)
|
||||
genmrb(1:K,id)=genmrb(1:K,icol)
|
||||
genmrb(1:K,icol)=temp(1:K)
|
||||
itmp=indices(id)
|
||||
indices(id)=indices(icol)
|
||||
indices(icol)=itmp
|
||||
endif
|
||||
do ii=1,K
|
||||
if( ii .ne. id .and. genmrb(ii,id) .eq. 1 ) then
|
||||
genmrb(ii,1:N)=ieor(genmrb(ii,1:N),genmrb(id,1:N))
|
||||
endif
|
||||
enddo
|
||||
exit
|
||||
endif
|
||||
enddo
|
||||
enddo
|
||||
|
||||
g2=transpose(genmrb)
|
||||
|
||||
! The hard decisions for the K MRB bits define the order 0 message, m0.
|
||||
! Encode m0 using the modified generator matrix to find the "order 0" codeword.
|
||||
! Flip various combinations of bits in m0 and re-encode to generate a list of
|
||||
! codewords. Test all such codewords against the received word to decide which
|
||||
! codeword is most likely to be correct.
|
||||
|
||||
hdec=hdec(indices) ! hard decisions from received symbols
|
||||
m0=hdec(1:K) ! zero'th order message
|
||||
absrx=absrx(indices)
|
||||
rx=rx(indices)
|
||||
apmaskr=apmaskr(indices)
|
||||
|
||||
s1=sum(absrx(1:K))
|
||||
s2=sum(absrx(K+1:N))
|
||||
xlam=7.0 ! larger values reject more error patterns
|
||||
rho=s1/(s1+xlam*s2)
|
||||
call mrbencode(m0,c0,g2,N,K)
|
||||
nxor=ieor(c0,hdec)
|
||||
nhardmin=sum(nxor)
|
||||
dmin=sum(nxor*absrx)
|
||||
thresh=rho*dmin
|
||||
|
||||
cw=c0
|
||||
nt=0
|
||||
nrejected=0
|
||||
do iorder=1,norder
|
||||
mi(1:K-iorder)=0
|
||||
mi(K-iorder+1:K)=1
|
||||
iflag=0
|
||||
do while(iflag .ge. 0 )
|
||||
if(all(iand(apmaskr(1:K),mi).eq.0)) then ! reject patterns with ap bits
|
||||
dpat=sum(mi*absrx(1:K))
|
||||
nt=nt+1
|
||||
if( dpat .lt. thresh ) then ! reject unlikely error patterns
|
||||
me=ieor(m0,mi)
|
||||
call mrbencode(me,ce,g2,N,K)
|
||||
nxor=ieor(ce,hdec)
|
||||
dd=sum(nxor*absrx)
|
||||
if( dd .lt. dmin ) then
|
||||
dmin=dd
|
||||
cw=ce
|
||||
nhardmin=sum(nxor)
|
||||
thresh=rho*dmin
|
||||
endif
|
||||
else
|
||||
nrejected=nrejected+1
|
||||
endif
|
||||
endif
|
||||
! get the next test error pattern, iflag will go negative
|
||||
! when the last pattern with weight iorder has been generated
|
||||
call nextpat(mi,k,iorder,iflag)
|
||||
enddo
|
||||
enddo
|
||||
|
||||
!write(*,*) 'nhardmin ',nhardmin
|
||||
!write(*,*) 'total patterns ',nt,' number rejected ',nrejected
|
||||
|
||||
! re-order the codeword to place message bits at the end
|
||||
cw(indices)=cw
|
||||
hdec(indices)=hdec
|
||||
decoded=cw(M+1:N)
|
||||
cw(colorder+1)=cw ! put the codeword back into received-word order
|
||||
return
|
||||
end subroutine osd174
|
||||
|
||||
subroutine mrbencode(me,codeword,g2,N,K)
|
||||
integer*1 me(K),codeword(N),g2(N,K)
|
||||
! fast encoding for low-weight test patterns
|
||||
codeword=0
|
||||
do i=1,K
|
||||
if( me(i) .eq. 1 ) then
|
||||
codeword=ieor(codeword,g2(1:N,i))
|
||||
endif
|
||||
enddo
|
||||
return
|
||||
end subroutine mrbencode
|
||||
|
||||
subroutine nextpat(mi,k,iorder,iflag)
|
||||
integer*1 mi(k),ms(k)
|
||||
! generate the next test error pattern
|
||||
ind=-1
|
||||
do i=1,k-1
|
||||
if( mi(i).eq.0 .and. mi(i+1).eq.1) ind=i
|
||||
enddo
|
||||
if( ind .lt. 0 ) then ! no more patterns of this order
|
||||
iflag=ind
|
||||
return
|
||||
endif
|
||||
ms=0
|
||||
ms(1:ind-1)=mi(1:ind-1)
|
||||
ms(ind)=1
|
||||
ms(ind+1)=0
|
||||
if( ind+1 .lt. k ) then
|
||||
nz=iorder-sum(ms)
|
||||
ms(k-nz+1:k)=1
|
||||
endif
|
||||
mi=ms
|
||||
iflag=ind
|
||||
return
|
||||
end subroutine nextpat
|
||||
@@ -43,9 +43,7 @@ subroutine symspec65(dd,npts,nqsym,savg)
|
||||
first=.false.
|
||||
endif
|
||||
|
||||
! do j=1,nhsym
|
||||
do j=1,nqsym
|
||||
! i0=(j-1)*hstep
|
||||
i0=(j-1)*qstep
|
||||
x=fac1*w*dd(i0+1:i0+NFFT)
|
||||
call four2a(c,NFFT,1,-1,0) !r2c forward FFT
|
||||
@@ -1,41 +0,0 @@
|
||||
// -*- Mode: C++ -*-
|
||||
#ifndef DISPLAYTEXT_H
|
||||
#define DISPLAYTEXT_H
|
||||
|
||||
#include <QTextEdit>
|
||||
#include "logbook/logbook.h"
|
||||
#include "decodedtext.h"
|
||||
|
||||
|
||||
class DisplayText : public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DisplayText(QWidget *parent = 0);
|
||||
|
||||
void setContentFont (QFont const&);
|
||||
void insertLineSpacer(QString const&);
|
||||
void displayDecodedText(DecodedText decodedText, QString myCall, bool displayDXCCEntity,
|
||||
LogBook logBook, QColor color_CQ, QColor color_MyCall,
|
||||
QColor color_DXCC, QColor color_NewCall);
|
||||
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
|
||||
QColor color_TxMsg, bool bFastMode);
|
||||
void displayQSY(QString text);
|
||||
|
||||
signals:
|
||||
void selectCallsign(bool shift, bool ctrl);
|
||||
|
||||
public slots:
|
||||
void appendText(QString const& text, QString const& bg = "white");
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent *e);
|
||||
|
||||
private:
|
||||
void _appendDXCCWorkedB4(/*mod*/DecodedText& t1, QString &bg, LogBook logBook,
|
||||
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
|
||||
|
||||
QTextCharFormat m_charFormat;
|
||||
};
|
||||
|
||||
#endif // DISPLAYTEXT_H
|
||||
@@ -1,148 +0,0 @@
|
||||
#include "logqso.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QSettings>
|
||||
#include <QStandardPaths>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "logbook/adif.h"
|
||||
#include "MessageBox.hpp"
|
||||
|
||||
#include "ui_logqso.h"
|
||||
#include "moc_logqso.cpp"
|
||||
|
||||
LogQSO::LogQSO(QString const& programTitle, QSettings * settings, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::LogQSO)
|
||||
, m_settings (settings)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowTitle(programTitle + " - Log QSO");
|
||||
loadSettings ();
|
||||
}
|
||||
|
||||
LogQSO::~LogQSO ()
|
||||
{
|
||||
}
|
||||
|
||||
void LogQSO::loadSettings ()
|
||||
{
|
||||
m_settings->beginGroup ("LogQSO");
|
||||
restoreGeometry (m_settings->value ("geometry", saveGeometry ()).toByteArray ());
|
||||
ui->cbTxPower->setChecked (m_settings->value ("SaveTxPower", false).toBool ());
|
||||
ui->cbComments->setChecked (m_settings->value ("SaveComments", false).toBool ());
|
||||
m_txPower = m_settings->value ("TxPower", "").toString ();
|
||||
m_comments = m_settings->value ("LogComments", "").toString();
|
||||
m_settings->endGroup ();
|
||||
}
|
||||
|
||||
void LogQSO::storeSettings () const
|
||||
{
|
||||
m_settings->beginGroup ("LogQSO");
|
||||
m_settings->setValue ("geometry", saveGeometry ());
|
||||
m_settings->setValue ("SaveTxPower", ui->cbTxPower->isChecked ());
|
||||
m_settings->setValue ("SaveComments", ui->cbComments->isChecked ());
|
||||
m_settings->setValue ("TxPower", m_txPower);
|
||||
m_settings->setValue ("LogComments", m_comments);
|
||||
m_settings->endGroup ();
|
||||
}
|
||||
|
||||
void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode,
|
||||
QString const& rptSent, QString const& rptRcvd,
|
||||
QDateTime const& dateTimeOn, QDateTime const& dateTimeOff,
|
||||
Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid,
|
||||
bool noSuffix, bool toRTTY, bool dBtoComments)
|
||||
{
|
||||
if(!isHidden()) return;
|
||||
ui->call->setText(hisCall);
|
||||
ui->grid->setText(hisGrid);
|
||||
ui->name->setText("");
|
||||
ui->txPower->setText("");
|
||||
ui->comments->setText("");
|
||||
if (ui->cbTxPower->isChecked ()) ui->txPower->setText(m_txPower);
|
||||
if (ui->cbComments->isChecked ()) ui->comments->setText(m_comments);
|
||||
if(dBtoComments) {
|
||||
QString t=mode;
|
||||
if(rptSent!="") t+=" Sent: " + rptSent;
|
||||
if(rptRcvd!="") t+=" Rcvd: " + rptRcvd;
|
||||
ui->comments->setText(t);
|
||||
}
|
||||
if(noSuffix and mode.mid(0,3)=="JT9") mode="JT9";
|
||||
if(toRTTY and mode.mid(0,3)=="JT9") mode="RTTY";
|
||||
ui->mode->setText(mode);
|
||||
ui->sent->setText(rptSent);
|
||||
ui->rcvd->setText(rptRcvd);
|
||||
ui->start_date_time->setDateTime (dateTimeOn);
|
||||
ui->end_date_time->setDateTime (dateTimeOff);
|
||||
m_dialFreq=dialFreq;
|
||||
m_myCall=myCall;
|
||||
m_myGrid=myGrid;
|
||||
QString band= ADIF::bandFromFrequency(dialFreq / 1.e6);
|
||||
ui->band->setText(band);
|
||||
|
||||
show ();
|
||||
}
|
||||
|
||||
void LogQSO::accept()
|
||||
{
|
||||
QString hisCall,hisGrid,mode,rptSent,rptRcvd,dateOn,dateOff,timeOn,timeOff,band;
|
||||
QString comments,name;
|
||||
|
||||
hisCall=ui->call->text();
|
||||
hisGrid=ui->grid->text();
|
||||
mode=ui->mode->text();
|
||||
rptSent=ui->sent->text();
|
||||
rptRcvd=ui->rcvd->text();
|
||||
m_dateTimeOn = ui->start_date_time->dateTime ();
|
||||
m_dateTimeOff = ui->end_date_time->dateTime ();
|
||||
band=ui->band->text();
|
||||
name=ui->name->text();
|
||||
m_txPower=ui->txPower->text();
|
||||
comments=ui->comments->text();
|
||||
m_comments=comments;
|
||||
QString strDialFreq(QString::number(m_dialFreq / 1.e6,'f',6));
|
||||
|
||||
//Log this QSO to ADIF file "wsjtx_log.adi"
|
||||
QString filename = "wsjtx_log.adi"; // TODO allow user to set
|
||||
ADIF adifile;
|
||||
auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx_log.adi");
|
||||
adifile.init(adifilePath);
|
||||
if (!adifile.addQSOToFile(hisCall,hisGrid,mode,rptSent,rptRcvd,m_dateTimeOn,m_dateTimeOff,band,comments,name,strDialFreq,m_myCall,m_myGrid,m_txPower))
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Log file error"),
|
||||
tr ("Cannot open \"%1\"").arg (adifilePath));
|
||||
}
|
||||
|
||||
//Log this QSO to file "wsjtx.log"
|
||||
static QFile f {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx.log")};
|
||||
if(!f.open(QIODevice::Text | QIODevice::Append)) {
|
||||
MessageBox::warning_message (this, tr ("Log file error"),
|
||||
tr ("Cannot open \"%1\" for append").arg (f.fileName ()),
|
||||
tr ("Error: %1").arg (f.errorString ()));
|
||||
} else {
|
||||
QString logEntry=m_dateTimeOn.date().toString("yyyy-MM-dd,") +
|
||||
m_dateTimeOn.time().toString("hh:mm:ss,") +
|
||||
m_dateTimeOff.date().toString("yyyy-MM-dd,") +
|
||||
m_dateTimeOff.time().toString("hh:mm:ss,") + hisCall + "," +
|
||||
hisGrid + "," + strDialFreq + "," + mode +
|
||||
"," + rptSent + "," + rptRcvd + "," + m_txPower +
|
||||
"," + comments + "," + name;
|
||||
QTextStream out(&f);
|
||||
out << logEntry << endl;
|
||||
f.close();
|
||||
}
|
||||
|
||||
//Clean up and finish logging
|
||||
Q_EMIT acceptQSO (m_dateTimeOff, hisCall, hisGrid, m_dialFreq, mode, rptSent, rptRcvd, m_txPower, comments, name,m_dateTimeOn);
|
||||
QDialog::accept();
|
||||
}
|
||||
|
||||
// closeEvent is only called from the system menu close widget for a
|
||||
// modeless dialog so we use the hideEvent override to store the
|
||||
// window settings
|
||||
void LogQSO::hideEvent (QHideEvent * e)
|
||||
{
|
||||
storeSettings ();
|
||||
QDialog::hideEvent (e);
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
// Status=review
|
||||
.Receiver Noise Level
|
||||
|
||||
- If it is not already highlighted in green, click the *Monitor*
|
||||
button to start normal receive operation.
|
||||
|
||||
- Be sure your transceiver is set to *USB* (or *USB Data*) mode.
|
||||
|
||||
- Use the receiver gain controls and/or the computer's audio mixer
|
||||
controls to set the background noise level (scale at lower left of
|
||||
main window) to around 30 dB when no signals are present. It is
|
||||
usually best to turn AGC off or reduce the RF gain control to minimize
|
||||
AGC action.
|
||||
|
||||
.Bandwidth and Frequency Setting
|
||||
|
||||
- If your transceiver offers more than one bandwidth setting in USB
|
||||
mode, you should normally choose the widest one possible, up to about
|
||||
5 kHz. This choice has the desirable effect of allowing the *Wide
|
||||
Graph* (waterfall and 2D spectrum) to display the conventional JT65
|
||||
and JT9 sub-bands simultaneously on most HF bands. Further details
|
||||
are provided in the <<TUTORIAL,Basic Operating Tutorial>>. A wider
|
||||
displayed bandwidth may also be helpful at VHF and above, where JT4,
|
||||
JT65, and QRA64 signals are found over much wider ranges of
|
||||
frequencies.
|
||||
|
||||
- If you have only a standard SSB filter you won’t be able to display
|
||||
more than about 2.7 kHz bandwidth. Depending on the exact dial
|
||||
frequency setting, on HF bands you can display the full sub-band
|
||||
generally used for one mode (JT65 or JT9) and part of the sub-band for
|
||||
the other mode.
|
||||
|
||||
- Of course, you might prefer to concentrate on one mode at a time,
|
||||
setting your dial frequency to (say) 14.076 for JT65 or 14.078 for
|
||||
JT9. Present conventions have the nominal JT9 dial frequency 2 kHz
|
||||
higher than the JT65 dial frequency on most bands.
|
||||
|
||||
.Transmitter Audio Level
|
||||
|
||||
* Click the *Tune* button on the main screen to switch the
|
||||
radio into transmit mode and generate a steady audio tone.
|
||||
|
||||
* Listen to the generated audio tone using your radio’s *Monitor*
|
||||
facility. The transmitted tone should be perfectly smooth, with no
|
||||
clicks or glitches. Make sure that this is true even when you
|
||||
simultaneously use the computer to do other tasks such as email, web
|
||||
browsing, etc.
|
||||
|
||||
* Open the computer's audio mixer controls for output ("`Playback`")
|
||||
devices and adjust the volume slider downward from its maximum until
|
||||
the RF output from your transmitter falls slightly. This is generally
|
||||
a good level for audio drive.
|
||||
|
||||
* Alternatively, you can make the Tx audio level adjustment using the
|
||||
digital slider labeled *Pwr* at the right edge of the main window.
|
||||
|
||||
* Toggle the *Tune* button once more or click *Halt Tx* to stop your
|
||||
test transmission.
|
||||
@@ -20,7 +20,7 @@ void ADIF::init(QString const& filename)
|
||||
|
||||
QString ADIF::extractField(QString const& record, QString const& fieldName) const
|
||||
{
|
||||
int fieldNameIndex = record.indexOf (fieldName + ':', 0, Qt::CaseInsensitive);
|
||||
int fieldNameIndex = record.indexOf ('<' + fieldName + ':', 0, Qt::CaseInsensitive);
|
||||
if (fieldNameIndex >=0)
|
||||
{
|
||||
int closingBracketIndex = record.indexOf('>',fieldNameIndex);
|
||||
@@ -167,15 +167,53 @@ QList<QString> ADIF::getCallList() const
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ADIF::getCount() const
|
||||
{
|
||||
return _data.size();
|
||||
}
|
||||
|
||||
QByteArray ADIF::QSOToADIF(QString const& hisCall, QString const& hisGrid, QString const& mode
|
||||
, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn
|
||||
, QDateTime const& dateTimeOff, QString const& band, QString const& comments
|
||||
, QString const& name, QString const& strDialFreq, QString const& m_myCall
|
||||
, QString const& m_myGrid, QString const& m_txPower, QString const& operator_call)
|
||||
{
|
||||
QString t;
|
||||
t = "<call:" + QString::number(hisCall.length()) + ">" + hisCall;
|
||||
t += " <gridsquare:" + QString::number(hisGrid.length()) + ">" + hisGrid;
|
||||
t += " <mode:" + QString::number(mode.length()) + ">" + mode;
|
||||
t += " <rst_sent:" + QString::number(rptSent.length()) + ">" + rptSent;
|
||||
t += " <rst_rcvd:" + QString::number(rptRcvd.length()) + ">" + rptRcvd;
|
||||
t += " <qso_date:8>" + dateTimeOn.date().toString("yyyyMMdd");
|
||||
t += " <time_on:6>" + dateTimeOn.time().toString("hhmmss");
|
||||
t += " <qso_date_off:8>" + dateTimeOff.date().toString("yyyyMMdd");
|
||||
t += " <time_off:6>" + dateTimeOff.time().toString("hhmmss");
|
||||
t += " <band:" + QString::number(band.length()) + ">" + band;
|
||||
t += " <freq:" + QString::number(strDialFreq.length()) + ">" + strDialFreq;
|
||||
t += " <station_callsign:" + QString::number(m_myCall.length()) + ">" +
|
||||
m_myCall;
|
||||
t += " <my_gridsquare:" + QString::number(m_myGrid.length()) + ">" +
|
||||
m_myGrid;
|
||||
if (m_txPower != "")
|
||||
t += " <tx_pwr:" + QString::number(m_txPower.length()) +
|
||||
">" + m_txPower;
|
||||
if (comments != "")
|
||||
t += " <comment:" + QString::number(comments.length()) +
|
||||
">" + comments;
|
||||
if (name != "")
|
||||
t += " <name:" + QString::number(name.length()) +
|
||||
">" + name;
|
||||
if (operator_call!="")
|
||||
t+=" <operator:" + QString::number(operator_call.length()) +
|
||||
">" + operator_call;
|
||||
return t.toLatin1 ();
|
||||
}
|
||||
|
||||
|
||||
// open ADIF file and append the QSO details. Return true on success
|
||||
bool ADIF::addQSOToFile(QString const& hisCall, QString const& hisGrid, QString const& mode, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QDateTime const& dateTimeOff, QString const& band,
|
||||
QString const& comments, QString const& name, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid, QString const& m_txPower)
|
||||
bool ADIF::addQSOToFile(QByteArray const& ADIF_record)
|
||||
{
|
||||
QFile f2(_filename);
|
||||
if (!f2.open(QIODevice::Text | QIODevice::Append))
|
||||
@@ -186,30 +224,7 @@ bool ADIF::addQSOToFile(QString const& hisCall, QString const& hisGrid, QString
|
||||
if (f2.size()==0)
|
||||
out << "WSJT-X ADIF Export<eoh>" << endl; // new file
|
||||
|
||||
QString t;
|
||||
t="<call:" + QString::number(hisCall.length()) + ">" + hisCall;
|
||||
t+=" <gridsquare:" + QString::number(hisGrid.length()) + ">" + hisGrid;
|
||||
t+=" <mode:" + QString::number(mode.length()) + ">" + mode;
|
||||
t+=" <rst_sent:" + QString::number(rptSent.length()) + ">" + rptSent;
|
||||
t+=" <rst_rcvd:" + QString::number(rptRcvd.length()) + ">" + rptRcvd;
|
||||
t+=" <qso_date:8>" + dateTimeOn.date ().toString ("yyyyMMdd");
|
||||
t+=" <time_on:6>" + dateTimeOn.time ().toString ("hhmmss");
|
||||
t+=" <qso_date_off:8>" + dateTimeOff.date ().toString ("yyyyMMdd");
|
||||
t+=" <time_off:6>" + dateTimeOff.time ().toString ("hhmmss");
|
||||
t+=" <band:" + QString::number(band.length()) + ">" + band;
|
||||
t+=" <freq:" + QString::number(strDialFreq.length()) + ">" + strDialFreq;
|
||||
t+=" <station_callsign:" + QString::number(m_myCall.length()) + ">" +
|
||||
m_myCall;
|
||||
t+=" <my_gridsquare:" + QString::number(m_myGrid.length()) + ">" +
|
||||
m_myGrid;
|
||||
if(m_txPower!="") t+= " <tx_pwr:" + QString::number(m_txPower.length()) +
|
||||
">" + m_txPower;
|
||||
if(comments!="") t+=" <comment:" + QString::number(comments.length()) +
|
||||
">" + comments;
|
||||
if(name!="") t+=" <name:" + QString::number(name.length()) +
|
||||
">" + name;
|
||||
t+=" <eor>";
|
||||
out << t << endl;
|
||||
out << ADIF_record << " <eor>" << endl;
|
||||
f2.close();
|
||||
}
|
||||
return true;
|
||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,126 @@
|
||||
Quick Start for DXpedition Mode
|
||||
-------------------------------
|
||||
|
||||
These notes are intended for operators already familiar with WSJT-X
|
||||
and FT8 mode. QSOs between the Dxpedition ("Fox") and other stations
|
||||
("Hounds") are completed with as little as one transmission per Hound,
|
||||
as in the following examples:
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
Fox (300-600 Hz) Hounds
|
||||
----------------------------------------------------------------------------
|
||||
1. CQ KH1DX AJ10
|
||||
2. KH1DX K1ABC FN42, KH1DX W9XYZ EN37, ...
|
||||
3. K1ABC KH1DX -13
|
||||
4. KH1DX K1ABC R-11
|
||||
5. K1ABC RR73; W9XYZ <KH1DX> -17
|
||||
6. KH1DX W9XYZ R-16
|
||||
7. W9XYZ RR73; G4AAA <KH1DX> -09
|
||||
8. ...
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Everybody sets dial frequency to an agreed number and uses CAT control
|
||||
with Split Operation (either *Rig* or *Fake It*). Fox transmits up to
|
||||
5 signals simultaneously, at audio frequencies 300, 360, ... 540
|
||||
Hz. Hounds make initial calls (e.g., line 2 above) anywhere in the
|
||||
range 1000 - 4000 Hz. They send "R+rpt" 350 Hz above the frequency
|
||||
where Fox called them.
|
||||
|
||||
|
||||
INSTRUCTIONS FOR FOX
|
||||
--------------------
|
||||
|
||||
1. Start WSJT-X in FT8 mode. Select *Fox* on the *Settings ->
|
||||
Advanced tab*. On the main window, check *Tx even/1st*, *Auto Seq*,
|
||||
and *Hold Tx Freq*; uncheck *Call 1st*. Set *Tx 300 Hz* and select
|
||||
Tab 3.
|
||||
|
||||
2. In Fox mode the left window (called "Band Activity" in normal FT8
|
||||
mode) is labeled "Stations calling DXpedition <MyCall>". It will be
|
||||
filled with a sorted list of calling Hounds. You can sort by Call,
|
||||
Grid, S/N, Distance, or Random order by using the comboBox at top
|
||||
right of Tab 3. You can limit the displayed Hound callsigns to those
|
||||
no stronger than *Max dB*. Fox might use this feature to discourage
|
||||
Hounds from engaging in a QRO arms race.
|
||||
|
||||
3. *N Slots* sets the number of simultaneous Fox signals to be used.
|
||||
Fox carries out as many as *N Slots* QSOs simultaneously.
|
||||
|
||||
4. *Repeats* sets the maximum number of repeat transmissions of the
|
||||
same message. A QSO is aborted when this number would be exceeded.
|
||||
|
||||
5. The *CQ* comboBox on Tab 3 offers a selection of directed CQ
|
||||
messages. *Reset* clears the QSO queue.
|
||||
|
||||
6. The Fox operator's main task is to select Hounds to be called and
|
||||
worked. The text box on Tab 3 holds the "QSO queue": a list of Hound
|
||||
calls to be worked. Hit Enter to select the top callsign from the
|
||||
sorted list of callers (left window), or double-click on any
|
||||
particular call. Either actiion moves that Hound into the "QSO
|
||||
queue".
|
||||
|
||||
7. The right window displays decodes of signals below 1000 Hz.
|
||||
Normally these should include only Hound messages containing "R+rpt"
|
||||
and Fox's own transmissions.
|
||||
|
||||
8. To get things started, toggle *Enable Tx* to red. If a Hound call
|
||||
is available in the QSO queue, that station will be called. If the
|
||||
QSO queue is empty, Fox calls CQ.
|
||||
|
||||
9. If you're using Nslots = 2 or higher, your signal no longer has
|
||||
a constant envelope. To avoid producing intermod sidebands you need
|
||||
to ensure linearity in your Tx system. One way to get things about right
|
||||
is to use the WSJT-X *Tune* button to generate a pure tone. Reduce the
|
||||
Tx audio level until your power output decreases by 10% or so. Use this
|
||||
level for your Fox transmissions.
|
||||
|
||||
NOTE: If you are generating Nslots signals, the average power in each one
|
||||
will be 1/Nslots^2 of its normal value for single-signal transmissions.
|
||||
|
||||
Nslots Relative dB
|
||||
-------------------
|
||||
1 0
|
||||
2 -6
|
||||
3 -9.5
|
||||
4 -12
|
||||
5 -14
|
||||
|
||||
|
||||
The following features are not yet implemented for Fox:
|
||||
|
||||
1. Enforce all required settings
|
||||
2. Tx message timeout
|
||||
3. Manual abort of selected QSO
|
||||
4. All Tx and Rx messages to all.txt
|
||||
5. Additional sort criteria for Hound calls
|
||||
6. Selectable timeout for keeping Hounds in the sorted list
|
||||
7. Display number of active callers
|
||||
8. Display QSO rate
|
||||
|
||||
|
||||
INSTRUCTIONS FOR HOUND
|
||||
----------------------
|
||||
|
||||
1. Start WSJT-X in FT8 mode. Select *Hound* On the *Settings ->
|
||||
Advanced* tab. On the main window check *Auto Seq* and uncheck *Tx
|
||||
even/1st*, *Call 1st*, and *Hold Tx Freq*. Set *Tx nnnn Hz* to some
|
||||
frequency between 1000 and 4000 Hz, and select *Tab 1*. Enter Fox's
|
||||
callsign and locator in DX Call and DX Grid, select Tx1, and start
|
||||
*Monitor*.
|
||||
|
||||
2. When you have copied Fox, hit *Enable Tx* to call him. You may
|
||||
keep calling until he answers. You may wish to move your TxFreq
|
||||
around, hoping to find a clear calling frequency.
|
||||
|
||||
3. When you are called by Fox with a signal report, your next
|
||||
transmission will automatically be sent as Tx3 ("R+rpt"). When Fox
|
||||
receives that message he responds with "RR73", and your QSO is
|
||||
complete!
|
||||
|
||||
|
||||
The following features are not yet implemented for Hound:
|
||||
|
||||
1. Force all required settings
|
||||
2. React properly to directed CQs from Fox
|
||||
3. Disable Tx2, 4, 5, 6
|
||||
4. For Tx1, enforce TxFreq >= 1000 Hz
|
||||
@@ -0,0 +1,18 @@
|
||||
program twq
|
||||
|
||||
character*22 msg0,msg
|
||||
integer*1 data0(11)
|
||||
|
||||
open(10,file='wqmsg.txt',status='old')
|
||||
write(*,1000)
|
||||
1000 format(4x,'Encoded message',9x,'Decoded as',12x,'itype'/55('-'))
|
||||
|
||||
do line=1,9999
|
||||
read(10,*,end=999) msg0
|
||||
call wqenc(msg0,itype,data0)
|
||||
call wqdec(data0,msg,ntype)
|
||||
write(*,1100) line,msg0,msg,ntype
|
||||
1100 format(i2,'.',1x,a22,2x,a22,i3)
|
||||
enddo
|
||||
|
||||
999 end program twq
|
||||
@@ -1,46 +0,0 @@
|
||||
// -*- Mode: C++ -*-
|
||||
#ifndef DISPLAYTEXT_H
|
||||
#define DISPLAYTEXT_H
|
||||
|
||||
#include <QTextEdit>
|
||||
#include <QFont>
|
||||
|
||||
#include "logbook/logbook.h"
|
||||
#include "decodedtext.h"
|
||||
|
||||
class QAction;
|
||||
|
||||
class DisplayText
|
||||
: public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DisplayText(QWidget *parent = 0);
|
||||
|
||||
void setContentFont (QFont const&);
|
||||
void insertLineSpacer(QString const&);
|
||||
void displayDecodedText(DecodedText const& decodedText, QString const& myCall, bool displayDXCCEntity,
|
||||
LogBook const& logBook, QColor color_CQ, QColor color_MyCall,
|
||||
QColor color_DXCC, QColor color_NewCall);
|
||||
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
|
||||
QColor color_TxMsg, bool bFastMode);
|
||||
void displayQSY(QString text);
|
||||
|
||||
Q_SIGNAL void selectCallsign (bool shift, bool ctrl, bool alt);
|
||||
Q_SIGNAL void erased ();
|
||||
|
||||
Q_SLOT void appendText (QString const& text, QColor bg = Qt::white);
|
||||
Q_SLOT void erase ();
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent *e);
|
||||
|
||||
private:
|
||||
QString appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg, LogBook const& logBook,
|
||||
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
|
||||
|
||||
QFont char_font_;
|
||||
QAction * erase_action_;
|
||||
};
|
||||
|
||||
#endif // DISPLAYTEXT_H
|
||||
@@ -1,59 +0,0 @@
|
||||
128
|
||||
56
|
||||
10
|
||||
1 15 30 44 58 71 84 100 115 0
|
||||
2 16 31 44 59 72 86 101 116 0
|
||||
3 17 31 45 60 73 87 102 117 0
|
||||
2 18 32 46 58 73 85 103 112 0
|
||||
4 19 32 47 61 74 88 104 118 0
|
||||
5 20 33 48 62 75 88 105 116 0
|
||||
6 19 34 49 63 76 89 105 119 0
|
||||
7 15 27 45 64 77 88 106 120 0
|
||||
8 15 35 50 59 75 90 107 121 127
|
||||
7 21 33 51 65 73 91 108 114 0
|
||||
9 22 30 46 59 78 92 99 122 0
|
||||
9 19 35 52 60 71 93 109 120 0
|
||||
10 20 31 53 63 79 93 107 123 0
|
||||
11 15 36 53 66 78 85 110 124 0
|
||||
8 23 37 49 67 71 86 111 118 0
|
||||
12 22 34 54 68 80 94 109 114 0
|
||||
1 24 34 52 65 75 87 97 123 0
|
||||
13 25 29 43 69 81 85 100 121 128
|
||||
12 17 38 55 63 82 90 101 125 0
|
||||
11 26 39 47 56 76 95 106 117 0
|
||||
2 27 40 49 69 74 94 108 117 0
|
||||
4 16 30 55 64 76 91 103 126 0
|
||||
13 17 28 47 65 80 96 111 124 126
|
||||
6 18 36 51 70 83 94 111 121 0
|
||||
13 16 34 48 57 82 95 112 120 127
|
||||
6 28 40 48 58 79 90 113 122 0
|
||||
5 27 41 46 67 83 91 109 127 0
|
||||
14 16 42 54 63 78 97 100 118 0
|
||||
13 27 39 52 70 84 90 114 118 0
|
||||
10 22 42 47 64 81 98 110 116 0
|
||||
11 22 29 55 60 84 97 108 111 127
|
||||
5 26 37 55 57 74 96 98 128 0
|
||||
3 21 35 54 62 82 98 104 113 0
|
||||
14 21 43 50 68 77 93 110 117 0
|
||||
9 24 33 56 69 72 89 110 112 0
|
||||
12 26 42 53 62 73 89 99 121 0
|
||||
10 25 35 41 57 76 97 101 122 0
|
||||
10 18 39 44 66 77 99 102 119 0
|
||||
3 29 40 44 61 83 93 106 125 0
|
||||
4 23 39 45 65 85 89 107 113 0
|
||||
6 26 30 43 61 80 86 108 123 0
|
||||
7 19 31 57 69 83 99 113 124 0
|
||||
3 24 37 43 66 84 92 105 120 126
|
||||
2 24 38 50 70 71 88 102 122 0
|
||||
1 20 32 51 68 81 86 102 124 0
|
||||
12 23 41 51 59 74 87 106 115 0
|
||||
14 28 37 46 62 72 95 114 115 125
|
||||
1 28 41 49 61 82 92 103 116 128
|
||||
7 25 38 56 60 75 98 103 115 0
|
||||
8 29 33 45 58 78 96 109 119 0
|
||||
4 25 36 54 67 77 96 105 123 0
|
||||
14 20 38 52 66 80 91 104 112 128
|
||||
8 18 42 56 68 79 87 104 125 0
|
||||
9 23 40 53 70 81 95 101 126 0
|
||||
11 21 32 48 67 72 94 107 119 0
|
||||
5 17 36 50 64 79 92 100 0 0
|
||||
@@ -1,63 +0,0 @@
|
||||
subroutine watterson(c,npts,fs,delay,fspread)
|
||||
|
||||
include 'wsprlf_params.f90'
|
||||
complex c(0:npts-1)
|
||||
complex c2(0:NZMAX-1)
|
||||
complex cs1(0:NZMAX-1)
|
||||
complex cs2(0:NZMAX-1)
|
||||
|
||||
nonzero=0
|
||||
df=fs/npts
|
||||
if(fspread.gt.0.0) then
|
||||
do i=0,npts-1
|
||||
xx=gran()
|
||||
yy=gran()
|
||||
cs1(i)=0.707*cmplx(xx,yy)
|
||||
xx=gran()
|
||||
yy=gran()
|
||||
cs2(i)=0.707*cmplx(xx,yy)
|
||||
enddo
|
||||
call four2a(cs1,npts,1,-1,1) !To freq domain
|
||||
call four2a(cs2,npts,1,-1,1)
|
||||
do i=0,npts-1
|
||||
f=i*df
|
||||
if(i.gt.npts/2) f=(i-npts)*df
|
||||
x=(f/(0.5*fspread))**2
|
||||
a=0.
|
||||
if(x.le.50.0) then
|
||||
a=exp(-x)
|
||||
endif
|
||||
cs1(i)=a*cs1(i)
|
||||
cs2(i)=a*cs2(i)
|
||||
if(abs(f).lt.10.0) then
|
||||
p1=real(cs1(i))**2 + aimag(cs1(i))**2
|
||||
p2=real(cs2(i))**2 + aimag(cs2(i))**2
|
||||
if(p1.gt.0.0) nonzero=nonzero+1
|
||||
! write(62,3101) f,p1,p2,db(p1+1.e-12)-60,db(p2+1.e-12)-60
|
||||
!3101 format(f10.3,2f12.3,2f10.3)
|
||||
endif
|
||||
enddo
|
||||
call four2a(cs1,npts,1,1,1) !Back to time domain
|
||||
call four2a(cs2,npts,1,1,1)
|
||||
cs1(0:npts-1)=cs1(0:npts-1)/npts
|
||||
cs2(0:npts-1)=cs2(0:npts-1)/npts
|
||||
endif
|
||||
|
||||
nshift=nint(0.001*delay*fs)
|
||||
c2(0:npts-1)=cshift(c(0:npts-1),nshift)
|
||||
sq=0.
|
||||
do i=0,npts-1
|
||||
if(nonzero.gt.1) then
|
||||
c(i)=0.5*(cs1(i)*c(i) + cs2(i)*c2(i))
|
||||
else
|
||||
c(i)=0.5*(c(i) + c2(i))
|
||||
endif
|
||||
sq=sq + real(c(i))**2 + aimag(c(i))**2
|
||||
! write(61,3001) i/12000.0,c(i)
|
||||
!3001 format(3f12.6)
|
||||
enddo
|
||||
rms=sqrt(sq/npts)
|
||||
c=c/rms
|
||||
|
||||
return
|
||||
end subroutine watterson
|
||||
@@ -1,748 +0,0 @@
|
||||
#include "plotter.h"
|
||||
#include <math.h>
|
||||
#include <QDebug>
|
||||
#include "commons.h"
|
||||
#include "moc_plotter.cpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#define MAX_SCREENSIZE 2048
|
||||
|
||||
CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
|
||||
QFrame {parent},
|
||||
m_bScaleOK {false},
|
||||
m_bReference {false},
|
||||
m_bReference0 {false},
|
||||
m_fSpan {2000.0},
|
||||
m_plotZero {0},
|
||||
m_plotGain {0},
|
||||
m_plot2dGain {0},
|
||||
m_plot2dZero {0},
|
||||
m_nSubMode {0},
|
||||
m_Running {false},
|
||||
m_paintEventBusy {false},
|
||||
m_fftBinWidth {1500.0/2048.0},
|
||||
m_dialFreq {0.},
|
||||
m_sum {},
|
||||
m_dBStepSize {10},
|
||||
m_FreqUnits {1},
|
||||
m_hdivs {HORZ_DIVS},
|
||||
m_line {0},
|
||||
m_fSample {12000},
|
||||
m_nsps {6912},
|
||||
m_Percent2DScreen {30}, //percent of screen used for 2D display
|
||||
m_Percent2DScreen0 {0},
|
||||
m_rxFreq {1020},
|
||||
m_txFreq {0},
|
||||
m_startFreq {0}
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setAttribute(Qt::WA_PaintOnScreen,false);
|
||||
setAutoFillBackground(false);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, false);
|
||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
}
|
||||
|
||||
CPlotter::~CPlotter() { } // Destructor
|
||||
|
||||
QSize CPlotter::minimumSizeHint() const
|
||||
{
|
||||
return QSize(50, 50);
|
||||
}
|
||||
|
||||
QSize CPlotter::sizeHint() const
|
||||
{
|
||||
return QSize(180, 180);
|
||||
}
|
||||
|
||||
void CPlotter::resizeEvent(QResizeEvent* ) //resizeEvent()
|
||||
{
|
||||
if(!size().isValid()) return;
|
||||
if( m_Size != size() or (m_bReference != m_bReference0) or
|
||||
m_Percent2DScreen != m_Percent2DScreen0) {
|
||||
m_Size = size();
|
||||
m_w = m_Size.width();
|
||||
m_h = m_Size.height();
|
||||
m_h2 = m_Percent2DScreen*m_h/100.0;
|
||||
if(m_h2>m_h-30) m_h2=m_h-30;
|
||||
if(m_bReference) m_h2=m_h-30;
|
||||
if(m_h2<1) m_h2=1;
|
||||
m_h1=m_h-m_h2;
|
||||
m_2DPixmap = QPixmap(m_Size.width(), m_h2);
|
||||
m_2DPixmap.fill(Qt::black);
|
||||
m_WaterfallPixmap = QPixmap(m_Size.width(), m_h1);
|
||||
m_OverlayPixmap = QPixmap(m_Size.width(), m_h2);
|
||||
m_OverlayPixmap.fill(Qt::black);
|
||||
m_WaterfallPixmap.fill(Qt::black);
|
||||
m_2DPixmap.fill(Qt::black);
|
||||
m_ScalePixmap = QPixmap(m_w,30);
|
||||
m_ScalePixmap.fill(Qt::white);
|
||||
m_Percent2DScreen0 = m_Percent2DScreen;
|
||||
}
|
||||
DrawOverlay();
|
||||
}
|
||||
|
||||
void CPlotter::paintEvent(QPaintEvent *) // paintEvent()
|
||||
{
|
||||
if(m_paintEventBusy) return;
|
||||
m_paintEventBusy=true;
|
||||
QPainter painter(this);
|
||||
painter.drawPixmap(0,0,m_ScalePixmap);
|
||||
painter.drawPixmap(0,30,m_WaterfallPixmap);
|
||||
painter.drawPixmap(0,m_h1,m_2DPixmap);
|
||||
m_paintEventBusy=false;
|
||||
}
|
||||
|
||||
void CPlotter::draw(float swide[], bool bScroll, bool bRed)
|
||||
{
|
||||
int j,j0;
|
||||
static int ktop=0;
|
||||
float y,y2,ymin;
|
||||
double fac = sqrt(m_binsPerPixel*m_waterfallAvg/15.0);
|
||||
double gain = fac*pow(10.0,0.02*m_plotGain);
|
||||
double gain2d = pow(10.0,0.02*(m_plot2dGain));
|
||||
|
||||
if(m_bReference != m_bReference0) resizeEvent(NULL);
|
||||
m_bReference0=m_bReference;
|
||||
|
||||
//move current data down one line (must do this before attaching a QPainter object)
|
||||
if(bScroll) m_WaterfallPixmap.scroll(0,1,0,0,m_w,m_h1);
|
||||
QPainter painter1(&m_WaterfallPixmap);
|
||||
m_2DPixmap = m_OverlayPixmap.copy(0,0,m_w,m_h2);
|
||||
QPainter painter2D(&m_2DPixmap);
|
||||
if(!painter2D.isActive()) return;
|
||||
QFont Font("Arial");
|
||||
Font.setPointSize(12);
|
||||
Font.setWeight(QFont::Normal);
|
||||
painter2D.setFont(Font);
|
||||
|
||||
if(m_bLinearAvg) {
|
||||
painter2D.setPen(Qt::yellow);
|
||||
} else if(m_bReference) {
|
||||
painter2D.setPen(Qt::blue);
|
||||
} else {
|
||||
painter2D.setPen(Qt::green);
|
||||
}
|
||||
static QPoint LineBuf[MAX_SCREENSIZE];
|
||||
static QPoint LineBuf2[MAX_SCREENSIZE];
|
||||
j=0;
|
||||
j0=int(m_startFreq/m_fftBinWidth + 0.5);
|
||||
int iz=XfromFreq(5000.0);
|
||||
int jz=iz*m_binsPerPixel;
|
||||
m_fMax=FreqfromX(iz);
|
||||
|
||||
m_line++;
|
||||
if(bScroll) {
|
||||
flat4_(swide,&iz,&m_Flatten);
|
||||
flat4_(&dec_data.savg[j0],&jz,&m_Flatten);
|
||||
}
|
||||
|
||||
ymin=1.e30;
|
||||
if(swide[0]>1.e29 and swide[0]< 1.5e30) painter1.setPen(Qt::green);
|
||||
if(swide[0]>1.4e30) painter1.setPen(Qt::yellow);
|
||||
for(int i=0; i<iz; i++) {
|
||||
y=swide[i];
|
||||
if(y<ymin) ymin=y;
|
||||
int y1 = 10.0*gain*y + 10*m_plotZero +40;
|
||||
if (y1<0) y1=0;
|
||||
if (y1>254) y1=254;
|
||||
if (swide[i]<1.e29) painter1.setPen(g_ColorTbl[y1]);
|
||||
painter1.drawPoint(i,0);
|
||||
}
|
||||
|
||||
float y2min=1.e30;
|
||||
float y2max=-1.e30;
|
||||
for(int i=0; i<iz; i++) {
|
||||
y=swide[i] - ymin;
|
||||
y2=0;
|
||||
if(m_bCurrent) y2 = gain2d*y + m_plot2dZero; //Current
|
||||
|
||||
if(bScroll) {
|
||||
float sum=0.0;
|
||||
int j=j0+m_binsPerPixel*i;
|
||||
for(int k=0; k<m_binsPerPixel; k++) {
|
||||
sum+=dec_data.savg[j++];
|
||||
}
|
||||
m_sum[i]=sum;
|
||||
}
|
||||
if(m_bCumulative) y2=gain2d*(m_sum[i]/m_binsPerPixel + m_plot2dZero);
|
||||
if(m_Flatten==0) y2 += 15; //### could do better! ###
|
||||
|
||||
if(m_bLinearAvg) { //Linear Avg (yellow)
|
||||
float sum=0.0;
|
||||
int j=j0+m_binsPerPixel*i;
|
||||
for(int k=0; k<m_binsPerPixel; k++) {
|
||||
sum+=spectra_.syellow[j++];
|
||||
}
|
||||
y2=gain2d*sum/m_binsPerPixel + m_plot2dZero;
|
||||
}
|
||||
|
||||
if(m_bReference) { //Reference (red)
|
||||
float df_ref=12000.0/6912.0;
|
||||
int j=FreqfromX(i)/df_ref + 0.5;
|
||||
y2=spectra_.ref[j] + m_plot2dZero;
|
||||
// if(gain2d>1.5) y2=spectra_.filter[j] + m_plot2dZero;
|
||||
|
||||
}
|
||||
|
||||
if(i==iz-1) {
|
||||
painter2D.drawPolyline(LineBuf,j);
|
||||
if(m_mode=="QRA64") {
|
||||
painter2D.setPen(Qt::red);
|
||||
painter2D.drawPolyline(LineBuf2,ktop);
|
||||
}
|
||||
}
|
||||
LineBuf[j].setX(i);
|
||||
LineBuf[j].setY(int(0.9*m_h2-y2*m_h2/70.0));
|
||||
if(y2<y2min) y2min=y2;
|
||||
if(y2>y2max) y2max=y2;
|
||||
j++;
|
||||
}
|
||||
|
||||
if(swide[0]>1.0e29) m_line=0;
|
||||
if(m_line == painter1.fontMetrics ().height ()) {
|
||||
painter1.setPen(Qt::white);
|
||||
QString t;
|
||||
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
||||
int n=(ms/1000) % m_TRperiod;
|
||||
QDateTime t1=QDateTime::currentDateTimeUtc().addSecs(-n);
|
||||
if(m_TRperiod < 60) {
|
||||
t=t1.toString("hh:mm:ss") + " " + m_rxBand;
|
||||
} else {
|
||||
t=t1.toString("hh:mm") + " " + m_rxBand;
|
||||
}
|
||||
painter1.drawText (5, painter1.fontMetrics ().ascent (), t);
|
||||
}
|
||||
|
||||
if(m_mode=="JT4") {
|
||||
QPen pen3(Qt::yellow); //Mark freqs of JT4 single-tone msgs
|
||||
painter2D.setPen(pen3);
|
||||
Font.setWeight(QFont::Bold);
|
||||
painter2D.setFont(Font);
|
||||
int x1=XfromFreq(m_rxFreq);
|
||||
y=0.2*m_h2;
|
||||
painter2D.drawText(x1-4,y,"T");
|
||||
x1=XfromFreq(m_rxFreq+250);
|
||||
painter2D.drawText(x1-4,y,"M");
|
||||
x1=XfromFreq(m_rxFreq+500);
|
||||
painter2D.drawText(x1-4,y,"R");
|
||||
x1=XfromFreq(m_rxFreq+750);
|
||||
painter2D.drawText(x1-4,y,"73");
|
||||
}
|
||||
|
||||
if(bRed) {
|
||||
std::ifstream f;
|
||||
f.open(m_redFile.toLatin1());
|
||||
if(f) {
|
||||
int x,y;
|
||||
float freq,sync;
|
||||
float slimit=6.0;
|
||||
QPen pen0(Qt::red,1);
|
||||
painter1.setPen(pen0);
|
||||
for(int i=0; i<99999; i++) {
|
||||
f >> freq >> sync;
|
||||
if(f.eof()) break;
|
||||
x=XfromFreq(freq);
|
||||
y=(sync-slimit)*3.0;
|
||||
if(y>0) {
|
||||
if(y>15.0) y=15.0;
|
||||
if(x>=0 and x<=m_w) {
|
||||
painter1.setPen(pen0);
|
||||
painter1.drawLine(x,0,x,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
// m_bDecodeFinished=false;
|
||||
}
|
||||
|
||||
update(); //trigger a new paintEvent
|
||||
m_bScaleOK=true;
|
||||
}
|
||||
|
||||
void CPlotter::drawRed(int ia, int ib, float swide[])
|
||||
{
|
||||
m_ia=ia;
|
||||
m_ib=ib;
|
||||
draw(swide,false,true);
|
||||
}
|
||||
|
||||
void CPlotter::DrawOverlay() //DrawOverlay()
|
||||
{
|
||||
if(m_OverlayPixmap.isNull()) return;
|
||||
if(m_WaterfallPixmap.isNull()) return;
|
||||
int w = m_WaterfallPixmap.width();
|
||||
int x,y,x1,x2,x3,x4,x5,x6;
|
||||
float pixperdiv;
|
||||
|
||||
double df = m_binsPerPixel*m_fftBinWidth;
|
||||
QRect rect;
|
||||
QPen penOrange(QColor(255,165,0),3);
|
||||
QPen penGreen(Qt::green, 3); //Mark Tol range with green line
|
||||
QPen penRed(Qt::red, 3); //Mark Tx freq with red
|
||||
QPainter painter(&m_OverlayPixmap);
|
||||
painter.initFrom(this);
|
||||
QLinearGradient gradient(0, 0, 0 ,m_h2); //fill background with gradient
|
||||
gradient.setColorAt(1, Qt::black);
|
||||
gradient.setColorAt(0, Qt::darkBlue);
|
||||
painter.setBrush(gradient);
|
||||
painter.drawRect(0, 0, m_w, m_h2);
|
||||
painter.setBrush(Qt::SolidPattern);
|
||||
|
||||
m_fSpan = w*df;
|
||||
// int n=m_fSpan/10;
|
||||
m_freqPerDiv=10;
|
||||
if(m_fSpan>100) m_freqPerDiv=20;
|
||||
if(m_fSpan>250) m_freqPerDiv=50;
|
||||
if(m_fSpan>500) m_freqPerDiv=100;
|
||||
if(m_fSpan>1000) m_freqPerDiv=200;
|
||||
if(m_fSpan>2500) m_freqPerDiv=500;
|
||||
|
||||
pixperdiv = m_freqPerDiv/df;
|
||||
m_hdivs = w*df/m_freqPerDiv + 1.9999;
|
||||
|
||||
float xx0=float(m_startFreq)/float(m_freqPerDiv);
|
||||
xx0=xx0-int(xx0);
|
||||
int x0=xx0*pixperdiv+0.5;
|
||||
for( int i=1; i<m_hdivs; i++) { //draw vertical grids
|
||||
x = (int)((float)i*pixperdiv ) - x0;
|
||||
if(x >= 0 and x<=m_w) {
|
||||
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
|
||||
painter.drawLine(x, 0, x , m_h2);
|
||||
}
|
||||
}
|
||||
|
||||
pixperdiv = (float)m_h2 / (float)VERT_DIVS;
|
||||
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
|
||||
for( int i=1; i<VERT_DIVS; i++) { //draw horizontal grids
|
||||
y = (int)( (float)i*pixperdiv );
|
||||
painter.drawLine(0, y, w, y);
|
||||
}
|
||||
|
||||
QRect rect0;
|
||||
QPainter painter0(&m_ScalePixmap);
|
||||
painter0.initFrom(this);
|
||||
|
||||
//create Font to use for scales
|
||||
QFont Font("Arial");
|
||||
Font.setPointSize(12);
|
||||
Font.setWeight(QFont::Normal);
|
||||
painter0.setFont(Font);
|
||||
painter0.setPen(Qt::black);
|
||||
|
||||
if(m_binsPerPixel < 1) m_binsPerPixel=1;
|
||||
m_hdivs = w*df/m_freqPerDiv + 0.9999;
|
||||
|
||||
m_ScalePixmap.fill(Qt::white);
|
||||
painter0.drawRect(0, 0, w, 30);
|
||||
MakeFrequencyStrs();
|
||||
|
||||
//draw tick marks on upper scale
|
||||
pixperdiv = m_freqPerDiv/df;
|
||||
for( int i=0; i<m_hdivs; i++) { //major ticks
|
||||
x = (int)((m_xOffset+i)*pixperdiv );
|
||||
painter0.drawLine(x,18,x,30);
|
||||
}
|
||||
int minor=5;
|
||||
if(m_freqPerDiv==200) minor=4;
|
||||
for( int i=1; i<minor*m_hdivs; i++) { //minor ticks
|
||||
x = i*pixperdiv/minor;
|
||||
painter0.drawLine(x,24,x,30);
|
||||
}
|
||||
|
||||
//draw frequency values
|
||||
for( int i=0; i<=m_hdivs; i++) {
|
||||
x = (int)((m_xOffset+i)*pixperdiv - pixperdiv/2);
|
||||
rect0.setRect(x,0, (int)pixperdiv, 20);
|
||||
painter0.drawText(rect0, Qt::AlignHCenter|Qt::AlignVCenter,m_HDivText[i]);
|
||||
}
|
||||
|
||||
float bw=9.0*12000.0/m_nsps; //JT9
|
||||
|
||||
if(m_mode=="FT8") bw=8*12000.0/2048.0; //FT8
|
||||
|
||||
if(m_mode=="JT4") { //JT4
|
||||
bw=3*11025.0/2520.0; //Max tone spacing (3/4 of actual BW)
|
||||
if(m_nSubMode==1) bw=2*bw;
|
||||
if(m_nSubMode==2) bw=4*bw;
|
||||
if(m_nSubMode==3) bw=9*bw;
|
||||
if(m_nSubMode==4) bw=18*bw;
|
||||
if(m_nSubMode==5) bw=36*bw;
|
||||
if(m_nSubMode==6) bw=72*bw;
|
||||
|
||||
painter0.setPen(penGreen);
|
||||
x1=XfromFreq(m_rxFreq-m_tol);
|
||||
x2=XfromFreq(m_rxFreq+m_tol);
|
||||
painter0.drawLine(x1,29,x2,29);
|
||||
for(int i=0; i<4; i++) {
|
||||
x1=XfromFreq(m_rxFreq+bw*i/3.0);
|
||||
int j=24;
|
||||
if(i==0) j=18;
|
||||
painter0.drawLine(x1,j,x1,30);
|
||||
}
|
||||
painter0.setPen(penRed);
|
||||
for(int i=0; i<4; i++) {
|
||||
x1=XfromFreq(m_txFreq+bw*i/3.0);
|
||||
painter0.drawLine(x1,12,x1,18);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_modeTx=="JT9" and m_nSubMode>0) { //JT9
|
||||
bw=8.0*12000.0/m_nsps;
|
||||
if(m_nSubMode==1) bw=2*bw; //B
|
||||
if(m_nSubMode==2) bw=4*bw; //C
|
||||
if(m_nSubMode==3) bw=8*bw; //D
|
||||
if(m_nSubMode==4) bw=16*bw; //E
|
||||
if(m_nSubMode==5) bw=32*bw; //F
|
||||
if(m_nSubMode==6) bw=64*bw; //G
|
||||
if(m_nSubMode==7) bw=128*bw; //H
|
||||
}
|
||||
|
||||
if(m_mode=="QRA64") { //QRA64
|
||||
bw=63.0*12000.0/m_nsps;
|
||||
if(m_nSubMode==1) bw=2*bw; //B
|
||||
if(m_nSubMode==2) bw=4*bw; //C
|
||||
if(m_nSubMode==3) bw=8*bw; //D
|
||||
if(m_nSubMode==4) bw=16*bw; //E
|
||||
}
|
||||
|
||||
if(m_modeTx=="JT65") { //JT65
|
||||
bw=65.0*11025.0/4096.0;
|
||||
if(m_nSubMode==1) bw=2*bw; //B
|
||||
if(m_nSubMode==2) bw=4*bw; //C
|
||||
}
|
||||
|
||||
painter0.setPen(penGreen);
|
||||
if(m_mode=="WSPR") {
|
||||
x1=XfromFreq(1400);
|
||||
x2=XfromFreq(1600);
|
||||
painter0.drawLine(x1,29,x2,29);
|
||||
}
|
||||
|
||||
if(m_mode=="WSPR-LF") {
|
||||
x1=XfromFreq(1600);
|
||||
x2=XfromFreq(1700);
|
||||
painter0.drawLine(x1,29,x2,29);
|
||||
}
|
||||
|
||||
if(m_mode=="FreqCal") { //FreqCal
|
||||
x1=XfromFreq(m_rxFreq-m_tol);
|
||||
x2=XfromFreq(m_rxFreq+m_tol);
|
||||
painter0.drawLine(x1,29,x2,29);
|
||||
x1=XfromFreq(m_rxFreq);
|
||||
painter0.drawLine(x1,24,x1,30);
|
||||
}
|
||||
|
||||
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or m_mode=="QRA64" or m_mode=="FT8") {
|
||||
|
||||
if(m_mode=="QRA64" or (m_mode=="JT65" and m_bVHF)) {
|
||||
painter0.setPen(penGreen);
|
||||
x1=XfromFreq(m_rxFreq-m_tol);
|
||||
x2=XfromFreq(m_rxFreq+m_tol);
|
||||
painter0.drawLine(x1,28,x2,28);
|
||||
x1=XfromFreq(m_rxFreq);
|
||||
painter0.drawLine(x1,24,x1,30);
|
||||
|
||||
if(m_mode=="JT65") {
|
||||
painter0.setPen(penOrange);
|
||||
x3=XfromFreq(m_rxFreq+20.0*bw/65.0); //RO
|
||||
painter0.drawLine(x3,24,x3,30);
|
||||
x4=XfromFreq(m_rxFreq+30.0*bw/65.0); //RRR
|
||||
painter0.drawLine(x4,24,x4,30);
|
||||
x5=XfromFreq(m_rxFreq+40.0*bw/65.0); //73
|
||||
painter0.drawLine(x5,24,x5,30);
|
||||
}
|
||||
painter0.setPen(penGreen);
|
||||
x6=XfromFreq(m_rxFreq+bw); //Highest tone
|
||||
painter0.drawLine(x6,24,x6,30);
|
||||
|
||||
} else {
|
||||
painter0.setPen(penGreen);
|
||||
x1=XfromFreq(m_rxFreq);
|
||||
x2=XfromFreq(m_rxFreq+bw);
|
||||
painter0.drawLine(x1,24,x1,30);
|
||||
painter0.drawLine(x1,28,x2,28);
|
||||
painter0.drawLine(x2,24,x2,30);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or
|
||||
m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="FT8") {
|
||||
painter0.setPen(penRed);
|
||||
x1=XfromFreq(m_txFreq);
|
||||
x2=XfromFreq(m_txFreq+bw);
|
||||
if(m_mode=="WSPR") {
|
||||
bw=4*12000.0/8192.0; //WSPR
|
||||
x1=XfromFreq(m_txFreq-0.5*bw);
|
||||
x2=XfromFreq(m_txFreq+0.5*bw);
|
||||
}
|
||||
if(m_mode=="WSPR-LF") {
|
||||
bw=3*12000.0/8640.0; //WSPR-LF
|
||||
x1=XfromFreq(m_txFreq-0.5*bw);
|
||||
x2=XfromFreq(m_txFreq+0.5*bw);
|
||||
}
|
||||
painter0.drawLine(x1,17,x1,21);
|
||||
painter0.drawLine(x1,17,x2,17);
|
||||
painter0.drawLine(x2,17,x2,21);
|
||||
}
|
||||
|
||||
if(m_mode=="JT9+JT65") {
|
||||
QPen pen2(Qt::blue, 3); //Mark the JT65 | JT9 divider
|
||||
painter0.setPen(pen2);
|
||||
x1=XfromFreq(m_fMin);
|
||||
if(x1<2) x1=2;
|
||||
x2=x1+30;
|
||||
painter0.drawLine(x1,8,x1,28);
|
||||
}
|
||||
|
||||
if(m_dialFreq>10.13 and m_dialFreq< 10.15 and m_mode.mid(0,4)!="WSPR") {
|
||||
float f1=1.0e6*(10.1401 - m_dialFreq);
|
||||
float f2=f1+200.0;
|
||||
x1=XfromFreq(f1);
|
||||
x2=XfromFreq(f2);
|
||||
if(x1<=m_w and x2>=0) {
|
||||
painter0.setPen(penOrange); //Mark WSPR sub-band orange
|
||||
painter0.drawLine(x1,9,x2,9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPlotter::MakeFrequencyStrs() //MakeFrequencyStrs
|
||||
{
|
||||
int f=(m_startFreq+m_freqPerDiv-1)/m_freqPerDiv;
|
||||
f*=m_freqPerDiv;
|
||||
m_xOffset=float(f-m_startFreq)/m_freqPerDiv;
|
||||
for(int i=0; i<=m_hdivs; i++) {
|
||||
m_HDivText[i].setNum(f);
|
||||
f+=m_freqPerDiv;
|
||||
}
|
||||
}
|
||||
|
||||
int CPlotter::XfromFreq(float f) //XfromFreq()
|
||||
{
|
||||
// float w = m_WaterfallPixmap.width();
|
||||
int x = int(m_w * (f - m_startFreq)/m_fSpan + 0.5);
|
||||
if(x<0 ) return 0;
|
||||
if(x>m_w) return m_w;
|
||||
return x;
|
||||
}
|
||||
|
||||
float CPlotter::FreqfromX(int x) //FreqfromX()
|
||||
{
|
||||
return float(m_startFreq + x*m_binsPerPixel*m_fftBinWidth);
|
||||
}
|
||||
|
||||
void CPlotter::SetRunningState(bool running) //SetRunningState()
|
||||
{
|
||||
m_Running = running;
|
||||
}
|
||||
|
||||
void CPlotter::setPlotZero(int plotZero) //setPlotZero()
|
||||
{
|
||||
m_plotZero=plotZero;
|
||||
}
|
||||
|
||||
int CPlotter::plotZero() //PlotZero()
|
||||
{
|
||||
return m_plotZero;
|
||||
}
|
||||
|
||||
void CPlotter::setPlotGain(int plotGain) //setPlotGain()
|
||||
{
|
||||
m_plotGain=plotGain;
|
||||
}
|
||||
|
||||
int CPlotter::plotGain() //plotGain()
|
||||
{
|
||||
return m_plotGain;
|
||||
}
|
||||
|
||||
int CPlotter::plot2dGain() //plot2dGain
|
||||
{
|
||||
return m_plot2dGain;
|
||||
}
|
||||
|
||||
void CPlotter::setPlot2dGain(int n) //setPlot2dGain
|
||||
{
|
||||
m_plot2dGain=n;
|
||||
update();
|
||||
}
|
||||
|
||||
int CPlotter::plot2dZero() //plot2dZero
|
||||
{
|
||||
return m_plot2dZero;
|
||||
}
|
||||
|
||||
void CPlotter::setPlot2dZero(int plot2dZero) //setPlot2dZero
|
||||
{
|
||||
m_plot2dZero=plot2dZero;
|
||||
}
|
||||
|
||||
void CPlotter::setStartFreq(int f) //SetStartFreq()
|
||||
{
|
||||
m_startFreq=f;
|
||||
resizeEvent(NULL);
|
||||
update();
|
||||
}
|
||||
|
||||
int CPlotter::startFreq() //startFreq()
|
||||
{
|
||||
return m_startFreq;
|
||||
}
|
||||
|
||||
int CPlotter::plotWidth(){return m_WaterfallPixmap.width();} //plotWidth
|
||||
void CPlotter::UpdateOverlay() {DrawOverlay();} //UpdateOverlay
|
||||
void CPlotter::setDataFromDisk(bool b) {m_dataFromDisk=b;} //setDataFromDisk
|
||||
|
||||
void CPlotter::setRxRange(int fMin) //setRxRange
|
||||
{
|
||||
m_fMin=fMin;
|
||||
}
|
||||
|
||||
void CPlotter::setBinsPerPixel(int n) //setBinsPerPixel
|
||||
{
|
||||
m_binsPerPixel = n;
|
||||
DrawOverlay(); //Redraw scales and ticks
|
||||
update(); //trigger a new paintEvent}
|
||||
}
|
||||
|
||||
int CPlotter::binsPerPixel() //binsPerPixel
|
||||
{
|
||||
return m_binsPerPixel;
|
||||
}
|
||||
|
||||
void CPlotter::setWaterfallAvg(int n) //setBinsPerPixel
|
||||
{
|
||||
m_waterfallAvg = n;
|
||||
}
|
||||
|
||||
void CPlotter::setRxFreq (int x) //setRxFreq
|
||||
{
|
||||
m_rxFreq = x; // x is freq in Hz
|
||||
DrawOverlay();
|
||||
update();
|
||||
}
|
||||
|
||||
int CPlotter::rxFreq() {return m_rxFreq;} //rxFreq
|
||||
|
||||
void CPlotter::mousePressEvent(QMouseEvent *event) //mousePressEvent
|
||||
{
|
||||
int x=event->x();
|
||||
if(x<0) x=0;
|
||||
if(x>m_Size.width()) x=m_Size.width();
|
||||
bool ctrl = (event->modifiers() & Qt::ControlModifier);
|
||||
bool shift = (event->modifiers() & Qt::ShiftModifier);
|
||||
int newFreq = int(FreqfromX(x)+0.5);
|
||||
int oldTxFreq = m_txFreq;
|
||||
int oldRxFreq = m_rxFreq;
|
||||
|
||||
if (ctrl or m_lockTxFreq) {
|
||||
emit setFreq1 (newFreq, newFreq);
|
||||
}
|
||||
else if (shift) {
|
||||
emit setFreq1 (oldRxFreq, newFreq);
|
||||
}
|
||||
else {
|
||||
emit setFreq1(newFreq,oldTxFreq);
|
||||
}
|
||||
|
||||
int n=1;
|
||||
if(ctrl) n+=100;
|
||||
emit freezeDecode1(n);
|
||||
}
|
||||
|
||||
void CPlotter::mouseDoubleClickEvent(QMouseEvent *event) //mouse2click
|
||||
{
|
||||
bool ctrl = (event->modifiers() & Qt::ControlModifier);
|
||||
int n=2;
|
||||
if(ctrl) n+=100;
|
||||
emit freezeDecode1(n);
|
||||
}
|
||||
|
||||
void CPlotter::setNsps(int ntrperiod, int nsps) //setNsps
|
||||
{
|
||||
m_TRperiod=ntrperiod;
|
||||
m_nsps=nsps;
|
||||
m_fftBinWidth=1500.0/2048.0;
|
||||
if(m_nsps==15360) m_fftBinWidth=1500.0/2048.0;
|
||||
if(m_nsps==40960) m_fftBinWidth=1500.0/6144.0;
|
||||
if(m_nsps==82944) m_fftBinWidth=1500.0/12288.0;
|
||||
if(m_nsps==252000) m_fftBinWidth=1500.0/32768.0;
|
||||
DrawOverlay(); //Redraw scales and ticks
|
||||
update(); //trigger a new paintEvent}
|
||||
}
|
||||
|
||||
void CPlotter::setTxFreq(int n) //setTxFreq
|
||||
{
|
||||
m_txFreq=n;
|
||||
DrawOverlay();
|
||||
update();
|
||||
}
|
||||
|
||||
void CPlotter::setMode(QString mode) //setMode
|
||||
{
|
||||
m_mode=mode;
|
||||
}
|
||||
|
||||
void CPlotter::setSubMode(int n) //setSubMode
|
||||
{
|
||||
m_nSubMode=n;
|
||||
}
|
||||
|
||||
void CPlotter::setModeTx(QString modeTx) //setModeTx
|
||||
{
|
||||
m_modeTx=modeTx;
|
||||
}
|
||||
|
||||
int CPlotter::Fmax()
|
||||
{
|
||||
return m_fMax;
|
||||
}
|
||||
|
||||
void CPlotter::setDialFreq(double d)
|
||||
{
|
||||
m_dialFreq=d;
|
||||
DrawOverlay();
|
||||
update();
|
||||
}
|
||||
|
||||
void CPlotter::setRxBand(QString band)
|
||||
{
|
||||
m_rxBand=band;
|
||||
}
|
||||
|
||||
void CPlotter::setFlatten(bool b1, bool b2)
|
||||
{
|
||||
m_Flatten=0;
|
||||
if(b1) m_Flatten=1;
|
||||
if(b2) m_Flatten=2;
|
||||
}
|
||||
|
||||
void CPlotter::setTol(int n) //setTol()
|
||||
{
|
||||
m_tol=n;
|
||||
DrawOverlay();
|
||||
}
|
||||
|
||||
void CPlotter::setColours(QVector<QColor> const& cl)
|
||||
{
|
||||
g_ColorTbl = cl;
|
||||
}
|
||||
|
||||
void CPlotter::SetPercent2DScreen(int percent)
|
||||
{
|
||||
m_Percent2DScreen=percent;
|
||||
resizeEvent(NULL);
|
||||
update();
|
||||
}
|
||||
void CPlotter::setVHF(bool bVHF)
|
||||
{
|
||||
m_bVHF=bVHF;
|
||||
}
|
||||
|
||||
void CPlotter::setRedFile(QString fRed)
|
||||
{
|
||||
m_redFile=fRed;
|
||||
}
|
||||
@@ -1,748 +0,0 @@
|
||||
#include "plotter.h"
|
||||
#include <math.h>
|
||||
#include <QDebug>
|
||||
#include "commons.h"
|
||||
#include "moc_plotter.cpp"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#define MAX_SCREENSIZE 2048
|
||||
|
||||
CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
|
||||
QFrame {parent},
|
||||
m_bScaleOK {false},
|
||||
m_bReference {false},
|
||||
m_bReference0 {false},
|
||||
m_fSpan {2000.0},
|
||||
m_plotZero {0},
|
||||
m_plotGain {0},
|
||||
m_plot2dGain {0},
|
||||
m_plot2dZero {0},
|
||||
m_nSubMode {0},
|
||||
m_Running {false},
|
||||
m_paintEventBusy {false},
|
||||
m_fftBinWidth {1500.0/2048.0},
|
||||
m_dialFreq {0.},
|
||||
m_sum {},
|
||||
m_dBStepSize {10},
|
||||
m_FreqUnits {1},
|
||||
m_hdivs {HORZ_DIVS},
|
||||
m_line {0},
|
||||
m_fSample {12000},
|
||||
m_nsps {6912},
|
||||
m_Percent2DScreen {30}, //percent of screen used for 2D display
|
||||
m_Percent2DScreen0 {0},
|
||||
m_rxFreq {1020},
|
||||
m_txFreq {0},
|
||||
m_startFreq {0}
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setAttribute(Qt::WA_PaintOnScreen,false);
|
||||
setAutoFillBackground(false);
|
||||
setAttribute(Qt::WA_OpaquePaintEvent, false);
|
||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
}
|
||||
|
||||
CPlotter::~CPlotter() { } // Destructor
|
||||
|
||||
QSize CPlotter::minimumSizeHint() const
|
||||
{
|
||||
return QSize(50, 50);
|
||||
}
|
||||
|
||||
QSize CPlotter::sizeHint() const
|
||||
{
|
||||
return QSize(180, 180);
|
||||
}
|
||||
|
||||
void CPlotter::resizeEvent(QResizeEvent* ) //resizeEvent()
|
||||
{
|
||||
if(!size().isValid()) return;
|
||||
if( m_Size != size() or (m_bReference != m_bReference0) or
|
||||
m_Percent2DScreen != m_Percent2DScreen0) {
|
||||
m_Size = size();
|
||||
m_w = m_Size.width();
|
||||
m_h = m_Size.height();
|
||||
m_h2 = m_Percent2DScreen*m_h/100.0;
|
||||
if(m_h2>m_h-30) m_h2=m_h-30;
|
||||
if(m_bReference) m_h2=m_h-30;
|
||||
if(m_h2<1) m_h2=1;
|
||||
m_h1=m_h-m_h2;
|
||||
m_2DPixmap = QPixmap(m_Size.width(), m_h2);
|
||||
m_2DPixmap.fill(Qt::black);
|
||||
m_WaterfallPixmap = QPixmap(m_Size.width(), m_h1);
|
||||
m_OverlayPixmap = QPixmap(m_Size.width(), m_h2);
|
||||
m_OverlayPixmap.fill(Qt::black);
|
||||
m_WaterfallPixmap.fill(Qt::black);
|
||||
m_2DPixmap.fill(Qt::black);
|
||||
m_ScalePixmap = QPixmap(m_w,30);
|
||||
m_ScalePixmap.fill(Qt::white);
|
||||
m_Percent2DScreen0 = m_Percent2DScreen;
|
||||
}
|
||||
DrawOverlay();
|
||||
}
|
||||
|
||||
void CPlotter::paintEvent(QPaintEvent *) // paintEvent()
|
||||
{
|
||||
if(m_paintEventBusy) return;
|
||||
m_paintEventBusy=true;
|
||||
QPainter painter(this);
|
||||
painter.drawPixmap(0,0,m_ScalePixmap);
|
||||
painter.drawPixmap(0,30,m_WaterfallPixmap);
|
||||
painter.drawPixmap(0,m_h1,m_2DPixmap);
|
||||
m_paintEventBusy=false;
|
||||
}
|
||||
|
||||
void CPlotter::draw(float swide[], bool bScroll, bool bRed)
|
||||
{
|
||||
int j,j0;
|
||||
static int ktop=0;
|
||||
float y,y2,ymin;
|
||||
double fac = sqrt(m_binsPerPixel*m_waterfallAvg/15.0);
|
||||
double gain = fac*pow(10.0,0.02*m_plotGain);
|
||||
double gain2d = pow(10.0,0.02*(m_plot2dGain));
|
||||
|
||||
if(m_bReference != m_bReference0) resizeEvent(NULL);
|
||||
m_bReference0=m_bReference;
|
||||
|
||||
//move current data down one line (must do this before attaching a QPainter object)
|
||||
if(bScroll) m_WaterfallPixmap.scroll(0,1,0,0,m_w,m_h1);
|
||||
QPainter painter1(&m_WaterfallPixmap);
|
||||
m_2DPixmap = m_OverlayPixmap.copy(0,0,m_w,m_h2);
|
||||
QPainter painter2D(&m_2DPixmap);
|
||||
if(!painter2D.isActive()) return;
|
||||
QFont Font("Arial");
|
||||
Font.setPointSize(12);
|
||||
Font.setWeight(QFont::Normal);
|
||||
painter2D.setFont(Font);
|
||||
|
||||
if(m_bLinearAvg) {
|
||||
painter2D.setPen(Qt::yellow);
|
||||
} else if(m_bReference) {
|
||||
painter2D.setPen(Qt::blue);
|
||||
} else {
|
||||
painter2D.setPen(Qt::green);
|
||||
}
|
||||
static QPoint LineBuf[MAX_SCREENSIZE];
|
||||
static QPoint LineBuf2[MAX_SCREENSIZE];
|
||||
j=0;
|
||||
j0=int(m_startFreq/m_fftBinWidth + 0.5);
|
||||
int iz=XfromFreq(5000.0);
|
||||
int jz=iz*m_binsPerPixel;
|
||||
m_fMax=FreqfromX(iz);
|
||||
|
||||
m_line++;
|
||||
if(bScroll) {
|
||||
flat4_(swide,&iz,&m_Flatten);
|
||||
flat4_(&dec_data.savg[j0],&jz,&m_Flatten);
|
||||
}
|
||||
|
||||
ymin=1.e30;
|
||||
if(swide[0]>1.e29 and swide[0]< 1.5e30) painter1.setPen(Qt::green);
|
||||
if(swide[0]>1.4e30) painter1.setPen(Qt::yellow);
|
||||
for(int i=0; i<iz; i++) {
|
||||
y=swide[i];
|
||||
if(y<ymin) ymin=y;
|
||||
int y1 = 10.0*gain*y + 10*m_plotZero +40;
|
||||
if (y1<0) y1=0;
|
||||
if (y1>254) y1=254;
|
||||
if (swide[i]<1.e29) painter1.setPen(g_ColorTbl[y1]);
|
||||
painter1.drawPoint(i,0);
|
||||
}
|
||||
|
||||
float y2min=1.e30;
|
||||
float y2max=-1.e30;
|
||||
for(int i=0; i<iz; i++) {
|
||||
y=swide[i] - ymin;
|
||||
y2=0;
|
||||
if(m_bCurrent) y2 = gain2d*y + m_plot2dZero; //Current
|
||||
|
||||
if(bScroll) {
|
||||
float sum=0.0;
|
||||
int j=j0+m_binsPerPixel*i;
|
||||
for(int k=0; k<m_binsPerPixel; k++) {
|
||||
sum+=dec_data.savg[j++];
|
||||
}
|
||||
m_sum[i]=sum;
|
||||
}
|
||||
if(m_bCumulative) y2=gain2d*(m_sum[i]/m_binsPerPixel + m_plot2dZero);
|
||||
if(m_Flatten==0) y2 += 15; //### could do better! ###
|
||||
|
||||
if(m_bLinearAvg) { //Linear Avg (yellow)
|
||||
float sum=0.0;
|
||||
int j=j0+m_binsPerPixel*i;
|
||||
for(int k=0; k<m_binsPerPixel; k++) {
|
||||
sum+=spectra_.syellow[j++];
|
||||
}
|
||||
y2=gain2d*sum/m_binsPerPixel + m_plot2dZero;
|
||||
}
|
||||
|
||||
if(m_bReference) { //Reference (red)
|
||||
float df_ref=12000.0/6912.0;
|
||||
int j=FreqfromX(i)/df_ref + 0.5;
|
||||
y2=spectra_.ref[j] + m_plot2dZero;
|
||||
// if(gain2d>1.5) y2=spectra_.filter[j] + m_plot2dZero;
|
||||
|
||||
}
|
||||
|
||||
if(i==iz-1) {
|
||||
painter2D.drawPolyline(LineBuf,j);
|
||||
if(m_mode=="QRA64") {
|
||||
painter2D.setPen(Qt::red);
|
||||
painter2D.drawPolyline(LineBuf2,ktop);
|
||||
}
|
||||
}
|
||||
LineBuf[j].setX(i);
|
||||
LineBuf[j].setY(int(0.9*m_h2-y2*m_h2/70.0));
|
||||
if(y2<y2min) y2min=y2;
|
||||
if(y2>y2max) y2max=y2;
|
||||
j++;
|
||||
}
|
||||
|
||||
if(swide[0]>1.0e29) m_line=0;
|
||||
if(m_line == painter1.fontMetrics ().height ()) {
|
||||
painter1.setPen(Qt::white);
|
||||
QString t;
|
||||
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
||||
int n=(ms/1000) % m_TRperiod;
|
||||
QDateTime t1=QDateTime::currentDateTimeUtc().addSecs(-n);
|
||||
if(m_TRperiod < 60) {
|
||||
t=t1.toString("hh:mm:ss") + " " + m_rxBand;
|
||||
} else {
|
||||
t=t1.toString("hh:mm") + " " + m_rxBand;
|
||||
}
|
||||
painter1.drawText (5, painter1.fontMetrics ().ascent (), t);
|
||||
}
|
||||
|
||||
if(m_mode=="JT4" or m_mode=="QRA64") {
|
||||
QPen pen3(Qt::yellow); //Mark freqs of JT4 single-tone msgs
|
||||
painter2D.setPen(pen3);
|
||||
Font.setWeight(QFont::Bold);
|
||||
painter2D.setFont(Font);
|
||||
int x1=XfromFreq(m_rxFreq);
|
||||
y=0.2*m_h2;
|
||||
painter2D.drawText(x1-4,y,"T");
|
||||
x1=XfromFreq(m_rxFreq+250);
|
||||
painter2D.drawText(x1-4,y,"M");
|
||||
x1=XfromFreq(m_rxFreq+500);
|
||||
painter2D.drawText(x1-4,y,"R");
|
||||
x1=XfromFreq(m_rxFreq+750);
|
||||
painter2D.drawText(x1-4,y,"73");
|
||||
}
|
||||
|
||||
if(bRed) {
|
||||
std::ifstream f;
|
||||
f.open(m_redFile.toLatin1());
|
||||
if(f) {
|
||||
int x,y;
|
||||
float freq,sync;
|
||||
float slimit=6.0;
|
||||
QPen pen0(Qt::red,1);
|
||||
painter1.setPen(pen0);
|
||||
for(int i=0; i<99999; i++) {
|
||||
f >> freq >> sync;
|
||||
if(f.eof()) break;
|
||||
x=XfromFreq(freq);
|
||||
y=(sync-slimit)*3.0;
|
||||
if(y>0) {
|
||||
if(y>15.0) y=15.0;
|
||||
if(x>=0 and x<=m_w) {
|
||||
painter1.setPen(pen0);
|
||||
painter1.drawLine(x,0,x,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
// m_bDecodeFinished=false;
|
||||
}
|
||||
|
||||
update(); //trigger a new paintEvent
|
||||
m_bScaleOK=true;
|
||||
}
|
||||
|
||||
void CPlotter::drawRed(int ia, int ib, float swide[])
|
||||
{
|
||||
m_ia=ia;
|
||||
m_ib=ib;
|
||||
draw(swide,false,true);
|
||||
}
|
||||
|
||||
void CPlotter::DrawOverlay() //DrawOverlay()
|
||||
{
|
||||
if(m_OverlayPixmap.isNull()) return;
|
||||
if(m_WaterfallPixmap.isNull()) return;
|
||||
int w = m_WaterfallPixmap.width();
|
||||
int x,y,x1,x2,x3,x4,x5,x6;
|
||||
float pixperdiv;
|
||||
|
||||
double df = m_binsPerPixel*m_fftBinWidth;
|
||||
QRect rect;
|
||||
QPen penOrange(QColor(255,165,0),3);
|
||||
QPen penGreen(Qt::green, 3); //Mark Tol range with green line
|
||||
QPen penRed(Qt::red, 3); //Mark Tx freq with red
|
||||
QPainter painter(&m_OverlayPixmap);
|
||||
painter.initFrom(this);
|
||||
QLinearGradient gradient(0, 0, 0 ,m_h2); //fill background with gradient
|
||||
gradient.setColorAt(1, Qt::black);
|
||||
gradient.setColorAt(0, Qt::darkBlue);
|
||||
painter.setBrush(gradient);
|
||||
painter.drawRect(0, 0, m_w, m_h2);
|
||||
painter.setBrush(Qt::SolidPattern);
|
||||
|
||||
m_fSpan = w*df;
|
||||
// int n=m_fSpan/10;
|
||||
m_freqPerDiv=10;
|
||||
if(m_fSpan>100) m_freqPerDiv=20;
|
||||
if(m_fSpan>250) m_freqPerDiv=50;
|
||||
if(m_fSpan>500) m_freqPerDiv=100;
|
||||
if(m_fSpan>1000) m_freqPerDiv=200;
|
||||
if(m_fSpan>2500) m_freqPerDiv=500;
|
||||
|
||||
pixperdiv = m_freqPerDiv/df;
|
||||
m_hdivs = w*df/m_freqPerDiv + 1.9999;
|
||||
|
||||
float xx0=float(m_startFreq)/float(m_freqPerDiv);
|
||||
xx0=xx0-int(xx0);
|
||||
int x0=xx0*pixperdiv+0.5;
|
||||
for( int i=1; i<m_hdivs; i++) { //draw vertical grids
|
||||
x = (int)((float)i*pixperdiv ) - x0;
|
||||
if(x >= 0 and x<=m_w) {
|
||||
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
|
||||
painter.drawLine(x, 0, x , m_h2);
|
||||
}
|
||||
}
|
||||
|
||||
pixperdiv = (float)m_h2 / (float)VERT_DIVS;
|
||||
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
|
||||
for( int i=1; i<VERT_DIVS; i++) { //draw horizontal grids
|
||||
y = (int)( (float)i*pixperdiv );
|
||||
painter.drawLine(0, y, w, y);
|
||||
}
|
||||
|
||||
QRect rect0;
|
||||
QPainter painter0(&m_ScalePixmap);
|
||||
painter0.initFrom(this);
|
||||
|
||||
//create Font to use for scales
|
||||
QFont Font("Arial");
|
||||
Font.setPointSize(12);
|
||||
Font.setWeight(QFont::Normal);
|
||||
painter0.setFont(Font);
|
||||
painter0.setPen(Qt::black);
|
||||
|
||||
if(m_binsPerPixel < 1) m_binsPerPixel=1;
|
||||
m_hdivs = w*df/m_freqPerDiv + 0.9999;
|
||||
|
||||
m_ScalePixmap.fill(Qt::white);
|
||||
painter0.drawRect(0, 0, w, 30);
|
||||
MakeFrequencyStrs();
|
||||
|
||||
//draw tick marks on upper scale
|
||||
pixperdiv = m_freqPerDiv/df;
|
||||
for( int i=0; i<m_hdivs; i++) { //major ticks
|
||||
x = (int)((m_xOffset+i)*pixperdiv );
|
||||
painter0.drawLine(x,18,x,30);
|
||||
}
|
||||
int minor=5;
|
||||
if(m_freqPerDiv==200) minor=4;
|
||||
for( int i=1; i<minor*m_hdivs; i++) { //minor ticks
|
||||
x = i*pixperdiv/minor;
|
||||
painter0.drawLine(x,24,x,30);
|
||||
}
|
||||
|
||||
//draw frequency values
|
||||
for( int i=0; i<=m_hdivs; i++) {
|
||||
x = (int)((m_xOffset+i)*pixperdiv - pixperdiv/2);
|
||||
rect0.setRect(x,0, (int)pixperdiv, 20);
|
||||
painter0.drawText(rect0, Qt::AlignHCenter|Qt::AlignVCenter,m_HDivText[i]);
|
||||
}
|
||||
|
||||
float bw=9.0*12000.0/m_nsps; //JT9
|
||||
|
||||
if(m_mode=="FT8") bw=8*12000.0/1920.0; //FT8
|
||||
|
||||
if(m_mode=="JT4") { //JT4
|
||||
bw=3*11025.0/2520.0; //Max tone spacing (3/4 of actual BW)
|
||||
if(m_nSubMode==1) bw=2*bw;
|
||||
if(m_nSubMode==2) bw=4*bw;
|
||||
if(m_nSubMode==3) bw=9*bw;
|
||||
if(m_nSubMode==4) bw=18*bw;
|
||||
if(m_nSubMode==5) bw=36*bw;
|
||||
if(m_nSubMode==6) bw=72*bw;
|
||||
|
||||
painter0.setPen(penGreen);
|
||||
x1=XfromFreq(m_rxFreq-m_tol);
|
||||
x2=XfromFreq(m_rxFreq+m_tol);
|
||||
painter0.drawLine(x1,29,x2,29);
|
||||
for(int i=0; i<4; i++) {
|
||||
x1=XfromFreq(m_rxFreq+bw*i/3.0);
|
||||
int j=24;
|
||||
if(i==0) j=18;
|
||||
painter0.drawLine(x1,j,x1,30);
|
||||
}
|
||||
painter0.setPen(penRed);
|
||||
for(int i=0; i<4; i++) {
|
||||
x1=XfromFreq(m_txFreq+bw*i/3.0);
|
||||
painter0.drawLine(x1,12,x1,18);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_modeTx=="JT9" and m_nSubMode>0) { //JT9
|
||||
bw=8.0*12000.0/m_nsps;
|
||||
if(m_nSubMode==1) bw=2*bw; //B
|
||||
if(m_nSubMode==2) bw=4*bw; //C
|
||||
if(m_nSubMode==3) bw=8*bw; //D
|
||||
if(m_nSubMode==4) bw=16*bw; //E
|
||||
if(m_nSubMode==5) bw=32*bw; //F
|
||||
if(m_nSubMode==6) bw=64*bw; //G
|
||||
if(m_nSubMode==7) bw=128*bw; //H
|
||||
}
|
||||
|
||||
if(m_mode=="QRA64") { //QRA64
|
||||
bw=63.0*12000.0/m_nsps;
|
||||
if(m_nSubMode==1) bw=2*bw; //B
|
||||
if(m_nSubMode==2) bw=4*bw; //C
|
||||
if(m_nSubMode==3) bw=8*bw; //D
|
||||
if(m_nSubMode==4) bw=16*bw; //E
|
||||
}
|
||||
|
||||
if(m_modeTx=="JT65") { //JT65
|
||||
bw=65.0*11025.0/4096.0;
|
||||
if(m_nSubMode==1) bw=2*bw; //B
|
||||
if(m_nSubMode==2) bw=4*bw; //C
|
||||
}
|
||||
|
||||
painter0.setPen(penGreen);
|
||||
if(m_mode=="WSPR") {
|
||||
x1=XfromFreq(1400);
|
||||
x2=XfromFreq(1600);
|
||||
painter0.drawLine(x1,29,x2,29);
|
||||
}
|
||||
|
||||
if(m_mode=="WSPR-LF") {
|
||||
x1=XfromFreq(1600);
|
||||
x2=XfromFreq(1700);
|
||||
painter0.drawLine(x1,29,x2,29);
|
||||
}
|
||||
|
||||
if(m_mode=="FreqCal") { //FreqCal
|
||||
x1=XfromFreq(m_rxFreq-m_tol);
|
||||
x2=XfromFreq(m_rxFreq+m_tol);
|
||||
painter0.drawLine(x1,29,x2,29);
|
||||
x1=XfromFreq(m_rxFreq);
|
||||
painter0.drawLine(x1,24,x1,30);
|
||||
}
|
||||
|
||||
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or m_mode=="QRA64" or m_mode=="FT8") {
|
||||
|
||||
if(m_mode=="QRA64" or (m_mode=="JT65" and m_bVHF)) {
|
||||
painter0.setPen(penGreen);
|
||||
x1=XfromFreq(m_rxFreq-m_tol);
|
||||
x2=XfromFreq(m_rxFreq+m_tol);
|
||||
painter0.drawLine(x1,28,x2,28);
|
||||
x1=XfromFreq(m_rxFreq);
|
||||
painter0.drawLine(x1,24,x1,30);
|
||||
|
||||
if(m_mode=="JT65") {
|
||||
painter0.setPen(penOrange);
|
||||
x3=XfromFreq(m_rxFreq+20.0*bw/65.0); //RO
|
||||
painter0.drawLine(x3,24,x3,30);
|
||||
x4=XfromFreq(m_rxFreq+30.0*bw/65.0); //RRR
|
||||
painter0.drawLine(x4,24,x4,30);
|
||||
x5=XfromFreq(m_rxFreq+40.0*bw/65.0); //73
|
||||
painter0.drawLine(x5,24,x5,30);
|
||||
}
|
||||
painter0.setPen(penGreen);
|
||||
x6=XfromFreq(m_rxFreq+bw); //Highest tone
|
||||
painter0.drawLine(x6,24,x6,30);
|
||||
|
||||
} else {
|
||||
painter0.setPen(penGreen);
|
||||
x1=XfromFreq(m_rxFreq);
|
||||
x2=XfromFreq(m_rxFreq+bw);
|
||||
painter0.drawLine(x1,24,x1,30);
|
||||
painter0.drawLine(x1,28,x2,28);
|
||||
painter0.drawLine(x2,24,x2,30);
|
||||
}
|
||||
}
|
||||
|
||||
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or
|
||||
m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="FT8") {
|
||||
painter0.setPen(penRed);
|
||||
x1=XfromFreq(m_txFreq);
|
||||
x2=XfromFreq(m_txFreq+bw);
|
||||
if(m_mode=="WSPR") {
|
||||
bw=4*12000.0/8192.0; //WSPR
|
||||
x1=XfromFreq(m_txFreq-0.5*bw);
|
||||
x2=XfromFreq(m_txFreq+0.5*bw);
|
||||
}
|
||||
if(m_mode=="WSPR-LF") {
|
||||
bw=3*12000.0/8640.0; //WSPR-LF
|
||||
x1=XfromFreq(m_txFreq-0.5*bw);
|
||||
x2=XfromFreq(m_txFreq+0.5*bw);
|
||||
}
|
||||
painter0.drawLine(x1,17,x1,21);
|
||||
painter0.drawLine(x1,17,x2,17);
|
||||
painter0.drawLine(x2,17,x2,21);
|
||||
}
|
||||
|
||||
if(m_mode=="JT9+JT65") {
|
||||
QPen pen2(Qt::blue, 3); //Mark the JT65 | JT9 divider
|
||||
painter0.setPen(pen2);
|
||||
x1=XfromFreq(m_fMin);
|
||||
if(x1<2) x1=2;
|
||||
x2=x1+30;
|
||||
painter0.drawLine(x1,8,x1,28);
|
||||
}
|
||||
|
||||
if(m_dialFreq>10.13 and m_dialFreq< 10.15 and m_mode.mid(0,4)!="WSPR") {
|
||||
float f1=1.0e6*(10.1401 - m_dialFreq);
|
||||
float f2=f1+200.0;
|
||||
x1=XfromFreq(f1);
|
||||
x2=XfromFreq(f2);
|
||||
if(x1<=m_w and x2>=0) {
|
||||
painter0.setPen(penOrange); //Mark WSPR sub-band orange
|
||||
painter0.drawLine(x1,9,x2,9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPlotter::MakeFrequencyStrs() //MakeFrequencyStrs
|
||||
{
|
||||
int f=(m_startFreq+m_freqPerDiv-1)/m_freqPerDiv;
|
||||
f*=m_freqPerDiv;
|
||||
m_xOffset=float(f-m_startFreq)/m_freqPerDiv;
|
||||
for(int i=0; i<=m_hdivs; i++) {
|
||||
m_HDivText[i].setNum(f);
|
||||
f+=m_freqPerDiv;
|
||||
}
|
||||
}
|
||||
|
||||
int CPlotter::XfromFreq(float f) //XfromFreq()
|
||||
{
|
||||
// float w = m_WaterfallPixmap.width();
|
||||
int x = int(m_w * (f - m_startFreq)/m_fSpan + 0.5);
|
||||
if(x<0 ) return 0;
|
||||
if(x>m_w) return m_w;
|
||||
return x;
|
||||
}
|
||||
|
||||
float CPlotter::FreqfromX(int x) //FreqfromX()
|
||||
{
|
||||
return float(m_startFreq + x*m_binsPerPixel*m_fftBinWidth);
|
||||
}
|
||||
|
||||
void CPlotter::SetRunningState(bool running) //SetRunningState()
|
||||
{
|
||||
m_Running = running;
|
||||
}
|
||||
|
||||
void CPlotter::setPlotZero(int plotZero) //setPlotZero()
|
||||
{
|
||||
m_plotZero=plotZero;
|
||||
}
|
||||
|
||||
int CPlotter::plotZero() //PlotZero()
|
||||
{
|
||||
return m_plotZero;
|
||||
}
|
||||
|
||||
void CPlotter::setPlotGain(int plotGain) //setPlotGain()
|
||||
{
|
||||
m_plotGain=plotGain;
|
||||
}
|
||||
|
||||
int CPlotter::plotGain() //plotGain()
|
||||
{
|
||||
return m_plotGain;
|
||||
}
|
||||
|
||||
int CPlotter::plot2dGain() //plot2dGain
|
||||
{
|
||||
return m_plot2dGain;
|
||||
}
|
||||
|
||||
void CPlotter::setPlot2dGain(int n) //setPlot2dGain
|
||||
{
|
||||
m_plot2dGain=n;
|
||||
update();
|
||||
}
|
||||
|
||||
int CPlotter::plot2dZero() //plot2dZero
|
||||
{
|
||||
return m_plot2dZero;
|
||||
}
|
||||
|
||||
void CPlotter::setPlot2dZero(int plot2dZero) //setPlot2dZero
|
||||
{
|
||||
m_plot2dZero=plot2dZero;
|
||||
}
|
||||
|
||||
void CPlotter::setStartFreq(int f) //SetStartFreq()
|
||||
{
|
||||
m_startFreq=f;
|
||||
resizeEvent(NULL);
|
||||
update();
|
||||
}
|
||||
|
||||
int CPlotter::startFreq() //startFreq()
|
||||
{
|
||||
return m_startFreq;
|
||||
}
|
||||
|
||||
int CPlotter::plotWidth(){return m_WaterfallPixmap.width();} //plotWidth
|
||||
void CPlotter::UpdateOverlay() {DrawOverlay();} //UpdateOverlay
|
||||
void CPlotter::setDataFromDisk(bool b) {m_dataFromDisk=b;} //setDataFromDisk
|
||||
|
||||
void CPlotter::setRxRange(int fMin) //setRxRange
|
||||
{
|
||||
m_fMin=fMin;
|
||||
}
|
||||
|
||||
void CPlotter::setBinsPerPixel(int n) //setBinsPerPixel
|
||||
{
|
||||
m_binsPerPixel = n;
|
||||
DrawOverlay(); //Redraw scales and ticks
|
||||
update(); //trigger a new paintEvent}
|
||||
}
|
||||
|
||||
int CPlotter::binsPerPixel() //binsPerPixel
|
||||
{
|
||||
return m_binsPerPixel;
|
||||
}
|
||||
|
||||
void CPlotter::setWaterfallAvg(int n) //setBinsPerPixel
|
||||
{
|
||||
m_waterfallAvg = n;
|
||||
}
|
||||
|
||||
void CPlotter::setRxFreq (int x) //setRxFreq
|
||||
{
|
||||
m_rxFreq = x; // x is freq in Hz
|
||||
DrawOverlay();
|
||||
update();
|
||||
}
|
||||
|
||||
int CPlotter::rxFreq() {return m_rxFreq;} //rxFreq
|
||||
|
||||
void CPlotter::mousePressEvent(QMouseEvent *event) //mousePressEvent
|
||||
{
|
||||
int x=event->x();
|
||||
if(x<0) x=0;
|
||||
if(x>m_Size.width()) x=m_Size.width();
|
||||
bool ctrl = (event->modifiers() & Qt::ControlModifier);
|
||||
bool shift = (event->modifiers() & Qt::ShiftModifier);
|
||||
int newFreq = int(FreqfromX(x)+0.5);
|
||||
int oldTxFreq = m_txFreq;
|
||||
int oldRxFreq = m_rxFreq;
|
||||
|
||||
if (ctrl or m_lockTxFreq) {
|
||||
emit setFreq1 (newFreq, newFreq);
|
||||
}
|
||||
else if (shift) {
|
||||
emit setFreq1 (oldRxFreq, newFreq);
|
||||
}
|
||||
else {
|
||||
emit setFreq1(newFreq,oldTxFreq);
|
||||
}
|
||||
|
||||
int n=1;
|
||||
if(ctrl) n+=100;
|
||||
emit freezeDecode1(n);
|
||||
}
|
||||
|
||||
void CPlotter::mouseDoubleClickEvent(QMouseEvent *event) //mouse2click
|
||||
{
|
||||
bool ctrl = (event->modifiers() & Qt::ControlModifier);
|
||||
int n=2;
|
||||
if(ctrl) n+=100;
|
||||
emit freezeDecode1(n);
|
||||
}
|
||||
|
||||
void CPlotter::setNsps(int ntrperiod, int nsps) //setNsps
|
||||
{
|
||||
m_TRperiod=ntrperiod;
|
||||
m_nsps=nsps;
|
||||
m_fftBinWidth=1500.0/2048.0;
|
||||
if(m_nsps==15360) m_fftBinWidth=1500.0/2048.0;
|
||||
if(m_nsps==40960) m_fftBinWidth=1500.0/6144.0;
|
||||
if(m_nsps==82944) m_fftBinWidth=1500.0/12288.0;
|
||||
if(m_nsps==252000) m_fftBinWidth=1500.0/32768.0;
|
||||
DrawOverlay(); //Redraw scales and ticks
|
||||
update(); //trigger a new paintEvent}
|
||||
}
|
||||
|
||||
void CPlotter::setTxFreq(int n) //setTxFreq
|
||||
{
|
||||
m_txFreq=n;
|
||||
DrawOverlay();
|
||||
update();
|
||||
}
|
||||
|
||||
void CPlotter::setMode(QString mode) //setMode
|
||||
{
|
||||
m_mode=mode;
|
||||
}
|
||||
|
||||
void CPlotter::setSubMode(int n) //setSubMode
|
||||
{
|
||||
m_nSubMode=n;
|
||||
}
|
||||
|
||||
void CPlotter::setModeTx(QString modeTx) //setModeTx
|
||||
{
|
||||
m_modeTx=modeTx;
|
||||
}
|
||||
|
||||
int CPlotter::Fmax()
|
||||
{
|
||||
return m_fMax;
|
||||
}
|
||||
|
||||
void CPlotter::setDialFreq(double d)
|
||||
{
|
||||
m_dialFreq=d;
|
||||
DrawOverlay();
|
||||
update();
|
||||
}
|
||||
|
||||
void CPlotter::setRxBand(QString band)
|
||||
{
|
||||
m_rxBand=band;
|
||||
}
|
||||
|
||||
void CPlotter::setFlatten(bool b1, bool b2)
|
||||
{
|
||||
m_Flatten=0;
|
||||
if(b1) m_Flatten=1;
|
||||
if(b2) m_Flatten=2;
|
||||
}
|
||||
|
||||
void CPlotter::setTol(int n) //setTol()
|
||||
{
|
||||
m_tol=n;
|
||||
DrawOverlay();
|
||||
}
|
||||
|
||||
void CPlotter::setColours(QVector<QColor> const& cl)
|
||||
{
|
||||
g_ColorTbl = cl;
|
||||
}
|
||||
|
||||
void CPlotter::SetPercent2DScreen(int percent)
|
||||
{
|
||||
m_Percent2DScreen=percent;
|
||||
resizeEvent(NULL);
|
||||
update();
|
||||
}
|
||||
void CPlotter::setVHF(bool bVHF)
|
||||
{
|
||||
m_bVHF=bVHF;
|
||||
}
|
||||
|
||||
void CPlotter::setRedFile(QString fRed)
|
||||
{
|
||||
m_redFile=fRed;
|
||||
}
|
||||
|
After Width: | Height: | Size: 16 KiB |
@@ -1,77 +0,0 @@
|
||||
// Status=review
|
||||
|
||||
image::RadioTab.png[align="center",alt="Radio Tab"]
|
||||
|
||||
_WSJT-X_ offers CAT (Computer Aided Transceiver) control of the
|
||||
relevant features of most modern transceivers. To configure the
|
||||
program for your radio, select the *Radio* tab.
|
||||
|
||||
- Select your radio type from the drop-down list labeled *Rig*, or
|
||||
*None* if you do not wish to use CAT control.
|
||||
|
||||
- Alternatively, if you have configured your station for control by
|
||||
*DX Lab Suite Commander*, *Ham Radio Deluxe*, *Hamlib NET rigctl*, or
|
||||
*OmniRig*, you may select one of those program names from the *Rig*
|
||||
list. In these cases the entry field immediately under _CAT Control_
|
||||
will be relabeled as *Network Server*. Leave this field blank to
|
||||
access the default instance of your control program, running on the
|
||||
same computer. If the control program runs on a different computer
|
||||
and/or port, specify it here. Hover the mouse pointer over the entry
|
||||
field to see the required formatting details.
|
||||
|
||||
- Select *OmniRig Rig 1* or *OmniRig Rig 2* to connect to an _OmniRig_
|
||||
server running on the same computer. Note that _OmniRig_ is available
|
||||
only under Windows.
|
||||
|
||||
- Set *Poll Interval* to the desired interval for _WSJT-X_ to query
|
||||
your radio. For most radios a small number (say, 1 – 3 s) is
|
||||
suitable.
|
||||
|
||||
- _CAT Control_: To have _WSJT-X_ control the radio directly rather
|
||||
than though another program, make the following settings:
|
||||
|
||||
* Select the *Serial Port* used to communicate with your radio.
|
||||
|
||||
* _Serial Port Parameters_: Set values for *Baud Rate*, *Data Bits*,
|
||||
*Stop Bits*, and *Handshake* method. Consult your radio's user guide
|
||||
for the proper parameter values.
|
||||
|
||||
* _Force Control Lines_: A few station setups require the CAT serial
|
||||
port’s *RTS* and/or *DTR* control lines to be forced high or
|
||||
low. Check these boxes only if you are sure they are needed (for
|
||||
example, to power the radio serial interface).
|
||||
|
||||
- _PTT Method_: select *VOX*, *CAT*, *DTR*, or *RTS* as the desired
|
||||
method for T/R switching. If your choice is *DTR* or *RTS*, select
|
||||
the desired serial port (which may be the same one as used for
|
||||
CAT control).
|
||||
|
||||
- _Transmit Audio Source_: some radios permit you to choose the
|
||||
connector that will accept Tx audio. If this choice is enabled,
|
||||
select *Rear/Data* or *Front/Mic*.
|
||||
|
||||
- _Mode_: _WSJT-X_ uses upper sideband mode for both transmitting and
|
||||
receiving. Select *USB*, or choose *Data/Pkt* if your radio offers
|
||||
such an option and uses it to enable the rear-panel audio line input.
|
||||
Some radios also offer wider and/or flatter passbands when set to
|
||||
*Data/Pkt* mode. Select *None* if you do not want _WSJT-X_ to change
|
||||
the radio's Mode setting.
|
||||
|
||||
- _Split Operation_: Significant advantages result from using *Split*
|
||||
mode (separate VFOs for Rx and Tx) if your radio supports it. If it
|
||||
does not, _WSJT-X_ can emulate such behavior. Either method will
|
||||
result in a cleaner transmitted signal, by keeping the Tx audio always
|
||||
in the range 1500 to 2000 Hz so that audio harmonics cannot pass
|
||||
through the Tx sideband filter. Select *Rig* to use the radio's Split
|
||||
mode, or *Fake It* to have _WSJT-X_ adjust the VFO frequency as
|
||||
needed, when T/R switching occurs. Choose *None* if you do not
|
||||
wish to use split operation.
|
||||
|
||||
When all required settings have been made, click *Test CAT* to test
|
||||
communication between _WSJT-X_ and your radio. The button should turn
|
||||
green to indicate that proper communication has been established.
|
||||
Failure of the CAT-control test turns the button red and displays an
|
||||
error message. After a successful CAT test, toggle the *Test PTT*
|
||||
button to confirm that your selected method of T/R control is working
|
||||
properly. (If you selected *VOX* for _PTT Method_, you can test T/R
|
||||
switching later by using the *Tune* button on the main window.)
|
||||
@@ -5,9 +5,9 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">Waterfall:</td>
|
||||
<td><b>Click</b> to set the Rx frequency.<br/>
|
||||
<td><b>Click</b> to set Rx frequency.<br/>
|
||||
<b>Shift-click</b> to set Tx frequency.<br/>
|
||||
<b>Ctrl-click</b> to set Rx and Tx frequencies.<br/>
|
||||
<b>Ctrl-click</b> or <b>Right-click</b> to set Rx and Tx frequencies.<br/>
|
||||
<b>Double-click</b> to also decode at Rx frequency.<br/>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -1,33 +0,0 @@
|
||||
<table cellspacing=1>
|
||||
<tr><td><b>F1 </b></td><td>Online User's Guide</td></tr>
|
||||
<tr><td><b>Ctrl+F1 </b></td><td>About WSJT-X</td></tr>
|
||||
<tr><td><b>F2 </b></td><td>Open configuration window</td></tr>
|
||||
<tr><td><b>F3 </b></td><td>Display keyboard shortcuts</td></tr>
|
||||
<tr><td><b>F4 </b></td><td>Clear DX Call, DX Grid, Tx messages 1-5</td></tr>
|
||||
<tr><td><b>Alt+F4 </b></td><td>Exit program</td></tr>
|
||||
<tr><td><b>F5 </b></td><td>Display special mouse commands</td></tr>
|
||||
<tr><td><b>F6 </b></td><td>Open next file in directory</td></tr>
|
||||
<tr><td><b>F7 </b></td><td>Display Message Averaging window</td></tr>
|
||||
<tr><td><b>Shift+F6 </b></td><td>Decode all remaining files in directrory</td></tr>
|
||||
<tr><td><b>F11 </b></td><td>Move Rx frequency down 1 Hz</td></tr>
|
||||
<tr><td><b>Ctrl+F11 </b></td><td>Move Rx and Tx frequencies down 1 Hz</td></tr>
|
||||
<tr><td><b>F12 </b></td><td>Move Rx frequency up 1 Hz</td></tr>
|
||||
<tr><td><b>Ctrl+F12 </b></td><td>Move Rx and Tx frequencies up 1 Hz</td></tr>
|
||||
<tr><td><b>Alt+1-6 </b></td><td>Set now transmission to this number on Tab 1</td></tr>
|
||||
<tr><td><b>Ctl+1-6 </b></td><td>Set next transmission to this number on Tab 1</td></tr>
|
||||
<tr><td><b>Alt+D </b></td><td>Decode again at QSO frequency</td></tr>
|
||||
<tr><td><b>Shift+D </b></td><td>Full decode (both windows)</td></tr>
|
||||
<tr><td><b>Alt+E </b></td><td>Erase</td></tr>
|
||||
<tr><td><b>Ctrl+F </b></td><td>Edit the free text message box</td></tr>
|
||||
<tr><td><b>Alt+G </b></td><td>Generate standard messages</td></tr>
|
||||
<tr><td><b>Alt+H </b></td><td>Halt Tx</td></tr>
|
||||
<tr><td><b>Ctrl+L </b></td><td>Lookup callsign in database, generate standard messages</td></tr>
|
||||
<tr><td><b>Alt+M </b></td><td>Monitor</td></tr>
|
||||
<tr><td><b>Ctrl+M </b></td><td>Minimize window size by hiding some controls</td></tr>
|
||||
<tr><td><b>Alt+N </b></td><td>Enable Tx</td></tr>
|
||||
<tr><td><b>Ctrl+O </b></td><td>Open a .wav file</td></tr>
|
||||
<tr><td><b>Alt+Q </b></td><td>Log QSO</td></tr>
|
||||
<tr><td><b>Alt+S </b></td><td>Stop monitoring</td></tr>
|
||||
<tr><td><b>Alt+T </b></td><td>Tune</td></tr>
|
||||
<tr><td><b>Alt+V </b></td><td>Save the most recently completed *.wav file</td></tr>
|
||||
</table>
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef BOOST_THREAD_THREAD_HPP
|
||||
#define BOOST_THREAD_THREAD_HPP
|
||||
|
||||
// thread.hpp
|
||||
//
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/detail/thread_group.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,124 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# These tests investigate what happens when the wrong model is used for
|
||||
# decoding. A (1800,1000) LDPC code with 3 check per bit is used.
|
||||
# Testing is done by transmitting random messages. Decoding is done using
|
||||
# a maximum of 100 iterations of probability propagation.
|
||||
#
|
||||
# The first set of tests compares decoding of messages sent through an
|
||||
# AWGN channel using the correct AWGN model with sigma=0.90 to decoding
|
||||
# using AWGN models with incorrect values for sigma and to decoding
|
||||
# using AWLN models with varying width parameters for the logistic noise
|
||||
# distribution.
|
||||
#
|
||||
# A second set of tests compares decoding of messages sent through an
|
||||
# AWLN channel using the correct AWLN model with width=0.50 to decoding
|
||||
# using AWLN models with incorrect values for width and to decoding
|
||||
# using AWGN models with varying sigma parameters.
|
||||
|
||||
set -e # Stop if an error occurs
|
||||
set -v # Echo commands as they are read
|
||||
|
||||
make-ldpc ex-wrong-model.pchk 1000 1800 1 evenboth 3 no4cycle
|
||||
make-gen ex-wrong-model.pchk ex-wrong-model.gen dense
|
||||
rand-src ex-wrong-model.src 1 800x1000
|
||||
encode ex-wrong-model.pchk ex-wrong-model.gen ex-wrong-model.src \
|
||||
ex-wrong-model.enc
|
||||
|
||||
# FIRST SET OF TESTS, TRANSMITTING THROUGH AWGN CHANNEL WITH SIGMA=0.90
|
||||
|
||||
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awgn 0.90
|
||||
|
||||
# DECODING WITH CORRECT AWGN NOISE MODEL, SIGMA=0.90
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.40
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.40 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.50
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.60
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.60 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.65
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.65 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# SECOND SET OF TESTS, TRANSMITTING THROUGH AWLN CHANNEL WITH WIDTH=0.50
|
||||
|
||||
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awln 0.50
|
||||
|
||||
# DECODING WITH CORRECT AWLN NOISE MODEL, WIDTH=0.50
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.80
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.80 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.90
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.00
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.00 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
|
||||
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.05
|
||||
|
||||
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.05 prprp 100 \
|
||||
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
|
||||
@@ -1,41 +0,0 @@
|
||||
image::settings-advanced.png[align="center",alt="Settings Advanced"]
|
||||
|
||||
_JT65 decoding parameters_
|
||||
|
||||
- *Random erasure patterns* logarithmically scales the number of
|
||||
pseudo-random trials used by the Franke-Taylor JT65 decoder. Larger
|
||||
numbers give slightly better sensitivity but take longer. For most
|
||||
purposes a good setting is 6 or 7.
|
||||
|
||||
- *Aggressive decoding level* sets the threshold for acceptable
|
||||
decodes using Deep Search. Higher numbers will display results
|
||||
with lower confidence levels.
|
||||
|
||||
- Check *MSK144 Contest Mode* to cause generation and auto-sequencing
|
||||
of MSK144 messages with four-character grid locators in place of signal
|
||||
reports.
|
||||
|
||||
- Check *Two-pass decoding* to enable a second decoding pass after
|
||||
signals producing first-pass decodes have been subtracted from the
|
||||
received data stream.
|
||||
|
||||
_Miscellaneous_
|
||||
|
||||
- Set a positive number in *Degrade S/N of .wav file* to add known
|
||||
amounts of pseudo-random noise to data read from a .wav file. To
|
||||
ensure that the resulting S/N degradation is close to the requested
|
||||
number of dB, set *Receiver bandwidth* to your best estimate of the
|
||||
receiver's effective noise bandwidth.
|
||||
|
||||
- Set *Tx delay* to a number larger than the default 0.2 s to create
|
||||
a larger delay between execution of a command to enable PTT and onset
|
||||
of Tx audio.
|
||||
|
||||
IMPORTANT: For the health of your T/R relays and external
|
||||
preamplifier, we strongly recommend using a hardware sequencer and
|
||||
testing to make sure that sequencing is correct.
|
||||
|
||||
- Check *x 2 Tone spacing* to generate Tx audio with twice the normal
|
||||
tone spacing. This feature is intended for use with specialized LF/MF
|
||||
transmitters that divide the audio waveform by 2 before further
|
||||
processing.
|
||||
@@ -139,15 +139,9 @@ elseif(ndeep.eq.5) then
|
||||
endif
|
||||
|
||||
do iorder=1,nord
|
||||
if( iorder.eq. 1 ) then
|
||||
misub(1:K-1)=0
|
||||
misub(K)=1
|
||||
iflag=K
|
||||
elseif( iorder.eq. 2 ) then
|
||||
misub(1:K-2)=0
|
||||
misub(K-1:K)=1
|
||||
iflag=K-1
|
||||
endif
|
||||
misub(1:K-iorder)=0
|
||||
misub(K-iorder+1:K)=1
|
||||
iflag=K-iorder+1
|
||||
do while(iflag .ge.0)
|
||||
if(iorder.eq.nord .and. npre1.eq.0) then
|
||||
iend=iflag
|
||||
@@ -209,15 +203,9 @@ if(npre2.eq.1) then
|
||||
ntotal2=0
|
||||
reset=.true.
|
||||
! Now run through again and do the second pre-processing rule
|
||||
if(nord.eq.1) then
|
||||
misub(1:K-1)=0
|
||||
misub(K)=1
|
||||
iflag=K
|
||||
elseif(nord.eq.2) then
|
||||
misub(1:K-1)=0
|
||||
misub(K-1:K)=1
|
||||
iflag=K-1
|
||||
endif
|
||||
misub(1:K-nord)=0
|
||||
misub(K-nord+1:K)=1
|
||||
iflag=K-nord+1
|
||||
do while(iflag .ge.0)
|
||||
me=ieor(m0,misub)
|
||||
call mrbencode(me,ce,g2,N,K)
|
||||
@@ -255,7 +243,7 @@ endif
|
||||
! Re-order the codeword to place message bits at the end.
|
||||
cw(indices)=cw
|
||||
hdec(indices)=hdec
|
||||
decoded=cw(K+1:N)
|
||||
decoded=cw(M+1:N)
|
||||
cw(colorder+1)=cw ! put the codeword back into received-word order
|
||||
return
|
||||
end subroutine osd174
|
||||
@@ -1,10 +1,12 @@
|
||||
subroutine decode65b(s2,nflip,nadd,mode65,ntrials,naggressive,ndepth, &
|
||||
mycall,hiscall,hisgrid,nexp_decode,nqd,nft,qual,nhist,decoded)
|
||||
mycall,hiscall,hisgrid,nQSOProgress,ljt65apon,nexp_decode,nqd, &
|
||||
nft,qual, &
|
||||
nhist,decoded)
|
||||
|
||||
use jt65_mod
|
||||
real s2(66,126)
|
||||
real s3(64,63)
|
||||
logical ltext
|
||||
logical ltext,ljt65apon
|
||||
character decoded*22
|
||||
character mycall*12,hiscall*12,hisgrid*6
|
||||
save
|
||||
@@ -19,7 +21,8 @@ subroutine decode65b(s2,nflip,nadd,mode65,ntrials,naggressive,ndepth, &
|
||||
enddo
|
||||
|
||||
call extract(s3,nadd,mode65,ntrials,naggressive,ndepth,nflip,mycall, &
|
||||
hiscall,hisgrid,nexp_decode,ncount,nhist,decoded,ltext,nft,qual)
|
||||
hiscall,hisgrid,nQSOProgress,ljt65apon,nexp_decode,ncount, &
|
||||
nhist,decoded,ltext,nft,qual)
|
||||
|
||||
! Suppress "birdie messages" and other garbage decodes:
|
||||
if(decoded(1:7).eq.'000AAA ') ncount=-1
|
||||
@@ -1,415 +0,0 @@
|
||||
/* MAKE-LDPC.C - Make a Low Density Parity Check code's parity check matrix. */
|
||||
|
||||
/* Copyright (c) 1995-2012 by Radford M. Neal and Peter Junteng Liu.
|
||||
*
|
||||
* Permission is granted for anyone to copy, use, modify, and distribute
|
||||
* these programs and accompanying documents for any purpose, provided
|
||||
* this copyright notice is retained and prominently displayed, and note
|
||||
* is made of any changes made to these programs. These programs and
|
||||
* documents are distributed without any warranty, express or implied.
|
||||
* As the programs were written for research purposes only, they have not
|
||||
* been tested to the degree that would be advisable in any important
|
||||
* application. All use of these programs is entirely at the user's own
|
||||
* risk.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "rand.h"
|
||||
#include "alloc.h"
|
||||
#include "intio.h"
|
||||
#include "open.h"
|
||||
#include "mod2sparse.h"
|
||||
#include "mod2dense.h"
|
||||
#include "mod2convert.h"
|
||||
#include "rcode.h"
|
||||
#include "distrib.h"
|
||||
|
||||
|
||||
/* METHODS FOR CONSTRUCTING CODES. */
|
||||
|
||||
typedef enum
|
||||
{ Evencol, /* Uniform number of bits per column, with number specified */
|
||||
Evenboth /* Uniform (as possible) over both columns and rows */
|
||||
} make_method;
|
||||
|
||||
|
||||
void make_ldpc (int, make_method, distrib *, int);
|
||||
int *column_partition (distrib *, int);
|
||||
void usage (void);
|
||||
|
||||
|
||||
/* MAIN PROGRAM. */
|
||||
|
||||
int main
|
||||
( int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
make_method method;
|
||||
char *file, **meth;
|
||||
int seed, no4cycle;
|
||||
distrib *d;
|
||||
char junk;
|
||||
FILE *f;
|
||||
|
||||
/* Look at initial arguments. */
|
||||
|
||||
if (!(file = argv[1])
|
||||
|| !argv[2] || sscanf(argv[2],"%d%c",&M,&junk)!=1 || M<=0
|
||||
|| !argv[3] || sscanf(argv[3],"%d%c",&N,&junk)!=1 || N<=0
|
||||
|| !argv[4] || sscanf(argv[4],"%d%c",&seed,&junk)!=1)
|
||||
{ usage();
|
||||
}
|
||||
|
||||
/* Look at the arguments specifying the method for producing the code. */
|
||||
|
||||
meth = argv+5;
|
||||
|
||||
if (!meth[0]) usage();
|
||||
|
||||
no4cycle = 0;
|
||||
|
||||
if (strcmp(meth[0],"evencol")==0 || strcmp(meth[0],"evenboth")==0)
|
||||
{ method = strcmp(meth[0],"evencol")==0 ? Evencol : Evenboth;
|
||||
if (!meth[1])
|
||||
{ usage();
|
||||
}
|
||||
d = distrib_create(meth[1]);
|
||||
if (d==0)
|
||||
{ usage();
|
||||
}
|
||||
if (meth[2])
|
||||
{ if (strcmp(meth[2],"no4cycle")==0)
|
||||
{ no4cycle = 1;
|
||||
if (meth[3])
|
||||
{ usage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{ usage();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ usage();
|
||||
}
|
||||
|
||||
/* Check for some problems. */
|
||||
|
||||
if (distrib_max(d)>M)
|
||||
{ fprintf(stderr,
|
||||
"At least one checks per bit (%d) is greater than total checks (%d)\n",
|
||||
distrib_max(d), M);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (distrib_max(d)==M && N>1 && no4cycle)
|
||||
{ fprintf(stderr,
|
||||
"Can't eliminate cycles of length four with this many checks per bit\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Make the parity check matrix. */
|
||||
|
||||
make_ldpc(seed,method,d,no4cycle);
|
||||
|
||||
/* Write out the parity check matrix. */
|
||||
|
||||
f = open_file_std(file,"wb");
|
||||
if (f==NULL)
|
||||
{ fprintf(stderr,"Can't create parity check file: %s\n",file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
intio_write(f,('P'<<8)+0x80);
|
||||
|
||||
if (ferror(f) || !mod2sparse_write(f,H) || fclose(f)!=0)
|
||||
{ fprintf(stderr,"Error writing to parity check file %s\n",file);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* PRINT USAGE MESSAGE AND EXIT. */
|
||||
|
||||
void usage(void)
|
||||
{ fprintf(stderr,"Usage: make-ldpc pchk-file n-checks n-bits seed method\n");
|
||||
fprintf(stderr,"Method: evencol checks-per-col [ \"no4cycle\" ]\n");
|
||||
fprintf(stderr," or: evencol checks-distribution [ \"no4cycle\" ]\n");
|
||||
fprintf(stderr," or: evenboth checks-per-col [ \"no4cycle\" ]\n");
|
||||
fprintf(stderr," or: evenboth checks-distribution [ \"no4cycle\" ]\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
/* CREATE A SPARSE PARITY-CHECK MATRIX. Of size M by N, stored in H. */
|
||||
|
||||
void make_ldpc
|
||||
( int seed, /* Random number seed */
|
||||
make_method method, /* How to make it */
|
||||
distrib *d, /* Distribution list specified */
|
||||
int no4cycle /* Eliminate cycles of length four? */
|
||||
)
|
||||
{
|
||||
mod2entry *e, *f, *g, *h;
|
||||
int added, uneven, elim4, all_even, n_full, left;
|
||||
int i, j, k, t, z, cb_N;
|
||||
int *part, *u;
|
||||
|
||||
rand_seed(10*seed+1);
|
||||
|
||||
H = mod2sparse_allocate(M,N);
|
||||
part = column_partition(d,N);
|
||||
|
||||
/* Create the initial version of the parity check matrix. */
|
||||
|
||||
switch (method)
|
||||
{
|
||||
case Evencol:
|
||||
{
|
||||
z = 0;
|
||||
left = part[z];
|
||||
|
||||
for (j = 0; j<N; j++)
|
||||
{ while (left==0)
|
||||
{ z += 1;
|
||||
if (z>distrib_size(d))
|
||||
{ abort();
|
||||
}
|
||||
left = part[z];
|
||||
}
|
||||
for (k = 0; k<distrib_num(d,z); k++)
|
||||
{ do
|
||||
{ i = rand_int(M);
|
||||
} while (mod2sparse_find(H,i,j));
|
||||
mod2sparse_insert(H,i,j);
|
||||
}
|
||||
left -= 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Evenboth:
|
||||
{
|
||||
cb_N = 0;
|
||||
for (z = 0; z<distrib_size(d); z++)
|
||||
{ cb_N += distrib_num(d,z) * part[z];
|
||||
}
|
||||
|
||||
u = chk_alloc (cb_N, sizeof *u);
|
||||
|
||||
for (k = cb_N-1; k>=0; k--)
|
||||
{ u[k] = k%M;
|
||||
}
|
||||
|
||||
uneven = 0;
|
||||
t = 0;
|
||||
z = 0;
|
||||
left = part[z];
|
||||
|
||||
for (j = 0; j<N; j++)
|
||||
{
|
||||
while (left==0)
|
||||
{ z += 1;
|
||||
if (z>distrib_size(d))
|
||||
{ abort();
|
||||
}
|
||||
left = part[z];
|
||||
}
|
||||
|
||||
for (k = 0; k<distrib_num(d,z); k++)
|
||||
{
|
||||
for (i = t; i<cb_N && mod2sparse_find(H,u[i],j); i++) ;
|
||||
|
||||
if (i==cb_N)
|
||||
{ uneven += 1;
|
||||
do
|
||||
{ i = rand_int(M);
|
||||
} while (mod2sparse_find(H,i,j));
|
||||
mod2sparse_insert(H,i,j);
|
||||
}
|
||||
else
|
||||
{ do
|
||||
{ i = t + rand_int(cb_N-t);
|
||||
} while (mod2sparse_find(H,u[i],j));
|
||||
mod2sparse_insert(H,u[i],j);
|
||||
u[i] = u[t];
|
||||
t += 1;
|
||||
}
|
||||
}
|
||||
|
||||
left -= 1;
|
||||
}
|
||||
|
||||
if (uneven>0)
|
||||
{ fprintf(stderr,"Had to place %d checks in rows unevenly\n",uneven);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: abort();
|
||||
}
|
||||
|
||||
/* Add extra bits to avoid rows with less than two checks. */
|
||||
|
||||
added = 0;
|
||||
|
||||
for (i = 0; i<M; i++)
|
||||
{ e = mod2sparse_first_in_row(H,i);
|
||||
if (mod2sparse_at_end(e))
|
||||
{ j = rand_int(N);
|
||||
e = mod2sparse_insert(H,i,j);
|
||||
added += 1;
|
||||
}
|
||||
e = mod2sparse_first_in_row(H,i);
|
||||
if (mod2sparse_at_end(mod2sparse_next_in_row(e)) && N>1)
|
||||
{ do
|
||||
{ j = rand_int(N);
|
||||
} while (j==mod2sparse_col(e));
|
||||
mod2sparse_insert(H,i,j);
|
||||
added += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (added>0)
|
||||
{ fprintf(stderr,
|
||||
"Added %d extra bit-checks to make row counts at least two\n",
|
||||
added);
|
||||
}
|
||||
|
||||
/* Add extra bits to try to avoid problems with even column counts. */
|
||||
|
||||
n_full = 0;
|
||||
all_even = 1;
|
||||
for (z = 0; z<distrib_size(d); z++)
|
||||
{ if (distrib_num(d,z)==M)
|
||||
{ n_full += part[z];
|
||||
}
|
||||
if (distrib_num(d,z)%2==1)
|
||||
{ all_even = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_even && N-n_full>1 && added<2)
|
||||
{ int a;
|
||||
for (a = 0; added+a<2; a++)
|
||||
{ do
|
||||
{ i = rand_int(M);
|
||||
j = rand_int(N);
|
||||
} while (mod2sparse_find(H,i,j));
|
||||
mod2sparse_insert(H,i,j);
|
||||
}
|
||||
fprintf(stderr,
|
||||
"Added %d extra bit-checks to try to avoid problems from even column counts\n",
|
||||
a);
|
||||
}
|
||||
|
||||
/* Eliminate cycles of length four, if asked, and if possible. */
|
||||
|
||||
if (no4cycle)
|
||||
{
|
||||
elim4 = 0;
|
||||
|
||||
for (t = 0; t<10; t++)
|
||||
{ k = 0;
|
||||
for (j = 0; j<N; j++)
|
||||
{ for (e = mod2sparse_first_in_col(H,j);
|
||||
!mod2sparse_at_end(e);
|
||||
e = mod2sparse_next_in_col(e))
|
||||
{ for (f = mod2sparse_first_in_row(H,mod2sparse_row(e));
|
||||
!mod2sparse_at_end(f);
|
||||
f = mod2sparse_next_in_row(f))
|
||||
{ if (f==e) continue;
|
||||
for (g = mod2sparse_first_in_col(H,mod2sparse_col(f));
|
||||
!mod2sparse_at_end(g);
|
||||
g = mod2sparse_next_in_col(g))
|
||||
{ if (g==f) continue;
|
||||
for (h = mod2sparse_first_in_row(H,mod2sparse_row(g));
|
||||
!mod2sparse_at_end(h);
|
||||
h = mod2sparse_next_in_row(h))
|
||||
{ if (mod2sparse_col(h)==j)
|
||||
{ do
|
||||
{ i = rand_int(M);
|
||||
} while (mod2sparse_find(H,i,j));
|
||||
mod2sparse_delete(H,e);
|
||||
mod2sparse_insert(H,i,j);
|
||||
elim4 += 1;
|
||||
k += 1;
|
||||
goto nextj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nextj: ;
|
||||
}
|
||||
if (k==0) break;
|
||||
}
|
||||
|
||||
if (elim4>0)
|
||||
{ fprintf(stderr,
|
||||
"Eliminated %d cycles of length four by moving checks within column\n",
|
||||
elim4);
|
||||
}
|
||||
|
||||
if (t==10)
|
||||
{ fprintf(stderr,
|
||||
"Couldn't eliminate all cycles of length four in 10 passes\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* PARTITION THE COLUMNS ACCORDING TO THE SPECIFIED PROPORTIONS. It
|
||||
may not be possible to do this exactly. Returns a pointer to an
|
||||
array of integers containing the numbers of columns corresponding
|
||||
to the entries in the distribution passed. */
|
||||
|
||||
int *column_partition
|
||||
( distrib *d, /* List of proportions and number of check-bits */
|
||||
int n /* Total number of columns to partition */
|
||||
)
|
||||
{
|
||||
double *trunc;
|
||||
int *part;
|
||||
int cur, used;
|
||||
int i, j;
|
||||
|
||||
trunc = chk_alloc (distrib_size(d), sizeof(double));
|
||||
part = chk_alloc (distrib_size(d), sizeof(int));
|
||||
|
||||
used = 0;
|
||||
for (i = 0; i<distrib_size(d); i++)
|
||||
{ cur = floor(distrib_prop(d,i)*n);
|
||||
part[i] = cur;
|
||||
trunc[i] = distrib_prop(d,i)*n - cur;
|
||||
used += cur;
|
||||
}
|
||||
|
||||
if (used>n)
|
||||
{ abort();
|
||||
}
|
||||
|
||||
while (used<n)
|
||||
{ cur = 0;
|
||||
for (j = 1; j<distrib_size(d); j++)
|
||||
{ if (trunc[j]>trunc[cur])
|
||||
{ cur = j;
|
||||
}
|
||||
}
|
||||
part[cur] += 1;
|
||||
used += 1;
|
||||
trunc[cur] = -1;
|
||||
}
|
||||
|
||||
free(trunc);
|
||||
return part;
|
||||
}
|
||||
@@ -1,269 +0,0 @@
|
||||
#include "ClientWidget.hpp"
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QColor>
|
||||
|
||||
namespace
|
||||
{
|
||||
//QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"};
|
||||
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"};
|
||||
QRegularExpression cq_re {"(CQ|CQDX|QRZ)[^A-Z0-9/]+"};
|
||||
|
||||
void update_dynamic_property (QWidget * widget, char const * property, QVariant const& value)
|
||||
{
|
||||
widget->setProperty (property, value);
|
||||
widget->style ()->unpolish (widget);
|
||||
widget->style ()->polish (widget);
|
||||
widget->update ();
|
||||
}
|
||||
}
|
||||
|
||||
ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id)
|
||||
: client_id_ {client_id}
|
||||
, rx_df_ (-1)
|
||||
{
|
||||
}
|
||||
|
||||
QVariant ClientWidget::IdFilterModel::data (QModelIndex const& proxy_index, int role) const
|
||||
{
|
||||
if (role == Qt::BackgroundRole)
|
||||
{
|
||||
switch (proxy_index.column ())
|
||||
{
|
||||
case 6: // message
|
||||
{
|
||||
auto message = QSortFilterProxyModel::data (proxy_index).toString ();
|
||||
if (base_call_re_.pattern ().size ()
|
||||
&& message.contains (base_call_re_))
|
||||
{
|
||||
return QColor {255,200,200};
|
||||
}
|
||||
if (message.contains (cq_re))
|
||||
{
|
||||
return QColor {200, 255, 200};
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 4: // DF
|
||||
if (qAbs (QSortFilterProxyModel::data (proxy_index).toInt () - rx_df_) <= 10)
|
||||
{
|
||||
return QColor {255, 200, 200};
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QSortFilterProxyModel::data (proxy_index, role);
|
||||
}
|
||||
|
||||
bool ClientWidget::IdFilterModel::filterAcceptsRow (int source_row
|
||||
, QModelIndex const& source_parent) const
|
||||
{
|
||||
auto source_index_col0 = sourceModel ()->index (source_row, 0, source_parent);
|
||||
return sourceModel ()->data (source_index_col0).toString () == client_id_;
|
||||
}
|
||||
|
||||
void ClientWidget::IdFilterModel::de_call (QString const& call)
|
||||
{
|
||||
if (call != call_)
|
||||
{
|
||||
beginResetModel ();
|
||||
if (call.size ())
|
||||
{
|
||||
base_call_re_.setPattern ("[^A-Z0-9]*" + Radio::base_callsign (call) + "[^A-Z0-9]*");
|
||||
}
|
||||
else
|
||||
{
|
||||
base_call_re_.setPattern (QString {});
|
||||
}
|
||||
call_ = call;
|
||||
endResetModel ();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientWidget::IdFilterModel::rx_df (int df)
|
||||
{
|
||||
if (df != rx_df_)
|
||||
{
|
||||
beginResetModel ();
|
||||
rx_df_ = df;
|
||||
endResetModel ();
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
QString make_title (QString const& id, QString const& version, QString const& revision)
|
||||
{
|
||||
QString title {id};
|
||||
if (version.size ())
|
||||
{
|
||||
title += QString {" v%1"}.arg (version);
|
||||
}
|
||||
if (revision.size ())
|
||||
{
|
||||
title += QString {" (%1)"}.arg (revision);
|
||||
}
|
||||
return title;
|
||||
}
|
||||
}
|
||||
|
||||
ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
|
||||
, QString const& id, QString const& version, QString const& revision
|
||||
, QWidget * parent)
|
||||
: QDockWidget {make_title (id, version, revision), parent}
|
||||
, id_ {id}
|
||||
, decodes_proxy_model_ {id_}
|
||||
, decodes_table_view_ {new QTableView}
|
||||
, beacons_table_view_ {new QTableView}
|
||||
, message_line_edit_ {new QLineEdit}
|
||||
, decodes_stack_ {new QStackedLayout}
|
||||
, auto_off_button_ {new QPushButton {tr ("&Auto Off")}}
|
||||
, halt_tx_button_ {new QPushButton {tr ("&Halt Tx")}}
|
||||
, mode_label_ {new QLabel}
|
||||
, fast_mode_ {false}
|
||||
, frequency_label_ {new QLabel}
|
||||
, dx_label_ {new QLabel}
|
||||
, rx_df_label_ {new QLabel}
|
||||
, tx_df_label_ {new QLabel}
|
||||
, report_label_ {new QLabel}
|
||||
{
|
||||
// set up widgets
|
||||
decodes_proxy_model_.setSourceModel (decodes_model);
|
||||
decodes_table_view_->setModel (&decodes_proxy_model_);
|
||||
decodes_table_view_->verticalHeader ()->hide ();
|
||||
decodes_table_view_->hideColumn (0);
|
||||
decodes_table_view_->horizontalHeader ()->setStretchLastSection (true);
|
||||
|
||||
auto form_layout = new QFormLayout;
|
||||
form_layout->addRow (tr ("Free text:"), message_line_edit_);
|
||||
message_line_edit_->setValidator (new QRegExpValidator {message_alphabet, this});
|
||||
connect (message_line_edit_, &QLineEdit::textEdited, [this] (QString const& text) {
|
||||
Q_EMIT do_free_text (id_, text, false);
|
||||
});
|
||||
connect (message_line_edit_, &QLineEdit::editingFinished, [this] () {
|
||||
Q_EMIT do_free_text (id_, message_line_edit_->text (), true);
|
||||
});
|
||||
|
||||
auto decodes_page = new QWidget;
|
||||
auto decodes_layout = new QVBoxLayout {decodes_page};
|
||||
decodes_layout->setContentsMargins (QMargins {2, 2, 2, 2});
|
||||
decodes_layout->addWidget (decodes_table_view_);
|
||||
decodes_layout->addLayout (form_layout);
|
||||
|
||||
auto beacons_proxy_model = new IdFilterModel {id_};
|
||||
beacons_proxy_model->setSourceModel (beacons_model);
|
||||
beacons_table_view_->setModel (beacons_proxy_model);
|
||||
beacons_table_view_->verticalHeader ()->hide ();
|
||||
beacons_table_view_->hideColumn (0);
|
||||
beacons_table_view_->horizontalHeader ()->setStretchLastSection (true);
|
||||
|
||||
auto beacons_page = new QWidget;
|
||||
auto beacons_layout = new QVBoxLayout {beacons_page};
|
||||
beacons_layout->setContentsMargins (QMargins {2, 2, 2, 2});
|
||||
beacons_layout->addWidget (beacons_table_view_);
|
||||
|
||||
decodes_stack_->addWidget (decodes_page);
|
||||
decodes_stack_->addWidget (beacons_page);
|
||||
|
||||
// stack alternative views
|
||||
auto content_layout = new QVBoxLayout;
|
||||
content_layout->setContentsMargins (QMargins {2, 2, 2, 2});
|
||||
content_layout->addLayout (decodes_stack_);
|
||||
|
||||
// set up controls
|
||||
auto control_button_box = new QDialogButtonBox;
|
||||
control_button_box->addButton (auto_off_button_, QDialogButtonBox::ActionRole);
|
||||
control_button_box->addButton (halt_tx_button_, QDialogButtonBox::ActionRole);
|
||||
connect (auto_off_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
||||
Q_EMIT do_halt_tx (id_, true);
|
||||
});
|
||||
connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
|
||||
Q_EMIT do_halt_tx (id_, false);
|
||||
});
|
||||
content_layout->addWidget (control_button_box);
|
||||
|
||||
// set up status area
|
||||
auto status_bar = new QStatusBar;
|
||||
status_bar->addPermanentWidget (mode_label_);
|
||||
status_bar->addPermanentWidget (frequency_label_);
|
||||
status_bar->addPermanentWidget (dx_label_);
|
||||
status_bar->addPermanentWidget (rx_df_label_);
|
||||
status_bar->addPermanentWidget (tx_df_label_);
|
||||
status_bar->addPermanentWidget (report_label_);
|
||||
content_layout->addWidget (status_bar);
|
||||
connect (this, &ClientWidget::topLevelChanged, status_bar, &QStatusBar::setSizeGripEnabled);
|
||||
|
||||
// set up central widget
|
||||
auto content_widget = new QFrame;
|
||||
content_widget->setFrameStyle (QFrame::StyledPanel | QFrame::Sunken);
|
||||
content_widget->setLayout (content_layout);
|
||||
setWidget (content_widget);
|
||||
// setMinimumSize (QSize {550, 0});
|
||||
setFeatures (DockWidgetMovable | DockWidgetFloatable);
|
||||
setAllowedAreas (Qt::BottomDockWidgetArea);
|
||||
|
||||
// connect up table view signals
|
||||
connect (decodes_table_view_, &QTableView::doubleClicked, this, [this] (QModelIndex const& index) {
|
||||
Q_EMIT do_reply (decodes_proxy_model_.mapToSource (index));
|
||||
});
|
||||
}
|
||||
|
||||
void ClientWidget::update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
|
||||
, QString const& report, QString const& tx_mode, bool tx_enabled
|
||||
, bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df
|
||||
, QString const& de_call, QString const& /*de_grid*/, QString const& dx_grid
|
||||
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode)
|
||||
{
|
||||
if (id == id_)
|
||||
{
|
||||
fast_mode_ = fast_mode;
|
||||
decodes_proxy_model_.de_call (de_call);
|
||||
decodes_proxy_model_.rx_df (rx_df);
|
||||
mode_label_->setText (QString {"Mode: %1%2%3%4"}
|
||||
.arg (mode)
|
||||
.arg (sub_mode)
|
||||
.arg (fast_mode && !mode.contains (QRegularExpression {R"(ISCAT|MSK144)"}) ? "fast" : "")
|
||||
.arg (tx_mode.isEmpty () || tx_mode == mode ? "" : '(' + tx_mode + ')'));
|
||||
frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f));
|
||||
dx_label_->setText (dx_call.size () >= 0 ? QString {"DX: %1%2"}.arg (dx_call)
|
||||
.arg (dx_grid.size () ? '(' + dx_grid + ')' : QString {}) : QString {});
|
||||
rx_df_label_->setText (rx_df >= 0 ? QString {"Rx: %1"}.arg (rx_df) : "");
|
||||
tx_df_label_->setText (tx_df >= 0 ? QString {"Tx: %1"}.arg (tx_df) : "");
|
||||
report_label_->setText ("SNR: " + report);
|
||||
update_dynamic_property (frequency_label_, "transmitting", transmitting);
|
||||
auto_off_button_->setEnabled (tx_enabled);
|
||||
halt_tx_button_->setEnabled (transmitting);
|
||||
update_dynamic_property (mode_label_, "decoding", decoding);
|
||||
update_dynamic_property (tx_df_label_, "watchdog_timeout", watchdog_timeout);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
|
||||
, float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/
|
||||
, QString const& /*message*/)
|
||||
{
|
||||
if (client_id == id_)
|
||||
{
|
||||
decodes_stack_->setCurrentIndex (0);
|
||||
decodes_table_view_->resizeColumnsToContents ();
|
||||
decodes_table_view_->scrollToBottom ();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientWidget::beacon_spot_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
|
||||
, float /*delta_time*/, Frequency /*delta_frequency*/, qint32 /*drift*/
|
||||
, QString const& /*callsign*/, QString const& /*grid*/, qint32 /*power*/)
|
||||
{
|
||||
if (client_id == id_)
|
||||
{
|
||||
decodes_stack_->setCurrentIndex (1);
|
||||
beacons_table_view_->resizeColumnsToContents ();
|
||||
beacons_table_view_->scrollToBottom ();
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_ClientWidget.cpp"
|
||||
@@ -1,619 +0,0 @@
|
||||
// -*- Mode: C++ -*-
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
#ifdef QT5
|
||||
#include <QtWidgets>
|
||||
#else
|
||||
#include <QtGui>
|
||||
#endif
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QDateTime>
|
||||
#include <QList>
|
||||
#include <QAudioDeviceInfo>
|
||||
#include <QScopedPointer>
|
||||
#include <QDir>
|
||||
#include <QProgressDialog>
|
||||
#include <QAbstractSocket>
|
||||
#include <QHostAddress>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QVector>
|
||||
#include <QFuture>
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include "AudioDevice.hpp"
|
||||
#include "commons.h"
|
||||
#include "Radio.hpp"
|
||||
#include "Modes.hpp"
|
||||
#include "FrequencyList.hpp"
|
||||
#include "Configuration.hpp"
|
||||
#include "WSPRBandHopping.hpp"
|
||||
#include "Transceiver.hpp"
|
||||
#include "DisplayManual.hpp"
|
||||
#include "psk_reporter.h"
|
||||
#include "logbook/logbook.h"
|
||||
#include "decodedtext.h"
|
||||
#include "commons.h"
|
||||
#include "astro.h"
|
||||
#include "MessageBox.hpp"
|
||||
#include "NetworkAccessManager.hpp"
|
||||
|
||||
#define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync
|
||||
#define NUM_JT65_SYMBOLS 126 //63 data + 63 sync
|
||||
#define NUM_JT9_SYMBOLS 85 //69 data + 16 sync
|
||||
#define NUM_WSPR_SYMBOLS 162 //(50+31)*2, embedded sync
|
||||
#define NUM_WSPR_LF_SYMBOLS 412 //300 data + 109 sync + 3 ramp
|
||||
#define NUM_ISCAT_SYMBOLS 1291 //30*11025/256
|
||||
#define NUM_MSK144_SYMBOLS 144 //s8 + d48 + s8 + d80
|
||||
#define NUM_QRA64_SYMBOLS 84 //63 data + 21 sync
|
||||
#define NUM_FT8_SYMBOLS 79
|
||||
#define NUM_CW_SYMBOLS 250
|
||||
#define TX_SAMPLE_RATE 48000
|
||||
#define N_WIDGETS 24
|
||||
|
||||
extern int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols
|
||||
extern int volatile icw[NUM_CW_SYMBOLS]; //Dits for CW ID
|
||||
|
||||
//--------------------------------------------------------------- MainWindow
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class QSettings;
|
||||
class QLineEdit;
|
||||
class QFont;
|
||||
class QHostInfo;
|
||||
class EchoGraph;
|
||||
class FastGraph;
|
||||
class WideGraph;
|
||||
class LogQSO;
|
||||
class Transceiver;
|
||||
class MessageAveraging;
|
||||
class MessageClient;
|
||||
class QTime;
|
||||
class WSPRBandHopping;
|
||||
class HelpTextWindow;
|
||||
class WSPRNet;
|
||||
class SoundOutput;
|
||||
class Modulator;
|
||||
class SoundInput;
|
||||
class Detector;
|
||||
class SampleDownloader;
|
||||
class MultiSettings;
|
||||
class PhaseEqualizationDialog;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
using Frequency = Radio::Frequency;
|
||||
using FrequencyDelta = Radio::FrequencyDelta;
|
||||
using Mode = Modes::Mode;
|
||||
|
||||
explicit MainWindow(QDir const& temp_directory, bool multiple, MultiSettings *,
|
||||
QSharedMemory *shdmem, unsigned downSampleFactor,
|
||||
QSplashScreen *,
|
||||
QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
public slots:
|
||||
void showSoundInError(const QString& errorMsg);
|
||||
void showSoundOutError(const QString& errorMsg);
|
||||
void showStatusMessage(const QString& statusMsg);
|
||||
void dataSink(qint64 frames);
|
||||
void fastSink(qint64 frames);
|
||||
void diskDat();
|
||||
void freezeDecode(int n);
|
||||
void guiUpdate();
|
||||
void doubleClickOnCall(bool shift, bool ctrl);
|
||||
void doubleClickOnCall2(bool shift, bool ctrl);
|
||||
void readFromStdout();
|
||||
void p1ReadFromStdout();
|
||||
void setXIT(int n, Frequency base = 0u);
|
||||
void setFreq4(int rxFreq, int txFreq);
|
||||
void msgAvgDecode2();
|
||||
void fastPick(int x0, int x1, int y);
|
||||
|
||||
protected:
|
||||
void keyPressEvent (QKeyEvent *) override;
|
||||
void closeEvent(QCloseEvent *) override;
|
||||
void childEvent(QChildEvent *) override;
|
||||
bool eventFilter(QObject *, QEvent *) override;
|
||||
|
||||
private slots:
|
||||
void on_tx1_editingFinished();
|
||||
void on_tx2_editingFinished();
|
||||
void on_tx3_editingFinished();
|
||||
void on_tx4_editingFinished();
|
||||
void on_tx5_currentTextChanged (QString const&);
|
||||
void on_tx6_editingFinished();
|
||||
void on_actionSettings_triggered();
|
||||
void on_monitorButton_clicked (bool);
|
||||
void on_actionAbout_triggered();
|
||||
void on_autoButton_clicked (bool);
|
||||
void on_stopTxButton_clicked();
|
||||
void on_stopButton_clicked();
|
||||
void on_actionRelease_Notes_triggered ();
|
||||
void on_actionOnline_User_Guide_triggered();
|
||||
void on_actionLocal_User_Guide_triggered();
|
||||
void on_actionWide_Waterfall_triggered();
|
||||
void on_actionOpen_triggered();
|
||||
void on_actionOpen_next_in_directory_triggered();
|
||||
void on_actionDecode_remaining_files_in_directory_triggered();
|
||||
void on_actionDelete_all_wav_files_in_SaveDir_triggered();
|
||||
void on_actionOpen_log_directory_triggered ();
|
||||
void on_actionNone_triggered();
|
||||
void on_actionSave_all_triggered();
|
||||
void on_actionKeyboard_shortcuts_triggered();
|
||||
void on_actionSpecial_mouse_commands_triggered();
|
||||
void on_DecodeButton_clicked (bool);
|
||||
void decode();
|
||||
void decodeBusy(bool b);
|
||||
void on_EraseButton_clicked();
|
||||
void on_txb1_clicked();
|
||||
void on_txFirstCheckBox_stateChanged(int arg1);
|
||||
void set_dateTimeQSO(int m_ntx);
|
||||
void set_ntx(int n);
|
||||
void on_txrb1_toggled(bool status);
|
||||
void on_txrb2_toggled(bool status);
|
||||
void on_txrb3_toggled(bool status);
|
||||
void on_txb2_clicked();
|
||||
void on_txb3_clicked();
|
||||
void on_txb4_clicked();
|
||||
void on_txb5_clicked();
|
||||
void on_txb6_clicked();
|
||||
void on_lookupButton_clicked();
|
||||
void on_addButton_clicked();
|
||||
void on_dxCallEntry_textChanged (QString const&);
|
||||
void on_dxGridEntry_textChanged (QString const&);
|
||||
void on_dxCallEntry_returnPressed ();
|
||||
void on_genStdMsgsPushButton_clicked();
|
||||
void on_logQSOButton_clicked();
|
||||
void on_actionJT9_triggered();
|
||||
void on_actionJT65_triggered();
|
||||
void on_actionJT9_JT65_triggered();
|
||||
void on_actionJT4_triggered();
|
||||
void on_actionFT8_triggered();
|
||||
void on_TxFreqSpinBox_valueChanged(int arg1);
|
||||
void on_actionSave_decoded_triggered();
|
||||
void on_actionQuickDecode_toggled (bool);
|
||||
void on_actionMediumDecode_toggled (bool);
|
||||
void on_actionDeepestDecode_toggled (bool);
|
||||
void on_inGain_valueChanged(int n);
|
||||
void bumpFqso(int n);
|
||||
void on_actionErase_ALL_TXT_triggered();
|
||||
void on_actionErase_wsjtx_log_adi_triggered();
|
||||
void startTx2();
|
||||
void startP1();
|
||||
void stopTx();
|
||||
void stopTx2();
|
||||
void on_pbCallCQ_clicked();
|
||||
void on_pbAnswerCaller_clicked();
|
||||
void on_pbSendRRR_clicked();
|
||||
void on_pbAnswerCQ_clicked();
|
||||
void on_pbSendReport_clicked();
|
||||
void on_pbSend73_clicked();
|
||||
void on_rbGenMsg_clicked(bool checked);
|
||||
void on_rbFreeText_clicked(bool checked);
|
||||
void on_freeTextMsg_currentTextChanged (QString const&);
|
||||
void on_rptSpinBox_valueChanged(int n);
|
||||
void killFile();
|
||||
void on_tuneButton_clicked (bool);
|
||||
void on_pbR2T_clicked();
|
||||
void on_pbT2R_clicked();
|
||||
void acceptQSO2(QDateTime const&, QString const& call, QString const& grid
|
||||
, Frequency dial_freq, QString const& mode
|
||||
, QString const& rpt_sent, QString const& rpt_received
|
||||
, QString const& tx_power, QString const& comments
|
||||
, QString const& name, QDateTime const&);
|
||||
void on_bandComboBox_currentIndexChanged (int index);
|
||||
void on_bandComboBox_activated (int index);
|
||||
void on_readFreq_clicked();
|
||||
void on_pbTxMode_clicked();
|
||||
void on_RxFreqSpinBox_valueChanged(int n);
|
||||
void on_cbTxLock_clicked(bool checked);
|
||||
void on_outAttenuation_valueChanged (int);
|
||||
void rigOpen ();
|
||||
void handle_transceiver_update (Transceiver::TransceiverState const&);
|
||||
void handle_transceiver_failure (QString const& reason);
|
||||
void on_actionAstronomical_data_toggled (bool);
|
||||
void on_actionShort_list_of_add_on_prefixes_and_suffixes_triggered();
|
||||
void band_changed (Frequency);
|
||||
void monitor (bool);
|
||||
void stop_tuning ();
|
||||
void stopTuneATU();
|
||||
void auto_tx_mode(bool);
|
||||
void on_actionMessage_averaging_triggered();
|
||||
void on_actionInclude_averaging_toggled (bool);
|
||||
void on_actionInclude_correlation_toggled (bool);
|
||||
void on_actionEnable_AP_DXcall_toggled (bool);
|
||||
void VHF_features_enabled(bool b);
|
||||
void on_sbSubmode_valueChanged(int n);
|
||||
void on_cbShMsgs_toggled(bool b);
|
||||
void on_cbSWL_toggled(bool b);
|
||||
void on_cbTx6_toggled(bool b);
|
||||
void networkError (QString const&);
|
||||
void on_ClrAvgButton_clicked();
|
||||
void on_actionWSPR_triggered();
|
||||
void on_actionWSPR_LF_triggered();
|
||||
void on_syncSpinBox_valueChanged(int n);
|
||||
void on_TxPowerComboBox_currentIndexChanged(const QString &arg1);
|
||||
void on_sbTxPercent_valueChanged(int n);
|
||||
void on_cbUploadWSPR_Spots_toggled(bool b);
|
||||
void WSPR_config(bool b);
|
||||
void uploadSpots();
|
||||
void TxAgain();
|
||||
void uploadResponse(QString response);
|
||||
void on_WSPRfreqSpinBox_valueChanged(int n);
|
||||
void on_pbTxNext_clicked(bool b);
|
||||
void on_actionEcho_Graph_triggered();
|
||||
void on_actionEcho_triggered();
|
||||
void on_actionISCAT_triggered();
|
||||
void on_actionFast_Graph_triggered();
|
||||
void on_actionHide_Controls_toggled (bool chaecked);
|
||||
void fast_decode_done();
|
||||
void on_actionMeasure_reference_spectrum_triggered();
|
||||
void on_actionErase_reference_spectrum_triggered();
|
||||
void on_actionMeasure_phase_response_triggered();
|
||||
void on_sbTR_valueChanged (int);
|
||||
void on_sbFtol_valueChanged (int);
|
||||
void on_cbFast9_clicked(bool b);
|
||||
void on_sbCQTxFreq_valueChanged(int n);
|
||||
void on_cbCQTx_toggled(bool b);
|
||||
void on_actionMSK144_triggered();
|
||||
void on_actionQRA64_triggered();
|
||||
void on_actionFreqCal_triggered();
|
||||
void splash_done ();
|
||||
|
||||
private:
|
||||
Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo,
|
||||
unsigned channels, unsigned msBuffered) const;
|
||||
Q_SIGNAL void stopAudioOutputStream () const;
|
||||
Q_SIGNAL void startAudioInputStream (QAudioDeviceInfo const&,
|
||||
int framesPerBuffer, AudioDevice * sink,
|
||||
unsigned downSampleFactor, AudioDevice::Channel) const;
|
||||
Q_SIGNAL void suspendAudioInputStream () const;
|
||||
Q_SIGNAL void resumeAudioInputStream () const;
|
||||
Q_SIGNAL void startDetector (AudioDevice::Channel) const;
|
||||
Q_SIGNAL void FFTSize (unsigned) const;
|
||||
Q_SIGNAL void detectorClose () const;
|
||||
Q_SIGNAL void finished () const;
|
||||
Q_SIGNAL void transmitFrequency (double) const;
|
||||
Q_SIGNAL void endTransmitMessage (bool quick = false) const;
|
||||
Q_SIGNAL void tune (bool = true) const;
|
||||
Q_SIGNAL void sendMessage (unsigned symbolsLength, double framesPerSymbol,
|
||||
double frequency, double toneSpacing,
|
||||
SoundOutput *, AudioDevice::Channel = AudioDevice::Mono,
|
||||
bool synchronize = true, bool fastMode = false, double dBSNR = 99.,
|
||||
int TRperiod=60) const;
|
||||
Q_SIGNAL void outAttenuationChanged (qreal) const;
|
||||
Q_SIGNAL void toggleShorthand () const;
|
||||
|
||||
private:
|
||||
void astroUpdate ();
|
||||
void writeAllTxt(QString message);
|
||||
void FT8_AutoSeq(QString message);
|
||||
|
||||
NetworkAccessManager m_network_manager;
|
||||
bool m_valid;
|
||||
QSplashScreen * m_splash;
|
||||
QDir m_dataDir;
|
||||
QString m_revision;
|
||||
bool m_multiple;
|
||||
MultiSettings * m_multi_settings;
|
||||
QPushButton * m_configurations_button;
|
||||
QSettings * m_settings;
|
||||
QScopedPointer<Ui::MainWindow> ui;
|
||||
|
||||
// other windows
|
||||
Configuration m_config;
|
||||
WSPRBandHopping m_WSPR_band_hopping;
|
||||
bool m_WSPR_tx_next;
|
||||
MessageBox m_rigErrorMessageBox;
|
||||
QScopedPointer<SampleDownloader> m_sampleDownloader;
|
||||
QScopedPointer<PhaseEqualizationDialog> m_phaseEqualizationDialog;
|
||||
|
||||
QScopedPointer<WideGraph> m_wideGraph;
|
||||
QScopedPointer<EchoGraph> m_echoGraph;
|
||||
QScopedPointer<FastGraph> m_fastGraph;
|
||||
QScopedPointer<LogQSO> m_logDlg;
|
||||
QScopedPointer<Astro> m_astroWidget;
|
||||
QScopedPointer<HelpTextWindow> m_shortcuts;
|
||||
QScopedPointer<HelpTextWindow> m_prefixes;
|
||||
QScopedPointer<HelpTextWindow> m_mouseCmnds;
|
||||
QScopedPointer<MessageAveraging> m_msgAvgWidget;
|
||||
|
||||
Transceiver::TransceiverState m_rigState;
|
||||
Frequency m_lastDialFreq;
|
||||
QString m_lastBand;
|
||||
Frequency m_dialFreqRxWSPR; // best guess at WSPR QRG
|
||||
|
||||
Detector * m_detector;
|
||||
unsigned m_FFTSize;
|
||||
SoundInput * m_soundInput;
|
||||
Modulator * m_modulator;
|
||||
SoundOutput * m_soundOutput;
|
||||
QThread m_audioThread;
|
||||
|
||||
qint64 m_msErase;
|
||||
qint64 m_secBandChanged;
|
||||
qint64 m_freqMoon;
|
||||
Frequency m_freqNominal;
|
||||
Frequency m_freqTxNominal;
|
||||
Astro::Correction m_astroCorrection;
|
||||
|
||||
double m_s6;
|
||||
double m_tRemaining;
|
||||
|
||||
float m_DTtol;
|
||||
float m_t0;
|
||||
float m_t1;
|
||||
float m_t0Pick;
|
||||
float m_t1Pick;
|
||||
float m_fCPUmskrtd;
|
||||
|
||||
qint32 m_waterfallAvg;
|
||||
qint32 m_ntx;
|
||||
bool m_gen_message_is_cq;
|
||||
qint32 m_timeout;
|
||||
qint32 m_XIT;
|
||||
qint32 m_setftx;
|
||||
qint32 m_ndepth;
|
||||
qint32 m_sec0;
|
||||
qint32 m_RxLog;
|
||||
qint32 m_nutc0;
|
||||
qint32 m_ntr;
|
||||
qint32 m_tx;
|
||||
qint32 m_hsym;
|
||||
qint32 m_TRperiod;
|
||||
qint32 m_nsps;
|
||||
qint32 m_hsymStop;
|
||||
qint32 m_inGain;
|
||||
qint32 m_ncw;
|
||||
qint32 m_secID;
|
||||
qint32 m_idleMinutes;
|
||||
qint32 m_nSubMode;
|
||||
qint32 m_nclearave;
|
||||
qint32 m_minSync;
|
||||
qint32 m_dBm;
|
||||
qint32 m_pctx;
|
||||
qint32 m_nseq;
|
||||
qint32 m_nWSPRdecodes;
|
||||
qint32 m_k0;
|
||||
qint32 m_kdone;
|
||||
qint32 m_nPick;
|
||||
FrequencyList::const_iterator m_frequency_list_fcal_iter;
|
||||
qint32 m_nTx73;
|
||||
qint32 m_UTCdisk;
|
||||
qint32 m_wait;
|
||||
|
||||
bool m_btxok; //True if OK to transmit
|
||||
bool m_diskData;
|
||||
bool m_loopall;
|
||||
bool m_decoderBusy;
|
||||
bool m_txFirst;
|
||||
bool m_auto;
|
||||
bool m_restart;
|
||||
bool m_startAnother;
|
||||
bool m_saveDecoded;
|
||||
bool m_saveAll;
|
||||
bool m_widebandDecode;
|
||||
bool m_call3Modified;
|
||||
bool m_dataAvailable;
|
||||
bool m_bDecoded;
|
||||
bool m_noSuffix;
|
||||
bool m_blankLine;
|
||||
bool m_decodedText2;
|
||||
bool m_freeText;
|
||||
bool m_sentFirst73;
|
||||
int m_currentMessageType;
|
||||
QString m_currentMessage;
|
||||
int m_lastMessageType;
|
||||
QString m_lastMessageSent;
|
||||
bool m_lockTxFreq;
|
||||
bool m_bShMsgs;
|
||||
bool m_bSWL;
|
||||
bool m_uploadSpots;
|
||||
bool m_uploading;
|
||||
bool m_txNext;
|
||||
bool m_grid6;
|
||||
bool m_tuneup;
|
||||
bool m_bTxTime;
|
||||
bool m_rxDone;
|
||||
bool m_bSimplex; // not using split even if it is available
|
||||
bool m_bEchoTxOK;
|
||||
bool m_bTransmittedEcho;
|
||||
bool m_bEchoTxed;
|
||||
bool m_bFastMode;
|
||||
bool m_bFast9;
|
||||
bool m_bFastDecodeCalled;
|
||||
bool m_bDoubleClickAfterCQnnn;
|
||||
bool m_bRefSpec;
|
||||
bool m_bClearRefSpec;
|
||||
bool m_bTrain;
|
||||
bool m_bUseRef;
|
||||
bool m_bFastDone;
|
||||
bool m_bAltV;
|
||||
bool m_bNoMoreFiles;
|
||||
bool m_bQRAsyncWarned;
|
||||
bool m_bDoubleClicked;
|
||||
|
||||
int m_ihsym;
|
||||
int m_nzap;
|
||||
int m_npts8;
|
||||
float m_px;
|
||||
float m_pxmax;
|
||||
float m_df3;
|
||||
int m_iptt0;
|
||||
bool m_btxok0;
|
||||
int m_nsendingsh;
|
||||
double m_onAirFreq0;
|
||||
bool m_first_error;
|
||||
|
||||
char m_msg[100][80];
|
||||
|
||||
// labels in status bar
|
||||
QLabel tx_status_label;
|
||||
QLabel config_label;
|
||||
QLabel mode_label;
|
||||
QLabel last_tx_label;
|
||||
QLabel auto_tx_label;
|
||||
QLabel band_hopping_label;
|
||||
QProgressBar progressBar;
|
||||
QLabel watchdog_label;
|
||||
|
||||
QFuture<void> m_wav_future;
|
||||
QFutureWatcher<void> m_wav_future_watcher;
|
||||
QFutureWatcher<void> watcher3;
|
||||
QFutureWatcher<QString> m_saveWAVWatcher;
|
||||
|
||||
QProcess proc_jt9;
|
||||
QProcess p1;
|
||||
QProcess p3;
|
||||
|
||||
WSPRNet *wsprNet;
|
||||
|
||||
QTimer m_guiTimer;
|
||||
QTimer ptt1Timer; //StartTx delay
|
||||
QTimer ptt0Timer; //StopTx delay
|
||||
QTimer logQSOTimer;
|
||||
QTimer killFileTimer;
|
||||
QTimer tuneButtonTimer;
|
||||
QTimer uploadTimer;
|
||||
QTimer tuneATU_Timer;
|
||||
QTimer TxAgainTimer;
|
||||
QTimer minuteTimer;
|
||||
QTimer splashTimer;
|
||||
QTimer p1Timer;
|
||||
|
||||
QString m_path;
|
||||
QString m_baseCall;
|
||||
QString m_hisCall;
|
||||
QString m_hisGrid;
|
||||
QString m_appDir;
|
||||
QString m_palette;
|
||||
QString m_dateTime;
|
||||
QString m_mode;
|
||||
QString m_modeTx;
|
||||
QString m_fnameWE; // save path without extension
|
||||
QString m_rpt;
|
||||
QString m_rptSent;
|
||||
QString m_rptRcvd;
|
||||
QString m_qsoStart;
|
||||
QString m_qsoStop;
|
||||
QString m_cmnd;
|
||||
QString m_cmndP1;
|
||||
QString m_msgSent0;
|
||||
QString m_fileToSave;
|
||||
QString m_calls;
|
||||
|
||||
QSet<QString> m_pfx;
|
||||
QSet<QString> m_sfx;
|
||||
|
||||
QDateTime m_dateTimeQSOOn;
|
||||
QDateTime m_dateTimeQSOOff;
|
||||
QDateTime m_dateTimeDefault;
|
||||
|
||||
QSharedMemory *mem_jt9;
|
||||
LogBook m_logBook;
|
||||
DecodedText m_QSOText;
|
||||
unsigned m_msAudioOutputBuffered;
|
||||
unsigned m_framesAudioInputBuffered;
|
||||
unsigned m_downSampleFactor;
|
||||
QThread::Priority m_audioThreadPriority;
|
||||
bool m_bandEdited;
|
||||
bool m_splitMode;
|
||||
bool m_monitoring;
|
||||
bool m_tx_when_ready;
|
||||
bool m_transmitting;
|
||||
bool m_tune;
|
||||
bool m_tx_watchdog; // true when watchdog triggered
|
||||
bool m_block_pwr_tooltip;
|
||||
bool m_PwrBandSetOK;
|
||||
bool m_bVHFwarned;
|
||||
Frequency m_lastMonitoredFrequency;
|
||||
double m_toneSpacing;
|
||||
int m_firstDecode;
|
||||
QProgressDialog m_optimizingProgress;
|
||||
QTimer m_heartbeat;
|
||||
MessageClient * m_messageClient;
|
||||
PSK_Reporter *psk_Reporter;
|
||||
DisplayManual m_manual;
|
||||
QHash<QString, QVariant> m_pwrBandTxMemory; // Remembers power level by band
|
||||
QHash<QString, QVariant> m_pwrBandTuneMemory; // Remembers power level by band for tuning
|
||||
QByteArray m_geometryNoControls;
|
||||
QVector<double> m_phaseEqCoefficients;
|
||||
|
||||
//---------------------------------------------------- private functions
|
||||
void readSettings();
|
||||
void setDecodedTextFont (QFont const&);
|
||||
void writeSettings();
|
||||
void createStatusBar();
|
||||
void updateStatusBar();
|
||||
void genStdMsgs(QString rpt);
|
||||
void genCQMsg();
|
||||
void clearDX ();
|
||||
void lookup();
|
||||
void ba2msg(QByteArray ba, char* message);
|
||||
void msgtype(QString t, QLineEdit* tx);
|
||||
void stub();
|
||||
void statusChanged();
|
||||
void fixStop();
|
||||
bool shortList(QString callsign);
|
||||
void transmit (double snr = 99.);
|
||||
void rigFailure (QString const& reason);
|
||||
void pskSetLocal ();
|
||||
void pskPost(DecodedText decodedtext);
|
||||
void displayDialFrequency ();
|
||||
void transmitDisplay (bool);
|
||||
void processMessage(QString const& messages, qint32 position, bool ctrl);
|
||||
void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text);
|
||||
void replayDecodes ();
|
||||
void postDecode (bool is_new, QString const& message);
|
||||
void postWSPRDecode (bool is_new, QStringList message_parts);
|
||||
void enable_DXCC_entity (bool on);
|
||||
void switch_mode (Mode);
|
||||
void WSPR_scheduling ();
|
||||
void freqCalStep();
|
||||
void setRig (Frequency = 0); // zero frequency means no change
|
||||
void WSPR_history(Frequency dialFreq, int ndecodes);
|
||||
QString WSPR_hhmm(int n);
|
||||
void fast_config(bool b);
|
||||
void CQTxFreq();
|
||||
QString save_wave_file (QString const& name
|
||||
, short const * data
|
||||
, int seconds
|
||||
, QString const& my_callsign
|
||||
, QString const& my_grid
|
||||
, QString const& mode
|
||||
, qint32 sub_mode
|
||||
, Frequency frequency
|
||||
, QString const& his_call
|
||||
, QString const& his_grid) const;
|
||||
void read_wav_file (QString const& fname);
|
||||
void decodeDone ();
|
||||
void subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus);
|
||||
void subProcessError (QProcess *, QProcess::ProcessError);
|
||||
void statusUpdate () const;
|
||||
void update_watchdog_label ();
|
||||
void on_the_minute ();
|
||||
void add_child_to_event_filter (QObject *);
|
||||
void remove_child_from_event_filter (QObject *);
|
||||
void setup_status_bar (bool vhf);
|
||||
void tx_watchdog (bool triggered);
|
||||
int nWidgets(QString t);
|
||||
void displayWidgets(int n);
|
||||
void vhfWarning();
|
||||
QChar current_submode () const; // returns QChar {0} if sub mode is
|
||||
// not appropriate
|
||||
};
|
||||
|
||||
extern int killbyname(const char* progName);
|
||||
extern void getDev(int* numDevices,char hostAPI_DeviceName[][50],
|
||||
int minChan[], int maxChan[],
|
||||
int minSpeed[], int maxSpeed[]);
|
||||
extern int next_tx_state(int pctx);
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
@@ -1,24 +0,0 @@
|
||||
#include <boost/crc.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
short crc10 (unsigned char const * data, int length);
|
||||
bool crc10_check (unsigned char const * data, int length);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
unsigned long constexpr truncated_polynomial = 0x08f;
|
||||
}
|
||||
|
||||
// assumes CRC is last 16 bits of the data and is set to zero
|
||||
// caller should assign the returned CRC into the message in big endian byte order
|
||||
short crc10 (unsigned char const * data, int length)
|
||||
{
|
||||
return boost::augmented_crc<10, truncated_polynomial> (data, length);
|
||||
}
|
||||
|
||||
bool crc10_check (unsigned char const * data, int length)
|
||||
{
|
||||
return !boost::augmented_crc<10, truncated_polynomial> (data, length);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
// Status=review
|
||||
.Main Window:
|
||||
- Select *FT8* on the *Mode* menu.
|
||||
- Set Tx and Rx frequencies to 1200 Hz.
|
||||
- Double-click on *Erase* to clear both text windows.
|
||||
|
||||
.Wide Graph Settings:
|
||||
|
||||
- *Bins/Pixel* = 4, *Start* = 200 Hz, *N Avg* = 2
|
||||
- Adjust the width of the Wide Graph window so that the upper
|
||||
frequency limit is approximately 2600 Hz.
|
||||
|
||||
.Open a Wave File:
|
||||
|
||||
- Select *File | Open* and navigate to
|
||||
+...\save\samples\FT8\170709_135615.wav+. The waterfall and decoded
|
||||
text window should look something like the following screen shots:
|
||||
|
||||
[[X15]]
|
||||
image::170709_135615.wav.png[align="left",alt="Wide Graph Decode 170709_135615"]
|
||||
|
||||
image::ft8_decodes.png[align="left"]
|
||||
|
||||
- Click with the mouse anywhere on the waterfall display. The green Rx
|
||||
frequency marker will jump to your selected frequency, and the Rx
|
||||
frequency control on the main window will be updated accordingly.
|
||||
|
||||
- Do the same thing with the Shift key held down. Now the red Tx
|
||||
frequency marker and its associated control on the main window will
|
||||
follow your frequency selections.
|
||||
|
||||
- Do the same thing with the Ctrl key held down. Now the both colored
|
||||
markers and both spinner controls will follow your selections.
|
||||
|
||||
- Double-clicking at any frequency on the waterfall does all the
|
||||
things just described and also invokes the decoder in a small range
|
||||
around that frequency.
|
||||
|
||||
- Now double-click on any of the the lines of decoded text in the main
|
||||
window. Unless you have *My Call* set to K1JT or KY7M on the
|
||||
*Settings -> General* tab, all three lines will show the same
|
||||
behavior, setting both RxFreq and TxFreq to the frequency of the
|
||||
selected message. However, if MyCall is set to K1JT then clicking on
|
||||
a message directed to K1JT will move only the Rx frequency setting.
|
||||
This behavior is desirable so that you will not inadvertently change
|
||||
your Tx frequency to that of a tail-ender who called you somewhere
|
||||
else in the FT8 subband.
|
||||
|
||||
IMPORTANT: When finished with this Tutorial, don't forget to re-enter
|
||||
your own callsign as *My Call* on the *Settings | General* tab.
|
||||
@@ -1,371 +0,0 @@
|
||||
<HTML><HEAD>
|
||||
|
||||
<TITLE> Creating a Parity Check Matrix </TITLE>
|
||||
|
||||
</HEAD><BODY>
|
||||
|
||||
|
||||
<H1> Creating a Parity Check Matrix </H1>
|
||||
|
||||
<P>This software deals only with linear block codes for binary (ie,
|
||||
modulo-2, GF(2)) vectors. The set of valid codewords for a linear
|
||||
code can be specified by giving a <I>parity check matrix</I>,
|
||||
<B>H</B>, with <I>M</I> rows and <I>N</I> columns. The valid
|
||||
codewords are the vectors, <B>x</B>, of length <I>N</I>, for which
|
||||
<B>Hx</B>=<B>0</B>, where all arithmetic is done modulo-2. Each row
|
||||
of <B>H</B> represents a parity check on a subset of the bits in
|
||||
<B>x</B>; all these parity checks must be satisfied for <B>x</B> to be
|
||||
a codeword. Note that the parity check matrix for a given code (ie,
|
||||
for a given set of valid codewords) is not unique, even after
|
||||
eliminating rows of <B>H</B> that are redundant because they are
|
||||
linear combinations of other rows.
|
||||
|
||||
<P>This software stores parity check matrices in files in a sparse
|
||||
format. These parity-check files are <I>not</I> human-readable
|
||||
(except by using the <A HREF="#print-pchk"><TT>print-pchk</TT></A>
|
||||
program). However, they <I>are</I> readable on a machine with a
|
||||
different architecture than they were written on.
|
||||
|
||||
<P>Some LDPC software by David MacKay and others uses the
|
||||
<A HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
|
||||
format</A> for parity check matrices. Two programs for converting
|
||||
between this format and the format for sparse parity check matrices
|
||||
used by this software are provided.
|
||||
|
||||
|
||||
<A NAME="ldpc"><H2>Methods for constructing LDPC codes</H2></A>
|
||||
|
||||
<P>This software is primarily intended for experimentation with Low
|
||||
Density Parity Check (LDPC) codes. These codes can be constructed by
|
||||
various methods, which generally involve some random selection of
|
||||
where to put 1s in a parity check matrix. Any such method for
|
||||
constructing LDPC codes will have the property that it produces parity
|
||||
check matrices in which the number of 1s in a column is approximately
|
||||
the same (perhaps on average) for any size parity check matrix. For a
|
||||
given code rate, these matrices therefore become increasingly sparse
|
||||
as the length of a codeword, and hence the number of parity checks,
|
||||
increases.
|
||||
|
||||
<P>Many methods for constructing LDPC matrices are described in the
|
||||
<A HREF="refs.html">references</A>. Two simple methods are currently
|
||||
implemented by this software, both of which operate according to the
|
||||
following scheme:
|
||||
<OL>
|
||||
<LI> Create a preliminary parity check matrix by one of the methods.
|
||||
<LI> Add 1s to the parity check matrix in order to avoid rows that have no
|
||||
1s in them, and hence are redundant, or which have only one 1 in them,
|
||||
in which case the corresponding codeword bits will always be zero.
|
||||
The places within such a row to add these 1s are selected randomly.
|
||||
<LI> If the preliminary parity check matrix constructed in step (1) had
|
||||
an even number of 1s in each column, add further 1s to avoid the problem
|
||||
that this will cause the rows to add to zero, and hence at least
|
||||
one check will be redundant. Up to two 1s are added (since it is also
|
||||
undesirable for the sum of the rows to have only one 1 in it), at
|
||||
positions selected randomly from the entire matrix. However, the
|
||||
number of 1s to add in this step is reduced by the number already added
|
||||
in step (2). (Note that although redundant checks are not disastrous,
|
||||
they are better avoided; see the discussion of <A HREF="dep-H.html">linear
|
||||
dependence in parity check matrices</A>.)
|
||||
<LI> If requested, try to eliminate
|
||||
situations where a pair of columns both have 1s in a particular pair of
|
||||
rows, which correspond to cycles of length four in the factor graph of
|
||||
the parity check matrix. When such a situation is detected, one of the
|
||||
1s involved is moved randomly within its column. This continues until
|
||||
no such situations remain, or until 10 passes over all columns have
|
||||
failed to eliminate all such situations.
|
||||
</OL>
|
||||
|
||||
<P>The <I>evencol</I> method is the simplest way of performing step
|
||||
(1) of the above procedure. For each column of the parity check
|
||||
matrix, independently, it places a specified number of 1s in positions
|
||||
selected uniformly at random, with the only constraint being that
|
||||
these 1s be in distinct rows. Note that despite the name, the columns
|
||||
do not have to have the same number of 1s - a distribution over
|
||||
several values for the number of 1s in a column can be specified
|
||||
instead. Such codes with different-weight columns are sometimes
|
||||
better than codes in which every column has the same weight.
|
||||
|
||||
<P>The <I>evenboth</I> method also puts a specified number of 1s in
|
||||
each column, but it tries as well to keep the numbers of 1s in the
|
||||
rows approximately the same. Initially, it creates indicators for all
|
||||
the 1s that will be required, and assigns these 1s to rows as evenly
|
||||
as it can, favouring earlier rows if an exactly even split is not
|
||||
possible. It then assigns 1s to successive columns by selecting
|
||||
randomly, without replacement, from this initial supply of 1s, subject
|
||||
only to the constraint that the 1s assigned to a column must be in
|
||||
distinct rows. If at some point it is impossible to put the required
|
||||
number of 1s in a column by picking from the 1s remaining, a 1 is set
|
||||
in that column without reference to other columns, creating a possible
|
||||
unevenness.
|
||||
|
||||
<P>Note that regardless of how evenly 1s are distributed in the
|
||||
preliminary parity check matrix created in step (1), steps (2) and (3)
|
||||
can make the numbers of 1s in the both rows and columns be uneven, and
|
||||
step (4), if done, can make the numbers of 1s in rows be uneven.
|
||||
|
||||
|
||||
<P><A NAME="make-pchk"><HR><B>make-pchk</B>: Make a parity check
|
||||
matrix by explicit specification.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
make-pchk <I>pchk-file n-checks n-bits row</I>:<I>col ...</I>
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Creates a file named <TT><I>pchk-file</I></TT> in
|
||||
which it stores a parity check matrix with <TT><I>n-checks</I></TT>
|
||||
rows and <TT><I>n-bits</I></TT> columns. This parity check matrix
|
||||
consists of all 0s except for 1s at the <I>row</I>:<I>col</I>
|
||||
positions listed. Rows and columns are numbered starting at zero.
|
||||
This program is intended primarily for testing and demonstration
|
||||
purposes.
|
||||
|
||||
<P><B>Example:</B> The well-known Hamming code with codewords of
|
||||
length <I>N</I>=7 and with <I>M</I>=3 parity checks can be can be
|
||||
created as follows:
|
||||
<UL><PRE>
|
||||
<LI>make-pchk ham7.pchk 3 7 0:0 0:3 0:4 0:5 1:1 1:3 1:4 1:6 2:2 2:4 2:5 2:6
|
||||
</PRE></UL>
|
||||
|
||||
|
||||
<P><A NAME="alist-to-pchk"><HR><B>alist-to-pchk</B>: Convert a parity
|
||||
check matrix from alist format to the sparse matrix format used by
|
||||
this software.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
alist-to-pchk [ -t ] <I>alist-file pchk-file</I>
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Converts a parity check matrix in
|
||||
<A HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
|
||||
format</A> stored in the file named <TT><I>alist-file</I></TT> to
|
||||
the sparse matrix format used by this software, storing it in the
|
||||
file named <TT><I>pchk-file</I></TT>.
|
||||
|
||||
<P>If the <B>-t</B> option is given, the transpose of the parity check
|
||||
matrix in <TT><I>alist-file</I></TT> is stored in the
|
||||
<TT><I>pchk-file</I></TT>.
|
||||
|
||||
<P>Any zeros indexes in the alist file are ignored, so that alist files
|
||||
with zero padding (as required in the specification) are accepted,
|
||||
but files without this zero padding are also accepted. Newlines
|
||||
are ignored by <TT>alist-to-pchk</TT>, so no error is reported if
|
||||
the set of indexes in a row or column description are not those
|
||||
on a single line.
|
||||
|
||||
|
||||
<P><A NAME="pchk-to-alist"><HR><B>pchk-to-alist</B>: Convert a parity
|
||||
check matrix to alist format.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
pchk-to-alist [ -t ] [ -z ] <I>pchk-file alist-file</I>
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Converts a parity check matrix stored in the sparse matrix format
|
||||
used by this software, in the file named <TT><I>pchk-file</I></TT>, to
|
||||
the <A
|
||||
HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
|
||||
format</A>, storing it in the file named <TT><I>alist-file</I></TT>.
|
||||
|
||||
<P>If the <B>-t</B> option is given, the transpose of the parity check
|
||||
matrix is converted to alist format.
|
||||
|
||||
<P>If the number of 1s is not
|
||||
the same for each row or each column, the alist format specification
|
||||
says that the list of indexes of 1s for each row or column should
|
||||
be padded with zeros to the maximum number of indexes. By default,
|
||||
<TT>pchk-to-alist</TT> does this, but output of these 0s can be
|
||||
suppressed by specifying the <B>-z</B> option. (The <TT>alist-to-pchk</TT>
|
||||
program will accept alist files produced with or without the <B>-z</B>
|
||||
option.)
|
||||
|
||||
|
||||
<P><A NAME="print-pchk"><HR><B>print-pchk</B>: Print a parity check matrix.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
print-pchk [ -d ] [ -t ] <I>pchk-file</I>
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Prints a human-readable representation of the parity check matrix stored
|
||||
in <TT><I>pchk-file</I></TT>.
|
||||
The <B>-d</B> option causes the matrix to be printed in a dense
|
||||
format, even though parity check matrices are always stored in the
|
||||
file in a sparse format. If the <B>-t</B> option is present, what is
|
||||
printed is the transpose of the parity check matrix.
|
||||
|
||||
<P>The sparse display format consists of one line for every row of the
|
||||
matrix, consisting of the row number, a colon, and the column numbers
|
||||
at which 1s are located (possibly none). Row and columns numbers
|
||||
start at zero. No attempt is made to wrap long lines.
|
||||
|
||||
<P>The dense display is the obvious array of 0s and 1s. Long lines
|
||||
are not wrapped.
|
||||
|
||||
<P><B>Example</B>: The parity check matrix for the Hamming code created
|
||||
by the example for <A HREF="#make-pchk"><TT>make-pchk</TT></A> would print
|
||||
as follows:
|
||||
<UL><PRE>
|
||||
<LI>print-pchk ham7.pchk
|
||||
|
||||
Parity check matrix in ham7.pchk (sparse format):
|
||||
|
||||
0: 0 3 4 5
|
||||
1: 1 3 4 6
|
||||
2: 2 4 5 6
|
||||
|
||||
<LI>print-pchk -d ham7.pchk
|
||||
|
||||
Parity check matrix in ham7.pchk (dense format):
|
||||
|
||||
1 0 0 1 1 1 0
|
||||
0 1 0 1 1 0 1
|
||||
0 0 1 0 1 1 1
|
||||
</PRE></UL>
|
||||
|
||||
|
||||
<P><A NAME="make-ldpc"><HR><B>make-ldpc</B>: Make a low density parity
|
||||
check matrix, by random generation.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
make-ldpc <I>pchk-file n-checks n-bits seed method</I>
|
||||
</PRE>
|
||||
<BLOCKQUOTE>
|
||||
where <TT><I>method</I></TT> is one of the following:
|
||||
<BLOCKQUOTE><PRE>
|
||||
evencol <I>checks-per-col</I> [ no4cycle ]
|
||||
|
||||
evencol <I>checks-distribution</I> [ no4cycle ]
|
||||
|
||||
evenboth <I>checks-per-col</I> [ no4cycle ]
|
||||
|
||||
evenboth <I>checks-distribution</I> [ no4cycle ]
|
||||
</PRE></BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P>Creates a Low Density Parity Check matrix with
|
||||
<TT><I>n-checks</I></TT> rows and <TT><I>n-bits</I></TT> columns. The
|
||||
parity check matrix will be generated pseudo-randomly by the indicated
|
||||
method, using a pseudo-random number stream determined by <TT><I>seed</I></TT>.
|
||||
The actual random number seed used is 10 times <TT><I>seed</I></TT> plus 1,
|
||||
so as to avoid using the same stream as any of the other programs.
|
||||
|
||||
<P>Two methods are currently available for creating the LDPC matrix,
|
||||
specified by <TT>evencol</TT> or <TT>evenboth</TT>. Both methods
|
||||
produce a matrix in which the number of 1s in each column is
|
||||
approximately <TT><I>checks-per-col</I></TT>, or varies from column
|
||||
to column according the the <TT><I>checks-distribution</I></TT>.
|
||||
The <TT>evenboth</TT> method also tries to make the number of checks per row be
|
||||
approximately uniform; if this is not achieved, a message saying that
|
||||
how many bits were placed unevenly is displayed on standard error.
|
||||
|
||||
<P>For both methods, the <TT>no4cycle</TT> option will cause cycles of
|
||||
length four in the factor graph representation of the code to be
|
||||
eliminated (if possible). A message is displayed on standard error if
|
||||
this is not achieved.
|
||||
|
||||
<P>A <TT><I>checks-distribution</I></TT> has the form
|
||||
<BLOCKQUOTE><PRE>
|
||||
<I>prop</I>x<I>count</I>/<I>prop</I>x<I>count</I>/...
|
||||
</PRE></BLOCKQUOTE>
|
||||
Here, <TT><I>prop</I></TT> is a proportion of columns that have the
|
||||
associated <TT><I>count</I></TT>. The proportions need not sum to one,
|
||||
since they will be automatically normalized. For example, <TT>0.3x4/0.2x5</TT>
|
||||
specifies that 60% of the columns will contain four 1s and 40% will
|
||||
contain five 1s.
|
||||
|
||||
<P>See the <A HREF="#ldpc">discussion above</A> for more details
|
||||
on how these methods construct LDPC matrices.
|
||||
|
||||
<P><B>Example 1:</B> The <TT>make-ldpc</TT> command below creates
|
||||
a 20 by 40 low density parity check matrix with three 1s per
|
||||
column and six 1s per row, using random seed 1. The matrix
|
||||
is then printed in sparse format
|
||||
using <A HREF="#print-pchk">print-pchk</A>.
|
||||
<UL><PRE>
|
||||
<LI>make-ldpc ldpc.pchk 20 40 1 evenboth 3
|
||||
<LI>print-pchk ldpc.pchk
|
||||
|
||||
Parity check matrix in ldpc.pchk (sparse format):
|
||||
|
||||
0: 10 14 18 27 38 39
|
||||
1: 2 3 5 11 27 30
|
||||
2: 15 19 20 21 24 26
|
||||
3: 2 4 25 28 32 38
|
||||
4: 7 9 12 22 33 34
|
||||
5: 5 6 21 22 26 32
|
||||
6: 1 4 13 24 25 28
|
||||
7: 1 14 28 29 30 36
|
||||
8: 11 13 22 23 32 37
|
||||
9: 6 8 13 20 31 33
|
||||
10: 0 3 24 29 31 38
|
||||
11: 7 12 15 16 17 23
|
||||
12: 3 16 29 34 35 39
|
||||
13: 0 8 10 18 36 37
|
||||
14: 6 11 18 20 35 39
|
||||
15: 0 7 14 16 25 37
|
||||
16: 2 4 9 19 30 31
|
||||
17: 5 9 10 17 19 23
|
||||
18: 8 15 17 21 26 27
|
||||
19: 1 12 33 34 35 36
|
||||
</PRE></UL>
|
||||
|
||||
<P><B>Example 2:</B> The two <TT>make-ldpc</TT> commands
|
||||
below both create a 20 by 40 low density parity check matrix with 30%
|
||||
of columns with two 1s, 60% of columns with three 1s, and 10% of
|
||||
columns with seven 1s. The transpose of the parity check matrix
|
||||
is then printed in sparse format.
|
||||
<UL><PRE>
|
||||
<LI>make-ldpc ldpc.pchk 20 40 1 evenboth 0.3x2/0.6x3/0.1x7
|
||||
<LI>make-ldpc ldpc.pchk 20 40 1 evenboth 3x2/6x3/1x7
|
||||
<LI>print-pchk -t ldpc.pchk
|
||||
|
||||
Transpose of parity check matrix in ldpc.pchk (sparse format):
|
||||
|
||||
0: 13 16
|
||||
1: 9 18
|
||||
2: 1 10
|
||||
3: 3 15
|
||||
4: 4 14
|
||||
5: 14 17
|
||||
6: 4 5
|
||||
7: 1 8
|
||||
8: 0 4
|
||||
9: 9 14
|
||||
10: 5 8
|
||||
11: 6 16
|
||||
12: 2 12 19
|
||||
13: 3 17 18
|
||||
14: 2 16 17
|
||||
15: 2 11 18
|
||||
16: 12 13 19
|
||||
17: 7 13 18
|
||||
18: 2 5 11
|
||||
19: 10 12 14
|
||||
20: 1 8 16
|
||||
21: 10 18 19
|
||||
22: 3 6 17
|
||||
23: 7 11 12
|
||||
24: 1 2 19
|
||||
25: 0 6 7
|
||||
26: 5 8 15
|
||||
27: 1 4 7
|
||||
28: 6 13 19
|
||||
29: 3 4 11
|
||||
30: 3 8 17
|
||||
31: 4 5 9
|
||||
32: 0 10 15
|
||||
33: 7 11 13
|
||||
34: 8 12 19
|
||||
35: 0 2 10
|
||||
36: 0 5 9 11 15 17 18
|
||||
37: 0 1 2 6 7 14 16
|
||||
38: 0 1 3 9 12 13 15
|
||||
39: 3 6 9 10 14 15 16
|
||||
</PRE></UL>
|
||||
|
||||
<HR>
|
||||
|
||||
<A HREF="index.html">Back to index for LDPC software</A>
|
||||
|
||||
</BODY></HTML>
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<table cellpadding=5>
|
||||
<tr>
|
||||
<th align="right">Click on</th>
|
||||
<th align="left">Action</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">Waterfall:</td>
|
||||
<td><b>Click</b> to set the Rx frequency.<br/>
|
||||
<b>Shift-click</b> to set Tx frequency.<br/>
|
||||
<b>Ctrl-click</b> to set Rx and Tx frequencies.<br/>
|
||||
<b>Double-click</b> to decode at resulting Rx frequency.<br/>
|
||||
If <b>Lock Tx=Rx</b> is checked all actions set Tx/Rx.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">Decoded text:</td>
|
||||
<td><b>Double-click</b> to copy second callsign to Dx Call,<br/>
|
||||
locator to Dx Grid; change Rx and Tx frequencies to<br/>
|
||||
decoded signal's frequency; generate standard messages.<br/>
|
||||
If first callsign is your own, Tx frequency is not<br/>
|
||||
changed unless Ctrl is held down when double-clicking.
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="right">Erase button:</td>
|
||||
<td><b>Click</b> to erase QSO window.<br/>
|
||||
<b>Double-click</b> to erase QSO and Band Activity windows.
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -1,89 +0,0 @@
|
||||
<HTML><HEAD>
|
||||
|
||||
<TITLE> Modules Used in LDPC Programs </TITLE>
|
||||
|
||||
</HEAD><BODY>
|
||||
|
||||
|
||||
<H1> Modules Used in LDPC Programs </H1>
|
||||
|
||||
You may need to familiarize yourself with the modules documented here
|
||||
in order to <A HREF="modify.html">modify the LDPC programs</A>.
|
||||
These modules may also be useful for other purposes.
|
||||
|
||||
<P>Click on the title of a module below for general information, or on
|
||||
specific routines for detailed documentation.
|
||||
|
||||
<P><A HREF="mod2dense.html">Dense modulo-2 matrix routines</A>:
|
||||
<BLOCKQUOTE><PRE>
|
||||
<A HREF="mod2dense.html#dimension-sec"><I>Dimension macros:</I> mod2dense_rows mod2dense_cols</A>
|
||||
|
||||
<I><A HREF="mod2dense.html#alloc-sec">Allocation:</A> <A HREF="mod2dense.html#copy-clear-sec">Copy/Clear:</A> <A HREF="mod2dense.html#input-output-sec">Input/Output:</A> <A HREF="mod2dense.html#elementary-sec">Elementary ops:</A></I>
|
||||
|
||||
<A HREF="mod2dense.html#allocate">mod2dense_allocate</A> <A HREF="mod2dense.html#clear">mod2dense_clear</A> <A HREF="mod2dense.html#print">mod2dense_print</A> <A HREF="mod2dense.html#get">mod2dense_get</A>
|
||||
<A HREF="mod2dense.html#free">mod2dense_free</A> <A HREF="mod2dense.html#copy">mod2dense_copy</A> <A HREF="mod2dense.html#write">mod2dense_write</A> <A HREF="mod2dense.html#set">mod2dense_set</A>
|
||||
<A HREF="mod2dense.html#copyrows">mod2dense_copyrows</A> <A HREF="mod2dense.html#read">mod2dense_read</A> <A HREF="mod2dense.html#flip">mod2dense_flip</A>
|
||||
<A HREF="mod2dense.html#copycols">mod2dense_copycols</A>
|
||||
|
||||
<I><A HREF="mod2dense.html#arith-sec">Matrix arithmetic:</A> <A HREF="mod2dense.html#invert-sec">Matrix inversion:</A></I>
|
||||
|
||||
<A HREF="mod2dense.html#transpose">mod2dense_transpose</A> <A HREF="mod2dense.html#invert">mod2dense_invert</A>
|
||||
<A HREF="mod2dense.html#add">mod2dense_add</A> <A HREF="mod2dense.html#forcibly_invert">mod2dense_forcibly_invert</A>
|
||||
<A HREF="mod2dense.html#multiply">mod2dense_multiply</A> <A HREF="mod2dense.html#invert_selected">mod2dense_invert_selected</A>
|
||||
<A HREF="mod2dense.html#equal">mod2dense_equal</A>
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P><A HREF="mod2sparse.html">Sparse modulo-2 matrix routines</A>:
|
||||
<BLOCKQUOTE><PRE>
|
||||
<A HREF="mod2sparse.html#dimension-sec"><I>Dimension macros:</I> mod2sparse_rows mod2sparse_cols</A>
|
||||
|
||||
<A HREF="mod2sparse.html#traversal-sec"><I>Traversal macros:</I> mod2sparse_first_in_row mod2sparse_next_in_row ...</A>
|
||||
|
||||
<I><A HREF="mod2sparse.html#alloc-sec">Allocation:</A> <A HREF="mod2sparse.html#copy-clear-sec">Copy/Clear:</A> <A HREF="mod2sparse.html#input-output-sec">Input/Output:</A> <A HREF="mod2sparse.html#elementary-sec">Elementary ops:</A></I>
|
||||
|
||||
<A HREF="mod2sparse.html#allocate">mod2sparse_allocate</A> <A HREF="mod2sparse.html#clear">mod2sparse_clear</A> <A HREF="mod2sparse.html#print">mod2sparse_print</A> <A HREF="mod2sparse.html#find">mod2sparse_find</A>
|
||||
<A HREF="mod2sparse.html#free">mod2sparse_free</A> <A HREF="mod2sparse.html#copy">mod2sparse_copy</A> <A HREF="mod2sparse.html#write">mod2sparse_write</A> <A HREF="mod2sparse.html#insert">mod2sparse_insert</A>
|
||||
<A HREF="mod2sparse.html#copyrows">mod2sparse_copyrows</A> <A HREF="mod2sparse.html#read">mod2sparse_read</A> <A HREF="mod2sparse.html#delete">mod2sparse_delete</A>
|
||||
<A HREF="mod2sparse.html#copycols">mod2sparse_copycols</A>
|
||||
|
||||
<I><A HREF="mod2sparse.html#arith-sec">Matrix arithmetic:</A> <A HREF="mod2sparse.html#row-col-ops-sec">Row/Column ops:</A> <A HREF="mod2sparse.html#lu-decomp-sec">LU decomposition:</A></I>
|
||||
|
||||
<A HREF="mod2sparse.html#transpose">mod2sparse_transpose</A> <A HREF="mod2sparse.html#count_row">mod2sparse_count_row</A> <A HREF="mod2sparse.html#decomp">mod2sparse_decomp</A>
|
||||
<A HREF="mod2sparse.html#add">mod2sparse_add</A> <A HREF="mod2sparse.html#count_col">mod2sparse_count_col</A> <A HREF="mod2sparse.html#forward_sub">mod2sparse_forward_sub</A>
|
||||
<A HREF="mod2sparse.html#multiply">mod2sparse_multiply</A> <A HREF="mod2sparse.html#add_row">mod2sparse_add_row</A> <A HREF="mod2sparse.html#backward_sub">mod2sparse_backward_sub</A>
|
||||
<A HREF="mod2sparse.html#mulvec">mod2sparse_mulvec</A> <A HREF="mod2sparse.html#add_col">mod2sparse_add_col</A>
|
||||
<A HREF="mod2sparse.html#equal">mod2sparse_equal</A>
|
||||
</PRE>
|
||||
<A HREF="sparse-LU.html">Discussion of sparse LU decomposition methods.</A>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><A HREF="mod2convert.html">Modulo-2 matrix sparse/dense conversion</A>:
|
||||
<BLOCKQUOTE><PRE>
|
||||
<A HREF="mod2convert.html#sparse_to_dense">mod2sparse_to_dense</A>
|
||||
<A HREF="mod2convert.html#dense_to_sparse">mod2dense_to_sparse</A>
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P><A HREF="rand.html">Random variate generation routines</A>:
|
||||
<BLOCKQUOTE><PRE>
|
||||
<I><A HREF="rand.html#get-set-sec">Set/Get state:<A> <A HREF="rand.html#uniform-sec">Uniform:</A> <A HREF="rand.html#discrete-sec">Discrete:</A> <A HREF="rand.html#continuous-sec">Continuous:</A></I>
|
||||
|
||||
<A HREF="rand.html#seed">rand_seed</A> <A HREF="rand.html#uniform">rand_uniform</A> <A HREF="rand.html#int">rand_int</A> <A HREF="rand.html#gaussian">rand_gaussian</A>
|
||||
<A HREF="rand.html#get_state">rand_get_state</A> <A HREF="rand.html#uniopen">rand_uniopen</A> <A HREF="rand.html#pickd">rand_pickd</A> <A HREF="rand.html#logistic">rand_logistic</A>
|
||||
<A HREF="rand.html#use_state">rand_use_state</A> <A HREF="rand.html#pickf">rand_pickf</A> <A HREF="rand.html#cauchy">rand_cauchy</A>
|
||||
<A HREF="rand.html#poisson">rand_poisson</A> <A HREF="rand.html#gamma">rand_gamma</A>
|
||||
<A HREF="rand.html#permutation">rand_permutation</A> <A HREF="rand.html#exp">rand_exp</A>
|
||||
<A HREF="rand.html#beta">rand_beta</A>
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Each of the modules above has a test program, called
|
||||
<TT><I>module</I>-test</TT>. These programs are compiled by the command
|
||||
<BLOCKQUOTE><PRE>
|
||||
make tests
|
||||
</PRE></BLOCKQUOTE>
|
||||
See the source files for these test programs for further information.
|
||||
|
||||
<HR>
|
||||
|
||||
<A HREF="index.html">Back to index for LDPC software</A>
|
||||
|
||||
</BODY></HTML>
|
||||
@@ -1,262 +0,0 @@
|
||||
#ifndef CONFIGURATION_HPP_
|
||||
#define CONFIGURATION_HPP_
|
||||
|
||||
#include <QObject>
|
||||
#include <QFont>
|
||||
|
||||
#include "Radio.hpp"
|
||||
#include "IARURegions.hpp"
|
||||
#include "AudioDevice.hpp"
|
||||
#include "Transceiver.hpp"
|
||||
|
||||
#include "pimpl_h.hpp"
|
||||
|
||||
class QSettings;
|
||||
class QWidget;
|
||||
class QAudioDeviceInfo;
|
||||
class QString;
|
||||
class QDir;
|
||||
class Bands;
|
||||
class FrequencyList;
|
||||
class StationList;
|
||||
class QStringListModel;
|
||||
class QHostAddress;
|
||||
|
||||
//
|
||||
// Class Configuration
|
||||
//
|
||||
// Encapsulates the control, access and, persistence of user defined
|
||||
// settings for the wsjtx GUI. Setting values are accessed through a
|
||||
// QDialog window containing concept orientated tab windows.
|
||||
//
|
||||
// Responsibilities
|
||||
//
|
||||
// Provides management of the CAT and PTT rig interfaces, providing
|
||||
// control access via a minimal generic set of Qt slots and status
|
||||
// updates via Qt signals. Internally the rig control capability is
|
||||
// farmed out to a separate thread since many of the rig control
|
||||
// functions are blocking.
|
||||
//
|
||||
// All user settings required by the wsjtx GUI are exposed through
|
||||
// query methods. Settings only become visible once they have been
|
||||
// accepted by the user which is done by clicking the "OK" button on
|
||||
// the settings dialog.
|
||||
//
|
||||
// The QSettings instance passed to the constructor is used to read
|
||||
// and write user settings.
|
||||
//
|
||||
// Pointers to three QAbstractItemModel objects are provided to give
|
||||
// access to amateur band information, user working frequencies and,
|
||||
// user operating band information. These porovide consistent data
|
||||
// models that can be used in GUI lists or tables or simply queried
|
||||
// for user defined bands, default operating frequencies and, station
|
||||
// descriptions.
|
||||
//
|
||||
class Configuration final
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS (DataMode Type2MsgGen)
|
||||
|
||||
public:
|
||||
using MODE = Transceiver::MODE;
|
||||
using TransceiverState = Transceiver::TransceiverState;
|
||||
using Frequency = Radio::Frequency;
|
||||
using port_type = quint16;
|
||||
|
||||
enum DataMode {data_mode_none, data_mode_USB, data_mode_data};
|
||||
Q_ENUM (DataMode)
|
||||
enum Type2MsgGen {type_2_msg_1_full, type_2_msg_3_full, type_2_msg_5_only};
|
||||
Q_ENUM (Type2MsgGen)
|
||||
|
||||
explicit Configuration (QDir const& temp_directory, QSettings * settings,
|
||||
QWidget * parent = nullptr);
|
||||
~Configuration ();
|
||||
|
||||
void select_tab (int);
|
||||
int exec ();
|
||||
bool is_active () const;
|
||||
|
||||
QDir temp_dir () const;
|
||||
QDir doc_dir () const;
|
||||
QDir data_dir () const;
|
||||
QDir writeable_data_dir () const;
|
||||
|
||||
QAudioDeviceInfo const& audio_input_device () const;
|
||||
AudioDevice::Channel audio_input_channel () const;
|
||||
QAudioDeviceInfo const& audio_output_device () const;
|
||||
AudioDevice::Channel audio_output_channel () const;
|
||||
|
||||
// These query methods should be used after a call to exec() to
|
||||
// determine if either the audio input or audio output stream
|
||||
// parameters have changed. The respective streams should be
|
||||
// re-opened if they return true.
|
||||
bool restart_audio_input () const;
|
||||
bool restart_audio_output () const;
|
||||
|
||||
QString my_callsign () const;
|
||||
QString my_grid () const;
|
||||
QFont decoded_text_font () const;
|
||||
qint32 id_interval () const;
|
||||
qint32 ntrials() const;
|
||||
qint32 aggressive() const;
|
||||
qint32 RxBandwidth() const;
|
||||
double degrade() const;
|
||||
double txDelay() const;
|
||||
bool id_after_73 () const;
|
||||
bool tx_QSY_allowed () const;
|
||||
bool spot_to_psk_reporter () const;
|
||||
bool monitor_off_at_startup () const;
|
||||
bool monitor_last_used () const;
|
||||
bool log_as_RTTY () const;
|
||||
bool report_in_comments () const;
|
||||
bool prompt_to_log () const;
|
||||
bool insert_blank () const;
|
||||
bool DXCC () const;
|
||||
bool clear_DX () const;
|
||||
bool miles () const;
|
||||
bool quick_call () const;
|
||||
bool disable_TX_on_73 () const;
|
||||
int watchdog () const;
|
||||
bool TX_messages () const;
|
||||
bool split_mode () const;
|
||||
bool enable_VHF_features () const;
|
||||
bool decode_at_52s () const;
|
||||
bool single_decode () const;
|
||||
bool twoPass() const;
|
||||
bool x2ToneSpacing() const;
|
||||
bool contestMode() const;
|
||||
bool realTimeDecode() const;
|
||||
bool MyDx() const;
|
||||
bool CQMyN() const;
|
||||
bool NDxG() const;
|
||||
bool NN() const;
|
||||
bool EMEonly() const;
|
||||
bool post_decodes () const;
|
||||
QString udp_server_name () const;
|
||||
port_type udp_server_port () const;
|
||||
bool accept_udp_requests () const;
|
||||
bool udpWindowToFront () const;
|
||||
bool udpWindowRestore () const;
|
||||
Bands * bands ();
|
||||
Bands const * bands () const;
|
||||
IARURegions::Region region () const;
|
||||
FrequencyList * frequencies ();
|
||||
FrequencyList const * frequencies () const;
|
||||
StationList * stations ();
|
||||
StationList const * stations () const;
|
||||
QStringListModel * macros ();
|
||||
QStringListModel const * macros () const;
|
||||
QDir save_directory () const;
|
||||
QDir azel_directory () const;
|
||||
QString rig_name () const;
|
||||
Type2MsgGen type_2_msg_gen () const;
|
||||
QColor color_CQ () const;
|
||||
QColor color_MyCall () const;
|
||||
QColor color_TxMsg () const;
|
||||
QColor color_DXCC () const;
|
||||
QColor color_NewCall () const;
|
||||
bool pwrBandTxMemory () const;
|
||||
bool pwrBandTuneMemory () const;
|
||||
// This method queries if a CAT and PTT connection is operational.
|
||||
bool is_transceiver_online () const;
|
||||
|
||||
// Start the rig connection, safe and normal to call when rig is
|
||||
// already open.
|
||||
bool transceiver_online ();
|
||||
|
||||
// check if a real rig is configured
|
||||
bool is_dummy_rig () const;
|
||||
|
||||
// Frequency resolution of the rig
|
||||
//
|
||||
// 0 - 1Hz
|
||||
// 1 - 10Hz rounded
|
||||
// -1 - 10Hz truncated
|
||||
// 2 - 100Hz rounded
|
||||
// -2 - 100Hz truncated
|
||||
int transceiver_resolution () const;
|
||||
|
||||
// Close down connection to rig.
|
||||
void transceiver_offline ();
|
||||
|
||||
// Set transceiver frequency in Hertz.
|
||||
Q_SLOT void transceiver_frequency (Frequency);
|
||||
|
||||
// Setting a non zero TX frequency means split operation
|
||||
// rationalise_mode means ensure TX uses same mode as RX.
|
||||
Q_SLOT void transceiver_tx_frequency (Frequency = 0u);
|
||||
|
||||
// Set transceiver mode.
|
||||
//
|
||||
// Rationalise means ensure TX uses same mode as RX.
|
||||
Q_SLOT void transceiver_mode (MODE);
|
||||
|
||||
// Set/unset PTT.
|
||||
//
|
||||
// Note that this must be called even if VOX PTT is selected since
|
||||
// the "Emulate Split" mode requires PTT information to coordinate
|
||||
// frequency changes.
|
||||
Q_SLOT void transceiver_ptt (bool = true);
|
||||
|
||||
// Attempt to (re-)synchronise transceiver state.
|
||||
//
|
||||
// Force signal guarantees either a transceiver_update or a
|
||||
// transceiver_failure signal.
|
||||
//
|
||||
// The enforce_mode_and_split parameter ensures that future
|
||||
// transceiver updates have the correct mode and split setting
|
||||
// i.e. the transceiver is ready for use.
|
||||
Q_SLOT void sync_transceiver (bool force_signal = false, bool enforce_mode_and_split = false);
|
||||
|
||||
|
||||
//
|
||||
// This signal indicates that a font has been selected and accepted
|
||||
// for the decoded text.
|
||||
//
|
||||
Q_SIGNAL void decoded_text_font_changed (QFont);
|
||||
|
||||
//
|
||||
// This signal is emitted when the UDP server changes
|
||||
//
|
||||
Q_SIGNAL void udp_server_changed (QString const& udp_server);
|
||||
Q_SIGNAL void udp_server_port_changed (port_type server_port);
|
||||
|
||||
|
||||
//
|
||||
// These signals are emitted and reflect transceiver state changes
|
||||
//
|
||||
|
||||
// signals a change in one of the TransceiverState members
|
||||
Q_SIGNAL void transceiver_update (Transceiver::TransceiverState const&) const;
|
||||
|
||||
// Signals a failure of a control rig CAT or PTT connection.
|
||||
//
|
||||
// A failed rig CAT or PTT connection is fatal and the underlying
|
||||
// connections are closed automatically. The connections can be
|
||||
// re-established with a call to transceiver_online(true) assuming
|
||||
// the fault condition has been rectified or is transient.
|
||||
Q_SIGNAL void transceiver_failure (QString const& reason) const;
|
||||
|
||||
private:
|
||||
class impl;
|
||||
pimpl<impl> m_;
|
||||
};
|
||||
|
||||
#if QT_VERSION < 0x050500
|
||||
Q_DECLARE_METATYPE (Configuration::DataMode);
|
||||
Q_DECLARE_METATYPE (Configuration::Type2MsgGen);
|
||||
#endif
|
||||
|
||||
#if !defined (QT_NO_DEBUG_STREAM)
|
||||
ENUM_QDEBUG_OPS_DECL (Configuration, DataMode);
|
||||
ENUM_QDEBUG_OPS_DECL (Configuration, Type2MsgGen);
|
||||
#endif
|
||||
|
||||
ENUM_QDATASTREAM_OPS_DECL (Configuration, DataMode);
|
||||
ENUM_QDATASTREAM_OPS_DECL (Configuration, Type2MsgGen);
|
||||
|
||||
ENUM_CONVERSION_OPS_DECL (Configuration, DataMode);
|
||||
ENUM_CONVERSION_OPS_DECL (Configuration, Type2MsgGen);
|
||||
|
||||
#endif
|
||||
@@ -1,342 +0,0 @@
|
||||
<HTML><HEAD>
|
||||
|
||||
<TITLE> Decoding Received Blocks </TITLE>
|
||||
|
||||
|
||||
</HEAD><BODY>
|
||||
|
||||
<H1> Decoding Received Blocks </H1>
|
||||
|
||||
Transmitted codewords are decoded from the received data on the basis
|
||||
of the <I>likelihood</I> of the possible codewords, which is the
|
||||
probability of receiving the data that was actually received if the
|
||||
codeword is question were the one that was sent. This software
|
||||
presently deals only with memoryless channels, in which the noise is
|
||||
independent from bit to bit. For such a channel, the likelihood
|
||||
factorizes into a product of likelihoods for each bit.
|
||||
|
||||
For decoding purposes, all that matters is the relative likelihood
|
||||
for a bit to be 1 versus 0. This is captured by the <I>likelihood
|
||||
ratio</I> in favour of a 1, which is P(data | bit is 1) / P(data |
|
||||
bit is 0).
|
||||
|
||||
<P>For a Binary Symmetric Channel with error probability <I>p</I>,
|
||||
the likelihood ratio in favour of a 1 bit is as follows:
|
||||
<BLOCKQUOTE>
|
||||
If the received data was +1: (1-<I>p</I>) / <I>p</I><BR>
|
||||
If the received data was -1: <I>p</I> / (1-<I>p</I>)
|
||||
</BLOCKQUOTE>
|
||||
For an Additive White Gaussian Noise channel, with signals of +1 for a 1 bit
|
||||
and or -1 for a 0 bit, and with noise standard deviation <I>s</I>, the
|
||||
likelihood ratio in favour of a 1 bit when data <I>y</I> was received is
|
||||
<BLOCKQUOTE>
|
||||
exp ( 2y / s<SUP><SMALL>2</SMALL></SUP> )
|
||||
</BLOCKQUOTE>
|
||||
For an Additive White Logistic Noise channel, the corresponding
|
||||
likelihood ratio is
|
||||
<I>d</I><SUB><SMALL>1</SMALL></SUB>/<I>d</I><SUB><SMALL>0</SMALL></SUB>,
|
||||
where
|
||||
<I>d</I><SUB><SMALL>1</SMALL></SUB>=<I>e</I><SUB><SMALL>1</SMALL></SUB>
|
||||
/ (1+<I>e</I><SUB><SMALL>1</SMALL></SUB>)<SUP><SMALL>2</SMALL></SUP> and
|
||||
<I>d</I><SUB><SMALL>0</SMALL></SUB>=<I>e</I><SUB><SMALL>0</SMALL></SUB>
|
||||
/ (1+<I>e</I><SUB><SMALL>0</SMALL></SUB>)<SUP><SMALL>2</SMALL></SUP>,
|
||||
with <I>e</I><SUB><SMALL>1</SMALL></SUB>=exp(-(<I>y</I>-1)/<I>w</I>) and
|
||||
<I>e</I><SUB><SMALL>0</SMALL></SUB>=exp(-(<I>y</I>+1)/<I>w</I>).
|
||||
<BLOCKQUOTE> </BLOCKQUOTE>
|
||||
|
||||
<P>It is usual to consider codewords to be equally likely <I>a
|
||||
priori</I>. This is reasonable if the source messages are all equally
|
||||
likely (any source redundancy being ignored, or remove by a
|
||||
preliminary data compression stage), provided that the mapping from
|
||||
source messages to codewords is onto. Decoding can then be done using
|
||||
only the parity check matrix defining the codewords, without reference
|
||||
to the generator matrix defining the mapping from source messages to
|
||||
codewords. Note that the condition that this mapping be onto isn't
|
||||
true with this software in the atypical case where the code is defined
|
||||
by a parity check matrix with redundant rows; see the discussion of <A
|
||||
HREF="dep-H.html">linear dependence in parity check matrices</A>.
|
||||
This minor complication is mostly ignored here, except by the exhaustive
|
||||
enumeration decoding methods.
|
||||
|
||||
<P>Assuming equal <I>a priori</I> probabilities for codewords, the
|
||||
probability of correctly decoding an entire codeword is minimized by
|
||||
picking the codeword with the highest likelihood. One might instead
|
||||
wish to decode each bit to the value that is most probable. This
|
||||
minimizes the bit error rate, but is not in general guaranteed to lead
|
||||
a decoding for each block to the most probable complete codeword;
|
||||
indeed, the decoding may not be a codeword at all. Minimizing the bit
|
||||
error rate seems nevertheless to be the most sensible objective,
|
||||
unless block boundaries have some significance in a wider context.
|
||||
|
||||
<P>Optimal decoding by either criterion is infeasible for general
|
||||
linear codes when messages are more than about 20 or 30 bits in
|
||||
length. The fundamental advantage of Low Density Parity Check codes
|
||||
is that good (though not optimal) decodings can be obtained by methods
|
||||
such as probability propagation, described next.
|
||||
|
||||
<A NAME="prprp"><H2>Decoding by probability propagation</H2></A>
|
||||
|
||||
<P>The probability propagation algorithm was originally devised by
|
||||
Robert Gallager in the early 1960's and later reinvented by David
|
||||
MacKay and myself. It can be seen as an instance of the sum-product
|
||||
algorithm for inference on factor graphs, and as an instance of belief
|
||||
propagation in probabilistic networks. See the <A
|
||||
HREF="refs.html">references</A> for details. Below, I give a fairly
|
||||
intuitive description of the algorithm.
|
||||
|
||||
<P>The algorithm uses only the parity check matrix for the code, whose
|
||||
columns correspond to codeword bits, and whose rows correspond to
|
||||
parity checks, and the likelihood ratios for the bits derived from the
|
||||
data. It aims to find the probability of each bit of the transmitted
|
||||
codeword being 1, though the results of the algorithm are in general
|
||||
only approximate.
|
||||
|
||||
<P>The begin, information about each bit of the codeword derived from
|
||||
the received data for that bit alone is expressed as a <I>probability
|
||||
ratio</I>, the probability of the bit being 1 divided by the
|
||||
probability of the bit being 0. This probability ratio is equal to
|
||||
the likelihood ratio (see above) for that bit, since 0 and 1 are
|
||||
assumed to be equally likely <I>a priori</I>. As the algorithm
|
||||
progresses, these probability ratios will be modified to take account
|
||||
of information obtained from other bits, in conjunction with the
|
||||
requirement that the parity checks be satisfied. To avoid double
|
||||
counting of information, for every bit, the algorithm maintains a
|
||||
separate probability ratio for each parity check that that bit
|
||||
participates in, giving the probability for that bit to be 1 versus 0
|
||||
based only on information derived from <I>other</I> parity checks,
|
||||
along with the data received for the bit.
|
||||
|
||||
<P>For each parity check, the algorithm maintains separate
|
||||
<I>likelihood ratios</I> (analogous to, but distinct from, the
|
||||
likelihood ratios based on received data), for every bit that
|
||||
participates in that parity check. These ratios give the probability
|
||||
of that parity check being satisfied if the bit in question is 1
|
||||
divided by the probability of the check being satisfied if the bit is
|
||||
0, taking account of the probabilities of each of the <I>other</I>
|
||||
bits participating in this check being 1, as derived from the
|
||||
probability ratios for these bits with respect to this check.
|
||||
|
||||
<P>The algorithm alternates between recalculating the likelihood
|
||||
ratios for each check, which are stored in the <B>lr</B> fields of the
|
||||
parity check matrix entries, and recalculating the probability ratios
|
||||
for each bit, which are stored in the <B>pr</B> fields of the entries
|
||||
in the sparse matrix representation of the parity check matrix. (See
|
||||
the documentation on <A HREF="mod2sparse.html#rep">representation of
|
||||
sparse matrices</A> for details on these entries.)
|
||||
|
||||
<P>Recalculating the likelihood ratio for a check with respect to some
|
||||
bit may appear time consuming, requiring that all possible
|
||||
combinations of values for the other bits participating in the check
|
||||
be considered. Fortunately, there is a short cut. One can calculate
|
||||
<BLOCKQUOTE>
|
||||
<I>t</I>
|
||||
= product of [ 1 / (1+<I>p<SUB><SMALL>i</SMALL></SUB></I>)
|
||||
- <I>p<SUB><SMALL>i</SMALL></SUB></I> /
|
||||
(1+<I>p<SUB><SMALL>i</SMALL></SUB></I>) ]
|
||||
= product of [ 2 / (1+<I>p<SUB><SMALL>i</SMALL></SUB></I>) - 1 ]
|
||||
</BLOCKQUOTE>
|
||||
where the product is over the probability ratios
|
||||
<I>p<SUB><SMALL>i</SMALL></SUB></I> for the other bits participating
|
||||
in this check. Factor <I>i</I> in this product is equal to probability
|
||||
of bit <I>i</I> being 0 minus the probability that it is 1. The terms
|
||||
in the expansion of this product (in the first form above) correspond to
|
||||
possible combinations of values for the other bits, with the result that
|
||||
<I>t</I> will be the probability of the check being satisfied if the bit
|
||||
in question is 0 minus the probability if the bit in question is 1. The
|
||||
likelihood ratio for this check with respect to the bit in question can then
|
||||
be calculated as (1-<I>t</I>)/(1+<I>t</I>).
|
||||
|
||||
<P>For a particular check, the product above differs for different
|
||||
bits, with respect to which we wish to calculate a likelihood ratio,
|
||||
only in that for each bit the factor corresponding to that bit is left
|
||||
out. We can calculate all these products easily by ordering the bits
|
||||
arbitrarily, computing running products of the factor for the first
|
||||
bit, the factors for the first two bits, etc., and also running
|
||||
products of the factor for the last bit, the factors for the last two
|
||||
bits, etc. Multiplying the running product of the factors up to
|
||||
<I>i</I>-1 by the running product of the factors from <I>i</I>+1 on
|
||||
gives the product needed for bit <I>i</I>. The second form of the
|
||||
factors above is used, as it requires less computation, and is still
|
||||
well defined even if some ratios are infinite.
|
||||
|
||||
<P>To recalculate the probability ratio for a bit with respect to a
|
||||
check, all that is need is to multiply together the likelihood ratio
|
||||
for this bit derived from the received data (see above), and the
|
||||
current values of the likelihood ratios for all the <I>other</I>
|
||||
checks that this bit participates in, with respect to this bit. To
|
||||
save time, these products are computed by combining forward and
|
||||
backward products, similarly to the method used for likelihood ratios.
|
||||
|
||||
<P>By including likelihood ratios from all checks, a similar
|
||||
calculation produces the current probability ratio for the bit to be 1
|
||||
versus 0 based on all information that has propagated to the bit so
|
||||
far. This ratio can be thresholded at one to produce the current best
|
||||
guess as to whether this bit is a 1 or a 0.
|
||||
|
||||
<P>The hope is that this algorithm will eventually converge to a state
|
||||
where these bit probabilities give a near-optimal decoding. This is
|
||||
does not always occur, but the algorithm behaves well enough to
|
||||
produce very good results at rates approaching (though not yet
|
||||
reaching) the theoretical Shannon limit.
|
||||
|
||||
|
||||
<P><A NAME="decode"><HR><B>decode</B>: Decode blocks of received data
|
||||
into codewords.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
decode [ -f ] [ -t | -T ] <I>pchk-file received-file decoded-file</I> [ <I>bp-file</I> ] <I>channel method</I>
|
||||
</PRE>
|
||||
<BLOCKQUOTE>
|
||||
where <TT><I>channel</I></TT> is one of:
|
||||
<BLOCKQUOTE><PRE>
|
||||
bsc <I>error-probability</I>
|
||||
|
||||
awgn <I>standard-deviation</I>
|
||||
|
||||
awln <I>width</I>
|
||||
</PRE></BLOCKQUOTE>
|
||||
and <TT><I>method</I></TT> is one of:
|
||||
<BLOCKQUOTE><PRE>
|
||||
enum-block <TT><I>gen-file</I></TT>
|
||||
|
||||
enum-bit <TT><I>gen-file</I></TT>
|
||||
|
||||
prprp <TT>[-]<I>max-iterations</I></TT>
|
||||
</PRE></BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P>Decodes the blocks in <TT><I>received-file</I></TT>, which are
|
||||
assumed to be have been received through the specified channel. The
|
||||
results written to <TT><I>decoded-file</I></TT> are the specified
|
||||
decoding method's guesses as to what bits were sent through the
|
||||
channel, given what was received. The probability of each bit being a
|
||||
1, as judged by the decoding method being used, is written to
|
||||
<TT><I>bp-file</I></TT>, if given.
|
||||
|
||||
<P>A newline is output at the end of each block written to
|
||||
<TT><I>decoded-file</I></TT> and <TT><I>bp-file</I></TT>. Newlines in
|
||||
<TT><I>received-file</I></TT> are ignored. A warning is displayed on
|
||||
standard error if the number of bits in <TT><I>received-file</I></TT>
|
||||
is not a multiple of the block length.
|
||||
|
||||
<P>A summary is displayed on standard error, giving the total number
|
||||
of blocks decoded, the number of blocks that decoded to valid
|
||||
codewords, the average number of iterations of the decoding algorithm
|
||||
used, and the percent of bits that were changed from the values one
|
||||
would guess for them based just on their individual likelihood ratios.
|
||||
|
||||
<P>If the <B>-t</B> option is given, a line of information regarding each block
|
||||
decoded is written to standard output, preceded by a line of headers.
|
||||
The information for each block is as follows:
|
||||
<BLOCKQUOTE>
|
||||
<TABLE>
|
||||
<tr align="left" valign="top">
|
||||
<td> <B>block</B> </td>
|
||||
<td>The number of the block, from zero</td></tr>
|
||||
<tr align="left" valign="top">
|
||||
<td> <B>iterations</B> </td>
|
||||
<td>The number of "iterations" used in decoding. What exactly an iteration
|
||||
is depends on the decoding method used (see
|
||||
<A HREF="decode-detail.html">here</A>).</td></tr>
|
||||
<tr align="left" valign="top">
|
||||
<td> <B>valid</B> </td>
|
||||
<td>Has the value 1 if the decoding is a valid codeword, 0 if not.</td></tr>
|
||||
<tr align="left" valign="top">
|
||||
<td> <B>changed</B> </td>
|
||||
<td>The number of bits in the decoding that differ from the bit that would
|
||||
be chosen based just on the likelihood ratio for that bit. Bits whose
|
||||
likelihood ratios are exactly one contribute 0.5 to this count.</td></tr>
|
||||
</TABLE>
|
||||
</BLOCKQUOTE>
|
||||
The file produced is is suitable for
|
||||
reading into the S-Plus or R statistics packages, with a command such as
|
||||
<BLOCKQUOTE><PRE>
|
||||
data <- read.table(<I>file</I>,header=T)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>If instead the <B>-T</B> option is given, detailed information on
|
||||
the process of decoding each block will be written to standard output.
|
||||
For a description, see the <A HREF="decode-detail.html">documentation
|
||||
on detailed decoding trace information</A>.
|
||||
|
||||
<P>The type of channel that is assumed is specified after the file
|
||||
name arguments. This may currently be either <TT>bsc</TT> (or
|
||||
<TT>BSC</TT>) for the Binary Symmetric Channel, or <TT>awgn</TT> (or
|
||||
<TT>AWGN</TT>) for the Additive White Gaussian Noise channel, or
|
||||
<TT>awln</TT> (or <TT>AWLN</TT>) for the Additive White Logistic Noise
|
||||
channel. The channel type is followed by an argument specifying the
|
||||
assumed characteristics of the channel, as follows:
|
||||
<BLOCKQUOTE>
|
||||
<P>BSC: The probability that a bit will be flipped by noise - ie, the
|
||||
probability that the bit received is an error.
|
||||
|
||||
<P>AWGN: The standard deviation of the Gaussian noise added to the
|
||||
encodings of the bits.
|
||||
|
||||
<P>AWLN: The width parameter of the logistic distribution for the noise
|
||||
that is added to the encodings of the bits.
|
||||
</BLOCKQUOTE>
|
||||
See the description of <A HREF="channel.html">channel transmission</A>
|
||||
for more about these channels.
|
||||
|
||||
<P>Following the channel specification is a specification of the
|
||||
decoding method to use. The <TT>enum-block</TT> and <TT>enum-bit</TT>
|
||||
methods find the optimal decoding by exhaustive enumeration of
|
||||
codewords derived from all possible source messages. They differ in
|
||||
that <TT>enum-block</TT> decodes to the most likely codeword, whereas
|
||||
<TT>enum-bit</TT> decodes to the bits that are individually most
|
||||
probable. These methods require that a file containing a
|
||||
representation of a generator matrix be given, to allow enumeration of
|
||||
codewords. If the parity check matrix has no redundant rows, any
|
||||
valid generator matrix will give the same decoding (except perhaps if
|
||||
there is a tie). If redundant rows exist, the generator matrix should
|
||||
specify the same set of message bits as the generator matrix that was
|
||||
used for the actual encoding, since the redundancy will lead to some
|
||||
codeword bits being fixed at zero (see <A HREF="dep-H.html">linear
|
||||
dependence in parity check matrices</A>).
|
||||
|
||||
<P>The <TT>prprp</TT> decoding method decodes using <A
|
||||
HREF="#prprp">probability propagation</A>. The maximum number of
|
||||
iterations of probability propagation to do is given following
|
||||
<TT>prprp</TT>. If a minus sign precedes this number, the maximum
|
||||
number of iterations is always done. If no minus sign is present, the
|
||||
algorithm stops once the tentative decoding, based on bit-by-bit
|
||||
probabilities, is a valid codeword. Note that continuing to the
|
||||
maximum number of iterations will usually result in
|
||||
at least slightly different bit probabilities (written to
|
||||
<TT><I>bp-file</I></TT> if specified), and could conceivably change
|
||||
the decoding compared to stopping at the first valid codeword, or
|
||||
result in a failure to decode to a valid codeword even though one was
|
||||
found earlier.
|
||||
|
||||
<P>If the <B>-f</B> option is given, output to <TT><I>decoded-file</I></TT>
|
||||
is flushed after each block. This allows one to use decode as a server,
|
||||
reading blocks to decode from a named pipe, and writing the decoded block
|
||||
to another named pipe.
|
||||
|
||||
|
||||
<P><A NAME="extract"><HR><B>extract</B>: Extract the message bits from a block.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
extract <I>gen-file decoded-file extracted-file</I>
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Given a file of codewords in <TT><I>decoded-file</I></TT> (usually,
|
||||
decoded blocks output by <A HREF="#decode"><TT>decode</TT></A>), and a
|
||||
generator matrix from <TT><I>gen-file</I></TT> (needed only to
|
||||
determine where the message bits are located in a codeword), this
|
||||
program writes the message bits extracted from these codewords to the
|
||||
file <TT><I>extracted-file</I></TT>.
|
||||
|
||||
<P>A newline is output at the end of each block written to
|
||||
<TT><I>extracted-file</I></TT>. Newlines in
|
||||
<TT><I>decoded-file</I></TT> are ignored. A warning is displayed on
|
||||
standard error if the number of bits in <TT><I>decoded-file</I></TT>
|
||||
is not a multiple of the block length.
|
||||
|
||||
<HR>
|
||||
|
||||
<A HREF="index.html">Back to index for LDPC software</A>
|
||||
|
||||
</BODY></HTML>
|
||||
@@ -8,7 +8,9 @@
|
||||
#include <QtGui>
|
||||
#endif
|
||||
|
||||
#include <QString>
|
||||
#include <QScopedPointer>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "Radio.hpp"
|
||||
|
||||
@@ -18,6 +20,7 @@ namespace Ui {
|
||||
|
||||
class QSettings;
|
||||
class Configuration;
|
||||
class QByteArray;
|
||||
|
||||
class LogQSO : public QDialog
|
||||
{
|
||||
@@ -30,7 +33,7 @@ public:
|
||||
QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
|
||||
QDateTime const& dateTimeOff,
|
||||
Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid,
|
||||
bool noSuffix, bool toRTTY, bool dBtoComments);
|
||||
bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, QString const& opCall);
|
||||
|
||||
public slots:
|
||||
void accept();
|
||||
@@ -40,7 +43,8 @@ signals:
|
||||
, Radio::Frequency dial_freq, QString const& mode
|
||||
, QString const& rpt_sent, QString const& rpt_received
|
||||
, QString const& tx_power, QString const& comments
|
||||
, QString const& name, QDateTime const& QSO_date_on);
|
||||
, QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
|
||||
, QString const& my_call, QString const& my_grid, QByteArray const& ADIF);
|
||||
|
||||
protected:
|
||||
void hideEvent (QHideEvent *);
|
||||
@@ -1,238 +0,0 @@
|
||||
program ldpcsim174
|
||||
! End to end test of the (174,75)/crc12 encoder and decoder.
|
||||
use crc
|
||||
use packjt
|
||||
|
||||
parameter(NRECENT=10)
|
||||
character*12 recent_calls(NRECENT)
|
||||
character*22 msg,msgsent,msgreceived
|
||||
character*8 arg
|
||||
integer*1, allocatable :: codeword(:), decoded(:), message(:)
|
||||
integer*1, target:: i1Msg8BitBytes(11)
|
||||
integer*1 msgbits(87)
|
||||
integer*1 apmask(174), cw(174)
|
||||
integer*2 checksum
|
||||
integer*4 i4Msg6BitWords(13)
|
||||
integer colorder(174)
|
||||
integer nerrtot(174),nerrdec(174),nmpcbad(87)
|
||||
logical checksumok,fsk,bpsk
|
||||
real*8, allocatable :: rxdata(:)
|
||||
real, allocatable :: llr(:)
|
||||
|
||||
data colorder/ &
|
||||
0, 1, 2, 3, 30, 4, 5, 6, 7, 8, 9, 10, 11, 32, 12, 40, 13, 14, 15, 16,&
|
||||
17, 18, 37, 45, 29, 19, 20, 21, 41, 22, 42, 31, 33, 34, 44, 35, 47, 51, 50, 43,&
|
||||
36, 52, 63, 46, 25, 55, 27, 24, 23, 53, 39, 49, 59, 38, 48, 61, 60, 57, 28, 62,&
|
||||
56, 58, 65, 66, 26, 70, 64, 69, 68, 67, 74, 71, 54, 76, 72, 75, 78, 77, 80, 79,&
|
||||
73, 83, 84, 81, 82, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,&
|
||||
100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,&
|
||||
120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,&
|
||||
140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,&
|
||||
160,161,162,163,164,165,166,167,168,169,170,171,172,173/
|
||||
|
||||
do i=1,NRECENT
|
||||
recent_calls(i)=' '
|
||||
enddo
|
||||
nerrtot=0
|
||||
nerrdec=0
|
||||
nmpcbad=0 ! Used to collect the number of errors in the message+crc part of the codeword
|
||||
|
||||
nargs=iargc()
|
||||
if(nargs.ne.4) then
|
||||
print*,'Usage: ldpcsim niter norder #trials s '
|
||||
print*,'eg: ldpcsim 10 2 1000 0.84'
|
||||
print*,'belief propagation iterations: niter, ordered-statistics order: norder'
|
||||
print*,'If s is negative, then value is ignored and sigma is calculated from SNR.'
|
||||
return
|
||||
endif
|
||||
call getarg(1,arg)
|
||||
read(arg,*) max_iterations
|
||||
call getarg(2,arg)
|
||||
read(arg,*) norder
|
||||
call getarg(3,arg)
|
||||
read(arg,*) ntrials
|
||||
call getarg(4,arg)
|
||||
read(arg,*) s
|
||||
|
||||
fsk=.false.
|
||||
bpsk=.true.
|
||||
|
||||
! don't count crc bits as data bits
|
||||
N=174
|
||||
K=87
|
||||
! scale Eb/No for a (174,87) code
|
||||
rate=real(K)/real(N)
|
||||
|
||||
write(*,*) "rate: ",rate
|
||||
write(*,*) "niter= ",max_iterations," s= ",s
|
||||
|
||||
allocate ( codeword(N), decoded(K), message(K) )
|
||||
allocate ( rxdata(N), llr(N) )
|
||||
|
||||
msg="K1JT K9AN EN50"
|
||||
! msg="G4WJS K9AN EN50"
|
||||
call packmsg(msg,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes
|
||||
call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent
|
||||
write(*,*) "message sent ",msgsent
|
||||
|
||||
i4=0
|
||||
ik=0
|
||||
im=0
|
||||
do i=1,12
|
||||
nn=i4Msg6BitWords(i)
|
||||
do j=1, 6
|
||||
ik=ik+1
|
||||
i4=i4+i4+iand(1,ishft(nn,j-6))
|
||||
i4=iand(i4,255)
|
||||
if(ik.eq.8) then
|
||||
im=im+1
|
||||
! if(i4.gt.127) i4=i4-256
|
||||
i1Msg8BitBytes(im)=i4
|
||||
ik=0
|
||||
endif
|
||||
enddo
|
||||
enddo
|
||||
|
||||
i1Msg8BitBytes(10:11)=0
|
||||
checksum = crc12 (c_loc (i1Msg8BitBytes), 11)
|
||||
! For reference, the next 3 lines show how to check the CRC
|
||||
i1Msg8BitBytes(10)=checksum/256
|
||||
i1Msg8BitBytes(11)=iand (checksum,255)
|
||||
checksumok = crc12_check(c_loc (i1Msg8BitBytes), 11)
|
||||
if( checksumok ) write(*,*) 'Good checksum'
|
||||
|
||||
! K=87, For now:
|
||||
! msgbits(1:72) JT message bits
|
||||
! msgbits(73:75) 3 free message bits (set to 0)
|
||||
! msgbits(76:87) CRC12
|
||||
mbit=0
|
||||
do i=1, 9
|
||||
i1=i1Msg8BitBytes(i)
|
||||
do ibit=1,8
|
||||
mbit=mbit+1
|
||||
msgbits(mbit)=iand(1,ishft(i1,ibit-8))
|
||||
enddo
|
||||
enddo
|
||||
msgbits(73:75)=0 ! the three extra message bits go here
|
||||
i1=i1Msg8BitBytes(10) ! First 4 bits of crc12 are LSB of this byte
|
||||
do ibit=1,4
|
||||
msgbits(75+ibit)=iand(1,ishft(i1,ibit-4))
|
||||
enddo
|
||||
i1=i1Msg8BitBytes(11) ! Now shift in last 8 bits of the CRC
|
||||
do ibit=1,8
|
||||
msgbits(79+ibit)=iand(1,ishft(i1,ibit-8))
|
||||
enddo
|
||||
|
||||
write(*,*) 'message'
|
||||
write(*,'(11(8i1,1x))') msgbits
|
||||
|
||||
call encode174(msgbits,codeword)
|
||||
call init_random_seed()
|
||||
call sgran()
|
||||
|
||||
write(*,*) 'codeword'
|
||||
write(*,'(22(8i1,1x))') codeword
|
||||
|
||||
write(*,*) "Es/N0 SNR2500 ngood nundetected nbadcrc sigma"
|
||||
do idb = 20,-10,-1
|
||||
db=idb/2.0-1.0
|
||||
sigma=1/sqrt( 2*(10**(db/10.0)) )
|
||||
ngood=0
|
||||
nue=0
|
||||
nbadcrc=0
|
||||
nberr=0
|
||||
do itrial=1, ntrials
|
||||
! Create a realization of a noisy received word
|
||||
do i=1,N
|
||||
if( bpsk ) then
|
||||
rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran()
|
||||
elseif( fsk ) then
|
||||
if( codeword(i) .eq. 1 ) then
|
||||
r1=(1.0 + sigma*gran())**2 + (sigma*gran())**2
|
||||
r2=(sigma*gran())**2 + (sigma*gran())**2
|
||||
elseif( codeword(i) .eq. 0 ) then
|
||||
r2=(1.0 + sigma*gran())**2 + (sigma*gran())**2
|
||||
r1=(sigma*gran())**2 + (sigma*gran())**2
|
||||
endif
|
||||
! rxdata(i)=0.35*(sqrt(r1)-sqrt(r2))
|
||||
! rxdata(i)=0.35*(exp(r1)-exp(r2))
|
||||
rxdata(i)=0.12*(log(r1)-log(r2))
|
||||
endif
|
||||
enddo
|
||||
nerr=0
|
||||
do i=1,N
|
||||
if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1
|
||||
enddo
|
||||
nerrtot(nerr)=nerrtot(nerr)+1
|
||||
nberr=nberr+nerr
|
||||
|
||||
! Correct signal normalization is important for this decoder.
|
||||
rxav=sum(rxdata)/N
|
||||
rx2av=sum(rxdata*rxdata)/N
|
||||
rxsig=sqrt(rx2av-rxav*rxav)
|
||||
rxdata=rxdata/rxsig
|
||||
! To match the metric to the channel, s should be set to the noise standard deviation.
|
||||
! For now, set s to the value that optimizes decode probability near threshold.
|
||||
! The s parameter can be tuned to trade a few tenth's dB of threshold for an order of
|
||||
! magnitude in UER
|
||||
if( s .lt. 0 ) then
|
||||
ss=sigma
|
||||
else
|
||||
ss=s
|
||||
endif
|
||||
|
||||
llr=2.0*rxdata/(ss*ss)
|
||||
nap=0 ! number of AP bits
|
||||
llr(colorder(174-87+1:174-87+nap)+1)=5*(2.0*msgbits(1:nap)-1.0)
|
||||
apmask=0
|
||||
apmask(colorder(174-87+1:174-87+nap)+1)=1
|
||||
|
||||
! max_iterations is max number of belief propagation iterations
|
||||
call bpdecode174(llr, apmask, max_iterations, decoded, cw, nharderrors)
|
||||
if( norder .ge. 0 .and. nharderrors .lt. 0 ) call osd174(llr, norder, decoded, cw, nharderrors)
|
||||
! If the decoder finds a valid codeword, nharderrors will be .ge. 0.
|
||||
if( nharderrors .ge. 0 ) then
|
||||
call extractmessage174(decoded,msgreceived,ncrcflag,recent_calls,nrecent)
|
||||
if( ncrcflag .ne. 1 ) then
|
||||
nbadcrc=nbadcrc+1
|
||||
endif
|
||||
|
||||
nueflag=0
|
||||
nerrmpc=0
|
||||
do i=1,K ! find number of errors in message+crc part of codeword
|
||||
if( msgbits(i) .ne. decoded(i) ) then
|
||||
nueflag=1
|
||||
nerrmpc=nerrmpc+1
|
||||
endif
|
||||
enddo
|
||||
nmpcbad(nerrmpc)=nmpcbad(nerrmpc)+1
|
||||
|
||||
if( ncrcflag .eq. 1 ) then
|
||||
if( nueflag .eq. 0 ) then
|
||||
ngood=ngood+1
|
||||
nerrdec(nerr)=nerrdec(nerr)+1
|
||||
else if( nueflag .eq. 1 ) then
|
||||
nue=nue+1;
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
enddo
|
||||
baud=12000/2048
|
||||
snr2500=db+10.0*log10((baud/2500.0))
|
||||
pberr=real(nberr)/(real(ntrials*N))
|
||||
write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2,8x,e10.3)") db,snr2500,ngood,nue,nbadcrc,ss,pberr
|
||||
|
||||
enddo
|
||||
|
||||
open(unit=23,file='nerrhisto.dat',status='unknown')
|
||||
do i=1,174
|
||||
write(23,'(i4,2x,i10,i10,f10.2)') i,nerrdec(i),nerrtot(i),real(nerrdec(i))/real(nerrtot(i)+1e-10)
|
||||
enddo
|
||||
close(23)
|
||||
open(unit=25,file='nmpcbad.dat',status='unknown')
|
||||
do i=1,87
|
||||
write(25,'(i4,2x,i10)') i,nmpcbad(i)
|
||||
enddo
|
||||
close(25)
|
||||
|
||||
end program ldpcsim174
|
||||
@@ -1,41 +0,0 @@
|
||||
// -*- Mode: C++ -*-
|
||||
#ifndef DISPLAYTEXT_H
|
||||
#define DISPLAYTEXT_H
|
||||
|
||||
#include <QTextEdit>
|
||||
#include <QFont>
|
||||
|
||||
#include "logbook/logbook.h"
|
||||
#include "decodedtext.h"
|
||||
|
||||
class DisplayText
|
||||
: public QTextEdit
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DisplayText(QWidget *parent = 0);
|
||||
|
||||
void setContentFont (QFont const&);
|
||||
void insertLineSpacer(QString const&);
|
||||
void displayDecodedText(DecodedText decodedText, QString myCall, bool displayDXCCEntity,
|
||||
LogBook logBook, QColor color_CQ, QColor color_MyCall,
|
||||
QColor color_DXCC, QColor color_NewCall);
|
||||
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
|
||||
QColor color_TxMsg, bool bFastMode);
|
||||
void displayQSY(QString text);
|
||||
|
||||
Q_SIGNAL void selectCallsign (bool alt, bool ctrl);
|
||||
|
||||
Q_SLOT void appendText (QString const& text, QColor bg = Qt::white);
|
||||
|
||||
protected:
|
||||
void mouseDoubleClickEvent(QMouseEvent *e);
|
||||
|
||||
private:
|
||||
QString appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg, LogBook logBook,
|
||||
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
|
||||
|
||||
QFont char_font_;
|
||||
};
|
||||
|
||||
#endif // DISPLAYTEXT_H
|
||||
@@ -1,100 +0,0 @@
|
||||
program ft8sim
|
||||
|
||||
! Generate simulated data for a 15-second HF/6m mode using 8-FSK.
|
||||
! Output is saved to a *.wav file.
|
||||
|
||||
use wavhdr
|
||||
include 'ft8_params.f90' !Set various constants
|
||||
type(hdr) h !Header for .wav file
|
||||
character arg*12,fname*17
|
||||
character msg*22,msgsent*22
|
||||
complex c0(0:NMAX-1)
|
||||
complex c(0:NMAX-1)
|
||||
integer itone(NN)
|
||||
integer*2 iwave(NMAX) !Generated full-length waveform
|
||||
|
||||
! Get command-line argument(s)
|
||||
nargs=iargc()
|
||||
if(nargs.ne.6) then
|
||||
print*,'Usage: ft8sim "message" DT fdop del nfiles snr'
|
||||
print*,'Example: ft8sim "K1ABC W9XYZ EN37" 0.0 0.1 1.0 10 -18'
|
||||
go to 999
|
||||
endif
|
||||
call getarg(1,msg) !Message to be transmitted
|
||||
call getarg(2,arg)
|
||||
read(arg,*) xdt !Time offset from nominal (s)
|
||||
call getarg(3,arg)
|
||||
read(arg,*) fspread !Watterson frequency spread (Hz)
|
||||
call getarg(4,arg)
|
||||
read(arg,*) delay !Watterson delay (ms)
|
||||
call getarg(5,arg)
|
||||
read(arg,*) nfiles !Number of files
|
||||
call getarg(6,arg)
|
||||
read(arg,*) snrdb !SNR_2500
|
||||
|
||||
twopi=8.0*atan(1.0)
|
||||
fs=12000.0 !Sample rate (Hz)
|
||||
dt=1.0/fs !Sample interval (s)
|
||||
tt=NSPS*dt !Duration of symbols (s)
|
||||
baud=1.0/tt !Keying rate (baud)
|
||||
bw=8*baud !Occupied bandwidth (Hz)
|
||||
txt=NZ*dt !Transmission length (s)
|
||||
bandwidth_ratio=2500.0/(fs/2.0)
|
||||
sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb)
|
||||
if(snrdb.gt.90.0) sig=1.0
|
||||
txt=NN*NSPS/12000.0
|
||||
|
||||
call genft8(msg,msgsent,itone) !Source-encode, then get itone()
|
||||
write(*,1000) f0,xdt,txt,snrdb,bw,msgsent
|
||||
1000 format('f0:',f9.3,' DT:',f6.2,' TxT:',f6.1,' SNR:',f6.1, &
|
||||
' BW:',f4.1,2x,a22)
|
||||
|
||||
! call sgran()
|
||||
c=0.
|
||||
do ifile=1,nfiles
|
||||
|
||||
c0=0.
|
||||
do isig=1,25
|
||||
f0=(isig+2)*100.0
|
||||
phi=0.0
|
||||
k=-1 + nint(xdt/dt)
|
||||
do j=1,NN !Generate complex waveform
|
||||
dphi=twopi*(f0+itone(j)*baud)*dt
|
||||
if(k.eq.0) phi=-dphi
|
||||
do i=1,NSPS
|
||||
k=k+1
|
||||
phi=phi+dphi
|
||||
if(phi.gt.twopi) phi=phi-twopi
|
||||
xphi=phi
|
||||
if(k.ge.0 .and. k.lt.NMAX) c0(k)=cmplx(cos(xphi),sin(xphi))
|
||||
enddo
|
||||
enddo
|
||||
if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c,NZ,fs,delay,fspread)
|
||||
c=c+c0
|
||||
enddo
|
||||
c=c*sig
|
||||
if(snrdb.lt.90) then
|
||||
do i=0,NZ-1 !Add gaussian noise at specified SNR
|
||||
xnoise=gran()
|
||||
ynoise=gran()
|
||||
c(i)=c(i) + cmplx(xnoise,ynoise)
|
||||
enddo
|
||||
endif
|
||||
|
||||
fac=32767.0
|
||||
rms=100.0
|
||||
if(snrdb.ge.90.0) iwave(1:NMAX)=nint(fac*real(c))
|
||||
if(snrdb.lt.90.0) iwave(1:NMAX)=nint(rms*real(c))
|
||||
iwave(NZ+1:)=0
|
||||
|
||||
h=default_header(12000,NMAX)
|
||||
write(fname,1102) ifile
|
||||
1102 format('000000_',i6.6,'.wav')
|
||||
open(10,file=fname,status='unknown',access='stream')
|
||||
write(10) h,iwave !Save to *.wav file
|
||||
close(10)
|
||||
write(*,1110) ifile,xdt,f0,snrdb,fname
|
||||
1110 format(i4,f7.2,f8.2,f7.1,2x,a17)
|
||||
enddo
|
||||
|
||||
999 end program ft8sim
|
||||
@@ -37,7 +37,8 @@ contains
|
||||
|
||||
subroutine decode(this,callback,dd0,npts,newdat,nutc,nf1,nf2,nfqso, &
|
||||
ntol,nsubmode,minsync,nagain,n2pass,nrobust,ntrials,naggressive, &
|
||||
ndepth,emedelay,clearave,mycall,hiscall,hisgrid,nexp_decode)
|
||||
ndepth,emedelay,clearave,mycall,hiscall,hisgrid,nexp_decode, &
|
||||
nQSOProgress,ljt65apon)
|
||||
|
||||
! Process dd0() data to find and decode JT65 signals.
|
||||
|
||||
@@ -51,8 +52,8 @@ contains
|
||||
real, intent(in) :: dd0(NZMAX),emedelay
|
||||
integer, intent(in) :: npts, nutc, nf1, nf2, nfqso, ntol &
|
||||
, nsubmode, minsync, n2pass, ntrials, naggressive, ndepth &
|
||||
, nexp_decode
|
||||
logical, intent(in) :: newdat, nagain, nrobust, clearave
|
||||
, nexp_decode, nQSOProgress
|
||||
logical, intent(in) :: newdat, nagain, nrobust, clearave, ljt65apon
|
||||
character(len=12), intent(in) :: mycall, hiscall
|
||||
character(len=6), intent(in) :: hisgrid
|
||||
|
||||
@@ -120,9 +121,26 @@ contains
|
||||
go to 900
|
||||
endif
|
||||
|
||||
! do ipass=1,n2pass !Two-pass decoding loop
|
||||
single_decode=iand(nexp_decode,32).ne.0 .or. nagain
|
||||
bVHF=iand(nexp_decode,64).ne.0
|
||||
|
||||
if( bVHF ) then
|
||||
nvec=ntrials
|
||||
npass=1
|
||||
if(n2pass .gt. 1) npass=ndepth+1 !**** TEMPORARY ****
|
||||
if(n2pass.gt.1) npass=2
|
||||
else
|
||||
nvec=1000
|
||||
if(ndepth.eq.1) then
|
||||
npass=2
|
||||
nvec=100
|
||||
elseif(ndepth.eq.2) then
|
||||
npass=2
|
||||
nvec=1000
|
||||
else
|
||||
npass=4
|
||||
nvec=1000
|
||||
endif
|
||||
endif
|
||||
do ipass=1,npass
|
||||
first_time=.true.
|
||||
if(ipass.eq.1) then !First-pass parameters
|
||||
@@ -149,13 +167,10 @@ contains
|
||||
|
||||
call timer('symsp65 ',0)
|
||||
ss=0.
|
||||
! call symspec65(dd,npts,ss,nqsym,savg) !Get normalized symbol spectra
|
||||
call symspec65(dd,npts,nqsym,savg) !Get normalized symbol spectra
|
||||
call timer('symsp65 ',1)
|
||||
nfa=nf1
|
||||
nfb=nf2
|
||||
single_decode=iand(nexp_decode,32).ne.0 .or. nagain
|
||||
bVHF=iand(nexp_decode,64).ne.0
|
||||
|
||||
!### Q: should either of the next two uses of "single_decode" be "bVHF" instead?
|
||||
if(single_decode .or. (bVHF .and. ntol.lt.1000)) then
|
||||
@@ -177,7 +192,6 @@ contains
|
||||
|
||||
ncand=0
|
||||
call timer('sync65 ',0)
|
||||
! call sync65(ss,nfa,nfb,naggressive,ntol,nqsym,ca,ncand,0,bVHF)
|
||||
call sync65(nfa,nfb,naggressive,ntol,nqsym,ca,ncand,nrob,bVHF)
|
||||
call timer('sync65 ',1)
|
||||
|
||||
@@ -187,7 +201,6 @@ contains
|
||||
if(ncand.eq.0) ncand=1
|
||||
if(abs(ca(1)%freq - f0).gt.width) width=2*df !### ??? ###
|
||||
endif
|
||||
nvec=ntrials
|
||||
|
||||
mode65=2**nsubmode
|
||||
nflip=1
|
||||
@@ -213,7 +226,6 @@ contains
|
||||
sync1=ca(icand)%sync
|
||||
dtx=ca(icand)%dt
|
||||
freq=ca(icand)%freq
|
||||
!write(*,*) icand,sync1,dtx,freq,ndepth,bVHF,mode65
|
||||
if(bVHF) then
|
||||
flip=ca(icand)%flip
|
||||
nflip=flip
|
||||
@@ -225,8 +237,8 @@ contains
|
||||
nft=0
|
||||
nspecial=0
|
||||
call decode65a(dd,npts,first_time,nqd,freq,nflip,mode65,nvec, &
|
||||
naggressive,ndepth,ntol,mycall,hiscall,hisgrid, &
|
||||
nexp_decode,bVHF,sync2,a,dtx,nft,nspecial,qual, &
|
||||
naggressive,ndepth,ntol,mycall,hiscall,hisgrid,nQSOProgress, &
|
||||
ljt65apon,nexp_decode,bVHF,sync2,a,dtx,nft,nspecial,qual, &
|
||||
nhist,nsmo,decoded)
|
||||
if(nspecial.eq.2) decoded='RO'
|
||||
if(nspecial.eq.3) decoded='RRR'
|
||||
@@ -244,7 +256,9 @@ contains
|
||||
nfreq=nint(freq+a(1))
|
||||
ndrift=nint(2.0*a(2))
|
||||
if(bVHF) then
|
||||
s2db=sync1 - 30.0 + db(width/3.3) !### VHF/UHF/microwave
|
||||
xtmp=10**((sync1+16.0)/10.0) ! sync comes to us in dB
|
||||
s2db=1.1*db(xtmp)+1.4*(dB(width)-4.3)-52.0
|
||||
! s2db=sync1 - 30.0 + db(width/3.3) !### VHF/UHF/microwave
|
||||
if(nspecial.gt.0) s2db=sync2
|
||||
else
|
||||
s2db=10.0*log10(sync2) - 35 !### Empirical (HF)
|
||||
@@ -254,6 +268,7 @@ contains
|
||||
if(nsnr.gt.-1) nsnr=-1
|
||||
nftt=0
|
||||
|
||||
!********* DOES THIS STILL WORK WHEN NFT INCLUDES # OF AP SYMBOLS USED??
|
||||
if(nft.ne.1 .and. iand(ndepth,16).eq.16 .and. (.not.prtavg)) then
|
||||
! Single-sequence FT decode failed, so try for an average FT decode.
|
||||
if(nutc.ne.nutc0 .or. abs(nfreq-nfreq0).gt.ntol) then
|
||||
@@ -264,7 +279,8 @@ contains
|
||||
nsave=mod(nsave-1,64)+1
|
||||
call avg65(nutc,nsave,sync1,dtx,nflip,nfreq,mode65,ntol, &
|
||||
ndepth,nagain,ntrials,naggressive,clearave,neme,mycall, &
|
||||
hiscall,hisgrid,nftt,avemsg,qave,deepave,nsum,ndeepave)
|
||||
hiscall,hisgrid,nftt,avemsg,qave,deepave,nsum,ndeepave, &
|
||||
nQSOProgress,ljt65apon)
|
||||
nsmo=param(9)
|
||||
nqave=qave
|
||||
|
||||
@@ -329,13 +345,13 @@ contains
|
||||
endif
|
||||
enddo !Candidate loop
|
||||
if(ipass.eq.2 .and. ndecoded.lt.1) exit
|
||||
enddo !Two-pass loop
|
||||
enddo !Multiple-pass loop
|
||||
900 return
|
||||
end subroutine decode
|
||||
|
||||
subroutine avg65(nutc,nsave,snrsync,dtxx,nflip,nfreq,mode65,ntol,ndepth, &
|
||||
nagain, ntrials,naggressive,clearave,neme,mycall,hiscall,hisgrid,nftt, &
|
||||
avemsg,qave,deepave,nsum,ndeepave)
|
||||
avemsg,qave,deepave,nsum,ndeepave,nQSOProgress,ljt65apon)
|
||||
|
||||
! Decodes averaged JT65 data
|
||||
|
||||
@@ -358,7 +374,7 @@ contains
|
||||
real s3c(64,63)
|
||||
real dtsave(MAXAVE)
|
||||
real syncsave(MAXAVE)
|
||||
logical first,clearave
|
||||
logical first,clearave,ljt65apon
|
||||
data first/.true./
|
||||
save
|
||||
|
||||
@@ -475,7 +491,8 @@ contains
|
||||
|
||||
nadd=nsum*ismo
|
||||
call extract(s3c,nadd,mode65,ntrials,naggressive,ndepth,nflip,mycall, &
|
||||
hiscall,hisgrid,nexp_decode,ncount,nhist,avemsg,ltext,nftt,qual)
|
||||
hiscall,hisgrid,nQSOProgress,ljt65apon,nexp_decode,ncount,nhist, &
|
||||
avemsg,ltext,nftt,qual)
|
||||
if(nftt.eq.1) then
|
||||
nsmo=ismo
|
||||
param(9)=nsmo
|
||||
@@ -54,7 +54,7 @@ subroutine genwspr5(msg,msgsent,itone)
|
||||
|
||||
! Message structure:
|
||||
! I channel: R1 48*(S1+D1) S13 48*(D1+S1) R1
|
||||
! Q channel: R1 D109 R1
|
||||
! Q channel: R1 D204 R1
|
||||
! Generate QPSK with no offset, then shift the y array to get OQPSK.
|
||||
|
||||
! I channel:
|
||||
@@ -1,16 +0,0 @@
|
||||
function stdmsg(msg0,bcontest,mygrid)
|
||||
|
||||
use iso_c_binding, only: c_bool
|
||||
use packjt
|
||||
character*22 msg0,msg
|
||||
character*6 mygrid
|
||||
integer dat(12)
|
||||
logical(c_bool), value :: bcontest
|
||||
logical(c_bool) :: stdmsg
|
||||
|
||||
call packmsg(msg0,dat,itype,logical(bcontest))
|
||||
call unpackmsg(dat,msg,logical(bcontest),mygrid)
|
||||
stdmsg=(msg.eq.msg0) .and. (itype.ge.0) .and. itype.ne.6
|
||||
|
||||
return
|
||||
end function stdmsg
|
||||
@@ -48,12 +48,12 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbRxOnly">
|
||||
<widget class="QRadioButton" name="rbOwnEcho">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Both stations do full correction to their QSO partner's grid square during receive, no correction is applied on transmit.</p><p>This mode facilitates accurate Doppler shift correction when one or both stations have a rig that does not accept CAT QSY commands while transmitting.</p></body></html></string>
|
||||
<string><html><head/><body><p>Transmit takes place on sked frequency and receive frequency is corrected for own echoes. </p><p>This mode can be used for calling CQ, or when using Echo mode.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Receive only</string>
|
||||
<string>Own Echo</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -69,6 +69,32 @@
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbOnDxEcho">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>DX station announces their TX Freq, which is entered as the Sked Freq. Correction applied to RX and TX so you appear on the DX's station's own echo Freq.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>On DX Echo</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbCallDx">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Tune radio manually and select this mode to put your echo on the same frequency.</p><p>If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Call DX</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="rbNoDoppler">
|
||||
@@ -0,0 +1,36 @@
|
||||
subroutine foxfilt(nslots,nfreq,width,wave)
|
||||
|
||||
parameter (NN=79,ND=58,KK=87,NSPS=4*1920)
|
||||
parameter (NWAVE=NN*NSPS,NFFT=614400,NH=NFFT/2)
|
||||
real wave(NWAVE)
|
||||
real x(NFFT)
|
||||
complex cx(0:NH)
|
||||
equivalence (x,cx)
|
||||
|
||||
x(1:NWAVE)=wave
|
||||
x(NWAVE+1:)=0.
|
||||
call four2a(x,NFFT,1,-1,0) !r2c
|
||||
df=48000.0/NFFT
|
||||
fa=nfreq - 0.5*6.25
|
||||
fb=nfreq + 7.5*6.25 + (nslots-1)*60.0
|
||||
ia2=nint(fa/df)
|
||||
ib1=nint(fb/df)
|
||||
ia1=nint(ia2-width/df)
|
||||
ib2=nint(ib1+width/df)
|
||||
pi=4.0*atan(1.0)
|
||||
do i=ia1,ia2
|
||||
fil=(1.0 + cos(pi*df*(i-ia2)/width))/2.0
|
||||
cx(i)=fil*cx(i)
|
||||
enddo
|
||||
do i=ib1,ib2
|
||||
fil=(1.0 + cos(pi*df*(i-ib1)/width))/2.0
|
||||
cx(i)=fil*cx(i)
|
||||
enddo
|
||||
cx(0:ia1-1)=0.
|
||||
cx(ib2+1:)=0.
|
||||
|
||||
call four2a(cx,nfft,1,1,-1) !c2r
|
||||
wave=x(1:NWAVE)/nfft
|
||||
|
||||
return
|
||||
end subroutine foxfilt
|
||||
|
Before Width: | Height: | Size: 33 KiB |
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>374</width>
|
||||
<height>229</height>
|
||||
<width>377</width>
|
||||
<height>257</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
@@ -351,6 +351,45 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="operatorLabel">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Operator</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="loggedOperator">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@@ -1,266 +0,0 @@
|
||||
/* RAND-TEST.C - Program to test random number generators. */
|
||||
|
||||
/* Copyright (c) 1995-2012 by Radford M. Neal.
|
||||
*
|
||||
* Permission is granted for anyone to copy, use, modify, and distribute
|
||||
* these programs and accompanying documents for any purpose, provided
|
||||
* this copyright notice is retained and prominently displayed, and note
|
||||
* is made of any changes made to these programs. These programs and
|
||||
* documents are distributed without any warranty, express or implied.
|
||||
* As the programs were written for research purposes only, they have not
|
||||
* been tested to the degree that would be advisable in any important
|
||||
* application. All use of these programs is entirely at the user's own
|
||||
* risk.
|
||||
*/
|
||||
|
||||
|
||||
/* Usage:
|
||||
|
||||
rand-test seed generator { parameters } / sample-size [ low high bins ]
|
||||
|
||||
Using the seed given, tests the random number generator identified by
|
||||
the second argument, for the parameter values specified. The possible
|
||||
generators and required parameters are as follows:
|
||||
|
||||
uniform Uniform from [0,1)
|
||||
uniopen Uniform from (0,1)
|
||||
int n Uniform from the set { 0, 1, ..., (n-1) }
|
||||
gaussian From Gaussian with mean zero and unit variance
|
||||
exp From exponential with mean one
|
||||
cauchy From Cauchy centred at zero with unit width
|
||||
gamma alpha From Gamma with shape parameter (and mean) alpha
|
||||
beta a b From Beta with parameters a and b
|
||||
|
||||
The size of the sample to use is also specified. The program reports
|
||||
the mean and variance of the sample. A histogram is also printed if a
|
||||
low and high range and number of bins are for it are specified.
|
||||
|
||||
These tests are not really adequate to detect subtle forms of bias due
|
||||
to use of pseudo-random numbers, but are hopefully good enough to find
|
||||
most programming errors.
|
||||
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "rand.h"
|
||||
|
||||
|
||||
#define Max_bins 1000 /* Maximum number of histogram bins */
|
||||
|
||||
static void usage (void);
|
||||
|
||||
|
||||
/* MAIN PROGRAM. */
|
||||
|
||||
main
|
||||
( int argc,
|
||||
char **argv
|
||||
)
|
||||
{
|
||||
int seed, sample_size, bins, np;
|
||||
double low, high;
|
||||
char *generator;
|
||||
double p1, p2;
|
||||
|
||||
double mean, variance;
|
||||
double tmean, tvariance;
|
||||
int undef_mean, undef_variance;
|
||||
|
||||
int count[Max_bins];
|
||||
int under, over;
|
||||
|
||||
char **ap;
|
||||
double x;
|
||||
int i, n;
|
||||
|
||||
bins = 0;
|
||||
|
||||
if (argc<5) usage();
|
||||
|
||||
if ((seed = atoi(argv[1]))==0 && strcmp(argv[1],"0")!=0) usage();
|
||||
|
||||
generator = argv[2];
|
||||
|
||||
if (strcmp(generator,"uniform")==0) np = 0;
|
||||
else if (strcmp(generator,"uniopen")==0) np = 0;
|
||||
else if (strcmp(generator,"int")==0) np = 1;
|
||||
else if (strcmp(generator,"poisson")==0) np = 1;
|
||||
else if (strcmp(generator,"gaussian")==0) np = 0;
|
||||
else if (strcmp(generator,"exp")==0) np = 0;
|
||||
else if (strcmp(generator,"cauchy")==0) np = 0;
|
||||
else if (strcmp(generator,"gamma")==0) np = 1;
|
||||
else if (strcmp(generator,"beta")==0) np = 2;
|
||||
else
|
||||
{ fprintf(stderr,"Unknown generator: %s\n",generator);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ap = argv+3;
|
||||
|
||||
if (np>0)
|
||||
{ if (*ap==0 || (p1 = atof(*ap++))<=0) usage();
|
||||
}
|
||||
if (np>1)
|
||||
{ if (*ap==0 || (p2 = atof(*ap++))<=0) usage();
|
||||
}
|
||||
|
||||
if (*ap==0 || strcmp(*ap++,"/")!=0) usage();
|
||||
|
||||
if (*ap==0 || (sample_size = atoi(*ap++))<=0) usage();
|
||||
|
||||
if (*ap!=0)
|
||||
{ low = atof(*ap++);
|
||||
if (*ap==0) usage();
|
||||
high = atof(*ap++);
|
||||
if (high<=low) usage();
|
||||
if (*ap==0 || (bins = atoi(*ap++))<=0) usage();
|
||||
if (bins>Max_bins)
|
||||
{ fprintf(stderr,"Too many histogram bins\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (*ap!=0) usage();
|
||||
|
||||
printf("\nTest of %s(",generator);
|
||||
if (np>0) printf("%.4f",p1);
|
||||
if (np>1) printf(",%.4f",p2);
|
||||
printf(") generator using sample of size %d with seed %d\n\n",
|
||||
sample_size, seed);
|
||||
|
||||
undef_mean = undef_variance = 0;
|
||||
|
||||
if (strcmp(generator,"uniform")==0)
|
||||
{ tmean = 0.5;
|
||||
tvariance = 1.0/12.0;
|
||||
}
|
||||
else if (strcmp(generator,"uniopen")==0)
|
||||
{ tmean = 0.5;
|
||||
tvariance = 1.0/12.0;
|
||||
}
|
||||
else if (strcmp(generator,"int")==0)
|
||||
{ tmean = (p1-1)/2;
|
||||
tvariance = p1*p1/3.0 - p1/2.0 + 1/6.0 - tmean*tmean;
|
||||
}
|
||||
else if (strcmp(generator,"poisson")==0)
|
||||
{ tmean = p1;
|
||||
tvariance = p1;
|
||||
}
|
||||
else if (strcmp(generator,"gaussian")==0)
|
||||
{ tmean = 0;
|
||||
tvariance = 1;
|
||||
}
|
||||
else if (strcmp(generator,"exp")==0)
|
||||
{ tmean = 1;
|
||||
tvariance = 1;
|
||||
}
|
||||
else if (strcmp(generator,"cauchy")==0)
|
||||
{ undef_mean = 1;
|
||||
undef_variance = 1;
|
||||
}
|
||||
else if (strcmp(generator,"gamma")==0)
|
||||
{ tmean = p1;
|
||||
tvariance = p1;
|
||||
}
|
||||
else if (strcmp(generator,"beta")==0)
|
||||
{ tmean = p1 / (p1+p2);
|
||||
tvariance = (p1*p2) / ((p1+p2)*(p1+p2)*(p1+p2+1));
|
||||
}
|
||||
else
|
||||
{ abort();
|
||||
}
|
||||
|
||||
mean = 0;
|
||||
variance = 0;
|
||||
|
||||
if (bins>0)
|
||||
{ for (i = 0; i<bins; i++) count[i] = 0;
|
||||
under = over = 0;
|
||||
}
|
||||
|
||||
rand_seed(seed);
|
||||
|
||||
for (n = 0; n<sample_size; n++)
|
||||
{
|
||||
if (strcmp(generator,"uniform")==0) x = rand_uniform();
|
||||
else if (strcmp(generator,"uniopen")==0) x = rand_uniopen();
|
||||
else if (strcmp(generator,"int")==0) x = rand_int((int)p1);
|
||||
else if (strcmp(generator,"poisson")==0) x = rand_poisson(p1);
|
||||
else if (strcmp(generator,"gaussian")==0) x = rand_gaussian();
|
||||
else if (strcmp(generator,"exp")==0) x = rand_exp();
|
||||
else if (strcmp(generator,"cauchy")==0) x = rand_cauchy();
|
||||
else if (strcmp(generator,"gamma")==0) x = rand_gamma(p1);
|
||||
else if (strcmp(generator,"beta")==0) x = rand_beta(p1,p2);
|
||||
else abort();
|
||||
|
||||
mean += x;
|
||||
variance += x*x;
|
||||
|
||||
if (bins>0)
|
||||
{ if (x<low)
|
||||
{ under += 1;
|
||||
}
|
||||
else
|
||||
{ i = (int) ((x-low)/((high-low)/bins));
|
||||
if (i>=bins)
|
||||
{ over += 1;
|
||||
}
|
||||
else
|
||||
{ count[i] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mean /= sample_size;
|
||||
variance /= sample_size;
|
||||
variance -= mean*mean;
|
||||
|
||||
printf("Sample mean: %.4f",mean);
|
||||
if (undef_mean)
|
||||
{ printf(" (true value: undefined)\n");
|
||||
}
|
||||
else
|
||||
{ printf(" (true value: %.4f)\n",tmean);
|
||||
}
|
||||
|
||||
printf("Sample variance: %.4f",variance);
|
||||
if (undef_variance)
|
||||
{ printf(" (true value: undefined)\n");
|
||||
}
|
||||
else
|
||||
{ printf(" (true value: %.4f)\n",tvariance);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (bins!=0)
|
||||
{ printf("Histogram:\n");
|
||||
printf(" under : %8d %.5f\n\n",
|
||||
under, (double)under / sample_size);
|
||||
for (i = 0; i<bins; i++)
|
||||
{ printf(" %10.4f - %10.4f : %8d %.5f\n",
|
||||
i*(high-low)/bins + low, (i+1)*(high-low)/bins + low,
|
||||
count[i], (double)count[i] / sample_size);
|
||||
}
|
||||
printf("\n over : %8d %.5f\n",
|
||||
over, (double)over / sample_size);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
/* PRINT USAGE MESSAGE AND EXIT. */
|
||||
|
||||
static void usage (void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"Usage: rand-test seed generator { parameters } / sample-size [ low high bins ]\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
<HTML><HEAD>
|
||||
|
||||
<TITLE> Support Programs </TITLE>
|
||||
|
||||
</HEAD><BODY>
|
||||
|
||||
|
||||
<H1> Support Programs </H1>
|
||||
|
||||
The following programs provide support for testing and performance
|
||||
assessment.
|
||||
|
||||
|
||||
<P><A NAME="rand-src"><HR><B>rand-src</B>: Generate random message bits.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
rand-src <I>source-file seed n-bits</I>
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Creates a file of random messages bits called
|
||||
<TT><I>source-file</I></TT>, which is suitable for testing the
|
||||
correctness and performance of other programs. The bits in the file
|
||||
are independent, and are equally likely to be 0 or 1. They are
|
||||
generated pseudo-randomly based on <TT><I>seed</I></TT>. The actual
|
||||
random number seed used will be <TT><I>seed</I></TT> times 10 plus 2,
|
||||
so that the stream of pseudo-random numbers will not be the same as
|
||||
any that might have been used by another program.
|
||||
|
||||
<P>The <TT><I>n-bits</I></TT> argument specifies the number of bits to
|
||||
produce. It can be a single number, or it can consist of a block size
|
||||
and a number of blocks, written with <TT>x</TT> separating these
|
||||
numbers, with no spaces. Each block is written as a single line, with
|
||||
the bits in the block represented by the characters '0' and '1', with
|
||||
no intervening spaces. If the bit count is given by a single number,
|
||||
the block size is assumed to be one.
|
||||
|
||||
<P><B>Example:</B> The following command produces a file containing
|
||||
3 blocks, each consisting of 15 random bits, produced using the pseudo-random
|
||||
number stream identified by the <TT><I>seed</I></TT> of 17:
|
||||
<UL><PRE>
|
||||
<LI>rand-src rsrc 17 15x3
|
||||
</PRE></UL>
|
||||
The contents of the file <TT>rsrc</TT> after this command might be something
|
||||
like the following:
|
||||
<BLOCKQUOTE><PRE>
|
||||
111011000110000
|
||||
010010110010111
|
||||
100000000000111
|
||||
</BLOCKQUOTE></PRE>
|
||||
|
||||
|
||||
<P><A NAME="verify"><HR><B>verify</B>: Verify that decoded blocks are
|
||||
codewords, and that they match the source.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
verify [ -t ] <I>pchk-file decoded-file</I> [ <I>gen-file</I> [ <I>source-file</I> ] ]
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Checks whether or not the blocks in <TT><I>decoded-file</I></TT>
|
||||
are codewords, according to the parity check matrix in
|
||||
<TT><I>pchk-file</I></TT>. If <TT><I>gen-file</I></TT> is specified,
|
||||
the message bits of the blocks are also checked against the
|
||||
corresponding blocks of <TT><I>source-file</I></TT>, or against zero
|
||||
if <TT><I>source-file</I></TT> is not given. (Normally, one would
|
||||
leave out <TT><I>source-file</I></TT> only if the <A
|
||||
HREF="channel.html#transmit"><TT>transmit</TT></A> command was used
|
||||
with an argument specifying that zeros are to be transmitted, rather
|
||||
than a file of encoded data.)
|
||||
|
||||
<P>A summary of the results is displayed on standard error, giving the
|
||||
total numbers of blocks, the number with parity check errors, and, if
|
||||
<TT><I>gen-file</I></TT> was specified, the number of blocks with
|
||||
source errors and the number with errors of both kinds. If
|
||||
<TT><I>gen-file</I></TT> was specified, a second
|
||||
summary line displays the bit error rate from
|
||||
comparing the decoded message bits with the true message bits (zeros
|
||||
if no <TT><I>source file</I></TT> was given).
|
||||
|
||||
<P>If the <B>-t</B> option is given, block-by-block results are
|
||||
printed on standard output in two or three columns, giving the block
|
||||
number (from zero), the number of parity check errors for that block,
|
||||
and the number of errors in source bits. The last column is omitted
|
||||
if <TT><I>gen-file</I></TT> is not specified. The columns are
|
||||
preceded by a line of headers, so the file is suitable for reading
|
||||
into the S-Plus or R statistics packages, with a command such as
|
||||
<BLOCKQUOTE><PRE>
|
||||
data <- read.table(<I>file</I>,header=T)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Warning messages are displayed on standard error if the number of
|
||||
bits in <TT><I>decoded-file</I></TT> is not a multiple of the block
|
||||
length, or if <TT><I>source-file</I></TT> is too short. Newlines
|
||||
in these files are ignored, even though they would normally occur
|
||||
at the ends of blocks.
|
||||
|
||||
<HR>
|
||||
|
||||
<A HREF="index.html">Back to index for LDPC software</A>
|
||||
|
||||
</BODY></HTML>
|
||||
@@ -1,34 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MessageAveraging</class>
|
||||
<widget class="QWidget" name="MessageAveraging">
|
||||
<property name="windowTitle">
|
||||
<string>Message Averaging</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="header_label">
|
||||
<property name="text">
|
||||
<string> UTC Sync DT Freq </string>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QPlainTextEdit" name="msgAvgPlainTextEdit">
|
||||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
@@ -291,14 +291,19 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
QByteArray comments;
|
||||
QByteArray name;
|
||||
QDateTime time_on; // Note: LOTW uses TIME_ON for their +/- 30-minute time window
|
||||
QByteArray operator_call;
|
||||
QByteArray my_call;
|
||||
QByteArray my_grid;
|
||||
in >> time_off >> dx_call >> dx_grid >> dial_frequency >> mode >> report_sent >> report_received
|
||||
>> tx_power >> comments >> name >> time_on;
|
||||
>> tx_power >> comments >> name >> time_on >> operator_call >> my_call >> my_grid;
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->qso_logged (id, time_off, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid)
|
||||
, dial_frequency, QString::fromUtf8 (mode), QString::fromUtf8 (report_sent)
|
||||
, QString::fromUtf8 (report_received), QString::fromUtf8 (tx_power)
|
||||
, QString::fromUtf8 (comments), QString::fromUtf8 (name), time_on);
|
||||
, QString::fromUtf8 (comments), QString::fromUtf8 (name), time_on
|
||||
, QString::fromUtf8 (operator_call), QString::fromUtf8 (my_call)
|
||||
, QString::fromUtf8 (my_grid));
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -308,6 +313,17 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
|
||||
clients_.remove (id);
|
||||
break;
|
||||
|
||||
case NetworkMessage::LoggedADIF:
|
||||
{
|
||||
QByteArray ADIF;
|
||||
in >> ADIF;
|
||||
if (check_status (in) != Fail)
|
||||
{
|
||||
Q_EMIT self_->logged_ADIF (id, ADIF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Ignore
|
||||
break;
|
||||
@@ -452,3 +468,28 @@ void MessageServer::free_text (QString const& id, QString const& text, bool send
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::location (QString const& id, QString const& loc)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::Location, id, (*iter).negotiated_schema_number_};
|
||||
out << loc.toUtf8 ();
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageServer::highlight_callsign (QString const& id, QString const& callsign
|
||||
, QColor const& bg, QColor const& fg, bool last_only)
|
||||
{
|
||||
auto iter = m_->clients_.find (id);
|
||||
if (iter != std::end (m_->clients_))
|
||||
{
|
||||
QByteArray message;
|
||||
NetworkMessage::Builder out {&message, NetworkMessage::HighlightCallsign, id, (*iter).negotiated_schema_number_};
|
||||
out << callsign.toUtf8 () << bg << fg << last_only;
|
||||
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
|
||||
}
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
#include "displaytext.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QDateTime>
|
||||
#include <QTextCharFormat>
|
||||
#include <QTextCursor>
|
||||
#include <QTextBlock>
|
||||
|
||||
#include "qt_helpers.hpp"
|
||||
|
||||
#include "moc_displaytext.cpp"
|
||||
|
||||
DisplayText::DisplayText(QWidget *parent) :
|
||||
QTextEdit(parent)
|
||||
{
|
||||
setReadOnly (true);
|
||||
viewport ()->setCursor (Qt::ArrowCursor);
|
||||
setWordWrapMode (QTextOption::NoWrap);
|
||||
document ()->setMaximumBlockCount (5000); // max lines to limit heap usage
|
||||
}
|
||||
|
||||
void DisplayText::setContentFont(QFont const& font)
|
||||
{
|
||||
char_font_ = font;
|
||||
selectAll ();
|
||||
auto cursor = textCursor ();
|
||||
cursor.beginEditBlock ();
|
||||
auto char_format = cursor.charFormat ();
|
||||
char_format.setFont (char_font_);
|
||||
cursor.mergeCharFormat (char_format);
|
||||
cursor.clearSelection ();
|
||||
cursor.movePosition (QTextCursor::End);
|
||||
|
||||
// position so viewport scrolled to left
|
||||
cursor.movePosition (QTextCursor::Up);
|
||||
cursor.movePosition (QTextCursor::StartOfLine);
|
||||
cursor.endEditBlock ();
|
||||
|
||||
setTextCursor (cursor);
|
||||
ensureCursorVisible ();
|
||||
}
|
||||
|
||||
void DisplayText::mouseDoubleClickEvent(QMouseEvent *e)
|
||||
{
|
||||
bool ctrl = (e->modifiers() & Qt::ControlModifier);
|
||||
bool alt = (e->modifiers() & Qt::AltModifier);
|
||||
emit(selectCallsign(alt,ctrl));
|
||||
QTextEdit::mouseDoubleClickEvent(e);
|
||||
}
|
||||
|
||||
void DisplayText::insertLineSpacer(QString const& line)
|
||||
{
|
||||
appendText (line, "#d3d3d3");
|
||||
}
|
||||
|
||||
void DisplayText::appendText(QString const& text, QColor bg)
|
||||
{
|
||||
auto cursor = textCursor ();
|
||||
cursor.movePosition (QTextCursor::End);
|
||||
auto block_format = cursor.blockFormat ();
|
||||
block_format.setBackground (bg);
|
||||
if (0 == cursor.position ())
|
||||
{
|
||||
cursor.setBlockFormat (block_format);
|
||||
auto char_format = cursor.charFormat ();
|
||||
char_format.setFont (char_font_);
|
||||
cursor.setCharFormat (char_format);
|
||||
}
|
||||
else
|
||||
{
|
||||
cursor.insertBlock (block_format);
|
||||
}
|
||||
cursor.insertText (text);
|
||||
|
||||
// position so viewport scrolled to left
|
||||
cursor.movePosition (QTextCursor::StartOfLine);
|
||||
setTextCursor (cursor);
|
||||
ensureCursorVisible ();
|
||||
document ()->setMaximumBlockCount (document ()->maximumBlockCount ());
|
||||
}
|
||||
|
||||
|
||||
QString DisplayText::appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg,
|
||||
LogBook const& logBook, QColor color_CQ,
|
||||
QColor color_DXCC,
|
||||
QColor color_NewCall)
|
||||
{
|
||||
// allow for seconds
|
||||
unsigned padding {message.indexOf (" ") > 4 ? 2U : 0U};
|
||||
QString call = callsign;
|
||||
QString countryName;
|
||||
bool callWorkedBefore;
|
||||
bool countryWorkedBefore;
|
||||
|
||||
if(call.length()==2) {
|
||||
int i0=message.indexOf("CQ "+call);
|
||||
call=message.mid(i0+6,-1);
|
||||
i0=call.indexOf(" ");
|
||||
call=call.mid(0,i0);
|
||||
}
|
||||
if(call.length()<3) return message;
|
||||
if(!call.contains(QRegExp("[0-9]|[A-Z]"))) return message;
|
||||
|
||||
logBook.match(/*in*/call,/*out*/countryName,callWorkedBefore,countryWorkedBefore);
|
||||
int charsAvail = 52 + padding;
|
||||
|
||||
// the decoder (seems) to always generate 41 chars. For a normal CQ
|
||||
// call, the last five are spaces
|
||||
//
|
||||
// A maximum length call is "QRZ VP2X/GM4WJS IO91" "CQ AA ..." or CQ
|
||||
// nnn ..." don't allow grid squares so are not longer. Here we align
|
||||
// the added info at least after the longest CQ/QRZ message plus one
|
||||
// space so that it can be stripped off algorithmically later.
|
||||
//
|
||||
int nmin = 46 + padding;
|
||||
int s3 = message.indexOf (" ", nmin);
|
||||
if (s3 < nmin) s3 = nmin; // always want at least the characters to position 45
|
||||
s3 += 1; // convert the index into a character count
|
||||
message = message.left(s3); // reduce trailing white space
|
||||
charsAvail -= s3;
|
||||
if (charsAvail > 4)
|
||||
{
|
||||
if (!countryWorkedBefore) // therefore not worked call either
|
||||
{
|
||||
message += "!";
|
||||
*bg = color_DXCC;
|
||||
}
|
||||
else
|
||||
if (!callWorkedBefore) // but have worked the country
|
||||
{
|
||||
message += "~";
|
||||
*bg = color_NewCall;
|
||||
}
|
||||
else
|
||||
{
|
||||
message += " "; // have worked this call before
|
||||
*bg = color_CQ;
|
||||
}
|
||||
charsAvail -= 1;
|
||||
|
||||
// do some obvious abbreviations
|
||||
countryName.replace ("Islands", "Is.");
|
||||
countryName.replace ("Island", "Is.");
|
||||
countryName.replace ("North ", "N. ");
|
||||
countryName.replace ("Northern ", "N. ");
|
||||
countryName.replace ("South ", "S. ");
|
||||
countryName.replace ("East ", "E. ");
|
||||
countryName.replace ("Eastern ", "E. ");
|
||||
countryName.replace ("West ", "W. ");
|
||||
countryName.replace ("Western ", "W. ");
|
||||
countryName.replace ("Central ", "C. ");
|
||||
countryName.replace (" and ", " & ");
|
||||
countryName.replace ("Republic", "Rep.");
|
||||
countryName.replace ("United States", "U.S.A.");
|
||||
countryName.replace ("Fed. Rep. of ", "");
|
||||
countryName.replace ("French ", "Fr.");
|
||||
countryName.replace ("Asiatic", "AS");
|
||||
countryName.replace ("European", "EU");
|
||||
countryName.replace ("African", "AF");
|
||||
|
||||
message += countryName;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
void DisplayText::displayDecodedText(DecodedText const& decodedText, QString const& myCall,
|
||||
bool displayDXCCEntity, LogBook const& logBook,
|
||||
QColor color_CQ, QColor color_MyCall,
|
||||
QColor color_DXCC, QColor color_NewCall)
|
||||
{
|
||||
QColor bg {Qt::white};
|
||||
bool CQcall = false;
|
||||
if (decodedText.string ().contains (" CQ ")
|
||||
|| decodedText.string ().contains (" CQDX ")
|
||||
|| decodedText.string ().contains (" QRZ "))
|
||||
{
|
||||
CQcall = true;
|
||||
bg = color_CQ;
|
||||
}
|
||||
if (myCall != "" and (
|
||||
decodedText.indexOf (" " + myCall + " ") >= 0
|
||||
or decodedText.indexOf (" " + myCall + "/") >= 0
|
||||
or decodedText.indexOf ("/" + myCall + " ") >= 0
|
||||
or decodedText.indexOf ("<" + myCall + " ") >= 0
|
||||
or decodedText.indexOf (" " + myCall + ">") >= 0)) {
|
||||
bg = color_MyCall;
|
||||
}
|
||||
// if enabled add the DXCC entity and B4 status to the end of the
|
||||
// preformated text line t1
|
||||
auto message = decodedText.string ();
|
||||
if (displayDXCCEntity && CQcall)
|
||||
message = appendDXCCWorkedB4 (message, decodedText.CQersCall (), &bg, logBook, color_CQ,
|
||||
color_DXCC, color_NewCall);
|
||||
appendText (message, bg);
|
||||
}
|
||||
|
||||
|
||||
void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
|
||||
QColor color_TxMsg, bool bFastMode)
|
||||
{
|
||||
QString t1=" @ ";
|
||||
if(modeTx=="FT8") t1=" ~ ";
|
||||
if(modeTx=="JT4") t1=" $ ";
|
||||
if(modeTx=="JT65") t1=" # ";
|
||||
if(modeTx=="MSK144") t1=" & ";
|
||||
QString t2;
|
||||
t2.sprintf("%4d",txFreq);
|
||||
QString t;
|
||||
if(bFastMode or modeTx=="FT8") {
|
||||
t = QDateTime::currentDateTimeUtc().toString("hhmmss") + \
|
||||
" Tx " + t2 + t1 + text;
|
||||
} else {
|
||||
t = QDateTime::currentDateTimeUtc().toString("hhmm") + \
|
||||
" Tx " + t2 + t1 + text;
|
||||
}
|
||||
appendText (t, color_TxMsg);
|
||||
}
|
||||
|
||||
void DisplayText::displayQSY(QString text)
|
||||
{
|
||||
QString t = QDateTime::currentDateTimeUtc().toString("hhmmss") + " " + text;
|
||||
appendText (t, "hotpink");
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
subroutine extract(s3,nadd,mode65,ntrials,naggressive,ndepth,nflip, &
|
||||
mycall_12,hiscall_12,hisgrid,nexp_decode,ncount,nhist,decoded, &
|
||||
ltext,nft,qual)
|
||||
|
||||
! Input:
|
||||
! s3 64-point spectra for each of 63 data symbols
|
||||
! nadd number of spectra summed into s3
|
||||
! nqd 0/1 to indicate decode attempt at QSO frequency
|
||||
|
||||
! Output:
|
||||
! ncount number of symbols requiring correction (-1 for no KV decode)
|
||||
! nhist maximum number of identical symbol values
|
||||
! decoded decoded message (if ncount >=0)
|
||||
! ltext true if decoded message is free text
|
||||
! nft 0=no decode; 1=FT decode; 2=hinted decode
|
||||
|
||||
use prog_args !shm_key, exe_dir, data_dir
|
||||
use packjt
|
||||
use jt65_mod
|
||||
use timer_module, only: timer
|
||||
|
||||
real s3(64,63)
|
||||
character decoded*22
|
||||
character*12 mycall_12,hiscall_12
|
||||
character*6 mycall,hiscall,hisgrid
|
||||
integer dat4(12)
|
||||
integer mrsym(63),mr2sym(63),mrprob(63),mr2prob(63)
|
||||
integer correct(63),tmp(63)
|
||||
logical ltext
|
||||
common/chansyms65/correct
|
||||
save
|
||||
|
||||
if(mode65.eq.-99) stop !Silence compiler warning
|
||||
mycall=mycall_12(1:6)
|
||||
hiscall=hiscall_12(1:6)
|
||||
qual=0.
|
||||
nbirdie=20
|
||||
npct=50
|
||||
afac1=1.1
|
||||
nft=0
|
||||
nfail=0
|
||||
decoded=' '
|
||||
call pctile(s3,4032,npct,base)
|
||||
s3=s3/base
|
||||
s3a=s3 !###
|
||||
|
||||
! Get most reliable and second-most-reliable symbol values, and their
|
||||
! probabilities
|
||||
1 call demod64a(s3,nadd,afac1,mrsym,mrprob,mr2sym,mr2prob,ntest,nlow)
|
||||
|
||||
call chkhist(mrsym,nhist,ipk) !Test for birdies and QRM
|
||||
if(nhist.ge.nbirdie) then
|
||||
nfail=nfail+1
|
||||
call pctile(s3,4032,npct,base)
|
||||
s3(ipk,1:63)=base
|
||||
if(nfail.gt.30) then
|
||||
decoded=' '
|
||||
ncount=-1
|
||||
go to 900
|
||||
endif
|
||||
go to 1
|
||||
endif
|
||||
|
||||
mrs=mrsym
|
||||
mrs2=mr2sym
|
||||
|
||||
call graycode65(mrsym,63,-1) !Remove gray code
|
||||
call interleave63(mrsym,-1) !Remove interleaving
|
||||
call interleave63(mrprob,-1)
|
||||
|
||||
call graycode65(mr2sym,63,-1) !Remove gray code and interleaving
|
||||
call interleave63(mr2sym,-1) !from second-most-reliable symbols
|
||||
call interleave63(mr2prob,-1)
|
||||
ntry=0
|
||||
|
||||
call timer('ftrsd ',0)
|
||||
param=0
|
||||
call ftrsd2(mrsym,mrprob,mr2sym,mr2prob,ntrials,correct,param,ntry)
|
||||
call timer('ftrsd ',1)
|
||||
ncandidates=param(0)
|
||||
nhard=param(1)
|
||||
nsoft=param(2)
|
||||
nerased=param(3)
|
||||
rtt=0.001*param(4)
|
||||
ntotal=param(5)
|
||||
qual=0.001*param(7)
|
||||
nd0=81
|
||||
r0=0.87
|
||||
if(naggressive.eq.10) then
|
||||
nd0=83
|
||||
r0=0.90
|
||||
endif
|
||||
if(ntotal.le.nd0 .and. rtt.le.r0) nft=1
|
||||
|
||||
if(nft.eq.0 .and. iand(ndepth,32).eq.32) then
|
||||
qmin=2.0 - 0.1*naggressive
|
||||
call timer('hint65 ',0)
|
||||
call hint65(s3,mrs,mrs2,nadd,nflip,mycall,hiscall,hisgrid,qual,decoded)
|
||||
if(qual.ge.qmin) then
|
||||
nft=2
|
||||
ncount=0
|
||||
else
|
||||
decoded=' '
|
||||
ntry=0
|
||||
endif
|
||||
call timer('hint65 ',1)
|
||||
go to 900
|
||||
endif
|
||||
|
||||
ncount=-1
|
||||
decoded=' '
|
||||
ltext=.false.
|
||||
if(nft.gt.0) then
|
||||
! Turn the corrected symbol array into channel symbols for subtraction;
|
||||
! pass it back to jt65a via common block "chansyms65".
|
||||
do i=1,12
|
||||
dat4(i)=correct(13-i)
|
||||
enddo
|
||||
do i=1,63
|
||||
tmp(i)=correct(64-i)
|
||||
enddo
|
||||
correct(1:63)=tmp(1:63)
|
||||
call interleave63(correct,63,1)
|
||||
call graycode65(correct,63,1)
|
||||
call unpackmsg(dat4,decoded,.false.,' ') !Unpack the user message
|
||||
ncount=0
|
||||
if(iand(dat4(10),8).ne.0) ltext=.true.
|
||||
endif
|
||||
900 continue
|
||||
if(nft.eq.1 .and. nhard.lt.0) decoded=' '
|
||||
|
||||
return
|
||||
end subroutine extract
|
||||
|
||||
subroutine getpp(workdat,p)
|
||||
|
||||
use jt65_mod
|
||||
integer workdat(63)
|
||||
integer a(63)
|
||||
|
||||
a(1:63)=workdat(63:1:-1)
|
||||
call interleave63(a,1)
|
||||
call graycode(a,63,1,a)
|
||||
|
||||
psum=0.
|
||||
do j=1,63
|
||||
i=a(j)+1
|
||||
x=s3a(i,j)
|
||||
s3a(i,j)=0.
|
||||
psum=psum + x
|
||||
s3a(i,j)=x
|
||||
enddo
|
||||
p=psum/63.0
|
||||
|
||||
return
|
||||
end subroutine getpp
|
||||
@@ -0,0 +1,154 @@
|
||||
integer, parameter:: N=204, K=68, M=N-K
|
||||
character*17 g(136)
|
||||
integer colorder(N)
|
||||
data g/ & !parity generator matrix for (204,68) code
|
||||
"2de7435fd27c0031d", &
|
||||
"f331b40671e20ea80", &
|
||||
"48bd3f8cb9a24392f", &
|
||||
"d4ed71c935162aa2a", &
|
||||
"c437a3284ec58bce7", &
|
||||
"35a806dd5be35627c", &
|
||||
"396e797c33a4739a6", &
|
||||
"768f331a59c15487b", &
|
||||
"c214eac24ae5e1732", &
|
||||
"0b5c53ff3a6da1192", &
|
||||
"99624981d2703fb97", &
|
||||
"e9f5447ef7f1ff6af", &
|
||||
"bd8c730f0cfdf0727", &
|
||||
"26f61e63e1e098f7f", &
|
||||
"ef826566137b6526f", &
|
||||
"af0e4fa251e9b4926", &
|
||||
"75974a8b2a24292c5", &
|
||||
"71caf0f2cd10f6d4f", &
|
||||
"b1103f1f26e6898b7", &
|
||||
"67ceb7d6f490da64f", &
|
||||
"ee0e8fbefec23008a", &
|
||||
"11cc2227e8bd676ca", &
|
||||
"6e71626ba1e278046", &
|
||||
"005d28da267e50e13", &
|
||||
"a9ae4a130aaba8219", &
|
||||
"d8ab72e0158d0da70", &
|
||||
"56009d42b37bd66ff", &
|
||||
"c39a75eca99b0e996", &
|
||||
"6886de0bf7c0bf4bb", &
|
||||
"1046cd8f64162f7b5", &
|
||||
"da0f15843ac21e3a5", &
|
||||
"e9bf9cd19f3db3913", &
|
||||
"2fb9cb42d650f47a7", &
|
||||
"a2b6c5a378fa75a65", &
|
||||
"41a88f3cd60b79d6c", &
|
||||
"fcf175794cc3ac96a", &
|
||||
"8677a3447d40a9f71", &
|
||||
"97a1f08c250b4bf12", &
|
||||
"0168f090a1df6e8ea", &
|
||||
"418a06bf372cc67d9", &
|
||||
"0f17b880c1ff51239", &
|
||||
"b2afd6d585deb961b", &
|
||||
"60298ac5b58dbeee0", &
|
||||
"8350c03c40119feff", &
|
||||
"b29c964a8accf6af4", &
|
||||
"9b46f036a5c178b5d", &
|
||||
"917398bff051c300a", &
|
||||
"5e52c03b2f8c5128c", &
|
||||
"beae6c33c87ba38ab", &
|
||||
"20843f7b056a02ebf", &
|
||||
"66690d65acd9de598", &
|
||||
"8f025841af5b54331", &
|
||||
"b43cd869d3be2c3db", &
|
||||
"c9c342fe63c18df50", &
|
||||
"d331b40671e28ea80", &
|
||||
"62406a0f4947e6ce9", &
|
||||
"d67b1495883b22e1b", &
|
||||
"734534c372408895b", &
|
||||
"d88750e33d9677dcd", &
|
||||
"6f96964da55138687", &
|
||||
"80bee98bb75d50ef2", &
|
||||
"c428ef3e3f06f4c56", &
|
||||
"b1a1499b125883a35", &
|
||||
"ac892d4b37fa9e395", &
|
||||
"458dbda0f95ab11a5", &
|
||||
"6f93c9e95b1094eed", &
|
||||
"2e370d713914f848e", &
|
||||
"758806dd5be35627c", &
|
||||
"8c52e01caec798b49", &
|
||||
"c286cc25bae3669cf", &
|
||||
"87c56fb895c100884", &
|
||||
"e89cb1376a18fd911", &
|
||||
"156ffe5f30dc354e0", &
|
||||
"f20d0b121d6a6b3ee", &
|
||||
"7db08891b491a95d2", &
|
||||
"191fac548d5077bdf", &
|
||||
"023a37d7ea5660bbc", &
|
||||
"6781668b363fee682", &
|
||||
"bbfaf262cab7370da", &
|
||||
"feea557965b7e474f", &
|
||||
"c094eb223e1d305b8", &
|
||||
"2be051abdd5beea35", &
|
||||
"0790449880fda9d00", &
|
||||
"f9029a39ec869e7b4", &
|
||||
"5a29f48926ec9a552", &
|
||||
"e0463306dc1470f87", &
|
||||
"9251058334d790f86", &
|
||||
"3019e1d4578e8a4dc", &
|
||||
"887e46631502fa111", &
|
||||
"c25fcd7a42465d326", &
|
||||
"cf64bcc1056b555c4", &
|
||||
"3e71c0fe5f0ad733b", &
|
||||
"11055ec43b076e5b2", &
|
||||
"3440f64dfa3c30a96", &
|
||||
"2b73885b4d3299f60", &
|
||||
"2e71627ba1e268046", &
|
||||
"ad23743d5e6e5b80c", &
|
||||
"c9757b05f29bfdc10", &
|
||||
"f7112bea739247b51", &
|
||||
"3664062387998b2b1", &
|
||||
"90897a3b8785aefba", &
|
||||
"29e126e3201fc1d46", &
|
||||
"96c9001c84d5257fc", &
|
||||
"067723447d40a9f71", &
|
||||
"1a019cc68f7511402", &
|
||||
"4bd48eb2330032763", &
|
||||
"d139a5da936b37647", &
|
||||
"765ab46a4dec5f04f", &
|
||||
"706f475ad19b91955", &
|
||||
"1755c988fa8a55e5c", &
|
||||
"2fd9ed5777eb01d6a", &
|
||||
"bec27d85b954d3fe8", &
|
||||
"7135a3b92c45b3f8d", &
|
||||
"353237872f002163a", &
|
||||
"e31e4a97aef10c729", &
|
||||
"da527d5e1cbc4edb6", &
|
||||
"6e33cdede17c3207e", &
|
||||
"ef2d2062e84dc401f", &
|
||||
"8217c84c50c1bf833", &
|
||||
"12ffbac7b2219c9e0", &
|
||||
"3729178706f66881f", &
|
||||
"2fdd748c382a608a1", &
|
||||
"dd0a00076f9dcec73", &
|
||||
"46b1d37bced447035", &
|
||||
"7316f33a9c05ef178", &
|
||||
"152c39a6de8954cc3", &
|
||||
"16efffb7b62e12ba3", &
|
||||
"9d9ec2bb467affd83", &
|
||||
"467723445d40a9f61", &
|
||||
"87994762b3bf50697", &
|
||||
"b1bfa5b51526dde9b", &
|
||||
"b0a6a19d709a96148", &
|
||||
"990d567c0aba31a14", &
|
||||
"171f190792461b1e0", &
|
||||
"166011c27d2b6b8a4", &
|
||||
"170c15831244ae73e"/
|
||||
|
||||
data colorder/ &
|
||||
0, 1, 2, 3, 4, 5, 47, 6, 7, 8, 9, 10, 11, 12, 58, 55, 13, &
|
||||
14, 15, 46, 17, 18, 60, 19, 20, 21, 22, 23, 24, 25, 57, 26, 27, 49, &
|
||||
28, 52, 65, 16, 50, 73, 59, 68, 63, 29, 30, 31, 32, 51, 62, 56, 66, &
|
||||
45, 33, 34, 53, 67, 35, 36, 37, 61, 69, 54, 38, 71, 82, 39, 77, 80, &
|
||||
83, 78, 84, 48, 41, 85, 40, 64, 75, 96, 74, 72, 76, 86, 87, 89, 90, &
|
||||
79, 70, 92, 99, 93,101, 95,100, 97, 94, 42, 98,103,105,102, 43,104, &
|
||||
88, 44,106, 81,107,110,108,111,112,109,113,114,117,118,116,121,115, &
|
||||
119,122,120,125,129,124,127,126,128, 91,123,133,131,130,134,135,137, &
|
||||
136,132,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, &
|
||||
153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169, &
|
||||
170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, &
|
||||
187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203/
|
||||
@@ -0,0 +1,43 @@
|
||||
// Forward declaration of the circular buffer and its adaptor.
|
||||
|
||||
// Copyright (c) 2003-2008 Jan Gaspar
|
||||
|
||||
// Use, modification, and distribution is subject to the Boost Software
|
||||
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See www.boost.org/libs/circular_buffer for documentation.
|
||||
|
||||
#if !defined(BOOST_CIRCULAR_BUFFER_FWD_HPP)
|
||||
#define BOOST_CIRCULAR_BUFFER_FWD_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if !defined(BOOST_NO_STD_ALLOCATOR)
|
||||
#include <memory>
|
||||
#else
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if !defined(BOOST_NO_STD_ALLOCATOR)
|
||||
#define BOOST_CB_DEFAULT_ALLOCATOR(T) std::allocator<T>
|
||||
#else
|
||||
#define BOOST_CB_DEFAULT_ALLOCATOR(T) BOOST_DEDUCED_TYPENAME std::vector<T>::allocator_type
|
||||
#endif
|
||||
|
||||
template <class T, class Alloc = BOOST_CB_DEFAULT_ALLOCATOR(T)>
|
||||
class circular_buffer;
|
||||
|
||||
template <class T, class Alloc = BOOST_CB_DEFAULT_ALLOCATOR(T)>
|
||||
class circular_buffer_space_optimized;
|
||||
|
||||
#undef BOOST_CB_DEFAULT_ALLOCATOR
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // #if !defined(BOOST_CIRCULAR_BUFFER_FWD_HPP)
|
||||
@@ -1,719 +0,0 @@
|
||||
<HTML><HEAD>
|
||||
|
||||
<TITLE> Sparse Modulo-2 Matrix Routines </TITLE>
|
||||
|
||||
</HEAD><BODY>
|
||||
|
||||
|
||||
<H1> Sparse Modulo-2 Matrix Routines </H1>
|
||||
|
||||
<P>This module implements operations on matrices in which the elements
|
||||
are all 0 or 1, with addition and multiplication being done modulo 2.
|
||||
The matrices are represented by doubly-linked lists of entries
|
||||
representing the elements in each row and column that are 1s, with
|
||||
other elements being assumed to be zero.
|
||||
|
||||
<P>This is an appropriate representation when the matrices are sparse
|
||||
(ie, 0s are much more frequent that 1s). Matrices in which 0s and 1s
|
||||
are about equally likely may be better handled with the <A
|
||||
HREF="mod2dense.html">dense modulo-2 matrix routines</A>. Matrices
|
||||
can be converted between these two formats using the <A
|
||||
HREF="mod2convert.html">module-2 matrix conversion routines</A>.
|
||||
|
||||
<P>All procedures in this module display an error message on standard
|
||||
error and terminate the program if passed an invalid argument (indicative
|
||||
of a programming error), or if memory cannot be allocated. Errors from
|
||||
invalid contents of a file result in an error code being returned to the
|
||||
caller, with no message being printed by this module.
|
||||
|
||||
|
||||
<A NAME="rep"><H2>Representation of sparse matrices</H2></A>
|
||||
|
||||
<P>This module represents a non-zero element of a matrix (which must have
|
||||
the value 1, since these are modulo-2 matrices) by a node of type
|
||||
<TT>mod2entry</TT>, which contains the row and column of the element,
|
||||
pointers to the next non-zero elements above and below in its column
|
||||
and to the left and the right in its row, and two double-precision
|
||||
floating-point numbers called <B>pr</B> and <B>lr</B>, which are
|
||||
of no significance to this module, but which are used by the routines
|
||||
for <A HREF="decoding.html#prprp">decoding LDPC codes by probability
|
||||
propagation</A>.
|
||||
|
||||
<P>The <TT>mod2sparse</TT> type represents a matrix. It records the
|
||||
number of rows and columns in the matrix, and contains arrays of
|
||||
pointers to the <TT>mod2entry</TT> structures for the first non-zero
|
||||
element in each row and the first non-zero element in each column.
|
||||
|
||||
<P>Matrices must be created by the <A
|
||||
HREF="#allocate"><TT>mod2sparse_allocate</TT></A> procedure, which
|
||||
returns a pointer to a <TT>mod2sparse</TT> structure. When a matrix
|
||||
is no longer needed, the space it occupies can be freed with <A
|
||||
HREF="#free"><TT>mod2sparse_free</TT></A>. Elements within a matrix,
|
||||
represented by <TT>mod2entry</TT> nodes, are allocated as needed, and
|
||||
if deleted, they will be reused for new elements within the same
|
||||
matrix. The space they occupy is not reusable for other matrices or
|
||||
other purposes until the entire matrix is either freed, with <A
|
||||
HREF="#free"><TT>mod2sparse_free</TT></A>, or cleared to all zeros,
|
||||
with <A HREF="#clear"><TT>mod2sparse_clear</TT></A>, or used as
|
||||
the result matrix for copying or arithmetic operations.
|
||||
|
||||
|
||||
<P><B>Header files required</B>:
|
||||
<TT>mod2sparse.h</TT>
|
||||
|
||||
|
||||
<A NAME="dimension-sec">
|
||||
<P><HR>
|
||||
<CENTER><BIG>Dimension Macros</BIG></CENTER>
|
||||
</A>
|
||||
|
||||
<HR>The following macros take a pointer to a mod2sparse structure as their
|
||||
argument, and return the number of rows or the number of columns in
|
||||
the matrix pointed to, which will have been fixed when the matrix was
|
||||
created with <A HREF="#allocate">mod2sparse_allocate</A>:
|
||||
<BLOCKQUOTE><PRE>
|
||||
mod2sparse_rows(m) /* Returns the number of rows in m */
|
||||
|
||||
mod2sparse_cols(m) /* Returns the number of columns in m */
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
|
||||
<A NAME="traversal-sec">
|
||||
<P><HR>
|
||||
<CENTER><BIG>Traversal Macros</BIG></CENTER>
|
||||
</A>
|
||||
|
||||
<HR>The following macros are used to move around a sparse matrix by
|
||||
following the pointers from one non-zero element to the next or
|
||||
previous non-zero element in the same row or column. If such a
|
||||
movement takes one beyond the last or before first entry in a row or
|
||||
column, or if one tries to find the first or last non-zero entry in a
|
||||
row or column that has no non-zero entries, the entry returned will be
|
||||
a special one that can be identified using the
|
||||
<TT>mod2sparse_at_end</TT> macro. If one is already at this special
|
||||
entry, moving further wraps one around to the first or last entry.
|
||||
|
||||
<P>The macros for finding the first or last entry in a row or column
|
||||
take as their arguments a pointer to the matrix (<TT>mod2sparse
|
||||
*</TT>) and a row or column index, starting at zero. The other macros
|
||||
take as their arguments a pointer to an entry (<TT>mod2entry *</TT>)
|
||||
within some matrix.
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
mod2sparse_first_in_row(m,i) /* Returns the first entry in row i of m */
|
||||
mod2sparse_first_in_col(m,j) /* Returns the first entry in column j of m */
|
||||
|
||||
mod2sparse_last_in_row(m,i) /* Returns the last entry in row i of m */
|
||||
mod2sparse_last_in_col(m,j) /* Returns the last entry in column j of m */
|
||||
|
||||
mod2sparse_next_in_row(e) /* Returns the entry after e in its row */
|
||||
mod2sparse_next_in_col(e) /* Returns the entry after e in its column */
|
||||
|
||||
mod2sparse_prev_in_row(e) /* Returns the entry before e in its row */
|
||||
mod2sparse_prev_in_col(e) /* Returns the entry before e in its col */
|
||||
|
||||
mod2sparse_row(e) /* Returns the row index of entry e */
|
||||
mod2sparse_col(e) /* Returns the column index of entry e */
|
||||
|
||||
mod2sparse_at_end(e) /* Returns 1 if e is a special entry obtained
|
||||
by moving past the end, returns 0 otherwise */
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
|
||||
<A NAME="alloc-sec">
|
||||
<P><HR>
|
||||
<CENTER><BIG>Allocating and Freeing Sparse Modulo-2 Matrices</BIG></CENTER>
|
||||
</A>
|
||||
|
||||
|
||||
<A NAME="allocate"><HR><B>mod2sparse_allocate</B>:
|
||||
Allocate space for a sparse module-2 matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
mod2sparse *mod2sparse_allocate
|
||||
( int n_rows, /* Number of rows in matrix */
|
||||
int n_cols /* Number of columns in matrix */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Allocates space for a matrix with the given number of rows and
|
||||
columns, and returns a pointer to it. The matrix will initially
|
||||
be all zero.
|
||||
|
||||
<P>If there is not enough memory available, a message is displayed on
|
||||
standard error and the program is terminated. The matrix should be
|
||||
freed with <A HREF="#free"><TT>mod2sparse_free</TT></A> once it is no
|
||||
longer in use.
|
||||
|
||||
<P><A NAME="free"><HR><B>mod2sparse_free</B>:
|
||||
Free the space occupied by a sparse module-2 matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_free
|
||||
( mod2sparse *m /* Pointer to matrix to free */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Frees the space occupied by the matrix for re-use. The pointer passed
|
||||
should not be used afterward. Note that space for the individual matrix
|
||||
elements (but not the matrix as a whole) is also freed when <A
|
||||
HREF="#clear"><TT>mod2sparse_clear</TT></A> is called, or the matrix
|
||||
is used as the destination for other operations.
|
||||
|
||||
|
||||
<A NAME="copy-clear-sec">
|
||||
<P><HR>
|
||||
<CENTER><BIG>Copying and Clearing Sparse Modulo-2 Matrices</BIG></CENTER>
|
||||
</A>
|
||||
|
||||
<A NAME="clear"><HR><B>mod2sparse_clear</B>:
|
||||
Set all elements of a matrix to zero.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_clear
|
||||
( mod2sparse *m /* Pointer to matrix to clear */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Sets all of the elements of the matrix passed to 0. The space occupied
|
||||
by the previous non-zero elements is freed for use in other matrices, or
|
||||
other purposes. The matrix itself is not freed, however. To do that,
|
||||
use <A HREF="#free"><TT>mod2sparse_free</TT></A>.
|
||||
|
||||
|
||||
<P><A NAME="copy"><HR><B>mod2sparse_copy</B>:
|
||||
Copy the contents of one matrix to another.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_copy
|
||||
( mod2sparse *m /* Pointer to matrix to copy from */
|
||||
mod2sparse *r /* Pointer to matrix to receive data */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Copies the contents of the first matrix passed, <B>m</B>, to the
|
||||
second matrix passed, <B>r</B>, which must already have been
|
||||
allocated, and must have at least as many rows and columns as the
|
||||
first. If <B>r</B> is larger than <B>m</B>, its elements that have
|
||||
row or column indexes greater than the dimension of <B>m</B> are set
|
||||
to zeros.
|
||||
|
||||
<P>The space occupied by the previous non-zero entries of <B>r</B> is
|
||||
freed for general use (which may include being reused immediately for
|
||||
the copies of the entries in <B>m</B>).
|
||||
|
||||
|
||||
<P><A NAME="copyrows"><HR><B>mod2sparse_copyrows</B>:
|
||||
Copy selected rows from one matrix to another.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_copyrows
|
||||
( mod2sparse *m, /* Pointer to matrix to copy rows from */
|
||||
mod2sparse *r, /* Pointer to matrix in which to store data */
|
||||
int *rows /* Indexes of rows, numbered from 0 */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Copies selected rows of the first matrix, <B>m</B>, to the second
|
||||
matrix, <B>r</B>, which must already have been allocated, and which
|
||||
must have at least as many columns as <B>m</B>. The indexes of the
|
||||
rows to copy are given in order as an array of length the same as
|
||||
the number of rows in <B>r</B>; duplicates are allowed. Row
|
||||
indexes start at 0. These rows are copied to <B>r</B>, with the
|
||||
row indexed by the first entry in <B>rows</B> going to the
|
||||
first row of <B>r</B>, and so forth. If <B>r</B> has more columns than
|
||||
<B>m</B>, the extra entries in each row are set to zeros.
|
||||
|
||||
<P>The space occupied by the previous non-zero entries of <B>r</B> is
|
||||
freed for general use (which may include being reused immediately for
|
||||
the copies of the entries in <B>m</B>).
|
||||
|
||||
|
||||
<P><A NAME="copycols"><HR><B>mod2sparse_copycols</B>:
|
||||
Copy selected columns from one matrix to another.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_copycols
|
||||
( mod2sparse *m, /* Pointer to matrix to copy columns from */
|
||||
mod2sparse *r, /* Pointer to matrix in which to store data */
|
||||
int *cols /* Indexes of columns, numbered from 0 */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Copies selected columns of the first matrix, <B>m</B>, to the second
|
||||
matrix, <B>r</B>, which must already have been allocated, and which
|
||||
must have at least as many rows as <B>m</B>. The indexes of the
|
||||
columns to copy are given in order as an array of length the same as
|
||||
the number of columns in <B>r</B>; duplicates are allowed. Column
|
||||
indexes start at 0. These columns are copied to <B>r</B>, with the
|
||||
column indexed by the first entry in <B>cols</B> going to the
|
||||
first column of <B>r</B>, and so forth. If <B>r</B> has more rows than
|
||||
<B>m</B>, the extra entries in each column are set to zeros.
|
||||
|
||||
<P>The space occupied by the previous non-zero entries of <B>r</B> is
|
||||
freed for general use (which may include being reused immediately for
|
||||
the copies of the entries in <B>m</B>).
|
||||
|
||||
|
||||
<A NAME="input-output-sec">
|
||||
<P><HR>
|
||||
<CENTER><BIG>Input and Output of Sparse Modulo-2 Matrices</BIG></CENTER>
|
||||
</A>
|
||||
|
||||
<A NAME="print"><HR><B>mod2sparse_print</B>:
|
||||
Print a sparse modulo-2 matrix in human-readable form.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_print
|
||||
( FILE *f, /* File to print to */
|
||||
mod2sparse *m /* Pointer to matrix to print */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
The matrix is printed on standard output with one line of output per row,
|
||||
of the form
|
||||
<BLOCKQUOTE><PRE>
|
||||
<I>row</I>: <I>col col col ...</I>
|
||||
</PRE></BLOCKQUOTE>
|
||||
where <I>row</I> is the index of the row, and the <I>col</I> entries are
|
||||
the indexes of columns that are non-zero in that row. Row and column
|
||||
indexes start at zero. Rows with no entries are printed with no column
|
||||
indexes after the colon. The number of columns is not indicated in the output.
|
||||
|
||||
<P><A NAME="write"><HR><B>mod2sparse_write</B>:
|
||||
Write a sparse modulo-2 matrix to a file in machine-readable format.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
int mod2sparse_write
|
||||
( FILE *f, /* File to write data to */
|
||||
mod2sparse *m /* Pointer to matrix write out */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Writes a machine-readable representation the sparse matrix <B>m</B> to
|
||||
the file <B>f</B>. The file should have been opened in binary mode
|
||||
(with a "b" in the mode passed to fopen). The contents written will
|
||||
not be text, and will not be human-readable. Other binary data may
|
||||
precede or follow the data for the matrix written.
|
||||
|
||||
<P>The data written to the file starts with the number of rows and the
|
||||
number of columns. Following this are negative integers giving row
|
||||
indexes (starting at 1), which apply until the next row index, and
|
||||
positive integers giving column indexes (starting at 1) for a non-zero
|
||||
entry in the matrix. The data should be readable by <A
|
||||
HREF="#read"><TT>mod2sparse_read</TT></A> even on a machine with a
|
||||
different byte-ordering.
|
||||
|
||||
<P>The value returned by <TT>mod2sparse_write</TT> is one if the
|
||||
operation was successful, zero if an error of some sort occurred.
|
||||
|
||||
<P><A NAME="read"><HR><B>mod2sparse_read</B>:
|
||||
Read a sparse modulo-2 matrix from a file.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
mod2sparse *mod2sparse_read
|
||||
( FILE *f, /* File to read data from */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Reads a sparse modulo-2 matrix from the file <B>f</B>. This file
|
||||
should have been opened in binary mode (with a "b" in the mode passed
|
||||
to fopen). The contents of the file at the point when
|
||||
<TT>mod2sparse_read</TT> is called should have been written by <A
|
||||
HREF="#write"><TT>mod2sparse_write</TT></A>. Other binary data may
|
||||
precede or follow this data.
|
||||
|
||||
<P>The value returned is a pointer to the matrix read, for which space
|
||||
will have been allocated by <TT>mod2sparse_read</TT>, or zero if an
|
||||
error occurred (either an error reading the file, or data not in the
|
||||
right format).
|
||||
|
||||
|
||||
<A NAME="elementary-sec">
|
||||
<P><HR>
|
||||
<CENTER><BIG>Elementary Operations on Sparse Modulo-2 Matrices</BIG></CENTER>
|
||||
</A>
|
||||
|
||||
<A NAME="find"><HR><B>mod2sparse_find</B>:
|
||||
Look for an entry at a given row and column.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
mod2entry *mod2sparse_find
|
||||
( mod2sparse *m, /* Matrix in which to look for entry */
|
||||
int row, /* Row index (from 0) */
|
||||
int col /* Column index (from 0) */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Looks for an entry at the given row and column in the matrix <B>m</B>,
|
||||
representing a non-zero element (ie, one with value 1). Returns a
|
||||
pointer to this entry if it exists, or zero (a null pointer) if it
|
||||
does not exist (ie, if that element of the matrix has value 0).
|
||||
|
||||
<P>The search strategy is to first look at the end of the row and the
|
||||
end of the column. The entry might be found at one of these two
|
||||
places, or it might be determinable from these end entries that no
|
||||
entry exists at the given row and column. Otherwise, searches are
|
||||
done from the start of the row and the start of the column, in
|
||||
parallel, until an entry with the given row and column are found, or
|
||||
until it can be determined that such an entry does not exist.
|
||||
Searching in parallel ensures that the operation will be fast if
|
||||
either the row is sparse or the column is sparse.
|
||||
|
||||
<P><A NAME="insert"><HR><B>mod2sparse_insert</B>:
|
||||
Insert an entry at a given row and column.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
mod2entry *mod2sparse_insert
|
||||
( mod2sparse *m, /* Matrix in which to insert an entry */
|
||||
int row, /* Row index (from 0) */
|
||||
int col /* Column index (from 0) */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Adds a new entry (representing an element with value 1) at the given
|
||||
row and column position in the matrix <B>m</B>. If such an entry
|
||||
already exists, nothing is done (this is not considered to be an
|
||||
error). The new (or existing) entry is returned as the value of
|
||||
this procedure.
|
||||
|
||||
<P>The search strategy is to first look at the end of the row for an
|
||||
existing entry or for the place where the new entry belongs. If this
|
||||
fails, the row is searched from the beginning. If an existing entry
|
||||
is found, it is returned. Otherwise, a new entry is created, it is
|
||||
inserted in its correct place in the row, and it is inserted in its
|
||||
correct place in its column, once again by first looking at the end,
|
||||
and then if required searching from the beginning.
|
||||
|
||||
<P>The effect of this strategy is that a sparse matrix can be efficiently
|
||||
created by either adding entries in increasing order by row and column or in
|
||||
decreasing order by row and column.
|
||||
|
||||
<P><A NAME="delete"><HR><B>mod2sparse_delete</B>:
|
||||
Delete an entry from a sparse modulo-2 matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_delete
|
||||
( mod2sparse *m, /* Matrix in which to delete an entry */
|
||||
mod2entry *e /* Entry to delete - MUST be in m */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Deletes the entry <B>e</B> from the sparse matrix <B>m</B>, which
|
||||
effectively sets to zero the element of the matrix that this entry
|
||||
corresponded to. The entry is freed for future use in the same
|
||||
matrix, but not (immediately, at least) for use in other matrices, or
|
||||
generally. The pointer to this entry should not be used again once
|
||||
it is deleted.
|
||||
|
||||
<P>The time required for this operation does not depend on how many
|
||||
entries are currently in the matrix.
|
||||
|
||||
<P><B>Warning:</B> It is an error if <B>e</B> is not an entry of
|
||||
<B>m</B>. This error is not currently diagnosed, but doing this may
|
||||
cause serious problems, as it may lead later to entries for <B>m</B>
|
||||
being erroneously freed when the matrix to which <B>e</B> properly
|
||||
belongs is freed.
|
||||
|
||||
<A NAME="arith-sec">
|
||||
<P><HR>
|
||||
<CENTER><BIG>Sparse Modulo-2 Matrix Arithmetic and Comparison</BIG></CENTER>
|
||||
</A>
|
||||
|
||||
<A NAME="transpose"><HR><B>mod2sparse_transpose</B>:
|
||||
Compute the transpose of a sparse modulo-2 matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_transpose
|
||||
( mod2sparse *m, /* Matrix to compute transpose of */
|
||||
mod2sparse *r /* Result of transpose operation */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Stores the transpose of its first argument, <B>m</B>, in the matrix
|
||||
pointed to by its second argument, <B>r</B>, which must already have
|
||||
been allocated, and which must have as many rows as <B>m</B> has
|
||||
columns, and as many columns as <B>m</B> has rows. The two matrices
|
||||
<B>m</B> and <B>r</B> must not be the same (ie, the two pointers
|
||||
passed must be different).
|
||||
|
||||
<P>The space occupied by the previous non-zero entries of <B>r</B> is
|
||||
freed for general use.
|
||||
|
||||
<P><A NAME="add"><HR><B>mod2sparse_add</B>:
|
||||
Add two sparse modulo-2 matrices.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_add
|
||||
( mod2sparse *m1, /* Left operand of add */
|
||||
mod2sparse *m2, /* Right operand of add */
|
||||
mod2sparse *r /* Place to store result of add */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Adds matrices <B>m1</B> and <B>m2</B>, storing the result in the
|
||||
matrix pointed to by <B>r</B>. All three matrices must have the same
|
||||
numbers of rows and columns. It is permissible for <B>r</B> to be the
|
||||
same as <B>m1</B> and/or <B>m2</B>. Neither of the first two matrices is
|
||||
changed by this procedure (unless they are the same as <B>r</B>).
|
||||
|
||||
<P>The space occupied by the previous non-zero entries of <B>r</B> is
|
||||
freed for general use.
|
||||
|
||||
|
||||
<P><A NAME="multiply"><HR><B>mod2sparse_multiply</B>:
|
||||
Multiply two sparse modulo-2 matrices.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_multiply
|
||||
( mod2sparse *m1, /* Left operand of multiply */
|
||||
mod2sparse *m2, /* Right operand of multiply */
|
||||
mod2sparse *r /* Place to store result of multiply */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Does a matrix multiplication of <B>m1</B> by <B>m2</B>, and stores the
|
||||
result in the matrix pointed to by <B>r</B>. The matrices must have
|
||||
compatible numbers of rows and columns. Neither of the first two
|
||||
matrices is changed by this procedure. The result matrix, <B>r</B>,
|
||||
must not be the same as either <B>m1</B> or <B>m2</B>.
|
||||
|
||||
<P>The space occupied by the previous non-zero entries of <B>r</B> is
|
||||
freed for general use.
|
||||
|
||||
<P><A NAME="mulvec"><HR><B>mod2sparse_mulvec</B>:
|
||||
Multiply a vector by a sparse modulo-2 matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_mulvec
|
||||
( mod2sparse *m, /* Pointer to matrix to multiply by, M rows, N columns */
|
||||
char *u, /* Pointer to unpacked vector to multiply, N long */
|
||||
char *v /* Pointer to unpacked result vector, M long */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Multiplies the vector <B>u</B> on the left by the sparse modulo-2
|
||||
matrix <B>m</B>, storing the result in <B>v</B>. Both <B>u</B> and
|
||||
<B>v</B> are modulo-2 vectors, but are stored unpacked, with one bit
|
||||
per char. Any non-zero value in <B>u</B> is equivalent to '1'.
|
||||
The vectors <B>u</B> and <B>v</B> must not overlap.
|
||||
|
||||
<P><A NAME="equal"><HR><B>mod2sparse_equal</B>:
|
||||
Check whether two sparse modulo-2 matrices are equal.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
int mod2sparse_equal
|
||||
( mod2sparse *m1, /* Pointers to the two matrices */
|
||||
mod2sparse *m2 /* to compare */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Returns one if every element of <B>m1</B> is equal to the
|
||||
corresponding element of <B>m2</B>, and otherwise returns zero. The
|
||||
two matrices must have the same number of rows and the same number of
|
||||
columns.
|
||||
|
||||
|
||||
<A NAME="row-col-ops-sec">
|
||||
<P><HR>
|
||||
<CENTER><BIG>Row/Column Operations on Sparse Modulo-2 Matrices</BIG>
|
||||
</CENTER></A>
|
||||
|
||||
<A NAME="count_row"><HR><B>mod2sparse_count_row</B>:
|
||||
Count the number of 1s in a row of a sparse matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
int mod2sparse_count_row
|
||||
( mod2sparse *m, /* Pointer to matrix */
|
||||
int row /* Index of row to count (from 0) */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Returns the number of 1s in the given row of the matrix, by counting
|
||||
the number of entries in that row.
|
||||
|
||||
<P><A NAME="count_col"><HR><B>mod2sparse_count_col</B>:
|
||||
Count the number of 1s in a column of a sparse matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
int mod2sparse_count_col
|
||||
( mod2sparse *m, /* Pointer to matrix */
|
||||
int col /* Index of column to count (from 0) */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Returns the number of 1s in the given column of the matrix, by counting
|
||||
the number of entries in that column.
|
||||
|
||||
<P><A NAME="add_row"><HR><B>mod2sparse_add_row</B>:
|
||||
Add a row to a row of a sparse matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_add_row
|
||||
( mod2sparse *m1, /* Matrix containing row to add to */
|
||||
int row1, /* Index in this matrix of row to add to */
|
||||
mod2sparse *m2, /* Matrix containing row to add from */
|
||||
int row2 /* Index in this matrix of row to add from */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Modifies the row with index <B>row1</B> in the matrix <B>m1</B> by
|
||||
adding to that row the row with index <B>row2</B> in the matrix
|
||||
<B>m2</B>. The matrix <B>m1</B> must have at least as many columns as
|
||||
<B>m2</B>. This operation is performed by inserting entries into the
|
||||
row of <B>m1</B> at positions where they exist in the row of <B>m2</B>
|
||||
but not in the row of <B>m1</B>, and deleting entries in the row of
|
||||
<B>m1</B> that exist in the same position in the row of <B>m2</B>.
|
||||
The matrix <B>m2</B> is not modified.
|
||||
|
||||
<P><A NAME="add_col"><HR><B>mod2sparse_add_col</B>:
|
||||
Add a column to a column of a sparse matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
void mod2sparse_add_col
|
||||
( mod2sparse *m1, /* Matrix containing column to add to */
|
||||
int col1, /* Index in this matrix of col to add to */
|
||||
mod2sparse *m2, /* Matrix containing column to add from */
|
||||
int col2 /* Index in this matrix of column to add from */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
Modifies the column with index <B>col1</B> in the matrix <B>m1</B> by
|
||||
adding to that column the column with index <B>col2</B> in the matrix
|
||||
<B>m2</B>. The matrix <B>m1</B> must have at least as many rows as
|
||||
<B>m2</B>. This operation is performed by inserting entries into the
|
||||
column of <B>m1</B> at positions where they exist in the column of
|
||||
<B>m2</B> but not in the column of <B>m1</B>, and deleting entries in
|
||||
the column of <B>m1</B> that exist in the same position in the column
|
||||
of <B>m2</B>. The matrix <B>m2</B> is not modified.
|
||||
|
||||
|
||||
<A NAME="lu-decomp-sec">
|
||||
<P><HR>
|
||||
<CENTER><BIG>LU Decomposition of Sparse Modulo-2 Matrices</BIG></CENTER>
|
||||
</A>
|
||||
|
||||
<A NAME="decomp"><HR><B>mod2sparse_decomp</B>:
|
||||
Find an LU decomposition of a sparse modulo-2 (sub-)matrix.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
int mod2sparse_decomp
|
||||
( mod2sparse *A, /* Matrix to find LU decomposition within, M by N */
|
||||
int K, /* Size of sub-matrix to find LU decomposition of */
|
||||
mod2sparse *L, /* Matrix in which L is stored, M by K */
|
||||
mod2sparse *U, /* Matrix in which U is stored, K by N */
|
||||
int *rows, /* Array where row indexes are stored, M long */
|
||||
int *cols, /* Array where column indexes are stored, N long */
|
||||
mod2sparse_strategy strategy, /* Strategy to follow in picking rows/columns */
|
||||
int abandon_number, /* Number of columns to abandon at some point */
|
||||
int abandon_when /* When to abandon these columns */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Takes as input a matrix, <B>A</B>, having <I>M</I> rows and
|
||||
<I>N</I> columns, and an integer <I>K</I>. Finds an LU decomposition
|
||||
of a <I>K</I> by <I>K</I> sub-matrix of <B>A</B>. The decomposition
|
||||
is stored in the matrix <B>L</B>, with <I>M</I> rows and <I>K</I>
|
||||
columns, and the matrix <B>U</B>, with <I>K</I> rows and <I>N</I>
|
||||
columns. The product of <B>L</B> and <B>U</B> will be equal to the
|
||||
<I>K</I> by <I>K</I> submatrix of <B>A</B> obtained by taking only
|
||||
rows and columns that are given in the first <I>K</I> elements of the
|
||||
<B>rows</B> and <B>cols</B> arrays, which are set by this procedure,
|
||||
with this sub-matrix distributed over the original <I>M</I> rows and
|
||||
<I>N</I> columns. Furthermore, the ordering of the row and column
|
||||
indexes in these arrays will be set so that if the rows of <B>L</B>
|
||||
and the columns of <B>U</B> were rearranged in this order, <B>L</B>
|
||||
would be lower triangular, with zeros in rows past row <I>K</I>, and
|
||||
<B>U</B> would be upper triangular, with zeros in columns past column
|
||||
<I>K</I>. The <B>rows</B> array is <I>M</I> long, and the <B>cols</B>
|
||||
array is <I>N</I> long. The elements in both arrays after the first
|
||||
<I>K</I> contain the indexes of the rows and columns not selected to
|
||||
be part of the sub-matrix of <B>A</B>, in arbitrary order.
|
||||
|
||||
<P>The rows and columns of <B>A</B> are selected in order to try to
|
||||
make the LU decomposition as sparse as possible, using the strategy
|
||||
identified by the <B>strategy</B>, <B>abandon_number</B>, and
|
||||
<B>abandon_when</B> parameters. The possible strategies are
|
||||
<TT>Mod2sparse_first</TT>, <TT>Mod2sparse_mincol</TT>, and
|
||||
<TT>Mod2sparse_minprod</TT>. If <B>abandon_number</B> is greater than
|
||||
zero, it is possible that the matrix will appear to have linearly
|
||||
dependent rows when it actually does not. See the <A
|
||||
HREF="sparse-LU.html">discussion of sparse LU decomposition
|
||||
methods</A> for details about these strategies.
|
||||
|
||||
<P>If <B>A</B> is not of rank <I>K</I> or more, <B>L</B> will contain
|
||||
some number less than <I>K</I> of non-zero columns, and <B>U</B> will
|
||||
contain an equal number of non-zero rows. The entries in the
|
||||
<B>rows</B> and <B>cols</B> arrays for the extra zero rows or columns
|
||||
will be arbitrary (but valid). The number of extra zero columns is
|
||||
returned as the value of this procedure (hence a return value of zero
|
||||
indicates that a <I>K</I> by <I>K</I> sub-matrix of full rank was
|
||||
found).
|
||||
|
||||
<P>The matrix <B>A</B> is not altered. The previous contents of
|
||||
<B>L</B> and <B>U</B> are cleared.
|
||||
|
||||
<P><A NAME="forward_sub"><HR><B>mod2sparse_forward_sub</B>:
|
||||
Solve a lower-triangular system by forward substitution.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
int mod2sparse_forward_sub
|
||||
( mod2sparse *L, /* Matrix that is lower triangular after reordering */
|
||||
int *rows, /* Array of indexes (from 0) of rows for new order */
|
||||
char *x, /* Vector on right of equation, also reordered */
|
||||
char *y /* Place to store solution */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Solves the system of equations <B>Ly</B>=<B>x</B> for <B>y</B> by
|
||||
forward substitution, based on <B>L</B> being lower triangular after
|
||||
its rows are reordered according to the given index array. The
|
||||
vectors <B>x</B> and <B>y</B> are stored unpacked, one bit per
|
||||
character. If <B>L</B> is <I>M</I> by <I>K</I>, then <B>x</B> should
|
||||
be <I>M</I> long, but only the <I>K</I> bits indexed by <B>rows</B>
|
||||
are looked at. The solution vector, <B>y</B>, must be <I>K</I> long.
|
||||
Only <I>K</I> rows of <B>L</B> are used, as also determined by the
|
||||
<I>K</I> indexes in the <B>rows</B> argument. If <B>rows</B> is null,
|
||||
the first <I>K</I> rows of <B>L</B> and the first <I>K</I> elements of
|
||||
<B>x</B> are used.
|
||||
|
||||
<P>If the matrix <B>L</B> does not have 1s on its diagonal (after row
|
||||
rearrangement), there may be no solution, depending on what <B>x</B>
|
||||
is. If no solution exists, this procedure returns zero, otherwise it
|
||||
returns one. Any arbitrary bits in the solution are set to zero.
|
||||
|
||||
<P><A NAME="backward_sub"><HR><B>mod2sparse_backward_sub</B>:
|
||||
Solve an upper-triangular system by backward substitution.</A>
|
||||
|
||||
<BLOCKQUOTE><PRE>
|
||||
int mod2sparse_backward_sub
|
||||
( mod2sparse *U, /* Matrix that is upper triangular after reordering */
|
||||
int *cols, /* Array of indexes (from 0) of columns for new order */
|
||||
char *y, /* Vector on right of equation */
|
||||
char *z /* Place to store solution, also reordered */
|
||||
)
|
||||
</PRE></BLOCKQUOTE>
|
||||
|
||||
<P>Solves <B>Uz</B>=<B>y</B> for <B>z</B> by backward substitution,
|
||||
based on <B>U</B> being upper triangular after its columns are
|
||||
reordered according to the given index array. The vectors <B>y</B>
|
||||
and <B>z</B> are stored unpacked, one bit per character. If <B>U</B>
|
||||
is <I>K</I> by <I>N</I>, then the solution vector, <I>z</I>, should be
|
||||
<I>N</I> long, but only the <I>K</I> bits indexed by <B>cols</B> are
|
||||
set. The vector <B>y</B> must be <I>K</I> long. Only <I>K</I> columns
|
||||
of <B>U</B> are used, as also determined by the <I>K</I> indexes in
|
||||
the <B>cols</B> argument. The other columns of <B>U</B> must be zero
|
||||
(this is not checked, but is necessary for the method used to work).
|
||||
If <B>cols</B> is null, the first <I>K</I> columns of <B>U</B> and the
|
||||
first <I>K</I> elements of <B>z</B> are used.
|
||||
|
||||
<P>If the matrix <B>U</B> does not have 1s on its diagonal (after
|
||||
column rearrangement) there may be no solution, depending on what y
|
||||
is. If no solution exists, this procedure returns zero, otherwise it
|
||||
returns one. Any arbitrary bits in the solution are set to zero.
|
||||
|
||||
<HR>
|
||||
|
||||
<A HREF="index.html">Back to index for LDPC software</A>
|
||||
|
||||
</BODY></HTML>
|
||||
@@ -1,3 +0,0 @@
|
||||
2
|
||||
3 4
|
||||
.9 .1
|
||||
|
Before Width: | Height: | Size: 3.0 KiB |
@@ -1,46 +0,0 @@
|
||||
#include "SplashScreen.hpp"
|
||||
|
||||
#include <QPixmap>
|
||||
#include <QVBoxLayout>
|
||||
#include <QCheckBox>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "revision_utils.hpp"
|
||||
#include "pimpl_impl.hpp"
|
||||
|
||||
class SplashScreen::impl
|
||||
{
|
||||
public:
|
||||
impl ()
|
||||
: checkbox_ {"Do not show this again"}
|
||||
{
|
||||
main_layout_.addStretch ();
|
||||
main_layout_.addWidget (&checkbox_, 0, Qt::AlignRight);
|
||||
}
|
||||
|
||||
QVBoxLayout main_layout_;
|
||||
QCheckBox checkbox_;
|
||||
};
|
||||
|
||||
SplashScreen::SplashScreen ()
|
||||
: QSplashScreen {QPixmap {":/splash.png"}, Qt::WindowStaysOnTopHint}
|
||||
{
|
||||
setLayout (&m_->main_layout_);
|
||||
showMessage ("<h2>" + QString {"WSJT-X v" +
|
||||
QCoreApplication::applicationVersion() + " " +
|
||||
revision ()}.simplified () + "</h2>"
|
||||
"V1.8 has many new features.<br /><br />"
|
||||
"The release notes have more details.<br /><br />"
|
||||
"Send issue reports to wsjtgroup@yahoogroups.com, and be sure to save .wav<br />"
|
||||
"files where appropriate.<br /><br />"
|
||||
"<b>Open the Help menu and select Release Notes for more details.</b><br />"
|
||||
"<img src=\":/icon_128x128.png\" />"
|
||||
"<img src=\":/gpl-v3-logo.svg\" height=\"80\" />", Qt::AlignCenter);
|
||||
connect (&m_->checkbox_, &QCheckBox::stateChanged, [this] (int s) {
|
||||
if (Qt::Checked == s) Q_EMIT disabled ();
|
||||
});
|
||||
}
|
||||
|
||||
SplashScreen::~SplashScreen ()
|
||||
{
|
||||
}
|
||||