Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
@@ -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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||
}
|
||||
Binary file not shown.
|
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);
|
||||
@@ -0,0 +1,54 @@
|
||||
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
|
||||
integer (c_short) :: crc12
|
||||
type (c_ptr), value :: data
|
||||
integer (c_int), value :: length
|
||||
end function crc12
|
||||
|
||||
function crc12_check (data, length) bind (C, name="crc12_check")
|
||||
use, intrinsic :: iso_c_binding, only: c_bool, c_ptr, c_int
|
||||
implicit none
|
||||
logical (c_bool) :: crc12_check
|
||||
type (c_ptr), value :: data
|
||||
integer (c_int), value :: length
|
||||
end function crc12_check
|
||||
|
||||
function crc10 (data, length) bind (C, name="crc10")
|
||||
use, intrinsic :: iso_c_binding, only: c_short, c_ptr, c_int
|
||||
implicit none
|
||||
integer (c_short) :: crc10
|
||||
type (c_ptr), value :: data
|
||||
integer (c_int), value :: length
|
||||
end function crc10
|
||||
|
||||
function crc10_check (data, length) bind (C, name="crc10_check")
|
||||
use, intrinsic :: iso_c_binding, only: c_bool, c_ptr, c_int
|
||||
implicit none
|
||||
logical (c_bool) :: crc10_check
|
||||
type (c_ptr), value :: data
|
||||
integer (c_int), value :: length
|
||||
end function crc10_check
|
||||
|
||||
end interface
|
||||
end module crc
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.7 KiB |
File diff suppressed because it is too large
Load Diff
@@ -1,48 +0,0 @@
|
||||
subroutine extractmessage174(decoded,msgreceived,ncrcflag,recent_calls,nrecent)
|
||||
use iso_c_binding, only: c_loc,c_size_t
|
||||
use crc
|
||||
use packjt
|
||||
|
||||
character*22 msgreceived
|
||||
character*12 call1,call2
|
||||
character*12 recent_calls(nrecent)
|
||||
character*87 cbits
|
||||
integer*1 decoded(87)
|
||||
integer*1, target:: i1Dec8BitBytes(11)
|
||||
integer*4 i4Dec6BitWords(12)
|
||||
|
||||
! Write decoded bits into cbits: 75-bit message plus 12-bit CRC
|
||||
write(cbits,1000) decoded
|
||||
1000 format(87i1)
|
||||
read(cbits,1001) i1Dec8BitBytes
|
||||
1001 format(11b8)
|
||||
read(cbits,1002) ncrc12 !Received CRC12
|
||||
1002 format(75x,b12)
|
||||
|
||||
i1Dec8BitBytes(10)=iand(i1Dec8BitBytes(10),128+64+32)
|
||||
i1Dec8BitBytes(11)=0
|
||||
icrc12=crc12(c_loc(i1Dec8BitBytes),11) !CRC12 computed from 75 msg bits
|
||||
|
||||
if(ncrc12.eq.icrc12) then
|
||||
! CRC12 checks out --- unpack 72-bit message
|
||||
do ibyte=1,12
|
||||
itmp=0
|
||||
do ibit=1,6
|
||||
itmp=ishft(itmp,1)+iand(1,decoded((ibyte-1)*6+ibit))
|
||||
enddo
|
||||
i4Dec6BitWords(ibyte)=itmp
|
||||
enddo
|
||||
call unpackmsg144(i4Dec6BitWords,msgreceived,call1,call2)
|
||||
ncrcflag=1
|
||||
if( call1(1:2) .ne. 'CQ' .and. call1(1:2) .ne. ' ' ) then
|
||||
call update_recent_calls(call1,recent_calls,nrecent)
|
||||
endif
|
||||
if( call2(1:2) .ne. ' ' ) then
|
||||
call update_recent_calls(call2,recent_calls,nrecent)
|
||||
endif
|
||||
else
|
||||
msgreceived=' '
|
||||
ncrcflag=-1
|
||||
endif
|
||||
return
|
||||
end subroutine extractmessage174
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
// 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 the Rx frequency. To decode a particular signal, double-click
|
||||
near the left edge of its waterfall trace.
|
||||
|
||||
- Now double-click on any of the the lines of decoded text in the main
|
||||
window. All three lines will show the same behavior, setting Rx
|
||||
frequency to that of the selected message and leaving Tx frequency
|
||||
unchanged. To change both Rx and Tx frequencies, hold *Ctrl* down
|
||||
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. The same is true when you tail-end another QSO. Choose a Tx
|
||||
frequency that appears to be not in use.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,50 @@
|
||||
subroutine encode174(message,codeword)
|
||||
! 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
|
||||
!
|
||||
|
||||
include "ldpc_174_87_params.f90"
|
||||
|
||||
integer*1 codeword(N)
|
||||
integer*1 gen(M,K)
|
||||
integer*1 itmp(N)
|
||||
integer*1 message(K)
|
||||
integer*1 pchecks(M)
|
||||
logical first
|
||||
data first/.true./
|
||||
|
||||
save first,gen
|
||||
|
||||
if( first ) then ! fill the generator matrix
|
||||
gen=0
|
||||
do i=1,M
|
||||
do j=1,11
|
||||
read(g(i)( (j-1)*2+1:(j-1)*2+2 ),"(Z2)") istr
|
||||
do jj=1, 8
|
||||
icol=(j-1)*8+jj
|
||||
if( icol .le. 87 ) then
|
||||
if( btest(istr,8-jj) ) gen(i,icol)=1
|
||||
endif
|
||||
enddo
|
||||
enddo
|
||||
enddo
|
||||
first=.false.
|
||||
endif
|
||||
|
||||
do i=1,M
|
||||
nsum=0
|
||||
do j=1,K
|
||||
nsum=nsum+message(j)*gen(i,j)
|
||||
enddo
|
||||
pchecks(i)=mod(nsum,2)
|
||||
enddo
|
||||
itmp(1:M)=pchecks
|
||||
itmp(M+1:N)=message(1:K)
|
||||
codeword(colorder+1)=itmp(1:N)
|
||||
|
||||
return
|
||||
end subroutine encode174
|
||||
@@ -1,151 +0,0 @@
|
||||
#include "logqso.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QSettings>
|
||||
#include <QStandardPaths>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
|
||||
#include "logbook/adif.h"
|
||||
#include "MessageBox.hpp"
|
||||
#include "Configuration.hpp"
|
||||
#include "Bands.hpp"
|
||||
|
||||
#include "ui_logqso.h"
|
||||
#include "moc_logqso.cpp"
|
||||
|
||||
LogQSO::LogQSO(QString const& programTitle, QSettings * settings
|
||||
, Configuration const * config, QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::LogQSO)
|
||||
, m_settings (settings)
|
||||
, m_config {config}
|
||||
{
|
||||
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;
|
||||
ui->band->setText (m_config->bands ()->find (dialFreq));
|
||||
|
||||
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,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);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,211 +0,0 @@
|
||||
//
|
||||
// UDPDaemon - an example console application that utilizes the WSJT-X
|
||||
// messaging facility
|
||||
//
|
||||
// This application is only provided as a simple console application
|
||||
// example to demonstrate the WSJT-X messaging facility. It allows
|
||||
// the user to set the server details either as a unicast UDP server
|
||||
// or, if a multicast group address is provided, as a multicast
|
||||
// server. The benefit of the multicast server is that multiple
|
||||
// servers can be active at once each receiving all WSJT-X broadcast
|
||||
// messages and each able to respond to individual WSJT_X clients. To
|
||||
// utilize the multicast group features each WSJT-X client must set
|
||||
// the same multicast group address as the UDP server address for
|
||||
// example 239.255.0.0 for a site local multicast group.
|
||||
//
|
||||
//
|
||||
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QCommandLineParser>
|
||||
#include <QDateTime>
|
||||
#include <QTime>
|
||||
#include <QHash>
|
||||
#include <QDebug>
|
||||
|
||||
#include "MessageServer.hpp"
|
||||
#include "Radio.hpp"
|
||||
|
||||
#include "qt_helpers.hpp"
|
||||
|
||||
using port_type = MessageServer::port_type;
|
||||
using Frequency = MessageServer::Frequency;
|
||||
|
||||
class Client
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Client (QString const& id, QObject * parent = nullptr)
|
||||
: QObject {parent}
|
||||
, id_ {id}
|
||||
, dial_frequency_ {0u}
|
||||
{
|
||||
}
|
||||
|
||||
Q_SLOT void 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_)
|
||||
{
|
||||
if (f != dial_frequency_)
|
||||
{
|
||||
std::cout << tr ("%1: Dial frequency changed to %2").arg (id_).arg (f).toStdString () << std::endl;
|
||||
dial_frequency_ = f;
|
||||
}
|
||||
if (mode + sub_mode != mode_)
|
||||
{
|
||||
std::cout << tr ("%1: Mode changed to %2").arg (id_).arg (mode + sub_mode).toStdString () << std::endl;
|
||||
mode_ = mode + sub_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Q_SLOT void 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, bool low_confidence, bool off_air)
|
||||
{
|
||||
if (client_id == id_)
|
||||
{
|
||||
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
|
||||
<< "Dt:" << delta_time << "Df:" << delta_frequency
|
||||
<< "mode:" << mode << "Confidence:" << (low_confidence ? "low" : "high")
|
||||
<< "On air:" << !off_air;
|
||||
std::cout << tr ("%1: Decoded %2").arg (id_).arg (message).toStdString () << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Q_SLOT void 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, bool off_air)
|
||||
{
|
||||
if (client_id == id_)
|
||||
{
|
||||
qDebug () << "new:" << is_new << "t:" << time << "snr:" << snr
|
||||
<< "Dt:" << delta_time << "Df:" << delta_frequency
|
||||
<< "drift:" << drift;
|
||||
std::cout << tr ("%1: WSPR decode %2 grid %3 power: %4").arg (id_).arg (callsign).arg (grid).arg (power).toStdString ()
|
||||
<< "On air:" << !off_air << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
QString id_;
|
||||
Frequency dial_frequency_;
|
||||
QString mode_;
|
||||
};
|
||||
|
||||
class Server
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Server (port_type port, QHostAddress const& multicast_group)
|
||||
: server_ {new MessageServer {this}}
|
||||
{
|
||||
// connect up server
|
||||
connect (server_, &MessageServer::error, [this] (QString const& message) {
|
||||
std::cerr << tr ("Network Error: %1").arg ( message).toStdString () << std::endl;
|
||||
});
|
||||
connect (server_, &MessageServer::client_opened, this, &Server::add_client);
|
||||
connect (server_, &MessageServer::client_closed, this, &Server::remove_client);
|
||||
|
||||
server_->start (port, multicast_group);
|
||||
}
|
||||
|
||||
private:
|
||||
void add_client (QString const& id, QString const& version, QString const& revision)
|
||||
{
|
||||
auto client = new Client {id};
|
||||
connect (server_, &MessageServer::status_update, client, &Client::update_status);
|
||||
connect (server_, &MessageServer::decode, client, &Client::decode_added);
|
||||
connect (server_, &MessageServer::WSPR_decode, client, &Client::beacon_spot_added);
|
||||
clients_[id] = client;
|
||||
server_->replay (id);
|
||||
std::cout << "Discovered WSJT-X instance: " << id.toStdString ();
|
||||
if (version.size ())
|
||||
{
|
||||
std::cout << " v" << version.toStdString ();
|
||||
}
|
||||
if (revision.size ())
|
||||
{
|
||||
std::cout << " (" << revision.toStdString () << ")";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void remove_client (QString const& id)
|
||||
{
|
||||
auto iter = clients_.find (id);
|
||||
if (iter != std::end (clients_))
|
||||
{
|
||||
clients_.erase (iter);
|
||||
(*iter)->deleteLater ();
|
||||
}
|
||||
std::cout << "Removed WSJT-X instance: " << id.toStdString () << std::endl;
|
||||
}
|
||||
|
||||
MessageServer * server_;
|
||||
|
||||
// maps client id to clients
|
||||
QHash<QString, Client *> clients_;
|
||||
};
|
||||
|
||||
#include "UDPDaemon.moc"
|
||||
|
||||
int main (int argc, char * argv[])
|
||||
{
|
||||
QCoreApplication app {argc, argv};
|
||||
try
|
||||
{
|
||||
setlocale (LC_NUMERIC, "C"); // ensure number forms are in
|
||||
// consistent format, do this after
|
||||
// instantiating QApplication so
|
||||
// that GUI has correct l18n
|
||||
|
||||
app.setApplicationName ("WSJT-X UDP Message Server Daemon");
|
||||
app.setApplicationVersion ("1.0");
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription ("\nWSJT-X UDP Message Server Daemon.");
|
||||
auto help_option = parser.addHelpOption ();
|
||||
auto version_option = parser.addVersionOption ();
|
||||
|
||||
QCommandLineOption port_option (QStringList {"p", "port"},
|
||||
app.translate ("UDPDaemon",
|
||||
"Where <PORT> is the UDP service port number to listen on.\n"
|
||||
"The default service port is 2237."),
|
||||
app.translate ("UDPDaemon", "PORT"),
|
||||
"2237");
|
||||
parser.addOption (port_option);
|
||||
|
||||
QCommandLineOption multicast_addr_option (QStringList {"g", "multicast-group"},
|
||||
app.translate ("UDPDaemon",
|
||||
"Where <GROUP> is the multicast group to join.\n"
|
||||
"The default is a unicast server listening on all interfaces."),
|
||||
app.translate ("UDPDaemon", "GROUP"));
|
||||
parser.addOption (multicast_addr_option);
|
||||
|
||||
parser.process (app);
|
||||
|
||||
Server server {static_cast<port_type> (parser.value (port_option).toUInt ()), QHostAddress {parser.value (multicast_addr_option)}};
|
||||
|
||||
return app.exec ();
|
||||
}
|
||||
catch (std::exception const & e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what () << '\n';
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "Unexpected error\n";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -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
|
||||
Binary file not shown.
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,544 @@
|
||||
program wspr5d
|
||||
|
||||
! Decode WSPR-LF data read from *.c5 or *.wav files.
|
||||
|
||||
! WSPR-LF is a potential WSPR-like mode intended for use at LF and MF.
|
||||
! It uses an LDPC (300,60) code, OQPSK modulation, and 5 minute T/R sequences.
|
||||
!
|
||||
! Still to do: find and decode more than one signal in the specified passband.
|
||||
|
||||
! include 'wsprlf_params.f90'
|
||||
|
||||
parameter (NDOWN=30)
|
||||
parameter (KK=60)
|
||||
parameter (ND=300)
|
||||
parameter (NS=109)
|
||||
parameter (NR=3)
|
||||
parameter (NN=NR+NS+ND)
|
||||
parameter (NSPS0=8640)
|
||||
parameter (NSPS=16)
|
||||
parameter (N2=2*NSPS)
|
||||
parameter (NZ=NSPS*NN)
|
||||
parameter (NZ400=288*NN)
|
||||
parameter (NMAX=300*12000)
|
||||
|
||||
character arg*8,message*22,cbits*50,infile*80,fname*16,datetime*11
|
||||
character*120 data_dir
|
||||
complex csync(0:NZ-1) !Sync symbols only, from cbb
|
||||
complex c400(0:NZ400-1) !Complex waveform
|
||||
complex c(0:NZ-1) !Complex waveform
|
||||
complex cd(0:NZ-1) !Complex waveform
|
||||
complex ca(0:NZ-1) !Complex waveform
|
||||
complex zz,zzsum
|
||||
real*8 fMHz
|
||||
real rxdata(ND),llr(ND) !Soft symbols
|
||||
real pp(32) !Shaped pulse for OQPSK
|
||||
real sbits(412),softbits(9)
|
||||
real fpks(20)
|
||||
integer id(NS+ND) !NRZ values (+/-1) for Sync and Data
|
||||
integer isync(48) !Long sync vector
|
||||
integer ib13(13) !Barker 13 code
|
||||
integer ihdr(11)
|
||||
integer*8 n8
|
||||
integer*2 iwave(NMAX) !Generated full-length waveform
|
||||
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()
|
||||
if(nargs.lt.2) then
|
||||
print*,'Usage: wspr5d [-a <data_dir>] [-f fMHz] file1 [file2 ...]'
|
||||
go to 999
|
||||
endif
|
||||
iarg=1
|
||||
data_dir="."
|
||||
call getarg(iarg,arg)
|
||||
if(arg(1:2).eq.'-a') then
|
||||
call getarg(iarg+1,data_dir)
|
||||
iarg=iarg+2
|
||||
endif
|
||||
call getarg(iarg,arg)
|
||||
if(arg(1:2).eq.'-f') then
|
||||
call getarg(iarg+1,arg)
|
||||
read(arg,*) fMHz
|
||||
iarg=iarg+2
|
||||
endif
|
||||
|
||||
open(13,file=trim(data_dir)//'/ALL_WSPR.TXT',status='unknown', &
|
||||
position='append')
|
||||
maxn=8 !Default value
|
||||
twopi=8.0*atan(1.0)
|
||||
fs=NSPS*12000.0/NSPS0 !Sample rate
|
||||
dt=1.0/fs !Sample interval (s)
|
||||
tt=NSPS*dt !Duration of "itone" symbols (s)
|
||||
ts=2*NSPS*dt !Duration of OQPSK symbols (s)
|
||||
baud=1.0/tt !Keying rate for "itone" symbols (baud)
|
||||
txt=NZ*dt !Transmission length (s)
|
||||
|
||||
do i=1,32 !Half-sine pulse shape
|
||||
pp(i)=sin(0.5*(i-1)*twopi/(32))
|
||||
enddo
|
||||
n8=z'cbf089223a51'
|
||||
do i=1,48
|
||||
isync(i)=-1
|
||||
if(iand(n8,1).eq.1) isync(i)=1
|
||||
n8=n8/2
|
||||
enddo
|
||||
|
||||
! Define array id() for sync symbols
|
||||
id=0
|
||||
do j=1,48 !First group of 48
|
||||
id(2*j-1)=2*isync(j)
|
||||
enddo
|
||||
do j=1,13 !Barker 13 code
|
||||
id(j+96)=2*ib13(j)
|
||||
enddo
|
||||
do j=1,48 !Second group of 48
|
||||
id(2*j+109)=2*isync(j)
|
||||
enddo
|
||||
|
||||
csync=0.
|
||||
do j=1,205
|
||||
if(abs(id(j)).eq.2) then
|
||||
ia=nint((j-0.5)*N2)
|
||||
ib=ia+N2-1
|
||||
csync(ia:ib)=pp*id(j)/abs(id(j))
|
||||
endif
|
||||
enddo
|
||||
|
||||
do ifile=iarg,nargs
|
||||
call getarg(ifile,infile)
|
||||
open(10,file=infile,status='old',access='stream')
|
||||
j1=index(infile,'.c5')
|
||||
j2=index(infile,'.wav')
|
||||
if(j1.gt.0) then
|
||||
read(10,end=999) fname,ntrmin,fMHz,c400
|
||||
read(fname(8:11),*) nutc
|
||||
write(datetime,'(i11)') nutc
|
||||
else if(j2.gt.0) then
|
||||
read(10,end=999) ihdr,iwave
|
||||
read(infile(j2-4:j2-1),*) nutc
|
||||
datetime=infile(j2-11:j2-1)
|
||||
call wspr5_downsample(iwave,c400)
|
||||
else
|
||||
print*,'Wrong file format?'
|
||||
go to 999
|
||||
endif
|
||||
close(10)
|
||||
|
||||
fa=100.0
|
||||
fb=150.0
|
||||
fs400=400.0
|
||||
call getfc1(c400,fs400,fa,fb,fc1,xsnr) !First approx for freq
|
||||
npeaks=5
|
||||
call getfc2(c400,npeaks,fs400,fc1,fpks) !Refined freq
|
||||
|
||||
! 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,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)
|
||||
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
|
||||
istep=iseq*4
|
||||
endif
|
||||
do i=1,408,istep
|
||||
j=(i+1)*16
|
||||
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 .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
|
||||
sbits(i+11)=softbits(9)
|
||||
endif
|
||||
endif
|
||||
enddo
|
||||
j=1
|
||||
do i=1,205
|
||||
if( abs(id(i)) .ne. 2 ) then
|
||||
rxdata(j)=sbits(2*i-1)
|
||||
j=j+1
|
||||
endif
|
||||
enddo
|
||||
do i=1,204
|
||||
rxdata(j)=sbits(2*i)
|
||||
j=j+1
|
||||
enddo
|
||||
rxav=sum(rxdata)/ND
|
||||
rx2av=sum(rxdata*rxdata)/ND
|
||||
rxsig=sqrt(rx2av-rxav*rxav)
|
||||
rxdata=rxdata/rxsig
|
||||
sigma=1.20
|
||||
llr=2*rxdata/(sigma*sigma)
|
||||
apmask=0
|
||||
max_iterations=40
|
||||
|
||||
ifer=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
|
||||
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)
|
||||
read(cbits,1202) idat
|
||||
1202 format(6b8,b2)
|
||||
idat(7)=ishft(idat(7),6)
|
||||
call wqdecode(idat,message,itype)
|
||||
nsnr=nint(xsnr)
|
||||
! 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,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
|
||||
enddo
|
||||
enddo
|
||||
888 continue
|
||||
enddo
|
||||
|
||||
write(*,1120)
|
||||
1120 format("<DecodeFinished>")
|
||||
|
||||
999 end program wspr5d
|
||||
|
||||
subroutine getmetric(ib,ps,xmet)
|
||||
real ps(0:511)
|
||||
xm1=0
|
||||
xm0=0
|
||||
do i=0,511
|
||||
if( iand(i/ib,1) .eq. 1 .and. ps(i) .gt. xm1 ) xm1=ps(i)
|
||||
if( iand(i/ib,1) .eq. 0 .and. ps(i) .gt. xm0 ) xm0=ps(i)
|
||||
enddo
|
||||
xmet=xm1-xm0
|
||||
return
|
||||
end subroutine getmetric
|
||||
|
||||
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.
|
||||
!
|
||||
complex cdat(16*12),cbest(16*12),cideal(16*12)
|
||||
complex cdf(16*12),cfac,zz
|
||||
real cm(0:511),cmbest(0:511)
|
||||
real pp(32),softbits(9)
|
||||
integer bit(13),bestbits(13),sgn(13)
|
||||
integer bsync(7)
|
||||
|
||||
twopi=8.0*atan(1.0)
|
||||
dt=30.0*18.0/12000.0
|
||||
cmax=0;
|
||||
fbest=0.0;
|
||||
np=2**ns-1
|
||||
idfmax=40
|
||||
if( ncoh .eq. 1 ) idfmax=0
|
||||
do idf=0,idfmax
|
||||
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))
|
||||
cdf=1.0
|
||||
do i=2,16*(ns-1)
|
||||
cdf(i)=cdf(i-1)*cfac
|
||||
enddo
|
||||
|
||||
cm=0
|
||||
ibflag=0
|
||||
do i=0,np
|
||||
bit(1)=(bsync(1)+2)/4
|
||||
bit(2)=iand(i/(2**(ns-1)),1)
|
||||
bit(3)=iand(i/(2**(ns-2)),1)
|
||||
if( bsync(2).ne.0 ) then ! force the barker bits
|
||||
bit(3)=(bsync(2)+2)/4
|
||||
endif
|
||||
bit(4)=iand(i/(2**(ns-3)),1)
|
||||
bit(5)=(bsync(3)+2)/4
|
||||
|
||||
if( ns .ge. 6 ) then
|
||||
bit(6)=iand(i/(2**(ns-4)),1)
|
||||
bit(7)=iand(i/(2**(ns-5)),1)
|
||||
if( bsync(4).ne.0 ) then ! force the barker bits
|
||||
bit(7)=(bsync(4)+2)/4
|
||||
endif
|
||||
bit(8)=iand(i/(2**(ns-6)),1)
|
||||
bit(9)=(bsync(5)+2)/4
|
||||
if( ns .eq. 9 ) then
|
||||
bit(10)=iand(i/4,1)
|
||||
bit(11)=iand(i/2,1)
|
||||
if( bsync(6).ne.0 ) then ! force the barker bits
|
||||
bit(11)=(bsync(6)+2)/4
|
||||
endif
|
||||
bit(12)=iand(i/1,1)
|
||||
bit(13)=(bsync(7)+2)/4
|
||||
endif
|
||||
endif
|
||||
|
||||
sgn=2*bit-1
|
||||
cideal(1:16) =cmplx(sgn(1)*pp(17:32),sgn(2)*pp(1:16))
|
||||
cideal(17:32) =cmplx(sgn(3)*pp(1:16),sgn(2)*pp(17:32))
|
||||
cideal(33:48) =cmplx(sgn(3)*pp(17:32),sgn(4)*pp(1:16))
|
||||
cideal(49:64) =cmplx(sgn(5)*pp(1:16),sgn(4)*pp(17:32))
|
||||
if( ns .ge. 6 ) then
|
||||
cideal(65:80) =cmplx(sgn(5)*pp(17:32),sgn(6)*pp(1:16))
|
||||
cideal(81:96) =cmplx(sgn(7)*pp(1:16),sgn(6)*pp(17:32))
|
||||
cideal(97:112) =cmplx(sgn(7)*pp(17:32),sgn(8)*pp(1:16))
|
||||
cideal(113:128)=cmplx(sgn(9)*pp(1:16),sgn(8)*pp(17:32))
|
||||
if( ns .eq. 9 ) then
|
||||
cideal(129:144) =cmplx(sgn(9)*pp(17:32),sgn(10)*pp(1:16))
|
||||
cideal(145:160) =cmplx(sgn(11)*pp(1:16),sgn(10)*pp(17:32))
|
||||
cideal(161:176) =cmplx(sgn(11)*pp(17:32),sgn(12)*pp(1:16))
|
||||
cideal(177:192)=cmplx(sgn(13)*pp(1:16),sgn(12)*pp(17:32))
|
||||
endif
|
||||
endif
|
||||
cideal=cideal*cdf
|
||||
cm(i)=abs(sum(cdat(1:64*ns/3)*conjg(cideal(1:64*ns/3))))/1.e3
|
||||
if( cm(i) .gt. cmax ) then
|
||||
ibflag=1
|
||||
cmax=cm(i)
|
||||
bestbits=bit
|
||||
cbest=cideal
|
||||
fbest=deltaf
|
||||
zz=sum(cdat*conjg(cbest))/1.e3
|
||||
endif
|
||||
enddo
|
||||
if( ibflag .eq. 1 ) then ! new best found
|
||||
cmbest=cm
|
||||
endif
|
||||
enddo
|
||||
softbits=0.0
|
||||
call getmetric(1,cmbest,softbits(ns))
|
||||
call getmetric(2,cmbest,softbits(ns-1))
|
||||
call getmetric(4,cmbest,softbits(ns-2))
|
||||
if( ns .ge. 6 ) then
|
||||
call getmetric(8,cmbest,softbits(ns-3))
|
||||
call getmetric(16,cmbest,softbits(ns-4))
|
||||
call getmetric(32,cmbest,softbits(ns-5))
|
||||
if( ns .eq. 9 ) then
|
||||
call getmetric(64,cmbest,softbits(3))
|
||||
call getmetric(128,cmbest,softbits(2))
|
||||
call getmetric(256,cmbest,softbits(1))
|
||||
endif
|
||||
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)
|
||||
complex co(0:NO-1)
|
||||
|
||||
df=400.0/NI
|
||||
ct=ci
|
||||
call four2a(ct,NI,1,-1,1) !c2c FFT to freq domain
|
||||
i0=nint(f0/df)
|
||||
co=0.0
|
||||
co(0)=ct(i0)
|
||||
! b=3.0 !optimized for sequence detection
|
||||
b=6.0
|
||||
do i=1,NO/2
|
||||
arg=(i*df/b)**2
|
||||
filt=exp(-arg)
|
||||
co(i)=ct(i0+i)*filt
|
||||
co(NO-i)=ct(i0-i)*filt
|
||||
enddo
|
||||
co=co/NO
|
||||
call four2a(co,NO,1,1,1) !c2c FFT back to time domain
|
||||
return
|
||||
end subroutine downsample
|
||||
|
||||
subroutine getfc1(c,fs,fa,fb,fc1,xsnr)
|
||||
|
||||
! include 'wsprlf_params.f90'
|
||||
parameter (NZ=288*412)
|
||||
parameter (NSPS=288)
|
||||
parameter (N2=2*NSPS)
|
||||
parameter (NFFT1=16*NSPS)
|
||||
parameter (NH1=NFFT1/2)
|
||||
|
||||
complex c(0:NZ-1) !Complex waveform
|
||||
complex c2(0:NFFT1-1) !Short spectra
|
||||
real s(-NH1+1:NH1) !Coarse spectrum
|
||||
nspec=NZ/N2
|
||||
df1=fs/NFFT1
|
||||
s=0.
|
||||
do k=1,nspec
|
||||
ia=(k-1)*N2
|
||||
ib=ia+N2-1
|
||||
c2(0:N2-1)=c(ia:ib)
|
||||
c2(N2:)=0.
|
||||
call four2a(c2,NFFT1,1,-1,1)
|
||||
do i=0,NFFT1-1
|
||||
j=i
|
||||
if(j.gt.NH1) j=j-NFFT1
|
||||
s(j)=s(j) + real(c2(i))**2 + aimag(c2(i))**2
|
||||
enddo
|
||||
enddo
|
||||
! call smo121(s,NFFT1)
|
||||
smax=0.
|
||||
ipk=0
|
||||
fc1=0.
|
||||
ia=nint(fa/df1)
|
||||
ib=nint(fb/df1)
|
||||
do i=ia,ib
|
||||
f=i*df1
|
||||
if(s(i).gt.smax) then
|
||||
smax=s(i)
|
||||
ipk=i
|
||||
fc1=f
|
||||
endif
|
||||
! write(51,3001) f,s(i),db(s(i))
|
||||
! 3001 format(f10.3,e12.3,f10.3)
|
||||
enddo
|
||||
|
||||
! The following is for testing SNR calibration:
|
||||
sp3n=(s(ipk-1)+s(ipk)+s(ipk+1)) !Sig + 3*noise
|
||||
base=(sum(s)-sp3n)/(NFFT1-3.0) !Noise per bin
|
||||
psig=sp3n-3*base !Sig only
|
||||
pnoise=(2500.0/df1)*base !Noise in 2500 Hz
|
||||
xsnr=db(psig/pnoise)
|
||||
xsnr=xsnr+5.0
|
||||
return
|
||||
end subroutine getfc1
|
||||
|
||||
subroutine getfc2(c,npeaks,fs,fc1,fpks)
|
||||
|
||||
! include 'wsprlf_params.f90'
|
||||
parameter (NZ=288*412)
|
||||
parameter (NSPS=288)
|
||||
parameter (N2=2*NSPS)
|
||||
parameter (NFFT1=16*NSPS)
|
||||
parameter (NH1=NFFT1/2)
|
||||
|
||||
complex c(0:NZ-1) !Complex waveform
|
||||
complex cs(0:NZ-1) !For computing spectrum
|
||||
real a(5)
|
||||
real freqs(413),sp2(413),fpks(npeaks)
|
||||
integer pkloc(1)
|
||||
|
||||
df=fs/NZ
|
||||
baud=fs/NSPS
|
||||
a(1)=-fc1
|
||||
a(2:5)=0.
|
||||
call twkfreq1(c,NZ,fs,a,cs) !Mix down by fc1
|
||||
|
||||
! Filter, square, then FFT to get refined carrier frequency fc2.
|
||||
call four2a(cs,NZ,1,-1,1) !To freq domain
|
||||
|
||||
ia=nint(0.75*baud/df)
|
||||
cs(ia:NZ-1-ia)=0. !Save only freqs around fc1
|
||||
! do i=1,NZ/2
|
||||
! filt=1/(1+((i*df)**2/(0.50*baud)**2)**8)
|
||||
! cs(i)=cs(i)*filt
|
||||
! cs(NZ+1-i)=cs(NZ+1-i)*filt
|
||||
! enddo
|
||||
call four2a(cs,NZ,1,1,1) !Back to time domain
|
||||
cs=cs/NZ
|
||||
cs=cs*cs !Square the data
|
||||
call four2a(cs,NZ,1,-1,1) !Compute squared spectrum
|
||||
! Find two peaks separated by baud
|
||||
pmax=0.
|
||||
fc2=0.
|
||||
! ja=nint(0.3*baud/df)
|
||||
ja=nint(0.5*baud/df)
|
||||
k=1
|
||||
sp2=0.0
|
||||
do j=-ja,ja
|
||||
f2=j*df
|
||||
ia=nint((f2-0.5*baud)/df)
|
||||
if(ia.lt.0) ia=ia+NZ
|
||||
ib=nint((f2+0.5*baud)/df)
|
||||
p=real(cs(ia))**2 + aimag(cs(ia))**2 + &
|
||||
real(cs(ib))**2 + aimag(cs(ib))**2
|
||||
if(p.gt.pmax) then
|
||||
pmax=p
|
||||
fc2=0.5*f2
|
||||
endif
|
||||
freqs(k)=0.5*f2
|
||||
sp2(k)=p
|
||||
k=k+1
|
||||
! write(52,1200) f2,p,db(p)
|
||||
!1200 format(f10.3,2f15.3)
|
||||
enddo
|
||||
|
||||
do i=1,npeaks
|
||||
pkloc=maxloc(sp2)
|
||||
ipk=pkloc(1)
|
||||
fpks(i)=freqs(ipk)
|
||||
ipk0=max(1,ipk-2)
|
||||
ipk1=min(413,ipk+2)
|
||||
! ipk0=ipk
|
||||
! ipk1=ipk
|
||||
sp2(ipk0:ipk1)=0.0
|
||||
enddo
|
||||
return
|
||||
end subroutine getfc2
|
||||
@@ -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
|
||||
@@ -0,0 +1,523 @@
|
||||
#include "widegraph.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <QApplication>
|
||||
#include <QSettings>
|
||||
#include "ui_widegraph.h"
|
||||
#include "commons.h"
|
||||
#include "Configuration.hpp"
|
||||
#include "MessageBox.hpp"
|
||||
#include "SettingsGroup.hpp"
|
||||
#include "moc_widegraph.cpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
auto user_defined = QObject::tr ("User Defined");
|
||||
float swide[MAX_SCREENSIZE];
|
||||
}
|
||||
|
||||
WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::WideGraph),
|
||||
m_settings (settings),
|
||||
m_palettes_path {":/Palettes"},
|
||||
m_ntr0 {0},
|
||||
m_n {0},
|
||||
m_bHaveTransmitted {false}
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setWindowTitle (QApplication::applicationName () + " - " + tr ("Wide Graph"));
|
||||
setWindowFlags (Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint);
|
||||
setMaximumWidth (MAX_SCREENSIZE);
|
||||
setMaximumHeight (880);
|
||||
|
||||
ui->widePlot->setCursor(Qt::CrossCursor);
|
||||
ui->widePlot->setMaximumHeight(800);
|
||||
ui->widePlot->setCurrent(false);
|
||||
|
||||
connect(ui->widePlot, SIGNAL(freezeDecode1(int)),this,
|
||||
SLOT(wideFreezeDecode(int)));
|
||||
|
||||
connect(ui->widePlot, SIGNAL(setFreq1(int,int)),this,
|
||||
SLOT(setFreq2(int,int)));
|
||||
|
||||
{
|
||||
//Restore user's settings
|
||||
SettingsGroup g {m_settings, "WideGraph"};
|
||||
restoreGeometry (m_settings->value ("geometry", saveGeometry ()).toByteArray ());
|
||||
ui->widePlot->setPlotZero(m_settings->value("PlotZero", 0).toInt());
|
||||
ui->widePlot->setPlotGain(m_settings->value("PlotGain", 0).toInt());
|
||||
ui->widePlot->setPlot2dGain(m_settings->value("Plot2dGain", 0).toInt());
|
||||
ui->widePlot->setPlot2dZero(m_settings->value("Plot2dZero", 0).toInt());
|
||||
ui->zeroSlider->setValue(ui->widePlot->plotZero());
|
||||
ui->gainSlider->setValue(ui->widePlot->plotGain());
|
||||
ui->gain2dSlider->setValue(ui->widePlot->plot2dGain());
|
||||
ui->zero2dSlider->setValue(ui->widePlot->plot2dZero());
|
||||
int n = m_settings->value("BinsPerPixel",2).toInt();
|
||||
m_bFlatten=m_settings->value("Flatten",true).toBool();
|
||||
m_bRef=m_settings->value("UseRef",false).toBool();
|
||||
ui->cbFlatten->setChecked(m_bFlatten);
|
||||
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
|
||||
ui->cbRef->setChecked(m_bRef);
|
||||
ui->widePlot->setBreadth(m_settings->value("PlotWidth",1000).toInt());
|
||||
ui->bppSpinBox->setValue(n);
|
||||
m_nsmo=m_settings->value("SmoothYellow",1).toInt();
|
||||
ui->smoSpinBox->setValue(m_nsmo);
|
||||
m_Percent2DScreen=m_settings->value("Percent2D",30).toInt();
|
||||
m_waterfallAvg = m_settings->value("WaterfallAvg",5).toInt();
|
||||
ui->waterfallAvgSpinBox->setValue(m_waterfallAvg);
|
||||
ui->widePlot->setWaterfallAvg(m_waterfallAvg);
|
||||
ui->widePlot->setCurrent(m_settings->value("Current",false).toBool());
|
||||
ui->widePlot->setCumulative(m_settings->value("Cumulative",true).toBool());
|
||||
ui->widePlot->setLinearAvg(m_settings->value("LinearAvg",false).toBool());
|
||||
ui->widePlot->setReference(m_settings->value("Reference",false).toBool());
|
||||
if(ui->widePlot->current()) ui->spec2dComboBox->setCurrentIndex(0);
|
||||
if(ui->widePlot->cumulative()) ui->spec2dComboBox->setCurrentIndex(1);
|
||||
if(ui->widePlot->linearAvg()) ui->spec2dComboBox->setCurrentIndex(2);
|
||||
if(ui->widePlot->Reference()) ui->spec2dComboBox->setCurrentIndex(3);
|
||||
int nbpp=m_settings->value("BinsPerPixel",2).toInt();
|
||||
ui->widePlot->setBinsPerPixel(nbpp);
|
||||
ui->sbPercent2dPlot->setValue(m_Percent2DScreen);
|
||||
ui->widePlot->setStartFreq(m_settings->value("StartFreq",0).toInt());
|
||||
ui->fStartSpinBox->setValue(ui->widePlot->startFreq());
|
||||
m_waterfallPalette=m_settings->value("WaterfallPalette","Default").toString();
|
||||
m_userPalette = WFPalette {m_settings->value("UserPalette").value<WFPalette::Colours> ()};
|
||||
m_fMinPerBand = m_settings->value ("FminPerBand").toHash ();
|
||||
setRxRange ();
|
||||
ui->controls_widget->setVisible(!m_settings->value("HideControls",false).toBool());
|
||||
ui->cbControls->setChecked(!m_settings->value("HideControls",false).toBool());
|
||||
}
|
||||
|
||||
int index=0;
|
||||
for (QString const& file:
|
||||
m_palettes_path.entryList(QDir::NoDotAndDotDot |
|
||||
QDir::System | QDir::Hidden |
|
||||
QDir::AllDirs | QDir::Files,
|
||||
QDir::DirsFirst)) {
|
||||
QString t=file.mid(0,file.length()-4);
|
||||
ui->paletteComboBox->addItem(t);
|
||||
if(t==m_waterfallPalette) ui->paletteComboBox->setCurrentIndex(index);
|
||||
index++;
|
||||
}
|
||||
ui->paletteComboBox->addItem (user_defined);
|
||||
if (user_defined == m_waterfallPalette) ui->paletteComboBox->setCurrentIndex(index);
|
||||
readPalette ();
|
||||
}
|
||||
|
||||
WideGraph::~WideGraph ()
|
||||
{
|
||||
}
|
||||
|
||||
void WideGraph::closeEvent (QCloseEvent * e)
|
||||
{
|
||||
saveSettings ();
|
||||
QDialog::closeEvent (e);
|
||||
}
|
||||
|
||||
void WideGraph::saveSettings() //saveSettings
|
||||
{
|
||||
SettingsGroup g {m_settings, "WideGraph"};
|
||||
m_settings->setValue ("geometry", saveGeometry ());
|
||||
m_settings->setValue ("PlotZero", ui->widePlot->plotZero());
|
||||
m_settings->setValue ("PlotGain", ui->widePlot->plotGain());
|
||||
m_settings->setValue ("Plot2dGain", ui->widePlot->plot2dGain());
|
||||
m_settings->setValue ("Plot2dZero", ui->widePlot->plot2dZero());
|
||||
m_settings->setValue ("PlotWidth", ui->widePlot->plotWidth ());
|
||||
m_settings->setValue ("BinsPerPixel", ui->bppSpinBox->value ());
|
||||
m_settings->setValue ("SmoothYellow", ui->smoSpinBox->value ());
|
||||
m_settings->setValue ("Percent2D",m_Percent2DScreen);
|
||||
m_settings->setValue ("WaterfallAvg", ui->waterfallAvgSpinBox->value ());
|
||||
m_settings->setValue ("Current", ui->widePlot->current());
|
||||
m_settings->setValue ("Cumulative", ui->widePlot->cumulative());
|
||||
m_settings->setValue ("LinearAvg", ui->widePlot->linearAvg());
|
||||
m_settings->setValue ("Reference", ui->widePlot->Reference());
|
||||
m_settings->setValue ("BinsPerPixel", ui->widePlot->binsPerPixel ());
|
||||
m_settings->setValue ("StartFreq", ui->widePlot->startFreq ());
|
||||
m_settings->setValue ("WaterfallPalette", m_waterfallPalette);
|
||||
m_settings->setValue ("UserPalette", QVariant::fromValue (m_userPalette.colours ()));
|
||||
m_settings->setValue("Flatten",m_bFlatten);
|
||||
m_settings->setValue("UseRef",m_bRef);
|
||||
m_settings->setValue ("HideControls", ui->controls_widget->isHidden ());
|
||||
m_settings->setValue ("FminPerBand", m_fMinPerBand);
|
||||
}
|
||||
|
||||
void WideGraph::drawRed(int ia, int ib)
|
||||
{
|
||||
ui->widePlot->drawRed(ia,ib,swide);
|
||||
}
|
||||
|
||||
void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dataSink2
|
||||
{
|
||||
static float splot[NSMAX];
|
||||
int nbpp = ui->widePlot->binsPerPixel();
|
||||
|
||||
//Average spectra over specified number, m_waterfallAvg
|
||||
if (m_n==0) {
|
||||
for (int i=0; i<NSMAX; i++)
|
||||
splot[i]=s[i];
|
||||
} else {
|
||||
for (int i=0; i<NSMAX; i++)
|
||||
splot[i] += s[i];
|
||||
}
|
||||
m_n++;
|
||||
|
||||
if (m_n>=m_waterfallAvg) {
|
||||
for (int i=0; i<NSMAX; i++)
|
||||
splot[i] /= m_n; //Normalize the average
|
||||
m_n=0;
|
||||
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.0;
|
||||
float smax=0;
|
||||
for (int k=0; k<nbpp; k++) {
|
||||
float sp=splot[i++];
|
||||
ss += sp;
|
||||
smax=qMax(smax,sp);
|
||||
}
|
||||
// swide[j]=nbpp*smax;
|
||||
swide[j]=nbpp*ss;
|
||||
}
|
||||
|
||||
// Time according to this computer
|
||||
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
|
||||
int ntr = (ms/1000) % m_TRperiod;
|
||||
if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && ntr<m_ntr0)) {
|
||||
float flagValue=1.0e30;
|
||||
if(m_bHaveTransmitted) flagValue=2.0e30;
|
||||
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;
|
||||
ui->widePlot->draw(swide,true,false);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::on_bppSpinBox_valueChanged(int n) //bpp
|
||||
{
|
||||
ui->widePlot->setBinsPerPixel(n);
|
||||
}
|
||||
|
||||
void WideGraph::on_waterfallAvgSpinBox_valueChanged(int n) //Navg
|
||||
{
|
||||
m_waterfallAvg = n;
|
||||
ui->widePlot->setWaterfallAvg(n);
|
||||
}
|
||||
|
||||
void WideGraph::keyPressEvent(QKeyEvent *e) //F11, F12
|
||||
{
|
||||
switch(e->key())
|
||||
{
|
||||
int n;
|
||||
case Qt::Key_F11:
|
||||
n=11;
|
||||
if(e->modifiers() & Qt::ControlModifier) n+=100;
|
||||
emit f11f12(n);
|
||||
break;
|
||||
case Qt::Key_F12:
|
||||
n=12;
|
||||
if(e->modifiers() & Qt::ControlModifier) n+=100;
|
||||
emit f11f12(n);
|
||||
break;
|
||||
default:
|
||||
QDialog::keyPressEvent (e);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::setRxFreq(int n) //setRxFreq
|
||||
{
|
||||
ui->widePlot->setRxFreq(n);
|
||||
ui->widePlot->draw(swide,false,false);
|
||||
}
|
||||
|
||||
int WideGraph::rxFreq() //rxFreq
|
||||
{
|
||||
return ui->widePlot->rxFreq();
|
||||
}
|
||||
|
||||
int WideGraph::nStartFreq() //nStartFreq
|
||||
{
|
||||
return ui->widePlot->startFreq();
|
||||
}
|
||||
|
||||
void WideGraph::wideFreezeDecode(int n) //wideFreezeDecode
|
||||
{
|
||||
emit freezeDecode2(n);
|
||||
}
|
||||
|
||||
void WideGraph::setRxRange ()
|
||||
{
|
||||
ui->widePlot->setRxRange (Fmin ());
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
int WideGraph::Fmin() //Fmin
|
||||
{
|
||||
return "60m" == m_rxBand ? 0 : m_fMinPerBand.value (m_rxBand, 2500).toUInt ();
|
||||
}
|
||||
|
||||
int WideGraph::Fmax() //Fmax
|
||||
{
|
||||
return std::min(5000,ui->widePlot->Fmax());
|
||||
}
|
||||
|
||||
int WideGraph::fSpan()
|
||||
{
|
||||
return ui->widePlot->fSpan ();
|
||||
}
|
||||
|
||||
void WideGraph::setPeriod(int ntrperiod, int nsps) //SetPeriod
|
||||
{
|
||||
m_TRperiod=ntrperiod;
|
||||
m_nsps=nsps;
|
||||
ui->widePlot->setNsps(ntrperiod, nsps);
|
||||
}
|
||||
|
||||
void WideGraph::setTxFreq(int n) //setTxFreq
|
||||
{
|
||||
emit setXIT2(n);
|
||||
ui->widePlot->setTxFreq(n);
|
||||
}
|
||||
|
||||
void WideGraph::setMode(QString mode) //setMode
|
||||
{
|
||||
m_mode=mode;
|
||||
ui->fSplitSpinBox->setEnabled(m_mode=="JT9+JT65");
|
||||
ui->widePlot->setMode(mode);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
void WideGraph::setSubMode(int n) //setSubMode
|
||||
{
|
||||
m_nSubMode=n;
|
||||
ui->widePlot->setSubMode(n);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
void WideGraph::setModeTx(QString modeTx) //setModeTx
|
||||
{
|
||||
m_modeTx=modeTx;
|
||||
ui->widePlot->setModeTx(modeTx);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
//Current-Cumulative-Yellow
|
||||
void WideGraph::on_spec2dComboBox_currentIndexChanged(const QString &arg1)
|
||||
{
|
||||
ui->widePlot->setCurrent(false);
|
||||
ui->widePlot->setCumulative(false);
|
||||
ui->widePlot->setLinearAvg(false);
|
||||
ui->widePlot->setReference(false);
|
||||
ui->smoSpinBox->setEnabled(false);
|
||||
if(arg1=="Current") ui->widePlot->setCurrent(true);
|
||||
if(arg1=="Cumulative") ui->widePlot->setCumulative(true);
|
||||
if(arg1=="Linear Avg") {
|
||||
ui->widePlot->setLinearAvg(true);
|
||||
ui->smoSpinBox->setEnabled(true);
|
||||
}
|
||||
if(arg1=="Reference") {
|
||||
ui->widePlot->setReference(true);
|
||||
}
|
||||
replot();
|
||||
}
|
||||
|
||||
void WideGraph::on_fSplitSpinBox_valueChanged(int n) //fSplit
|
||||
{
|
||||
if (m_rxBand != "60m") m_fMinPerBand[m_rxBand] = n;
|
||||
setRxRange ();
|
||||
}
|
||||
|
||||
void WideGraph::setFreq2(int rxFreq, int txFreq) //setFreq2
|
||||
{
|
||||
emit setFreq3(rxFreq,txFreq);
|
||||
}
|
||||
|
||||
void WideGraph::setDialFreq(double d) //setDialFreq
|
||||
{
|
||||
ui->widePlot->setDialFreq(d);
|
||||
}
|
||||
|
||||
void WideGraph::setRxBand (QString const& band)
|
||||
{
|
||||
m_rxBand = band;
|
||||
if ("60m" == m_rxBand)
|
||||
{
|
||||
ui->fSplitSpinBox->setEnabled (false);
|
||||
ui->fSplitSpinBox->setValue (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->fSplitSpinBox->setValue (m_fMinPerBand.value (band, 2500).toUInt ());
|
||||
ui->fSplitSpinBox->setEnabled (m_mode=="JT9+JT65");
|
||||
}
|
||||
ui->widePlot->setRxBand(band);
|
||||
setRxRange ();
|
||||
}
|
||||
|
||||
|
||||
void WideGraph::on_fStartSpinBox_valueChanged(int n) //fStart
|
||||
{
|
||||
ui->widePlot->setStartFreq(n);
|
||||
}
|
||||
|
||||
void WideGraph::readPalette () //readPalette
|
||||
{
|
||||
try
|
||||
{
|
||||
if (user_defined == m_waterfallPalette)
|
||||
{
|
||||
ui->widePlot->setColours (WFPalette {m_userPalette}.interpolate ());
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->widePlot->setColours (WFPalette {m_palettes_path.absoluteFilePath (m_waterfallPalette + ".pal")}.interpolate());
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Read Palette"), e.what ());
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::on_paletteComboBox_activated (QString const& palette) //palette selector
|
||||
{
|
||||
m_waterfallPalette = palette;
|
||||
readPalette();
|
||||
replot();
|
||||
}
|
||||
|
||||
void WideGraph::on_cbFlatten_toggled(bool b) //Flatten On/Off
|
||||
{
|
||||
m_bFlatten=b;
|
||||
if(m_bRef and m_bFlatten) {
|
||||
m_bRef=false;
|
||||
ui->cbRef->setChecked(false);
|
||||
}
|
||||
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
|
||||
}
|
||||
|
||||
void WideGraph::on_cbRef_toggled(bool b)
|
||||
{
|
||||
m_bRef=b;
|
||||
if(m_bRef and m_bFlatten) {
|
||||
m_bFlatten=false;
|
||||
ui->cbFlatten->setChecked(false);
|
||||
}
|
||||
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
|
||||
}
|
||||
|
||||
void WideGraph::on_cbControls_toggled(bool b)
|
||||
{
|
||||
ui->controls_widget->setVisible(b);
|
||||
}
|
||||
|
||||
void WideGraph::on_adjust_palette_push_button_clicked (bool) //Adjust Palette
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_userPalette.design ())
|
||||
{
|
||||
m_waterfallPalette = user_defined;
|
||||
ui->paletteComboBox->setCurrentText (m_waterfallPalette);
|
||||
readPalette ();
|
||||
}
|
||||
}
|
||||
catch (std::exception const& e)
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Read Palette"), e.what ());
|
||||
}
|
||||
}
|
||||
|
||||
bool WideGraph::flatten() //Flatten
|
||||
{
|
||||
return m_bFlatten;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
ui->widePlot->setPlot2dGain(value);
|
||||
if(ui->widePlot->scaleOK ()) {
|
||||
ui->widePlot->draw(swide,false,false);
|
||||
if(m_mode=="QRA64") ui->widePlot->draw(swide,false,true);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::on_zero2dSlider_valueChanged(int value) //Zero2
|
||||
{
|
||||
ui->widePlot->setPlot2dZero(value);
|
||||
if(ui->widePlot->scaleOK ()) {
|
||||
ui->widePlot->draw(swide,false,false);
|
||||
if(m_mode=="QRA64") ui->widePlot->draw(swide,false,true);
|
||||
}
|
||||
}
|
||||
|
||||
void WideGraph::setTol(int n) //setTol
|
||||
{
|
||||
ui->widePlot->setTol(n);
|
||||
ui->widePlot->DrawOverlay();
|
||||
ui->widePlot->update();
|
||||
}
|
||||
|
||||
void WideGraph::on_smoSpinBox_valueChanged(int n)
|
||||
{
|
||||
m_nsmo=n;
|
||||
}
|
||||
|
||||
int WideGraph::smoothYellow()
|
||||
{
|
||||
return m_nsmo;
|
||||
}
|
||||
|
||||
void WideGraph::setWSPRtransmitted()
|
||||
{
|
||||
m_bHaveTransmitted=true;
|
||||
}
|
||||
|
||||
void WideGraph::setVHF(bool bVHF)
|
||||
{
|
||||
ui->widePlot->setVHF(bVHF);
|
||||
}
|
||||
|
||||
void WideGraph::on_sbPercent2dPlot_valueChanged(int n)
|
||||
{
|
||||
m_Percent2DScreen=n;
|
||||
ui->widePlot->SetPercent2DScreen(n);
|
||||
}
|
||||
|
||||
void WideGraph::setRedFile(QString fRed)
|
||||
{
|
||||
ui->widePlot->setRedFile(fRed);
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
#include "astro.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QSettings>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QCloseEvent>
|
||||
#include <QDebug>
|
||||
|
||||
#include "commons.h"
|
||||
#include "MessageBox.hpp"
|
||||
#include "Configuration.hpp"
|
||||
#include "SettingsGroup.hpp"
|
||||
#include "qt_helpers.hpp"
|
||||
|
||||
#include "ui_astro.h"
|
||||
#include "moc_astro.cpp"
|
||||
|
||||
|
||||
extern "C" {
|
||||
void astrosub_(int* nyear, int* month, int* nday, double* uth, double* freqMoon,
|
||||
const char* mygrid, const char* hisgrid, double* azsun,
|
||||
double* elsun, double* azmoon, double* elmoon, double* azmoondx,
|
||||
double* elmoondx, int* ntsky, int* ndop, int* ndop00,
|
||||
double* ramoon, double* decmoon, double* dgrd, double* poloffset,
|
||||
double* xnr, double* techo, double* width1, double* width2,
|
||||
bool* bTx, const char* AzElFileName, const char* jpleph,
|
||||
int len1, int len2, int len3, int len4);
|
||||
}
|
||||
|
||||
Astro::Astro(QSettings * settings, Configuration const * configuration, QWidget * parent)
|
||||
: QDialog {parent, Qt::WindowTitleHint}
|
||||
, settings_ {settings}
|
||||
, configuration_ {configuration}
|
||||
, ui_ {new Ui::Astro}
|
||||
, m_DopplerMethod {0}
|
||||
{
|
||||
ui_->setupUi (this);
|
||||
setWindowTitle (QApplication::applicationName () + " - " + tr ("Astronomical Data"));
|
||||
setStyleSheet ("QWidget {background: white;}");
|
||||
connect (ui_->cbDopplerTracking, &QAbstractButton::toggled, ui_->doppler_widget, &QWidget::setVisible);
|
||||
read_settings ();
|
||||
ui_->text_label->clear ();
|
||||
}
|
||||
|
||||
Astro::~Astro ()
|
||||
{
|
||||
ui_->cbDopplerTracking->setChecked (false);
|
||||
Q_EMIT tracking_update ();
|
||||
if (isVisible ()) write_settings ();
|
||||
}
|
||||
|
||||
void Astro::closeEvent (QCloseEvent * e)
|
||||
{
|
||||
write_settings ();
|
||||
e->ignore (); // do not allow closure by the window system
|
||||
}
|
||||
|
||||
void Astro::read_settings ()
|
||||
{
|
||||
SettingsGroup g (settings_, "Astro");
|
||||
ui_->doppler_widget->setVisible (ui_->cbDopplerTracking->isChecked ());
|
||||
m_DopplerMethod=settings_->value("DopplerMethod",0).toInt();
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 0: ui_->rbNoDoppler->setChecked (true); break;
|
||||
case 1: ui_->rbFullTrack->setChecked (true); break;
|
||||
case 2: ui_->rbConstFreqOnMoon->setChecked (true); break;
|
||||
case 3: ui_->rbRxOnly->setChecked (true); break;
|
||||
}
|
||||
move (settings_->value ("window/pos", pos ()).toPoint ());
|
||||
}
|
||||
|
||||
void Astro::write_settings ()
|
||||
{
|
||||
SettingsGroup g (settings_, "Astro");
|
||||
//settings_->setValue ("DopplerTracking", ui_->cbDopplerTracking->isChecked ());
|
||||
settings_->setValue ("DopplerMethod",m_DopplerMethod);
|
||||
settings_->setValue ("window/pos", pos ());
|
||||
}
|
||||
|
||||
auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const& hisgrid, Frequency freq,
|
||||
bool dx_is_self, bool bTx, bool no_tx_QSY, int TR_period) -> Correction
|
||||
{
|
||||
Frequency freq_moon {freq};
|
||||
double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx;
|
||||
double ramoon,decmoon,dgrd,poloffset,xnr,techo,width1,width2;
|
||||
int ntsky;
|
||||
QString date {t.date().toString("yyyy MMM dd").trimmed ()};
|
||||
QString utc {t.time().toString().trimmed ()};
|
||||
int nyear {t.date().year()};
|
||||
int month {t.date().month()};
|
||||
int nday {t.date().day()};
|
||||
int nhr {t.time().hour()};
|
||||
int nmin {t.time().minute()};
|
||||
double sec {t.time().second() + 0.001*t.time().msec()};
|
||||
double uth {nhr + nmin/60.0 + sec/3600.0};
|
||||
if(freq_moon < 1) freq_moon = 144000000;
|
||||
int nfreq {static_cast<int> (freq_moon / 1000000u)};
|
||||
double freq8 {static_cast<double> (freq_moon)};
|
||||
auto const& AzElFileName = QDir::toNativeSeparators (configuration_->azel_directory ().absoluteFilePath ("azel.dat"));
|
||||
auto const& jpleph = configuration_->data_dir ().absoluteFilePath ("JPLEPH");
|
||||
int ndop;
|
||||
int ndop00;
|
||||
|
||||
QString mygrid_padded {(mygrid + " ").left (6)};
|
||||
QString hisgrid_padded {(hisgrid + " ").left (6)};
|
||||
astrosub_(&nyear, &month, &nday, &uth, &freq8, mygrid_padded.toLatin1().constData(),
|
||||
hisgrid_padded.toLatin1().constData(), &azsun, &elsun, &azmoon, &elmoon,
|
||||
&azmoondx, &elmoondx, &ntsky, &ndop, &ndop00, &ramoon, &decmoon,
|
||||
&dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx,
|
||||
AzElFileName.toLatin1().constData(), jpleph.toLatin1().constData(), 6, 6,
|
||||
AzElFileName.length(), jpleph.length());
|
||||
|
||||
if(hisgrid_padded==" ") {
|
||||
azmoondx=0.0;
|
||||
elmoondx=0.0;
|
||||
ndop=0;
|
||||
width2=0.0;
|
||||
}
|
||||
QString message;
|
||||
{
|
||||
QTextStream out {&message};
|
||||
out << " " << date << "\n"
|
||||
"UTC: " << utc << "\n"
|
||||
<< fixed
|
||||
<< qSetFieldWidth (6)
|
||||
<< qSetRealNumberPrecision (1)
|
||||
<< "Az: " << azmoon << "\n"
|
||||
"El: " << elmoon << "\n"
|
||||
"SelfDop:" << ndop00 << "\n"
|
||||
"Width: " << int(width1) << "\n"
|
||||
<< qSetRealNumberPrecision (2)
|
||||
<< "Delay: " << techo << "\n"
|
||||
<< qSetRealNumberPrecision (1)
|
||||
<< "DxAz: " << azmoondx << "\n"
|
||||
"DxEl: " << elmoondx << "\n"
|
||||
"DxDop: " << ndop << "\n"
|
||||
"DxWid: " << int(width2) << "\n"
|
||||
"Dec: " << decmoon << "\n"
|
||||
"SunAz: " << azsun << "\n"
|
||||
"SunEl: " << elsun << "\n"
|
||||
"Freq: " << nfreq << "\n";
|
||||
if(nfreq>=50) { //Suppress data not relevant below VHF
|
||||
out << "Tsky: " << ntsky << "\n"
|
||||
"Dpol: " << poloffset << "\n"
|
||||
"MNR: " << xnr << "\n"
|
||||
"Dgrd: " << dgrd;
|
||||
}
|
||||
}
|
||||
ui_->text_label->setText(message);
|
||||
|
||||
Correction correction;
|
||||
if (ui_->cbDopplerTracking->isChecked ()) {
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 1: // All Doppler correction done here; DX station stays at nominal dial frequency.
|
||||
case 3: // Both stations do full correction on Rx and none on Tx
|
||||
correction.rx = dx_is_self ? ndop00 : ndop;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Doppler correction to constant frequency on Moon
|
||||
correction.rx = ndop00 / 2;
|
||||
break;
|
||||
}
|
||||
|
||||
if (3 != m_DopplerMethod) correction.tx = -correction.rx;
|
||||
if(dx_is_self && m_DopplerMethod == 1) correction.rx = 0;
|
||||
|
||||
if (no_tx_QSY && 3 != m_DopplerMethod && 0 != m_DopplerMethod)
|
||||
{
|
||||
// calculate a single correction for transmit half way through
|
||||
// the period as a compromise for rigs that can't CAT QSY
|
||||
// while transmitting
|
||||
//
|
||||
// use a base time of (secs-since-epoch + 2) so as to be sure
|
||||
// we do the next period if we calculate just before it starts
|
||||
auto sec_since_epoch = t.toMSecsSinceEpoch () / 1000 + 2;
|
||||
auto target_sec = sec_since_epoch - sec_since_epoch % TR_period + TR_period / 2;
|
||||
auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000);
|
||||
QString date {target_date_time.date().toString("yyyy MMM dd").trimmed ()};
|
||||
QString utc {target_date_time.time().toString().trimmed ()};
|
||||
int nyear {target_date_time.date().year()};
|
||||
int month {target_date_time.date().month()};
|
||||
int nday {target_date_time.date().day()};
|
||||
int nhr {target_date_time.time().hour()};
|
||||
int nmin {target_date_time.time().minute()};
|
||||
double sec {target_date_time.time().second() + 0.001*target_date_time.time().msec()};
|
||||
double uth {nhr + nmin/60.0 + sec/3600.0};
|
||||
astrosub_(&nyear, &month, &nday, &uth, &freq8, mygrid_padded.toLatin1().constData(),
|
||||
hisgrid_padded.toLatin1().constData(), &azsun, &elsun, &azmoon, &elmoon,
|
||||
&azmoondx, &elmoondx, &ntsky, &ndop, &ndop00, &ramoon, &decmoon,
|
||||
&dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx,
|
||||
"", jpleph.toLatin1().constData(), 6, 6,
|
||||
0, jpleph.length());
|
||||
FrequencyDelta offset {0};
|
||||
switch (m_DopplerMethod)
|
||||
{
|
||||
case 1:
|
||||
// All Doppler correction done here; DX station stays at nominal dial frequency.
|
||||
offset = dx_is_self ? ndop00 : ndop;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// Doppler correction to constant frequency on Moon
|
||||
offset = ndop00 / 2;
|
||||
break;
|
||||
}
|
||||
correction.tx = -offset;
|
||||
}
|
||||
}
|
||||
return correction;
|
||||
}
|
||||
|
||||
void Astro::check_split ()
|
||||
{
|
||||
if (doppler_tracking () && !configuration_->split_mode ())
|
||||
{
|
||||
MessageBox::warning_message (this, tr ("Doppler Tracking Error"),
|
||||
tr ("Split operating is required for Doppler tracking"),
|
||||
tr ("Go to \"Menu->File->Settings->Radio\" to enable split operation"));
|
||||
ui_->rbNoDoppler->click ();
|
||||
}
|
||||
}
|
||||
|
||||
void Astro::on_rbFullTrack_clicked()
|
||||
{
|
||||
m_DopplerMethod = 1;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbRxOnly_clicked()
|
||||
{
|
||||
m_DopplerMethod = 3;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbConstFreqOnMoon_clicked()
|
||||
{
|
||||
m_DopplerMethod = 2;
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::on_rbNoDoppler_clicked()
|
||||
{
|
||||
m_DopplerMethod = 0;
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
bool Astro::doppler_tracking () const
|
||||
{
|
||||
return ui_->cbDopplerTracking->isChecked () && m_DopplerMethod;
|
||||
}
|
||||
|
||||
void Astro::on_cbDopplerTracking_toggled(bool)
|
||||
{
|
||||
check_split ();
|
||||
Q_EMIT tracking_update ();
|
||||
}
|
||||
|
||||
void Astro::nominal_frequency (Frequency rx, Frequency tx)
|
||||
{
|
||||
ui_->sked_frequency_label->setText (Radio::pretty_frequency_MHz_string (rx));
|
||||
ui_->sked_tx_frequency_label->setText (Radio::pretty_frequency_MHz_string (tx));
|
||||
}
|
||||
|
||||
void Astro::hideEvent (QHideEvent * e)
|
||||
{
|
||||
Q_EMIT tracking_update ();
|
||||
QWidget::hideEvent (e);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Status=review
|
||||
The following controls appear just under the decoded text windows on
|
||||
the main screen:
|
||||
|
||||
//.Main UI
|
||||
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
|
||||
information before clicking *OK* to log the QSO. If you check *Prompt
|
||||
me to log QSO* on the *Settings -> Reporting* tab, the program will
|
||||
raise the confirmation screen automatically when you send a message
|
||||
containing +73+. *Start Date* and *Start Time* are set when you click
|
||||
to send the *Tx 2* or *Tx 3* message, and backed up by one or two
|
||||
sequence lengths, respectively. (Note that the actual start time may
|
||||
have been earlier if repeats of early transmissions were required.)
|
||||
End date and time are set when the *Log QSO* screen is invoked.
|
||||
|
||||
//.Log QSO Window
|
||||
image::log-qso.png[align="center",alt="Log QSO"]
|
||||
|
||||
* *Stop* will terminate normal data acquisition in case you want to
|
||||
freeze the waterfall or open and explore a previously recorded audio
|
||||
file.
|
||||
|
||||
* *Monitor* toggles normal receive operation on or off. This button
|
||||
is highlighted in green when the _WSJT-X_ is receiving. If you are
|
||||
using CAT control, toggling *Monitor* OFF relinquishes control of the
|
||||
rig; if *Monitor returns to last used frequency* is selected on the
|
||||
*Settings | General* tab, toggling *Monitor* back ON will return to
|
||||
the original frequency.
|
||||
|
||||
* *Erase* clears the right-hand decoded text window.
|
||||
Double-clicking *Erase* clears both text windows.
|
||||
|
||||
TIP: Right-clicking on either text window brings up a context menu
|
||||
with several options (including *Erase*) which operate on that window
|
||||
alone.
|
||||
|
||||
* *Clear Avg* is present only in modes that support message averaging.
|
||||
It provides a way to erase the accumulating information, thus
|
||||
preparing to start a new average.
|
||||
|
||||
* *Decode* tells the program to repeat the decoding procedure at the
|
||||
Rx frequency (green marker on waterfall scale), using the most recently
|
||||
completed sequence of received data.
|
||||
|
||||
* *Enable Tx* toggles automatic T/R sequencing mode on or off and
|
||||
highlights the button in red when ON. A transmission will start at
|
||||
the beginning of the selected (odd or even) sequence, or immediately
|
||||
if appropriate. Toggling the button to OFF during a transmission
|
||||
allows the current transmission to finish.
|
||||
|
||||
* *Halt Tx* terminates a transmission immediately and disables
|
||||
automatic T/R sequencing.
|
||||
|
||||
* *Tune* toggles the program into Tx mode and generates an unmodulated
|
||||
carrier at the specified Tx frequency (red marker on waterfall scale).
|
||||
This process is useful for adjusting an antenna tuner or tuning an
|
||||
amplifier. The button is highlighted in red while *Tune* is active.
|
||||
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.
|
||||
@@ -0,0 +1,320 @@
|
||||
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=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/
|
||||
|
||||
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-1),*,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,pxdbmax)
|
||||
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%lft8apon=.true.
|
||||
shared_data%params%ljt65apon=.true.
|
||||
shared_data%params%napwid=75
|
||||
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=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
|
||||
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
|
||||
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
|
||||
|
||||
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
|
||||
@@ -1,55 +0,0 @@
|
||||
=== New in Version 1.8
|
||||
|
||||
For quick reference, here's a short list of features and capabilities
|
||||
added to _WSJT-X_ since Version 1.7.0:
|
||||
|
||||
- New mode *FT8* designed for fast QSOs
|
||||
|
||||
- New tool *FreqCal* for accurate frequency calibration of your radio
|
||||
|
||||
- Improved decoding performance for JT65, QRA64, and MSK144
|
||||
|
||||
- *SWL* option for third-party decoding short-format MSK144 messages
|
||||
|
||||
- Experimental amplitude and phase equalization for MSK144
|
||||
|
||||
- Options to minimize screen space used by *Main* and *Wide Graph*
|
||||
windows
|
||||
|
||||
- New set of suggested default frequencies specific to the three IARU
|
||||
regions
|
||||
|
||||
- Enhanced scheme for managing table of suggested default operating
|
||||
frequencies
|
||||
|
||||
- Improved CAT control for many radios, including those controlled
|
||||
through Commander or OmniRig
|
||||
|
||||
- Bug fixes and minor tweaks to user interface
|
||||
|
||||
=== Documentation Conventions
|
||||
|
||||
In this manual the following icons call attention to particular types
|
||||
of information:
|
||||
|
||||
NOTE: *Notes* containing information that may be of interest to
|
||||
particuar classes of users.
|
||||
|
||||
TIP: *Tips* on program features or capabilities that might otherwise be
|
||||
overlooked.
|
||||
|
||||
IMPORTANT: *Warnings* about usage that could lead to undesired
|
||||
consequences.
|
||||
|
||||
=== How You Can Contribute
|
||||
|
||||
_WSJT-X_ is part of an open-source project released under the
|
||||
{gnu_gpl} (GPL). If you have programming or documentation skills or
|
||||
would like to contribute to the project in other ways, please make
|
||||
your interests known to the development team. The project's
|
||||
source-code repository can be found at {devsvn}, and most
|
||||
communication among the developers takes place on the email reflector
|
||||
{devmail}. Bug reports and suggestions for new features, improvements
|
||||
to the _WSJT-X_ User Guide, etc., may also be sent to the
|
||||
{wsjt_yahoo_group} email reflector. You must join the relevant group
|
||||
before posting to either email list.
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 86 KiB |
@@ -1,164 +0,0 @@
|
||||
program chkfft
|
||||
|
||||
! Tests and times one-dimensional FFTs computed by four2a().
|
||||
! An all-Fortran version of four2a() is available, but the preferred
|
||||
! version uses calls to the FFTW library.
|
||||
|
||||
parameter (NMAX=8*1024*1024) !Maximum FFT length
|
||||
complex a(NMAX),b(NMAX)
|
||||
real ar(NMAX),br(NMAX)
|
||||
real mflops
|
||||
character infile*12,arg*8
|
||||
logical list
|
||||
common/patience/npatience
|
||||
equivalence (a,ar),(b,br)
|
||||
|
||||
nargs=iargc()
|
||||
if(nargs.ne.5) then
|
||||
print*,'Usage: chkfft <nfft | infile> nr nw nc np'
|
||||
print*,' nfft: length of FFT'
|
||||
print*,' nfft=0: do lengths 2^n, n=2^4 to 2^23'
|
||||
print*,' infile: name of file with nfft values, one per line'
|
||||
print*,' nr: 0/1 to not read (or read) wisdom'
|
||||
print*,' nw: 0/1 to not write (or write) wisdom'
|
||||
print*,' nc: 0/1 for real or complex data'
|
||||
print*,' np: 0-4 patience for finding best algorithm'
|
||||
go to 999
|
||||
endif
|
||||
|
||||
list=.false.
|
||||
nfft=-1
|
||||
call getarg(1,infile)
|
||||
open(10,file=infile,status='old',err=1)
|
||||
list=.true. !A valid file name was provided
|
||||
go to 2
|
||||
1 read(infile,*) nfft !Takje first argument to be nfft
|
||||
2 call getarg(2,arg)
|
||||
read(arg,*) nr
|
||||
call getarg(3,arg)
|
||||
read(arg,*) nw
|
||||
call getarg(4,arg)
|
||||
read(arg,*) ncomplex
|
||||
call getarg(5,arg)
|
||||
read(arg,*) npatience
|
||||
|
||||
call sgran()
|
||||
|
||||
if(list) write(*,1000) infile,nr,nw,ncomplex,npatience
|
||||
1000 format(/'infile: ',a12,' nr:',i2,' nw',i2,' nc:',i2,' np:',i2/)
|
||||
if(.not.list) write(*,1002) nfft,nr,nw,ncomplex,npatience
|
||||
1002 format(/'nfft: ',i10,' nr:',i2,' nw',i2,' nc:',i2,' np:',i2/)
|
||||
|
||||
open(12,file='chkfft.out',status='unknown')
|
||||
open(13,file='fftwf_wisdom.dat',status='unknown')
|
||||
|
||||
if(nr.ne.0) then
|
||||
call import_wisdom_from_file(isuccess,13)
|
||||
if(isuccess.eq.0) then
|
||||
write(*,1010)
|
||||
1010 format('Failed to import FFTW wisdom.')
|
||||
go to 999
|
||||
endif
|
||||
endif
|
||||
|
||||
idum=-1 !Set random seed
|
||||
ndim=1 !One-dimensional transforms
|
||||
do i=1,NMAX !Set random data
|
||||
x=gran()
|
||||
y=gran()
|
||||
b(i)=cmplx(x,y) !Generate random data
|
||||
enddo
|
||||
|
||||
iters=1000000
|
||||
if(list .or. (nfft.gt.0)) then
|
||||
n1=1
|
||||
n2=1
|
||||
if(nfft.eq.-1) n2=999999
|
||||
write(*,1020)
|
||||
1020 format(' NFFT Time rms MHz MFlops iters', &
|
||||
' tplan'/61('-'))
|
||||
else
|
||||
n1=4
|
||||
n2=23
|
||||
write(*,1030)
|
||||
1030 format(' n N=2^n Time rms MHz MFlops iters', &
|
||||
' tplan'/63('-'))
|
||||
endif
|
||||
|
||||
do ii=n1,n2 !Test one or more FFT lengths
|
||||
if(list) then
|
||||
read(10,*,end=900) nfft !Read nfft from file
|
||||
else if(n2.gt.n1) then
|
||||
nfft=2**ii !Do powers of 2
|
||||
endif
|
||||
|
||||
iformf=1
|
||||
iformb=1
|
||||
if(ncomplex.eq.0) then
|
||||
iformf=0 !Real-to-complex transform
|
||||
iformb=-1 !Complex-to-real (inverse) transform
|
||||
endif
|
||||
|
||||
if(nfft.gt.NMAX) go to 900
|
||||
a(1:nfft)=b(1:nfft) !Copy test data into a()
|
||||
t0=second()
|
||||
call four2a(a,nfft,ndim,-1,iformf) !Get planning time for forward FFT
|
||||
call four2a(a,nfft,ndim,+1,iformb) !Get planning time for backward FFT
|
||||
t2=second()
|
||||
tplan=t2-t0 !Total planning time for this length
|
||||
|
||||
total=0.
|
||||
do iter=1,iters !Now do many iterations
|
||||
a(1:nfft)=b(1:nfft) !Copy test data into a()
|
||||
|
||||
t0=second()
|
||||
call four2a(a,nfft,ndim,-1,iformf) !Forward FFT
|
||||
call four2a(a,nfft,ndim,+1,iformb) !Backward FFT on same data
|
||||
t1=second()
|
||||
total=total+t1-t0
|
||||
if(total.ge.1.0) go to 40 !Cut iterations short if t>1 s
|
||||
enddo
|
||||
iter=iters
|
||||
|
||||
40 time=0.5*total/iter !Time for one FFT of current length
|
||||
tplan=0.5*tplan-time !Planning time for one FFT
|
||||
if(tplan.lt.0) tplan=0.
|
||||
a(1:nfft)=a(1:nfft)/nfft
|
||||
|
||||
! Compute RMS difference between original array and back-transformed array.
|
||||
sq=0.
|
||||
if(ncomplex.eq.1) then
|
||||
do i=1,nfft
|
||||
sq=sq + real(a(i)-b(i))**2 + imag(a(i)-b(i))**2
|
||||
enddo
|
||||
else
|
||||
do i=1,nfft
|
||||
sq=sq + (ar(i)-br(i))**2
|
||||
enddo
|
||||
endif
|
||||
rms=sqrt(sq/nfft)
|
||||
|
||||
freq=1.e-6*nfft/time
|
||||
mflops=5.0/(1.e6*time/(nfft*log(float(nfft))/log(2.0)))
|
||||
if(n2.eq.1 .or. n2.eq.999999) then
|
||||
write(*,1050) nfft,time,rms,freq,mflops,iter,tplan
|
||||
write(12,1050) nfft,time,rms,freq,mflops,iter,tplan
|
||||
1050 format(i8,f11.7,f12.8,f7.2,f8.1,i8,f6.1)
|
||||
else
|
||||
write(*,1060) ii,nfft,time,rms,freq,mflops,iter,tplan
|
||||
write(12,1060) ii,nfft,time,rms,freq,mflops,iter,tplan
|
||||
1060 format(i2,i8,f11.7,f12.8,f7.2,f8.1,i8,f6.1)
|
||||
endif
|
||||
if(mod(ii,50).eq.0) call four2a(0,-1,0,0,0)
|
||||
enddo
|
||||
|
||||
900 continue
|
||||
if(nw.eq.1) then
|
||||
rewind 13
|
||||
call export_wisdom_to_file(13)
|
||||
! write(*,1070)
|
||||
!1070 format(/'Exported FFTW wisdom')
|
||||
endif
|
||||
|
||||
999 call four2a(0,-1,0,0,0)
|
||||
end program chkfft
|
||||
@@ -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
|
||||
@@ -0,0 +1,68 @@
|
||||
!subroutine symspec65(dd,npts,ss,nqsym,savg)
|
||||
subroutine symspec65(dd,npts,nqsym,savg)
|
||||
|
||||
! Compute JT65 symbol spectra at quarter-symbol steps
|
||||
|
||||
parameter (NFFT=8192)
|
||||
parameter (NSZ=3413) !NFFT*5000/12000
|
||||
parameter (MAXHSYM=322)
|
||||
parameter (MAXQSYM=552)
|
||||
real*8 hstep
|
||||
real*4 dd(npts)
|
||||
! real*4 ss(MAXHSYM,NSZ)
|
||||
real*4 ss(MAXQSYM,NSZ)
|
||||
real*4 savg(NSZ)
|
||||
real*4 x(NFFT)
|
||||
real*4 w(NFFT)
|
||||
complex c(0:NFFT/2)
|
||||
logical first
|
||||
common/refspec/dfref,ref(NSZ)
|
||||
equivalence (x,c)
|
||||
data first/.true./
|
||||
save /refspec/,first,w
|
||||
common/sync/ss
|
||||
|
||||
hstep=2048.d0*12000.d0/11025.d0 !half-symbol = 2229.116 samples
|
||||
qstep=hstep/2.0 !quarter-symbol = 1114.558 samples
|
||||
nsps=nint(2*hstep)
|
||||
df=12000.0/NFFT
|
||||
nhsym=(npts-NFFT)/hstep
|
||||
nqsym=(npts-NFFT)/qstep
|
||||
savg=0.
|
||||
fac1=1.e-3
|
||||
|
||||
if(first) then
|
||||
! Compute the FFT window
|
||||
! width=0.25*nsps
|
||||
do i=1,NFFT
|
||||
! z=(i-NFFT/2)/width
|
||||
w(i)=1
|
||||
if(i.gt.4458) w(i)=0
|
||||
! w(i)=exp(-z*z)
|
||||
enddo
|
||||
first=.false.
|
||||
endif
|
||||
|
||||
do j=1,nqsym
|
||||
i0=(j-1)*qstep
|
||||
x=fac1*w*dd(i0+1:i0+NFFT)
|
||||
call four2a(c,NFFT,1,-1,0) !r2c forward FFT
|
||||
do i=1,NSZ
|
||||
s=real(c(i))**2 + aimag(c(i))**2
|
||||
ss(j,i)=s
|
||||
savg(i)=savg(i)+s
|
||||
enddo
|
||||
enddo
|
||||
savg=savg/nhsym
|
||||
|
||||
! call flat65(ss,nhsym,MAXQSYM,NSZ,ref) !Flatten the 2d spectrum, saving
|
||||
call flat65(ss,nqsym,MAXQSYM,NSZ,ref) !Flatten the 2d spectrum, saving
|
||||
dfref=df ! the reference spectrum ref()
|
||||
savg=savg/ref
|
||||
! do j=1,nhsym
|
||||
do j=1,nqsym
|
||||
ss(j,1:NSZ)=ss(j,1:NSZ)/ref
|
||||
enddo
|
||||
|
||||
return
|
||||
end subroutine symspec65
|
||||
@@ -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,34 +0,0 @@
|
||||
subroutine decode65b(s2,nflip,nadd,mode65,ntrials,naggressive,ndepth, &
|
||||
mycall,hiscall,hisgrid,nexp_decode,nqd,nft,qual,nhist,decoded)
|
||||
|
||||
use jt65_mod
|
||||
real s2(66,126)
|
||||
real s3(64,63)
|
||||
logical ltext
|
||||
character decoded*22
|
||||
character mycall*12,hiscall*12,hisgrid*6
|
||||
save
|
||||
|
||||
if(nqd.eq.-99) stop !Silence compiler warning
|
||||
do j=1,63
|
||||
k=mdat(j) !Points to data symbol
|
||||
if(nflip.lt.0) k=mdat2(j)
|
||||
do i=1,64
|
||||
s3(i,j)=s2(i+2,k)
|
||||
enddo
|
||||
enddo
|
||||
|
||||
call extract(s3,nadd,mode65,ntrials,naggressive,ndepth,nflip,mycall, &
|
||||
hiscall,hisgrid,nexp_decode,ncount,nhist,decoded,ltext,nft,qual)
|
||||
|
||||
! Suppress "birdie messages" and other garbage decodes:
|
||||
if(decoded(1:7).eq.'000AAA ') ncount=-1
|
||||
if(decoded(1:7).eq.'0L6MWK ') ncount=-1
|
||||
if(nflip.lt.0 .and. ltext) ncount=-1
|
||||
if(ncount.lt.0) then
|
||||
nft=0
|
||||
decoded=' '
|
||||
endif
|
||||
|
||||
return
|
||||
end subroutine decode65b
|
||||
@@ -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.
|
||||
@@ -0,0 +1,231 @@
|
||||
#include "adif.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
/*
|
||||
<CALL:4>W1XT<BAND:3>20m<FREQ:6>14.076<GRIDSQUARE:4>DM33<MODE:4>JT65<RST_RCVD:3>-21<RST_SENT:3>-14<QSO_DATE:8>20110422<TIME_ON:6>041712<TIME_OFF:6>042435<TX_PWR:1>4<COMMENT:34>1st JT65A QSO. Him: mag loop 20W<STATION_CALLSIGN:6>VK3ACF<MY_GRIDSQUARE:6>qf22lb<eor>
|
||||
<CALL:6>IK1SOW<BAND:3>20m<FREQ:6>14.076<GRIDSQUARE:4>JN35<MODE:4>JT65<RST_RCVD:3>-19<RST_SENT:3>-11<QSO_DATE:8>20110422<TIME_ON:6>052501<TIME_OFF:6>053359<TX_PWR:1>3<STATION_CALLSIGN:6>VK3ACF<MY_GRIDSQUARE:6>qf22lb<eor>
|
||||
<CALL:6:S>W4ABC> ...
|
||||
*/
|
||||
|
||||
void ADIF::init(QString const& filename)
|
||||
{
|
||||
_filename = filename;
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
|
||||
QString ADIF::extractField(QString const& record, QString const& fieldName) const
|
||||
{
|
||||
int fieldNameIndex = record.indexOf ('<' + fieldName + ':', 0, Qt::CaseInsensitive);
|
||||
if (fieldNameIndex >=0)
|
||||
{
|
||||
int closingBracketIndex = record.indexOf('>',fieldNameIndex);
|
||||
int fieldLengthIndex = record.indexOf(':',fieldNameIndex); // find the size delimiter
|
||||
int dataTypeIndex = -1;
|
||||
if (fieldLengthIndex >= 0)
|
||||
{
|
||||
dataTypeIndex = record.indexOf(':',fieldLengthIndex+1); // check for a second : indicating there is a data type
|
||||
if (dataTypeIndex > closingBracketIndex)
|
||||
dataTypeIndex = -1; // second : was found but it was beyond the closing >
|
||||
}
|
||||
|
||||
if ((closingBracketIndex > fieldNameIndex) && (fieldLengthIndex > fieldNameIndex) && (fieldLengthIndex< closingBracketIndex))
|
||||
{
|
||||
int fieldLengthCharCount = closingBracketIndex - fieldLengthIndex -1;
|
||||
if (dataTypeIndex >= 0)
|
||||
fieldLengthCharCount -= 2; // data type indicator is always a colon followed by a single character
|
||||
QString fieldLengthString = record.mid(fieldLengthIndex+1,fieldLengthCharCount);
|
||||
int fieldLength = fieldLengthString.toInt();
|
||||
if (fieldLength > 0)
|
||||
{
|
||||
QString field = record.mid(closingBracketIndex+1,fieldLength);
|
||||
return field;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ADIF::load()
|
||||
{
|
||||
_data.clear();
|
||||
QFile inputFile(_filename);
|
||||
if (inputFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QTextStream in(&inputFile);
|
||||
QString buffer;
|
||||
bool pre_read {false};
|
||||
int end_position {-1};
|
||||
|
||||
// skip optional header record
|
||||
do
|
||||
{
|
||||
buffer += in.readLine () + '\n';
|
||||
if (buffer.startsWith (QChar {'<'})) // denotes no header
|
||||
{
|
||||
pre_read = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
end_position = buffer.indexOf ("<EOH>", 0, Qt::CaseInsensitive);
|
||||
}
|
||||
}
|
||||
while (!in.atEnd () && !pre_read && end_position < 0);
|
||||
if (!pre_read) // found header
|
||||
{
|
||||
buffer.remove (0, end_position + 5);
|
||||
}
|
||||
while (buffer.size () || !in.atEnd ())
|
||||
{
|
||||
do
|
||||
{
|
||||
end_position = buffer.indexOf ("<EOR>", 0, Qt::CaseInsensitive);
|
||||
if (!in.atEnd () && end_position < 0)
|
||||
{
|
||||
buffer += in.readLine () + '\n';
|
||||
}
|
||||
}
|
||||
while (!in.atEnd () && end_position < 0);
|
||||
int record_length {end_position >= 0 ? end_position + 5 : -1};
|
||||
auto record = buffer.left (record_length).trimmed ();
|
||||
auto next_record = buffer.indexOf (QChar {'<'}, record_length);
|
||||
buffer.remove (0, next_record >=0 ? next_record : buffer.size ());
|
||||
record = record.mid (record.indexOf (QChar {'<'}));
|
||||
add (extractField (record, "CALL")
|
||||
, extractField (record, "BAND")
|
||||
, extractField (record, "MODE")
|
||||
, extractField (record, "QSO_DATE"));
|
||||
}
|
||||
inputFile.close ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ADIF::add(QString const& call, QString const& band, QString const& mode, QString const& date)
|
||||
{
|
||||
QSO q;
|
||||
q.call = call;
|
||||
q.band = band;
|
||||
q.mode = mode;
|
||||
q.date = date;
|
||||
if (q.call.size ())
|
||||
{
|
||||
_data.insert(q.call,q);
|
||||
// qDebug() << "Added as worked:" << call << band << mode << date;
|
||||
}
|
||||
}
|
||||
|
||||
// return true if in the log same band and mode (where JT65 == JT9)
|
||||
bool ADIF::match(QString const& call, QString const& band, QString const& mode) const
|
||||
{
|
||||
QList<QSO> qsos = _data.values(call);
|
||||
if (qsos.size()>0)
|
||||
{
|
||||
QSO q;
|
||||
foreach(q,qsos)
|
||||
{
|
||||
if ( (band.compare(q.band,Qt::CaseInsensitive) == 0)
|
||||
|| (band=="")
|
||||
|| (q.band==""))
|
||||
{
|
||||
if (
|
||||
(
|
||||
((mode.compare("JT65",Qt::CaseInsensitive)==0) ||
|
||||
(mode.compare("JT9",Qt::CaseInsensitive)==0) ||
|
||||
(mode.compare("FT8",Qt::CaseInsensitive)==0))
|
||||
&&
|
||||
((q.mode.compare("JT65",Qt::CaseInsensitive)==0) ||
|
||||
(q.mode.compare("JT9",Qt::CaseInsensitive)==0) ||
|
||||
(q.mode.compare("FT8",Qt::CaseInsensitive)==0))
|
||||
)
|
||||
|| (mode.compare(q.mode,Qt::CaseInsensitive)==0)
|
||||
|| (mode=="")
|
||||
|| (q.mode=="")
|
||||
)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QString> ADIF::getCallList() const
|
||||
{
|
||||
QList<QString> p;
|
||||
QMultiHash<QString,QSO>::const_iterator i = _data.constBegin();
|
||||
while (i != _data.constEnd())
|
||||
{
|
||||
p << i.key();
|
||||
++i;
|
||||
}
|
||||
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(QByteArray const& ADIF_record)
|
||||
{
|
||||
QFile f2(_filename);
|
||||
if (!f2.open(QIODevice::Text | QIODevice::Append))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
QTextStream out(&f2);
|
||||
if (f2.size()==0)
|
||||
out << "WSJT-X ADIF Export<eoh>" << endl; // new file
|
||||
|
||||
out << ADIF_record << " <eor>" << endl;
|
||||
f2.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 KiB |
File diff suppressed because it is too large
Load Diff
@@ -1,41 +0,0 @@
|
||||
#ifndef WSJTX_CONFIG_H__
|
||||
#define WSJTX_CONFIG_H__
|
||||
|
||||
#define WSJTX_VERSION_MAJOR @WSJTX_VERSION_MAJOR@
|
||||
#define WSJTX_VERSION_MINOR @WSJTX_VERSION_MINOR@
|
||||
#define WSJTX_VERSION_PATCH @WSJTX_VERSION_PATCH@
|
||||
|
||||
#cmakedefine CMAKE_INSTALL_DATAROOTDIR "@CMAKE_INSTALL_DATAROOTDIR@"
|
||||
#cmakedefine CMAKE_INSTALL_DOCDIR "@CMAKE_INSTALL_DOCDIR@"
|
||||
#cmakedefine CMAKE_INSTALL_DATADIR "@CMAKE_INSTALL_DATADIR@"
|
||||
#cmakedefine CMAKE_PROJECT_NAME "@CMAKE_PROJECT_NAME@"
|
||||
#cmakedefine PROJECT_MANUAL "@PROJECT_MANUAL@"
|
||||
#cmakedefine PROJECT_HOMEPAGE "@PROJECT_HOMEPAGE@"
|
||||
#cmakedefine PROJECT_MANUAL_DIRECTORY_URL "@PROJECT_MANUAL_DIRECTORY_URL@"
|
||||
#cmakedefine PROJECT_SAMPLES_URL "@PROJECT_SAMPLES_URL@"
|
||||
#cmakedefine PROJECT_SUMMARY_DESCRIPTION "@PROJECT_SUMMARY_DESCRIPTION@"
|
||||
|
||||
#cmakedefine01 WSJT_SHARED_RUNTIME
|
||||
#cmakedefine01 WSJT_QDEBUG_TO_FILE
|
||||
#cmakedefine01 WSJT_QDEBUG_IN_RELEASE
|
||||
#cmakedefine01 WSJT_TRACE_CAT
|
||||
#cmakedefine01 WSJT_TRACE_CAT_POLLS
|
||||
#cmakedefine01 WSJT_HAMLIB_TRACE
|
||||
#cmakedefine01 WSJT_HAMLIB_VERBOSE_TRACE
|
||||
#cmakedefine01 WSJT_SOFT_KEYING
|
||||
#cmakedefine01 WSJT_ENABLE_EXPERIMENTAL_FEATURES
|
||||
#cmakedefine01 WSJT_RIG_NONE_CAN_SPLIT
|
||||
|
||||
#define WSJTX_STRINGIZE1(x) #x
|
||||
#define WSJTX_STRINGIZE(x) WSJTX_STRINGIZE1(x)
|
||||
|
||||
/* consistent UNICODE behaviour */
|
||||
#ifndef UNICODE
|
||||
# undef _UNICODE
|
||||
#else
|
||||
# ifndef _UNICODE
|
||||
# define _UNICODE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,64 +0,0 @@
|
||||
// Status=review
|
||||
|
||||
_WSJT-X_ is a computer program designed to facilitate basic amateur
|
||||
radio communication using very weak signals. The first four letters in
|
||||
the program name stand for "`**W**eak **S**ignal communication by
|
||||
K1**JT**,`" while the suffix "`-X`" indicates that _WSJT-X_ started as
|
||||
an extended and experimental branch of the program
|
||||
_WSJT_.
|
||||
|
||||
_WSJT-X_ Version 1.8 offers nine different protocols or modes: *FT8*,
|
||||
*JT4*, *JT9*, *JT65*, *QRA64*, *ISCAT*, *MSK144*, *WSPR*, and *Echo*.
|
||||
The first five are designed for making reliable QSOs under extreme
|
||||
weak-signal conditions. They use nearly identical message structure
|
||||
and source encoding. JT65 and QRA64 were designed for EME
|
||||
("`moonbounce`") on the VHF/UHF bands and have also proven very
|
||||
effective for worldwide QRP communication on the HF bands. QRA64 has
|
||||
a number of advantages over JT65, including better performance on the
|
||||
very weakest signals. We imagine that over time it may replace JT65
|
||||
for EME use. JT9 was originally designed for the LF, MF, and lower HF
|
||||
bands. Its submode JT9A is 2 dB more sensitive than JT65 while using
|
||||
less than 10% of the bandwidth. JT4 offers a wide variety of tone
|
||||
spacings and has proven highly effective for EME on microwave bands up
|
||||
to 24 GHz. These four "`slow`" modes use one-minute timed sequences
|
||||
of alternating transmission and reception, so a minimal QSO takes four
|
||||
to six minutes — two or three transmissions by each station, one
|
||||
sending in odd UTC minutes and the other even. FT8 is operationally
|
||||
similar but four times faster (15-second T/R sequences) and less
|
||||
sensitive by a few dB. On the HF bands, world-wide QSOs are possible
|
||||
with any of these modes using power levels of a few watts (or even
|
||||
milliwatts) and compromise antennas. On VHF bands and higher, QSOs
|
||||
are possible (by EME and other propagation types) at signal levels 10
|
||||
to 15 dB below those required for CW.
|
||||
|
||||
*ISCAT*, *MSK144*, and optionally submodes *JT9E-H* are "`fast`"
|
||||
protocols designed to take advantage of brief signal enhancements from
|
||||
ionized meteor trails, aircraft scatter, and other types of scatter
|
||||
propagation. These modes use timed sequences of 5, 10, 15, or 30 s
|
||||
duration. User messages are transmitted repeatedly at high rate (up
|
||||
to 250 characters per second, for MSK144) to make good use of the
|
||||
shortest meteor-trail reflections or "`pings`". ISCAT uses free-form
|
||||
messages up to 28 characters long, while MSK144 uses the same
|
||||
structured messages as the slow modes and optionally an abbreviated
|
||||
format with hashed callsigns.
|
||||
|
||||
*WSPR* (pronounced "`whisper`") stands for **W**eak **S**ignal
|
||||
**P**ropagation **R**eporter. The WSPR protocol was designed for probing
|
||||
potential propagation paths using low-power transmissions. WSPR
|
||||
messages normally carry the transmitting station’s callsign, grid
|
||||
locator, and transmitter power in dBm, and they can be decoded at
|
||||
signal-to-noise ratios as low as -28 dB in a 2500 Hz bandwidth. WSPR
|
||||
users with internet access can automatically upload reception
|
||||
reports to a central database called {wsprnet} that provides a mapping
|
||||
facility, archival storage, and many other features.
|
||||
|
||||
*Echo* mode allows you to detect and measure your own station's echoes
|
||||
from the moon, even if they are far below the audible threshold.
|
||||
|
||||
_WSJT-X_ provides spectral displays for receiver passbands as wide as
|
||||
5 kHz, flexible rig control for nearly all modern radios used by
|
||||
amateurs, and a wide variety of special aids such as automatic Doppler
|
||||
tracking for EME QSOs and Echo testing. The program runs equally well
|
||||
on Windows, Macintosh, and Linux systems, and installation packages
|
||||
are available for all three platforms.
|
||||
|
||||
@@ -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,217 +0,0 @@
|
||||
#include "decodedtext.h"
|
||||
|
||||
#include <QStringList>
|
||||
#include <QRegularExpression>
|
||||
#include <QDebug>
|
||||
|
||||
extern "C" {
|
||||
bool stdmsg_(char const * msg, bool contest_mode, char const * mygrid, int len_msg, int len_grid);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
QRegularExpression words_re {R"(^(?:(?<word1>(?:CQ|DE|QRZ)(?:\s?DX|\s(?:[A-Z]{2}|\d{3}))|[A-Z0-9/]+)\s)(?:(?<word2>[A-Z0-9/]+)(?:\s(?<word3>[-+A-Z0-9]+)(?:\s(?<word4>(?:OOO|(?!RR73)[A-R]{2}[0-9]{2})))?)?)?)"};
|
||||
}
|
||||
|
||||
DecodedText::DecodedText (QString const& the_string, bool contest_mode, QString const& my_grid)
|
||||
: string_ {the_string.left (the_string.indexOf (QChar::Nbsp))} // discard appended info
|
||||
, padding_ {string_.indexOf (" ") > 4 ? 2 : 0} // allow for
|
||||
// seconds
|
||||
, contest_mode_ {contest_mode}
|
||||
, message_ {string_.mid (column_qsoText + padding_).trimmed ()}
|
||||
, is_standard_ {false}
|
||||
{
|
||||
if (message_.length() >= 1)
|
||||
{
|
||||
message_ = message_.left (21).remove (QRegularExpression {"[<>]"});
|
||||
int i1 = message_.indexOf ('\r');
|
||||
if (i1 > 0)
|
||||
{
|
||||
message_ = message_.left (i1 - 1);
|
||||
}
|
||||
if (message_.contains (QRegularExpression {"^(CQ|QRZ)\\s"}))
|
||||
{
|
||||
// TODO this magic position 16 is guaranteed to be after the
|
||||
// last space in a decoded CQ or QRZ message but before any
|
||||
// appended DXCC entity name or worked before information
|
||||
auto eom_pos = message_.indexOf (' ', 16);
|
||||
// we always want at least the characters to position 16
|
||||
if (eom_pos < 16) eom_pos = message_.size () - 1;
|
||||
// remove DXCC entity and worked B4 status. TODO need a better way to do this
|
||||
message_ = message_.left (eom_pos + 1);
|
||||
}
|
||||
// stdmsg is a fortran routine that packs the text, unpacks it
|
||||
// and compares the result
|
||||
auto message_c_string = message_.toLocal8Bit ();
|
||||
message_c_string += QByteArray {22 - message_c_string.size (), ' '};
|
||||
auto grid_c_string = my_grid.toLocal8Bit ();
|
||||
grid_c_string += QByteArray {6 - grid_c_string.size (), ' '};
|
||||
is_standard_ = stdmsg_ (message_c_string.constData ()
|
||||
, contest_mode_
|
||||
, grid_c_string.constData ()
|
||||
, 22, 6);
|
||||
}
|
||||
};
|
||||
|
||||
QStringList DecodedText::messageWords () const
|
||||
{
|
||||
if (is_standard_)
|
||||
{
|
||||
// extract up to the first four message words
|
||||
return words_re.match (message_).capturedTexts ();
|
||||
}
|
||||
// simple word split for free text messages
|
||||
auto words = message_.split (' ', QString::SkipEmptyParts);
|
||||
// add whole message as item 0 to mimic RE capture list
|
||||
words.prepend (message_);
|
||||
return words;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return words_re.match (message_).captured ("word1");
|
||||
}
|
||||
|
||||
// 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 const& match = words_re.match (message_);
|
||||
call = match.captured ("word2");
|
||||
grid = match.captured ("word3");
|
||||
if (contest_mode_ && "R" == grid)
|
||||
{
|
||||
grid = match.captured ("word4");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned DecodedText::timeInSeconds() const
|
||||
{
|
||||
return 3600 * string_.mid (column_time, 2).toUInt ()
|
||||
+ 60 * string_.mid (column_time + 2, 2).toUInt()
|
||||
+ (padding_ ? string_.mid (column_time + 2 + padding_, 2).toUInt () : 0U);
|
||||
}
|
||||
|
||||
/*
|
||||
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,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;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
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.)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,216 +0,0 @@
|
||||
#include "adif.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
|
||||
/*
|
||||
<CALL:4>W1XT<BAND:3>20m<FREQ:6>14.076<GRIDSQUARE:4>DM33<MODE:4>JT65<RST_RCVD:3>-21<RST_SENT:3>-14<QSO_DATE:8>20110422<TIME_ON:6>041712<TIME_OFF:6>042435<TX_PWR:1>4<COMMENT:34>1st JT65A QSO. Him: mag loop 20W<STATION_CALLSIGN:6>VK3ACF<MY_GRIDSQUARE:6>qf22lb<eor>
|
||||
<CALL:6>IK1SOW<BAND:3>20m<FREQ:6>14.076<GRIDSQUARE:4>JN35<MODE:4>JT65<RST_RCVD:3>-19<RST_SENT:3>-11<QSO_DATE:8>20110422<TIME_ON:6>052501<TIME_OFF:6>053359<TX_PWR:1>3<STATION_CALLSIGN:6>VK3ACF<MY_GRIDSQUARE:6>qf22lb<eor>
|
||||
<CALL:6:S>W4ABC> ...
|
||||
*/
|
||||
|
||||
void ADIF::init(QString const& filename)
|
||||
{
|
||||
_filename = filename;
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
|
||||
QString ADIF::extractField(QString const& record, QString const& fieldName) const
|
||||
{
|
||||
int fieldNameIndex = record.indexOf (fieldName + ':', 0, Qt::CaseInsensitive);
|
||||
if (fieldNameIndex >=0)
|
||||
{
|
||||
int closingBracketIndex = record.indexOf('>',fieldNameIndex);
|
||||
int fieldLengthIndex = record.indexOf(':',fieldNameIndex); // find the size delimiter
|
||||
int dataTypeIndex = -1;
|
||||
if (fieldLengthIndex >= 0)
|
||||
{
|
||||
dataTypeIndex = record.indexOf(':',fieldLengthIndex+1); // check for a second : indicating there is a data type
|
||||
if (dataTypeIndex > closingBracketIndex)
|
||||
dataTypeIndex = -1; // second : was found but it was beyond the closing >
|
||||
}
|
||||
|
||||
if ((closingBracketIndex > fieldNameIndex) && (fieldLengthIndex > fieldNameIndex) && (fieldLengthIndex< closingBracketIndex))
|
||||
{
|
||||
int fieldLengthCharCount = closingBracketIndex - fieldLengthIndex -1;
|
||||
if (dataTypeIndex >= 0)
|
||||
fieldLengthCharCount -= 2; // data type indicator is always a colon followed by a single character
|
||||
QString fieldLengthString = record.mid(fieldLengthIndex+1,fieldLengthCharCount);
|
||||
int fieldLength = fieldLengthString.toInt();
|
||||
if (fieldLength > 0)
|
||||
{
|
||||
QString field = record.mid(closingBracketIndex+1,fieldLength);
|
||||
return field;
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ADIF::load()
|
||||
{
|
||||
_data.clear();
|
||||
QFile inputFile(_filename);
|
||||
if (inputFile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QTextStream in(&inputFile);
|
||||
QString buffer;
|
||||
bool pre_read {false};
|
||||
int end_position {-1};
|
||||
|
||||
// skip optional header record
|
||||
do
|
||||
{
|
||||
buffer += in.readLine () + '\n';
|
||||
if (buffer.startsWith (QChar {'<'})) // denotes no header
|
||||
{
|
||||
pre_read = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
end_position = buffer.indexOf ("<EOH>", 0, Qt::CaseInsensitive);
|
||||
}
|
||||
}
|
||||
while (!in.atEnd () && !pre_read && end_position < 0);
|
||||
if (!pre_read) // found header
|
||||
{
|
||||
buffer.remove (0, end_position + 5);
|
||||
}
|
||||
while (buffer.size () || !in.atEnd ())
|
||||
{
|
||||
do
|
||||
{
|
||||
end_position = buffer.indexOf ("<EOR>", 0, Qt::CaseInsensitive);
|
||||
if (!in.atEnd () && end_position < 0)
|
||||
{
|
||||
buffer += in.readLine () + '\n';
|
||||
}
|
||||
}
|
||||
while (!in.atEnd () && end_position < 0);
|
||||
int record_length {end_position >= 0 ? end_position + 5 : -1};
|
||||
auto record = buffer.left (record_length).trimmed ();
|
||||
auto next_record = buffer.indexOf (QChar {'<'}, record_length);
|
||||
buffer.remove (0, next_record >=0 ? next_record : buffer.size ());
|
||||
record = record.mid (record.indexOf (QChar {'<'}));
|
||||
add (extractField (record, "CALL")
|
||||
, extractField (record, "BAND")
|
||||
, extractField (record, "MODE")
|
||||
, extractField (record, "QSO_DATE"));
|
||||
}
|
||||
inputFile.close ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ADIF::add(QString const& call, QString const& band, QString const& mode, QString const& date)
|
||||
{
|
||||
QSO q;
|
||||
q.call = call;
|
||||
q.band = band;
|
||||
q.mode = mode;
|
||||
q.date = date;
|
||||
if (q.call.size ())
|
||||
{
|
||||
_data.insert(q.call,q);
|
||||
// qDebug() << "Added as worked:" << call << band << mode << date;
|
||||
}
|
||||
}
|
||||
|
||||
// return true if in the log same band and mode (where JT65 == JT9)
|
||||
bool ADIF::match(QString const& call, QString const& band, QString const& mode) const
|
||||
{
|
||||
QList<QSO> qsos = _data.values(call);
|
||||
if (qsos.size()>0)
|
||||
{
|
||||
QSO q;
|
||||
foreach(q,qsos)
|
||||
{
|
||||
if ( (band.compare(q.band,Qt::CaseInsensitive) == 0)
|
||||
|| (band=="")
|
||||
|| (q.band==""))
|
||||
{
|
||||
if (
|
||||
(
|
||||
((mode.compare("JT65",Qt::CaseInsensitive)==0) ||
|
||||
(mode.compare("JT9",Qt::CaseInsensitive)==0) ||
|
||||
(mode.compare("FT8",Qt::CaseInsensitive)==0))
|
||||
&&
|
||||
((q.mode.compare("JT65",Qt::CaseInsensitive)==0) ||
|
||||
(q.mode.compare("JT9",Qt::CaseInsensitive)==0) ||
|
||||
(q.mode.compare("FT8",Qt::CaseInsensitive)==0))
|
||||
)
|
||||
|| (mode.compare(q.mode,Qt::CaseInsensitive)==0)
|
||||
|| (mode=="")
|
||||
|| (q.mode=="")
|
||||
)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<QString> ADIF::getCallList() const
|
||||
{
|
||||
QList<QString> p;
|
||||
QMultiHash<QString,QSO>::const_iterator i = _data.constBegin();
|
||||
while (i != _data.constEnd())
|
||||
{
|
||||
p << i.key();
|
||||
++i;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int ADIF::getCount() const
|
||||
{
|
||||
return _data.size();
|
||||
}
|
||||
|
||||
|
||||
// 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)
|
||||
{
|
||||
QFile f2(_filename);
|
||||
if (!f2.open(QIODevice::Text | QIODevice::Append))
|
||||
return false;
|
||||
else
|
||||
{
|
||||
QTextStream out(&f2);
|
||||
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;
|
||||
f2.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<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 Rx frequency.<br/>
|
||||
<b>Shift-click</b> to set Tx frequency.<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>
|
||||
<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 frequency to<br/>
|
||||
decoded signal's frequency, and generate standard<br/>
|
||||
messages.<br/>
|
||||
If <b>Hold Tx Freq</b> is checked or first callsign in message<br/>
|
||||
is your own call, Tx frequency is not changed unless <br/>
|
||||
<b>Ctrl</b> is held down.<br/>
|
||||
</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,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
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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.
|
||||
@@ -0,0 +1,365 @@
|
||||
subroutine osd174(llr,apmask,ndeep,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),misub(K),e2sub(N-K),e2(N-K),ui(N-K)
|
||||
integer*1 r2pat(N-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,reset
|
||||
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 decisions on 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).
|
||||
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. Return the member of the list that has the smallest Euclidean
|
||||
! distance to the received word.
|
||||
|
||||
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)
|
||||
|
||||
call mrbencode(m0,c0,g2,N,K)
|
||||
nxor=ieor(c0,hdec)
|
||||
nhardmin=sum(nxor)
|
||||
dmin=sum(nxor*absrx)
|
||||
|
||||
cw=c0
|
||||
ntotal=0
|
||||
nrejected=0
|
||||
|
||||
if(ndeep.eq.0) goto 998 ! norder=0
|
||||
if(ndeep.gt.5) ndeep=5
|
||||
if( ndeep.eq. 1) then
|
||||
nord=1
|
||||
npre1=0
|
||||
npre2=0
|
||||
nt=40
|
||||
ntheta=12
|
||||
elseif(ndeep.eq.2) then
|
||||
nord=1
|
||||
npre1=1
|
||||
npre2=0
|
||||
nt=40
|
||||
ntheta=12
|
||||
elseif(ndeep.eq.3) then
|
||||
nord=1
|
||||
npre1=1
|
||||
npre2=1
|
||||
nt=40
|
||||
ntheta=12
|
||||
ntau=14
|
||||
elseif(ndeep.eq.4) then
|
||||
nord=2
|
||||
npre1=1
|
||||
npre2=0
|
||||
nt=40
|
||||
ntheta=12
|
||||
ntau=19
|
||||
elseif(ndeep.eq.5) then
|
||||
nord=2
|
||||
npre1=1
|
||||
npre2=1
|
||||
nt=40
|
||||
ntheta=12
|
||||
ntau=19
|
||||
endif
|
||||
|
||||
do iorder=1,nord
|
||||
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
|
||||
else
|
||||
iend=1
|
||||
endif
|
||||
do n1=iflag,iend,-1
|
||||
mi=misub
|
||||
mi(n1)=1
|
||||
if(any(iand(apmaskr(1:K),mi).eq.1)) cycle
|
||||
ntotal=ntotal+1
|
||||
me=ieor(m0,mi)
|
||||
if(n1.eq.iflag) then
|
||||
call mrbencode(me,ce,g2,N,K)
|
||||
e2sub=ieor(ce(K+1:N),hdec(K+1:N))
|
||||
e2=e2sub
|
||||
nd1Kpt=sum(e2sub(1:nt))+1
|
||||
d1=sum(ieor(me(1:K),hdec(1:K))*absrx(1:K))
|
||||
else
|
||||
e2=ieor(e2sub,g2(K+1:N,n1))
|
||||
nd1Kpt=sum(e2(1:nt))+2
|
||||
endif
|
||||
if(nd1Kpt .le. ntheta) then
|
||||
call mrbencode(me,ce,g2,N,K)
|
||||
nxor=ieor(ce,hdec)
|
||||
if(n1.eq.iflag) then
|
||||
dd=d1+sum(e2sub*absrx(K+1:N))
|
||||
else
|
||||
dd=d1+ieor(ce(n1),hdec(n1))*absrx(n1)+sum(e2*absrx(K+1:N))
|
||||
endif
|
||||
if( dd .lt. dmin ) then
|
||||
dmin=dd
|
||||
cw=ce
|
||||
nhardmin=sum(nxor)
|
||||
nd1Kptbest=nd1Kpt
|
||||
endif
|
||||
else
|
||||
nrejected=nrejected+1
|
||||
endif
|
||||
enddo
|
||||
! Get the next test error pattern, iflag will go negative
|
||||
! when the last pattern with weight iorder has been generated.
|
||||
call nextpat(misub,k,iorder,iflag)
|
||||
enddo
|
||||
enddo
|
||||
|
||||
if(npre2.eq.1) then
|
||||
reset=.true.
|
||||
ntotal=0
|
||||
do i1=K,1,-1
|
||||
do i2=i1-1,1,-1
|
||||
ntotal=ntotal+1
|
||||
mi(1:ntau)=ieor(g2(K+1:K+ntau,i1),g2(K+1:K+ntau,i2))
|
||||
call boxit(reset,mi(1:ntau),ntau,ntotal,i1,i2)
|
||||
enddo
|
||||
enddo
|
||||
|
||||
ncount2=0
|
||||
ntotal2=0
|
||||
reset=.true.
|
||||
! Now run through again and do the second pre-processing rule
|
||||
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)
|
||||
e2sub=ieor(ce(K+1:N),hdec(K+1:N))
|
||||
do i2=0,ntau
|
||||
ntotal2=ntotal2+1
|
||||
ui=0
|
||||
if(i2.gt.0) ui(i2)=1
|
||||
r2pat=ieor(e2sub,ui)
|
||||
778 continue
|
||||
call fetchit(reset,r2pat(1:ntau),ntau,in1,in2)
|
||||
if(in1.gt.0.and.in2.gt.0) then
|
||||
ncount2=ncount2+1
|
||||
mi=misub
|
||||
mi(in1)=1
|
||||
mi(in2)=1
|
||||
if(sum(mi).lt.nord+npre1+npre2.or.any(iand(apmaskr(1:K),mi).eq.1)) cycle
|
||||
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)
|
||||
endif
|
||||
goto 778
|
||||
endif
|
||||
enddo
|
||||
call nextpat(misub,K,nord,iflag)
|
||||
enddo
|
||||
endif
|
||||
|
||||
998 continue
|
||||
! 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
|
||||
do i=1,k ! iflag will point to the lowest-index 1 in mi
|
||||
if(mi(i).eq.1) then
|
||||
iflag=i
|
||||
exit
|
||||
endif
|
||||
enddo
|
||||
return
|
||||
end subroutine nextpat
|
||||
|
||||
subroutine boxit(reset,e2,ntau,npindex,i1,i2)
|
||||
integer*1 e2(1:ntau)
|
||||
integer indexes(4000,2),fp(0:525000),np(4000)
|
||||
logical reset
|
||||
common/boxes/indexes,fp,np
|
||||
|
||||
if(reset) then
|
||||
patterns=-1
|
||||
fp=-1
|
||||
np=-1
|
||||
sc=-1
|
||||
indexes=-1
|
||||
reset=.false.
|
||||
endif
|
||||
|
||||
indexes(npindex,1)=i1
|
||||
indexes(npindex,2)=i2
|
||||
ipat=0
|
||||
do i=1,ntau
|
||||
if(e2(i).eq.1) then
|
||||
ipat=ipat+ishft(1,ntau-i)
|
||||
endif
|
||||
enddo
|
||||
|
||||
ip=fp(ipat) ! see what's currently stored in fp(ipat)
|
||||
if(ip.eq.-1) then
|
||||
fp(ipat)=npindex
|
||||
else
|
||||
do while (np(ip).ne.-1)
|
||||
ip=np(ip)
|
||||
enddo
|
||||
np(ip)=npindex
|
||||
endif
|
||||
return
|
||||
end subroutine boxit
|
||||
|
||||
subroutine fetchit(reset,e2,ntau,i1,i2)
|
||||
integer indexes(4000,2),fp(0:525000),np(4000)
|
||||
integer lastpat
|
||||
integer*1 e2(ntau)
|
||||
logical reset
|
||||
common/boxes/indexes,fp,np
|
||||
save lastpat,inext
|
||||
|
||||
if(reset) then
|
||||
lastpat=-1
|
||||
reset=.false.
|
||||
endif
|
||||
|
||||
ipat=0
|
||||
do i=1,ntau
|
||||
if(e2(i).eq.1) then
|
||||
ipat=ipat+ishft(1,ntau-i)
|
||||
endif
|
||||
enddo
|
||||
index=fp(ipat)
|
||||
|
||||
if(lastpat.ne.ipat .and. index.gt.0) then ! return first set of indices
|
||||
i1=indexes(index,1)
|
||||
i2=indexes(index,2)
|
||||
inext=np(index)
|
||||
elseif(lastpat.eq.ipat .and. inext.gt.0) then
|
||||
i1=indexes(inext,1)
|
||||
i2=indexes(inext,2)
|
||||
inext=np(inext)
|
||||
else
|
||||
i1=-1
|
||||
i2=-1
|
||||
inext=-1
|
||||
endif
|
||||
lastpat=ipat
|
||||
return
|
||||
end subroutine fetchit
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,37 @@
|
||||
subroutine decode65b(s2,nflip,nadd,mode65,ntrials,naggressive,ndepth, &
|
||||
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,ljt65apon
|
||||
character decoded*22
|
||||
character mycall*12,hiscall*12,hisgrid*6
|
||||
save
|
||||
|
||||
if(nqd.eq.-99) stop !Silence compiler warning
|
||||
do j=1,63
|
||||
k=mdat(j) !Points to data symbol
|
||||
if(nflip.lt.0) k=mdat2(j)
|
||||
do i=1,64
|
||||
s3(i,j)=s2(i+2,k)
|
||||
enddo
|
||||
enddo
|
||||
|
||||
call extract(s3,nadd,mode65,ntrials,naggressive,ndepth,nflip,mycall, &
|
||||
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
|
||||
if(decoded(1:7).eq.'0L6MWK ') ncount=-1
|
||||
if(nflip.lt.0 .and. ltext) ncount=-1
|
||||
if(ncount.lt.0) then
|
||||
nft=0
|
||||
decoded=' '
|
||||
endif
|
||||
|
||||
return
|
||||
end subroutine decode65b
|
||||
@@ -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,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 time_off, 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 time_on);
|
||||
|
||||
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,214 +0,0 @@
|
||||
// Status=review
|
||||
=== Standard Exchange
|
||||
By longstanding tradition, a minimally valid QSO requires the exchange
|
||||
of callsigns, a signal report or some other information, and
|
||||
acknowledgments. _WSJT-X_ is designed to facilitate making such
|
||||
minimal QSOs using short, structured messages. The process works best
|
||||
if you use these formats and follow standard operating practices. The
|
||||
recommended basic QSO goes something like this:
|
||||
|
||||
CQ K1ABC FN42 #K1ABC calls CQ
|
||||
K1ABC G0XYZ IO91 #G0XYZ answers
|
||||
G0XYZ K1ABC –19 #K1ABC sends report
|
||||
K1ABC G0XYZ R-22 #G0XYZ sends R+report
|
||||
G0XYZ K1ABC RRR #K1ABC sends RRR
|
||||
K1ABC G0XYZ 73 #G0XYZ sends 73
|
||||
|
||||
*Standard messages* consist of two callsigns (or CQ, QRZ, or DE and
|
||||
one callsign) followed by the transmitting station’s grid locator, a
|
||||
signal report, R plus a signal report, or the final acknowledgements
|
||||
RRR or 73. These messages are compressed and encoded in a highly
|
||||
efficient and reliable way. In uncompressed form (as displayed
|
||||
on-screen) they may contain as many as 22 characters.
|
||||
|
||||
*Signal reports* are specified as signal-to-noise ratio (S/N) in dB,
|
||||
using a standard reference noise bandwidth of 2500 Hz. Thus, in the
|
||||
example message above, K1ABC is telling G0XYZ that his
|
||||
signal is 19 dB below the noise power in bandwidth 2500 Hz. In the
|
||||
message at 0004, G0XYZ acknowledges receipt of that report and
|
||||
responds with a –22 dB signal report. JT65 reports are constrained to
|
||||
lie in the range –30 to –1 dB, and values are significantly compressed
|
||||
above about -10 dB. JT9 supports the extended range –50 to +49 dB and
|
||||
assigns more reliable numbers to relatively strong signals.
|
||||
|
||||
NOTE: Signals become visible on the waterfall around S/N = –26 dB and
|
||||
audible (to someone with very good hearing) around –15 dB. Thresholds
|
||||
for decodability are around -20 dB for FT8, -23 dB for JT4, –25 dB for
|
||||
JT65, –27 dB for JT9.
|
||||
|
||||
NOTE: Several options are available for circumstances where fast QSOs
|
||||
are desirable. Double-click the *Tx1* control under _Now_ or _Next_
|
||||
to toggle use of the Tx2 message rather than Tx1 to start a QSO.
|
||||
Similarly, double-click the *Tx4* control to toggle between sending
|
||||
`RRR` and `RR73` in that message. The `RR73` message should be used
|
||||
only if you are reasonably confident that no repititions will be
|
||||
required.
|
||||
|
||||
=== Free-Text Messages
|
||||
|
||||
Users often add some friendly chit-chat at the end of a QSO.
|
||||
Free-format messages such as "`TNX ROBERT 73`" or "`5W VERT 73 GL`"
|
||||
are supported, up to a maximum of 13 characters, including spaces. In
|
||||
general you should avoid the character / in free-text messages, as the
|
||||
program may then try to interpret your construction as part of a
|
||||
compound callsign. It should be obvious that the JT4, JT9, and JT65
|
||||
protocols are not designed or well suited for extensive conversations
|
||||
or rag-chewing.
|
||||
|
||||
=== Auto-Sequencing
|
||||
|
||||
The slow modes JT4, JT9, JT65, and QRA64 allow nearly 10 seconds at
|
||||
the end of each one-minute receiving sequence -- enough time for you
|
||||
to inspect decoded messages and decide how to reply. The 15-second
|
||||
T/R cycles of FT8 allow only about two seconds for this task, which is
|
||||
often not enough. For this reason a basic auto-sequencing feature is
|
||||
offered. Check *Auto Seq* on the main window to enable this feature:
|
||||
|
||||
image::auto-seq.png[align="center",alt="AutoSeq"]
|
||||
|
||||
When calling CQ you may also choose to check the box *Call 1st*.
|
||||
_WSJT-X_ will then respond automatically to the first decoded
|
||||
responder to your CQ.
|
||||
|
||||
NOTE: When *Auto-Seq* is enabled the program de-activates *Enable Tx*
|
||||
at the end of each QSO. It is not intended that _WSJT-X_ should make
|
||||
fully automated QSOs.
|
||||
|
||||
=== VHF Contest Mode
|
||||
|
||||
A special *NA VHF Contest* mode can be activated for FT8 and MSK144
|
||||
modes by checking a box on the main window. This mode is configured
|
||||
especially for contests in which four-character grid locators are the
|
||||
required exchange. When *NA VHF Contest* mode is active, the standard
|
||||
QSO sequence looks like this:
|
||||
|
||||
CQ K1ABC FN42
|
||||
K1ABC W9XYZ EN37
|
||||
W9XYZ K1ABC R FN42
|
||||
K1ABC W9XYZ RRR
|
||||
W9XYZ K1ABC 73
|
||||
|
||||
In contest circumstances K1ABC might choose to call CQ again rather
|
||||
than sending 73 for his third transmission.
|
||||
|
||||
IMPORTANT: Do not use VHF Contest Mode on an HF band or in conditions
|
||||
where worldwide propagation is available. See
|
||||
<<PROTOCOL_OVERVIEW,Protocol Specifications>> for further details.
|
||||
|
||||
[[COMP-CALL]]
|
||||
=== Compound Callsigns
|
||||
|
||||
Compound callsigns such as xx/K1ABC or K1ABC/x are handled in
|
||||
one of two possible ways:
|
||||
|
||||
.Messages containing Type 1 compound callsigns
|
||||
|
||||
A list of about 350 of the most common prefixes and suffixes can be
|
||||
displayed from the *Help* menu. A single compound callsign involving
|
||||
one item from this list can be used in place of the standard third
|
||||
word of a message (normally a locator, signal report, RRR, or 73).
|
||||
The following examples are all acceptable messages containing *Type 1*
|
||||
compound callsigns:
|
||||
|
||||
CQ ZA/K1ABC
|
||||
CQ K1ABC/4
|
||||
ZA/K1ABC G0XYZ
|
||||
G0XYZ K1ABC/4
|
||||
|
||||
The following messages are _not_ valid, because a third word is not
|
||||
permitted in any message containing a *Type 1* compound callsign:
|
||||
|
||||
ZA/K1ABC G0XYZ -22 #These messages are invalid; each would
|
||||
G0XYZ K1ABC/4 73 # be sent without its third "word"
|
||||
|
||||
A QSO between two stations using *Type 1* compound-callsign messages
|
||||
might look like this:
|
||||
|
||||
CQ ZA/K1ABC
|
||||
ZA/K1ABC G0XYZ
|
||||
G0XYZ K1ABC –19
|
||||
K1ABC G0XYZ R–22
|
||||
G0XYZ K1ABC RRR
|
||||
K1ABC G0XYZ 73
|
||||
|
||||
Notice that the full compound callsign is sent and received in the
|
||||
first two transmissions. After that, the operators omit the add-on
|
||||
prefix or suffix and use the standard structured messages.
|
||||
|
||||
.Type 2 Compound-Callsign Messages
|
||||
|
||||
Prefixes and suffixes _not_ found in the displayable short list are
|
||||
handled by using *Type 2* compound callsigns. In this case the
|
||||
compound callsign must be the second word in a two- or three-word
|
||||
message, and the first word must be CQ, DE, or QRZ. Prefixes can be 1
|
||||
to 4 characters, suffixes 1 to 3 characters. A third word conveying a
|
||||
locator, report, RRR, or 73 is permitted. The following are valid
|
||||
messages containing *Type 2* compound callsigns:
|
||||
|
||||
CQ W4/G0XYZ FM07
|
||||
QRZ K1ABC/VE6 DO33
|
||||
DE W4/G0XYZ FM18
|
||||
DE W4/G0XYZ -22
|
||||
DE W4/G0XYZ R-22
|
||||
DE W4/G0XYZ RRR
|
||||
DE W4/G0XYZ 73
|
||||
|
||||
In each case, the compound callsign is treated as *Type 2* because the
|
||||
add-on prefix or suffix is _not_ one of those in the fixed list. Note
|
||||
that a second callsign is never permissible in these messages.
|
||||
|
||||
NOTE: During a transmission your outgoing message is displayed in the
|
||||
first label on the *Status Bar* and shown exactly as another station
|
||||
will receive it. You can check to see that you are actually
|
||||
transmitting the message you wish to send.
|
||||
|
||||
QSOs involving *Type 2* compound callsigns might look like either
|
||||
of the following sequences:
|
||||
|
||||
CQ K1ABC/VE1 FN75
|
||||
K1ABC G0XYZ IO91
|
||||
G0XYZ K1ABC –19
|
||||
K1ABC G0XYZ R–22
|
||||
G0XYZ K1ABC RRR
|
||||
K1ABC/VE1 73
|
||||
|
||||
|
||||
CQ K1ABC FN42
|
||||
DE G0XYZ/W4 FM18
|
||||
G0XYZ K1ABC –19
|
||||
K1ABC G0XYZ R–22
|
||||
G0XYZ K1ABC RRR
|
||||
DE G0XYZ/W4 73
|
||||
|
||||
Operators with a compound callsign use its full form when calling CQ
|
||||
and possibly also in a 73 transmission, as may be required by
|
||||
licensing authorities. Other transmissions during a QSO may use the
|
||||
standard structured messages without callsign prefix or suffix.
|
||||
|
||||
TIP: If you are using a compound callsign, you may want to
|
||||
experiment with the option *Message generation for type 2 compound
|
||||
callsign holders* on the *Settings | General* tab, so that messages
|
||||
will be generated that best suit your needs.
|
||||
|
||||
=== Pre-QSO Checklist
|
||||
|
||||
Before attempting your first QSO with one of the WSJT modes, be sure
|
||||
to go through the <<TUTORIAL,Basic Operating Tutorial>> above as well
|
||||
as the following checklist:
|
||||
|
||||
- Your callsign and grid locator set to correct values
|
||||
|
||||
- PTT and CAT control (if used) properly configured and tested
|
||||
|
||||
- Computer clock properly synchronized to UTC within ±1 s
|
||||
|
||||
- Audio input and output devices configured for sample rate 48000 Hz,
|
||||
16 bits
|
||||
|
||||
- Radio set to *USB* (upper sideband) mode
|
||||
|
||||
- Radio filters centered and set to widest available passband (up to 5 kHz).
|
||||
|
||||
TIP: Remember that in many circumstances FT8, JT4, JT9, JT65, and WSPR
|
||||
do not require high power. Under most HF propagation conditions, QRP
|
||||
is the norm.
|
||||
@@ -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
|
||||
Binary file not shown.
@@ -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>
|
||||
@@ -1,200 +0,0 @@
|
||||
#ifndef TRANSCEIVER_FACTORY_HPP__
|
||||
#define TRANSCEIVER_FACTORY_HPP__
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QObject>
|
||||
#include <QMap>
|
||||
|
||||
#include "Transceiver.hpp"
|
||||
|
||||
#include "qt_helpers.hpp"
|
||||
|
||||
class QString;
|
||||
class QThread;
|
||||
class QDir;
|
||||
|
||||
//
|
||||
// Transceiver Factory
|
||||
//
|
||||
class TransceiverFactory
|
||||
: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS (DataBits StopBits Handshake PTTMethod TXAudioSource SplitMode)
|
||||
|
||||
public:
|
||||
//
|
||||
// Capabilities of a Transceiver that can be determined without
|
||||
// actually instantiating one, these are for use in Configuration
|
||||
// GUI behaviour determination
|
||||
//
|
||||
struct Capabilities
|
||||
{
|
||||
enum PortType {none, serial, network, usb};
|
||||
|
||||
explicit Capabilities (int model_number = 0
|
||||
, PortType port_type = none
|
||||
, bool has_CAT_PTT = false
|
||||
, bool has_CAT_PTT_mic_data = false
|
||||
, bool has_CAT_indirect_serial_PTT = false
|
||||
, bool asynchronous = false)
|
||||
: model_number_ {model_number}
|
||||
, port_type_ {port_type}
|
||||
, has_CAT_PTT_ {has_CAT_PTT}
|
||||
, has_CAT_PTT_mic_data_ {has_CAT_PTT_mic_data}
|
||||
, has_CAT_indirect_serial_PTT_ {has_CAT_indirect_serial_PTT}
|
||||
, asynchronous_ {asynchronous}
|
||||
{
|
||||
}
|
||||
|
||||
int model_number_;
|
||||
PortType port_type_;
|
||||
bool has_CAT_PTT_;
|
||||
bool has_CAT_PTT_mic_data_;
|
||||
bool has_CAT_indirect_serial_PTT_; // OmniRig controls RTS/DTR via COM interface
|
||||
bool asynchronous_;
|
||||
};
|
||||
|
||||
//
|
||||
// Dictionary of Transceiver types Capabilities
|
||||
//
|
||||
typedef QMap<QString, Capabilities> Transceivers;
|
||||
|
||||
//
|
||||
// various Transceiver parameters
|
||||
//
|
||||
enum DataBits {seven_data_bits = 7, eight_data_bits};
|
||||
Q_ENUM (DataBits)
|
||||
enum StopBits {one_stop_bit = 1, two_stop_bits};
|
||||
Q_ENUM (StopBits)
|
||||
enum Handshake {handshake_none, handshake_XonXoff, handshake_hardware};
|
||||
Q_ENUM (Handshake)
|
||||
enum PTTMethod {PTT_method_VOX, PTT_method_CAT, PTT_method_DTR, PTT_method_RTS};
|
||||
Q_ENUM (PTTMethod)
|
||||
enum TXAudioSource {TX_audio_source_front, TX_audio_source_rear};
|
||||
Q_ENUM (TXAudioSource)
|
||||
enum SplitMode {split_mode_none, split_mode_rig, split_mode_emulate};
|
||||
Q_ENUM (SplitMode)
|
||||
|
||||
TransceiverFactory ();
|
||||
~TransceiverFactory ();
|
||||
|
||||
static char const * const basic_transceiver_name_; // dummy transceiver is basic model
|
||||
|
||||
//
|
||||
// fetch all supported rigs as a list of name and model id
|
||||
//
|
||||
Transceivers const& supported_transceivers () const;
|
||||
|
||||
// supported model queries
|
||||
Capabilities::PortType CAT_port_type (QString const& name) const; // how to talk to CAT
|
||||
bool has_CAT_PTT (QString const& name) const; // can be keyed via CAT
|
||||
bool has_CAT_PTT_mic_data (QString const& name) const; // Tx audio port is switchable via CAT
|
||||
bool has_CAT_indirect_serial_PTT (QString const& name) const; // Can PTT via CAT port use DTR or RTS (OmniRig for example)
|
||||
bool has_asynchronous_CAT (QString const& name) const; // CAT asynchronous rather than polled
|
||||
|
||||
struct ParameterPack
|
||||
{
|
||||
QString rig_name; // from supported_transceivers () key
|
||||
QString serial_port; // serial port device name or empty
|
||||
QString network_port; // hostname:port or empty
|
||||
QString usb_port; // [vid[:pid[:vendor[:product]]]]
|
||||
int baud;
|
||||
DataBits data_bits;
|
||||
StopBits stop_bits;
|
||||
Handshake handshake;
|
||||
bool force_dtr;
|
||||
bool dtr_high; // to power interface
|
||||
bool force_rts;
|
||||
bool rts_high; // to power interface
|
||||
PTTMethod ptt_type; // "CAT" | "DTR" | "RTS" | "VOX"
|
||||
TXAudioSource audio_source; // some rigs allow audio routing
|
||||
// to Mic/Data connector
|
||||
SplitMode split_mode; // how to support split TX mode
|
||||
QString ptt_port; // serial port device name or special
|
||||
// value "CAT"
|
||||
int poll_interval; // in seconds for interfaces that
|
||||
// require polling for state changes
|
||||
|
||||
bool operator == (ParameterPack const& rhs) const
|
||||
{
|
||||
return rhs.rig_name == rig_name
|
||||
&& rhs.serial_port == serial_port
|
||||
&& rhs.network_port == network_port
|
||||
&& rhs.usb_port == usb_port
|
||||
&& rhs.baud == baud
|
||||
&& rhs.data_bits == data_bits
|
||||
&& rhs.stop_bits == stop_bits
|
||||
&& rhs.handshake == handshake
|
||||
&& rhs.force_dtr == force_dtr
|
||||
&& rhs.dtr_high == dtr_high
|
||||
&& rhs.force_rts == force_rts
|
||||
&& rhs.rts_high == rts_high
|
||||
&& rhs.ptt_type == ptt_type
|
||||
&& rhs.audio_source == audio_source
|
||||
&& rhs.split_mode == split_mode
|
||||
&& rhs.ptt_port == ptt_port
|
||||
&& rhs.poll_interval == poll_interval
|
||||
;
|
||||
}
|
||||
};
|
||||
|
||||
// make a new Transceiver instance
|
||||
//
|
||||
// cat_port, cat_baud, cat_data_bits, cat_stop_bits, cat_handshake,
|
||||
// cat_dtr_control, cat_rts_control are only relevant to interfaces
|
||||
// that are served by Hamlib
|
||||
//
|
||||
// PTT port and to some extent ptt_type are independent of interface
|
||||
// type
|
||||
//
|
||||
std::unique_ptr<Transceiver> create (ParameterPack const&, QThread * target_thread = nullptr);
|
||||
|
||||
private:
|
||||
Transceivers transceivers_;
|
||||
};
|
||||
|
||||
inline
|
||||
bool operator != (TransceiverFactory::ParameterPack const& lhs, TransceiverFactory::ParameterPack const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
//
|
||||
// boilerplate routines to make enum types useable and debuggable in
|
||||
// Qt
|
||||
//
|
||||
#if QT_VERSION < 0x050500
|
||||
Q_DECLARE_METATYPE (TransceiverFactory::DataBits);
|
||||
Q_DECLARE_METATYPE (TransceiverFactory::StopBits);
|
||||
Q_DECLARE_METATYPE (TransceiverFactory::Handshake);
|
||||
Q_DECLARE_METATYPE (TransceiverFactory::PTTMethod);
|
||||
Q_DECLARE_METATYPE (TransceiverFactory::TXAudioSource);
|
||||
Q_DECLARE_METATYPE (TransceiverFactory::SplitMode);
|
||||
#endif
|
||||
|
||||
#if !defined (QT_NO_DEBUG_STREAM)
|
||||
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, DataBits);
|
||||
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, StopBits);
|
||||
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, Handshake);
|
||||
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, PTTMethod);
|
||||
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, TXAudioSource);
|
||||
ENUM_QDEBUG_OPS_DECL (TransceiverFactory, SplitMode);
|
||||
#endif
|
||||
|
||||
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, DataBits);
|
||||
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, StopBits);
|
||||
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, Handshake);
|
||||
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, PTTMethod);
|
||||
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, TXAudioSource);
|
||||
ENUM_QDATASTREAM_OPS_DECL (TransceiverFactory, SplitMode);
|
||||
|
||||
ENUM_CONVERSION_OPS_DECL (TransceiverFactory, DataBits);
|
||||
ENUM_CONVERSION_OPS_DECL (TransceiverFactory, StopBits);
|
||||
ENUM_CONVERSION_OPS_DECL (TransceiverFactory, Handshake);
|
||||
ENUM_CONVERSION_OPS_DECL (TransceiverFactory, PTTMethod);
|
||||
ENUM_CONVERSION_OPS_DECL (TransceiverFactory, TXAudioSource);
|
||||
ENUM_CONVERSION_OPS_DECL (TransceiverFactory, SplitMode);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
// -*- Mode: C++ -*-
|
||||
#ifndef LogQSO_H
|
||||
#define LogQSO_H
|
||||
|
||||
#ifdef QT5
|
||||
#include <QtWidgets>
|
||||
#else
|
||||
#include <QtGui>
|
||||
#endif
|
||||
|
||||
#include <QString>
|
||||
#include <QScopedPointer>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "Radio.hpp"
|
||||
|
||||
namespace Ui {
|
||||
class LogQSO;
|
||||
}
|
||||
|
||||
class QSettings;
|
||||
class Configuration;
|
||||
class QByteArray;
|
||||
|
||||
class LogQSO : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LogQSO(QString const& programTitle, QSettings *, Configuration const *, QWidget *parent = 0);
|
||||
~LogQSO();
|
||||
void 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, bool bFox, QString const& opCall);
|
||||
|
||||
public slots:
|
||||
void accept();
|
||||
|
||||
signals:
|
||||
void acceptQSO (QDateTime const& QSO_date_off, QString const& call, QString const& grid
|
||||
, 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& operator_call
|
||||
, QString const& my_call, QString const& my_grid, QByteArray const& ADIF);
|
||||
|
||||
protected:
|
||||
void hideEvent (QHideEvent *);
|
||||
|
||||
private:
|
||||
void loadSettings ();
|
||||
void storeSettings () const;
|
||||
|
||||
QScopedPointer<Ui::LogQSO> ui;
|
||||
QSettings * m_settings;
|
||||
Configuration const * m_config;
|
||||
QString m_txPower;
|
||||
QString m_comments;
|
||||
Radio::Frequency m_dialFreq;
|
||||
QString m_myCall;
|
||||
QString m_myGrid;
|
||||
QDateTime m_dateTimeOn;
|
||||
QDateTime m_dateTimeOff;
|
||||
};
|
||||
|
||||
#endif // LogQSO_H
|
||||
@@ -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
|
||||
@@ -0,0 +1,524 @@
|
||||
module jt65_decode
|
||||
|
||||
integer, parameter :: NSZ=3413, NZMAX=60*12000
|
||||
|
||||
type :: jt65_decoder
|
||||
procedure(jt65_decode_callback), pointer :: callback => null()
|
||||
contains
|
||||
procedure :: decode
|
||||
end type jt65_decoder
|
||||
|
||||
! Callback function to be called with each decode
|
||||
abstract interface
|
||||
subroutine jt65_decode_callback(this,sync,snr,dt,freq,drift, &
|
||||
nflip,width,decoded,ft,qual,nsmo,nsum,minsync)
|
||||
|
||||
import jt65_decoder
|
||||
implicit none
|
||||
class(jt65_decoder), intent(inout) :: this
|
||||
real, intent(in) :: sync
|
||||
integer, intent(in) :: snr
|
||||
real, intent(in) :: dt
|
||||
integer, intent(in) :: freq
|
||||
integer, intent(in) :: drift
|
||||
integer, intent(in) :: nflip
|
||||
real, intent(in) :: width
|
||||
character(len=22), intent(in) :: decoded
|
||||
integer, intent(in) :: ft
|
||||
integer, intent(in) :: qual
|
||||
integer, intent(in) :: nsmo
|
||||
integer, intent(in) :: nsum
|
||||
integer, intent(in) :: minsync
|
||||
|
||||
end subroutine jt65_decode_callback
|
||||
end interface
|
||||
|
||||
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, &
|
||||
nQSOProgress,ljt65apon)
|
||||
|
||||
! Process dd0() data to find and decode JT65 signals.
|
||||
|
||||
use jt65_mod
|
||||
use timer_module, only: timer
|
||||
|
||||
include 'constants.f90'
|
||||
|
||||
class(jt65_decoder), intent(inout) :: this
|
||||
procedure(jt65_decode_callback) :: callback
|
||||
real, intent(in) :: dd0(NZMAX),emedelay
|
||||
integer, intent(in) :: npts, nutc, nf1, nf2, nfqso, ntol &
|
||||
, nsubmode, minsync, n2pass, ntrials, naggressive, ndepth &
|
||||
, nexp_decode, nQSOProgress
|
||||
logical, intent(in) :: newdat, nagain, nrobust, clearave, ljt65apon
|
||||
character(len=12), intent(in) :: mycall, hiscall
|
||||
character(len=6), intent(in) :: hisgrid
|
||||
|
||||
real dd(NZMAX)
|
||||
real ss(552,NSZ)
|
||||
real savg(NSZ)
|
||||
real a(5)
|
||||
character*22 decoded,decoded0,avemsg,deepave
|
||||
type candidate
|
||||
real freq
|
||||
real dt
|
||||
real sync
|
||||
real flip
|
||||
end type candidate
|
||||
type(candidate) ca(300)
|
||||
type accepted_decode
|
||||
real freq
|
||||
real dt
|
||||
real sync
|
||||
character*22 decoded
|
||||
end type accepted_decode
|
||||
type(accepted_decode) dec(50)
|
||||
logical :: first_time,prtavg,single_decode,bVHF
|
||||
|
||||
integer h0(0:11),d0(0:11)
|
||||
real r0(0:11)
|
||||
common/decstats/ntry65a,ntry65b,n65a,n65b,num9,numfano
|
||||
common/steve/thresh0
|
||||
common/sync/ss
|
||||
|
||||
! 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
data h0/41,42,43,43,44,45,46,47,48,48,49,49/
|
||||
data d0/71,72,73,74,76,77,78,80,81,82,83,83/
|
||||
|
||||
! 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
data r0/0.70,0.72,0.74,0.76,0.78,0.80,0.82,0.84,0.86,0.88,0.90,0.90/
|
||||
data nutc0/-999/,nfreq0/-999/,nsave/0/
|
||||
save
|
||||
|
||||
this%callback => callback
|
||||
first_time=newdat
|
||||
dd=dd0
|
||||
ndecoded=0
|
||||
|
||||
if(nsubmode.ge.100) then
|
||||
! This is QRA64 mode
|
||||
mode64=2**(nsubmode-100)
|
||||
!###
|
||||
! open(60,file='qra64_data.bin',access='stream',position='append')
|
||||
! write(60) dd,npts,nutc,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, &
|
||||
! mycall,hiscall,hisgrid
|
||||
! close(60)
|
||||
!###
|
||||
call qra64a(dd,npts,nutc,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, &
|
||||
emedelay,mycall,hiscall,hisgrid,sync,nsnr,dtx,nfreq,decoded,nft)
|
||||
if (associated(this%callback)) then
|
||||
ndrift=0
|
||||
nflip=1
|
||||
width=1.0
|
||||
nsmo=0
|
||||
nqual=0
|
||||
call this%callback(sync,nsnr,dtx,nfreq,ndrift, &
|
||||
nflip,width,decoded,nft,nqual,nsmo,1,minsync)
|
||||
end if
|
||||
go to 900
|
||||
endif
|
||||
|
||||
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=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
|
||||
thresh0=2.5
|
||||
nsubtract=1
|
||||
nrob=0
|
||||
elseif( ipass.eq.2 ) then !Second-pass parameters
|
||||
thresh0=2.0
|
||||
nsubtract=1
|
||||
nrob=0
|
||||
elseif( ipass.eq.3 ) then
|
||||
thresh0=2.0
|
||||
nsubtract=1
|
||||
nrob=0
|
||||
elseif( ipass.eq.4 ) then
|
||||
thresh0=2.0
|
||||
nsubtract=0
|
||||
nrob=1
|
||||
endif
|
||||
if(npass.eq.1) then
|
||||
nsubtract=0
|
||||
thresh0=2.0
|
||||
endif
|
||||
|
||||
call timer('symsp65 ',0)
|
||||
ss=0.
|
||||
call symspec65(dd,npts,nqsym,savg) !Get normalized symbol spectra
|
||||
call timer('symsp65 ',1)
|
||||
nfa=nf1
|
||||
nfb=nf2
|
||||
|
||||
!### Q: should either of the next two uses of "single_decode" be "bVHF" instead?
|
||||
if(single_decode .or. (bVHF .and. ntol.lt.1000)) then
|
||||
nfa=max(200,nfqso-ntol)
|
||||
nfb=min(4000,nfqso+ntol)
|
||||
thresh0=1.0
|
||||
endif
|
||||
df=12000.0/8192.0 !df = 1.465 Hz
|
||||
if(bVHF) then
|
||||
ia=max(1,nint(nfa/df)-ntol)
|
||||
ib=min(NSZ,nint(nfb/df)+ntol)
|
||||
nz=ib-ia+1
|
||||
call lorentzian(savg(ia),nz,a)
|
||||
baseline=a(1)
|
||||
amp=a(2)
|
||||
f0=(a(3)+ia-1)*df
|
||||
width=a(4)*df
|
||||
endif
|
||||
|
||||
ncand=0
|
||||
call timer('sync65 ',0)
|
||||
call sync65(nfa,nfb,naggressive,ntol,nqsym,ca,ncand,nrob,bVHF)
|
||||
call timer('sync65 ',1)
|
||||
|
||||
! If a candidate was found within +/- ntol of nfqso, move it into ca(1).
|
||||
call fqso_first(nfqso,ntol,ca,ncand)
|
||||
if(single_decode) then
|
||||
if(ncand.eq.0) ncand=1
|
||||
if(abs(ca(1)%freq - f0).gt.width) width=2*df !### ??? ###
|
||||
endif
|
||||
|
||||
mode65=2**nsubmode
|
||||
nflip=1
|
||||
nqd=0
|
||||
decoded=' '
|
||||
decoded0=""
|
||||
freq0=0.
|
||||
prtavg=.false.
|
||||
if(.not.nagain) nsum=0
|
||||
if(clearave) then
|
||||
nsum=0
|
||||
nsave=0
|
||||
endif
|
||||
|
||||
if(bVHF) then
|
||||
! Be sure to search for shorthand message at nfqso +/- ntol
|
||||
if(ncand.lt.300) ncand=ncand+1
|
||||
ca(ncand)%sync=5.0
|
||||
ca(ncand)%dt=2.5
|
||||
ca(ncand)%freq=nfqso
|
||||
endif
|
||||
do icand=1,ncand
|
||||
sync1=ca(icand)%sync
|
||||
dtx=ca(icand)%dt
|
||||
freq=ca(icand)%freq
|
||||
if(bVHF) then
|
||||
flip=ca(icand)%flip
|
||||
nflip=flip
|
||||
endif
|
||||
if(sync1.lt.float(minsync)) nflip=0
|
||||
if(ipass.eq.1) ntry65a=ntry65a + 1
|
||||
if(ipass.eq.2) ntry65b=ntry65b + 1
|
||||
call timer('decod65a',0)
|
||||
nft=0
|
||||
nspecial=0
|
||||
call decode65a(dd,npts,first_time,nqd,freq,nflip,mode65,nvec, &
|
||||
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'
|
||||
if(nspecial.eq.4) decoded='73'
|
||||
call timer('decod65a',1)
|
||||
if(sync1.lt.float(minsync) .and. &
|
||||
decoded.eq.' ') nflip=0
|
||||
if(nft.ne.0) nsum=1
|
||||
|
||||
nhard_min=param(1)
|
||||
nrtt1000=param(4)
|
||||
ntotal_min=param(5)
|
||||
nsmo=param(9)
|
||||
|
||||
nfreq=nint(freq+a(1))
|
||||
ndrift=nint(2.0*a(2))
|
||||
if(bVHF) then
|
||||
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)
|
||||
endif
|
||||
nsnr=nint(s2db)
|
||||
if(nsnr.lt.-30) nsnr=-30
|
||||
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
|
||||
! This is a new minute or a new frequency, so call avg65.
|
||||
nutc0=nutc
|
||||
nfreq0=nfreq
|
||||
nsave=nsave+1
|
||||
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, &
|
||||
nQSOProgress,ljt65apon)
|
||||
nsmo=param(9)
|
||||
nqave=qave
|
||||
|
||||
if (associated(this%callback) .and. nsum.ge.2) then
|
||||
call this%callback(sync1,nsnr,dtx-1.0,nfreq,ndrift, &
|
||||
nflip,width,avemsg,nftt,nqave,nsmo,nsum,minsync)
|
||||
prtavg=.true.
|
||||
end if
|
||||
|
||||
endif
|
||||
endif
|
||||
|
||||
if(nftt.eq.1) then
|
||||
! nft=1
|
||||
decoded=avemsg
|
||||
go to 5
|
||||
endif
|
||||
n=naggressive
|
||||
rtt=0.001*nrtt1000
|
||||
if(nft.lt.2 .and. minsync.ge.0 .and. nspecial.eq.0) then
|
||||
if(nhard_min.gt.50) cycle
|
||||
if(nhard_min.gt.h0(n)) cycle
|
||||
if(ntotal_min.gt.d0(n)) cycle
|
||||
if(rtt.gt.r0(n)) cycle
|
||||
endif
|
||||
|
||||
5 continue
|
||||
if(decoded.eq.decoded0 .and. abs(freq-freq0).lt. 3.0 .and. &
|
||||
minsync.ge.0) cycle !Don't display dupes
|
||||
if(decoded.ne.' ' .or. minsync.lt.0) then
|
||||
if(nsubtract.eq.1) then
|
||||
call timer('subtr65 ',0)
|
||||
call subtract65(dd,npts,freq,dtx)
|
||||
call timer('subtr65 ',1)
|
||||
endif
|
||||
|
||||
ndupe=0 ! de-dedupe
|
||||
do i=1, ndecoded
|
||||
if(decoded==dec(i)%decoded) then
|
||||
ndupe=1
|
||||
exit
|
||||
endif
|
||||
enddo
|
||||
if(ndupe.ne.1 .and. sync1.ge.float(minsync)) then
|
||||
if(ipass.eq.1) n65a=n65a + 1
|
||||
if(ipass.eq.2) n65b=n65b + 1
|
||||
if(ndecoded.lt.50) ndecoded=ndecoded+1
|
||||
dec(ndecoded)%freq=freq+a(1)
|
||||
dec(ndecoded)%dt=dtx
|
||||
dec(ndecoded)%sync=sync2
|
||||
dec(ndecoded)%decoded=decoded
|
||||
nqual=min(qual,9999.0)
|
||||
|
||||
if (associated(this%callback)) then
|
||||
call this%callback(sync1,nsnr,dtx-1.0,nfreq,ndrift, &
|
||||
nflip,width,decoded,nft,nqual,nsmo,1,minsync)
|
||||
end if
|
||||
endif
|
||||
decoded0=decoded
|
||||
freq0=freq
|
||||
if(decoded0.eq.' ') decoded0='*'
|
||||
endif
|
||||
enddo !Candidate loop
|
||||
if(ipass.eq.2 .and. ndecoded.lt.1) exit
|
||||
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,nQSOProgress,ljt65apon)
|
||||
|
||||
! Decodes averaged JT65 data
|
||||
|
||||
use jt65_mod
|
||||
parameter (MAXAVE=64)
|
||||
character*22 avemsg,deepave,deepbest
|
||||
character mycall*12,hiscall*12,hisgrid*6
|
||||
character*1 csync,cused(64)
|
||||
logical nagain
|
||||
integer iused(64)
|
||||
! Accumulated data for message averaging
|
||||
integer iutc(MAXAVE)
|
||||
integer nfsave(MAXAVE)
|
||||
integer nflipsave(MAXAVE)
|
||||
real s1b(-255:256,126)
|
||||
real s1save(-255:256,126,MAXAVE)
|
||||
real s2(66,126)
|
||||
real s3save(64,63,MAXAVE)
|
||||
real s3b(64,63)
|
||||
real s3c(64,63)
|
||||
real dtsave(MAXAVE)
|
||||
real syncsave(MAXAVE)
|
||||
logical first,clearave,ljt65apon
|
||||
data first/.true./
|
||||
save
|
||||
|
||||
if(first .or. clearave) then
|
||||
iutc=-1
|
||||
nfsave=0
|
||||
dtdiff=0.2
|
||||
first=.false.
|
||||
s3save=0.
|
||||
s1save=0.
|
||||
nsave=1 !### ???
|
||||
! Silence compiler warnings
|
||||
if(nagain .and. ndeepave.eq.-99 .and. neme.eq.-99) stop
|
||||
endif
|
||||
|
||||
do i=1,64
|
||||
if(iutc(i).lt.0) exit
|
||||
if(nutc.eq.iutc(i) .and. abs(nfreq-nfsave(i)).le.ntol) go to 10
|
||||
enddo
|
||||
|
||||
! Save data for message averaging
|
||||
iutc(nsave)=nutc
|
||||
syncsave(nsave)=snrsync
|
||||
dtsave(nsave)=dtxx
|
||||
nfsave(nsave)=nfreq
|
||||
nflipsave(nsave)=nflip
|
||||
s1save(-255:256,1:126,nsave)=s1
|
||||
s3save(1:64,1:63,nsave)=s3a
|
||||
|
||||
10 syncsum=0.
|
||||
dtsum=0.
|
||||
nfsum=0
|
||||
nsum=0
|
||||
s1b=0.
|
||||
s3b=0.
|
||||
s3c=0.
|
||||
|
||||
do i=1,MAXAVE !Consider all saved spectra
|
||||
cused(i)='.'
|
||||
if(iutc(i).lt.0) cycle
|
||||
if(mod(iutc(i),2).ne.mod(nutc,2)) cycle !Use only same (odd/even) seq
|
||||
if(abs(dtxx-dtsave(i)).gt.dtdiff) cycle !DT must match
|
||||
if(abs(nfreq-nfsave(i)).gt.ntol) cycle !Freq must match
|
||||
if(nflip.ne.nflipsave(i)) cycle !Sync type (*/#) must match
|
||||
s3b=s3b + s3save(1:64,1:63,i)
|
||||
s1b=s1b + s1save(-255:256,1:126,i)
|
||||
syncsum=syncsum + syncsave(i)
|
||||
dtsum=dtsum + dtsave(i)
|
||||
nfsum=nfsum + nfsave(i)
|
||||
cused(i)='$'
|
||||
nsum=nsum+1
|
||||
iused(nsum)=i
|
||||
enddo
|
||||
if(nsum.lt.64) iused(nsum+1)=0
|
||||
|
||||
syncave=0.
|
||||
dtave=0.
|
||||
fave=0.
|
||||
if(nsum.gt.0) then
|
||||
syncave=syncsum/nsum
|
||||
dtave=dtsum/nsum
|
||||
fave=float(nfsum)/nsum
|
||||
endif
|
||||
|
||||
do i=1,nsave
|
||||
csync='*'
|
||||
if(nflipsave(i).lt.0.0) csync='#'
|
||||
write(14,1000) cused(i),iutc(i),syncsave(i),dtsave(i)-1.0,nfsave(i),csync
|
||||
1000 format(a1,i5.4,f6.1,f6.2,i6,1x,a1)
|
||||
enddo
|
||||
if(nsum.lt.2) go to 900
|
||||
|
||||
nftt=0
|
||||
df=1378.125/512.0
|
||||
|
||||
! Do the smoothing loop
|
||||
qualbest=0.
|
||||
minsmo=0
|
||||
maxsmo=0
|
||||
if(mode65.ge.2) then
|
||||
minsmo=nint(width/df)
|
||||
maxsmo=2*minsmo
|
||||
endif
|
||||
nn=0
|
||||
do ismo=minsmo,maxsmo
|
||||
if(ismo.gt.0) then
|
||||
do j=1,126
|
||||
call smo121(s1b(-255,j),512)
|
||||
if(j.eq.1) nn=nn+1
|
||||
if(nn.ge.4) then
|
||||
call smo121(s1b(-255,j),512)
|
||||
if(j.eq.1) nn=nn+1
|
||||
endif
|
||||
enddo
|
||||
endif
|
||||
|
||||
do i=1,66
|
||||
jj=i
|
||||
if(mode65.eq.2) jj=2*i-1
|
||||
if(mode65.eq.4) then
|
||||
ff=4*(i-1)*df - 355.297852
|
||||
jj=nint(ff/df)+1
|
||||
endif
|
||||
s2(i,1:126)=s1b(jj,1:126)
|
||||
enddo
|
||||
|
||||
do j=1,63
|
||||
k=mdat(j) !Points to data symbol
|
||||
if(nflip.lt.0) k=mdat2(j)
|
||||
do i=1,64
|
||||
s3c(i,j)=4.e-5*s2(i+2,k)
|
||||
enddo
|
||||
enddo
|
||||
|
||||
nadd=nsum*ismo
|
||||
call extract(s3c,nadd,mode65,ntrials,naggressive,ndepth,nflip,mycall, &
|
||||
hiscall,hisgrid,nQSOProgress,ljt65apon,nexp_decode,ncount,nhist, &
|
||||
avemsg,ltext,nftt,qual)
|
||||
if(nftt.eq.1) then
|
||||
nsmo=ismo
|
||||
param(9)=nsmo
|
||||
go to 900
|
||||
else if(nftt.eq.2) then
|
||||
if(qual.gt.qualbest) then
|
||||
deepbest=avemsg
|
||||
qualbest=qual
|
||||
nnbest=nn
|
||||
nsmobest=ismo
|
||||
nfttbest=nftt
|
||||
endif
|
||||
endif
|
||||
enddo
|
||||
|
||||
if(nfttbest.eq.2) then
|
||||
avemsg=deepbest !### ???
|
||||
deepave=deepbest
|
||||
qave=qualbest
|
||||
nsmo=nsmobest
|
||||
param(9)=nsmo
|
||||
nftt=nfttbest
|
||||
endif
|
||||
900 continue
|
||||
|
||||
return
|
||||
end subroutine avg65
|
||||
|
||||
end module jt65_decode
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user