Merged master 8748

This commit is contained in:
Jordan Sherer
2018-08-05 11:33:30 -04:00
parent 8f8772f1bd
commit 62899069bf
1095 changed files with 31298 additions and 367679 deletions
-1
View File
@@ -1,3 +1,2 @@
TAGS TAGS
tags tags
.svn
@@ -1,51 +0,0 @@
#ifndef WSJTX_MESSAGE_AGGREGATOR_MAIN_WINDOW_MODEL_HPP__
#define WSJTX_MESSAGE_AGGREGATOR_MAIN_WINDOW_MODEL_HPP__
#include <QMainWindow>
#include <QHash>
#include <QString>
#include "MessageServer.hpp"
class QDateTime;
class QStandardItemModel;
class QMenu;
class DecodesModel;
class BeaconsModel;
class QLineEdit;
class QTableView;
class ClientWidget;
using Frequency = MessageServer::Frequency;
class MessageAggregatorMainWindow
: public QMainWindow
{
Q_OBJECT;
public:
MessageAggregatorMainWindow ();
Q_SLOT void log_qso (QString const& /*id*/, QDateTime timeOff, QString const& dx_call, QString const& dx_grid
, Frequency dial_frequency, QString const& mode, QString const& report_sent
, QString const& report_received, QString const& tx_power, QString const& comments
, QString const& name, QDateTime timeOn);
private:
void add_client (QString const& id, QString const& version, QString const& revision);
void remove_client (QString const& id);
QStandardItemModel * log_;
QMenu * view_menu_;
DecodesModel * decodes_model_;
BeaconsModel * beacons_model_;
MessageServer * server_;
QLineEdit * multicast_group_line_edit_;
QTableView * log_table_view_;
// maps client id to widgets
using ClientsDictionary = QHash<QString, ClientWidget *>;
ClientsDictionary dock_widgets_;
};
#endif
@@ -1,5 +0,0 @@
kern.sysv.shmmax=33554432
kern.sysv.shmmin=1
kern.sysv.shmmni=128
kern.sysv.shmseg=32
kern.sysv.shmall=8192
@@ -1,166 +0,0 @@
/* ALIST-TO-PCHK.C - Convert a parity check matrix to alist format. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "alloc.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
void usage(void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
char *alist_file, *pchk_file;
FILE *af, *pf;
int mxrw, mxcw;
int *rw, *cw;
int i, j, k;
mod2entry *e;
int trans;
int nozeros;
int last;
trans = 0;
nozeros = 0;
for (;;)
{
if (argc>1 && strcmp(argv[1],"-t")==0)
{ trans = 1;
argc -= 1;
argv += 1;
}
else if (argc>1 && strcmp(argv[1],"-z")==0)
{ nozeros = 1;
argc -= 1;
argv += 1;
}
else
{ break;
}
}
if (argc!=3)
{ usage();
}
pchk_file = argv[1];
alist_file = argv[2];
read_pchk(pchk_file);
if (trans)
{ mod2sparse *HT;
HT = H;
H = mod2sparse_allocate(N,M);
mod2sparse_transpose(HT,H);
M = mod2sparse_rows(H);
N = mod2sparse_cols(H);
}
af = open_file_std(alist_file,"wb");
if (af==NULL)
{ fprintf(stderr,"Can't create alist file: %s\n",alist_file);
exit(1);
}
fprintf(af,"%d %d\n",M,N);
rw = (int *) chk_alloc (M, sizeof *rw);
mxrw = 0;
for (i = 0; i<M; i++)
{ rw[i] = mod2sparse_count_row(H,i);
if (rw[i]>mxrw)
{ mxrw = rw[i];
}
}
cw = (int *) chk_alloc (N, sizeof *cw);
mxcw = 0;
for (j = 0; j<N; j++)
{ cw[j] = mod2sparse_count_col(H,j);
if (cw[j]>mxcw)
{ mxcw = cw[j];
}
}
fprintf(af,"%d %d\n",mxrw,mxcw);
for (i = 0; i<M; i++)
{ fprintf(af,"%d%c",rw[i],i==M-1?'\n':' ');
}
for (j = 0; j<N; j++)
{ fprintf(af,"%d%c",cw[j],j==N-1?'\n':' ');
}
for (i = 0; i<M; i++)
{ e = mod2sparse_first_in_row(H,i);
last = 0;
for (k = 0; !last; k++)
{ last = nozeros ? k==rw[i]-1 : k==mxrw-1;
fprintf (af, "%d%c", mod2sparse_at_end(e)?0:mod2sparse_col(e)+1,
last?'\n':' ');
if (!mod2sparse_at_end(e))
{ e = mod2sparse_next_in_row(e);
}
}
}
for (j = 0; j<N; j++)
{ e = mod2sparse_first_in_col(H,j);
last = 0;
for (k = 0; !last; k++)
{ last = nozeros ? k==cw[j]-1 : k==mxcw-1;
fprintf (af, "%d%c", mod2sparse_at_end(e)?0:mod2sparse_row(e)+1,
last?'\n':' ');
if (!mod2sparse_at_end(e))
{ e = mod2sparse_next_in_col(e);
}
}
}
if (ferror(af) || fclose(af)!=0)
{ fprintf(stderr,"Error writing to alist file %s\n",alist_file);
exit(1);
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage: pchk-to-alist [ -t ] [ -z ] pchk-file alist-file\n");
exit(1);
}
@@ -1,197 +0,0 @@
#include "decodedtext.h"
#include <QStringList>
#include <QRegularExpression>
extern "C" {
bool stdmsg_(const char* msg, int len);
}
DecodedText::DecodedText (QString const& the_string)
: string_ {the_string}
, padding_ {the_string.indexOf (" ") > 4 ? 2 : 0} // allow for
// seconds
, message_ {string_.mid (column_qsoText + padding_).trimmed ()}
, is_standard_ {false}
{
if (message_.length() >= 1)
{
message_ = message_.left (22).remove (QRegularExpression {"[<>]"});
int i1 = message_.indexOf ('\r');
if (i1 > 0)
{
message_ = message_.left (i1 - 1);
}
// stdmsg is a fortran routine that packs the text, unpacks it and compares the result
is_standard_ = stdmsg_ ((message_ + " ").toLatin1 ().constData (),22);
}
};
void DecodedText::removeAddedInfo ()
{
if (string_.indexOf (" CQ ") > 0) {
// TODO this magic 37 characters is also referenced in DisplayText::_appendDXCCWorkedB4()
auto eom_pos = string_.indexOf (' ', 37);
if (eom_pos < 37) eom_pos = string_.size () - 1; // we always want at least the characters
// to position 37
string_ = string_.left (eom_pos + 1); // remove DXCC entity and worked B4 status. TODO need a better way to do this
}
}
QString DecodedText::CQersCall() const
{
QRegularExpression callsign_re {R"(^(CQ|DE|QRZ)(\s?DX|\s([A-Z]{2}|\d{3}))?\s(?<callsign>[A-Z0-9/]{2,})(\s[A-R]{2}[0-9]{2})?)"};
return callsign_re.match (message_).captured ("callsign");
}
bool DecodedText::isJT65() const
{
return string_.indexOf("#") == column_mode + padding_;
}
bool DecodedText::isJT9() const
{
return string_.indexOf("@") == column_mode + padding_;
}
bool DecodedText::isTX() const
{
int i = string_.indexOf("Tx");
return (i >= 0 && i < 15); // TODO guessing those numbers. Does Tx ever move?
}
bool DecodedText::isLowConfidence () const
{
return QChar {'?'} == string_.mid (padding_ + column_qsoText + 21, 1);
}
int DecodedText::frequencyOffset() const
{
return string_.mid(column_freq + padding_,4).toInt();
}
int DecodedText::snr() const
{
int i1=string_.indexOf(" ")+1;
return string_.mid(i1,3).toInt();
}
float DecodedText::dt() const
{
return string_.mid(column_dt + padding_,5).toFloat();
}
/*
2343 -11 0.8 1259 # YV6BFE F6GUU R-08
2343 -19 0.3 718 # VE6WQ SQ2NIJ -14
2343 -7 0.3 815 # KK4DSD W7VP -16
2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02
0605 Tx 1259 # CQ VK3ACF QF22
*/
// find and extract any report. Returns true if this is a standard message
bool DecodedText::report(QString const& myBaseCall, QString const& dxBaseCall, /*mod*/QString& report) const
{
if (message_.size () < 1) return false;
QStringList const& w = message_.split(" ",QString::SkipEmptyParts);
if (w.size ()
&& is_standard_ && (w[0] == myBaseCall
|| w[0].endsWith ("/" + myBaseCall)
|| w[0].startsWith (myBaseCall + "/")
|| (w.size () > 1 && !dxBaseCall.isEmpty ()
&& (w[1] == dxBaseCall
|| w[1].endsWith ("/" + dxBaseCall)
|| w[1].startsWith (dxBaseCall + "/")))))
{
QString tt="";
if(w.size() > 2) tt=w[2];
bool ok;
auto i1=tt.toInt(&ok);
if (ok and i1>=-50 and i1<50)
{
report = tt;
}
else
{
if (tt.mid(0,1)=="R")
{
i1=tt.mid(1).toInt(&ok);
if(ok and i1>=-50 and i1<50)
{
report = tt.mid(1);
}
}
}
}
return is_standard_;
}
// get the first text word, usually the call
QString DecodedText::call() const
{
auto call = string_;
call = call.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
int i = call.indexOf(" ");
return call.mid(0,i);
}
// get the second word, most likely the de call and the third word, most likely grid
void DecodedText::deCallAndGrid(/*out*/QString& call, QString& grid) const
{
auto msg = string_;
if(msg.mid(4,1)!=" ") msg=msg.mid(0,4)+msg.mid(6,-1); //Remove seconds from UTC
msg = msg.replace (QRegularExpression {" CQ ([A-Z]{2,2}|[0-9]{3,3}) "}, " CQ_\\1 ").mid (column_qsoText + padding_);
int i1 = msg.indexOf (" ");
call = msg.mid (i1 + 1);
int i2 = call.indexOf (" ");
if (" R " == call.mid (i2, 3)) // MSK144 contest mode report
{
grid = call.mid (i2 + 3, 4);
}
else
{
grid = call.mid (i2 + 1, 4);
}
call = call.left (i2).replace (">", "");
}
int DecodedText::timeInSeconds() const
{
return 60*string_.mid(column_time,2).toInt() + string_.mid(2,2).toInt();
}
/*
2343 -11 0.8 1259 # YV6BFE F6GUU R-08
2343 -19 0.3 718 # VE6WQ SQ2NIJ -14
2343 -7 0.3 815 # KK4DSD W7VP -16
2343 -13 0.1 3627 @ CT1FBK IK5YZT R+02
0605 Tx 1259 # CQ VK3ACF QF22
*/
QString DecodedText::report() const // returns a string of the SNR field with a leading + or - followed by two digits
{
int sr = snr();
if (sr<-50)
sr = -50;
else
if (sr > 49)
sr = 49;
QString rpt;
rpt.sprintf("%d",abs(sr));
if (sr > 9)
rpt = "+" + rpt;
else
if (sr >= 0)
rpt = "+0" + rpt;
else
if (sr >= -9)
rpt = "-0" + rpt;
else
rpt = "-" + rpt;
return rpt;
}
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);
@@ -1,6 +1,23 @@
module crc module crc
use, intrinsic :: iso_c_binding, only: c_int, c_loc, c_int8_t, c_bool, c_short use, intrinsic :: iso_c_binding, only: c_int, c_loc, c_int8_t, c_bool, c_short
interface 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") function crc12 (data, length) bind (C, name="crc12")
use, intrinsic :: iso_c_binding, only: c_short, c_ptr, c_int use, intrinsic :: iso_c_binding, only: c_short, c_ptr, c_int
implicit none implicit none
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

@@ -45,16 +45,32 @@ when double-clicking.
NOTE: To avoid QRM from competing callers, it is frequently desirable NOTE: To avoid QRM from competing callers, it is frequently desirable
to answer a CQ on a different frequency from that of the CQing to answer a CQ on a different frequency from that of the CQing
station. Choose a Tx frequency that appears to be not in use. The station. The same is true when you tail-end another QSO. Choose a Tx
same is true when you tail-end another QSO. frequency that appears to be not in use.
NOTE: The FT8 decoder can often copy several overlapping signals at NOTE: Keyboard shortcuts *Shift+F11* and *Shift+F12* provide an easy
nearly the same frequency. Keyboard shortcuts *Shift+F11* and way to move your Tx frequency down or up in 60 Hz steps.
*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 NOTE: Further helpful tips on FT8 operating procedures are available
{ft8_tips}. Thanks to ZL2IFB! {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 IMPORTANT: When finished with this Tutorial, don't forget to re-enter
your own callsign as *My Call* on the *Settings | General* tab. your own callsign as *My Call* on the *Settings | General* tab.
@@ -1,7 +1,7 @@
subroutine encode174(message,codeword) subroutine encode174(message,codeword)
! Encode an 101-bit message and return a 174-bit codeword. ! Encode an 87-bit message and return a 174-bit codeword.
! The generator matrix has dimensions (73,101). ! The generator matrix has dimensions (87,87).
! The code is a (174,101) regular ldpc code with column weight 3. ! The code is a (174,87) regular ldpc code with column weight 3.
! The code was generated using the PEG algorithm. ! The code was generated using the PEG algorithm.
! After creating the codeword, the columns are re-ordered according to ! After creating the codeword, the columns are re-ordered according to
! "colorder" to make the codeword compatible with the parity-check matrix ! "colorder" to make the codeword compatible with the parity-check matrix
@@ -1,99 +0,0 @@
#include "IARURegions.hpp"
#include <algorithm>
#include <QString>
#include <QVariant>
#include <QModelIndex>
#include "moc_IARURegions.cpp"
namespace
{
// human readable strings for each Region enumeration value
char const * const region_names[] =
{
"All",
"Region 1",
"Region 2",
"Region 3",
};
std::size_t constexpr region_names_size = sizeof (region_names) / sizeof (region_names[0]);
}
IARURegions::IARURegions (QObject * parent)
: QAbstractListModel {parent}
{
static_assert (region_names_size == REGIONS_END_SENTINAL_AND_COUNT,
"region_names array must match Region enumeration");
}
char const * IARURegions::name (Region r)
{
return region_names[static_cast<int> (r)];
}
auto IARURegions::value (QString const& s) -> Region
{
auto end = region_names + region_names_size;
auto p = std::find_if (region_names, end
, [&s] (char const * const name) {
return name == s;
});
return p != end ? static_cast<Region> (p - region_names) : ALL;
}
QVariant IARURegions::data (QModelIndex const& index, int role) const
{
QVariant item;
if (index.isValid ())
{
auto const& row = index.row ();
switch (role)
{
case Qt::ToolTipRole:
case Qt::AccessibleDescriptionRole:
item = tr ("IARU Region");
break;
case Qt::EditRole:
item = static_cast<Region> (row);
break;
case Qt::DisplayRole:
case Qt::AccessibleTextRole:
item = region_names[row];
break;
case Qt::TextAlignmentRole:
item = Qt::AlignHCenter + Qt::AlignVCenter;
break;
}
}
return item;
}
QVariant IARURegions::headerData (int section, Qt::Orientation orientation, int role) const
{
QVariant result;
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
{
result = tr ("IARU Region");
}
else
{
result = QAbstractListModel::headerData (section, orientation, role);
}
return result;
}
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (IARURegions, Region);
#endif
ENUM_QDATASTREAM_OPS_IMPL (IARURegions, Region);
ENUM_CONVERSION_OPS_IMPL (IARURegions, Region);
@@ -48,7 +48,7 @@ message (STATUS "Building ${CMAKE_PROJECT_NAME}-${wsjtx_VERSION}")
set (PROJECT_NAME "WSJT-X") set (PROJECT_NAME "WSJT-X")
set (PROJECT_VENDOR "Joe Taylor, K1JT") set (PROJECT_VENDOR "Joe Taylor, K1JT")
set (PROJECT_CONTACT "Joe Taylor <k1jt@arrl.net>") set (PROJECT_CONTACT "Joe Taylor <k1jt@arrl.net>")
set (PROJECT_COPYRIGHT "Copyright (C) 2001-2017 by Joe Taylor, K1JT") set (PROJECT_COPYRIGHT "Copyright (C) 2001-2018 by Joe Taylor, K1JT")
set (PROJECT_HOMEPAGE http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html) set (PROJECT_HOMEPAGE http://www.physics.princeton.edu/pulsar/K1JT/wsjtx.html)
set (PROJECT_MANUAL wsjtx-main) set (PROJECT_MANUAL wsjtx-main)
set (PROJECT_MANUAL_DIRECTORY_URL http://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/) set (PROJECT_MANUAL_DIRECTORY_URL http://www.physics.princeton.edu/pulsar/K1JT/wsjtx-doc/)
@@ -366,12 +366,12 @@ set (wsjt_FSRCS
lib/averms.f90 lib/averms.f90
lib/azdist.f90 lib/azdist.f90
lib/badmsg.f90 lib/badmsg.f90
lib/fsk4hf/baseline.f90 lib/ft8/baseline.f90
lib/bpdecode40.f90 lib/bpdecode40.f90
lib/bpdecode144.f90 lib/bpdecode144.f90
lib/fsk4hf/bpdecode120.f90 lib/fsk4hf/bpdecode120.f90
lib/fsk4hf/bpdecode168.f90 lib/fsk4hf/bpdecode168.f90
lib/fsk4hf/bpdecode174.f90 lib/ft8/bpdecode174.f90
lib/fsk4hf/bpdecode300.f90 lib/fsk4hf/bpdecode300.f90
lib/baddata.f90 lib/baddata.f90
lib/calibrate.f90 lib/calibrate.f90
@@ -379,11 +379,12 @@ set (wsjt_FSRCS
lib/ccf65.f90 lib/ccf65.f90
lib/fsk4hf/chkcrc10.f90 lib/fsk4hf/chkcrc10.f90
lib/fsk4hf/chkcrc12.f90 lib/fsk4hf/chkcrc12.f90
lib/fsk4hf/chkcrc12a.f90 lib/ft8/chkcrc12a.f90
lib/chkcall.f90 lib/chkcall.f90
lib/chkhist.f90 lib/chkhist.f90
lib/chkmsg.f90 lib/chkmsg.f90
lib/chkss2.f90 lib/chkss2.f90
lib/ft8/compress.f90
lib/coord.f90 lib/coord.f90
lib/fsk4hf/cpolyfit.f90 lib/fsk4hf/cpolyfit.f90
lib/fsk4hf/cpolyfitw.f90 lib/fsk4hf/cpolyfitw.f90
@@ -405,7 +406,7 @@ set (wsjt_FSRCS
lib/encode_msk144.f90 lib/encode_msk144.f90
lib/fsk4hf/encode120.f90 lib/fsk4hf/encode120.f90
lib/fsk4hf/encode168.f90 lib/fsk4hf/encode168.f90
lib/fsk4hf/encode174.f90 lib/ft8/encode174.f90
lib/fsk4hf/encode300.f90 lib/fsk4hf/encode300.f90
lib/entail.f90 lib/entail.f90
lib/ephem.f90 lib/ephem.f90
@@ -413,7 +414,7 @@ set (wsjt_FSRCS
lib/extract4.f90 lib/extract4.f90
lib/extractmessage144.f90 lib/extractmessage144.f90
lib/fsk4hf/extractmessage168.f90 lib/fsk4hf/extractmessage168.f90
lib/fsk4hf/extractmessage174.f90 lib/ft8/extractmessage174.f90
lib/fano232.f90 lib/fano232.f90
lib/fast9.f90 lib/fast9.f90
lib/fast_decode.f90 lib/fast_decode.f90
@@ -425,6 +426,7 @@ set (wsjt_FSRCS
lib/fil4.f90 lib/fil4.f90
lib/fil6521.f90 lib/fil6521.f90
lib/filbig.f90 lib/filbig.f90
lib/ft8/filt8.f90
lib/fitcal.f90 lib/fitcal.f90
lib/fix_contest_msg.f90 lib/fix_contest_msg.f90
lib/flat1.f90 lib/flat1.f90
@@ -436,19 +438,23 @@ set (wsjt_FSRCS
lib/fmtmsg.f90 lib/fmtmsg.f90
lib/foldspec9f.f90 lib/foldspec9f.f90
lib/four2a.f90 lib/four2a.f90
lib/ft8/foxfilt.f90
lib/ft8/foxgen.f90
lib/ft8/foxgen_wrap.f90
lib/fqso_first.f90 lib/fqso_first.f90
lib/freqcal.f90 lib/freqcal.f90
lib/fsk4hf/fsk4hf.f90 lib/fsk4hf/fsk4hf.f90
lib/fsk4hf/ft8apset.f90 lib/ft8/ft8apset.f90
lib/fsk4hf/ft8b.f90 lib/ft8/ft8b.f90
lib/fsk4hf/ft8_downsample.f90 lib/ft8/ft8code.f90
lib/fsk4hf/ft8sim.f90 lib/ft8/ft8_downsample.f90
lib/ft8/ft8sim.f90
lib/gen4.f90 lib/gen4.f90
lib/gen65.f90 lib/gen65.f90
lib/gen9.f90 lib/gen9.f90
lib/geniscat.f90 lib/geniscat.f90
lib/fsk4hf/genfsk4hf.f90 lib/fsk4hf/genfsk4hf.f90
lib/fsk4hf/genft8.f90 lib/ft8/genft8.f90
lib/genmsk144.f90 lib/genmsk144.f90
lib/genmsk40.f90 lib/genmsk40.f90
lib/fsk4hf/genmskhf.f90 lib/fsk4hf/genmskhf.f90
@@ -459,7 +465,7 @@ set (wsjt_FSRCS
lib/fsk4hf/getfc1w.f90 lib/fsk4hf/getfc1w.f90
lib/fsk4hf/getfc2w.f90 lib/fsk4hf/getfc2w.f90
lib/genqra64.f90 lib/genqra64.f90
lib/fsk4hf/genft8refsig.f90 lib/ft8/genft8refsig.f90
lib/genwspr.f90 lib/genwspr.f90
lib/geodist.f90 lib/geodist.f90
lib/getlags.f90 lib/getlags.f90
@@ -468,6 +474,7 @@ set (wsjt_FSRCS
lib/graycode65.f90 lib/graycode65.f90
lib/grayline.f90 lib/grayline.f90
lib/grid2deg.f90 lib/grid2deg.f90
lib/ft8/h1.f90
lib/hash.f90 lib/hash.f90
lib/hint65.f90 lib/hint65.f90
lib/hspec.f90 lib/hspec.f90
@@ -484,7 +491,7 @@ set (wsjt_FSRCS
lib/ldpcsim144.f90 lib/ldpcsim144.f90
lib/fsk4hf/ldpcsim120.f90 lib/fsk4hf/ldpcsim120.f90
lib/fsk4hf/ldpcsim168.f90 lib/fsk4hf/ldpcsim168.f90
lib/fsk4hf/ldpcsim174.f90 lib/ft8/ldpcsim174.f90
lib/fsk4hf/ldpcsim300.f90 lib/fsk4hf/ldpcsim300.f90
lib/ldpcsim40.f90 lib/ldpcsim40.f90
lib/libration.f90 lib/libration.f90
@@ -512,11 +519,12 @@ set (wsjt_FSRCS
lib/mskrtd.f90 lib/mskrtd.f90
lib/fsk4hf/msksoftsym.f90 lib/fsk4hf/msksoftsym.f90
lib/fsk4hf/msksoftsymw.f90 lib/fsk4hf/msksoftsymw.f90
lib/fsk4hf/osd174.f90 lib/ft8/osd174.f90
lib/fsk4hf/osd300.f90 lib/fsk4hf/osd300.f90
lib/pctile.f90 lib/pctile.f90
lib/peakdt9.f90 lib/peakdt9.f90
lib/peakup.f90 lib/peakup.f90
lib/plotsave.f90
lib/polyfit.f90 lib/polyfit.f90
lib/fsk4hf/polyfit4.f90 lib/fsk4hf/polyfit4.f90
lib/prog_args.f90 lib/prog_args.f90
@@ -543,7 +551,7 @@ set (wsjt_FSRCS
lib/spec9f.f90 lib/spec9f.f90
lib/stdmsg.f90 lib/stdmsg.f90
lib/subtract65.f90 lib/subtract65.f90
lib/fsk4hf/subtractft8.f90 lib/ft8/subtractft8.f90
lib/sun.f90 lib/sun.f90
lib/symspec.f90 lib/symspec.f90
lib/symspec2.f90 lib/symspec2.f90
@@ -551,8 +559,8 @@ set (wsjt_FSRCS
lib/sync4.f90 lib/sync4.f90
lib/sync64.f90 lib/sync64.f90
lib/sync65.f90 lib/sync65.f90
lib/fsk4hf/sync8.f90 lib/ft8/sync8.f90
lib/fsk4hf/sync8d.f90 lib/ft8/sync8d.f90
lib/sync9.f90 lib/sync9.f90
lib/sync9f.f90 lib/sync9f.f90
lib/sync9w.f90 lib/sync9w.f90
@@ -561,12 +569,12 @@ set (wsjt_FSRCS
lib/to_contest_msg.f90 lib/to_contest_msg.f90
lib/tweak1.f90 lib/tweak1.f90
lib/twkfreq.f90 lib/twkfreq.f90
lib/fsk4hf/twkfreq1.f90 lib/ft8/twkfreq1.f90
lib/twkfreq65.f90 lib/twkfreq65.f90
lib/unpackmsg144.f90 lib/unpackmsg144.f90
lib/update_recent_calls.f90 lib/update_recent_calls.f90
lib/update_hasharray.f90 lib/update_hasharray.f90
lib/fsk4hf/watterson.f90 lib/ft8/watterson.f90
lib/wav11.f90 lib/wav11.f90
lib/wav12.f90 lib/wav12.f90
lib/xcor.f90 lib/xcor.f90
@@ -582,6 +590,9 @@ set (wsjt_FSRCS
lib/zplot9.f90 lib/zplot9.f90
) )
# temporary workaround for a gfortran v7.3 ICE on Fedora 27 64-bit
set_source_files_properties (lib/slasubs.f PROPERTIES COMPILE_FLAGS -O2)
set (ka9q_CSRCS set (ka9q_CSRCS
lib/ftrsd/decode_rs.c lib/ftrsd/decode_rs.c
lib/ftrsd/encode_rs.c lib/ftrsd/encode_rs.c
@@ -602,7 +613,7 @@ set (qra_CSRCS
set (wsjt_CSRCS set (wsjt_CSRCS
${ka9q_CSRCS} ${ka9q_CSRCS}
lib/ftrsd/ftrsd2.c lib/ftrsd/ftrsdap.c
lib/sgran.c lib/sgran.c
lib/golay24_table.c lib/golay24_table.c
lib/gran.c lib/gran.c
@@ -675,6 +686,7 @@ set (message_aggregator_CXXSRCS
UDPExamples/DecodesModel.cpp UDPExamples/DecodesModel.cpp
UDPExamples/BeaconsModel.cpp UDPExamples/BeaconsModel.cpp
UDPExamples/ClientWidget.cpp UDPExamples/ClientWidget.cpp
MaidenheadLocatorValidator.cpp
) )
set (message_aggregator_STYLESHEETS set (message_aggregator_STYLESHEETS
@@ -943,7 +955,7 @@ if (Fortran_COMPILER_NAME MATCHES "gfortran.*")
set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -isysroot ${CMAKE_OSX_SYSROOT}") set (CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -isysroot ${CMAKE_OSX_SYSROOT}")
endif (CMAKE_OSX_SYSROOT) endif (CMAKE_OSX_SYSROOT)
set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -funroll-all-loops -fno-f2c ${General_FFLAGS}") set (CMAKE_Fortran_FLAGS_RELEASE "${CMAKE_Fortran_FLAGS_RELEASE} -fbounds-check -funroll-all-loops -fno-f2c ${General_FFLAGS}")
set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fbounds-check -fno-f2c ${General_FFLAGS}") set (CMAKE_Fortran_FLAGS_DEBUG "${CMAKE_Fortran_FLAGS_DEBUG} -fbounds-check -fno-f2c ${General_FFLAGS}")
elseif (Fortran_COMPILER_NAME MATCHES "ifort.*") elseif (Fortran_COMPILER_NAME MATCHES "ifort.*")
# ifort (untested) # ifort (untested)
@@ -1162,8 +1174,8 @@ target_link_libraries (jt65sim wsjt_fort wsjt_cxx)
add_executable (qra64sim lib/qra/qra64/qra64sim.f90 wsjtx.rc) add_executable (qra64sim lib/qra/qra64/qra64sim.f90 wsjtx.rc)
target_link_libraries (qra64sim wsjt_fort wsjt_cxx) target_link_libraries (qra64sim wsjt_fort wsjt_cxx)
add_executable (jt9sim lib/jt9sim.f90 wsjtx.rc) add_executable (jt49sim lib/jt49sim.f90 wsjtx.rc)
target_link_libraries (jt9sim wsjt_fort wsjt_cxx) target_link_libraries (jt49sim wsjt_fort wsjt_cxx)
add_executable (allsim lib/allsim.f90 wsjtx.rc) add_executable (allsim lib/allsim.f90 wsjtx.rc)
target_link_libraries (allsim wsjt_fort wsjt_cxx) target_link_libraries (allsim wsjt_fort wsjt_cxx)
@@ -1202,8 +1214,8 @@ target_link_libraries (ldpcsim40 wsjt_fort wsjt_cxx)
add_executable (ldpcsim120 lib/fsk4hf/ldpcsim120.f90 wsjtx.rc) add_executable (ldpcsim120 lib/fsk4hf/ldpcsim120.f90 wsjtx.rc)
target_link_libraries (ldpcsim120 wsjt_fort wsjt_cxx) target_link_libraries (ldpcsim120 wsjt_fort wsjt_cxx)
add_executable (ldpcsim300 lib/fsk4hf/ldpcsim300.f90 wsjtx.rc) add_executable (ldpcsim174 lib/ft8/ldpcsim174.f90 wsjtx.rc)
target_link_libraries (ldpcsim300 wsjt_fort wsjt_cxx) target_link_libraries (ldpcsim174 wsjt_fort wsjt_cxx)
add_executable (ldpcsim144 lib/ldpcsim144.f90 wsjtx.rc) add_executable (ldpcsim144 lib/ldpcsim144.f90 wsjtx.rc)
target_link_libraries (ldpcsim144 wsjt_fort wsjt_cxx) target_link_libraries (ldpcsim144 wsjt_fort wsjt_cxx)
@@ -1214,7 +1226,10 @@ target_link_libraries (ldpcsim168 wsjt_fort wsjt_cxx)
add_executable (fsk4hf lib/fsk4hf/fsk4hf.f90 wsjtx.rc) add_executable (fsk4hf lib/fsk4hf/fsk4hf.f90 wsjtx.rc)
target_link_libraries (fsk4hf wsjt_fort wsjt_cxx) target_link_libraries (fsk4hf wsjt_fort wsjt_cxx)
add_executable (ft8sim lib/fsk4hf/ft8sim.f90 wsjtx.rc) add_executable (ft8code lib/ft8/ft8code.f90 wsjtx.rc)
target_link_libraries (ft8code wsjt_fort wsjt_cxx)
add_executable (ft8sim lib/ft8/ft8sim.f90 wsjtx.rc)
target_link_libraries (ft8sim wsjt_fort wsjt_cxx) target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
add_executable (wsprlfsim lib/fsk4hf/wsprlfsim.f90 wsjtx.rc) add_executable (wsprlfsim lib/fsk4hf/wsprlfsim.f90 wsjtx.rc)
@@ -1296,12 +1311,14 @@ if (WSJT_CREATE_WINMAIN)
endif (WSJT_CREATE_WINMAIN) endif (WSJT_CREATE_WINMAIN)
set_target_properties (wsjtx PROPERTIES set_target_properties (wsjtx PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Darwin/Info.plist.in"
MACOSX_BUNDLE_INFO_STRING "${WSJTX_DESCRIPTION_SUMMARY}" MACOSX_BUNDLE_INFO_STRING "${WSJTX_DESCRIPTION_SUMMARY}"
MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}" MACOSX_BUNDLE_ICON_FILE "${WSJTX_ICON_FILE}"
MACOSX_BUNDLE_BUNDLE_VERSION ${wsjtx_VERSION} MACOSX_BUNDLE_BUNDLE_VERSION ${wsjtx_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING "v${wsjtx_VERSION}" MACOSX_BUNDLE_SHORT_VERSION_STRING "v${wsjtx_VERSION}"
MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${wsjtx_VERSION}" MACOSX_BUNDLE_LONG_VERSION_STRING "Version ${wsjtx_VERSION}"
MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}" MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}"
MACOSX_BUNDLE_BUNDLE_EXECUTABLE_NAME "${PROJECT_NAME}"
MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}" MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT}"
MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx" MACOSX_BUNDLE_GUI_IDENTIFIER "org.k1jt.wsjtx"
) )
@@ -1347,7 +1364,7 @@ set_target_properties (wsjtx_udp-static PROPERTIES
) )
target_compile_definitions (wsjtx_udp-static PUBLIC UDP_STATIC_DEFINE) target_compile_definitions (wsjtx_udp-static PUBLIC UDP_STATIC_DEFINE)
#qt5_use_modules (wsjtx_udp Network) #qt5_use_modules (wsjtx_udp Network)
qt5_use_modules (wsjtx_udp-static Network) qt5_use_modules (wsjtx_udp-static Network Gui)
generate_export_header (wsjtx_udp-static BASE_NAME udp) generate_export_header (wsjtx_udp-static BASE_NAME udp)
add_executable (udp_daemon UDPExamples/UDPDaemon.cpp UDPExamples/udp_daemon.rc ${WSJTX_ICON_FILE}) add_executable (udp_daemon UDPExamples/UDPDaemon.cpp UDPExamples/udp_daemon.rc ${WSJTX_ICON_FILE})
@@ -1409,7 +1426,7 @@ install (TARGETS udp_daemon message_aggregator
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
) )
install (TARGETS jt9 jt65code qra64code qra64sim jt9code jt4code install (TARGETS jt9 ft8code jt65code qra64code qra64sim jt9code jt4code
msk144code wsprd wspr_fsk8d fmtave fcal fmeasure msk144code wsprd wspr_fsk8d fmtave fcal fmeasure
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
@@ -1471,9 +1488,13 @@ add_custom_target (uninstall
"${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
# creates svnversion.h using cmake script # creates or updates ${PROJECT_BINARY_DIR}/scs_version.h using cmake script
add_custom_target (revisiontag add_custom_target (revisiontag
COMMAND ${CMAKE_COMMAND} -D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} -D OUTPUT_DIR=${PROJECT_BINARY_DIR} -P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/getsvn.cmake COMMAND ${CMAKE_COMMAND}
-D SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}
-D BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}
-D OUTPUT_DIR=${PROJECT_BINARY_DIR}
-P ${CMAKE_CURRENT_SOURCE_DIR}/CMake/getsvn.cmake
COMMENT "Generating Subversion revision information" COMMENT "Generating Subversion revision information"
VERBATIM VERBATIM
) )
@@ -1,148 +0,0 @@
/*
#Sov Mil Order of Malta: 15: 28: EU: 41.90: -12.43: -1.0: 1A:
#1A;
#Spratly Islands: 26: 50: AS: 9.88: -114.23: -8.0: 1S:
#1S,9M0,BV9S;
#Monaco: 14: 27: EU: 43.73: -7.40: -1.0: 3A:
#3A;
#Heard Island: 39: 68: AF: -53.08: -73.50: -5.0: VK0H:
#=VK0IR;
#Macquarie Island: 30: 60: OC: -54.60: -158.88: -10.0: VK0M:
#=VK0KEV;
#Cocos-Keeling: 29: 54: OC: -12.15: -96.82: -6.5: VK9C:
#AX9C,AX9Y,VH9C,VH9Y,VI9C,VI9Y,VJ9C,VJ9Y,VK9C,VK9Y,VL9C,VL9Y,VM9C,VM9Y,
#VN9C,VN9Y,VZ9C,VZ9Y,=VK9AA;
*/
#include "countrydat.h"
#include <QFile>
#include <QTextStream>
void CountryDat::init(const QString filename)
{
_filename = filename;
_data.clear();
}
QString CountryDat::_extractName(const QString line)
{
int s1 = line.indexOf(':');
if (s1>=0)
{
QString name = line.mid(0,s1);
return name;
}
return "";
}
void CountryDat::_removeBrackets(QString &line, const QString a, const QString b)
{
int s1 = line.indexOf(a);
while (s1 >= 0)
{
int s2 = line.indexOf(b);
line = line.mid(0,s1) + line.mid(s2+1,-1);
s1 = line.indexOf(a);
}
}
QStringList CountryDat::_extractPrefix(QString &line, bool &more)
{
line = line.remove(" \n");
line = line.replace("=","");
line = line.replace(" ","");
_removeBrackets(line,"(",")");
_removeBrackets(line,"[","]");
_removeBrackets(line,"<",">");
_removeBrackets(line,"~","~");
int s1 = line.indexOf(';');
more = true;
if (s1 >= 0)
{
line = line.mid(0,s1);
more = false;
}
QStringList r = line.split(',');
return r;
}
void CountryDat::load()
{
_data.clear();
_countryNames.clear(); //used by countriesWorked
QFile inputFile(_filename);
if (inputFile.open(QIODevice::ReadOnly))
{
QTextStream in(&inputFile);
while ( !in.atEnd() )
{
QString line1 = in.readLine();
if ( !in.atEnd() )
{
QString line2 = in.readLine();
QString name = _extractName(line1);
if (name.length()>0)
{
_countryNames << name;
bool more = true;
QStringList prefixs;
while (more)
{
QStringList p = _extractPrefix(line2,more);
prefixs += p;
if (more)
line2 = in.readLine();
}
QString p;
foreach(p,prefixs)
{
if (p.length() > 0)
_data.insert(p,name);
}
}
}
}
inputFile.close();
}
}
// return country name else ""
QString CountryDat::find(QString prefix)
{
prefix = prefix.toUpper ();
auto pf = prefix;
while (pf.size () >= 1)
{
if (_data.contains (pf))
{
QString country {_data.value (pf)};
//
// deal with special rules that cty.dat does not cope with
//
// KG4 2x1 and 2x3 calls that map to Gitmo are mainland US not Gitmo
if (prefix.startsWith ("KG4") && prefix.size () != 5)
{
country.replace ("Guantanamo Bay", "United States");
}
return country;
}
pf = pf.left (pf.size () - 1);
}
return QString {};
}
@@ -1,180 +0,0 @@
48 128
12 4
11 11 11 11 11 11 11 11 11 11 11 11 11 10 11 11 11 10 10 11 10 11 10 11 10 10 10 10 10 11 10 12 11 11 10 11 11 11 11 11 10 10 11 10 10 11 11 10
4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4
1 13 26 38 51 62 75 86 99 111 124 0
2 13 27 39 49 63 76 87 100 112 121 0
3 14 27 40 52 64 74 88 101 104 123 0
2 15 28 41 53 65 77 89 102 113 125 0
4 16 26 41 54 66 71 90 101 114 122 0
5 15 29 40 55 67 78 91 98 110 126 0
6 17 30 42 56 63 79 90 103 115 124 0
7 18 25 43 56 68 80 87 104 113 122 0
7 13 29 44 52 69 81 92 102 114 127 0
8 14 29 42 57 66 77 86 97 116 119 0
9 19 26 45 56 69 76 93 97 110 128 0
9 14 28 46 54 68 82 91 99 112 118 0
8 20 31 47 49 69 78 88 105 109 124 0
1 20 32 42 52 70 76 94 106 117 0 0
10 15 33 48 52 62 80 93 100 118 119 0
11 18 31 39 48 67 83 94 97 114 125 0
12 15 34 37 49 64 73 85 99 116 127 0
2 21 25 45 55 64 83 92 103 119 0 0
4 22 33 46 55 65 84 86 107 108 0 0
11 16 27 45 53 70 79 95 107 111 126 0
6 13 33 45 57 68 85 96 101 120 0 0
12 17 25 38 58 67 76 96 107 118 123 0
5 18 30 44 59 71 77 93 106 120 0 0
6 20 28 43 50 72 83 86 95 121 127 0
11 23 28 38 59 73 81 88 108 115 0 0
10 19 32 49 60 67 75 89 101 108 0 0
5 22 27 48 54 69 73 96 103 113 0 0
12 23 35 47 50 62 79 97 106 122 0 0
3 18 26 47 53 61 82 85 98 108 0 0
9 22 31 41 58 60 72 87 106 115 116 0
10 16 30 50 58 65 73 91 104 109 0 0
10 24 36 41 57 61 78 94 103 111 123 127
4 17 29 43 59 74 85 89 109 112 128 0
3 21 34 38 60 63 77 95 105 114 128 0
7 24 37 46 53 71 74 96 105 110 0 0
6 19 34 47 51 70 81 91 100 123 125 0
2 24 31 40 56 66 81 84 95 118 120 0
1 14 30 37 48 72 78 92 107 122 128 0
3 23 24 42 55 68 75 93 109 121 125 0
12 22 32 43 51 71 82 88 102 119 126 0
1 23 36 44 58 64 80 90 110 112 0 0
7 19 35 40 59 65 82 90 111 117 0 0
9 17 36 39 50 66 75 92 105 117 126 0
4 21 35 39 57 70 80 98 99 115 0 0
8 25 33 37 54 60 79 94 98 121 0 0
8 16 34 46 61 62 83 87 102 117 120 0
11 21 32 44 61 72 74 84 100 113 124 0
5 20 35 36 51 63 84 89 104 116 0 0
1 14 38 41
2 4 18 37
3 29 34 39
5 19 33 44
6 23 27 48
7 21 24 36
8 9 35 42
10 13 45 46
11 12 30 43
15 26 31 32
16 20 25 47
17 22 28 40
1 2 9 21
3 10 12 38
4 6 15 17
5 20 31 46
7 22 33 43
8 16 23 29
11 26 36 42
13 14 24 48
18 34 44 47
19 27 30 40
25 28 39 41
32 35 37 39
8 18 22 45
1 5 11 29
2 3 20 27
4 12 24 25
6 9 10 33
7 23 31 38
13 16 30 37
14 26 40 47
15 19 21 45
17 34 36 46
28 42 44 48
32 41 43 48
17 35 38 45
1 22 25 34
2 16 43 44
3 6 37 42
4 5 30 32
7 10 14 39
8 24 33 40
9 23 41 47
11 18 20 21
12 19 35 46
13 28 29 36
15 16 27 38
2 13 17 26
24 28 31 43
1 36 40 48
3 9 14 15
4 20 29 35
5 12 27 45
6 18 19 39
7 8 11 37
10 21 32 44
22 30 31 41
23 25 33 42
26 30 34 45
29 32 46 47
1 15 28 46
2 7 34 48
3 17 18 41
4 19 31 42
5 10 37 43
6 16 22 26
8 12 21 39
9 11 13 27
14 20 36 44
5 23 35 40
24 30 38 47
17 25 27 31
3 33 35 47
1 26 39 43
2 11 14 22
4 10 23 34
6 13 32 38
7 20 28 45
8 15 41 44
9 25 36 37
12 29 40 42
16 18 24 46
19 37 47 48
17 21 29 33
1 10 19 24
2 8 30 46
3 13 25 40
4 26 33 48
5 7 41 42
6 12 31 36
9 18 38 43
11 15 23 39
14 16 32 45
20 24 34 37
21 22 27 35
10 11 16 28
6 29 44 45
1 12 17 44
2 15 36 47
3 5 21 26
4 9 40 46
7 18 27 32
3 8 31 48
13 34 35 43
14 23 28 30
19 20 22 38
19 25 26 29
13 31 33 39
6 11 35 41
1 20 32 42
2 12 33 41
4 8 27 47
5 9 16 34
7 25 30 44
10 17 30 48
14 42 43 46
12 15 22 37
10 15 18 40
21 23 37 46
2 24 39 45
5 8 28 38
3 22 32 36
1 7 13 47
4 16 36 39
6 20 40 43
9 17 24 32
11 33 34 38
@@ -1,242 +0,0 @@
// This is a comment line, anything with // is ignored at process time.
= WSJT-X User Guide
Joseph H Taylor, Jr, K1JT
:revnumber: {VERSION}
// For web-pages, adding :badges: is ok, but is a security issue for
// package building .deb, .rpm, etc as it exposes the IP address and the images
// are non-free, so can't be included as part of the Debian package.
// :badges:
:docinfo1:
:imagesdir: {docdir}/images
:icons: font
:numbered:
:keywords: amateur radio weak signal communication K1JT WSJT JT65 JT9
:description: Software for Amateur Radio Weak-Signal Communication
:prog: WSJT-X
// use global link file
include::../../common/links.adoc[]
// These [[xxxx]] labels are HTML anchors, and can be used to
// navigate though the document easily: <<INTRO,See Introduction>> will
// place a hyper-link in your text to take you too the anchored section.
// All major sections or points of interest should have one.
// == is level (2), section 1.0, === would mean section 1.1, === would
// be section 1.1.1. This method is used throughout the document.
[[INTRO]]
== Introduction
include::introduction.adoc[]
[[NEW_FEATURES]]
include::new_features.adoc[]
[[SYSREQ]]
== System Requirements
include::system-requirements.adoc[]
[[INSTALL]]
== Installation
Installation packages for released versions on Windows, Linux, and OS
X are found on the {homepage}. Click on the _WSJT-X_ link at the
left margin and select the appropriate package for your operating
system.
[[INSTALL_WIN]]
=== Windows
include::install-windows.adoc[]
[[INSTALL_LINUX]]
=== Linux
include::install-linux.adoc[]
[[INSTALL_OSX]]
=== OS X and macOS
include::install-mac.adoc[]
////
[[SRC_CODE]]
=== Source Code
include::install-from-source.adoc[]
////
[[CONFIG]]
== Settings
Select *Settings* from the *File* menu or by typing *F2*. (On
Macintosh select *Preferences* from the _WSJT-X_ menu, or use the
keyboard shortcut *Cmd+,*). The following sections describe setup
options available on each of seven tabs selectable near the top of the
window.
[[GENERAL]]
=== General
include::settings-general.adoc[]
[[RADIO]]
=== Radio
include::settings-radio.adoc[]
[[AUDIO]]
=== Audio
include::settings-audio.adoc[]
[[TXMACROS]]
=== Tx Macros
include::settings-txmacros.adoc[]
[[REPORTING]]
=== Reporting
include::settings-reporting.adoc[]
[[BAND_SETTINGS]]
=== Frequencies
include::settings-frequencies.adoc[]
[[COLORS]]
=== Colors
include::settings-colors.adoc[]
[[ADVANCED]]
=== Advanced
include::settings-advanced.adoc[]
[[TRANSCEIVER]]
== Transceiver Setup
include::transceiver-setup.adoc[]
[[TUTORIAL]]
== Basic Operating Tutorial
<<TUT_MAIN,Sections 6.1>> through <<TUT_EX2,6.4>> introduce basic user
controls and program behavior of _WSJT-X_. We suggest that new users
should go through the full HF-oriented tutorial, preferably while at
your radio. Subsequent sections cover additional details on
<<MAKE_QSOS,Making QSOs>>, <<WSPR,WSPR mode>> and <<VHF_AND_UP,VHF+
Features>>.
[[TUT_MAIN]]
=== Main Window Settings
include::tutorial-main-window.adoc[]
[[TUT_WIDE_GRAPH]]
=== Wide Graph Settings
include::tutorial-wide-graph-settings.adoc[]
[[TUT_EX1]]
=== JT9
include::tutorial-example1.adoc[]
[[TUT_EX2]]
=== JT9+JT65
include::tutorial-example2.adoc[]
[[TUT_EX3]]
=== FT8
include::tutorial-example3.adoc[]
[[MAKE_QSOS]]
== Making QSOs
include::make-qso.adoc[]
[[VHF_AND_UP]]
== VHF+ Features
include::vhf-features.adoc[]
[[WSPR]]
== WSPR Mode
include::wspr.adoc[]
[[COMMAND_REF]]
== On-Screen Controls
[[MENUS]]
=== Menus
include::controls-functions-menus.adoc[]
[[CONTROLS_MAIN]]
=== Button Row
include::controls-functions-main-window.adoc[]
[[CONTROLS_LEFT]]
=== Left
include::controls-functions-left.adoc[]
[[CONTROLS_CENTER]]
=== Center
include::controls-functions-center.adoc[]
[[CONTROLS_MSGS]]
=== Tx Messages
include::controls-functions-messages.adoc[]
[[STATUS_BAR]]
=== Status Bar
include::controls-functions-status-bar.adoc[]
[[CONTROLS_WIDE]]
=== Wide Graph
include::controls-functions-wide-graph.adoc[]
[[LOGGING]]
== Logging
include::logging.adoc[]
[[ODDS_AND_ENDS]]
== Odds and Ends
include::odds_and_ends.adoc[]
[[COOP_PGMS]]
== Cooperating Programs
include::cooperating-programs.adoc[]
[[PLATFORM]]
== Platform Dependencies
include::platform-dependencies.adoc[]
[[FAQ]]
== Frequently Asked Questions
include::faq.adoc[]
[[PROTOCOLS]]
== Protocol Specifications
include::protocols.adoc[]
[[ASTRODATA]]
== Astronomical Data
include::astro_data.adoc[]
[[UTIL]]
== Utility Programs
include::utilities.adoc[]
////
[[TXRX]]
== Implementation Details
include::implementation.adoc[]
[[TROUBLE_SHOOTING]]
== Troubleshooting
To be added (?) ...
////
[[SUPPORT]]
== Support
include::support.adoc[]
[[ACK]]
== Acknowledgements
include::acknowledgements.adoc[]
[[LICENSE]]
== License
include::../../common/license.adoc[]
ifeval::["{backend}" != "html5"]
[index]
== Index
endif::[]
@@ -1,106 +0,0 @@
#include "Modes.hpp"
#include <algorithm>
#include <QString>
#include <QVariant>
#include <QModelIndex>
#include "moc_Modes.cpp"
namespace
{
// human readable strings for each Mode enumeration value
char const * const mode_names[] =
{
"",
"JT65",
"JT9",
"JT4",
"WSPR",
"Echo",
"ISCAT",
"MSK144",
"QRA64",
"FreqCal",
"FT8"
};
std::size_t constexpr mode_names_size = sizeof (mode_names) / sizeof (mode_names[0]);
}
Modes::Modes (QObject * parent)
: QAbstractListModel {parent}
{
static_assert (mode_names_size == MODES_END_SENTINAL_AND_COUNT,
"mode_names array must match Mode enumeration");
}
char const * Modes::name (Mode m)
{
return mode_names[static_cast<int> (m)];
}
auto Modes::value (QString const& s) -> Mode
{
auto end = mode_names + mode_names_size;
auto p = std::find_if (mode_names, end
, [&s] (char const * const name) {
return name == s;
});
return p != end ? static_cast<Mode> (p - mode_names) : NULL_MODE;
}
QVariant Modes::data (QModelIndex const& index, int role) const
{
QVariant item;
if (index.isValid ())
{
auto const& row = index.row ();
switch (role)
{
case Qt::ToolTipRole:
case Qt::AccessibleDescriptionRole:
item = tr ("Mode");
break;
case Qt::EditRole:
item = static_cast<Mode> (row);
break;
case Qt::DisplayRole:
case Qt::AccessibleTextRole:
item = mode_names[row];
break;
case Qt::TextAlignmentRole:
item = Qt::AlignHCenter + Qt::AlignVCenter;
break;
}
}
return item;
}
QVariant Modes::headerData (int section, Qt::Orientation orientation, int role) const
{
QVariant result;
if (Qt::DisplayRole == role && Qt::Horizontal == orientation)
{
result = tr ("Mode");
}
else
{
result = QAbstractListModel::headerData (section, orientation, role);
}
return result;
}
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_IMPL (Modes, Mode);
#endif
ENUM_QDATASTREAM_OPS_IMPL (Modes, Mode);
ENUM_CONVERSION_OPS_IMPL (Modes, Mode);
@@ -0,0 +1,52 @@
subroutine filt8(f0,nslots,width,wave)
parameter (NFFT=180000,NH=NFFT/2)
real wave(NFFT)
real x(NFFT)
real s1(0:NH)
real s2(0:NH)
complex cx(0:NH)
equivalence (x,cx)
x=wave
call four2a(x,NFFT,1,-1,0) !r2c
df=12000.0/NFFT
fa=f0 - 0.5*6.25
fb=f0 + 7.5*6.25 + (nslots-1)*60.0
ia2=nint(fa/df)
ib1=nint(fb/df)
ia1=nint(ia2-width/df)
ib2=nint(ib1+width/df)
pi=4.0*atan(1.0)
do i=ia1,ia2
fil=(1.0 + cos(pi*df*(i-ia2)/width))/2.0
cx(i)=fil*cx(i)
enddo
do i=ib1,ib2
fil=(1.0 + cos(pi*df*(i-ib1)/width))/2.0
cx(i)=fil*cx(i)
enddo
cx(0:ia1-1)=0.
cx(ib2+1:)=0.
call four2a(cx,nfft,1,1,-1) !c2r
wave=x/nfft
!###
if(nslots.ne.99) return
x=wave
call four2a(x,NFFT,1,-1,0) !r2c
do i=0,NH
s1(i)=real(cx(i))**2 + aimag(cx(i))**2
enddo
nadd=20
call smo(s1,NH+1,s2,nadd)
do i=0,NH
freq=i*df
write(29,3101) freq,db(s2(i)) - 72.0
3101 format(2f12.3)
enddo
!###
return
end subroutine filt8
@@ -1,318 +0,0 @@
program jt9
! Decoder for JT9. Can run stand-alone, reading data from *.wav files;
! or as the back end of wsjt-x, with data placed in a shared memory region.
use options
use prog_args
use, intrinsic :: iso_c_binding
use FFTW3
use timer_module, only: timer
use timer_impl, only: init_timer, fini_timer
use readwav
include 'jt9com.f90'
integer(C_INT) iret
type(wav_header) wav
real*4 s(NSMAX)
character c
character(len=500) optarg, infile
character wisfile*80
!### ndepth was defined as 60001. Why???
integer :: arglen,stat,offset,remain,mode=0,flow=200,fsplit=2700, &
fhigh=4000,nrxfreq=1500,ntrperiod=1,ndepth=1,nexp_decode=0
logical :: read_files = .true., tx9 = .false., display_help = .false.
type (option) :: long_options(25) = [ &
option ('help', .false., 'h', 'Display this help message', ''), &
option ('shmem',.true.,'s','Use shared memory for sample data','KEY'), &
option ('tr-period', .true., 'p', 'Tx/Rx period, default MINUTES=1', &
'MINUTES'), &
option ('executable-path', .true., 'e', &
'Location of subordinate executables (KVASD) default PATH="."', &
'PATH'), &
option ('data-path', .true., 'a', &
'Location of writeable data files, default PATH="."', 'PATH'), &
option ('temp-path', .true., 't', &
'Temporary files path, default PATH="."', 'PATH'), &
option ('lowest', .true., 'L', &
'Lowest frequency decoded (JT65), default HERTZ=200', 'HERTZ'), &
option ('highest', .true., 'H', &
'Highest frequency decoded, default HERTZ=4007', 'HERTZ'), &
option ('split', .true., 'S', &
'Lowest JT9 frequency decoded, default HERTZ=2700', 'HERTZ'), &
option ('rx-frequency', .true., 'f', &
'Receive frequency offset, default HERTZ=1500', 'HERTZ'), &
option ('patience', .true., 'w', &
'FFTW3 planing patience (0-4), default PATIENCE=1', 'PATIENCE'), &
option ('fft-threads', .true., 'm', &
'Number of threads to process large FFTs, default THREADS=1', &
'THREADS'), &
option ('jt65', .false., '6', 'JT65 mode', ''), &
option ('jt9', .false., '9', 'JT9 mode', ''), &
option ('ft8', .false., '8', 'FT8 mode', ''), &
option ('jt4', .false., '4', 'JT4 mode', ''), &
option ('qra64', .false., 'q', 'QRA64 mode', ''), &
option ('sub-mode', .true., 'b', 'Sub mode, default SUBMODE=A', 'A'), &
option ('depth', .true., 'd', &
'JT9 decoding depth (1-3), default DEPTH=1', 'DEPTH'), &
option ('tx-jt9', .false., 'T', 'Tx mode is JT9', ''), &
option ('my-call', .true., 'c', 'my callsign', 'CALL'), &
option ('my-grid', .true., 'G', 'my grid locator', 'GRID'), &
option ('his-call', .true., 'x', 'his callsign', 'CALL'), &
option ('his-grid', .true., 'g', 'his grid locator', 'GRID'), &
option ('experience-decode', .true., 'X', &
'experience based decoding flags (1..n), default FLAGS=0', &
'FLAGS') ]
type(dec_data), allocatable :: shared_data
character(len=12) :: mycall, hiscall
character(len=6) :: mygrid, hisgrid
common/patience/npatience,nthreads
common/decstats/ntry65a,ntry65b,n65a,n65b,num9,numfano
data npatience/1/,nthreads/1/
nsubmode = 0
do
call getopt('hs:e:a:b:r:m:p:d:f:w:t:9864qTL:S:H:c:G:x:g:X:', &
long_options,c,optarg,arglen,stat,offset,remain,.true.)
if (stat .ne. 0) then
exit
end if
select case (c)
case ('h')
display_help = .true.
case ('s')
read_files = .false.
shm_key = optarg(:arglen)
case ('e')
exe_dir = optarg(:arglen)
case ('a')
data_dir = optarg(:arglen)
case ('b')
nsubmode = ichar (optarg(:1)) - ichar ('A')
case ('t')
temp_dir = optarg(:arglen)
case ('m')
read (optarg(:arglen), *) nthreads
case ('p')
read (optarg(:arglen), *) ntrperiod
case ('d')
read (optarg(:arglen), *) ndepth
case ('f')
read (optarg(:arglen), *) nrxfreq
case ('L')
read (optarg(:arglen), *) flow
case ('S')
read (optarg(:arglen), *) fsplit
case ('H')
read (optarg(:arglen), *) fhigh
case ('q')
mode = 164
case ('4')
mode = 4
case ('6')
if (mode.lt.65) mode = mode + 65
case ('9')
if (mode.lt.9.or.mode.eq.65) mode = mode + 9
case ('8')
mode = 8
case ('T')
tx9 = .true.
case ('w')
read (optarg(:arglen), *) npatience
case ('c')
read (optarg(:arglen), *) mycall
case ('G')
read (optarg(:arglen), *) mygrid
case ('x')
read (optarg(:arglen), *) hiscall
case ('g')
read (optarg(:arglen), *) hisgrid
case ('X')
read (optarg(:arglen), *) nexp_decode
end select
end do
if (display_help .or. stat .lt. 0 &
.or. (.not. read_files .and. remain .gt. 0) &
.or. (read_files .and. remain .lt. 1)) then
print *, 'Usage: jt9 [OPTIONS] file1 [file2 ...]'
print *, ' Reads data from *.wav files.'
print *, ''
print *, ' jt9 -s <key> [-w patience] [-m threads] [-e path] [-a path] [-t path]'
print *, ' Gets data from shared memory region with key==<key>'
print *, ''
print *, 'OPTIONS:'
print *, ''
do i = 1, size (long_options)
call long_options(i) % print (6)
end do
go to 999
endif
iret=fftwf_init_threads() !Initialize FFTW threading
! Default to 1 thread, but use nthreads for the big ones
call fftwf_plan_with_nthreads(1)
! Import FFTW wisdom, if available
wisfile=trim(data_dir)//'/jt9_wisdom.dat'// C_NULL_CHAR
iret=fftwf_import_wisdom_from_filename(wisfile)
ntry65a=0
ntry65b=0
n65a=0
n65b=0
num9=0
numfano=0
if (.not. read_files) then
call jt9a() !We're running under control of WSJT-X
go to 999
endif
allocate(shared_data)
nflatten=0
do iarg = offset + 1, offset + remain
call get_command_argument (iarg, optarg, arglen)
infile = optarg(:arglen)
call wav%read (infile)
nfsample=wav%audio_format%sample_rate
i1=index(infile,'.wav')
if(i1.lt.1) i1=index(infile,'.WAV')
if(infile(i1-5:i1-5).eq.'_') then
read(infile(i1-4:i1-1),*,err=1) nutc
else
read(infile(i1-6:i1-3),*,err=1) nutc
endif
go to 2
1 nutc=0
2 nsps=0
if(ntrperiod.eq.1) then
nsps=6912
shared_data%params%nzhsym=181
else if(ntrperiod.eq.2) then
nsps=15360
shared_data%params%nzhsym=178
else if(ntrperiod.eq.5) then
nsps=40960
shared_data%params%nzhsym=172
else if(ntrperiod.eq.10) then
nsps=82944
shared_data%params%nzhsym=171
else if(ntrperiod.eq.30) then
nsps=252000
shared_data%params%nzhsym=167
endif
if(nsps.eq.0) stop 'Error: bad TRperiod'
kstep=nsps/2
k=0
nhsym0=-999
npts=(60*ntrperiod-6)*12000
if(iarg .eq. offset + 1) then
call init_timer (trim(data_dir)//'/timer.out')
call timer('jt9 ',0)
endif
shared_data%id2=0 !??? Why is this necessary ???
do iblk=1,npts/kstep
k=iblk*kstep
if(mode.eq.8 .and. k.gt.179712) exit
call timer('read_wav',0)
read(unit=wav%lun,end=3) shared_data%id2(k-kstep+1:k)
go to 4
3 call timer('read_wav',1)
print*,'EOF on input file ',infile
exit
4 call timer('read_wav',1)
nhsym=(k-2048)/kstep
if(nhsym.ge.1 .and. nhsym.ne.nhsym0) then
if(mode.eq.9 .or. mode.eq.74) then
! Compute rough symbol spectra for the JT9 decoder
ingain=0
call timer('symspec ',0)
nminw=1
call symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3, &
ihsym,npts8)
call timer('symspec ',1)
endif
nhsym0=nhsym
if(nhsym.ge.181) exit
endif
enddo
close(unit=wav%lun)
shared_data%params%nutc=nutc
shared_data%params%ndiskdat=.true.
shared_data%params%ntr=60
shared_data%params%nfqso=nrxfreq
shared_data%params%newdat=.true.
shared_data%params%npts8=74736
shared_data%params%nfa=flow
shared_data%params%nfsplit=fsplit
shared_data%params%nfb=fhigh
shared_data%params%ntol=20
shared_data%params%kin=64800
shared_data%params%nzhsym=181
shared_data%params%ndepth=ndepth
shared_data%params%dttol=3.
shared_data%params%minsync=0 !### TEST ONLY
! shared_data%params%nfqso=1500 !### TEST ONLY
! mycall="G3WDG " !### TEST ONLY
! hiscall="VK7MO " !### TEST ONLY
! hisgrid="QE37 " !### TEST ONLY
if(mode.eq.164 .and. nsubmode.lt.100) nsubmode=nsubmode+100
shared_data%params%naggressive=0
shared_data%params%n2pass=2
! shared_data%params%nranera=8 !### ntrials=10000
shared_data%params%nranera=6 !### ntrials=3000
shared_data%params%nrobust=.false.
shared_data%params%nexp_decode=nexp_decode
shared_data%params%mycall=mycall
shared_data%params%mygrid=mygrid
shared_data%params%hiscall=hiscall
shared_data%params%hisgrid=hisgrid
if (shared_data%params%mycall == '') shared_data%params%mycall='K1ABC'
if (shared_data%params%hiscall == '') shared_data%params%hiscall='W9XYZ'
if (shared_data%params%hisgrid == '') shared_data%params%hiscall='EN37'
if (tx9) then
shared_data%params%ntxmode=9
else
shared_data%params%ntxmode=65
end if
if (mode.eq.0) then
shared_data%params%nmode=65+9
else
shared_data%params%nmode=mode
end if
shared_data%params%nsubmode=nsubmode
shared_data%params%datetime="2013-Apr-16 15:13" !### Temp
if(mode.eq.9 .and. fsplit.ne.2700) shared_data%params%nfa=fsplit
call multimode_decoder(shared_data%ss,shared_data%id2,shared_data%params,nfsample)
enddo
call timer('jt9 ',1)
call timer('jt9 ',101)
999 continue
! Output decoder statistics
call fini_timer ()
! open (unit=12, file=trim(data_dir)//'/timer.out', status='unknown', position='append')
! write(12,1100) n65a,ntry65a,n65b,ntry65b,numfano,num9
!1100 format(58('-')/' JT65_1 Tries_1 JT65_2 Tries_2 JT9 Tries'/ &
! 58('-')/6i8)
! Save wisdom and free memory
iret=fftwf_export_wisdom_to_filename(wisfile)
call four2a(a,-1,1,1,1)
call filbig(a,-1,1,0.0,0,0,0,0,0) !used for FFT plans
call fftwf_cleanup_threads()
call fftwf_cleanup()
end program jt9
File diff suppressed because it is too large Load Diff
@@ -29,7 +29,7 @@ program wspr5d
complex c(0:NZ-1) !Complex waveform complex c(0:NZ-1) !Complex waveform
complex cd(0:NZ-1) !Complex waveform complex cd(0:NZ-1) !Complex waveform
complex ca(0:NZ-1) !Complex waveform complex ca(0:NZ-1) !Complex waveform
complex zz complex zz,zzsum
real*8 fMHz real*8 fMHz
real rxdata(ND),llr(ND) !Soft symbols real rxdata(ND),llr(ND) !Soft symbols
real pp(32) !Shaped pulse for OQPSK real pp(32) !Shaped pulse for OQPSK
@@ -44,6 +44,7 @@ program wspr5d
integer*1 idat(7) integer*1 idat(7)
integer*1 decoded(KK),apmask(ND),cw(ND) integer*1 decoded(KK),apmask(ND),cw(ND)
integer*1 hbits(412),bits(13) integer*1 hbits(412),bits(13)
logical reset
data ib13/1,1,1,1,1,-1,-1,1,1,-1,1,-1,1/ data ib13/1,1,1,1,1,-1,-1,1,1,-1,1,-1,1/
nargs=iargc() nargs=iargc()
@@ -131,41 +132,57 @@ program wspr5d
fb=150.0 fb=150.0
fs400=400.0 fs400=400.0
call getfc1(c400,fs400,fa,fb,fc1,xsnr) !First approx for freq call getfc1(c400,fs400,fa,fb,fc1,xsnr) !First approx for freq
!write(*,*) datetime,'initial guess ',fc1
npeaks=5 npeaks=5
call getfc2(c400,npeaks,fs400,fc1,fpks) !Refined freq call getfc2(c400,npeaks,fs400,fc1,fpks) !Refined freq
do idf=1,npeaks ! consider the top npeak peaks ! do idf=1,npeaks ! consider the top npeak peaks
fc2=fpks(idf) 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) call downsample(c400,fc1+fc2,cd)
s2=sum(cd*conjg(cd))/(16*412) s2=sum(cd*conjg(cd))/(16*412)
cd=cd/sqrt(s2) cd=cd/sqrt(s2)
do is=0,8 ! dt search range is narrow, to save time. do is=0,0 ! dt search range is zeroed for genie-aided sync
idt=is/2 idt=is/2
if( mod(is,2).eq. 1 ) idt=-(is+1)/2 if( mod(is,2).eq. 1 ) idt=-(is+1)/2
xdt=real(22+idt)/22.222 - 1.0 xdt=real(22+idt)/22.222 - 1.0
ca=cshift(cd,22+idt) ca=cshift(cd,22+idt)
do iseq=1,3 ! try sequence estimation lengths of 3, 6, and 9 bits. zzsum=0.0
k=1-2*iseq do iseq=3,4
nseq=iseq*3 if(iseq.eq.4) then
do i=1,408,iseq*4 k=1-2*3
k=k+iseq*2 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 j=(i+1)*16
call mskseqdet(nseq,ca(j),pp,id(k),softbits,1,phase) if(iseq.eq.4) then
hbits(i:i+iseq*4)=bits ! phase=-1.18596900
sbits(i:i+iseq*4)=bits ! 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+1)=softbits(1)
sbits(i+2)=softbits(2) sbits(i+2)=softbits(2)
if( id(k+1) .ne. 0 ) sbits(i+2)=id(k+1)*25 if( id(k+1) .ne. 0 ) sbits(i+2)=id(k+1)*25
sbits(i+3)=softbits(3) sbits(i+3)=softbits(3)
if( iseq .ge. 2 ) then if( iseq .ge. 2 ) then
sbits(i+5)=softbits(4) sbits(i+5)=softbits(4)
sbits(i+6)=softbits(5) sbits(i+6)=softbits(5)
if( id(k+3) .ne. 0 ) sbits(i+6)=id(k+3)*25 if( id(k+3) .ne. 0 ) sbits(i+6)=id(k+3)*25
sbits(i+7)=softbits(6) sbits(i+7)=softbits(6)
if( iseq .eq. 3 ) then if( iseq .ge. 3 ) then
sbits(i+9)=softbits(7) sbits(i+9)=softbits(7)
sbits(i+10)=softbits(8) sbits(i+10)=softbits(8)
if( id(k+5) .ne. 0 ) sbits(i+10)=id(k+5)*25 if( id(k+5) .ne. 0 ) sbits(i+10)=id(k+5)*25
@@ -188,18 +205,21 @@ program wspr5d
rx2av=sum(rxdata*rxdata)/ND rx2av=sum(rxdata*rxdata)/ND
rxsig=sqrt(rx2av-rxav*rxav) rxsig=sqrt(rx2av-rxav*rxav)
rxdata=rxdata/rxsig rxdata=rxdata/rxsig
! sigma=0.84
sigma=1.20 sigma=1.20
llr=2*rxdata/(sigma*sigma) llr=2*rxdata/(sigma*sigma)
apmask=0 apmask=0
max_iterations=40 max_iterations=40
ifer=0 ifer=0
nbadcrc=0
call bpdecode300(llr,apmask,max_iterations,decoded,niterations,cw) call bpdecode300(llr,apmask,max_iterations,decoded,niterations,cw)
! niterations will be equal to the Hamming distance between hard received word and the codeword ! niterations will be equal to the Hamming distance between hard received word and the codeword
if(niterations.lt.0) call osd300(llr,3,decoded,niterations,cw) nhardmin=0
if(niterations.ge.0) call chkcrc10(decoded,nbadcrc) if(niterations.lt.0) call osd300(llr,apmask,5,decoded,cw,nhardmin,dmin)
if(niterations.lt.0 .or. nbadcrc.ne.0) ifer=1 if(nhardmin.gt.0) niterations=nhardmin
nbadcrc=0
call chkcrc10(decoded,nbadcrc)
if(nbadcrc.ne.0) ifer=1
if( ifer.eq.0 ) then if( ifer.eq.0 ) then
write(cbits,1200) decoded(1:50) write(cbits,1200) decoded(1:50)
1200 format(50i1) 1200 format(50i1)
@@ -208,12 +228,14 @@ program wspr5d
idat(7)=ishft(idat(7),6) idat(7)=ishft(idat(7),6)
call wqdecode(idat,message,itype) call wqdecode(idat,message,itype)
nsnr=nint(xsnr) nsnr=nint(xsnr)
freq=fMHz + 1.d-6*(fc1+fc2) ! freq=fMHz + 1.d-6*(fc1+fc2)
freq=fc1+fc2
nfdot=0 nfdot=0
write(13,1210) datetime,0,nsnr,xdt,freq,message,nfdot write(13,1210) datetime,0,nsnr,xdt,freq,message,nfdot
1210 format(a11,2i4,f6.2,f12.7,2x,a22,i3) 1210 format(a11,2i4,f6.2,f12.7,2x,a22,i3)
write(*,1212) datetime(8:11),nsnr,xdt,freq,nfdot,message,'*',idf,nseq,is,niterations 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,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 goto 888
endif endif
enddo !iseq enddo !iseq
@@ -239,7 +261,7 @@ subroutine getmetric(ib,ps,xmet)
return return
end subroutine getmetric end subroutine getmetric
subroutine mskseqdet(ns,cdat,pp,bsync,softbits,ncoh,phase) subroutine mskseqdet(ns,cdat,pp,bsync,softbits,ncoh,zz)
! !
! Detect sequences of 3, 6, or 9 bits (ns). ! Detect sequences of 3, 6, or 9 bits (ns).
! Sync bits are assumed to be known. ! Sync bits are assumed to be known.
@@ -259,7 +281,7 @@ np=2**ns-1
idfmax=40 idfmax=40
if( ncoh .eq. 1 ) idfmax=0 if( ncoh .eq. 1 ) idfmax=0
do idf=0,idfmax do idf=0,idfmax
if( mod(idf,2).eq.1 ) deltaf=idf/2*0.02 if( mod(idf,2).eq.0 ) deltaf=idf/2*0.02
if( mod(idf,2).eq.1 ) deltaf=-(idf+1)/2*0.02 if( mod(idf,2).eq.1 ) deltaf=-(idf+1)/2*0.02
dphi=twopi*deltaf*dt dphi=twopi*deltaf*dt
cfac=cmplx(cos(dphi),sin(dphi)) cfac=cmplx(cos(dphi),sin(dphi))
@@ -325,7 +347,6 @@ do idf=0,idfmax
cbest=cideal cbest=cideal
fbest=deltaf fbest=deltaf
zz=sum(cdat*conjg(cbest))/1.e3 zz=sum(cdat*conjg(cbest))/1.e3
phase=atan2(imag(zz),real(zz))
endif endif
enddo enddo
if( ibflag .eq. 1 ) then ! new best found if( ibflag .eq. 1 ) then ! new best found
@@ -348,6 +369,29 @@ if( ns .ge. 6 ) then
endif endif
end subroutine mskseqdet 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) subroutine downsample(ci,f0,co)
parameter(NI=412*288,NO=NI/18) parameter(NI=412*288,NO=NI/18)
complex ci(0:NI-1),ct(0:NI-1) complex ci(0:NI-1),ct(0:NI-1)
@@ -359,7 +403,8 @@ subroutine downsample(ci,f0,co)
i0=nint(f0/df) i0=nint(f0/df)
co=0.0 co=0.0
co(0)=ct(i0) co(0)=ct(i0)
b=3.0 ! b=3.0 !optimized for sequence detection
b=6.0
do i=1,NO/2 do i=1,NO/2
arg=(i*df/b)**2 arg=(i*df/b)**2
filt=exp(-arg) filt=exp(-arg)
@@ -1,238 +0,0 @@
program ldpcsim174
! End to end test of the (174,75)/crc12 encoder and decoder.
use crc
use packjt
parameter(NRECENT=10)
character*12 recent_calls(NRECENT)
character*22 msg,msgsent,msgreceived
character*8 arg
integer*1, allocatable :: codeword(:), decoded(:), message(:)
integer*1, target:: i1Msg8BitBytes(11)
integer*1 msgbits(87)
integer*1 apmask(174), cw(174)
integer*2 checksum
integer*4 i4Msg6BitWords(13)
integer colorder(174)
integer nerrtot(174),nerrdec(174),nmpcbad(87)
logical checksumok,fsk,bpsk
real*8, allocatable :: rxdata(:)
real, allocatable :: llr(:)
data colorder/ &
0, 1, 2, 3, 30, 4, 5, 6, 7, 8, 9, 10, 11, 32, 12, 40, 13, 14, 15, 16,&
17, 18, 37, 45, 29, 19, 20, 21, 41, 22, 42, 31, 33, 34, 44, 35, 47, 51, 50, 43,&
36, 52, 63, 46, 25, 55, 27, 24, 23, 53, 39, 49, 59, 38, 48, 61, 60, 57, 28, 62,&
56, 58, 65, 66, 26, 70, 64, 69, 68, 67, 74, 71, 54, 76, 72, 75, 78, 77, 80, 79,&
73, 83, 84, 81, 82, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,&
100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,&
120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,&
140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,&
160,161,162,163,164,165,166,167,168,169,170,171,172,173/
do i=1,NRECENT
recent_calls(i)=' '
enddo
nerrtot=0
nerrdec=0
nmpcbad=0 ! Used to collect the number of errors in the message+crc part of the codeword
nargs=iargc()
if(nargs.ne.4) then
print*,'Usage: ldpcsim niter ndepth #trials s '
print*,'eg: ldpcsim 10 2 1000 0.84'
print*,'belief propagation iterations: niter, ordered-statistics depth: ndepth'
print*,'If s is negative, then value is ignored and sigma is calculated from SNR.'
return
endif
call getarg(1,arg)
read(arg,*) max_iterations
call getarg(2,arg)
read(arg,*) ndepth
call getarg(3,arg)
read(arg,*) ntrials
call getarg(4,arg)
read(arg,*) s
fsk=.false.
bpsk=.true.
! don't count crc bits as data bits
N=174
K=87
! scale Eb/No for a (174,87) code
rate=real(K)/real(N)
write(*,*) "rate: ",rate
write(*,*) "niter= ",max_iterations," s= ",s
allocate ( codeword(N), decoded(K), message(K) )
allocate ( rxdata(N), llr(N) )
msg="K1JT K9AN EN50"
! msg="G4WJS K9AN EN50"
call packmsg(msg,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes
call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent
write(*,*) "message sent ",msgsent
i4=0
ik=0
im=0
do i=1,12
nn=i4Msg6BitWords(i)
do j=1, 6
ik=ik+1
i4=i4+i4+iand(1,ishft(nn,j-6))
i4=iand(i4,255)
if(ik.eq.8) then
im=im+1
! if(i4.gt.127) i4=i4-256
i1Msg8BitBytes(im)=i4
ik=0
endif
enddo
enddo
i1Msg8BitBytes(10:11)=0
checksum = crc12 (c_loc (i1Msg8BitBytes), 11)
! For reference, the next 3 lines show how to check the CRC
i1Msg8BitBytes(10)=checksum/256
i1Msg8BitBytes(11)=iand (checksum,255)
checksumok = crc12_check(c_loc (i1Msg8BitBytes), 11)
if( checksumok ) write(*,*) 'Good checksum'
! K=87, For now:
! msgbits(1:72) JT message bits
! msgbits(73:75) 3 free message bits (set to 0)
! msgbits(76:87) CRC12
mbit=0
do i=1, 9
i1=i1Msg8BitBytes(i)
do ibit=1,8
mbit=mbit+1
msgbits(mbit)=iand(1,ishft(i1,ibit-8))
enddo
enddo
msgbits(73:75)=0 ! the three extra message bits go here
i1=i1Msg8BitBytes(10) ! First 4 bits of crc12 are LSB of this byte
do ibit=1,4
msgbits(75+ibit)=iand(1,ishft(i1,ibit-4))
enddo
i1=i1Msg8BitBytes(11) ! Now shift in last 8 bits of the CRC
do ibit=1,8
msgbits(79+ibit)=iand(1,ishft(i1,ibit-8))
enddo
write(*,*) 'message'
write(*,'(11(8i1,1x))') msgbits
call encode174(msgbits,codeword)
call init_random_seed()
! call sgran()
write(*,*) 'codeword'
write(*,'(22(8i1,1x))') codeword
write(*,*) "Es/N0 SNR2500 ngood nundetected nbadcrc sigma"
do idb = 20,-10,-1
!do idb = -3,-3,-1
db=idb/2.0-1.0
sigma=1/sqrt( 2*(10**(db/10.0)) )
ngood=0
nue=0
nbadcrc=0
nberr=0
do itrial=1, ntrials
! Create a realization of a noisy received word
do i=1,N
if( bpsk ) then
rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran()
elseif( fsk ) then
if( codeword(i) .eq. 1 ) then
r1=(1.0 + sigma*gran())**2 + (sigma*gran())**2
r2=(sigma*gran())**2 + (sigma*gran())**2
elseif( codeword(i) .eq. 0 ) then
r2=(1.0 + sigma*gran())**2 + (sigma*gran())**2
r1=(sigma*gran())**2 + (sigma*gran())**2
endif
! rxdata(i)=0.35*(sqrt(r1)-sqrt(r2))
! rxdata(i)=0.35*(exp(r1)-exp(r2))
rxdata(i)=0.12*(log(r1)-log(r2))
endif
enddo
nerr=0
do i=1,N
if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1
enddo
nerrtot(nerr)=nerrtot(nerr)+1
nberr=nberr+nerr
! Correct signal normalization is important for this decoder.
rxav=sum(rxdata)/N
rx2av=sum(rxdata*rxdata)/N
rxsig=sqrt(rx2av-rxav*rxav)
rxdata=rxdata/rxsig
! To match the metric to the channel, s should be set to the noise standard deviation.
! For now, set s to the value that optimizes decode probability near threshold.
! The s parameter can be tuned to trade a few tenth's dB of threshold for an order of
! magnitude in UER
if( s .lt. 0 ) then
ss=sigma
else
ss=s
endif
llr=2.0*rxdata/(ss*ss)
nap=0 ! number of AP bits
llr(colorder(174-87+1:174-87+nap)+1)=5*(2.0*msgbits(1:nap)-1.0)
apmask=0
apmask(colorder(174-87+1:174-87+nap)+1)=1
! max_iterations is max number of belief propagation iterations
call bpdecode174(llr, apmask, max_iterations, decoded, cw, nharderrors,niterations)
if( ndepth .ge. 0 .and. nharderrors .lt. 0 ) call osd174(llr, apmask, ndepth, decoded, cw, nharderrors, dmin)
! If the decoder finds a valid codeword, nharderrors will be .ge. 0.
if( nharderrors .ge. 0 ) then
call extractmessage174(decoded,msgreceived,ncrcflag,recent_calls,nrecent)
if( ncrcflag .ne. 1 ) then
nbadcrc=nbadcrc+1
endif
nueflag=0
nerrmpc=0
do i=1,K ! find number of errors in message+crc part of codeword
if( msgbits(i) .ne. decoded(i) ) then
nueflag=1
nerrmpc=nerrmpc+1
endif
enddo
nmpcbad(nerrmpc)=nmpcbad(nerrmpc)+1
if( ncrcflag .eq. 1 ) then
if( nueflag .eq. 0 ) then
ngood=ngood+1
nerrdec(nerr)=nerrdec(nerr)+1
else if( nueflag .eq. 1 ) then
nue=nue+1;
endif
endif
endif
enddo
baud=12000/1920
snr2500=db+10.0*log10((baud/2500.0))
pberr=real(nberr)/(real(ntrials*N))
write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2,8x,e10.3)") db,snr2500,ngood,nue,nbadcrc,ss,pberr
enddo
open(unit=23,file='nerrhisto.dat',status='unknown')
do i=1,174
write(23,'(i4,2x,i10,i10,f10.2)') i,nerrdec(i),nerrtot(i),real(nerrdec(i))/real(nerrtot(i)+1e-10)
enddo
close(23)
open(unit=25,file='nmpcbad.dat',status='unknown')
do i=1,87
write(25,'(i4,2x,i10)') i,nmpcbad(i)
enddo
close(25)
end program ldpcsim174
@@ -22,8 +22,8 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
m_settings (settings), m_settings (settings),
m_palettes_path {":/Palettes"}, m_palettes_path {":/Palettes"},
m_ntr0 {0}, m_ntr0 {0},
m_bHaveTransmitted {false}, m_n {0},
m_n {0} m_bHaveTransmitted {false}
{ {
ui->setupUi(this); ui->setupUi(this);
@@ -169,12 +169,16 @@ void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dat
int i=int(ui->widePlot->startFreq()/df3 + 0.5); int i=int(ui->widePlot->startFreq()/df3 + 0.5);
int jz=5000.0/(nbpp*df3); int jz=5000.0/(nbpp*df3);
if(jz>MAX_SCREENSIZE) jz=MAX_SCREENSIZE; if(jz>MAX_SCREENSIZE) jz=MAX_SCREENSIZE;
m_jz=jz;
for (int j=0; j<jz; j++) { for (int j=0; j<jz; j++) {
float ss=0; float ss=0.0;
float smax=0;
for (int k=0; k<nbpp; k++) { for (int k=0; k<nbpp; k++) {
if(splot[i]>ss) ss=splot[i]; float sp=splot[i++];
i++; ss += sp;
smax=qMax(smax,sp);
} }
// swide[j]=nbpp*smax;
swide[j]=nbpp*ss; swide[j]=nbpp*ss;
} }
@@ -184,9 +188,12 @@ void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dat
if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && ntr<m_ntr0)) { if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && ntr<m_ntr0)) {
float flagValue=1.0e30; float flagValue=1.0e30;
if(m_bHaveTransmitted) flagValue=2.0e30; if(m_bHaveTransmitted) flagValue=2.0e30;
for (int i=0; i<2048; i++) { for(int i=0; i<MAX_SCREENSIZE; i++) {
swide[i] = flagValue; swide[i] = flagValue;
} }
for(int i=0; i<NSMAX; i++) {
splot[i] = flagValue;
}
m_bHaveTransmitted=false; m_bHaveTransmitted=false;
} }
m_ntr0=ntr; m_ntr0=ntr;
@@ -322,7 +329,7 @@ void WideGraph::on_spec2dComboBox_currentIndexChanged(const QString &arg1)
if(arg1=="Reference") { if(arg1=="Reference") {
ui->widePlot->setReference(true); ui->widePlot->setReference(true);
} }
if(ui->widePlot->scaleOK ()) ui->widePlot->draw(swide,false,false); replot();
} }
void WideGraph::on_fSplitSpinBox_valueChanged(int n) //fSplit void WideGraph::on_fSplitSpinBox_valueChanged(int n) //fSplit
@@ -387,6 +394,7 @@ void WideGraph::on_paletteComboBox_activated (QString const& palette) //palet
{ {
m_waterfallPalette = palette; m_waterfallPalette = palette;
readPalette(); readPalette();
replot();
} }
void WideGraph::on_cbFlatten_toggled(bool b) //Flatten On/Off void WideGraph::on_cbFlatten_toggled(bool b) //Flatten On/Off
@@ -441,14 +449,21 @@ bool WideGraph::useRef() //Flatten
return m_bRef; return m_bRef;
} }
void WideGraph::replot()
{
if(ui->widePlot->scaleOK()) ui->widePlot->replot();
}
void WideGraph::on_gainSlider_valueChanged(int value) //Gain void WideGraph::on_gainSlider_valueChanged(int value) //Gain
{ {
ui->widePlot->setPlotGain(value); ui->widePlot->setPlotGain(value);
replot();
} }
void WideGraph::on_zeroSlider_valueChanged(int value) //Zero void WideGraph::on_zeroSlider_valueChanged(int value) //Zero
{ {
ui->widePlot->setPlotZero(value); ui->widePlot->setPlotZero(value);
replot();
} }
void WideGraph::on_gain2dSlider_valueChanged(int value) //Gain2 void WideGraph::on_gain2dSlider_valueChanged(int value) //Gain2
@@ -1,9 +1,12 @@
// Status=review // Status=review
The following buttons appear just under the decoded text windows on The following controls appear just under the decoded text windows on
the main screen: the main screen:
//.Main UI //.Main UI
image::main-ui-controls.png[align="left",width=650,alt="Main UI Controls"] image::main-ui-controls.png[align="center",width=650,alt="Main UI Controls"]
* When *CQ only* is checked, only messages from stations calling CQ will
be displayed in the left text panel.
* *Log QSO* raises a dialog window pre-filled with known information * *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 about a QSO you have nearly completed. You can edit or add to this
@@ -62,3 +65,5 @@ Toggle the button a second time or click *Halt Tx* to terminate the
*Tune* process. Note that activating *Tune* interrupts a receive *Tune* process. Note that activating *Tune* interrupts a receive
sequence and will prevent decoding during that sequence. sequence and will prevent decoding during that sequence.
* Uncheck the box *Menus* to make the top-of-window menus disappear,
leaving more vertical space for decoded messages.
@@ -66,8 +66,9 @@ program jt9
'FLAGS') ] 'FLAGS') ]
type(dec_data), allocatable :: shared_data type(dec_data), allocatable :: shared_data
character(len=12) :: mycall, hiscall character(len=20) :: datetime=''
character(len=6) :: mygrid, hisgrid character(len=12) :: mycall='K1ABC', hiscall='W9XYZ'
character(len=6) :: mygrid='', hisgrid='EN37'
common/patience/npatience,nthreads common/patience/npatience,nthreads
common/decstats/ntry65a,ntry65b,n65a,n65b,num9,numfano common/decstats/ntry65a,ntry65b,n65a,n65b,num9,numfano
data npatience/1/,nthreads/1/ data npatience/1/,nthreads/1/
@@ -260,7 +261,8 @@ program jt9
shared_data%params%kin=64800 shared_data%params%kin=64800
shared_data%params%nzhsym=181 shared_data%params%nzhsym=181
shared_data%params%ndepth=ndepth shared_data%params%ndepth=ndepth
shared_data%params%lapon=.true. shared_data%params%lft8apon=.true.
shared_data%params%ljt65apon=.true.
shared_data%params%napwid=75 shared_data%params%napwid=75
shared_data%params%dttol=3. shared_data%params%dttol=3.
@@ -277,13 +279,10 @@ program jt9
shared_data%params%nranera=6 !### ntrials=3000 shared_data%params%nranera=6 !### ntrials=3000
shared_data%params%nrobust=.false. shared_data%params%nrobust=.false.
shared_data%params%nexp_decode=nexp_decode shared_data%params%nexp_decode=nexp_decode
shared_data%params%mycall=mycall shared_data%params%mycall=transfer(mycall,shared_data%params%mycall)
shared_data%params%mygrid=mygrid shared_data%params%mygrid=transfer(mygrid,shared_data%params%mygrid)
shared_data%params%hiscall=hiscall shared_data%params%hiscall=transfer(hiscall,shared_data%params%hiscall)
shared_data%params%hisgrid=hisgrid shared_data%params%hisgrid=transfer(hisgrid,shared_data%params%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 if (tx9) then
shared_data%params%ntxmode=9 shared_data%params%ntxmode=9
else else
@@ -295,7 +294,8 @@ program jt9
shared_data%params%nmode=mode shared_data%params%nmode=mode
end if end if
shared_data%params%nsubmode=nsubmode shared_data%params%nsubmode=nsubmode
shared_data%params%datetime="2013-Apr-16 15:13" !### Temp datetime="2013-Apr-16 15:13" !### Temp
shared_data%params%datetime=transfer(datetime,shared_data%params%datetime)
if(mode.eq.9 .and. fsplit.ne.2700) shared_data%params%nfa=fsplit 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) call multimode_decoder(shared_data%ss,shared_data%id2,shared_data%params,nfsample)
enddo enddo
@@ -1,31 +0,0 @@
#ifndef PHASE_EQUALIZATION_DIALOG_HPP__
#define PHASE_EQUALIZATION_DIALOG_HPP__
#include <QObject>
#include "pimpl_h.hpp"
class QWidget;
class QSettings;
class QDir;
class PhaseEqualizationDialog
: public QObject
{
Q_OBJECT
public:
explicit PhaseEqualizationDialog (QSettings *
, QDir const& data_directory
, QVector<double> const& coefficients
, QWidget * = nullptr);
Q_SLOT void show ();
Q_SIGNAL void phase_equalization_changed (QVector<double> const&);
private:
class impl;
pimpl<impl> m_;
};
#endif
@@ -1,56 +0,0 @@
#ifndef LIVE_FREQUENCY_VALIDATOR_HPP__
#define LIVE_FREQUENCY_VALIDATOR_HPP__
#include <QObject>
#include <QRegExpValidator>
#include "Radio.hpp"
class Bands;
class FrequencyList;
class QComboBox;
class QWidget;
//
// Class LiveFrequencyValidator
//
// QLineEdit validator that controls input to an editable
// QComboBox where the user can enter a valid band or a valid
// frequency in megahetz.
//
// Collabrations
//
// Implements the QRegExpValidator interface. Validates input
// from the supplied QComboBox as either a valid frequency in
// megahertz or a valid band as defined by the supplied column of
// the supplied QAbstractItemModel.
//
class LiveFrequencyValidator final
: public QRegExpValidator
{
Q_OBJECT;
public:
using Frequency = Radio::Frequency;
LiveFrequencyValidator (QComboBox * combo_box // associated combo box
, Bands const * bands // bands model
, FrequencyList const * frequencies // working
// frequencies
// model
, Frequency const * nominal_frequency
, QWidget * parent = nullptr);
State validate (QString& input, int& pos) const override;
void fixup (QString& input) const override;
Q_SIGNAL void valid (Frequency) const;
private:
Bands const * bands_;
FrequencyList const * frequencies_;
Frequency const * nominal_frequency_;
QComboBox * combo_box_;
};
#endif
@@ -1,200 +0,0 @@
/************************************************************************/
/* */
/* Free software: Progressive edge-growth (PEG) algorithm */
/* Created by Xiaoyu Hu */
/* Evangelos Eletheriou */
/* Dieter Arnold */
/* IBM Research, Zurich Research Lab., Switzerland */
/* */
/* The C++ sources files have been compiled using xlC compiler */
/* at IBM RS/6000 running AIX. For other compilers and platforms,*/
/* minor changes might be needed. */
/* */
/* Bug reporting to: xhu@zurich.ibm.com */
/**********************************************************************/
////
// Modified by F. P. Beekhof; 2008 / 08 / 19
////
#include <cstdlib>
#include <cstring>
#include <string>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <vector>
#include "BigGirth.h"
#include "Random.h"
#include "CyclesOfGraph.h"
const double EPS = 1e-6;
using namespace std;
void usage()
{
cout<<"*******************************************************************************************"<<endl;
cout<<" Usage Reminder: MainPEG -numM M -numN N -codeName CodeName -degFileName DegFileName " <<endl;
cout<<" option: -sglConcent SglConcent " <<endl;
cout<<" sglConcent==0 ----- strictly concentrated parity-check " <<endl;
cout<<" degree distribution (including regular graphs)" <<endl;
cout<<" sglConcent==1 ----- Best-effort concentrated (DEFAULT) " <<endl;
cout<<" option: -tgtGirth TgtGirth " <<endl;
cout<<" TgtGirth==4, 6 ...; if very large, then greedy PEG (DEFAULT) " <<endl;
cout<<" IF sglConcent==0, TgtGirth is recommended to be set relatively small" <<endl;
cout<<" option: -q " <<endl;
cout<<" Quiet mode. Produces less output to the screen. " <<endl;
cout<<" option: -outputMode <0,1,2> " <<endl;
cout<<" Specifies output format. " <<endl;
cout<<" '0': H in compressed format (default) " <<endl;
cout<<" '1': H in un-compressed format " <<endl;
cout<<" '2': G and H in compressed format " <<endl;
cout<<" " <<endl;
cout<<" Remarks: File CodeName stores the generated PEG Tanner graph. The first line contains"<<endl;
cout<<" the block length, N. The second line defines the number of parity-checks, M."<<endl;
cout<<" The third line defines the number of columns of the compressed parity-check "<<endl;
cout<<" matrix. The following M lines are then the compressed parity-check matrix. "<<endl;
cout<<" Each of the M rows contains the indices (1 ... N) of 1's in the compressed "<<endl;
cout<<" row of parity-check matrix. If not all column entries are used, the column "<<endl;
cout<<" is filled up with 0's. "<<endl;
cout<<" "<<endl;
cout<<" If both G and H are in the output, (outMode 2), the first line contains"<<endl;
cout<<" N, the 2nd line K, the number of message bits, the 3rd line M, the 4th line"<<endl;
cout<<" contains the number of rows of the compressed generator matrix; the 5th"<<endl;
cout<<" defines the number of columns of the compressed parity-check matrix. The"<<endl;
cout<<" format of G is almost like that of H, but vertical -- i.e. the padding"<<endl;
cout<<" zeroes are on the bottom. "<<endl;
cout<<" "<<endl;
cout<<" File DegFileName is the input file to specify the degree distribution (node "<<endl;
cout<<" perspective). The first line contains the number of various degrees. The second"<<endl;
cout<<" defines the row vector of degree sequence in the increasing order. The vector"<<endl;
cout<<" of fractions of the corresponding degree is defined in the last line. "<<endl;
cout<<" "<<endl;
cout<<" A log file called 'leftHandGirth.dat' will also be generated and stored in the"<<endl;
cout<<" current directory, which gives the girth of the left-hand subgraph of j, where"<<endl;
cout<<" 1<=j<=N. The left-hand subgraph of j is defined as all the edges emanating from"<<endl;
cout<<" bit nodes {1 ... j} and their associated nodes. "<<endl;
cout<<" "<<endl;
cout<<" The last point is, when strictly concentrated parity-check degree distribution"<<endl;
cout<<" is invoked, i.e. sglConcent==0, the girth might be weaken to some extent as "<<endl;
cout<<" compared to the generic PEG algorithm. "<<endl;
cout<<"**********************************************************************************************"<<endl;
exit(-1);
}
int main(int argc, char * argv[]){
int sglConcent=1; // default to non-strictly concentrated parity-check distribution
int targetGirth=100000; // default to greedy PEG version
std::string codeName, degFileName;
int M = -1, N = -1;
bool verbose = true;
const int OUTPUT_MODE_H_COMPRESSED = 0;
const int OUTPUT_MODE_H = 1;
const int OUTPUT_MODE_G_H_COMPRESSED = 2;
int output_mode = OUTPUT_MODE_H_COMPRESSED; // default
if (argc<9) {
usage();
}else {
for(int i=1;i<argc;++i){
if (strcmp(argv[i], "-numM")==0) {
if (++i >= argc) usage();
M=atoi(argv[i]);
} else if(strcmp(argv[i], "-numN")==0) {
if (++i >= argc) usage();
N=atoi(argv[i]);
} else if(strcmp(argv[i], "-codeName")==0) {
if (++i >= argc) usage();
codeName = argv[i];
} else if(strcmp(argv[i], "-degFileName")==0) {
if (++i >= argc) usage();
degFileName = argv[i];
} else if(strcmp(argv[i], "-sglConcent")==0) {
if (++i >= argc) usage();
sglConcent=atoi(argv[i]);
} else if(strcmp(argv[i], "-tgtGirth")==0) {
if (++i >= argc) usage();
targetGirth=atoi(argv[i]);
} else if(strcmp(argv[i], "-outputMode")==0) {
if (++i >= argc) usage();
output_mode=atoi(argv[i]);
} else if(strcmp(argv[i], "-q")==0) {
verbose=false;
} else{
usage();
}
}
if (M == -1 || N == -1) {
cout<<"Error: M or N not specified!"<<endl;
exit(-1);
}
if (M>N) {
cout<<"Error: M must be smaller than N!"<<endl;
exit(-1);
}
}
std::vector<int> degSeq(N);
ifstream infn(degFileName.c_str());
if (!infn) {cout << "\nCannot open file " << degFileName << endl; exit(-1); }
int m;
infn >>m;
std::vector<int> deg(m);
std::vector<double> degFrac(m);
for(int i=0;i<m;i++) infn>>deg[i];
for(int i=0;i<m;i++) infn>>degFrac[i];
infn.close();
double dtmp=0.0;
for(int i=0;i<m;i++) dtmp+=degFrac[i];
cout.setf(ios::fixed, ios::floatfield);
if(abs(dtmp-1.0)>EPS) {
cout.setf(ios::fixed, ios::floatfield);
cout <<"\n Invalid degree distribution (node perspective): sum != 1.0 but "<<setprecision(10)<<dtmp<<endl; exit(-1);
}
for(int i=1;i<m;++i) degFrac[i]+=degFrac[i-1];
for(int i=0;i<N;++i) {
dtmp=double(i)/double(N);
int j;
for(j=m-1;j>=0;--j) {
if(dtmp>degFrac[j]) break;
}
if(dtmp<degFrac[0]) degSeq[i]=deg[0];
else degSeq[i]=deg[j+1];
}
BigGirth bigGirth(M, N, &degSeq[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,186 +0,0 @@
subroutine osd174(llr,apmask,norder,decoded,cw,nhardmin,dmin)
!
! An ordered-statistics decoder for the (174,87) code.
!
include "ldpc_174_87_params.f90"
integer*1 apmask(N),apmaskr(N)
integer*1 gen(K,N)
integer*1 genmrb(K,N),g2(N,K)
integer*1 temp(K),m0(K),me(K),mi(K)
integer indices(N),nxor(N)
integer*1 cw(N),ce(N),c0(N),hdec(N)
integer*1 decoded(K)
integer indx(N)
real llr(N),rx(N),absrx(N)
logical first
data first/.true./
save first,gen
if( first ) then ! fill the generator matrix
gen=0
do i=1,M
do j=1,22
read(g(i)(j:j),"(Z1)") istr
do jj=1, 4
irow=(j-1)*4+jj
if( btest(istr,4-jj) ) gen(irow,i)=1
enddo
enddo
enddo
do irow=1,K
gen(irow,M+irow)=1
enddo
first=.false.
endif
! re-order received vector to place systematic msg bits at the end
rx=llr(colorder+1)
apmaskr=apmask(colorder+1)
! hard decode the received word
hdec=0
where(rx .ge. 0) hdec=1
! use magnitude of received symbols as a measure of reliability.
absrx=abs(rx)
call indexx(absrx,N,indx)
! re-order the columns of the generator matrix in order of decreasing reliability.
do i=1,N
genmrb(1:K,i)=gen(1:K,indx(N+1-i))
indices(i)=indx(N+1-i)
enddo
! do gaussian elimination to create a generator matrix with the most reliable
! received bits in positions 1:K in order of decreasing reliability (more or less).
! reliability will not be strictly decreasing because column re-ordering is needed
! to put the generator matrix in systematic form. the "indices" array tracks
! column permutations caused by reliability sorting and gaussian elimination.
do id=1,K ! diagonal element indices
do icol=id,K+20 ! The 20 is ad hoc - beware
iflag=0
if( genmrb(id,icol) .eq. 1 ) then
iflag=1
if( icol .ne. id ) then ! reorder column
temp(1:K)=genmrb(1:K,id)
genmrb(1:K,id)=genmrb(1:K,icol)
genmrb(1:K,icol)=temp(1:K)
itmp=indices(id)
indices(id)=indices(icol)
indices(icol)=itmp
endif
do ii=1,K
if( ii .ne. id .and. genmrb(ii,id) .eq. 1 ) then
genmrb(ii,1:N)=ieor(genmrb(ii,1:N),genmrb(id,1:N))
endif
enddo
exit
endif
enddo
enddo
g2=transpose(genmrb)
! The hard decisions for the K MRB bits define the order 0 message, m0.
! Encode m0 using the modified generator matrix to find the "order 0" codeword.
! Flip various combinations of bits in m0 and re-encode to generate a list of
! codewords. Test all such codewords against the received word to decide which
! codeword is most likely to be correct.
hdec=hdec(indices) ! hard decisions from received symbols
m0=hdec(1:K) ! zero'th order message
absrx=absrx(indices)
rx=rx(indices)
apmaskr=apmaskr(indices)
s1=sum(absrx(1:K))
s2=sum(absrx(K+1:N))
xlam=7.0 ! larger values reject more error patterns
rho=s1/(s1+xlam*s2)
call mrbencode(m0,c0,g2,N,K)
nxor=ieor(c0,hdec)
nhardmin=sum(nxor)
dmin=sum(nxor*absrx)
thresh=rho*dmin
cw=c0
nt=0
nrejected=0
do iorder=1,norder
mi(1:K-iorder)=0
mi(K-iorder+1:K)=1
iflag=0
do while(iflag .ge. 0 )
if(all(iand(apmaskr(1:K),mi).eq.0)) then ! reject patterns with ap bits
dpat=sum(mi*absrx(1:K))
nt=nt+1
if( dpat .lt. thresh ) then ! reject unlikely error patterns
me=ieor(m0,mi)
call mrbencode(me,ce,g2,N,K)
nxor=ieor(ce,hdec)
dd=sum(nxor*absrx)
if( dd .lt. dmin ) then
dmin=dd
cw=ce
nhardmin=sum(nxor)
thresh=rho*dmin
endif
else
nrejected=nrejected+1
endif
endif
! get the next test error pattern, iflag will go negative
! when the last pattern with weight iorder has been generated
call nextpat(mi,k,iorder,iflag)
enddo
enddo
!write(*,*) 'nhardmin ',nhardmin
!write(*,*) 'total patterns ',nt,' number rejected ',nrejected
! re-order the codeword to place message bits at the end
cw(indices)=cw
hdec(indices)=hdec
decoded=cw(M+1:N)
cw(colorder+1)=cw ! put the codeword back into received-word order
return
end subroutine osd174
subroutine mrbencode(me,codeword,g2,N,K)
integer*1 me(K),codeword(N),g2(N,K)
! fast encoding for low-weight test patterns
codeword=0
do i=1,K
if( me(i) .eq. 1 ) then
codeword=ieor(codeword,g2(1:N,i))
endif
enddo
return
end subroutine mrbencode
subroutine nextpat(mi,k,iorder,iflag)
integer*1 mi(k),ms(k)
! generate the next test error pattern
ind=-1
do i=1,k-1
if( mi(i).eq.0 .and. mi(i+1).eq.1) ind=i
enddo
if( ind .lt. 0 ) then ! no more patterns of this order
iflag=ind
return
endif
ms=0
ms(1:ind-1)=mi(1:ind-1)
ms(ind)=1
ms(ind+1)=0
if( ind+1 .lt. k ) then
nz=iorder-sum(ms)
ms(k-nz+1:k)=1
endif
mi=ms
iflag=ind
return
end subroutine nextpat
@@ -43,9 +43,7 @@ subroutine symspec65(dd,npts,nqsym,savg)
first=.false. first=.false.
endif endif
! do j=1,nhsym
do j=1,nqsym do j=1,nqsym
! i0=(j-1)*hstep
i0=(j-1)*qstep i0=(j-1)*qstep
x=fac1*w*dd(i0+1:i0+NFFT) x=fac1*w*dd(i0+1:i0+NFFT)
call four2a(c,NFFT,1,-1,0) !r2c forward FFT call four2a(c,NFFT,1,-1,0) !r2c forward FFT
@@ -1,41 +0,0 @@
// -*- Mode: C++ -*-
#ifndef DISPLAYTEXT_H
#define DISPLAYTEXT_H
#include <QTextEdit>
#include "logbook/logbook.h"
#include "decodedtext.h"
class DisplayText : public QTextEdit
{
Q_OBJECT
public:
explicit DisplayText(QWidget *parent = 0);
void setContentFont (QFont const&);
void insertLineSpacer(QString const&);
void displayDecodedText(DecodedText decodedText, QString myCall, bool displayDXCCEntity,
LogBook logBook, QColor color_CQ, QColor color_MyCall,
QColor color_DXCC, QColor color_NewCall);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
QColor color_TxMsg, bool bFastMode);
void displayQSY(QString text);
signals:
void selectCallsign(bool shift, bool ctrl);
public slots:
void appendText(QString const& text, QString const& bg = "white");
protected:
void mouseDoubleClickEvent(QMouseEvent *e);
private:
void _appendDXCCWorkedB4(/*mod*/DecodedText& t1, QString &bg, LogBook logBook,
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
QTextCharFormat m_charFormat;
};
#endif // DISPLAYTEXT_H
@@ -1,148 +0,0 @@
#include "logqso.h"
#include <QString>
#include <QSettings>
#include <QStandardPaths>
#include <QDir>
#include <QDebug>
#include "logbook/adif.h"
#include "MessageBox.hpp"
#include "ui_logqso.h"
#include "moc_logqso.cpp"
LogQSO::LogQSO(QString const& programTitle, QSettings * settings, QWidget *parent)
: QDialog(parent)
, ui(new Ui::LogQSO)
, m_settings (settings)
{
ui->setupUi(this);
setWindowTitle(programTitle + " - Log QSO");
loadSettings ();
}
LogQSO::~LogQSO ()
{
}
void LogQSO::loadSettings ()
{
m_settings->beginGroup ("LogQSO");
restoreGeometry (m_settings->value ("geometry", saveGeometry ()).toByteArray ());
ui->cbTxPower->setChecked (m_settings->value ("SaveTxPower", false).toBool ());
ui->cbComments->setChecked (m_settings->value ("SaveComments", false).toBool ());
m_txPower = m_settings->value ("TxPower", "").toString ();
m_comments = m_settings->value ("LogComments", "").toString();
m_settings->endGroup ();
}
void LogQSO::storeSettings () const
{
m_settings->beginGroup ("LogQSO");
m_settings->setValue ("geometry", saveGeometry ());
m_settings->setValue ("SaveTxPower", ui->cbTxPower->isChecked ());
m_settings->setValue ("SaveComments", ui->cbComments->isChecked ());
m_settings->setValue ("TxPower", m_txPower);
m_settings->setValue ("LogComments", m_comments);
m_settings->endGroup ();
}
void LogQSO::initLogQSO(QString const& hisCall, QString const& hisGrid, QString mode,
QString const& rptSent, QString const& rptRcvd,
QDateTime const& dateTimeOn, QDateTime const& dateTimeOff,
Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid,
bool noSuffix, bool toRTTY, bool dBtoComments)
{
if(!isHidden()) return;
ui->call->setText(hisCall);
ui->grid->setText(hisGrid);
ui->name->setText("");
ui->txPower->setText("");
ui->comments->setText("");
if (ui->cbTxPower->isChecked ()) ui->txPower->setText(m_txPower);
if (ui->cbComments->isChecked ()) ui->comments->setText(m_comments);
if(dBtoComments) {
QString t=mode;
if(rptSent!="") t+=" Sent: " + rptSent;
if(rptRcvd!="") t+=" Rcvd: " + rptRcvd;
ui->comments->setText(t);
}
if(noSuffix and mode.mid(0,3)=="JT9") mode="JT9";
if(toRTTY and mode.mid(0,3)=="JT9") mode="RTTY";
ui->mode->setText(mode);
ui->sent->setText(rptSent);
ui->rcvd->setText(rptRcvd);
ui->start_date_time->setDateTime (dateTimeOn);
ui->end_date_time->setDateTime (dateTimeOff);
m_dialFreq=dialFreq;
m_myCall=myCall;
m_myGrid=myGrid;
QString band= ADIF::bandFromFrequency(dialFreq / 1.e6);
ui->band->setText(band);
show ();
}
void LogQSO::accept()
{
QString hisCall,hisGrid,mode,rptSent,rptRcvd,dateOn,dateOff,timeOn,timeOff,band;
QString comments,name;
hisCall=ui->call->text();
hisGrid=ui->grid->text();
mode=ui->mode->text();
rptSent=ui->sent->text();
rptRcvd=ui->rcvd->text();
m_dateTimeOn = ui->start_date_time->dateTime ();
m_dateTimeOff = ui->end_date_time->dateTime ();
band=ui->band->text();
name=ui->name->text();
m_txPower=ui->txPower->text();
comments=ui->comments->text();
m_comments=comments;
QString strDialFreq(QString::number(m_dialFreq / 1.e6,'f',6));
//Log this QSO to ADIF file "wsjtx_log.adi"
QString filename = "wsjtx_log.adi"; // TODO allow user to set
ADIF adifile;
auto adifilePath = QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx_log.adi");
adifile.init(adifilePath);
if (!adifile.addQSOToFile(hisCall,hisGrid,mode,rptSent,rptRcvd,m_dateTimeOn,m_dateTimeOff,band,comments,name,strDialFreq,m_myCall,m_myGrid,m_txPower))
{
MessageBox::warning_message (this, tr ("Log file error"),
tr ("Cannot open \"%1\"").arg (adifilePath));
}
//Log this QSO to file "wsjtx.log"
static QFile f {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("wsjtx.log")};
if(!f.open(QIODevice::Text | QIODevice::Append)) {
MessageBox::warning_message (this, tr ("Log file error"),
tr ("Cannot open \"%1\" for append").arg (f.fileName ()),
tr ("Error: %1").arg (f.errorString ()));
} else {
QString logEntry=m_dateTimeOn.date().toString("yyyy-MM-dd,") +
m_dateTimeOn.time().toString("hh:mm:ss,") +
m_dateTimeOff.date().toString("yyyy-MM-dd,") +
m_dateTimeOff.time().toString("hh:mm:ss,") + hisCall + "," +
hisGrid + "," + strDialFreq + "," + mode +
"," + rptSent + "," + rptRcvd + "," + m_txPower +
"," + comments + "," + name;
QTextStream out(&f);
out << logEntry << endl;
f.close();
}
//Clean up and finish logging
Q_EMIT acceptQSO (m_dateTimeOff, hisCall, hisGrid, m_dialFreq, mode, rptSent, rptRcvd, m_txPower, comments, name,m_dateTimeOn);
QDialog::accept();
}
// closeEvent is only called from the system menu close widget for a
// modeless dialog so we use the hideEvent override to store the
// window settings
void LogQSO::hideEvent (QHideEvent * e)
{
storeSettings ();
QDialog::hideEvent (e);
}
@@ -1,58 +0,0 @@
// Status=review
.Receiver Noise Level
- If it is not already highlighted in green, click the *Monitor*
button to start normal receive operation.
- Be sure your transceiver is set to *USB* (or *USB Data*) mode.
- Use the receiver gain controls and/or the computer's audio mixer
controls to set the background noise level (scale at lower left of
main window) to around 30 dB when no signals are present. It is
usually best to turn AGC off or reduce the RF gain control to minimize
AGC action.
.Bandwidth and Frequency Setting
- If your transceiver offers more than one bandwidth setting in USB
mode, you should normally choose the widest one possible, up to about
5 kHz. This choice has the desirable effect of allowing the *Wide
Graph* (waterfall and 2D spectrum) to display the conventional JT65
and JT9 sub-bands simultaneously on most HF bands. Further details
are provided in the <<TUTORIAL,Basic Operating Tutorial>>. A wider
displayed bandwidth may also be helpful at VHF and above, where JT4,
JT65, and QRA64 signals are found over much wider ranges of
frequencies.
- If you have only a standard SSB filter you wont 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 radios *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.
@@ -14,13 +14,13 @@
void ADIF::init(QString const& filename) void ADIF::init(QString const& filename)
{ {
_filename = filename; _filename = filename;
_data.clear(); _data.clear();
} }
QString ADIF::extractField(QString const& record, QString const& fieldName) const QString ADIF::extractField(QString const& record, QString const& fieldName) const
{ {
int fieldNameIndex = record.indexOf (fieldName + ':', 0, Qt::CaseInsensitive); int fieldNameIndex = record.indexOf ('<' + fieldName + ':', 0, Qt::CaseInsensitive);
if (fieldNameIndex >=0) if (fieldNameIndex >=0)
{ {
int closingBracketIndex = record.indexOf('>',fieldNameIndex); int closingBracketIndex = record.indexOf('>',fieldNameIndex);
@@ -165,17 +165,55 @@ QList<QString> ADIF::getCallList() const
++i; ++i;
} }
return p; return p;
} }
int ADIF::getCount() const int ADIF::getCount() const
{ {
return _data.size(); 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 // 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, bool ADIF::addQSOToFile(QByteArray const& ADIF_record)
QString const& comments, QString const& name, QString const& strDialFreq, QString const& m_myCall, QString const& m_myGrid, QString const& m_txPower)
{ {
QFile f2(_filename); QFile f2(_filename);
if (!f2.open(QIODevice::Text | QIODevice::Append)) if (!f2.open(QIODevice::Text | QIODevice::Append))
@@ -186,30 +224,7 @@ bool ADIF::addQSOToFile(QString const& hisCall, QString const& hisGrid, QString
if (f2.size()==0) if (f2.size()==0)
out << "WSJT-X ADIF Export<eoh>" << endl; // new file out << "WSJT-X ADIF Export<eoh>" << endl; // new file
QString t; out << ADIF_record << " <eor>" << endl;
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(); f2.close();
} }
return true; return true;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

@@ -0,0 +1,126 @@
Quick Start for DXpedition Mode
-------------------------------
These notes are intended for operators already familiar with WSJT-X
and FT8 mode. QSOs between the Dxpedition ("Fox") and other stations
("Hounds") are completed with as little as one transmission per Hound,
as in the following examples:
----------------------------------------------------------------------------
Fox (300-600 Hz) Hounds
----------------------------------------------------------------------------
1. CQ KH1DX AJ10
2. KH1DX K1ABC FN42, KH1DX W9XYZ EN37, ...
3. K1ABC KH1DX -13
4. KH1DX K1ABC R-11
5. K1ABC RR73; W9XYZ <KH1DX> -17
6. KH1DX W9XYZ R-16
7. W9XYZ RR73; G4AAA <KH1DX> -09
8. ...
----------------------------------------------------------------------------
Everybody sets dial frequency to an agreed number and uses CAT control
with Split Operation (either *Rig* or *Fake It*). Fox transmits up to
5 signals simultaneously, at audio frequencies 300, 360, ... 540
Hz. Hounds make initial calls (e.g., line 2 above) anywhere in the
range 1000 - 4000 Hz. They send "R+rpt" 350 Hz above the frequency
where Fox called them.
INSTRUCTIONS FOR FOX
--------------------
1. Start WSJT-X in FT8 mode. Select *Fox* on the *Settings ->
Advanced tab*. On the main window, check *Tx even/1st*, *Auto Seq*,
and *Hold Tx Freq*; uncheck *Call 1st*. Set *Tx 300 Hz* and select
Tab 3.
2. In Fox mode the left window (called "Band Activity" in normal FT8
mode) is labeled "Stations calling DXpedition <MyCall>". It will be
filled with a sorted list of calling Hounds. You can sort by Call,
Grid, S/N, Distance, or Random order by using the comboBox at top
right of Tab 3. You can limit the displayed Hound callsigns to those
no stronger than *Max dB*. Fox might use this feature to discourage
Hounds from engaging in a QRO arms race.
3. *N Slots* sets the number of simultaneous Fox signals to be used.
Fox carries out as many as *N Slots* QSOs simultaneously.
4. *Repeats* sets the maximum number of repeat transmissions of the
same message. A QSO is aborted when this number would be exceeded.
5. The *CQ* comboBox on Tab 3 offers a selection of directed CQ
messages. *Reset* clears the QSO queue.
6. The Fox operator's main task is to select Hounds to be called and
worked. The text box on Tab 3 holds the "QSO queue": a list of Hound
calls to be worked. Hit Enter to select the top callsign from the
sorted list of callers (left window), or double-click on any
particular call. Either actiion moves that Hound into the "QSO
queue".
7. The right window displays decodes of signals below 1000 Hz.
Normally these should include only Hound messages containing "R+rpt"
and Fox's own transmissions.
8. To get things started, toggle *Enable Tx* to red. If a Hound call
is available in the QSO queue, that station will be called. If the
QSO queue is empty, Fox calls CQ.
9. If you're using Nslots = 2 or higher, your signal no longer has
a constant envelope. To avoid producing intermod sidebands you need
to ensure linearity in your Tx system. One way to get things about right
is to use the WSJT-X *Tune* button to generate a pure tone. Reduce the
Tx audio level until your power output decreases by 10% or so. Use this
level for your Fox transmissions.
NOTE: If you are generating Nslots signals, the average power in each one
will be 1/Nslots^2 of its normal value for single-signal transmissions.
Nslots Relative dB
-------------------
1 0
2 -6
3 -9.5
4 -12
5 -14
The following features are not yet implemented for Fox:
1. Enforce all required settings
2. Tx message timeout
3. Manual abort of selected QSO
4. All Tx and Rx messages to all.txt
5. Additional sort criteria for Hound calls
6. Selectable timeout for keeping Hounds in the sorted list
7. Display number of active callers
8. Display QSO rate
INSTRUCTIONS FOR HOUND
----------------------
1. Start WSJT-X in FT8 mode. Select *Hound* On the *Settings ->
Advanced* tab. On the main window check *Auto Seq* and uncheck *Tx
even/1st*, *Call 1st*, and *Hold Tx Freq*. Set *Tx nnnn Hz* to some
frequency between 1000 and 4000 Hz, and select *Tab 1*. Enter Fox's
callsign and locator in DX Call and DX Grid, select Tx1, and start
*Monitor*.
2. When you have copied Fox, hit *Enable Tx* to call him. You may
keep calling until he answers. You may wish to move your TxFreq
around, hoping to find a clear calling frequency.
3. When you are called by Fox with a signal report, your next
transmission will automatically be sent as Tx3 ("R+rpt"). When Fox
receives that message he responds with "RR73", and your QSO is
complete!
The following features are not yet implemented for Hound:
1. Force all required settings
2. React properly to directed CQs from Fox
3. Disable Tx2, 4, 5, 6
4. For Tx1, enforce TxFreq >= 1000 Hz
@@ -0,0 +1,18 @@
program twq
character*22 msg0,msg
integer*1 data0(11)
open(10,file='wqmsg.txt',status='old')
write(*,1000)
1000 format(4x,'Encoded message',9x,'Decoded as',12x,'itype'/55('-'))
do line=1,9999
read(10,*,end=999) msg0
call wqenc(msg0,itype,data0)
call wqdec(data0,msg,ntype)
write(*,1100) line,msg0,msg,ntype
1100 format(i2,'.',1x,a22,2x,a22,i3)
enddo
999 end program twq
@@ -1,46 +0,0 @@
// -*- Mode: C++ -*-
#ifndef DISPLAYTEXT_H
#define DISPLAYTEXT_H
#include <QTextEdit>
#include <QFont>
#include "logbook/logbook.h"
#include "decodedtext.h"
class QAction;
class DisplayText
: public QTextEdit
{
Q_OBJECT
public:
explicit DisplayText(QWidget *parent = 0);
void setContentFont (QFont const&);
void insertLineSpacer(QString const&);
void displayDecodedText(DecodedText const& decodedText, QString const& myCall, bool displayDXCCEntity,
LogBook const& logBook, QColor color_CQ, QColor color_MyCall,
QColor color_DXCC, QColor color_NewCall);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
QColor color_TxMsg, bool bFastMode);
void displayQSY(QString text);
Q_SIGNAL void selectCallsign (bool shift, bool ctrl, bool alt);
Q_SIGNAL void erased ();
Q_SLOT void appendText (QString const& text, QColor bg = Qt::white);
Q_SLOT void erase ();
protected:
void mouseDoubleClickEvent(QMouseEvent *e);
private:
QString appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg, LogBook const& logBook,
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
QFont char_font_;
QAction * erase_action_;
};
#endif // DISPLAYTEXT_H
@@ -1,59 +0,0 @@
128
56
10
1 15 30 44 58 71 84 100 115 0
2 16 31 44 59 72 86 101 116 0
3 17 31 45 60 73 87 102 117 0
2 18 32 46 58 73 85 103 112 0
4 19 32 47 61 74 88 104 118 0
5 20 33 48 62 75 88 105 116 0
6 19 34 49 63 76 89 105 119 0
7 15 27 45 64 77 88 106 120 0
8 15 35 50 59 75 90 107 121 127
7 21 33 51 65 73 91 108 114 0
9 22 30 46 59 78 92 99 122 0
9 19 35 52 60 71 93 109 120 0
10 20 31 53 63 79 93 107 123 0
11 15 36 53 66 78 85 110 124 0
8 23 37 49 67 71 86 111 118 0
12 22 34 54 68 80 94 109 114 0
1 24 34 52 65 75 87 97 123 0
13 25 29 43 69 81 85 100 121 128
12 17 38 55 63 82 90 101 125 0
11 26 39 47 56 76 95 106 117 0
2 27 40 49 69 74 94 108 117 0
4 16 30 55 64 76 91 103 126 0
13 17 28 47 65 80 96 111 124 126
6 18 36 51 70 83 94 111 121 0
13 16 34 48 57 82 95 112 120 127
6 28 40 48 58 79 90 113 122 0
5 27 41 46 67 83 91 109 127 0
14 16 42 54 63 78 97 100 118 0
13 27 39 52 70 84 90 114 118 0
10 22 42 47 64 81 98 110 116 0
11 22 29 55 60 84 97 108 111 127
5 26 37 55 57 74 96 98 128 0
3 21 35 54 62 82 98 104 113 0
14 21 43 50 68 77 93 110 117 0
9 24 33 56 69 72 89 110 112 0
12 26 42 53 62 73 89 99 121 0
10 25 35 41 57 76 97 101 122 0
10 18 39 44 66 77 99 102 119 0
3 29 40 44 61 83 93 106 125 0
4 23 39 45 65 85 89 107 113 0
6 26 30 43 61 80 86 108 123 0
7 19 31 57 69 83 99 113 124 0
3 24 37 43 66 84 92 105 120 126
2 24 38 50 70 71 88 102 122 0
1 20 32 51 68 81 86 102 124 0
12 23 41 51 59 74 87 106 115 0
14 28 37 46 62 72 95 114 115 125
1 28 41 49 61 82 92 103 116 128
7 25 38 56 60 75 98 103 115 0
8 29 33 45 58 78 96 109 119 0
4 25 36 54 67 77 96 105 123 0
14 20 38 52 66 80 91 104 112 128
8 18 42 56 68 79 87 104 125 0
9 23 40 53 70 81 95 101 126 0
11 21 32 48 67 72 94 107 119 0
5 17 36 50 64 79 92 100 0 0
@@ -1,63 +0,0 @@
subroutine watterson(c,npts,fs,delay,fspread)
include 'wsprlf_params.f90'
complex c(0:npts-1)
complex c2(0:NZMAX-1)
complex cs1(0:NZMAX-1)
complex cs2(0:NZMAX-1)
nonzero=0
df=fs/npts
if(fspread.gt.0.0) then
do i=0,npts-1
xx=gran()
yy=gran()
cs1(i)=0.707*cmplx(xx,yy)
xx=gran()
yy=gran()
cs2(i)=0.707*cmplx(xx,yy)
enddo
call four2a(cs1,npts,1,-1,1) !To freq domain
call four2a(cs2,npts,1,-1,1)
do i=0,npts-1
f=i*df
if(i.gt.npts/2) f=(i-npts)*df
x=(f/(0.5*fspread))**2
a=0.
if(x.le.50.0) then
a=exp(-x)
endif
cs1(i)=a*cs1(i)
cs2(i)=a*cs2(i)
if(abs(f).lt.10.0) then
p1=real(cs1(i))**2 + aimag(cs1(i))**2
p2=real(cs2(i))**2 + aimag(cs2(i))**2
if(p1.gt.0.0) nonzero=nonzero+1
! write(62,3101) f,p1,p2,db(p1+1.e-12)-60,db(p2+1.e-12)-60
!3101 format(f10.3,2f12.3,2f10.3)
endif
enddo
call four2a(cs1,npts,1,1,1) !Back to time domain
call four2a(cs2,npts,1,1,1)
cs1(0:npts-1)=cs1(0:npts-1)/npts
cs2(0:npts-1)=cs2(0:npts-1)/npts
endif
nshift=nint(0.001*delay*fs)
c2(0:npts-1)=cshift(c(0:npts-1),nshift)
sq=0.
do i=0,npts-1
if(nonzero.gt.1) then
c(i)=0.5*(cs1(i)*c(i) + cs2(i)*c2(i))
else
c(i)=0.5*(c(i) + c2(i))
endif
sq=sq + real(c(i))**2 + aimag(c(i))**2
! write(61,3001) i/12000.0,c(i)
!3001 format(3f12.6)
enddo
rms=sqrt(sq/npts)
c=c/rms
return
end subroutine watterson
@@ -1,748 +0,0 @@
#include "plotter.h"
#include <math.h>
#include <QDebug>
#include "commons.h"
#include "moc_plotter.cpp"
#include <fstream>
#include <iostream>
#define MAX_SCREENSIZE 2048
CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
QFrame {parent},
m_bScaleOK {false},
m_bReference {false},
m_bReference0 {false},
m_fSpan {2000.0},
m_plotZero {0},
m_plotGain {0},
m_plot2dGain {0},
m_plot2dZero {0},
m_nSubMode {0},
m_Running {false},
m_paintEventBusy {false},
m_fftBinWidth {1500.0/2048.0},
m_dialFreq {0.},
m_sum {},
m_dBStepSize {10},
m_FreqUnits {1},
m_hdivs {HORZ_DIVS},
m_line {0},
m_fSample {12000},
m_nsps {6912},
m_Percent2DScreen {30}, //percent of screen used for 2D display
m_Percent2DScreen0 {0},
m_rxFreq {1020},
m_txFreq {0},
m_startFreq {0}
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setFocusPolicy(Qt::StrongFocus);
setAttribute(Qt::WA_PaintOnScreen,false);
setAutoFillBackground(false);
setAttribute(Qt::WA_OpaquePaintEvent, false);
setAttribute(Qt::WA_NoSystemBackground, true);
}
CPlotter::~CPlotter() { } // Destructor
QSize CPlotter::minimumSizeHint() const
{
return QSize(50, 50);
}
QSize CPlotter::sizeHint() const
{
return QSize(180, 180);
}
void CPlotter::resizeEvent(QResizeEvent* ) //resizeEvent()
{
if(!size().isValid()) return;
if( m_Size != size() or (m_bReference != m_bReference0) or
m_Percent2DScreen != m_Percent2DScreen0) {
m_Size = size();
m_w = m_Size.width();
m_h = m_Size.height();
m_h2 = m_Percent2DScreen*m_h/100.0;
if(m_h2>m_h-30) m_h2=m_h-30;
if(m_bReference) m_h2=m_h-30;
if(m_h2<1) m_h2=1;
m_h1=m_h-m_h2;
m_2DPixmap = QPixmap(m_Size.width(), m_h2);
m_2DPixmap.fill(Qt::black);
m_WaterfallPixmap = QPixmap(m_Size.width(), m_h1);
m_OverlayPixmap = QPixmap(m_Size.width(), m_h2);
m_OverlayPixmap.fill(Qt::black);
m_WaterfallPixmap.fill(Qt::black);
m_2DPixmap.fill(Qt::black);
m_ScalePixmap = QPixmap(m_w,30);
m_ScalePixmap.fill(Qt::white);
m_Percent2DScreen0 = m_Percent2DScreen;
}
DrawOverlay();
}
void CPlotter::paintEvent(QPaintEvent *) // paintEvent()
{
if(m_paintEventBusy) return;
m_paintEventBusy=true;
QPainter painter(this);
painter.drawPixmap(0,0,m_ScalePixmap);
painter.drawPixmap(0,30,m_WaterfallPixmap);
painter.drawPixmap(0,m_h1,m_2DPixmap);
m_paintEventBusy=false;
}
void CPlotter::draw(float swide[], bool bScroll, bool bRed)
{
int j,j0;
static int ktop=0;
float y,y2,ymin;
double fac = sqrt(m_binsPerPixel*m_waterfallAvg/15.0);
double gain = fac*pow(10.0,0.02*m_plotGain);
double gain2d = pow(10.0,0.02*(m_plot2dGain));
if(m_bReference != m_bReference0) resizeEvent(NULL);
m_bReference0=m_bReference;
//move current data down one line (must do this before attaching a QPainter object)
if(bScroll) m_WaterfallPixmap.scroll(0,1,0,0,m_w,m_h1);
QPainter painter1(&m_WaterfallPixmap);
m_2DPixmap = m_OverlayPixmap.copy(0,0,m_w,m_h2);
QPainter painter2D(&m_2DPixmap);
if(!painter2D.isActive()) return;
QFont Font("Arial");
Font.setPointSize(12);
Font.setWeight(QFont::Normal);
painter2D.setFont(Font);
if(m_bLinearAvg) {
painter2D.setPen(Qt::yellow);
} else if(m_bReference) {
painter2D.setPen(Qt::blue);
} else {
painter2D.setPen(Qt::green);
}
static QPoint LineBuf[MAX_SCREENSIZE];
static QPoint LineBuf2[MAX_SCREENSIZE];
j=0;
j0=int(m_startFreq/m_fftBinWidth + 0.5);
int iz=XfromFreq(5000.0);
int jz=iz*m_binsPerPixel;
m_fMax=FreqfromX(iz);
m_line++;
if(bScroll) {
flat4_(swide,&iz,&m_Flatten);
flat4_(&dec_data.savg[j0],&jz,&m_Flatten);
}
ymin=1.e30;
if(swide[0]>1.e29 and swide[0]< 1.5e30) painter1.setPen(Qt::green);
if(swide[0]>1.4e30) painter1.setPen(Qt::yellow);
for(int i=0; i<iz; i++) {
y=swide[i];
if(y<ymin) ymin=y;
int y1 = 10.0*gain*y + 10*m_plotZero +40;
if (y1<0) y1=0;
if (y1>254) y1=254;
if (swide[i]<1.e29) painter1.setPen(g_ColorTbl[y1]);
painter1.drawPoint(i,0);
}
float y2min=1.e30;
float y2max=-1.e30;
for(int i=0; i<iz; i++) {
y=swide[i] - ymin;
y2=0;
if(m_bCurrent) y2 = gain2d*y + m_plot2dZero; //Current
if(bScroll) {
float sum=0.0;
int j=j0+m_binsPerPixel*i;
for(int k=0; k<m_binsPerPixel; k++) {
sum+=dec_data.savg[j++];
}
m_sum[i]=sum;
}
if(m_bCumulative) y2=gain2d*(m_sum[i]/m_binsPerPixel + m_plot2dZero);
if(m_Flatten==0) y2 += 15; //### could do better! ###
if(m_bLinearAvg) { //Linear Avg (yellow)
float sum=0.0;
int j=j0+m_binsPerPixel*i;
for(int k=0; k<m_binsPerPixel; k++) {
sum+=spectra_.syellow[j++];
}
y2=gain2d*sum/m_binsPerPixel + m_plot2dZero;
}
if(m_bReference) { //Reference (red)
float df_ref=12000.0/6912.0;
int j=FreqfromX(i)/df_ref + 0.5;
y2=spectra_.ref[j] + m_plot2dZero;
// if(gain2d>1.5) y2=spectra_.filter[j] + m_plot2dZero;
}
if(i==iz-1) {
painter2D.drawPolyline(LineBuf,j);
if(m_mode=="QRA64") {
painter2D.setPen(Qt::red);
painter2D.drawPolyline(LineBuf2,ktop);
}
}
LineBuf[j].setX(i);
LineBuf[j].setY(int(0.9*m_h2-y2*m_h2/70.0));
if(y2<y2min) y2min=y2;
if(y2>y2max) y2max=y2;
j++;
}
if(swide[0]>1.0e29) m_line=0;
if(m_line == painter1.fontMetrics ().height ()) {
painter1.setPen(Qt::white);
QString t;
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
int n=(ms/1000) % m_TRperiod;
QDateTime t1=QDateTime::currentDateTimeUtc().addSecs(-n);
if(m_TRperiod < 60) {
t=t1.toString("hh:mm:ss") + " " + m_rxBand;
} else {
t=t1.toString("hh:mm") + " " + m_rxBand;
}
painter1.drawText (5, painter1.fontMetrics ().ascent (), t);
}
if(m_mode=="JT4") {
QPen pen3(Qt::yellow); //Mark freqs of JT4 single-tone msgs
painter2D.setPen(pen3);
Font.setWeight(QFont::Bold);
painter2D.setFont(Font);
int x1=XfromFreq(m_rxFreq);
y=0.2*m_h2;
painter2D.drawText(x1-4,y,"T");
x1=XfromFreq(m_rxFreq+250);
painter2D.drawText(x1-4,y,"M");
x1=XfromFreq(m_rxFreq+500);
painter2D.drawText(x1-4,y,"R");
x1=XfromFreq(m_rxFreq+750);
painter2D.drawText(x1-4,y,"73");
}
if(bRed) {
std::ifstream f;
f.open(m_redFile.toLatin1());
if(f) {
int x,y;
float freq,sync;
float slimit=6.0;
QPen pen0(Qt::red,1);
painter1.setPen(pen0);
for(int i=0; i<99999; i++) {
f >> freq >> sync;
if(f.eof()) break;
x=XfromFreq(freq);
y=(sync-slimit)*3.0;
if(y>0) {
if(y>15.0) y=15.0;
if(x>=0 and x<=m_w) {
painter1.setPen(pen0);
painter1.drawLine(x,0,x,y);
}
}
}
f.close();
}
// m_bDecodeFinished=false;
}
update(); //trigger a new paintEvent
m_bScaleOK=true;
}
void CPlotter::drawRed(int ia, int ib, float swide[])
{
m_ia=ia;
m_ib=ib;
draw(swide,false,true);
}
void CPlotter::DrawOverlay() //DrawOverlay()
{
if(m_OverlayPixmap.isNull()) return;
if(m_WaterfallPixmap.isNull()) return;
int w = m_WaterfallPixmap.width();
int x,y,x1,x2,x3,x4,x5,x6;
float pixperdiv;
double df = m_binsPerPixel*m_fftBinWidth;
QRect rect;
QPen penOrange(QColor(255,165,0),3);
QPen penGreen(Qt::green, 3); //Mark Tol range with green line
QPen penRed(Qt::red, 3); //Mark Tx freq with red
QPainter painter(&m_OverlayPixmap);
painter.initFrom(this);
QLinearGradient gradient(0, 0, 0 ,m_h2); //fill background with gradient
gradient.setColorAt(1, Qt::black);
gradient.setColorAt(0, Qt::darkBlue);
painter.setBrush(gradient);
painter.drawRect(0, 0, m_w, m_h2);
painter.setBrush(Qt::SolidPattern);
m_fSpan = w*df;
// int n=m_fSpan/10;
m_freqPerDiv=10;
if(m_fSpan>100) m_freqPerDiv=20;
if(m_fSpan>250) m_freqPerDiv=50;
if(m_fSpan>500) m_freqPerDiv=100;
if(m_fSpan>1000) m_freqPerDiv=200;
if(m_fSpan>2500) m_freqPerDiv=500;
pixperdiv = m_freqPerDiv/df;
m_hdivs = w*df/m_freqPerDiv + 1.9999;
float xx0=float(m_startFreq)/float(m_freqPerDiv);
xx0=xx0-int(xx0);
int x0=xx0*pixperdiv+0.5;
for( int i=1; i<m_hdivs; i++) { //draw vertical grids
x = (int)((float)i*pixperdiv ) - x0;
if(x >= 0 and x<=m_w) {
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
painter.drawLine(x, 0, x , m_h2);
}
}
pixperdiv = (float)m_h2 / (float)VERT_DIVS;
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
for( int i=1; i<VERT_DIVS; i++) { //draw horizontal grids
y = (int)( (float)i*pixperdiv );
painter.drawLine(0, y, w, y);
}
QRect rect0;
QPainter painter0(&m_ScalePixmap);
painter0.initFrom(this);
//create Font to use for scales
QFont Font("Arial");
Font.setPointSize(12);
Font.setWeight(QFont::Normal);
painter0.setFont(Font);
painter0.setPen(Qt::black);
if(m_binsPerPixel < 1) m_binsPerPixel=1;
m_hdivs = w*df/m_freqPerDiv + 0.9999;
m_ScalePixmap.fill(Qt::white);
painter0.drawRect(0, 0, w, 30);
MakeFrequencyStrs();
//draw tick marks on upper scale
pixperdiv = m_freqPerDiv/df;
for( int i=0; i<m_hdivs; i++) { //major ticks
x = (int)((m_xOffset+i)*pixperdiv );
painter0.drawLine(x,18,x,30);
}
int minor=5;
if(m_freqPerDiv==200) minor=4;
for( int i=1; i<minor*m_hdivs; i++) { //minor ticks
x = i*pixperdiv/minor;
painter0.drawLine(x,24,x,30);
}
//draw frequency values
for( int i=0; i<=m_hdivs; i++) {
x = (int)((m_xOffset+i)*pixperdiv - pixperdiv/2);
rect0.setRect(x,0, (int)pixperdiv, 20);
painter0.drawText(rect0, Qt::AlignHCenter|Qt::AlignVCenter,m_HDivText[i]);
}
float bw=9.0*12000.0/m_nsps; //JT9
if(m_mode=="FT8") bw=8*12000.0/2048.0; //FT8
if(m_mode=="JT4") { //JT4
bw=3*11025.0/2520.0; //Max tone spacing (3/4 of actual BW)
if(m_nSubMode==1) bw=2*bw;
if(m_nSubMode==2) bw=4*bw;
if(m_nSubMode==3) bw=9*bw;
if(m_nSubMode==4) bw=18*bw;
if(m_nSubMode==5) bw=36*bw;
if(m_nSubMode==6) bw=72*bw;
painter0.setPen(penGreen);
x1=XfromFreq(m_rxFreq-m_tol);
x2=XfromFreq(m_rxFreq+m_tol);
painter0.drawLine(x1,29,x2,29);
for(int i=0; i<4; i++) {
x1=XfromFreq(m_rxFreq+bw*i/3.0);
int j=24;
if(i==0) j=18;
painter0.drawLine(x1,j,x1,30);
}
painter0.setPen(penRed);
for(int i=0; i<4; i++) {
x1=XfromFreq(m_txFreq+bw*i/3.0);
painter0.drawLine(x1,12,x1,18);
}
}
if(m_modeTx=="JT9" and m_nSubMode>0) { //JT9
bw=8.0*12000.0/m_nsps;
if(m_nSubMode==1) bw=2*bw; //B
if(m_nSubMode==2) bw=4*bw; //C
if(m_nSubMode==3) bw=8*bw; //D
if(m_nSubMode==4) bw=16*bw; //E
if(m_nSubMode==5) bw=32*bw; //F
if(m_nSubMode==6) bw=64*bw; //G
if(m_nSubMode==7) bw=128*bw; //H
}
if(m_mode=="QRA64") { //QRA64
bw=63.0*12000.0/m_nsps;
if(m_nSubMode==1) bw=2*bw; //B
if(m_nSubMode==2) bw=4*bw; //C
if(m_nSubMode==3) bw=8*bw; //D
if(m_nSubMode==4) bw=16*bw; //E
}
if(m_modeTx=="JT65") { //JT65
bw=65.0*11025.0/4096.0;
if(m_nSubMode==1) bw=2*bw; //B
if(m_nSubMode==2) bw=4*bw; //C
}
painter0.setPen(penGreen);
if(m_mode=="WSPR") {
x1=XfromFreq(1400);
x2=XfromFreq(1600);
painter0.drawLine(x1,29,x2,29);
}
if(m_mode=="WSPR-LF") {
x1=XfromFreq(1600);
x2=XfromFreq(1700);
painter0.drawLine(x1,29,x2,29);
}
if(m_mode=="FreqCal") { //FreqCal
x1=XfromFreq(m_rxFreq-m_tol);
x2=XfromFreq(m_rxFreq+m_tol);
painter0.drawLine(x1,29,x2,29);
x1=XfromFreq(m_rxFreq);
painter0.drawLine(x1,24,x1,30);
}
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or m_mode=="QRA64" or m_mode=="FT8") {
if(m_mode=="QRA64" or (m_mode=="JT65" and m_bVHF)) {
painter0.setPen(penGreen);
x1=XfromFreq(m_rxFreq-m_tol);
x2=XfromFreq(m_rxFreq+m_tol);
painter0.drawLine(x1,28,x2,28);
x1=XfromFreq(m_rxFreq);
painter0.drawLine(x1,24,x1,30);
if(m_mode=="JT65") {
painter0.setPen(penOrange);
x3=XfromFreq(m_rxFreq+20.0*bw/65.0); //RO
painter0.drawLine(x3,24,x3,30);
x4=XfromFreq(m_rxFreq+30.0*bw/65.0); //RRR
painter0.drawLine(x4,24,x4,30);
x5=XfromFreq(m_rxFreq+40.0*bw/65.0); //73
painter0.drawLine(x5,24,x5,30);
}
painter0.setPen(penGreen);
x6=XfromFreq(m_rxFreq+bw); //Highest tone
painter0.drawLine(x6,24,x6,30);
} else {
painter0.setPen(penGreen);
x1=XfromFreq(m_rxFreq);
x2=XfromFreq(m_rxFreq+bw);
painter0.drawLine(x1,24,x1,30);
painter0.drawLine(x1,28,x2,28);
painter0.drawLine(x2,24,x2,30);
}
}
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or
m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="FT8") {
painter0.setPen(penRed);
x1=XfromFreq(m_txFreq);
x2=XfromFreq(m_txFreq+bw);
if(m_mode=="WSPR") {
bw=4*12000.0/8192.0; //WSPR
x1=XfromFreq(m_txFreq-0.5*bw);
x2=XfromFreq(m_txFreq+0.5*bw);
}
if(m_mode=="WSPR-LF") {
bw=3*12000.0/8640.0; //WSPR-LF
x1=XfromFreq(m_txFreq-0.5*bw);
x2=XfromFreq(m_txFreq+0.5*bw);
}
painter0.drawLine(x1,17,x1,21);
painter0.drawLine(x1,17,x2,17);
painter0.drawLine(x2,17,x2,21);
}
if(m_mode=="JT9+JT65") {
QPen pen2(Qt::blue, 3); //Mark the JT65 | JT9 divider
painter0.setPen(pen2);
x1=XfromFreq(m_fMin);
if(x1<2) x1=2;
x2=x1+30;
painter0.drawLine(x1,8,x1,28);
}
if(m_dialFreq>10.13 and m_dialFreq< 10.15 and m_mode.mid(0,4)!="WSPR") {
float f1=1.0e6*(10.1401 - m_dialFreq);
float f2=f1+200.0;
x1=XfromFreq(f1);
x2=XfromFreq(f2);
if(x1<=m_w and x2>=0) {
painter0.setPen(penOrange); //Mark WSPR sub-band orange
painter0.drawLine(x1,9,x2,9);
}
}
}
void CPlotter::MakeFrequencyStrs() //MakeFrequencyStrs
{
int f=(m_startFreq+m_freqPerDiv-1)/m_freqPerDiv;
f*=m_freqPerDiv;
m_xOffset=float(f-m_startFreq)/m_freqPerDiv;
for(int i=0; i<=m_hdivs; i++) {
m_HDivText[i].setNum(f);
f+=m_freqPerDiv;
}
}
int CPlotter::XfromFreq(float f) //XfromFreq()
{
// float w = m_WaterfallPixmap.width();
int x = int(m_w * (f - m_startFreq)/m_fSpan + 0.5);
if(x<0 ) return 0;
if(x>m_w) return m_w;
return x;
}
float CPlotter::FreqfromX(int x) //FreqfromX()
{
return float(m_startFreq + x*m_binsPerPixel*m_fftBinWidth);
}
void CPlotter::SetRunningState(bool running) //SetRunningState()
{
m_Running = running;
}
void CPlotter::setPlotZero(int plotZero) //setPlotZero()
{
m_plotZero=plotZero;
}
int CPlotter::plotZero() //PlotZero()
{
return m_plotZero;
}
void CPlotter::setPlotGain(int plotGain) //setPlotGain()
{
m_plotGain=plotGain;
}
int CPlotter::plotGain() //plotGain()
{
return m_plotGain;
}
int CPlotter::plot2dGain() //plot2dGain
{
return m_plot2dGain;
}
void CPlotter::setPlot2dGain(int n) //setPlot2dGain
{
m_plot2dGain=n;
update();
}
int CPlotter::plot2dZero() //plot2dZero
{
return m_plot2dZero;
}
void CPlotter::setPlot2dZero(int plot2dZero) //setPlot2dZero
{
m_plot2dZero=plot2dZero;
}
void CPlotter::setStartFreq(int f) //SetStartFreq()
{
m_startFreq=f;
resizeEvent(NULL);
update();
}
int CPlotter::startFreq() //startFreq()
{
return m_startFreq;
}
int CPlotter::plotWidth(){return m_WaterfallPixmap.width();} //plotWidth
void CPlotter::UpdateOverlay() {DrawOverlay();} //UpdateOverlay
void CPlotter::setDataFromDisk(bool b) {m_dataFromDisk=b;} //setDataFromDisk
void CPlotter::setRxRange(int fMin) //setRxRange
{
m_fMin=fMin;
}
void CPlotter::setBinsPerPixel(int n) //setBinsPerPixel
{
m_binsPerPixel = n;
DrawOverlay(); //Redraw scales and ticks
update(); //trigger a new paintEvent}
}
int CPlotter::binsPerPixel() //binsPerPixel
{
return m_binsPerPixel;
}
void CPlotter::setWaterfallAvg(int n) //setBinsPerPixel
{
m_waterfallAvg = n;
}
void CPlotter::setRxFreq (int x) //setRxFreq
{
m_rxFreq = x; // x is freq in Hz
DrawOverlay();
update();
}
int CPlotter::rxFreq() {return m_rxFreq;} //rxFreq
void CPlotter::mousePressEvent(QMouseEvent *event) //mousePressEvent
{
int x=event->x();
if(x<0) x=0;
if(x>m_Size.width()) x=m_Size.width();
bool ctrl = (event->modifiers() & Qt::ControlModifier);
bool shift = (event->modifiers() & Qt::ShiftModifier);
int newFreq = int(FreqfromX(x)+0.5);
int oldTxFreq = m_txFreq;
int oldRxFreq = m_rxFreq;
if (ctrl or m_lockTxFreq) {
emit setFreq1 (newFreq, newFreq);
}
else if (shift) {
emit setFreq1 (oldRxFreq, newFreq);
}
else {
emit setFreq1(newFreq,oldTxFreq);
}
int n=1;
if(ctrl) n+=100;
emit freezeDecode1(n);
}
void CPlotter::mouseDoubleClickEvent(QMouseEvent *event) //mouse2click
{
bool ctrl = (event->modifiers() & Qt::ControlModifier);
int n=2;
if(ctrl) n+=100;
emit freezeDecode1(n);
}
void CPlotter::setNsps(int ntrperiod, int nsps) //setNsps
{
m_TRperiod=ntrperiod;
m_nsps=nsps;
m_fftBinWidth=1500.0/2048.0;
if(m_nsps==15360) m_fftBinWidth=1500.0/2048.0;
if(m_nsps==40960) m_fftBinWidth=1500.0/6144.0;
if(m_nsps==82944) m_fftBinWidth=1500.0/12288.0;
if(m_nsps==252000) m_fftBinWidth=1500.0/32768.0;
DrawOverlay(); //Redraw scales and ticks
update(); //trigger a new paintEvent}
}
void CPlotter::setTxFreq(int n) //setTxFreq
{
m_txFreq=n;
DrawOverlay();
update();
}
void CPlotter::setMode(QString mode) //setMode
{
m_mode=mode;
}
void CPlotter::setSubMode(int n) //setSubMode
{
m_nSubMode=n;
}
void CPlotter::setModeTx(QString modeTx) //setModeTx
{
m_modeTx=modeTx;
}
int CPlotter::Fmax()
{
return m_fMax;
}
void CPlotter::setDialFreq(double d)
{
m_dialFreq=d;
DrawOverlay();
update();
}
void CPlotter::setRxBand(QString band)
{
m_rxBand=band;
}
void CPlotter::setFlatten(bool b1, bool b2)
{
m_Flatten=0;
if(b1) m_Flatten=1;
if(b2) m_Flatten=2;
}
void CPlotter::setTol(int n) //setTol()
{
m_tol=n;
DrawOverlay();
}
void CPlotter::setColours(QVector<QColor> const& cl)
{
g_ColorTbl = cl;
}
void CPlotter::SetPercent2DScreen(int percent)
{
m_Percent2DScreen=percent;
resizeEvent(NULL);
update();
}
void CPlotter::setVHF(bool bVHF)
{
m_bVHF=bVHF;
}
void CPlotter::setRedFile(QString fRed)
{
m_redFile=fRed;
}
@@ -1,748 +0,0 @@
#include "plotter.h"
#include <math.h>
#include <QDebug>
#include "commons.h"
#include "moc_plotter.cpp"
#include <fstream>
#include <iostream>
#define MAX_SCREENSIZE 2048
CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
QFrame {parent},
m_bScaleOK {false},
m_bReference {false},
m_bReference0 {false},
m_fSpan {2000.0},
m_plotZero {0},
m_plotGain {0},
m_plot2dGain {0},
m_plot2dZero {0},
m_nSubMode {0},
m_Running {false},
m_paintEventBusy {false},
m_fftBinWidth {1500.0/2048.0},
m_dialFreq {0.},
m_sum {},
m_dBStepSize {10},
m_FreqUnits {1},
m_hdivs {HORZ_DIVS},
m_line {0},
m_fSample {12000},
m_nsps {6912},
m_Percent2DScreen {30}, //percent of screen used for 2D display
m_Percent2DScreen0 {0},
m_rxFreq {1020},
m_txFreq {0},
m_startFreq {0}
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setFocusPolicy(Qt::StrongFocus);
setAttribute(Qt::WA_PaintOnScreen,false);
setAutoFillBackground(false);
setAttribute(Qt::WA_OpaquePaintEvent, false);
setAttribute(Qt::WA_NoSystemBackground, true);
}
CPlotter::~CPlotter() { } // Destructor
QSize CPlotter::minimumSizeHint() const
{
return QSize(50, 50);
}
QSize CPlotter::sizeHint() const
{
return QSize(180, 180);
}
void CPlotter::resizeEvent(QResizeEvent* ) //resizeEvent()
{
if(!size().isValid()) return;
if( m_Size != size() or (m_bReference != m_bReference0) or
m_Percent2DScreen != m_Percent2DScreen0) {
m_Size = size();
m_w = m_Size.width();
m_h = m_Size.height();
m_h2 = m_Percent2DScreen*m_h/100.0;
if(m_h2>m_h-30) m_h2=m_h-30;
if(m_bReference) m_h2=m_h-30;
if(m_h2<1) m_h2=1;
m_h1=m_h-m_h2;
m_2DPixmap = QPixmap(m_Size.width(), m_h2);
m_2DPixmap.fill(Qt::black);
m_WaterfallPixmap = QPixmap(m_Size.width(), m_h1);
m_OverlayPixmap = QPixmap(m_Size.width(), m_h2);
m_OverlayPixmap.fill(Qt::black);
m_WaterfallPixmap.fill(Qt::black);
m_2DPixmap.fill(Qt::black);
m_ScalePixmap = QPixmap(m_w,30);
m_ScalePixmap.fill(Qt::white);
m_Percent2DScreen0 = m_Percent2DScreen;
}
DrawOverlay();
}
void CPlotter::paintEvent(QPaintEvent *) // paintEvent()
{
if(m_paintEventBusy) return;
m_paintEventBusy=true;
QPainter painter(this);
painter.drawPixmap(0,0,m_ScalePixmap);
painter.drawPixmap(0,30,m_WaterfallPixmap);
painter.drawPixmap(0,m_h1,m_2DPixmap);
m_paintEventBusy=false;
}
void CPlotter::draw(float swide[], bool bScroll, bool bRed)
{
int j,j0;
static int ktop=0;
float y,y2,ymin;
double fac = sqrt(m_binsPerPixel*m_waterfallAvg/15.0);
double gain = fac*pow(10.0,0.02*m_plotGain);
double gain2d = pow(10.0,0.02*(m_plot2dGain));
if(m_bReference != m_bReference0) resizeEvent(NULL);
m_bReference0=m_bReference;
//move current data down one line (must do this before attaching a QPainter object)
if(bScroll) m_WaterfallPixmap.scroll(0,1,0,0,m_w,m_h1);
QPainter painter1(&m_WaterfallPixmap);
m_2DPixmap = m_OverlayPixmap.copy(0,0,m_w,m_h2);
QPainter painter2D(&m_2DPixmap);
if(!painter2D.isActive()) return;
QFont Font("Arial");
Font.setPointSize(12);
Font.setWeight(QFont::Normal);
painter2D.setFont(Font);
if(m_bLinearAvg) {
painter2D.setPen(Qt::yellow);
} else if(m_bReference) {
painter2D.setPen(Qt::blue);
} else {
painter2D.setPen(Qt::green);
}
static QPoint LineBuf[MAX_SCREENSIZE];
static QPoint LineBuf2[MAX_SCREENSIZE];
j=0;
j0=int(m_startFreq/m_fftBinWidth + 0.5);
int iz=XfromFreq(5000.0);
int jz=iz*m_binsPerPixel;
m_fMax=FreqfromX(iz);
m_line++;
if(bScroll) {
flat4_(swide,&iz,&m_Flatten);
flat4_(&dec_data.savg[j0],&jz,&m_Flatten);
}
ymin=1.e30;
if(swide[0]>1.e29 and swide[0]< 1.5e30) painter1.setPen(Qt::green);
if(swide[0]>1.4e30) painter1.setPen(Qt::yellow);
for(int i=0; i<iz; i++) {
y=swide[i];
if(y<ymin) ymin=y;
int y1 = 10.0*gain*y + 10*m_plotZero +40;
if (y1<0) y1=0;
if (y1>254) y1=254;
if (swide[i]<1.e29) painter1.setPen(g_ColorTbl[y1]);
painter1.drawPoint(i,0);
}
float y2min=1.e30;
float y2max=-1.e30;
for(int i=0; i<iz; i++) {
y=swide[i] - ymin;
y2=0;
if(m_bCurrent) y2 = gain2d*y + m_plot2dZero; //Current
if(bScroll) {
float sum=0.0;
int j=j0+m_binsPerPixel*i;
for(int k=0; k<m_binsPerPixel; k++) {
sum+=dec_data.savg[j++];
}
m_sum[i]=sum;
}
if(m_bCumulative) y2=gain2d*(m_sum[i]/m_binsPerPixel + m_plot2dZero);
if(m_Flatten==0) y2 += 15; //### could do better! ###
if(m_bLinearAvg) { //Linear Avg (yellow)
float sum=0.0;
int j=j0+m_binsPerPixel*i;
for(int k=0; k<m_binsPerPixel; k++) {
sum+=spectra_.syellow[j++];
}
y2=gain2d*sum/m_binsPerPixel + m_plot2dZero;
}
if(m_bReference) { //Reference (red)
float df_ref=12000.0/6912.0;
int j=FreqfromX(i)/df_ref + 0.5;
y2=spectra_.ref[j] + m_plot2dZero;
// if(gain2d>1.5) y2=spectra_.filter[j] + m_plot2dZero;
}
if(i==iz-1) {
painter2D.drawPolyline(LineBuf,j);
if(m_mode=="QRA64") {
painter2D.setPen(Qt::red);
painter2D.drawPolyline(LineBuf2,ktop);
}
}
LineBuf[j].setX(i);
LineBuf[j].setY(int(0.9*m_h2-y2*m_h2/70.0));
if(y2<y2min) y2min=y2;
if(y2>y2max) y2max=y2;
j++;
}
if(swide[0]>1.0e29) m_line=0;
if(m_line == painter1.fontMetrics ().height ()) {
painter1.setPen(Qt::white);
QString t;
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
int n=(ms/1000) % m_TRperiod;
QDateTime t1=QDateTime::currentDateTimeUtc().addSecs(-n);
if(m_TRperiod < 60) {
t=t1.toString("hh:mm:ss") + " " + m_rxBand;
} else {
t=t1.toString("hh:mm") + " " + m_rxBand;
}
painter1.drawText (5, painter1.fontMetrics ().ascent (), t);
}
if(m_mode=="JT4" or m_mode=="QRA64") {
QPen pen3(Qt::yellow); //Mark freqs of JT4 single-tone msgs
painter2D.setPen(pen3);
Font.setWeight(QFont::Bold);
painter2D.setFont(Font);
int x1=XfromFreq(m_rxFreq);
y=0.2*m_h2;
painter2D.drawText(x1-4,y,"T");
x1=XfromFreq(m_rxFreq+250);
painter2D.drawText(x1-4,y,"M");
x1=XfromFreq(m_rxFreq+500);
painter2D.drawText(x1-4,y,"R");
x1=XfromFreq(m_rxFreq+750);
painter2D.drawText(x1-4,y,"73");
}
if(bRed) {
std::ifstream f;
f.open(m_redFile.toLatin1());
if(f) {
int x,y;
float freq,sync;
float slimit=6.0;
QPen pen0(Qt::red,1);
painter1.setPen(pen0);
for(int i=0; i<99999; i++) {
f >> freq >> sync;
if(f.eof()) break;
x=XfromFreq(freq);
y=(sync-slimit)*3.0;
if(y>0) {
if(y>15.0) y=15.0;
if(x>=0 and x<=m_w) {
painter1.setPen(pen0);
painter1.drawLine(x,0,x,y);
}
}
}
f.close();
}
// m_bDecodeFinished=false;
}
update(); //trigger a new paintEvent
m_bScaleOK=true;
}
void CPlotter::drawRed(int ia, int ib, float swide[])
{
m_ia=ia;
m_ib=ib;
draw(swide,false,true);
}
void CPlotter::DrawOverlay() //DrawOverlay()
{
if(m_OverlayPixmap.isNull()) return;
if(m_WaterfallPixmap.isNull()) return;
int w = m_WaterfallPixmap.width();
int x,y,x1,x2,x3,x4,x5,x6;
float pixperdiv;
double df = m_binsPerPixel*m_fftBinWidth;
QRect rect;
QPen penOrange(QColor(255,165,0),3);
QPen penGreen(Qt::green, 3); //Mark Tol range with green line
QPen penRed(Qt::red, 3); //Mark Tx freq with red
QPainter painter(&m_OverlayPixmap);
painter.initFrom(this);
QLinearGradient gradient(0, 0, 0 ,m_h2); //fill background with gradient
gradient.setColorAt(1, Qt::black);
gradient.setColorAt(0, Qt::darkBlue);
painter.setBrush(gradient);
painter.drawRect(0, 0, m_w, m_h2);
painter.setBrush(Qt::SolidPattern);
m_fSpan = w*df;
// int n=m_fSpan/10;
m_freqPerDiv=10;
if(m_fSpan>100) m_freqPerDiv=20;
if(m_fSpan>250) m_freqPerDiv=50;
if(m_fSpan>500) m_freqPerDiv=100;
if(m_fSpan>1000) m_freqPerDiv=200;
if(m_fSpan>2500) m_freqPerDiv=500;
pixperdiv = m_freqPerDiv/df;
m_hdivs = w*df/m_freqPerDiv + 1.9999;
float xx0=float(m_startFreq)/float(m_freqPerDiv);
xx0=xx0-int(xx0);
int x0=xx0*pixperdiv+0.5;
for( int i=1; i<m_hdivs; i++) { //draw vertical grids
x = (int)((float)i*pixperdiv ) - x0;
if(x >= 0 and x<=m_w) {
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
painter.drawLine(x, 0, x , m_h2);
}
}
pixperdiv = (float)m_h2 / (float)VERT_DIVS;
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
for( int i=1; i<VERT_DIVS; i++) { //draw horizontal grids
y = (int)( (float)i*pixperdiv );
painter.drawLine(0, y, w, y);
}
QRect rect0;
QPainter painter0(&m_ScalePixmap);
painter0.initFrom(this);
//create Font to use for scales
QFont Font("Arial");
Font.setPointSize(12);
Font.setWeight(QFont::Normal);
painter0.setFont(Font);
painter0.setPen(Qt::black);
if(m_binsPerPixel < 1) m_binsPerPixel=1;
m_hdivs = w*df/m_freqPerDiv + 0.9999;
m_ScalePixmap.fill(Qt::white);
painter0.drawRect(0, 0, w, 30);
MakeFrequencyStrs();
//draw tick marks on upper scale
pixperdiv = m_freqPerDiv/df;
for( int i=0; i<m_hdivs; i++) { //major ticks
x = (int)((m_xOffset+i)*pixperdiv );
painter0.drawLine(x,18,x,30);
}
int minor=5;
if(m_freqPerDiv==200) minor=4;
for( int i=1; i<minor*m_hdivs; i++) { //minor ticks
x = i*pixperdiv/minor;
painter0.drawLine(x,24,x,30);
}
//draw frequency values
for( int i=0; i<=m_hdivs; i++) {
x = (int)((m_xOffset+i)*pixperdiv - pixperdiv/2);
rect0.setRect(x,0, (int)pixperdiv, 20);
painter0.drawText(rect0, Qt::AlignHCenter|Qt::AlignVCenter,m_HDivText[i]);
}
float bw=9.0*12000.0/m_nsps; //JT9
if(m_mode=="FT8") bw=8*12000.0/1920.0; //FT8
if(m_mode=="JT4") { //JT4
bw=3*11025.0/2520.0; //Max tone spacing (3/4 of actual BW)
if(m_nSubMode==1) bw=2*bw;
if(m_nSubMode==2) bw=4*bw;
if(m_nSubMode==3) bw=9*bw;
if(m_nSubMode==4) bw=18*bw;
if(m_nSubMode==5) bw=36*bw;
if(m_nSubMode==6) bw=72*bw;
painter0.setPen(penGreen);
x1=XfromFreq(m_rxFreq-m_tol);
x2=XfromFreq(m_rxFreq+m_tol);
painter0.drawLine(x1,29,x2,29);
for(int i=0; i<4; i++) {
x1=XfromFreq(m_rxFreq+bw*i/3.0);
int j=24;
if(i==0) j=18;
painter0.drawLine(x1,j,x1,30);
}
painter0.setPen(penRed);
for(int i=0; i<4; i++) {
x1=XfromFreq(m_txFreq+bw*i/3.0);
painter0.drawLine(x1,12,x1,18);
}
}
if(m_modeTx=="JT9" and m_nSubMode>0) { //JT9
bw=8.0*12000.0/m_nsps;
if(m_nSubMode==1) bw=2*bw; //B
if(m_nSubMode==2) bw=4*bw; //C
if(m_nSubMode==3) bw=8*bw; //D
if(m_nSubMode==4) bw=16*bw; //E
if(m_nSubMode==5) bw=32*bw; //F
if(m_nSubMode==6) bw=64*bw; //G
if(m_nSubMode==7) bw=128*bw; //H
}
if(m_mode=="QRA64") { //QRA64
bw=63.0*12000.0/m_nsps;
if(m_nSubMode==1) bw=2*bw; //B
if(m_nSubMode==2) bw=4*bw; //C
if(m_nSubMode==3) bw=8*bw; //D
if(m_nSubMode==4) bw=16*bw; //E
}
if(m_modeTx=="JT65") { //JT65
bw=65.0*11025.0/4096.0;
if(m_nSubMode==1) bw=2*bw; //B
if(m_nSubMode==2) bw=4*bw; //C
}
painter0.setPen(penGreen);
if(m_mode=="WSPR") {
x1=XfromFreq(1400);
x2=XfromFreq(1600);
painter0.drawLine(x1,29,x2,29);
}
if(m_mode=="WSPR-LF") {
x1=XfromFreq(1600);
x2=XfromFreq(1700);
painter0.drawLine(x1,29,x2,29);
}
if(m_mode=="FreqCal") { //FreqCal
x1=XfromFreq(m_rxFreq-m_tol);
x2=XfromFreq(m_rxFreq+m_tol);
painter0.drawLine(x1,29,x2,29);
x1=XfromFreq(m_rxFreq);
painter0.drawLine(x1,24,x1,30);
}
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or m_mode=="QRA64" or m_mode=="FT8") {
if(m_mode=="QRA64" or (m_mode=="JT65" and m_bVHF)) {
painter0.setPen(penGreen);
x1=XfromFreq(m_rxFreq-m_tol);
x2=XfromFreq(m_rxFreq+m_tol);
painter0.drawLine(x1,28,x2,28);
x1=XfromFreq(m_rxFreq);
painter0.drawLine(x1,24,x1,30);
if(m_mode=="JT65") {
painter0.setPen(penOrange);
x3=XfromFreq(m_rxFreq+20.0*bw/65.0); //RO
painter0.drawLine(x3,24,x3,30);
x4=XfromFreq(m_rxFreq+30.0*bw/65.0); //RRR
painter0.drawLine(x4,24,x4,30);
x5=XfromFreq(m_rxFreq+40.0*bw/65.0); //73
painter0.drawLine(x5,24,x5,30);
}
painter0.setPen(penGreen);
x6=XfromFreq(m_rxFreq+bw); //Highest tone
painter0.drawLine(x6,24,x6,30);
} else {
painter0.setPen(penGreen);
x1=XfromFreq(m_rxFreq);
x2=XfromFreq(m_rxFreq+bw);
painter0.drawLine(x1,24,x1,30);
painter0.drawLine(x1,28,x2,28);
painter0.drawLine(x2,24,x2,30);
}
}
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or
m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="FT8") {
painter0.setPen(penRed);
x1=XfromFreq(m_txFreq);
x2=XfromFreq(m_txFreq+bw);
if(m_mode=="WSPR") {
bw=4*12000.0/8192.0; //WSPR
x1=XfromFreq(m_txFreq-0.5*bw);
x2=XfromFreq(m_txFreq+0.5*bw);
}
if(m_mode=="WSPR-LF") {
bw=3*12000.0/8640.0; //WSPR-LF
x1=XfromFreq(m_txFreq-0.5*bw);
x2=XfromFreq(m_txFreq+0.5*bw);
}
painter0.drawLine(x1,17,x1,21);
painter0.drawLine(x1,17,x2,17);
painter0.drawLine(x2,17,x2,21);
}
if(m_mode=="JT9+JT65") {
QPen pen2(Qt::blue, 3); //Mark the JT65 | JT9 divider
painter0.setPen(pen2);
x1=XfromFreq(m_fMin);
if(x1<2) x1=2;
x2=x1+30;
painter0.drawLine(x1,8,x1,28);
}
if(m_dialFreq>10.13 and m_dialFreq< 10.15 and m_mode.mid(0,4)!="WSPR") {
float f1=1.0e6*(10.1401 - m_dialFreq);
float f2=f1+200.0;
x1=XfromFreq(f1);
x2=XfromFreq(f2);
if(x1<=m_w and x2>=0) {
painter0.setPen(penOrange); //Mark WSPR sub-band orange
painter0.drawLine(x1,9,x2,9);
}
}
}
void CPlotter::MakeFrequencyStrs() //MakeFrequencyStrs
{
int f=(m_startFreq+m_freqPerDiv-1)/m_freqPerDiv;
f*=m_freqPerDiv;
m_xOffset=float(f-m_startFreq)/m_freqPerDiv;
for(int i=0; i<=m_hdivs; i++) {
m_HDivText[i].setNum(f);
f+=m_freqPerDiv;
}
}
int CPlotter::XfromFreq(float f) //XfromFreq()
{
// float w = m_WaterfallPixmap.width();
int x = int(m_w * (f - m_startFreq)/m_fSpan + 0.5);
if(x<0 ) return 0;
if(x>m_w) return m_w;
return x;
}
float CPlotter::FreqfromX(int x) //FreqfromX()
{
return float(m_startFreq + x*m_binsPerPixel*m_fftBinWidth);
}
void CPlotter::SetRunningState(bool running) //SetRunningState()
{
m_Running = running;
}
void CPlotter::setPlotZero(int plotZero) //setPlotZero()
{
m_plotZero=plotZero;
}
int CPlotter::plotZero() //PlotZero()
{
return m_plotZero;
}
void CPlotter::setPlotGain(int plotGain) //setPlotGain()
{
m_plotGain=plotGain;
}
int CPlotter::plotGain() //plotGain()
{
return m_plotGain;
}
int CPlotter::plot2dGain() //plot2dGain
{
return m_plot2dGain;
}
void CPlotter::setPlot2dGain(int n) //setPlot2dGain
{
m_plot2dGain=n;
update();
}
int CPlotter::plot2dZero() //plot2dZero
{
return m_plot2dZero;
}
void CPlotter::setPlot2dZero(int plot2dZero) //setPlot2dZero
{
m_plot2dZero=plot2dZero;
}
void CPlotter::setStartFreq(int f) //SetStartFreq()
{
m_startFreq=f;
resizeEvent(NULL);
update();
}
int CPlotter::startFreq() //startFreq()
{
return m_startFreq;
}
int CPlotter::plotWidth(){return m_WaterfallPixmap.width();} //plotWidth
void CPlotter::UpdateOverlay() {DrawOverlay();} //UpdateOverlay
void CPlotter::setDataFromDisk(bool b) {m_dataFromDisk=b;} //setDataFromDisk
void CPlotter::setRxRange(int fMin) //setRxRange
{
m_fMin=fMin;
}
void CPlotter::setBinsPerPixel(int n) //setBinsPerPixel
{
m_binsPerPixel = n;
DrawOverlay(); //Redraw scales and ticks
update(); //trigger a new paintEvent}
}
int CPlotter::binsPerPixel() //binsPerPixel
{
return m_binsPerPixel;
}
void CPlotter::setWaterfallAvg(int n) //setBinsPerPixel
{
m_waterfallAvg = n;
}
void CPlotter::setRxFreq (int x) //setRxFreq
{
m_rxFreq = x; // x is freq in Hz
DrawOverlay();
update();
}
int CPlotter::rxFreq() {return m_rxFreq;} //rxFreq
void CPlotter::mousePressEvent(QMouseEvent *event) //mousePressEvent
{
int x=event->x();
if(x<0) x=0;
if(x>m_Size.width()) x=m_Size.width();
bool ctrl = (event->modifiers() & Qt::ControlModifier);
bool shift = (event->modifiers() & Qt::ShiftModifier);
int newFreq = int(FreqfromX(x)+0.5);
int oldTxFreq = m_txFreq;
int oldRxFreq = m_rxFreq;
if (ctrl or m_lockTxFreq) {
emit setFreq1 (newFreq, newFreq);
}
else if (shift) {
emit setFreq1 (oldRxFreq, newFreq);
}
else {
emit setFreq1(newFreq,oldTxFreq);
}
int n=1;
if(ctrl) n+=100;
emit freezeDecode1(n);
}
void CPlotter::mouseDoubleClickEvent(QMouseEvent *event) //mouse2click
{
bool ctrl = (event->modifiers() & Qt::ControlModifier);
int n=2;
if(ctrl) n+=100;
emit freezeDecode1(n);
}
void CPlotter::setNsps(int ntrperiod, int nsps) //setNsps
{
m_TRperiod=ntrperiod;
m_nsps=nsps;
m_fftBinWidth=1500.0/2048.0;
if(m_nsps==15360) m_fftBinWidth=1500.0/2048.0;
if(m_nsps==40960) m_fftBinWidth=1500.0/6144.0;
if(m_nsps==82944) m_fftBinWidth=1500.0/12288.0;
if(m_nsps==252000) m_fftBinWidth=1500.0/32768.0;
DrawOverlay(); //Redraw scales and ticks
update(); //trigger a new paintEvent}
}
void CPlotter::setTxFreq(int n) //setTxFreq
{
m_txFreq=n;
DrawOverlay();
update();
}
void CPlotter::setMode(QString mode) //setMode
{
m_mode=mode;
}
void CPlotter::setSubMode(int n) //setSubMode
{
m_nSubMode=n;
}
void CPlotter::setModeTx(QString modeTx) //setModeTx
{
m_modeTx=modeTx;
}
int CPlotter::Fmax()
{
return m_fMax;
}
void CPlotter::setDialFreq(double d)
{
m_dialFreq=d;
DrawOverlay();
update();
}
void CPlotter::setRxBand(QString band)
{
m_rxBand=band;
}
void CPlotter::setFlatten(bool b1, bool b2)
{
m_Flatten=0;
if(b1) m_Flatten=1;
if(b2) m_Flatten=2;
}
void CPlotter::setTol(int n) //setTol()
{
m_tol=n;
DrawOverlay();
}
void CPlotter::setColours(QVector<QColor> const& cl)
{
g_ColorTbl = cl;
}
void CPlotter::SetPercent2DScreen(int percent)
{
m_Percent2DScreen=percent;
resizeEvent(NULL);
update();
}
void CPlotter::setVHF(bool bVHF)
{
m_bVHF=bVHF;
}
void CPlotter::setRedFile(QString fRed)
{
m_redFile=fRed;
}
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
ports *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
@@ -5,9 +5,9 @@
</tr> </tr>
<tr> <tr>
<td align="right">Waterfall:</td> <td align="right">Waterfall:</td>
<td><b>Click</b> to set the Rx frequency.<br/> <td><b>Click</b> to set Rx frequency.<br/>
<b>Shift-click</b> to set Tx frequency.<br/> <b>Shift-click</b> to set Tx frequency.<br/>
<b>Ctrl-click</b> to set Rx and Tx frequencies.<br/> <b>Ctrl-click</b> or <b>Right-click</b> to set Rx and Tx frequencies.<br/>
<b>Double-click</b> to also decode at Rx frequency.<br/> <b>Double-click</b> to also decode at Rx frequency.<br/>
</td> </td>
</tr> </tr>
@@ -1,33 +0,0 @@
<table cellspacing=1>
<tr><td><b>F1 </b></td><td>Online User's Guide</td></tr>
<tr><td><b>Ctrl+F1 </b></td><td>About WSJT-X</td></tr>
<tr><td><b>F2 </b></td><td>Open configuration window</td></tr>
<tr><td><b>F3 </b></td><td>Display keyboard shortcuts</td></tr>
<tr><td><b>F4 </b></td><td>Clear DX Call, DX Grid, Tx messages 1-5</td></tr>
<tr><td><b>Alt+F4 </b></td><td>Exit program</td></tr>
<tr><td><b>F5 </b></td><td>Display special mouse commands</td></tr>
<tr><td><b>F6 </b></td><td>Open next file in directory</td></tr>
<tr><td><b>F7 </b></td><td>Display Message Averaging window</td></tr>
<tr><td><b>Shift+F6 </b></td><td>Decode all remaining files in directrory</td></tr>
<tr><td><b>F11 </b></td><td>Move Rx frequency down 1 Hz</td></tr>
<tr><td><b>Ctrl+F11 </b></td><td>Move Rx and Tx frequencies down 1 Hz</td></tr>
<tr><td><b>F12 </b></td><td>Move Rx frequency up 1 Hz</td></tr>
<tr><td><b>Ctrl+F12 </b></td><td>Move Rx and Tx frequencies up 1 Hz</td></tr>
<tr><td><b>Alt+1-6 </b></td><td>Set now transmission to this number on Tab 1</td></tr>
<tr><td><b>Ctl+1-6 </b></td><td>Set next transmission to this number on Tab 1</td></tr>
<tr><td><b>Alt+D </b></td><td>Decode again at QSO frequency</td></tr>
<tr><td><b>Shift+D </b></td><td>Full decode (both windows)</td></tr>
<tr><td><b>Alt+E </b></td><td>Erase</td></tr>
<tr><td><b>Ctrl+F </b></td><td>Edit the free text message box</td></tr>
<tr><td><b>Alt+G </b></td><td>Generate standard messages</td></tr>
<tr><td><b>Alt+H </b></td><td>Halt Tx</td></tr>
<tr><td><b>Ctrl+L </b></td><td>Lookup callsign in database, generate standard messages</td></tr>
<tr><td><b>Alt+M </b></td><td>Monitor</td></tr>
<tr><td><b>Ctrl+M </b></td><td>Minimize window size by hiding some controls</td></tr>
<tr><td><b>Alt+N </b></td><td>Enable Tx</td></tr>
<tr><td><b>Ctrl+O </b></td><td>Open a .wav file</td></tr>
<tr><td><b>Alt+Q </b></td><td>Log QSO</td></tr>
<tr><td><b>Alt+S </b></td><td>Stop monitoring</td></tr>
<tr><td><b>Alt+T </b></td><td>Tune</td></tr>
<tr><td><b>Alt+V </b></td><td>Save the most recently completed *.wav file</td></tr>
</table>
@@ -0,0 +1,16 @@
#ifndef BOOST_THREAD_THREAD_HPP
#define BOOST_THREAD_THREAD_HPP
// thread.hpp
//
// (C) Copyright 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/thread_only.hpp>
#include <boost/thread/detail/thread_group.hpp>
#endif
@@ -1,124 +0,0 @@
#!/bin/sh
# These tests investigate what happens when the wrong model is used for
# decoding. A (1800,1000) LDPC code with 3 check per bit is used.
# Testing is done by transmitting random messages. Decoding is done using
# a maximum of 100 iterations of probability propagation.
#
# The first set of tests compares decoding of messages sent through an
# AWGN channel using the correct AWGN model with sigma=0.90 to decoding
# using AWGN models with incorrect values for sigma and to decoding
# using AWLN models with varying width parameters for the logistic noise
# distribution.
#
# A second set of tests compares decoding of messages sent through an
# AWLN channel using the correct AWLN model with width=0.50 to decoding
# using AWLN models with incorrect values for width and to decoding
# using AWGN models with varying sigma parameters.
set -e # Stop if an error occurs
set -v # Echo commands as they are read
make-ldpc ex-wrong-model.pchk 1000 1800 1 evenboth 3 no4cycle
make-gen ex-wrong-model.pchk ex-wrong-model.gen dense
rand-src ex-wrong-model.src 1 800x1000
encode ex-wrong-model.pchk ex-wrong-model.gen ex-wrong-model.src \
ex-wrong-model.enc
# FIRST SET OF TESTS, TRANSMITTING THROUGH AWGN CHANNEL WITH SIGMA=0.90
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awgn 0.90
# DECODING WITH CORRECT AWGN NOISE MODEL, SIGMA=0.90
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.40
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.40 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.50
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.60
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.60 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.65
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.65 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# SECOND SET OF TESTS, TRANSMITTING THROUGH AWLN CHANNEL WITH WIDTH=0.50
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awln 0.50
# DECODING WITH CORRECT AWLN NOISE MODEL, WIDTH=0.50
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.80
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.80 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.90
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.00
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.00 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.05
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.05 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
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.
@@ -25,7 +25,7 @@ if( first ) then ! fill the generator matrix
read(g(i)(j:j),"(Z1)") istr read(g(i)(j:j),"(Z1)") istr
do jj=1, 4 do jj=1, 4
irow=(j-1)*4+jj irow=(j-1)*4+jj
if( btest(istr,4-jj) ) gen(irow,i)=1 if( btest(istr,4-jj) ) gen(irow,i)=1
enddo enddo
enddo enddo
enddo enddo
@@ -139,15 +139,9 @@ elseif(ndeep.eq.5) then
endif endif
do iorder=1,nord do iorder=1,nord
if( iorder.eq. 1 ) then misub(1:K-iorder)=0
misub(1:K-1)=0 misub(K-iorder+1:K)=1
misub(K)=1 iflag=K-iorder+1
iflag=K
elseif( iorder.eq. 2 ) then
misub(1:K-2)=0
misub(K-1:K)=1
iflag=K-1
endif
do while(iflag .ge.0) do while(iflag .ge.0)
if(iorder.eq.nord .and. npre1.eq.0) then if(iorder.eq.nord .and. npre1.eq.0) then
iend=iflag iend=iflag
@@ -209,15 +203,9 @@ if(npre2.eq.1) then
ntotal2=0 ntotal2=0
reset=.true. reset=.true.
! Now run through again and do the second pre-processing rule ! Now run through again and do the second pre-processing rule
if(nord.eq.1) then misub(1:K-nord)=0
misub(1:K-1)=0 misub(K-nord+1:K)=1
misub(K)=1 iflag=K-nord+1
iflag=K
elseif(nord.eq.2) then
misub(1:K-1)=0
misub(K-1:K)=1
iflag=K-1
endif
do while(iflag .ge.0) do while(iflag .ge.0)
me=ieor(m0,misub) me=ieor(m0,misub)
call mrbencode(me,ce,g2,N,K) call mrbencode(me,ce,g2,N,K)
@@ -255,7 +243,7 @@ endif
! Re-order the codeword to place message bits at the end. ! Re-order the codeword to place message bits at the end.
cw(indices)=cw cw(indices)=cw
hdec(indices)=hdec hdec(indices)=hdec
decoded=cw(K+1:N) decoded=cw(M+1:N)
cw(colorder+1)=cw ! put the codeword back into received-word order cw(colorder+1)=cw ! put the codeword back into received-word order
return return
end subroutine osd174 end subroutine osd174
File diff suppressed because it is too large Load Diff
@@ -1,10 +1,12 @@
subroutine decode65b(s2,nflip,nadd,mode65,ntrials,naggressive,ndepth, & subroutine decode65b(s2,nflip,nadd,mode65,ntrials,naggressive,ndepth, &
mycall,hiscall,hisgrid,nexp_decode,nqd,nft,qual,nhist,decoded) mycall,hiscall,hisgrid,nQSOProgress,ljt65apon,nexp_decode,nqd, &
nft,qual, &
nhist,decoded)
use jt65_mod use jt65_mod
real s2(66,126) real s2(66,126)
real s3(64,63) real s3(64,63)
logical ltext logical ltext,ljt65apon
character decoded*22 character decoded*22
character mycall*12,hiscall*12,hisgrid*6 character mycall*12,hiscall*12,hisgrid*6
save save
@@ -19,7 +21,8 @@ subroutine decode65b(s2,nflip,nadd,mode65,ntrials,naggressive,ndepth, &
enddo enddo
call extract(s3,nadd,mode65,ntrials,naggressive,ndepth,nflip,mycall, & call extract(s3,nadd,mode65,ntrials,naggressive,ndepth,nflip,mycall, &
hiscall,hisgrid,nexp_decode,ncount,nhist,decoded,ltext,nft,qual) hiscall,hisgrid,nQSOProgress,ljt65apon,nexp_decode,ncount, &
nhist,decoded,ltext,nft,qual)
! Suppress "birdie messages" and other garbage decodes: ! Suppress "birdie messages" and other garbage decodes:
if(decoded(1:7).eq.'000AAA ') ncount=-1 if(decoded(1:7).eq.'000AAA ') ncount=-1
@@ -1,415 +0,0 @@
/* MAKE-LDPC.C - Make a Low Density Parity Check code's parity check matrix. */
/* Copyright (c) 1995-2012 by Radford M. Neal and Peter Junteng Liu.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "rand.h"
#include "alloc.h"
#include "intio.h"
#include "open.h"
#include "mod2sparse.h"
#include "mod2dense.h"
#include "mod2convert.h"
#include "rcode.h"
#include "distrib.h"
/* METHODS FOR CONSTRUCTING CODES. */
typedef enum
{ Evencol, /* Uniform number of bits per column, with number specified */
Evenboth /* Uniform (as possible) over both columns and rows */
} make_method;
void make_ldpc (int, make_method, distrib *, int);
int *column_partition (distrib *, int);
void usage (void);
/* MAIN PROGRAM. */
int main
( int argc,
char **argv
)
{
make_method method;
char *file, **meth;
int seed, no4cycle;
distrib *d;
char junk;
FILE *f;
/* Look at initial arguments. */
if (!(file = argv[1])
|| !argv[2] || sscanf(argv[2],"%d%c",&M,&junk)!=1 || M<=0
|| !argv[3] || sscanf(argv[3],"%d%c",&N,&junk)!=1 || N<=0
|| !argv[4] || sscanf(argv[4],"%d%c",&seed,&junk)!=1)
{ usage();
}
/* Look at the arguments specifying the method for producing the code. */
meth = argv+5;
if (!meth[0]) usage();
no4cycle = 0;
if (strcmp(meth[0],"evencol")==0 || strcmp(meth[0],"evenboth")==0)
{ method = strcmp(meth[0],"evencol")==0 ? Evencol : Evenboth;
if (!meth[1])
{ usage();
}
d = distrib_create(meth[1]);
if (d==0)
{ usage();
}
if (meth[2])
{ if (strcmp(meth[2],"no4cycle")==0)
{ no4cycle = 1;
if (meth[3])
{ usage();
}
}
else
{ usage();
}
}
}
else
{ usage();
}
/* Check for some problems. */
if (distrib_max(d)>M)
{ fprintf(stderr,
"At least one checks per bit (%d) is greater than total checks (%d)\n",
distrib_max(d), M);
exit(1);
}
if (distrib_max(d)==M && N>1 && no4cycle)
{ fprintf(stderr,
"Can't eliminate cycles of length four with this many checks per bit\n");
exit(1);
}
/* Make the parity check matrix. */
make_ldpc(seed,method,d,no4cycle);
/* Write out the parity check matrix. */
f = open_file_std(file,"wb");
if (f==NULL)
{ fprintf(stderr,"Can't create parity check file: %s\n",file);
exit(1);
}
intio_write(f,('P'<<8)+0x80);
if (ferror(f) || !mod2sparse_write(f,H) || fclose(f)!=0)
{ fprintf(stderr,"Error writing to parity check file %s\n",file);
exit(1);
}
return 0;
}
/* PRINT USAGE MESSAGE AND EXIT. */
void usage(void)
{ fprintf(stderr,"Usage: make-ldpc pchk-file n-checks n-bits seed method\n");
fprintf(stderr,"Method: evencol checks-per-col [ \"no4cycle\" ]\n");
fprintf(stderr," or: evencol checks-distribution [ \"no4cycle\" ]\n");
fprintf(stderr," or: evenboth checks-per-col [ \"no4cycle\" ]\n");
fprintf(stderr," or: evenboth checks-distribution [ \"no4cycle\" ]\n");
exit(1);
}
/* CREATE A SPARSE PARITY-CHECK MATRIX. Of size M by N, stored in H. */
void make_ldpc
( int seed, /* Random number seed */
make_method method, /* How to make it */
distrib *d, /* Distribution list specified */
int no4cycle /* Eliminate cycles of length four? */
)
{
mod2entry *e, *f, *g, *h;
int added, uneven, elim4, all_even, n_full, left;
int i, j, k, t, z, cb_N;
int *part, *u;
rand_seed(10*seed+1);
H = mod2sparse_allocate(M,N);
part = column_partition(d,N);
/* Create the initial version of the parity check matrix. */
switch (method)
{
case Evencol:
{
z = 0;
left = part[z];
for (j = 0; j<N; j++)
{ while (left==0)
{ z += 1;
if (z>distrib_size(d))
{ abort();
}
left = part[z];
}
for (k = 0; k<distrib_num(d,z); k++)
{ do
{ i = rand_int(M);
} while (mod2sparse_find(H,i,j));
mod2sparse_insert(H,i,j);
}
left -= 1;
}
break;
}
case Evenboth:
{
cb_N = 0;
for (z = 0; z<distrib_size(d); z++)
{ cb_N += distrib_num(d,z) * part[z];
}
u = chk_alloc (cb_N, sizeof *u);
for (k = cb_N-1; k>=0; k--)
{ u[k] = k%M;
}
uneven = 0;
t = 0;
z = 0;
left = part[z];
for (j = 0; j<N; j++)
{
while (left==0)
{ z += 1;
if (z>distrib_size(d))
{ abort();
}
left = part[z];
}
for (k = 0; k<distrib_num(d,z); k++)
{
for (i = t; i<cb_N && mod2sparse_find(H,u[i],j); i++) ;
if (i==cb_N)
{ uneven += 1;
do
{ i = rand_int(M);
} while (mod2sparse_find(H,i,j));
mod2sparse_insert(H,i,j);
}
else
{ do
{ i = t + rand_int(cb_N-t);
} while (mod2sparse_find(H,u[i],j));
mod2sparse_insert(H,u[i],j);
u[i] = u[t];
t += 1;
}
}
left -= 1;
}
if (uneven>0)
{ fprintf(stderr,"Had to place %d checks in rows unevenly\n",uneven);
}
break;
}
default: abort();
}
/* Add extra bits to avoid rows with less than two checks. */
added = 0;
for (i = 0; i<M; i++)
{ e = mod2sparse_first_in_row(H,i);
if (mod2sparse_at_end(e))
{ j = rand_int(N);
e = mod2sparse_insert(H,i,j);
added += 1;
}
e = mod2sparse_first_in_row(H,i);
if (mod2sparse_at_end(mod2sparse_next_in_row(e)) && N>1)
{ do
{ j = rand_int(N);
} while (j==mod2sparse_col(e));
mod2sparse_insert(H,i,j);
added += 1;
}
}
if (added>0)
{ fprintf(stderr,
"Added %d extra bit-checks to make row counts at least two\n",
added);
}
/* Add extra bits to try to avoid problems with even column counts. */
n_full = 0;
all_even = 1;
for (z = 0; z<distrib_size(d); z++)
{ if (distrib_num(d,z)==M)
{ n_full += part[z];
}
if (distrib_num(d,z)%2==1)
{ all_even = 0;
}
}
if (all_even && N-n_full>1 && added<2)
{ int a;
for (a = 0; added+a<2; a++)
{ do
{ i = rand_int(M);
j = rand_int(N);
} while (mod2sparse_find(H,i,j));
mod2sparse_insert(H,i,j);
}
fprintf(stderr,
"Added %d extra bit-checks to try to avoid problems from even column counts\n",
a);
}
/* Eliminate cycles of length four, if asked, and if possible. */
if (no4cycle)
{
elim4 = 0;
for (t = 0; t<10; t++)
{ k = 0;
for (j = 0; j<N; j++)
{ for (e = mod2sparse_first_in_col(H,j);
!mod2sparse_at_end(e);
e = mod2sparse_next_in_col(e))
{ for (f = mod2sparse_first_in_row(H,mod2sparse_row(e));
!mod2sparse_at_end(f);
f = mod2sparse_next_in_row(f))
{ if (f==e) continue;
for (g = mod2sparse_first_in_col(H,mod2sparse_col(f));
!mod2sparse_at_end(g);
g = mod2sparse_next_in_col(g))
{ if (g==f) continue;
for (h = mod2sparse_first_in_row(H,mod2sparse_row(g));
!mod2sparse_at_end(h);
h = mod2sparse_next_in_row(h))
{ if (mod2sparse_col(h)==j)
{ do
{ i = rand_int(M);
} while (mod2sparse_find(H,i,j));
mod2sparse_delete(H,e);
mod2sparse_insert(H,i,j);
elim4 += 1;
k += 1;
goto nextj;
}
}
}
}
}
nextj: ;
}
if (k==0) break;
}
if (elim4>0)
{ fprintf(stderr,
"Eliminated %d cycles of length four by moving checks within column\n",
elim4);
}
if (t==10)
{ fprintf(stderr,
"Couldn't eliminate all cycles of length four in 10 passes\n");
}
}
}
/* PARTITION THE COLUMNS ACCORDING TO THE SPECIFIED PROPORTIONS. It
may not be possible to do this exactly. Returns a pointer to an
array of integers containing the numbers of columns corresponding
to the entries in the distribution passed. */
int *column_partition
( distrib *d, /* List of proportions and number of check-bits */
int n /* Total number of columns to partition */
)
{
double *trunc;
int *part;
int cur, used;
int i, j;
trunc = chk_alloc (distrib_size(d), sizeof(double));
part = chk_alloc (distrib_size(d), sizeof(int));
used = 0;
for (i = 0; i<distrib_size(d); i++)
{ cur = floor(distrib_prop(d,i)*n);
part[i] = cur;
trunc[i] = distrib_prop(d,i)*n - cur;
used += cur;
}
if (used>n)
{ abort();
}
while (used<n)
{ cur = 0;
for (j = 1; j<distrib_size(d); j++)
{ if (trunc[j]>trunc[cur])
{ cur = j;
}
}
part[cur] += 1;
used += 1;
trunc[cur] = -1;
}
free(trunc);
return part;
}
@@ -1,269 +0,0 @@
#include "ClientWidget.hpp"
#include <QRegExp>
#include <QColor>
namespace
{
//QRegExp message_alphabet {"[- A-Za-z0-9+./?]*"};
QRegExp message_alphabet {"[- @A-Za-z0-9+./?#<>]*"};
QRegularExpression cq_re {"(CQ|CQDX|QRZ)[^A-Z0-9/]+"};
void update_dynamic_property (QWidget * widget, char const * property, QVariant const& value)
{
widget->setProperty (property, value);
widget->style ()->unpolish (widget);
widget->style ()->polish (widget);
widget->update ();
}
}
ClientWidget::IdFilterModel::IdFilterModel (QString const& client_id)
: client_id_ {client_id}
, rx_df_ (-1)
{
}
QVariant ClientWidget::IdFilterModel::data (QModelIndex const& proxy_index, int role) const
{
if (role == Qt::BackgroundRole)
{
switch (proxy_index.column ())
{
case 6: // message
{
auto message = QSortFilterProxyModel::data (proxy_index).toString ();
if (base_call_re_.pattern ().size ()
&& message.contains (base_call_re_))
{
return QColor {255,200,200};
}
if (message.contains (cq_re))
{
return QColor {200, 255, 200};
}
}
break;
case 4: // DF
if (qAbs (QSortFilterProxyModel::data (proxy_index).toInt () - rx_df_) <= 10)
{
return QColor {255, 200, 200};
}
break;
default:
break;
}
}
return QSortFilterProxyModel::data (proxy_index, role);
}
bool ClientWidget::IdFilterModel::filterAcceptsRow (int source_row
, QModelIndex const& source_parent) const
{
auto source_index_col0 = sourceModel ()->index (source_row, 0, source_parent);
return sourceModel ()->data (source_index_col0).toString () == client_id_;
}
void ClientWidget::IdFilterModel::de_call (QString const& call)
{
if (call != call_)
{
beginResetModel ();
if (call.size ())
{
base_call_re_.setPattern ("[^A-Z0-9]*" + Radio::base_callsign (call) + "[^A-Z0-9]*");
}
else
{
base_call_re_.setPattern (QString {});
}
call_ = call;
endResetModel ();
}
}
void ClientWidget::IdFilterModel::rx_df (int df)
{
if (df != rx_df_)
{
beginResetModel ();
rx_df_ = df;
endResetModel ();
}
}
namespace
{
QString make_title (QString const& id, QString const& version, QString const& revision)
{
QString title {id};
if (version.size ())
{
title += QString {" v%1"}.arg (version);
}
if (revision.size ())
{
title += QString {" (%1)"}.arg (revision);
}
return title;
}
}
ClientWidget::ClientWidget (QAbstractItemModel * decodes_model, QAbstractItemModel * beacons_model
, QString const& id, QString const& version, QString const& revision
, QWidget * parent)
: QDockWidget {make_title (id, version, revision), parent}
, id_ {id}
, decodes_proxy_model_ {id_}
, decodes_table_view_ {new QTableView}
, beacons_table_view_ {new QTableView}
, message_line_edit_ {new QLineEdit}
, decodes_stack_ {new QStackedLayout}
, auto_off_button_ {new QPushButton {tr ("&Auto Off")}}
, halt_tx_button_ {new QPushButton {tr ("&Halt Tx")}}
, mode_label_ {new QLabel}
, fast_mode_ {false}
, frequency_label_ {new QLabel}
, dx_label_ {new QLabel}
, rx_df_label_ {new QLabel}
, tx_df_label_ {new QLabel}
, report_label_ {new QLabel}
{
// set up widgets
decodes_proxy_model_.setSourceModel (decodes_model);
decodes_table_view_->setModel (&decodes_proxy_model_);
decodes_table_view_->verticalHeader ()->hide ();
decodes_table_view_->hideColumn (0);
decodes_table_view_->horizontalHeader ()->setStretchLastSection (true);
auto form_layout = new QFormLayout;
form_layout->addRow (tr ("Free text:"), message_line_edit_);
message_line_edit_->setValidator (new QRegExpValidator {message_alphabet, this});
connect (message_line_edit_, &QLineEdit::textEdited, [this] (QString const& text) {
Q_EMIT do_free_text (id_, text, false);
});
connect (message_line_edit_, &QLineEdit::editingFinished, [this] () {
Q_EMIT do_free_text (id_, message_line_edit_->text (), true);
});
auto decodes_page = new QWidget;
auto decodes_layout = new QVBoxLayout {decodes_page};
decodes_layout->setContentsMargins (QMargins {2, 2, 2, 2});
decodes_layout->addWidget (decodes_table_view_);
decodes_layout->addLayout (form_layout);
auto beacons_proxy_model = new IdFilterModel {id_};
beacons_proxy_model->setSourceModel (beacons_model);
beacons_table_view_->setModel (beacons_proxy_model);
beacons_table_view_->verticalHeader ()->hide ();
beacons_table_view_->hideColumn (0);
beacons_table_view_->horizontalHeader ()->setStretchLastSection (true);
auto beacons_page = new QWidget;
auto beacons_layout = new QVBoxLayout {beacons_page};
beacons_layout->setContentsMargins (QMargins {2, 2, 2, 2});
beacons_layout->addWidget (beacons_table_view_);
decodes_stack_->addWidget (decodes_page);
decodes_stack_->addWidget (beacons_page);
// stack alternative views
auto content_layout = new QVBoxLayout;
content_layout->setContentsMargins (QMargins {2, 2, 2, 2});
content_layout->addLayout (decodes_stack_);
// set up controls
auto control_button_box = new QDialogButtonBox;
control_button_box->addButton (auto_off_button_, QDialogButtonBox::ActionRole);
control_button_box->addButton (halt_tx_button_, QDialogButtonBox::ActionRole);
connect (auto_off_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
Q_EMIT do_halt_tx (id_, true);
});
connect (halt_tx_button_, &QAbstractButton::clicked, [this] (bool /* checked */) {
Q_EMIT do_halt_tx (id_, false);
});
content_layout->addWidget (control_button_box);
// set up status area
auto status_bar = new QStatusBar;
status_bar->addPermanentWidget (mode_label_);
status_bar->addPermanentWidget (frequency_label_);
status_bar->addPermanentWidget (dx_label_);
status_bar->addPermanentWidget (rx_df_label_);
status_bar->addPermanentWidget (tx_df_label_);
status_bar->addPermanentWidget (report_label_);
content_layout->addWidget (status_bar);
connect (this, &ClientWidget::topLevelChanged, status_bar, &QStatusBar::setSizeGripEnabled);
// set up central widget
auto content_widget = new QFrame;
content_widget->setFrameStyle (QFrame::StyledPanel | QFrame::Sunken);
content_widget->setLayout (content_layout);
setWidget (content_widget);
// setMinimumSize (QSize {550, 0});
setFeatures (DockWidgetMovable | DockWidgetFloatable);
setAllowedAreas (Qt::BottomDockWidgetArea);
// connect up table view signals
connect (decodes_table_view_, &QTableView::doubleClicked, this, [this] (QModelIndex const& index) {
Q_EMIT do_reply (decodes_proxy_model_.mapToSource (index));
});
}
void ClientWidget::update_status (QString const& id, Frequency f, QString const& mode, QString const& dx_call
, QString const& report, QString const& tx_mode, bool tx_enabled
, bool transmitting, bool decoding, qint32 rx_df, qint32 tx_df
, QString const& de_call, QString const& /*de_grid*/, QString const& dx_grid
, bool watchdog_timeout, QString const& sub_mode, bool fast_mode)
{
if (id == id_)
{
fast_mode_ = fast_mode;
decodes_proxy_model_.de_call (de_call);
decodes_proxy_model_.rx_df (rx_df);
mode_label_->setText (QString {"Mode: %1%2%3%4"}
.arg (mode)
.arg (sub_mode)
.arg (fast_mode && !mode.contains (QRegularExpression {R"(ISCAT|MSK144)"}) ? "fast" : "")
.arg (tx_mode.isEmpty () || tx_mode == mode ? "" : '(' + tx_mode + ')'));
frequency_label_->setText ("QRG: " + Radio::pretty_frequency_MHz_string (f));
dx_label_->setText (dx_call.size () >= 0 ? QString {"DX: %1%2"}.arg (dx_call)
.arg (dx_grid.size () ? '(' + dx_grid + ')' : QString {}) : QString {});
rx_df_label_->setText (rx_df >= 0 ? QString {"Rx: %1"}.arg (rx_df) : "");
tx_df_label_->setText (tx_df >= 0 ? QString {"Tx: %1"}.arg (tx_df) : "");
report_label_->setText ("SNR: " + report);
update_dynamic_property (frequency_label_, "transmitting", transmitting);
auto_off_button_->setEnabled (tx_enabled);
halt_tx_button_->setEnabled (transmitting);
update_dynamic_property (mode_label_, "decoding", decoding);
update_dynamic_property (tx_df_label_, "watchdog_timeout", watchdog_timeout);
}
}
void ClientWidget::decode_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
, float /*delta_time*/, quint32 /*delta_frequency*/, QString const& /*mode*/
, QString const& /*message*/)
{
if (client_id == id_)
{
decodes_stack_->setCurrentIndex (0);
decodes_table_view_->resizeColumnsToContents ();
decodes_table_view_->scrollToBottom ();
}
}
void ClientWidget::beacon_spot_added (bool /*is_new*/, QString const& client_id, QTime /*time*/, qint32 /*snr*/
, float /*delta_time*/, Frequency /*delta_frequency*/, qint32 /*drift*/
, QString const& /*callsign*/, QString const& /*grid*/, qint32 /*power*/)
{
if (client_id == id_)
{
decodes_stack_->setCurrentIndex (1);
beacons_table_view_->resizeColumnsToContents ();
beacons_table_view_->scrollToBottom ();
}
}
#include "moc_ClientWidget.cpp"
@@ -1,619 +0,0 @@
// -*- Mode: C++ -*-
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#ifdef QT5
#include <QtWidgets>
#else
#include <QtGui>
#endif
#include <QThread>
#include <QTimer>
#include <QDateTime>
#include <QList>
#include <QAudioDeviceInfo>
#include <QScopedPointer>
#include <QDir>
#include <QProgressDialog>
#include <QAbstractSocket>
#include <QHostAddress>
#include <QPointer>
#include <QSet>
#include <QVector>
#include <QFuture>
#include <QFutureWatcher>
#include "AudioDevice.hpp"
#include "commons.h"
#include "Radio.hpp"
#include "Modes.hpp"
#include "FrequencyList.hpp"
#include "Configuration.hpp"
#include "WSPRBandHopping.hpp"
#include "Transceiver.hpp"
#include "DisplayManual.hpp"
#include "psk_reporter.h"
#include "logbook/logbook.h"
#include "decodedtext.h"
#include "commons.h"
#include "astro.h"
#include "MessageBox.hpp"
#include "NetworkAccessManager.hpp"
#define NUM_JT4_SYMBOLS 206 //(72+31)*2, embedded sync
#define NUM_JT65_SYMBOLS 126 //63 data + 63 sync
#define NUM_JT9_SYMBOLS 85 //69 data + 16 sync
#define NUM_WSPR_SYMBOLS 162 //(50+31)*2, embedded sync
#define NUM_WSPR_LF_SYMBOLS 412 //300 data + 109 sync + 3 ramp
#define NUM_ISCAT_SYMBOLS 1291 //30*11025/256
#define NUM_MSK144_SYMBOLS 144 //s8 + d48 + s8 + d80
#define NUM_QRA64_SYMBOLS 84 //63 data + 21 sync
#define NUM_FT8_SYMBOLS 79
#define NUM_CW_SYMBOLS 250
#define TX_SAMPLE_RATE 48000
#define N_WIDGETS 24
extern int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols
extern int volatile icw[NUM_CW_SYMBOLS]; //Dits for CW ID
//--------------------------------------------------------------- MainWindow
namespace Ui {
class MainWindow;
}
class QSettings;
class QLineEdit;
class QFont;
class QHostInfo;
class EchoGraph;
class FastGraph;
class WideGraph;
class LogQSO;
class Transceiver;
class MessageAveraging;
class MessageClient;
class QTime;
class WSPRBandHopping;
class HelpTextWindow;
class WSPRNet;
class SoundOutput;
class Modulator;
class SoundInput;
class Detector;
class SampleDownloader;
class MultiSettings;
class PhaseEqualizationDialog;
class MainWindow : public QMainWindow
{
Q_OBJECT;
public:
using Frequency = Radio::Frequency;
using FrequencyDelta = Radio::FrequencyDelta;
using Mode = Modes::Mode;
explicit MainWindow(QDir const& temp_directory, bool multiple, MultiSettings *,
QSharedMemory *shdmem, unsigned downSampleFactor,
QSplashScreen *,
QWidget *parent = nullptr);
~MainWindow();
public slots:
void showSoundInError(const QString& errorMsg);
void showSoundOutError(const QString& errorMsg);
void showStatusMessage(const QString& statusMsg);
void dataSink(qint64 frames);
void fastSink(qint64 frames);
void diskDat();
void freezeDecode(int n);
void guiUpdate();
void doubleClickOnCall(bool shift, bool ctrl);
void doubleClickOnCall2(bool shift, bool ctrl);
void readFromStdout();
void p1ReadFromStdout();
void setXIT(int n, Frequency base = 0u);
void setFreq4(int rxFreq, int txFreq);
void msgAvgDecode2();
void fastPick(int x0, int x1, int y);
protected:
void keyPressEvent (QKeyEvent *) override;
void closeEvent(QCloseEvent *) override;
void childEvent(QChildEvent *) override;
bool eventFilter(QObject *, QEvent *) override;
private slots:
void on_tx1_editingFinished();
void on_tx2_editingFinished();
void on_tx3_editingFinished();
void on_tx4_editingFinished();
void on_tx5_currentTextChanged (QString const&);
void on_tx6_editingFinished();
void on_actionSettings_triggered();
void on_monitorButton_clicked (bool);
void on_actionAbout_triggered();
void on_autoButton_clicked (bool);
void on_stopTxButton_clicked();
void on_stopButton_clicked();
void on_actionRelease_Notes_triggered ();
void on_actionOnline_User_Guide_triggered();
void on_actionLocal_User_Guide_triggered();
void on_actionWide_Waterfall_triggered();
void on_actionOpen_triggered();
void on_actionOpen_next_in_directory_triggered();
void on_actionDecode_remaining_files_in_directory_triggered();
void on_actionDelete_all_wav_files_in_SaveDir_triggered();
void on_actionOpen_log_directory_triggered ();
void on_actionNone_triggered();
void on_actionSave_all_triggered();
void on_actionKeyboard_shortcuts_triggered();
void on_actionSpecial_mouse_commands_triggered();
void on_DecodeButton_clicked (bool);
void decode();
void decodeBusy(bool b);
void on_EraseButton_clicked();
void on_txb1_clicked();
void on_txFirstCheckBox_stateChanged(int arg1);
void set_dateTimeQSO(int m_ntx);
void set_ntx(int n);
void on_txrb1_toggled(bool status);
void on_txrb2_toggled(bool status);
void on_txrb3_toggled(bool status);
void on_txb2_clicked();
void on_txb3_clicked();
void on_txb4_clicked();
void on_txb5_clicked();
void on_txb6_clicked();
void on_lookupButton_clicked();
void on_addButton_clicked();
void on_dxCallEntry_textChanged (QString const&);
void on_dxGridEntry_textChanged (QString const&);
void on_dxCallEntry_returnPressed ();
void on_genStdMsgsPushButton_clicked();
void on_logQSOButton_clicked();
void on_actionJT9_triggered();
void on_actionJT65_triggered();
void on_actionJT9_JT65_triggered();
void on_actionJT4_triggered();
void on_actionFT8_triggered();
void on_TxFreqSpinBox_valueChanged(int arg1);
void on_actionSave_decoded_triggered();
void on_actionQuickDecode_toggled (bool);
void on_actionMediumDecode_toggled (bool);
void on_actionDeepestDecode_toggled (bool);
void on_inGain_valueChanged(int n);
void bumpFqso(int n);
void on_actionErase_ALL_TXT_triggered();
void on_actionErase_wsjtx_log_adi_triggered();
void startTx2();
void startP1();
void stopTx();
void stopTx2();
void on_pbCallCQ_clicked();
void on_pbAnswerCaller_clicked();
void on_pbSendRRR_clicked();
void on_pbAnswerCQ_clicked();
void on_pbSendReport_clicked();
void on_pbSend73_clicked();
void on_rbGenMsg_clicked(bool checked);
void on_rbFreeText_clicked(bool checked);
void on_freeTextMsg_currentTextChanged (QString const&);
void on_rptSpinBox_valueChanged(int n);
void killFile();
void on_tuneButton_clicked (bool);
void on_pbR2T_clicked();
void on_pbT2R_clicked();
void acceptQSO2(QDateTime const&, QString const& call, QString const& grid
, Frequency dial_freq, QString const& mode
, QString const& rpt_sent, QString const& rpt_received
, QString const& tx_power, QString const& comments
, QString const& name, QDateTime const&);
void on_bandComboBox_currentIndexChanged (int index);
void on_bandComboBox_activated (int index);
void on_readFreq_clicked();
void on_pbTxMode_clicked();
void on_RxFreqSpinBox_valueChanged(int n);
void on_cbTxLock_clicked(bool checked);
void on_outAttenuation_valueChanged (int);
void rigOpen ();
void handle_transceiver_update (Transceiver::TransceiverState const&);
void handle_transceiver_failure (QString const& reason);
void on_actionAstronomical_data_toggled (bool);
void on_actionShort_list_of_add_on_prefixes_and_suffixes_triggered();
void band_changed (Frequency);
void monitor (bool);
void stop_tuning ();
void stopTuneATU();
void auto_tx_mode(bool);
void on_actionMessage_averaging_triggered();
void on_actionInclude_averaging_toggled (bool);
void on_actionInclude_correlation_toggled (bool);
void on_actionEnable_AP_DXcall_toggled (bool);
void VHF_features_enabled(bool b);
void on_sbSubmode_valueChanged(int n);
void on_cbShMsgs_toggled(bool b);
void on_cbSWL_toggled(bool b);
void on_cbTx6_toggled(bool b);
void networkError (QString const&);
void on_ClrAvgButton_clicked();
void on_actionWSPR_triggered();
void on_actionWSPR_LF_triggered();
void on_syncSpinBox_valueChanged(int n);
void on_TxPowerComboBox_currentIndexChanged(const QString &arg1);
void on_sbTxPercent_valueChanged(int n);
void on_cbUploadWSPR_Spots_toggled(bool b);
void WSPR_config(bool b);
void uploadSpots();
void TxAgain();
void uploadResponse(QString response);
void on_WSPRfreqSpinBox_valueChanged(int n);
void on_pbTxNext_clicked(bool b);
void on_actionEcho_Graph_triggered();
void on_actionEcho_triggered();
void on_actionISCAT_triggered();
void on_actionFast_Graph_triggered();
void on_actionHide_Controls_toggled (bool chaecked);
void fast_decode_done();
void on_actionMeasure_reference_spectrum_triggered();
void on_actionErase_reference_spectrum_triggered();
void on_actionMeasure_phase_response_triggered();
void on_sbTR_valueChanged (int);
void on_sbFtol_valueChanged (int);
void on_cbFast9_clicked(bool b);
void on_sbCQTxFreq_valueChanged(int n);
void on_cbCQTx_toggled(bool b);
void on_actionMSK144_triggered();
void on_actionQRA64_triggered();
void on_actionFreqCal_triggered();
void splash_done ();
private:
Q_SIGNAL void initializeAudioOutputStream (QAudioDeviceInfo,
unsigned channels, unsigned msBuffered) const;
Q_SIGNAL void stopAudioOutputStream () const;
Q_SIGNAL void startAudioInputStream (QAudioDeviceInfo const&,
int framesPerBuffer, AudioDevice * sink,
unsigned downSampleFactor, AudioDevice::Channel) const;
Q_SIGNAL void suspendAudioInputStream () const;
Q_SIGNAL void resumeAudioInputStream () const;
Q_SIGNAL void startDetector (AudioDevice::Channel) const;
Q_SIGNAL void FFTSize (unsigned) const;
Q_SIGNAL void detectorClose () const;
Q_SIGNAL void finished () const;
Q_SIGNAL void transmitFrequency (double) const;
Q_SIGNAL void endTransmitMessage (bool quick = false) const;
Q_SIGNAL void tune (bool = true) const;
Q_SIGNAL void sendMessage (unsigned symbolsLength, double framesPerSymbol,
double frequency, double toneSpacing,
SoundOutput *, AudioDevice::Channel = AudioDevice::Mono,
bool synchronize = true, bool fastMode = false, double dBSNR = 99.,
int TRperiod=60) const;
Q_SIGNAL void outAttenuationChanged (qreal) const;
Q_SIGNAL void toggleShorthand () const;
private:
void astroUpdate ();
void writeAllTxt(QString message);
void FT8_AutoSeq(QString message);
NetworkAccessManager m_network_manager;
bool m_valid;
QSplashScreen * m_splash;
QDir m_dataDir;
QString m_revision;
bool m_multiple;
MultiSettings * m_multi_settings;
QPushButton * m_configurations_button;
QSettings * m_settings;
QScopedPointer<Ui::MainWindow> ui;
// other windows
Configuration m_config;
WSPRBandHopping m_WSPR_band_hopping;
bool m_WSPR_tx_next;
MessageBox m_rigErrorMessageBox;
QScopedPointer<SampleDownloader> m_sampleDownloader;
QScopedPointer<PhaseEqualizationDialog> m_phaseEqualizationDialog;
QScopedPointer<WideGraph> m_wideGraph;
QScopedPointer<EchoGraph> m_echoGraph;
QScopedPointer<FastGraph> m_fastGraph;
QScopedPointer<LogQSO> m_logDlg;
QScopedPointer<Astro> m_astroWidget;
QScopedPointer<HelpTextWindow> m_shortcuts;
QScopedPointer<HelpTextWindow> m_prefixes;
QScopedPointer<HelpTextWindow> m_mouseCmnds;
QScopedPointer<MessageAveraging> m_msgAvgWidget;
Transceiver::TransceiverState m_rigState;
Frequency m_lastDialFreq;
QString m_lastBand;
Frequency m_dialFreqRxWSPR; // best guess at WSPR QRG
Detector * m_detector;
unsigned m_FFTSize;
SoundInput * m_soundInput;
Modulator * m_modulator;
SoundOutput * m_soundOutput;
QThread m_audioThread;
qint64 m_msErase;
qint64 m_secBandChanged;
qint64 m_freqMoon;
Frequency m_freqNominal;
Frequency m_freqTxNominal;
Astro::Correction m_astroCorrection;
double m_s6;
double m_tRemaining;
float m_DTtol;
float m_t0;
float m_t1;
float m_t0Pick;
float m_t1Pick;
float m_fCPUmskrtd;
qint32 m_waterfallAvg;
qint32 m_ntx;
bool m_gen_message_is_cq;
qint32 m_timeout;
qint32 m_XIT;
qint32 m_setftx;
qint32 m_ndepth;
qint32 m_sec0;
qint32 m_RxLog;
qint32 m_nutc0;
qint32 m_ntr;
qint32 m_tx;
qint32 m_hsym;
qint32 m_TRperiod;
qint32 m_nsps;
qint32 m_hsymStop;
qint32 m_inGain;
qint32 m_ncw;
qint32 m_secID;
qint32 m_idleMinutes;
qint32 m_nSubMode;
qint32 m_nclearave;
qint32 m_minSync;
qint32 m_dBm;
qint32 m_pctx;
qint32 m_nseq;
qint32 m_nWSPRdecodes;
qint32 m_k0;
qint32 m_kdone;
qint32 m_nPick;
FrequencyList::const_iterator m_frequency_list_fcal_iter;
qint32 m_nTx73;
qint32 m_UTCdisk;
qint32 m_wait;
bool m_btxok; //True if OK to transmit
bool m_diskData;
bool m_loopall;
bool m_decoderBusy;
bool m_txFirst;
bool m_auto;
bool m_restart;
bool m_startAnother;
bool m_saveDecoded;
bool m_saveAll;
bool m_widebandDecode;
bool m_call3Modified;
bool m_dataAvailable;
bool m_bDecoded;
bool m_noSuffix;
bool m_blankLine;
bool m_decodedText2;
bool m_freeText;
bool m_sentFirst73;
int m_currentMessageType;
QString m_currentMessage;
int m_lastMessageType;
QString m_lastMessageSent;
bool m_lockTxFreq;
bool m_bShMsgs;
bool m_bSWL;
bool m_uploadSpots;
bool m_uploading;
bool m_txNext;
bool m_grid6;
bool m_tuneup;
bool m_bTxTime;
bool m_rxDone;
bool m_bSimplex; // not using split even if it is available
bool m_bEchoTxOK;
bool m_bTransmittedEcho;
bool m_bEchoTxed;
bool m_bFastMode;
bool m_bFast9;
bool m_bFastDecodeCalled;
bool m_bDoubleClickAfterCQnnn;
bool m_bRefSpec;
bool m_bClearRefSpec;
bool m_bTrain;
bool m_bUseRef;
bool m_bFastDone;
bool m_bAltV;
bool m_bNoMoreFiles;
bool m_bQRAsyncWarned;
bool m_bDoubleClicked;
int m_ihsym;
int m_nzap;
int m_npts8;
float m_px;
float m_pxmax;
float m_df3;
int m_iptt0;
bool m_btxok0;
int m_nsendingsh;
double m_onAirFreq0;
bool m_first_error;
char m_msg[100][80];
// labels in status bar
QLabel tx_status_label;
QLabel config_label;
QLabel mode_label;
QLabel last_tx_label;
QLabel auto_tx_label;
QLabel band_hopping_label;
QProgressBar progressBar;
QLabel watchdog_label;
QFuture<void> m_wav_future;
QFutureWatcher<void> m_wav_future_watcher;
QFutureWatcher<void> watcher3;
QFutureWatcher<QString> m_saveWAVWatcher;
QProcess proc_jt9;
QProcess p1;
QProcess p3;
WSPRNet *wsprNet;
QTimer m_guiTimer;
QTimer ptt1Timer; //StartTx delay
QTimer ptt0Timer; //StopTx delay
QTimer logQSOTimer;
QTimer killFileTimer;
QTimer tuneButtonTimer;
QTimer uploadTimer;
QTimer tuneATU_Timer;
QTimer TxAgainTimer;
QTimer minuteTimer;
QTimer splashTimer;
QTimer p1Timer;
QString m_path;
QString m_baseCall;
QString m_hisCall;
QString m_hisGrid;
QString m_appDir;
QString m_palette;
QString m_dateTime;
QString m_mode;
QString m_modeTx;
QString m_fnameWE; // save path without extension
QString m_rpt;
QString m_rptSent;
QString m_rptRcvd;
QString m_qsoStart;
QString m_qsoStop;
QString m_cmnd;
QString m_cmndP1;
QString m_msgSent0;
QString m_fileToSave;
QString m_calls;
QSet<QString> m_pfx;
QSet<QString> m_sfx;
QDateTime m_dateTimeQSOOn;
QDateTime m_dateTimeQSOOff;
QDateTime m_dateTimeDefault;
QSharedMemory *mem_jt9;
LogBook m_logBook;
DecodedText m_QSOText;
unsigned m_msAudioOutputBuffered;
unsigned m_framesAudioInputBuffered;
unsigned m_downSampleFactor;
QThread::Priority m_audioThreadPriority;
bool m_bandEdited;
bool m_splitMode;
bool m_monitoring;
bool m_tx_when_ready;
bool m_transmitting;
bool m_tune;
bool m_tx_watchdog; // true when watchdog triggered
bool m_block_pwr_tooltip;
bool m_PwrBandSetOK;
bool m_bVHFwarned;
Frequency m_lastMonitoredFrequency;
double m_toneSpacing;
int m_firstDecode;
QProgressDialog m_optimizingProgress;
QTimer m_heartbeat;
MessageClient * m_messageClient;
PSK_Reporter *psk_Reporter;
DisplayManual m_manual;
QHash<QString, QVariant> m_pwrBandTxMemory; // Remembers power level by band
QHash<QString, QVariant> m_pwrBandTuneMemory; // Remembers power level by band for tuning
QByteArray m_geometryNoControls;
QVector<double> m_phaseEqCoefficients;
//---------------------------------------------------- private functions
void readSettings();
void setDecodedTextFont (QFont const&);
void writeSettings();
void createStatusBar();
void updateStatusBar();
void genStdMsgs(QString rpt);
void genCQMsg();
void clearDX ();
void lookup();
void ba2msg(QByteArray ba, char* message);
void msgtype(QString t, QLineEdit* tx);
void stub();
void statusChanged();
void fixStop();
bool shortList(QString callsign);
void transmit (double snr = 99.);
void rigFailure (QString const& reason);
void pskSetLocal ();
void pskPost(DecodedText decodedtext);
void displayDialFrequency ();
void transmitDisplay (bool);
void processMessage(QString const& messages, qint32 position, bool ctrl);
void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text);
void replayDecodes ();
void postDecode (bool is_new, QString const& message);
void postWSPRDecode (bool is_new, QStringList message_parts);
void enable_DXCC_entity (bool on);
void switch_mode (Mode);
void WSPR_scheduling ();
void freqCalStep();
void setRig (Frequency = 0); // zero frequency means no change
void WSPR_history(Frequency dialFreq, int ndecodes);
QString WSPR_hhmm(int n);
void fast_config(bool b);
void CQTxFreq();
QString save_wave_file (QString const& name
, short const * data
, int seconds
, QString const& my_callsign
, QString const& my_grid
, QString const& mode
, qint32 sub_mode
, Frequency frequency
, QString const& his_call
, QString const& his_grid) const;
void read_wav_file (QString const& fname);
void decodeDone ();
void subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus);
void subProcessError (QProcess *, QProcess::ProcessError);
void statusUpdate () const;
void update_watchdog_label ();
void on_the_minute ();
void add_child_to_event_filter (QObject *);
void remove_child_from_event_filter (QObject *);
void setup_status_bar (bool vhf);
void tx_watchdog (bool triggered);
int nWidgets(QString t);
void displayWidgets(int n);
void vhfWarning();
QChar current_submode () const; // returns QChar {0} if sub mode is
// not appropriate
};
extern int killbyname(const char* progName);
extern void getDev(int* numDevices,char hostAPI_DeviceName[][50],
int minChan[], int maxChan[],
int minSpeed[], int maxSpeed[]);
extern int next_tx_state(int pctx);
#endif // MAINWINDOW_H
@@ -1,24 +0,0 @@
#include <boost/crc.hpp>
extern "C"
{
short crc10 (unsigned char const * data, int length);
bool crc10_check (unsigned char const * data, int length);
}
namespace
{
unsigned long constexpr truncated_polynomial = 0x08f;
}
// assumes CRC is last 16 bits of the data and is set to zero
// caller should assign the returned CRC into the message in big endian byte order
short crc10 (unsigned char const * data, int length)
{
return boost::augmented_crc<10, truncated_polynomial> (data, length);
}
bool crc10_check (unsigned char const * data, int length)
{
return !boost::augmented_crc<10, truncated_polynomial> (data, length);
}
@@ -1,50 +0,0 @@
// Status=review
.Main Window:
- Select *FT8* on the *Mode* menu.
- Set Tx and Rx frequencies to 1200 Hz.
- Double-click on *Erase* to clear both text windows.
.Wide Graph Settings:
- *Bins/Pixel* = 4, *Start* = 200 Hz, *N Avg* = 2
- Adjust the width of the Wide Graph window so that the upper
frequency limit is approximately 2600 Hz.
.Open a Wave File:
- Select *File | Open* and navigate to
+...\save\samples\FT8\170709_135615.wav+. The waterfall and decoded
text window should look something like the following screen shots:
[[X15]]
image::170709_135615.wav.png[align="left",alt="Wide Graph Decode 170709_135615"]
image::ft8_decodes.png[align="left"]
- Click with the mouse anywhere on the waterfall display. The green Rx
frequency marker will jump to your selected frequency, and the Rx
frequency control on the main window will be updated accordingly.
- Do the same thing with the Shift key held down. Now the red Tx
frequency marker and its associated control on the main window will
follow your frequency selections.
- Do the same thing with the Ctrl key held down. Now the both colored
markers and both spinner controls will follow your selections.
- Double-clicking at any frequency on the waterfall does all the
things just described and also invokes the decoder in a small range
around that frequency.
- Now double-click on any of the the lines of decoded text in the main
window. Unless you have *My Call* set to K1JT or KY7M on the
*Settings -> General* tab, all three lines will show the same
behavior, setting both RxFreq and TxFreq to the frequency of the
selected message. However, if MyCall is set to K1JT then clicking on
a message directed to K1JT will move only the Rx frequency setting.
This behavior is desirable so that you will not inadvertently change
your Tx frequency to that of a tail-ender who called you somewhere
else in the FT8 subband.
IMPORTANT: When finished with this Tutorial, don't forget to re-enter
your own callsign as *My Call* on the *Settings | General* tab.
@@ -1,371 +0,0 @@
<HTML><HEAD>
<TITLE> Creating a Parity Check Matrix </TITLE>
</HEAD><BODY>
<H1> Creating a Parity Check Matrix </H1>
<P>This software deals only with linear block codes for binary (ie,
modulo-2, GF(2)) vectors. The set of valid codewords for a linear
code can be specified by giving a <I>parity check matrix</I>,
<B>H</B>, with <I>M</I> rows and <I>N</I> columns. The valid
codewords are the vectors, <B>x</B>, of length <I>N</I>, for which
<B>Hx</B>=<B>0</B>, where all arithmetic is done modulo-2. Each row
of <B>H</B> represents a parity check on a subset of the bits in
<B>x</B>; all these parity checks must be satisfied for <B>x</B> to be
a codeword. Note that the parity check matrix for a given code (ie,
for a given set of valid codewords) is not unique, even after
eliminating rows of <B>H</B> that are redundant because they are
linear combinations of other rows.
<P>This software stores parity check matrices in files in a sparse
format. These parity-check files are <I>not</I> human-readable
(except by using the <A HREF="#print-pchk"><TT>print-pchk</TT></A>
program). However, they <I>are</I> readable on a machine with a
different architecture than they were written on.
<P>Some LDPC software by David MacKay and others uses the
<A HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
format</A> for parity check matrices. Two programs for converting
between this format and the format for sparse parity check matrices
used by this software are provided.
<A NAME="ldpc"><H2>Methods for constructing LDPC codes</H2></A>
<P>This software is primarily intended for experimentation with Low
Density Parity Check (LDPC) codes. These codes can be constructed by
various methods, which generally involve some random selection of
where to put 1s in a parity check matrix. Any such method for
constructing LDPC codes will have the property that it produces parity
check matrices in which the number of 1s in a column is approximately
the same (perhaps on average) for any size parity check matrix. For a
given code rate, these matrices therefore become increasingly sparse
as the length of a codeword, and hence the number of parity checks,
increases.
<P>Many methods for constructing LDPC matrices are described in the
<A HREF="refs.html">references</A>. Two simple methods are currently
implemented by this software, both of which operate according to the
following scheme:
<OL>
<LI> Create a preliminary parity check matrix by one of the methods.
<LI> Add 1s to the parity check matrix in order to avoid rows that have no
1s in them, and hence are redundant, or which have only one 1 in them,
in which case the corresponding codeword bits will always be zero.
The places within such a row to add these 1s are selected randomly.
<LI> If the preliminary parity check matrix constructed in step (1) had
an even number of 1s in each column, add further 1s to avoid the problem
that this will cause the rows to add to zero, and hence at least
one check will be redundant. Up to two 1s are added (since it is also
undesirable for the sum of the rows to have only one 1 in it), at
positions selected randomly from the entire matrix. However, the
number of 1s to add in this step is reduced by the number already added
in step (2). (Note that although redundant checks are not disastrous,
they are better avoided; see the discussion of <A HREF="dep-H.html">linear
dependence in parity check matrices</A>.)
<LI> If requested, try to eliminate
situations where a pair of columns both have 1s in a particular pair of
rows, which correspond to cycles of length four in the factor graph of
the parity check matrix. When such a situation is detected, one of the
1s involved is moved randomly within its column. This continues until
no such situations remain, or until 10 passes over all columns have
failed to eliminate all such situations.
</OL>
<P>The <I>evencol</I> method is the simplest way of performing step
(1) of the above procedure. For each column of the parity check
matrix, independently, it places a specified number of 1s in positions
selected uniformly at random, with the only constraint being that
these 1s be in distinct rows. Note that despite the name, the columns
do not have to have the same number of 1s - a distribution over
several values for the number of 1s in a column can be specified
instead. Such codes with different-weight columns are sometimes
better than codes in which every column has the same weight.
<P>The <I>evenboth</I> method also puts a specified number of 1s in
each column, but it tries as well to keep the numbers of 1s in the
rows approximately the same. Initially, it creates indicators for all
the 1s that will be required, and assigns these 1s to rows as evenly
as it can, favouring earlier rows if an exactly even split is not
possible. It then assigns 1s to successive columns by selecting
randomly, without replacement, from this initial supply of 1s, subject
only to the constraint that the 1s assigned to a column must be in
distinct rows. If at some point it is impossible to put the required
number of 1s in a column by picking from the 1s remaining, a 1 is set
in that column without reference to other columns, creating a possible
unevenness.
<P>Note that regardless of how evenly 1s are distributed in the
preliminary parity check matrix created in step (1), steps (2) and (3)
can make the numbers of 1s in the both rows and columns be uneven, and
step (4), if done, can make the numbers of 1s in rows be uneven.
<P><A NAME="make-pchk"><HR><B>make-pchk</B>: Make a parity check
matrix by explicit specification.
<BLOCKQUOTE><PRE>
make-pchk <I>pchk-file n-checks n-bits row</I>:<I>col ...</I>
</PRE></BLOCKQUOTE>
<P>Creates a file named <TT><I>pchk-file</I></TT> in
which it stores a parity check matrix with <TT><I>n-checks</I></TT>
rows and <TT><I>n-bits</I></TT> columns. This parity check matrix
consists of all 0s except for 1s at the <I>row</I>:<I>col</I>
positions listed. Rows and columns are numbered starting at zero.
This program is intended primarily for testing and demonstration
purposes.
<P><B>Example:</B> The well-known Hamming code with codewords of
length <I>N</I>=7 and with <I>M</I>=3 parity checks can be can be
created as follows:
<UL><PRE>
<LI>make-pchk ham7.pchk 3 7 0:0 0:3 0:4 0:5 1:1 1:3 1:4 1:6 2:2 2:4 2:5 2:6
</PRE></UL>
<P><A NAME="alist-to-pchk"><HR><B>alist-to-pchk</B>: Convert a parity
check matrix from alist format to the sparse matrix format used by
this software.
<BLOCKQUOTE><PRE>
alist-to-pchk [ -t ] <I>alist-file pchk-file</I>
</PRE></BLOCKQUOTE>
<P>Converts a parity check matrix in
<A HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
format</A> stored in the file named <TT><I>alist-file</I></TT> to
the sparse matrix format used by this software, storing it in the
file named <TT><I>pchk-file</I></TT>.
<P>If the <B>-t</B> option is given, the transpose of the parity check
matrix in <TT><I>alist-file</I></TT> is stored in the
<TT><I>pchk-file</I></TT>.
<P>Any zeros indexes in the alist file are ignored, so that alist files
with zero padding (as required in the specification) are accepted,
but files without this zero padding are also accepted. Newlines
are ignored by <TT>alist-to-pchk</TT>, so no error is reported if
the set of indexes in a row or column description are not those
on a single line.
<P><A NAME="pchk-to-alist"><HR><B>pchk-to-alist</B>: Convert a parity
check matrix to alist format.
<BLOCKQUOTE><PRE>
pchk-to-alist [ -t ] [ -z ] <I>pchk-file alist-file</I>
</PRE></BLOCKQUOTE>
<P>Converts a parity check matrix stored in the sparse matrix format
used by this software, in the file named <TT><I>pchk-file</I></TT>, to
the <A
HREF="http://www.inference.phy.cam.ac.uk/mackay/codes/alist.html">alist
format</A>, storing it in the file named <TT><I>alist-file</I></TT>.
<P>If the <B>-t</B> option is given, the transpose of the parity check
matrix is converted to alist format.
<P>If the number of 1s is not
the same for each row or each column, the alist format specification
says that the list of indexes of 1s for each row or column should
be padded with zeros to the maximum number of indexes. By default,
<TT>pchk-to-alist</TT> does this, but output of these 0s can be
suppressed by specifying the <B>-z</B> option. (The <TT>alist-to-pchk</TT>
program will accept alist files produced with or without the <B>-z</B>
option.)
<P><A NAME="print-pchk"><HR><B>print-pchk</B>: Print a parity check matrix.
<BLOCKQUOTE><PRE>
print-pchk [ -d ] [ -t ] <I>pchk-file</I>
</PRE></BLOCKQUOTE>
<P>Prints a human-readable representation of the parity check matrix stored
in <TT><I>pchk-file</I></TT>.
The <B>-d</B> option causes the matrix to be printed in a dense
format, even though parity check matrices are always stored in the
file in a sparse format. If the <B>-t</B> option is present, what is
printed is the transpose of the parity check matrix.
<P>The sparse display format consists of one line for every row of the
matrix, consisting of the row number, a colon, and the column numbers
at which 1s are located (possibly none). Row and columns numbers
start at zero. No attempt is made to wrap long lines.
<P>The dense display is the obvious array of 0s and 1s. Long lines
are not wrapped.
<P><B>Example</B>: The parity check matrix for the Hamming code created
by the example for <A HREF="#make-pchk"><TT>make-pchk</TT></A> would print
as follows:
<UL><PRE>
<LI>print-pchk ham7.pchk
Parity check matrix in ham7.pchk (sparse format):
0: 0 3 4 5
1: 1 3 4 6
2: 2 4 5 6
<LI>print-pchk -d ham7.pchk
Parity check matrix in ham7.pchk (dense format):
1 0 0 1 1 1 0
0 1 0 1 1 0 1
0 0 1 0 1 1 1
</PRE></UL>
<P><A NAME="make-ldpc"><HR><B>make-ldpc</B>: Make a low density parity
check matrix, by random generation.
<BLOCKQUOTE><PRE>
make-ldpc <I>pchk-file n-checks n-bits seed method</I>
</PRE>
<BLOCKQUOTE>
where <TT><I>method</I></TT> is one of the following:
<BLOCKQUOTE><PRE>
evencol <I>checks-per-col</I> [ no4cycle ]
evencol <I>checks-distribution</I> [ no4cycle ]
evenboth <I>checks-per-col</I> [ no4cycle ]
evenboth <I>checks-distribution</I> [ no4cycle ]
</PRE></BLOCKQUOTE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<P>Creates a Low Density Parity Check matrix with
<TT><I>n-checks</I></TT> rows and <TT><I>n-bits</I></TT> columns. The
parity check matrix will be generated pseudo-randomly by the indicated
method, using a pseudo-random number stream determined by <TT><I>seed</I></TT>.
The actual random number seed used is 10 times <TT><I>seed</I></TT> plus 1,
so as to avoid using the same stream as any of the other programs.
<P>Two methods are currently available for creating the LDPC matrix,
specified by <TT>evencol</TT> or <TT>evenboth</TT>. Both methods
produce a matrix in which the number of 1s in each column is
approximately <TT><I>checks-per-col</I></TT>, or varies from column
to column according the the <TT><I>checks-distribution</I></TT>.
The <TT>evenboth</TT> method also tries to make the number of checks per row be
approximately uniform; if this is not achieved, a message saying that
how many bits were placed unevenly is displayed on standard error.
<P>For both methods, the <TT>no4cycle</TT> option will cause cycles of
length four in the factor graph representation of the code to be
eliminated (if possible). A message is displayed on standard error if
this is not achieved.
<P>A <TT><I>checks-distribution</I></TT> has the form
<BLOCKQUOTE><PRE>
<I>prop</I>x<I>count</I>/<I>prop</I>x<I>count</I>/...
</PRE></BLOCKQUOTE>
Here, <TT><I>prop</I></TT> is a proportion of columns that have the
associated <TT><I>count</I></TT>. The proportions need not sum to one,
since they will be automatically normalized. For example, <TT>0.3x4/0.2x5</TT>
specifies that 60% of the columns will contain four 1s and 40% will
contain five 1s.
<P>See the <A HREF="#ldpc">discussion above</A> for more details
on how these methods construct LDPC matrices.
<P><B>Example 1:</B> The <TT>make-ldpc</TT> command below creates
a 20 by 40 low density parity check matrix with three 1s per
column and six 1s per row, using random seed 1. The matrix
is then printed in sparse format
using <A HREF="#print-pchk">print-pchk</A>.
<UL><PRE>
<LI>make-ldpc ldpc.pchk 20 40 1 evenboth 3
<LI>print-pchk ldpc.pchk
Parity check matrix in ldpc.pchk (sparse format):
0: 10 14 18 27 38 39
1: 2 3 5 11 27 30
2: 15 19 20 21 24 26
3: 2 4 25 28 32 38
4: 7 9 12 22 33 34
5: 5 6 21 22 26 32
6: 1 4 13 24 25 28
7: 1 14 28 29 30 36
8: 11 13 22 23 32 37
9: 6 8 13 20 31 33
10: 0 3 24 29 31 38
11: 7 12 15 16 17 23
12: 3 16 29 34 35 39
13: 0 8 10 18 36 37
14: 6 11 18 20 35 39
15: 0 7 14 16 25 37
16: 2 4 9 19 30 31
17: 5 9 10 17 19 23
18: 8 15 17 21 26 27
19: 1 12 33 34 35 36
</PRE></UL>
<P><B>Example 2:</B> The two <TT>make-ldpc</TT> commands
below both create a 20 by 40 low density parity check matrix with 30%
of columns with two 1s, 60% of columns with three 1s, and 10% of
columns with seven 1s. The transpose of the parity check matrix
is then printed in sparse format.
<UL><PRE>
<LI>make-ldpc ldpc.pchk 20 40 1 evenboth 0.3x2/0.6x3/0.1x7
<LI>make-ldpc ldpc.pchk 20 40 1 evenboth 3x2/6x3/1x7
<LI>print-pchk -t ldpc.pchk
Transpose of parity check matrix in ldpc.pchk (sparse format):
0: 13 16
1: 9 18
2: 1 10
3: 3 15
4: 4 14
5: 14 17
6: 4 5
7: 1 8
8: 0 4
9: 9 14
10: 5 8
11: 6 16
12: 2 12 19
13: 3 17 18
14: 2 16 17
15: 2 11 18
16: 12 13 19
17: 7 13 18
18: 2 5 11
19: 10 12 14
20: 1 8 16
21: 10 18 19
22: 3 6 17
23: 7 11 12
24: 1 2 19
25: 0 6 7
26: 5 8 15
27: 1 4 7
28: 6 13 19
29: 3 4 11
30: 3 8 17
31: 4 5 9
32: 0 10 15
33: 7 11 13
34: 8 12 19
35: 0 2 10
36: 0 5 9 11 15 17 18
37: 0 1 2 6 7 14 16
38: 0 1 3 9 12 13 15
39: 3 6 9 10 14 15 16
</PRE></UL>
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>
@@ -1,30 +0,0 @@
<table cellpadding=5>
<tr>
<th align="right">Click on</th>
<th align="left">Action</th>
</tr>
<tr>
<td align="right">Waterfall:</td>
<td><b>Click</b> to set the Rx frequency.<br/>
<b>Shift-click</b> to set Tx frequency.<br/>
<b>Ctrl-click</b> to set Rx and Tx frequencies.<br/>
<b>Double-click</b> to decode at resulting Rx frequency.<br/>
If <b>Lock Tx=Rx</b> is checked all actions set Tx/Rx.
</td>
</tr>
<tr>
<td align="right">Decoded text:</td>
<td><b>Double-click</b> to copy second callsign to Dx Call,<br/>
locator to Dx Grid; change Rx and Tx frequencies to<br/>
decoded signal's frequency; generate standard messages.<br/>
If first callsign is your own, Tx frequency is not<br/>
changed unless Ctrl is held down when double-clicking.
</td>
</tr>
<tr>
<td align="right">Erase button:</td>
<td><b>Click</b> to erase QSO window.<br/>
<b>Double-click</b> to erase QSO and Band Activity windows.
</td>
</tr>
</table>
@@ -1,89 +0,0 @@
<HTML><HEAD>
<TITLE> Modules Used in LDPC Programs </TITLE>
</HEAD><BODY>
<H1> Modules Used in LDPC Programs </H1>
You may need to familiarize yourself with the modules documented here
in order to <A HREF="modify.html">modify the LDPC programs</A>.
These modules may also be useful for other purposes.
<P>Click on the title of a module below for general information, or on
specific routines for detailed documentation.
<P><A HREF="mod2dense.html">Dense modulo-2 matrix routines</A>:
<BLOCKQUOTE><PRE>
<A HREF="mod2dense.html#dimension-sec"><I>Dimension macros:</I> mod2dense_rows mod2dense_cols</A>
<I><A HREF="mod2dense.html#alloc-sec">Allocation:</A> <A HREF="mod2dense.html#copy-clear-sec">Copy/Clear:</A> <A HREF="mod2dense.html#input-output-sec">Input/Output:</A> <A HREF="mod2dense.html#elementary-sec">Elementary ops:</A></I>
<A HREF="mod2dense.html#allocate">mod2dense_allocate</A> <A HREF="mod2dense.html#clear">mod2dense_clear</A> <A HREF="mod2dense.html#print">mod2dense_print</A> <A HREF="mod2dense.html#get">mod2dense_get</A>
<A HREF="mod2dense.html#free">mod2dense_free</A> <A HREF="mod2dense.html#copy">mod2dense_copy</A> <A HREF="mod2dense.html#write">mod2dense_write</A> <A HREF="mod2dense.html#set">mod2dense_set</A>
<A HREF="mod2dense.html#copyrows">mod2dense_copyrows</A> <A HREF="mod2dense.html#read">mod2dense_read</A> <A HREF="mod2dense.html#flip">mod2dense_flip</A>
<A HREF="mod2dense.html#copycols">mod2dense_copycols</A>
<I><A HREF="mod2dense.html#arith-sec">Matrix arithmetic:</A> <A HREF="mod2dense.html#invert-sec">Matrix inversion:</A></I>
<A HREF="mod2dense.html#transpose">mod2dense_transpose</A> <A HREF="mod2dense.html#invert">mod2dense_invert</A>
<A HREF="mod2dense.html#add">mod2dense_add</A> <A HREF="mod2dense.html#forcibly_invert">mod2dense_forcibly_invert</A>
<A HREF="mod2dense.html#multiply">mod2dense_multiply</A> <A HREF="mod2dense.html#invert_selected">mod2dense_invert_selected</A>
<A HREF="mod2dense.html#equal">mod2dense_equal</A>
</PRE></BLOCKQUOTE>
<P><A HREF="mod2sparse.html">Sparse modulo-2 matrix routines</A>:
<BLOCKQUOTE><PRE>
<A HREF="mod2sparse.html#dimension-sec"><I>Dimension macros:</I> mod2sparse_rows mod2sparse_cols</A>
<A HREF="mod2sparse.html#traversal-sec"><I>Traversal macros:</I> mod2sparse_first_in_row mod2sparse_next_in_row ...</A>
<I><A HREF="mod2sparse.html#alloc-sec">Allocation:</A> <A HREF="mod2sparse.html#copy-clear-sec">Copy/Clear:</A> <A HREF="mod2sparse.html#input-output-sec">Input/Output:</A> <A HREF="mod2sparse.html#elementary-sec">Elementary ops:</A></I>
<A HREF="mod2sparse.html#allocate">mod2sparse_allocate</A> <A HREF="mod2sparse.html#clear">mod2sparse_clear</A> <A HREF="mod2sparse.html#print">mod2sparse_print</A> <A HREF="mod2sparse.html#find">mod2sparse_find</A>
<A HREF="mod2sparse.html#free">mod2sparse_free</A> <A HREF="mod2sparse.html#copy">mod2sparse_copy</A> <A HREF="mod2sparse.html#write">mod2sparse_write</A> <A HREF="mod2sparse.html#insert">mod2sparse_insert</A>
<A HREF="mod2sparse.html#copyrows">mod2sparse_copyrows</A> <A HREF="mod2sparse.html#read">mod2sparse_read</A> <A HREF="mod2sparse.html#delete">mod2sparse_delete</A>
<A HREF="mod2sparse.html#copycols">mod2sparse_copycols</A>
<I><A HREF="mod2sparse.html#arith-sec">Matrix arithmetic:</A> <A HREF="mod2sparse.html#row-col-ops-sec">Row/Column ops:</A> <A HREF="mod2sparse.html#lu-decomp-sec">LU decomposition:</A></I>
<A HREF="mod2sparse.html#transpose">mod2sparse_transpose</A> <A HREF="mod2sparse.html#count_row">mod2sparse_count_row</A> <A HREF="mod2sparse.html#decomp">mod2sparse_decomp</A>
<A HREF="mod2sparse.html#add">mod2sparse_add</A> <A HREF="mod2sparse.html#count_col">mod2sparse_count_col</A> <A HREF="mod2sparse.html#forward_sub">mod2sparse_forward_sub</A>
<A HREF="mod2sparse.html#multiply">mod2sparse_multiply</A> <A HREF="mod2sparse.html#add_row">mod2sparse_add_row</A> <A HREF="mod2sparse.html#backward_sub">mod2sparse_backward_sub</A>
<A HREF="mod2sparse.html#mulvec">mod2sparse_mulvec</A> <A HREF="mod2sparse.html#add_col">mod2sparse_add_col</A>
<A HREF="mod2sparse.html#equal">mod2sparse_equal</A>
</PRE>
<A HREF="sparse-LU.html">Discussion of sparse LU decomposition methods.</A>
</BLOCKQUOTE>
<P><A HREF="mod2convert.html">Modulo-2 matrix sparse/dense conversion</A>:
<BLOCKQUOTE><PRE>
<A HREF="mod2convert.html#sparse_to_dense">mod2sparse_to_dense</A>
<A HREF="mod2convert.html#dense_to_sparse">mod2dense_to_sparse</A>
</PRE></BLOCKQUOTE>
<P><A HREF="rand.html">Random variate generation routines</A>:
<BLOCKQUOTE><PRE>
<I><A HREF="rand.html#get-set-sec">Set/Get state:<A> <A HREF="rand.html#uniform-sec">Uniform:</A> <A HREF="rand.html#discrete-sec">Discrete:</A> <A HREF="rand.html#continuous-sec">Continuous:</A></I>
<A HREF="rand.html#seed">rand_seed</A> <A HREF="rand.html#uniform">rand_uniform</A> <A HREF="rand.html#int">rand_int</A> <A HREF="rand.html#gaussian">rand_gaussian</A>
<A HREF="rand.html#get_state">rand_get_state</A> <A HREF="rand.html#uniopen">rand_uniopen</A> <A HREF="rand.html#pickd">rand_pickd</A> <A HREF="rand.html#logistic">rand_logistic</A>
<A HREF="rand.html#use_state">rand_use_state</A> <A HREF="rand.html#pickf">rand_pickf</A> <A HREF="rand.html#cauchy">rand_cauchy</A>
<A HREF="rand.html#poisson">rand_poisson</A> <A HREF="rand.html#gamma">rand_gamma</A>
<A HREF="rand.html#permutation">rand_permutation</A> <A HREF="rand.html#exp">rand_exp</A>
<A HREF="rand.html#beta">rand_beta</A>
</PRE></BLOCKQUOTE>
<P>Each of the modules above has a test program, called
<TT><I>module</I>-test</TT>. These programs are compiled by the command
<BLOCKQUOTE><PRE>
make tests
</PRE></BLOCKQUOTE>
See the source files for these test programs for further information.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>
@@ -1,262 +0,0 @@
#ifndef CONFIGURATION_HPP_
#define CONFIGURATION_HPP_
#include <QObject>
#include <QFont>
#include "Radio.hpp"
#include "IARURegions.hpp"
#include "AudioDevice.hpp"
#include "Transceiver.hpp"
#include "pimpl_h.hpp"
class QSettings;
class QWidget;
class QAudioDeviceInfo;
class QString;
class QDir;
class Bands;
class FrequencyList;
class StationList;
class QStringListModel;
class QHostAddress;
//
// Class Configuration
//
// Encapsulates the control, access and, persistence of user defined
// settings for the wsjtx GUI. Setting values are accessed through a
// QDialog window containing concept orientated tab windows.
//
// Responsibilities
//
// Provides management of the CAT and PTT rig interfaces, providing
// control access via a minimal generic set of Qt slots and status
// updates via Qt signals. Internally the rig control capability is
// farmed out to a separate thread since many of the rig control
// functions are blocking.
//
// All user settings required by the wsjtx GUI are exposed through
// query methods. Settings only become visible once they have been
// accepted by the user which is done by clicking the "OK" button on
// the settings dialog.
//
// The QSettings instance passed to the constructor is used to read
// and write user settings.
//
// Pointers to three QAbstractItemModel objects are provided to give
// access to amateur band information, user working frequencies and,
// user operating band information. These porovide consistent data
// models that can be used in GUI lists or tables or simply queried
// for user defined bands, default operating frequencies and, station
// descriptions.
//
class Configuration final
: public QObject
{
Q_OBJECT
Q_ENUMS (DataMode Type2MsgGen)
public:
using MODE = Transceiver::MODE;
using TransceiverState = Transceiver::TransceiverState;
using Frequency = Radio::Frequency;
using port_type = quint16;
enum DataMode {data_mode_none, data_mode_USB, data_mode_data};
Q_ENUM (DataMode)
enum Type2MsgGen {type_2_msg_1_full, type_2_msg_3_full, type_2_msg_5_only};
Q_ENUM (Type2MsgGen)
explicit Configuration (QDir const& temp_directory, QSettings * settings,
QWidget * parent = nullptr);
~Configuration ();
void select_tab (int);
int exec ();
bool is_active () const;
QDir temp_dir () const;
QDir doc_dir () const;
QDir data_dir () const;
QDir writeable_data_dir () const;
QAudioDeviceInfo const& audio_input_device () const;
AudioDevice::Channel audio_input_channel () const;
QAudioDeviceInfo const& audio_output_device () const;
AudioDevice::Channel audio_output_channel () const;
// These query methods should be used after a call to exec() to
// determine if either the audio input or audio output stream
// parameters have changed. The respective streams should be
// re-opened if they return true.
bool restart_audio_input () const;
bool restart_audio_output () const;
QString my_callsign () const;
QString my_grid () const;
QFont decoded_text_font () const;
qint32 id_interval () const;
qint32 ntrials() const;
qint32 aggressive() const;
qint32 RxBandwidth() const;
double degrade() const;
double txDelay() const;
bool id_after_73 () const;
bool tx_QSY_allowed () const;
bool spot_to_psk_reporter () const;
bool monitor_off_at_startup () const;
bool monitor_last_used () const;
bool log_as_RTTY () const;
bool report_in_comments () const;
bool prompt_to_log () const;
bool insert_blank () const;
bool DXCC () const;
bool clear_DX () const;
bool miles () const;
bool quick_call () const;
bool disable_TX_on_73 () const;
int watchdog () const;
bool TX_messages () const;
bool split_mode () const;
bool enable_VHF_features () const;
bool decode_at_52s () const;
bool single_decode () const;
bool twoPass() const;
bool x2ToneSpacing() const;
bool contestMode() const;
bool realTimeDecode() const;
bool MyDx() const;
bool CQMyN() const;
bool NDxG() const;
bool NN() const;
bool EMEonly() const;
bool post_decodes () const;
QString udp_server_name () const;
port_type udp_server_port () const;
bool accept_udp_requests () const;
bool udpWindowToFront () const;
bool udpWindowRestore () const;
Bands * bands ();
Bands const * bands () const;
IARURegions::Region region () const;
FrequencyList * frequencies ();
FrequencyList const * frequencies () const;
StationList * stations ();
StationList const * stations () const;
QStringListModel * macros ();
QStringListModel const * macros () const;
QDir save_directory () const;
QDir azel_directory () const;
QString rig_name () const;
Type2MsgGen type_2_msg_gen () const;
QColor color_CQ () const;
QColor color_MyCall () const;
QColor color_TxMsg () const;
QColor color_DXCC () const;
QColor color_NewCall () const;
bool pwrBandTxMemory () const;
bool pwrBandTuneMemory () const;
// This method queries if a CAT and PTT connection is operational.
bool is_transceiver_online () const;
// Start the rig connection, safe and normal to call when rig is
// already open.
bool transceiver_online ();
// check if a real rig is configured
bool is_dummy_rig () const;
// Frequency resolution of the rig
//
// 0 - 1Hz
// 1 - 10Hz rounded
// -1 - 10Hz truncated
// 2 - 100Hz rounded
// -2 - 100Hz truncated
int transceiver_resolution () const;
// Close down connection to rig.
void transceiver_offline ();
// Set transceiver frequency in Hertz.
Q_SLOT void transceiver_frequency (Frequency);
// Setting a non zero TX frequency means split operation
// rationalise_mode means ensure TX uses same mode as RX.
Q_SLOT void transceiver_tx_frequency (Frequency = 0u);
// Set transceiver mode.
//
// Rationalise means ensure TX uses same mode as RX.
Q_SLOT void transceiver_mode (MODE);
// Set/unset PTT.
//
// Note that this must be called even if VOX PTT is selected since
// the "Emulate Split" mode requires PTT information to coordinate
// frequency changes.
Q_SLOT void transceiver_ptt (bool = true);
// Attempt to (re-)synchronise transceiver state.
//
// Force signal guarantees either a transceiver_update or a
// transceiver_failure signal.
//
// The enforce_mode_and_split parameter ensures that future
// transceiver updates have the correct mode and split setting
// i.e. the transceiver is ready for use.
Q_SLOT void sync_transceiver (bool force_signal = false, bool enforce_mode_and_split = false);
//
// This signal indicates that a font has been selected and accepted
// for the decoded text.
//
Q_SIGNAL void decoded_text_font_changed (QFont);
//
// This signal is emitted when the UDP server changes
//
Q_SIGNAL void udp_server_changed (QString const& udp_server);
Q_SIGNAL void udp_server_port_changed (port_type server_port);
//
// These signals are emitted and reflect transceiver state changes
//
// signals a change in one of the TransceiverState members
Q_SIGNAL void transceiver_update (Transceiver::TransceiverState const&) const;
// Signals a failure of a control rig CAT or PTT connection.
//
// A failed rig CAT or PTT connection is fatal and the underlying
// connections are closed automatically. The connections can be
// re-established with a call to transceiver_online(true) assuming
// the fault condition has been rectified or is transient.
Q_SIGNAL void transceiver_failure (QString const& reason) const;
private:
class impl;
pimpl<impl> m_;
};
#if QT_VERSION < 0x050500
Q_DECLARE_METATYPE (Configuration::DataMode);
Q_DECLARE_METATYPE (Configuration::Type2MsgGen);
#endif
#if !defined (QT_NO_DEBUG_STREAM)
ENUM_QDEBUG_OPS_DECL (Configuration, DataMode);
ENUM_QDEBUG_OPS_DECL (Configuration, Type2MsgGen);
#endif
ENUM_QDATASTREAM_OPS_DECL (Configuration, DataMode);
ENUM_QDATASTREAM_OPS_DECL (Configuration, Type2MsgGen);
ENUM_CONVERSION_OPS_DECL (Configuration, DataMode);
ENUM_CONVERSION_OPS_DECL (Configuration, Type2MsgGen);
#endif
@@ -1,342 +0,0 @@
<HTML><HEAD>
<TITLE> Decoding Received Blocks </TITLE>
</HEAD><BODY>
<H1> Decoding Received Blocks </H1>
Transmitted codewords are decoded from the received data on the basis
of the <I>likelihood</I> of the possible codewords, which is the
probability of receiving the data that was actually received if the
codeword is question were the one that was sent. This software
presently deals only with memoryless channels, in which the noise is
independent from bit to bit. For such a channel, the likelihood
factorizes into a product of likelihoods for each bit.
For decoding purposes, all that matters is the relative likelihood
for a bit to be 1 versus 0. This is captured by the <I>likelihood
ratio</I> in favour of a 1, which is P(data | bit is 1) / P(data |
bit is 0).
<P>For a Binary Symmetric Channel with error probability <I>p</I>,
the likelihood ratio in favour of a 1 bit is as follows:
<BLOCKQUOTE>
If the received data was +1: (1-<I>p</I>) / <I>p</I><BR>
If the received data was -1: <I>p</I> / (1-<I>p</I>)
</BLOCKQUOTE>
For an Additive White Gaussian Noise channel, with signals of +1 for a 1 bit
and or -1 for a 0 bit, and with noise standard deviation <I>s</I>, the
likelihood ratio in favour of a 1 bit when data <I>y</I> was received is
<BLOCKQUOTE>
exp ( 2y / s<SUP><SMALL>2</SMALL></SUP> )
</BLOCKQUOTE>
For an Additive White Logistic Noise channel, the corresponding
likelihood ratio is
<I>d</I><SUB><SMALL>1</SMALL></SUB>/<I>d</I><SUB><SMALL>0</SMALL></SUB>,
where
<I>d</I><SUB><SMALL>1</SMALL></SUB>=<I>e</I><SUB><SMALL>1</SMALL></SUB>
/ (1+<I>e</I><SUB><SMALL>1</SMALL></SUB>)<SUP><SMALL>2</SMALL></SUP> and
<I>d</I><SUB><SMALL>0</SMALL></SUB>=<I>e</I><SUB><SMALL>0</SMALL></SUB>
/ (1+<I>e</I><SUB><SMALL>0</SMALL></SUB>)<SUP><SMALL>2</SMALL></SUP>,
with <I>e</I><SUB><SMALL>1</SMALL></SUB>=exp(-(<I>y</I>-1)/<I>w</I>) and
<I>e</I><SUB><SMALL>0</SMALL></SUB>=exp(-(<I>y</I>+1)/<I>w</I>).
<BLOCKQUOTE> </BLOCKQUOTE>
<P>It is usual to consider codewords to be equally likely <I>a
priori</I>. This is reasonable if the source messages are all equally
likely (any source redundancy being ignored, or remove by a
preliminary data compression stage), provided that the mapping from
source messages to codewords is onto. Decoding can then be done using
only the parity check matrix defining the codewords, without reference
to the generator matrix defining the mapping from source messages to
codewords. Note that the condition that this mapping be onto isn't
true with this software in the atypical case where the code is defined
by a parity check matrix with redundant rows; see the discussion of <A
HREF="dep-H.html">linear dependence in parity check matrices</A>.
This minor complication is mostly ignored here, except by the exhaustive
enumeration decoding methods.
<P>Assuming equal <I>a priori</I> probabilities for codewords, the
probability of correctly decoding an entire codeword is minimized by
picking the codeword with the highest likelihood. One might instead
wish to decode each bit to the value that is most probable. This
minimizes the bit error rate, but is not in general guaranteed to lead
a decoding for each block to the most probable complete codeword;
indeed, the decoding may not be a codeword at all. Minimizing the bit
error rate seems nevertheless to be the most sensible objective,
unless block boundaries have some significance in a wider context.
<P>Optimal decoding by either criterion is infeasible for general
linear codes when messages are more than about 20 or 30 bits in
length. The fundamental advantage of Low Density Parity Check codes
is that good (though not optimal) decodings can be obtained by methods
such as probability propagation, described next.
<A NAME="prprp"><H2>Decoding by probability propagation</H2></A>
<P>The probability propagation algorithm was originally devised by
Robert Gallager in the early 1960's and later reinvented by David
MacKay and myself. It can be seen as an instance of the sum-product
algorithm for inference on factor graphs, and as an instance of belief
propagation in probabilistic networks. See the <A
HREF="refs.html">references</A> for details. Below, I give a fairly
intuitive description of the algorithm.
<P>The algorithm uses only the parity check matrix for the code, whose
columns correspond to codeword bits, and whose rows correspond to
parity checks, and the likelihood ratios for the bits derived from the
data. It aims to find the probability of each bit of the transmitted
codeword being 1, though the results of the algorithm are in general
only approximate.
<P>The begin, information about each bit of the codeword derived from
the received data for that bit alone is expressed as a <I>probability
ratio</I>, the probability of the bit being 1 divided by the
probability of the bit being 0. This probability ratio is equal to
the likelihood ratio (see above) for that bit, since 0 and 1 are
assumed to be equally likely <I>a priori</I>. As the algorithm
progresses, these probability ratios will be modified to take account
of information obtained from other bits, in conjunction with the
requirement that the parity checks be satisfied. To avoid double
counting of information, for every bit, the algorithm maintains a
separate probability ratio for each parity check that that bit
participates in, giving the probability for that bit to be 1 versus 0
based only on information derived from <I>other</I> parity checks,
along with the data received for the bit.
<P>For each parity check, the algorithm maintains separate
<I>likelihood ratios</I> (analogous to, but distinct from, the
likelihood ratios based on received data), for every bit that
participates in that parity check. These ratios give the probability
of that parity check being satisfied if the bit in question is 1
divided by the probability of the check being satisfied if the bit is
0, taking account of the probabilities of each of the <I>other</I>
bits participating in this check being 1, as derived from the
probability ratios for these bits with respect to this check.
<P>The algorithm alternates between recalculating the likelihood
ratios for each check, which are stored in the <B>lr</B> fields of the
parity check matrix entries, and recalculating the probability ratios
for each bit, which are stored in the <B>pr</B> fields of the entries
in the sparse matrix representation of the parity check matrix. (See
the documentation on <A HREF="mod2sparse.html#rep">representation of
sparse matrices</A> for details on these entries.)
<P>Recalculating the likelihood ratio for a check with respect to some
bit may appear time consuming, requiring that all possible
combinations of values for the other bits participating in the check
be considered. Fortunately, there is a short cut. One can calculate
<BLOCKQUOTE>
<I>t</I>
= product of [ 1 / (1+<I>p<SUB><SMALL>i</SMALL></SUB></I>)
- <I>p<SUB><SMALL>i</SMALL></SUB></I> /
(1+<I>p<SUB><SMALL>i</SMALL></SUB></I>) ]
= product of [ 2 / (1+<I>p<SUB><SMALL>i</SMALL></SUB></I>) - 1 ]
</BLOCKQUOTE>
where the product is over the probability ratios
<I>p<SUB><SMALL>i</SMALL></SUB></I> for the other bits participating
in this check. Factor <I>i</I> in this product is equal to probability
of bit <I>i</I> being 0 minus the probability that it is 1. The terms
in the expansion of this product (in the first form above) correspond to
possible combinations of values for the other bits, with the result that
<I>t</I> will be the probability of the check being satisfied if the bit
in question is 0 minus the probability if the bit in question is 1. The
likelihood ratio for this check with respect to the bit in question can then
be calculated as (1-<I>t</I>)/(1+<I>t</I>).
<P>For a particular check, the product above differs for different
bits, with respect to which we wish to calculate a likelihood ratio,
only in that for each bit the factor corresponding to that bit is left
out. We can calculate all these products easily by ordering the bits
arbitrarily, computing running products of the factor for the first
bit, the factors for the first two bits, etc., and also running
products of the factor for the last bit, the factors for the last two
bits, etc. Multiplying the running product of the factors up to
<I>i</I>-1 by the running product of the factors from <I>i</I>+1 on
gives the product needed for bit <I>i</I>. The second form of the
factors above is used, as it requires less computation, and is still
well defined even if some ratios are infinite.
<P>To recalculate the probability ratio for a bit with respect to a
check, all that is need is to multiply together the likelihood ratio
for this bit derived from the received data (see above), and the
current values of the likelihood ratios for all the <I>other</I>
checks that this bit participates in, with respect to this bit. To
save time, these products are computed by combining forward and
backward products, similarly to the method used for likelihood ratios.
<P>By including likelihood ratios from all checks, a similar
calculation produces the current probability ratio for the bit to be 1
versus 0 based on all information that has propagated to the bit so
far. This ratio can be thresholded at one to produce the current best
guess as to whether this bit is a 1 or a 0.
<P>The hope is that this algorithm will eventually converge to a state
where these bit probabilities give a near-optimal decoding. This is
does not always occur, but the algorithm behaves well enough to
produce very good results at rates approaching (though not yet
reaching) the theoretical Shannon limit.
<P><A NAME="decode"><HR><B>decode</B>: Decode blocks of received data
into codewords.
<BLOCKQUOTE><PRE>
decode [ -f ] [ -t | -T ] <I>pchk-file received-file decoded-file</I> [ <I>bp-file</I> ] <I>channel method</I>
</PRE>
<BLOCKQUOTE>
where <TT><I>channel</I></TT> is one of:
<BLOCKQUOTE><PRE>
bsc <I>error-probability</I>
awgn <I>standard-deviation</I>
awln <I>width</I>
</PRE></BLOCKQUOTE>
and <TT><I>method</I></TT> is one of:
<BLOCKQUOTE><PRE>
enum-block <TT><I>gen-file</I></TT>
enum-bit <TT><I>gen-file</I></TT>
prprp <TT>[-]<I>max-iterations</I></TT>
</PRE></BLOCKQUOTE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<P>Decodes the blocks in <TT><I>received-file</I></TT>, which are
assumed to be have been received through the specified channel. The
results written to <TT><I>decoded-file</I></TT> are the specified
decoding method's guesses as to what bits were sent through the
channel, given what was received. The probability of each bit being a
1, as judged by the decoding method being used, is written to
<TT><I>bp-file</I></TT>, if given.
<P>A newline is output at the end of each block written to
<TT><I>decoded-file</I></TT> and <TT><I>bp-file</I></TT>. Newlines in
<TT><I>received-file</I></TT> are ignored. A warning is displayed on
standard error if the number of bits in <TT><I>received-file</I></TT>
is not a multiple of the block length.
<P>A summary is displayed on standard error, giving the total number
of blocks decoded, the number of blocks that decoded to valid
codewords, the average number of iterations of the decoding algorithm
used, and the percent of bits that were changed from the values one
would guess for them based just on their individual likelihood ratios.
<P>If the <B>-t</B> option is given, a line of information regarding each block
decoded is written to standard output, preceded by a line of headers.
The information for each block is as follows:
<BLOCKQUOTE>
<TABLE>
<tr align="left" valign="top">
<td> <B>block</B> </td>
<td>The number of the block, from zero</td></tr>
<tr align="left" valign="top">
<td> <B>iterations</B> </td>
<td>The number of "iterations" used in decoding. What exactly an iteration
is depends on the decoding method used (see
<A HREF="decode-detail.html">here</A>).</td></tr>
<tr align="left" valign="top">
<td> <B>valid</B> </td>
<td>Has the value 1 if the decoding is a valid codeword, 0 if not.</td></tr>
<tr align="left" valign="top">
<td> <B>changed</B> </td>
<td>The number of bits in the decoding that differ from the bit that would
be chosen based just on the likelihood ratio for that bit. Bits whose
likelihood ratios are exactly one contribute 0.5 to this count.</td></tr>
</TABLE>
</BLOCKQUOTE>
The file produced is is suitable for
reading into the S-Plus or R statistics packages, with a command such as
<BLOCKQUOTE><PRE>
data <- read.table(<I>file</I>,header=T)
</PRE></BLOCKQUOTE>
<P>If instead the <B>-T</B> option is given, detailed information on
the process of decoding each block will be written to standard output.
For a description, see the <A HREF="decode-detail.html">documentation
on detailed decoding trace information</A>.
<P>The type of channel that is assumed is specified after the file
name arguments. This may currently be either <TT>bsc</TT> (or
<TT>BSC</TT>) for the Binary Symmetric Channel, or <TT>awgn</TT> (or
<TT>AWGN</TT>) for the Additive White Gaussian Noise channel, or
<TT>awln</TT> (or <TT>AWLN</TT>) for the Additive White Logistic Noise
channel. The channel type is followed by an argument specifying the
assumed characteristics of the channel, as follows:
<BLOCKQUOTE>
<P>BSC: The probability that a bit will be flipped by noise - ie, the
probability that the bit received is an error.
<P>AWGN: The standard deviation of the Gaussian noise added to the
encodings of the bits.
<P>AWLN: The width parameter of the logistic distribution for the noise
that is added to the encodings of the bits.
</BLOCKQUOTE>
See the description of <A HREF="channel.html">channel transmission</A>
for more about these channels.
<P>Following the channel specification is a specification of the
decoding method to use. The <TT>enum-block</TT> and <TT>enum-bit</TT>
methods find the optimal decoding by exhaustive enumeration of
codewords derived from all possible source messages. They differ in
that <TT>enum-block</TT> decodes to the most likely codeword, whereas
<TT>enum-bit</TT> decodes to the bits that are individually most
probable. These methods require that a file containing a
representation of a generator matrix be given, to allow enumeration of
codewords. If the parity check matrix has no redundant rows, any
valid generator matrix will give the same decoding (except perhaps if
there is a tie). If redundant rows exist, the generator matrix should
specify the same set of message bits as the generator matrix that was
used for the actual encoding, since the redundancy will lead to some
codeword bits being fixed at zero (see <A HREF="dep-H.html">linear
dependence in parity check matrices</A>).
<P>The <TT>prprp</TT> decoding method decodes using <A
HREF="#prprp">probability propagation</A>. The maximum number of
iterations of probability propagation to do is given following
<TT>prprp</TT>. If a minus sign precedes this number, the maximum
number of iterations is always done. If no minus sign is present, the
algorithm stops once the tentative decoding, based on bit-by-bit
probabilities, is a valid codeword. Note that continuing to the
maximum number of iterations will usually result in
at least slightly different bit probabilities (written to
<TT><I>bp-file</I></TT> if specified), and could conceivably change
the decoding compared to stopping at the first valid codeword, or
result in a failure to decode to a valid codeword even though one was
found earlier.
<P>If the <B>-f</B> option is given, output to <TT><I>decoded-file</I></TT>
is flushed after each block. This allows one to use decode as a server,
reading blocks to decode from a named pipe, and writing the decoded block
to another named pipe.
<P><A NAME="extract"><HR><B>extract</B>: Extract the message bits from a block.
<BLOCKQUOTE><PRE>
extract <I>gen-file decoded-file extracted-file</I>
</PRE></BLOCKQUOTE>
<P>Given a file of codewords in <TT><I>decoded-file</I></TT> (usually,
decoded blocks output by <A HREF="#decode"><TT>decode</TT></A>), and a
generator matrix from <TT><I>gen-file</I></TT> (needed only to
determine where the message bits are located in a codeword), this
program writes the message bits extracted from these codewords to the
file <TT><I>extracted-file</I></TT>.
<P>A newline is output at the end of each block written to
<TT><I>extracted-file</I></TT>. Newlines in
<TT><I>decoded-file</I></TT> are ignored. A warning is displayed on
standard error if the number of bits in <TT><I>decoded-file</I></TT>
is not a multiple of the block length.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>
@@ -8,7 +8,9 @@
#include <QtGui> #include <QtGui>
#endif #endif
#include <QString>
#include <QScopedPointer> #include <QScopedPointer>
#include <QDateTime>
#include "Radio.hpp" #include "Radio.hpp"
@@ -18,6 +20,7 @@ namespace Ui {
class QSettings; class QSettings;
class Configuration; class Configuration;
class QByteArray;
class LogQSO : public QDialog class LogQSO : public QDialog
{ {
@@ -30,7 +33,7 @@ public:
QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn, QString const& rptSent, QString const& rptRcvd, QDateTime const& dateTimeOn,
QDateTime const& dateTimeOff, QDateTime const& dateTimeOff,
Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid, Radio::Frequency dialFreq, QString const& myCall, QString const& myGrid,
bool noSuffix, bool toRTTY, bool dBtoComments); bool noSuffix, bool toRTTY, bool dBtoComments, bool bFox, QString const& opCall);
public slots: public slots:
void accept(); void accept();
@@ -40,7 +43,8 @@ signals:
, Radio::Frequency dial_freq, QString const& mode , Radio::Frequency dial_freq, QString const& mode
, QString const& rpt_sent, QString const& rpt_received , QString const& rpt_sent, QString const& rpt_received
, QString const& tx_power, QString const& comments , QString const& tx_power, QString const& comments
, QString const& name, QDateTime const& QSO_date_on); , QString const& name, QDateTime const& QSO_date_on, QString const& operator_call
, QString const& my_call, QString const& my_grid, QByteArray const& ADIF);
protected: protected:
void hideEvent (QHideEvent *); void hideEvent (QHideEvent *);
@@ -1,238 +0,0 @@
program ldpcsim174
! End to end test of the (174,75)/crc12 encoder and decoder.
use crc
use packjt
parameter(NRECENT=10)
character*12 recent_calls(NRECENT)
character*22 msg,msgsent,msgreceived
character*8 arg
integer*1, allocatable :: codeword(:), decoded(:), message(:)
integer*1, target:: i1Msg8BitBytes(11)
integer*1 msgbits(87)
integer*1 apmask(174), cw(174)
integer*2 checksum
integer*4 i4Msg6BitWords(13)
integer colorder(174)
integer nerrtot(174),nerrdec(174),nmpcbad(87)
logical checksumok,fsk,bpsk
real*8, allocatable :: rxdata(:)
real, allocatable :: llr(:)
data colorder/ &
0, 1, 2, 3, 30, 4, 5, 6, 7, 8, 9, 10, 11, 32, 12, 40, 13, 14, 15, 16,&
17, 18, 37, 45, 29, 19, 20, 21, 41, 22, 42, 31, 33, 34, 44, 35, 47, 51, 50, 43,&
36, 52, 63, 46, 25, 55, 27, 24, 23, 53, 39, 49, 59, 38, 48, 61, 60, 57, 28, 62,&
56, 58, 65, 66, 26, 70, 64, 69, 68, 67, 74, 71, 54, 76, 72, 75, 78, 77, 80, 79,&
73, 83, 84, 81, 82, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,&
100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,&
120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,&
140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,&
160,161,162,163,164,165,166,167,168,169,170,171,172,173/
do i=1,NRECENT
recent_calls(i)=' '
enddo
nerrtot=0
nerrdec=0
nmpcbad=0 ! Used to collect the number of errors in the message+crc part of the codeword
nargs=iargc()
if(nargs.ne.4) then
print*,'Usage: ldpcsim niter norder #trials s '
print*,'eg: ldpcsim 10 2 1000 0.84'
print*,'belief propagation iterations: niter, ordered-statistics order: norder'
print*,'If s is negative, then value is ignored and sigma is calculated from SNR.'
return
endif
call getarg(1,arg)
read(arg,*) max_iterations
call getarg(2,arg)
read(arg,*) norder
call getarg(3,arg)
read(arg,*) ntrials
call getarg(4,arg)
read(arg,*) s
fsk=.false.
bpsk=.true.
! don't count crc bits as data bits
N=174
K=87
! scale Eb/No for a (174,87) code
rate=real(K)/real(N)
write(*,*) "rate: ",rate
write(*,*) "niter= ",max_iterations," s= ",s
allocate ( codeword(N), decoded(K), message(K) )
allocate ( rxdata(N), llr(N) )
msg="K1JT K9AN EN50"
! msg="G4WJS K9AN EN50"
call packmsg(msg,i4Msg6BitWords,itype) !Pack into 12 6-bit bytes
call unpackmsg(i4Msg6BitWords,msgsent) !Unpack to get msgsent
write(*,*) "message sent ",msgsent
i4=0
ik=0
im=0
do i=1,12
nn=i4Msg6BitWords(i)
do j=1, 6
ik=ik+1
i4=i4+i4+iand(1,ishft(nn,j-6))
i4=iand(i4,255)
if(ik.eq.8) then
im=im+1
! if(i4.gt.127) i4=i4-256
i1Msg8BitBytes(im)=i4
ik=0
endif
enddo
enddo
i1Msg8BitBytes(10:11)=0
checksum = crc12 (c_loc (i1Msg8BitBytes), 11)
! For reference, the next 3 lines show how to check the CRC
i1Msg8BitBytes(10)=checksum/256
i1Msg8BitBytes(11)=iand (checksum,255)
checksumok = crc12_check(c_loc (i1Msg8BitBytes), 11)
if( checksumok ) write(*,*) 'Good checksum'
! K=87, For now:
! msgbits(1:72) JT message bits
! msgbits(73:75) 3 free message bits (set to 0)
! msgbits(76:87) CRC12
mbit=0
do i=1, 9
i1=i1Msg8BitBytes(i)
do ibit=1,8
mbit=mbit+1
msgbits(mbit)=iand(1,ishft(i1,ibit-8))
enddo
enddo
msgbits(73:75)=0 ! the three extra message bits go here
i1=i1Msg8BitBytes(10) ! First 4 bits of crc12 are LSB of this byte
do ibit=1,4
msgbits(75+ibit)=iand(1,ishft(i1,ibit-4))
enddo
i1=i1Msg8BitBytes(11) ! Now shift in last 8 bits of the CRC
do ibit=1,8
msgbits(79+ibit)=iand(1,ishft(i1,ibit-8))
enddo
write(*,*) 'message'
write(*,'(11(8i1,1x))') msgbits
call encode174(msgbits,codeword)
call init_random_seed()
call sgran()
write(*,*) 'codeword'
write(*,'(22(8i1,1x))') codeword
write(*,*) "Es/N0 SNR2500 ngood nundetected nbadcrc sigma"
do idb = 20,-10,-1
db=idb/2.0-1.0
sigma=1/sqrt( 2*(10**(db/10.0)) )
ngood=0
nue=0
nbadcrc=0
nberr=0
do itrial=1, ntrials
! Create a realization of a noisy received word
do i=1,N
if( bpsk ) then
rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran()
elseif( fsk ) then
if( codeword(i) .eq. 1 ) then
r1=(1.0 + sigma*gran())**2 + (sigma*gran())**2
r2=(sigma*gran())**2 + (sigma*gran())**2
elseif( codeword(i) .eq. 0 ) then
r2=(1.0 + sigma*gran())**2 + (sigma*gran())**2
r1=(sigma*gran())**2 + (sigma*gran())**2
endif
! rxdata(i)=0.35*(sqrt(r1)-sqrt(r2))
! rxdata(i)=0.35*(exp(r1)-exp(r2))
rxdata(i)=0.12*(log(r1)-log(r2))
endif
enddo
nerr=0
do i=1,N
if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1
enddo
nerrtot(nerr)=nerrtot(nerr)+1
nberr=nberr+nerr
! Correct signal normalization is important for this decoder.
rxav=sum(rxdata)/N
rx2av=sum(rxdata*rxdata)/N
rxsig=sqrt(rx2av-rxav*rxav)
rxdata=rxdata/rxsig
! To match the metric to the channel, s should be set to the noise standard deviation.
! For now, set s to the value that optimizes decode probability near threshold.
! The s parameter can be tuned to trade a few tenth's dB of threshold for an order of
! magnitude in UER
if( s .lt. 0 ) then
ss=sigma
else
ss=s
endif
llr=2.0*rxdata/(ss*ss)
nap=0 ! number of AP bits
llr(colorder(174-87+1:174-87+nap)+1)=5*(2.0*msgbits(1:nap)-1.0)
apmask=0
apmask(colorder(174-87+1:174-87+nap)+1)=1
! max_iterations is max number of belief propagation iterations
call bpdecode174(llr, apmask, max_iterations, decoded, cw, nharderrors)
if( norder .ge. 0 .and. nharderrors .lt. 0 ) call osd174(llr, norder, decoded, cw, nharderrors)
! If the decoder finds a valid codeword, nharderrors will be .ge. 0.
if( nharderrors .ge. 0 ) then
call extractmessage174(decoded,msgreceived,ncrcflag,recent_calls,nrecent)
if( ncrcflag .ne. 1 ) then
nbadcrc=nbadcrc+1
endif
nueflag=0
nerrmpc=0
do i=1,K ! find number of errors in message+crc part of codeword
if( msgbits(i) .ne. decoded(i) ) then
nueflag=1
nerrmpc=nerrmpc+1
endif
enddo
nmpcbad(nerrmpc)=nmpcbad(nerrmpc)+1
if( ncrcflag .eq. 1 ) then
if( nueflag .eq. 0 ) then
ngood=ngood+1
nerrdec(nerr)=nerrdec(nerr)+1
else if( nueflag .eq. 1 ) then
nue=nue+1;
endif
endif
endif
enddo
baud=12000/2048
snr2500=db+10.0*log10((baud/2500.0))
pberr=real(nberr)/(real(ntrials*N))
write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,1x,i8,8x,f5.2,8x,e10.3)") db,snr2500,ngood,nue,nbadcrc,ss,pberr
enddo
open(unit=23,file='nerrhisto.dat',status='unknown')
do i=1,174
write(23,'(i4,2x,i10,i10,f10.2)') i,nerrdec(i),nerrtot(i),real(nerrdec(i))/real(nerrtot(i)+1e-10)
enddo
close(23)
open(unit=25,file='nmpcbad.dat',status='unknown')
do i=1,87
write(25,'(i4,2x,i10)') i,nmpcbad(i)
enddo
close(25)
end program ldpcsim174
@@ -1,41 +0,0 @@
// -*- Mode: C++ -*-
#ifndef DISPLAYTEXT_H
#define DISPLAYTEXT_H
#include <QTextEdit>
#include <QFont>
#include "logbook/logbook.h"
#include "decodedtext.h"
class DisplayText
: public QTextEdit
{
Q_OBJECT
public:
explicit DisplayText(QWidget *parent = 0);
void setContentFont (QFont const&);
void insertLineSpacer(QString const&);
void displayDecodedText(DecodedText decodedText, QString myCall, bool displayDXCCEntity,
LogBook logBook, QColor color_CQ, QColor color_MyCall,
QColor color_DXCC, QColor color_NewCall);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
QColor color_TxMsg, bool bFastMode);
void displayQSY(QString text);
Q_SIGNAL void selectCallsign (bool alt, bool ctrl);
Q_SLOT void appendText (QString const& text, QColor bg = Qt::white);
protected:
void mouseDoubleClickEvent(QMouseEvent *e);
private:
QString appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg, LogBook logBook,
QColor color_CQ, QColor color_DXCC, QColor color_NewCall);
QFont char_font_;
};
#endif // DISPLAYTEXT_H
@@ -1,100 +0,0 @@
program ft8sim
! Generate simulated data for a 15-second HF/6m mode using 8-FSK.
! Output is saved to a *.wav file.
use wavhdr
include 'ft8_params.f90' !Set various constants
type(hdr) h !Header for .wav file
character arg*12,fname*17
character msg*22,msgsent*22
complex c0(0:NMAX-1)
complex c(0:NMAX-1)
integer itone(NN)
integer*2 iwave(NMAX) !Generated full-length waveform
! Get command-line argument(s)
nargs=iargc()
if(nargs.ne.6) then
print*,'Usage: ft8sim "message" DT fdop del nfiles snr'
print*,'Example: ft8sim "K1ABC W9XYZ EN37" 0.0 0.1 1.0 10 -18'
go to 999
endif
call getarg(1,msg) !Message to be transmitted
call getarg(2,arg)
read(arg,*) xdt !Time offset from nominal (s)
call getarg(3,arg)
read(arg,*) fspread !Watterson frequency spread (Hz)
call getarg(4,arg)
read(arg,*) delay !Watterson delay (ms)
call getarg(5,arg)
read(arg,*) nfiles !Number of files
call getarg(6,arg)
read(arg,*) snrdb !SNR_2500
twopi=8.0*atan(1.0)
fs=12000.0 !Sample rate (Hz)
dt=1.0/fs !Sample interval (s)
tt=NSPS*dt !Duration of symbols (s)
baud=1.0/tt !Keying rate (baud)
bw=8*baud !Occupied bandwidth (Hz)
txt=NZ*dt !Transmission length (s)
bandwidth_ratio=2500.0/(fs/2.0)
sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb)
if(snrdb.gt.90.0) sig=1.0
txt=NN*NSPS/12000.0
call genft8(msg,msgsent,itone) !Source-encode, then get itone()
write(*,1000) f0,xdt,txt,snrdb,bw,msgsent
1000 format('f0:',f9.3,' DT:',f6.2,' TxT:',f6.1,' SNR:',f6.1, &
' BW:',f4.1,2x,a22)
! call sgran()
c=0.
do ifile=1,nfiles
c0=0.
do isig=1,25
f0=(isig+2)*100.0
phi=0.0
k=-1 + nint(xdt/dt)
do j=1,NN !Generate complex waveform
dphi=twopi*(f0+itone(j)*baud)*dt
if(k.eq.0) phi=-dphi
do i=1,NSPS
k=k+1
phi=phi+dphi
if(phi.gt.twopi) phi=phi-twopi
xphi=phi
if(k.ge.0 .and. k.lt.NMAX) c0(k)=cmplx(cos(xphi),sin(xphi))
enddo
enddo
if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c,NZ,fs,delay,fspread)
c=c+c0
enddo
c=c*sig
if(snrdb.lt.90) then
do i=0,NZ-1 !Add gaussian noise at specified SNR
xnoise=gran()
ynoise=gran()
c(i)=c(i) + cmplx(xnoise,ynoise)
enddo
endif
fac=32767.0
rms=100.0
if(snrdb.ge.90.0) iwave(1:NMAX)=nint(fac*real(c))
if(snrdb.lt.90.0) iwave(1:NMAX)=nint(rms*real(c))
iwave(NZ+1:)=0
h=default_header(12000,NMAX)
write(fname,1102) ifile
1102 format('000000_',i6.6,'.wav')
open(10,file=fname,status='unknown',access='stream')
write(10) h,iwave !Save to *.wav file
close(10)
write(*,1110) ifile,xdt,f0,snrdb,fname
1110 format(i4,f7.2,f8.2,f7.1,2x,a17)
enddo
999 end program ft8sim
@@ -37,7 +37,8 @@ contains
subroutine decode(this,callback,dd0,npts,newdat,nutc,nf1,nf2,nfqso, & subroutine decode(this,callback,dd0,npts,newdat,nutc,nf1,nf2,nfqso, &
ntol,nsubmode,minsync,nagain,n2pass,nrobust,ntrials,naggressive, & ntol,nsubmode,minsync,nagain,n2pass,nrobust,ntrials,naggressive, &
ndepth,emedelay,clearave,mycall,hiscall,hisgrid,nexp_decode) ndepth,emedelay,clearave,mycall,hiscall,hisgrid,nexp_decode, &
nQSOProgress,ljt65apon)
! Process dd0() data to find and decode JT65 signals. ! Process dd0() data to find and decode JT65 signals.
@@ -51,8 +52,8 @@ contains
real, intent(in) :: dd0(NZMAX),emedelay real, intent(in) :: dd0(NZMAX),emedelay
integer, intent(in) :: npts, nutc, nf1, nf2, nfqso, ntol & integer, intent(in) :: npts, nutc, nf1, nf2, nfqso, ntol &
, nsubmode, minsync, n2pass, ntrials, naggressive, ndepth & , nsubmode, minsync, n2pass, ntrials, naggressive, ndepth &
, nexp_decode , nexp_decode, nQSOProgress
logical, intent(in) :: newdat, nagain, nrobust, clearave logical, intent(in) :: newdat, nagain, nrobust, clearave, ljt65apon
character(len=12), intent(in) :: mycall, hiscall character(len=12), intent(in) :: mycall, hiscall
character(len=6), intent(in) :: hisgrid character(len=6), intent(in) :: hisgrid
@@ -120,9 +121,26 @@ contains
go to 900 go to 900
endif endif
! do ipass=1,n2pass !Two-pass decoding loop single_decode=iand(nexp_decode,32).ne.0 .or. nagain
npass=1 bVHF=iand(nexp_decode,64).ne.0
if(n2pass .gt. 1) npass=ndepth+1 !**** TEMPORARY ****
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 do ipass=1,npass
first_time=.true. first_time=.true.
if(ipass.eq.1) then !First-pass parameters if(ipass.eq.1) then !First-pass parameters
@@ -149,13 +167,10 @@ contains
call timer('symsp65 ',0) call timer('symsp65 ',0)
ss=0. ss=0.
! call symspec65(dd,npts,ss,nqsym,savg) !Get normalized symbol spectra
call symspec65(dd,npts,nqsym,savg) !Get normalized symbol spectra call symspec65(dd,npts,nqsym,savg) !Get normalized symbol spectra
call timer('symsp65 ',1) call timer('symsp65 ',1)
nfa=nf1 nfa=nf1
nfb=nf2 nfb=nf2
single_decode=iand(nexp_decode,32).ne.0 .or. nagain
bVHF=iand(nexp_decode,64).ne.0
!### Q: should either of the next two uses of "single_decode" be "bVHF" instead? !### Q: should either of the next two uses of "single_decode" be "bVHF" instead?
if(single_decode .or. (bVHF .and. ntol.lt.1000)) then if(single_decode .or. (bVHF .and. ntol.lt.1000)) then
@@ -177,7 +192,6 @@ contains
ncand=0 ncand=0
call timer('sync65 ',0) call timer('sync65 ',0)
! call sync65(ss,nfa,nfb,naggressive,ntol,nqsym,ca,ncand,0,bVHF)
call sync65(nfa,nfb,naggressive,ntol,nqsym,ca,ncand,nrob,bVHF) call sync65(nfa,nfb,naggressive,ntol,nqsym,ca,ncand,nrob,bVHF)
call timer('sync65 ',1) call timer('sync65 ',1)
@@ -187,7 +201,6 @@ contains
if(ncand.eq.0) ncand=1 if(ncand.eq.0) ncand=1
if(abs(ca(1)%freq - f0).gt.width) width=2*df !### ??? ### if(abs(ca(1)%freq - f0).gt.width) width=2*df !### ??? ###
endif endif
nvec=ntrials
mode65=2**nsubmode mode65=2**nsubmode
nflip=1 nflip=1
@@ -213,7 +226,6 @@ contains
sync1=ca(icand)%sync sync1=ca(icand)%sync
dtx=ca(icand)%dt dtx=ca(icand)%dt
freq=ca(icand)%freq freq=ca(icand)%freq
!write(*,*) icand,sync1,dtx,freq,ndepth,bVHF,mode65
if(bVHF) then if(bVHF) then
flip=ca(icand)%flip flip=ca(icand)%flip
nflip=flip nflip=flip
@@ -225,8 +237,8 @@ contains
nft=0 nft=0
nspecial=0 nspecial=0
call decode65a(dd,npts,first_time,nqd,freq,nflip,mode65,nvec, & call decode65a(dd,npts,first_time,nqd,freq,nflip,mode65,nvec, &
naggressive,ndepth,ntol,mycall,hiscall,hisgrid, & naggressive,ndepth,ntol,mycall,hiscall,hisgrid,nQSOProgress, &
nexp_decode,bVHF,sync2,a,dtx,nft,nspecial,qual, & ljt65apon,nexp_decode,bVHF,sync2,a,dtx,nft,nspecial,qual, &
nhist,nsmo,decoded) nhist,nsmo,decoded)
if(nspecial.eq.2) decoded='RO' if(nspecial.eq.2) decoded='RO'
if(nspecial.eq.3) decoded='RRR' if(nspecial.eq.3) decoded='RRR'
@@ -244,7 +256,9 @@ contains
nfreq=nint(freq+a(1)) nfreq=nint(freq+a(1))
ndrift=nint(2.0*a(2)) ndrift=nint(2.0*a(2))
if(bVHF) then if(bVHF) then
s2db=sync1 - 30.0 + db(width/3.3) !### VHF/UHF/microwave xtmp=10**((sync1+16.0)/10.0) ! sync comes to us in dB
s2db=1.1*db(xtmp)+1.4*(dB(width)-4.3)-52.0
! s2db=sync1 - 30.0 + db(width/3.3) !### VHF/UHF/microwave
if(nspecial.gt.0) s2db=sync2 if(nspecial.gt.0) s2db=sync2
else else
s2db=10.0*log10(sync2) - 35 !### Empirical (HF) s2db=10.0*log10(sync2) - 35 !### Empirical (HF)
@@ -254,6 +268,7 @@ contains
if(nsnr.gt.-1) nsnr=-1 if(nsnr.gt.-1) nsnr=-1
nftt=0 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 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. ! Single-sequence FT decode failed, so try for an average FT decode.
if(nutc.ne.nutc0 .or. abs(nfreq-nfreq0).gt.ntol) then if(nutc.ne.nutc0 .or. abs(nfreq-nfreq0).gt.ntol) then
@@ -264,7 +279,8 @@ contains
nsave=mod(nsave-1,64)+1 nsave=mod(nsave-1,64)+1
call avg65(nutc,nsave,sync1,dtx,nflip,nfreq,mode65,ntol, & call avg65(nutc,nsave,sync1,dtx,nflip,nfreq,mode65,ntol, &
ndepth,nagain,ntrials,naggressive,clearave,neme,mycall, & ndepth,nagain,ntrials,naggressive,clearave,neme,mycall, &
hiscall,hisgrid,nftt,avemsg,qave,deepave,nsum,ndeepave) hiscall,hisgrid,nftt,avemsg,qave,deepave,nsum,ndeepave, &
nQSOProgress,ljt65apon)
nsmo=param(9) nsmo=param(9)
nqave=qave nqave=qave
@@ -329,13 +345,13 @@ contains
endif endif
enddo !Candidate loop enddo !Candidate loop
if(ipass.eq.2 .and. ndecoded.lt.1) exit if(ipass.eq.2 .and. ndecoded.lt.1) exit
enddo !Two-pass loop enddo !Multiple-pass loop
900 return 900 return
end subroutine decode end subroutine decode
subroutine avg65(nutc,nsave,snrsync,dtxx,nflip,nfreq,mode65,ntol,ndepth, & subroutine avg65(nutc,nsave,snrsync,dtxx,nflip,nfreq,mode65,ntol,ndepth, &
nagain, ntrials,naggressive,clearave,neme,mycall,hiscall,hisgrid,nftt, & nagain, ntrials,naggressive,clearave,neme,mycall,hiscall,hisgrid,nftt, &
avemsg,qave,deepave,nsum,ndeepave) avemsg,qave,deepave,nsum,ndeepave,nQSOProgress,ljt65apon)
! Decodes averaged JT65 data ! Decodes averaged JT65 data
@@ -358,7 +374,7 @@ contains
real s3c(64,63) real s3c(64,63)
real dtsave(MAXAVE) real dtsave(MAXAVE)
real syncsave(MAXAVE) real syncsave(MAXAVE)
logical first,clearave logical first,clearave,ljt65apon
data first/.true./ data first/.true./
save save
@@ -475,7 +491,8 @@ contains
nadd=nsum*ismo nadd=nsum*ismo
call extract(s3c,nadd,mode65,ntrials,naggressive,ndepth,nflip,mycall, & call extract(s3c,nadd,mode65,ntrials,naggressive,ndepth,nflip,mycall, &
hiscall,hisgrid,nexp_decode,ncount,nhist,avemsg,ltext,nftt,qual) hiscall,hisgrid,nQSOProgress,ljt65apon,nexp_decode,ncount,nhist, &
avemsg,ltext,nftt,qual)
if(nftt.eq.1) then if(nftt.eq.1) then
nsmo=ismo nsmo=ismo
param(9)=nsmo param(9)=nsmo
@@ -54,7 +54,7 @@ subroutine genwspr5(msg,msgsent,itone)
! Message structure: ! Message structure:
! I channel: R1 48*(S1+D1) S13 48*(D1+S1) R1 ! I channel: R1 48*(S1+D1) S13 48*(D1+S1) R1
! Q channel: R1 D109 R1 ! Q channel: R1 D204 R1
! Generate QPSK with no offset, then shift the y array to get OQPSK. ! Generate QPSK with no offset, then shift the y array to get OQPSK.
! I channel: ! I channel:
@@ -1,16 +0,0 @@
function stdmsg(msg0,bcontest,mygrid)
use iso_c_binding, only: c_bool
use packjt
character*22 msg0,msg
character*6 mygrid
integer dat(12)
logical(c_bool), value :: bcontest
logical(c_bool) :: stdmsg
call packmsg(msg0,dat,itype,logical(bcontest))
call unpackmsg(dat,msg,logical(bcontest),mygrid)
stdmsg=(msg.eq.msg0) .and. (itype.ge.0) .and. itype.ne.6
return
end function stdmsg
@@ -48,12 +48,12 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QRadioButton" name="rbRxOnly"> <widget class="QRadioButton" name="rbOwnEcho">
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Both stations do full correction to their QSO partner's grid square during receive, no correction is applied on transmit.&lt;/p&gt;&lt;p&gt;This mode facilitates accurate Doppler shift correction when one or both stations have a rig that does not accept CAT QSY commands while transmitting.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Transmit takes place on sked frequency and receive frequency is corrected for own echoes. &lt;/p&gt;&lt;p&gt;This mode can be used for calling CQ, or when using Echo mode.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="text"> <property name="text">
<string>Receive only</string> <string>Own Echo</string>
</property> </property>
</widget> </widget>
</item> </item>
@@ -70,6 +70,32 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QRadioButton" name="rbOnDxEcho">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;DX station announces their TX Freq, which is entered as the Sked Freq. Correction applied to RX and TX so you appear on the DX's station's own echo Freq.&lt;/p&gt;&lt;p&gt;If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>On DX Echo</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="rbCallDx">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Tune radio manually and select this mode to put your echo on the same frequency.&lt;/p&gt;&lt;p&gt;If the rig does not accept CAT QSY commands while transmitting a single correction is applied for the whole transmit period.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Call DX</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item> <item>
<widget class="QRadioButton" name="rbNoDoppler"> <widget class="QRadioButton" name="rbNoDoppler">
<property name="toolTip"> <property name="toolTip">
@@ -83,7 +109,7 @@
</property> </property>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
</item> </item>
<item> <item>
@@ -0,0 +1,36 @@
subroutine foxfilt(nslots,nfreq,width,wave)
parameter (NN=79,ND=58,KK=87,NSPS=4*1920)
parameter (NWAVE=NN*NSPS,NFFT=614400,NH=NFFT/2)
real wave(NWAVE)
real x(NFFT)
complex cx(0:NH)
equivalence (x,cx)
x(1:NWAVE)=wave
x(NWAVE+1:)=0.
call four2a(x,NFFT,1,-1,0) !r2c
df=48000.0/NFFT
fa=nfreq - 0.5*6.25
fb=nfreq + 7.5*6.25 + (nslots-1)*60.0
ia2=nint(fa/df)
ib1=nint(fb/df)
ia1=nint(ia2-width/df)
ib2=nint(ib1+width/df)
pi=4.0*atan(1.0)
do i=ia1,ia2
fil=(1.0 + cos(pi*df*(i-ia2)/width))/2.0
cx(i)=fil*cx(i)
enddo
do i=ib1,ib2
fil=(1.0 + cos(pi*df*(i-ib1)/width))/2.0
cx(i)=fil*cx(i)
enddo
cx(0:ia1-1)=0.
cx(ib2+1:)=0.
call four2a(cx,nfft,1,1,-1) !c2r
wave=x(1:NWAVE)/nfft
return
end subroutine foxfilt
Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

@@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>374</width> <width>377</width>
<height>229</height> <height>257</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@@ -351,6 +351,45 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="operatorLabel">
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Operator</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="loggedOperator">
<property name="maximumSize">
<size>
<width>300</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item> <item>
<spacer name="verticalSpacer"> <spacer name="verticalSpacer">
<property name="orientation"> <property name="orientation">
@@ -1,266 +0,0 @@
/* RAND-TEST.C - Program to test random number generators. */
/* Copyright (c) 1995-2012 by Radford M. Neal.
*
* Permission is granted for anyone to copy, use, modify, and distribute
* these programs and accompanying documents for any purpose, provided
* this copyright notice is retained and prominently displayed, and note
* is made of any changes made to these programs. These programs and
* documents are distributed without any warranty, express or implied.
* As the programs were written for research purposes only, they have not
* been tested to the degree that would be advisable in any important
* application. All use of these programs is entirely at the user's own
* risk.
*/
/* Usage:
rand-test seed generator { parameters } / sample-size [ low high bins ]
Using the seed given, tests the random number generator identified by
the second argument, for the parameter values specified. The possible
generators and required parameters are as follows:
uniform Uniform from [0,1)
uniopen Uniform from (0,1)
int n Uniform from the set { 0, 1, ..., (n-1) }
gaussian From Gaussian with mean zero and unit variance
exp From exponential with mean one
cauchy From Cauchy centred at zero with unit width
gamma alpha From Gamma with shape parameter (and mean) alpha
beta a b From Beta with parameters a and b
The size of the sample to use is also specified. The program reports
the mean and variance of the sample. A histogram is also printed if a
low and high range and number of bins are for it are specified.
These tests are not really adequate to detect subtle forms of bias due
to use of pseudo-random numbers, but are hopefully good enough to find
most programming errors.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "rand.h"
#define Max_bins 1000 /* Maximum number of histogram bins */
static void usage (void);
/* MAIN PROGRAM. */
main
( int argc,
char **argv
)
{
int seed, sample_size, bins, np;
double low, high;
char *generator;
double p1, p2;
double mean, variance;
double tmean, tvariance;
int undef_mean, undef_variance;
int count[Max_bins];
int under, over;
char **ap;
double x;
int i, n;
bins = 0;
if (argc<5) usage();
if ((seed = atoi(argv[1]))==0 && strcmp(argv[1],"0")!=0) usage();
generator = argv[2];
if (strcmp(generator,"uniform")==0) np = 0;
else if (strcmp(generator,"uniopen")==0) np = 0;
else if (strcmp(generator,"int")==0) np = 1;
else if (strcmp(generator,"poisson")==0) np = 1;
else if (strcmp(generator,"gaussian")==0) np = 0;
else if (strcmp(generator,"exp")==0) np = 0;
else if (strcmp(generator,"cauchy")==0) np = 0;
else if (strcmp(generator,"gamma")==0) np = 1;
else if (strcmp(generator,"beta")==0) np = 2;
else
{ fprintf(stderr,"Unknown generator: %s\n",generator);
exit(1);
}
ap = argv+3;
if (np>0)
{ if (*ap==0 || (p1 = atof(*ap++))<=0) usage();
}
if (np>1)
{ if (*ap==0 || (p2 = atof(*ap++))<=0) usage();
}
if (*ap==0 || strcmp(*ap++,"/")!=0) usage();
if (*ap==0 || (sample_size = atoi(*ap++))<=0) usage();
if (*ap!=0)
{ low = atof(*ap++);
if (*ap==0) usage();
high = atof(*ap++);
if (high<=low) usage();
if (*ap==0 || (bins = atoi(*ap++))<=0) usage();
if (bins>Max_bins)
{ fprintf(stderr,"Too many histogram bins\n");
exit(1);
}
}
if (*ap!=0) usage();
printf("\nTest of %s(",generator);
if (np>0) printf("%.4f",p1);
if (np>1) printf(",%.4f",p2);
printf(") generator using sample of size %d with seed %d\n\n",
sample_size, seed);
undef_mean = undef_variance = 0;
if (strcmp(generator,"uniform")==0)
{ tmean = 0.5;
tvariance = 1.0/12.0;
}
else if (strcmp(generator,"uniopen")==0)
{ tmean = 0.5;
tvariance = 1.0/12.0;
}
else if (strcmp(generator,"int")==0)
{ tmean = (p1-1)/2;
tvariance = p1*p1/3.0 - p1/2.0 + 1/6.0 - tmean*tmean;
}
else if (strcmp(generator,"poisson")==0)
{ tmean = p1;
tvariance = p1;
}
else if (strcmp(generator,"gaussian")==0)
{ tmean = 0;
tvariance = 1;
}
else if (strcmp(generator,"exp")==0)
{ tmean = 1;
tvariance = 1;
}
else if (strcmp(generator,"cauchy")==0)
{ undef_mean = 1;
undef_variance = 1;
}
else if (strcmp(generator,"gamma")==0)
{ tmean = p1;
tvariance = p1;
}
else if (strcmp(generator,"beta")==0)
{ tmean = p1 / (p1+p2);
tvariance = (p1*p2) / ((p1+p2)*(p1+p2)*(p1+p2+1));
}
else
{ abort();
}
mean = 0;
variance = 0;
if (bins>0)
{ for (i = 0; i<bins; i++) count[i] = 0;
under = over = 0;
}
rand_seed(seed);
for (n = 0; n<sample_size; n++)
{
if (strcmp(generator,"uniform")==0) x = rand_uniform();
else if (strcmp(generator,"uniopen")==0) x = rand_uniopen();
else if (strcmp(generator,"int")==0) x = rand_int((int)p1);
else if (strcmp(generator,"poisson")==0) x = rand_poisson(p1);
else if (strcmp(generator,"gaussian")==0) x = rand_gaussian();
else if (strcmp(generator,"exp")==0) x = rand_exp();
else if (strcmp(generator,"cauchy")==0) x = rand_cauchy();
else if (strcmp(generator,"gamma")==0) x = rand_gamma(p1);
else if (strcmp(generator,"beta")==0) x = rand_beta(p1,p2);
else abort();
mean += x;
variance += x*x;
if (bins>0)
{ if (x<low)
{ under += 1;
}
else
{ i = (int) ((x-low)/((high-low)/bins));
if (i>=bins)
{ over += 1;
}
else
{ count[i] += 1;
}
}
}
}
mean /= sample_size;
variance /= sample_size;
variance -= mean*mean;
printf("Sample mean: %.4f",mean);
if (undef_mean)
{ printf(" (true value: undefined)\n");
}
else
{ printf(" (true value: %.4f)\n",tmean);
}
printf("Sample variance: %.4f",variance);
if (undef_variance)
{ printf(" (true value: undefined)\n");
}
else
{ printf(" (true value: %.4f)\n",tvariance);
}
printf("\n");
if (bins!=0)
{ printf("Histogram:\n");
printf(" under : %8d %.5f\n\n",
under, (double)under / sample_size);
for (i = 0; i<bins; i++)
{ printf(" %10.4f - %10.4f : %8d %.5f\n",
i*(high-low)/bins + low, (i+1)*(high-low)/bins + low,
count[i], (double)count[i] / sample_size);
}
printf("\n over : %8d %.5f\n",
over, (double)over / sample_size);
printf("\n");
}
exit(0);
}
/* PRINT USAGE MESSAGE AND EXIT. */
static void usage (void)
{
fprintf(stderr,
"Usage: rand-test seed generator { parameters } / sample-size [ low high bins ]\n");
exit(1);
}
@@ -1,100 +0,0 @@
<HTML><HEAD>
<TITLE> Support Programs </TITLE>
</HEAD><BODY>
<H1> Support Programs </H1>
The following programs provide support for testing and performance
assessment.
<P><A NAME="rand-src"><HR><B>rand-src</B>: Generate random message bits.
<BLOCKQUOTE><PRE>
rand-src <I>source-file seed n-bits</I>
</PRE></BLOCKQUOTE>
<P>Creates a file of random messages bits called
<TT><I>source-file</I></TT>, which is suitable for testing the
correctness and performance of other programs. The bits in the file
are independent, and are equally likely to be 0 or 1. They are
generated pseudo-randomly based on <TT><I>seed</I></TT>. The actual
random number seed used will be <TT><I>seed</I></TT> times 10 plus 2,
so that the stream of pseudo-random numbers will not be the same as
any that might have been used by another program.
<P>The <TT><I>n-bits</I></TT> argument specifies the number of bits to
produce. It can be a single number, or it can consist of a block size
and a number of blocks, written with <TT>x</TT> separating these
numbers, with no spaces. Each block is written as a single line, with
the bits in the block represented by the characters '0' and '1', with
no intervening spaces. If the bit count is given by a single number,
the block size is assumed to be one.
<P><B>Example:</B> The following command produces a file containing
3 blocks, each consisting of 15 random bits, produced using the pseudo-random
number stream identified by the <TT><I>seed</I></TT> of 17:
<UL><PRE>
<LI>rand-src rsrc 17 15x3
</PRE></UL>
The contents of the file <TT>rsrc</TT> after this command might be something
like the following:
<BLOCKQUOTE><PRE>
111011000110000
010010110010111
100000000000111
</BLOCKQUOTE></PRE>
<P><A NAME="verify"><HR><B>verify</B>: Verify that decoded blocks are
codewords, and that they match the source.
<BLOCKQUOTE><PRE>
verify [ -t ] <I>pchk-file decoded-file</I> [ <I>gen-file</I> [ <I>source-file</I> ] ]
</PRE></BLOCKQUOTE>
<P>Checks whether or not the blocks in <TT><I>decoded-file</I></TT>
are codewords, according to the parity check matrix in
<TT><I>pchk-file</I></TT>. If <TT><I>gen-file</I></TT> is specified,
the message bits of the blocks are also checked against the
corresponding blocks of <TT><I>source-file</I></TT>, or against zero
if <TT><I>source-file</I></TT> is not given. (Normally, one would
leave out <TT><I>source-file</I></TT> only if the <A
HREF="channel.html#transmit"><TT>transmit</TT></A> command was used
with an argument specifying that zeros are to be transmitted, rather
than a file of encoded data.)
<P>A summary of the results is displayed on standard error, giving the
total numbers of blocks, the number with parity check errors, and, if
<TT><I>gen-file</I></TT> was specified, the number of blocks with
source errors and the number with errors of both kinds. If
<TT><I>gen-file</I></TT> was specified, a second
summary line displays the bit error rate from
comparing the decoded message bits with the true message bits (zeros
if no <TT><I>source file</I></TT> was given).
<P>If the <B>-t</B> option is given, block-by-block results are
printed on standard output in two or three columns, giving the block
number (from zero), the number of parity check errors for that block,
and the number of errors in source bits. The last column is omitted
if <TT><I>gen-file</I></TT> is not specified. The columns are
preceded by a line of headers, so the file is suitable for reading
into the S-Plus or R statistics packages, with a command such as
<BLOCKQUOTE><PRE>
data <- read.table(<I>file</I>,header=T)
</PRE></BLOCKQUOTE>
<P>Warning messages are displayed on standard error if the number of
bits in <TT><I>decoded-file</I></TT> is not a multiple of the block
length, or if <TT><I>source-file</I></TT> is too short. Newlines
in these files are ignored, even though they would normally occur
at the ends of blocks.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>
@@ -1,34 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MessageAveraging</class>
<widget class="QWidget" name="MessageAveraging">
<property name="windowTitle">
<string>Message Averaging</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="header_label">
<property name="text">
<string> UTC Sync DT Freq </string>
</property>
<property name="margin">
<number>3</number>
</property>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="QPlainTextEdit" name="msgAvgPlainTextEdit">
<property name="lineWrapMode">
<enum>QPlainTextEdit::NoWrap</enum>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
@@ -291,14 +291,19 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
QByteArray comments; QByteArray comments;
QByteArray name; QByteArray name;
QDateTime time_on; // Note: LOTW uses TIME_ON for their +/- 30-minute time window QDateTime time_on; // Note: LOTW uses TIME_ON for their +/- 30-minute time window
QByteArray operator_call;
QByteArray my_call;
QByteArray my_grid;
in >> time_off >> dx_call >> dx_grid >> dial_frequency >> mode >> report_sent >> report_received in >> time_off >> dx_call >> dx_grid >> dial_frequency >> mode >> report_sent >> report_received
>> tx_power >> comments >> name >> time_on; >> tx_power >> comments >> name >> time_on >> operator_call >> my_call >> my_grid;
if (check_status (in) != Fail) if (check_status (in) != Fail)
{ {
Q_EMIT self_->qso_logged (id, time_off, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid) Q_EMIT self_->qso_logged (id, time_off, QString::fromUtf8 (dx_call), QString::fromUtf8 (dx_grid)
, dial_frequency, QString::fromUtf8 (mode), QString::fromUtf8 (report_sent) , dial_frequency, QString::fromUtf8 (mode), QString::fromUtf8 (report_sent)
, QString::fromUtf8 (report_received), QString::fromUtf8 (tx_power) , QString::fromUtf8 (report_received), QString::fromUtf8 (tx_power)
, QString::fromUtf8 (comments), QString::fromUtf8 (name), time_on); , QString::fromUtf8 (comments), QString::fromUtf8 (name), time_on
, QString::fromUtf8 (operator_call), QString::fromUtf8 (my_call)
, QString::fromUtf8 (my_grid));
} }
} }
break; break;
@@ -308,6 +313,17 @@ void MessageServer::impl::parse_message (QHostAddress const& sender, port_type s
clients_.remove (id); clients_.remove (id);
break; break;
case NetworkMessage::LoggedADIF:
{
QByteArray ADIF;
in >> ADIF;
if (check_status (in) != Fail)
{
Q_EMIT self_->logged_ADIF (id, ADIF);
}
}
break;
default: default:
// Ignore // Ignore
break; break;
@@ -452,3 +468,28 @@ void MessageServer::free_text (QString const& id, QString const& text, bool send
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_); m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
} }
} }
void MessageServer::location (QString const& id, QString const& loc)
{
auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_))
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::Location, id, (*iter).negotiated_schema_number_};
out << loc.toUtf8 ();
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}
void MessageServer::highlight_callsign (QString const& id, QString const& callsign
, QColor const& bg, QColor const& fg, bool last_only)
{
auto iter = m_->clients_.find (id);
if (iter != std::end (m_->clients_))
{
QByteArray message;
NetworkMessage::Builder out {&message, NetworkMessage::HighlightCallsign, id, (*iter).negotiated_schema_number_};
out << callsign.toUtf8 () << bg << fg << last_only;
m_->send_message (out, message, iter.value ().sender_address_, (*iter).sender_port_);
}
}
@@ -1,223 +0,0 @@
#include "displaytext.h"
#include <QMouseEvent>
#include <QDateTime>
#include <QTextCharFormat>
#include <QTextCursor>
#include <QTextBlock>
#include "qt_helpers.hpp"
#include "moc_displaytext.cpp"
DisplayText::DisplayText(QWidget *parent) :
QTextEdit(parent)
{
setReadOnly (true);
viewport ()->setCursor (Qt::ArrowCursor);
setWordWrapMode (QTextOption::NoWrap);
document ()->setMaximumBlockCount (5000); // max lines to limit heap usage
}
void DisplayText::setContentFont(QFont const& font)
{
char_font_ = font;
selectAll ();
auto cursor = textCursor ();
cursor.beginEditBlock ();
auto char_format = cursor.charFormat ();
char_format.setFont (char_font_);
cursor.mergeCharFormat (char_format);
cursor.clearSelection ();
cursor.movePosition (QTextCursor::End);
// position so viewport scrolled to left
cursor.movePosition (QTextCursor::Up);
cursor.movePosition (QTextCursor::StartOfLine);
cursor.endEditBlock ();
setTextCursor (cursor);
ensureCursorVisible ();
}
void DisplayText::mouseDoubleClickEvent(QMouseEvent *e)
{
bool ctrl = (e->modifiers() & Qt::ControlModifier);
bool alt = (e->modifiers() & Qt::AltModifier);
emit(selectCallsign(alt,ctrl));
QTextEdit::mouseDoubleClickEvent(e);
}
void DisplayText::insertLineSpacer(QString const& line)
{
appendText (line, "#d3d3d3");
}
void DisplayText::appendText(QString const& text, QColor bg)
{
auto cursor = textCursor ();
cursor.movePosition (QTextCursor::End);
auto block_format = cursor.blockFormat ();
block_format.setBackground (bg);
if (0 == cursor.position ())
{
cursor.setBlockFormat (block_format);
auto char_format = cursor.charFormat ();
char_format.setFont (char_font_);
cursor.setCharFormat (char_format);
}
else
{
cursor.insertBlock (block_format);
}
cursor.insertText (text);
// position so viewport scrolled to left
cursor.movePosition (QTextCursor::StartOfLine);
setTextCursor (cursor);
ensureCursorVisible ();
document ()->setMaximumBlockCount (document ()->maximumBlockCount ());
}
QString DisplayText::appendDXCCWorkedB4(QString message, QString const& callsign, QColor * bg,
LogBook const& logBook, QColor color_CQ,
QColor color_DXCC,
QColor color_NewCall)
{
// allow for seconds
unsigned padding {message.indexOf (" ") > 4 ? 2U : 0U};
QString call = callsign;
QString countryName;
bool callWorkedBefore;
bool countryWorkedBefore;
if(call.length()==2) {
int i0=message.indexOf("CQ "+call);
call=message.mid(i0+6,-1);
i0=call.indexOf(" ");
call=call.mid(0,i0);
}
if(call.length()<3) return message;
if(!call.contains(QRegExp("[0-9]|[A-Z]"))) return message;
logBook.match(/*in*/call,/*out*/countryName,callWorkedBefore,countryWorkedBefore);
int charsAvail = 52 + padding;
// the decoder (seems) to always generate 41 chars. For a normal CQ
// call, the last five are spaces
//
// A maximum length call is "QRZ VP2X/GM4WJS IO91" "CQ AA ..." or CQ
// nnn ..." don't allow grid squares so are not longer. Here we align
// the added info at least after the longest CQ/QRZ message plus one
// space so that it can be stripped off algorithmically later.
//
int nmin = 46 + padding;
int s3 = message.indexOf (" ", nmin);
if (s3 < nmin) s3 = nmin; // always want at least the characters to position 45
s3 += 1; // convert the index into a character count
message = message.left(s3); // reduce trailing white space
charsAvail -= s3;
if (charsAvail > 4)
{
if (!countryWorkedBefore) // therefore not worked call either
{
message += "!";
*bg = color_DXCC;
}
else
if (!callWorkedBefore) // but have worked the country
{
message += "~";
*bg = color_NewCall;
}
else
{
message += " "; // have worked this call before
*bg = color_CQ;
}
charsAvail -= 1;
// do some obvious abbreviations
countryName.replace ("Islands", "Is.");
countryName.replace ("Island", "Is.");
countryName.replace ("North ", "N. ");
countryName.replace ("Northern ", "N. ");
countryName.replace ("South ", "S. ");
countryName.replace ("East ", "E. ");
countryName.replace ("Eastern ", "E. ");
countryName.replace ("West ", "W. ");
countryName.replace ("Western ", "W. ");
countryName.replace ("Central ", "C. ");
countryName.replace (" and ", " & ");
countryName.replace ("Republic", "Rep.");
countryName.replace ("United States", "U.S.A.");
countryName.replace ("Fed. Rep. of ", "");
countryName.replace ("French ", "Fr.");
countryName.replace ("Asiatic", "AS");
countryName.replace ("European", "EU");
countryName.replace ("African", "AF");
message += countryName;
}
return message;
}
void DisplayText::displayDecodedText(DecodedText const& decodedText, QString const& myCall,
bool displayDXCCEntity, LogBook const& logBook,
QColor color_CQ, QColor color_MyCall,
QColor color_DXCC, QColor color_NewCall)
{
QColor bg {Qt::white};
bool CQcall = false;
if (decodedText.string ().contains (" CQ ")
|| decodedText.string ().contains (" CQDX ")
|| decodedText.string ().contains (" QRZ "))
{
CQcall = true;
bg = color_CQ;
}
if (myCall != "" and (
decodedText.indexOf (" " + myCall + " ") >= 0
or decodedText.indexOf (" " + myCall + "/") >= 0
or decodedText.indexOf ("/" + myCall + " ") >= 0
or decodedText.indexOf ("<" + myCall + " ") >= 0
or decodedText.indexOf (" " + myCall + ">") >= 0)) {
bg = color_MyCall;
}
// if enabled add the DXCC entity and B4 status to the end of the
// preformated text line t1
auto message = decodedText.string ();
if (displayDXCCEntity && CQcall)
message = appendDXCCWorkedB4 (message, decodedText.CQersCall (), &bg, logBook, color_CQ,
color_DXCC, color_NewCall);
appendText (message, bg);
}
void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
QColor color_TxMsg, bool bFastMode)
{
QString t1=" @ ";
if(modeTx=="FT8") t1=" ~ ";
if(modeTx=="JT4") t1=" $ ";
if(modeTx=="JT65") t1=" # ";
if(modeTx=="MSK144") t1=" & ";
QString t2;
t2.sprintf("%4d",txFreq);
QString t;
if(bFastMode or modeTx=="FT8") {
t = QDateTime::currentDateTimeUtc().toString("hhmmss") + \
" Tx " + t2 + t1 + text;
} else {
t = QDateTime::currentDateTimeUtc().toString("hhmm") + \
" Tx " + t2 + t1 + text;
}
appendText (t, color_TxMsg);
}
void DisplayText::displayQSY(QString text)
{
QString t = QDateTime::currentDateTimeUtc().toString("hhmmss") + " " + text;
appendText (t, "hotpink");
}
@@ -1,156 +0,0 @@
subroutine extract(s3,nadd,mode65,ntrials,naggressive,ndepth,nflip, &
mycall_12,hiscall_12,hisgrid,nexp_decode,ncount,nhist,decoded, &
ltext,nft,qual)
! Input:
! s3 64-point spectra for each of 63 data symbols
! nadd number of spectra summed into s3
! nqd 0/1 to indicate decode attempt at QSO frequency
! Output:
! ncount number of symbols requiring correction (-1 for no KV decode)
! nhist maximum number of identical symbol values
! decoded decoded message (if ncount >=0)
! ltext true if decoded message is free text
! nft 0=no decode; 1=FT decode; 2=hinted decode
use prog_args !shm_key, exe_dir, data_dir
use packjt
use jt65_mod
use timer_module, only: timer
real s3(64,63)
character decoded*22
character*12 mycall_12,hiscall_12
character*6 mycall,hiscall,hisgrid
integer dat4(12)
integer mrsym(63),mr2sym(63),mrprob(63),mr2prob(63)
integer correct(63),tmp(63)
logical ltext
common/chansyms65/correct
save
if(mode65.eq.-99) stop !Silence compiler warning
mycall=mycall_12(1:6)
hiscall=hiscall_12(1:6)
qual=0.
nbirdie=20
npct=50
afac1=1.1
nft=0
nfail=0
decoded=' '
call pctile(s3,4032,npct,base)
s3=s3/base
s3a=s3 !###
! Get most reliable and second-most-reliable symbol values, and their
! probabilities
1 call demod64a(s3,nadd,afac1,mrsym,mrprob,mr2sym,mr2prob,ntest,nlow)
call chkhist(mrsym,nhist,ipk) !Test for birdies and QRM
if(nhist.ge.nbirdie) then
nfail=nfail+1
call pctile(s3,4032,npct,base)
s3(ipk,1:63)=base
if(nfail.gt.30) then
decoded=' '
ncount=-1
go to 900
endif
go to 1
endif
mrs=mrsym
mrs2=mr2sym
call graycode65(mrsym,63,-1) !Remove gray code
call interleave63(mrsym,-1) !Remove interleaving
call interleave63(mrprob,-1)
call graycode65(mr2sym,63,-1) !Remove gray code and interleaving
call interleave63(mr2sym,-1) !from second-most-reliable symbols
call interleave63(mr2prob,-1)
ntry=0
call timer('ftrsd ',0)
param=0
call ftrsd2(mrsym,mrprob,mr2sym,mr2prob,ntrials,correct,param,ntry)
call timer('ftrsd ',1)
ncandidates=param(0)
nhard=param(1)
nsoft=param(2)
nerased=param(3)
rtt=0.001*param(4)
ntotal=param(5)
qual=0.001*param(7)
nd0=81
r0=0.87
if(naggressive.eq.10) then
nd0=83
r0=0.90
endif
if(ntotal.le.nd0 .and. rtt.le.r0) nft=1
if(nft.eq.0 .and. iand(ndepth,32).eq.32) then
qmin=2.0 - 0.1*naggressive
call timer('hint65 ',0)
call hint65(s3,mrs,mrs2,nadd,nflip,mycall,hiscall,hisgrid,qual,decoded)
if(qual.ge.qmin) then
nft=2
ncount=0
else
decoded=' '
ntry=0
endif
call timer('hint65 ',1)
go to 900
endif
ncount=-1
decoded=' '
ltext=.false.
if(nft.gt.0) then
! Turn the corrected symbol array into channel symbols for subtraction;
! pass it back to jt65a via common block "chansyms65".
do i=1,12
dat4(i)=correct(13-i)
enddo
do i=1,63
tmp(i)=correct(64-i)
enddo
correct(1:63)=tmp(1:63)
call interleave63(correct,63,1)
call graycode65(correct,63,1)
call unpackmsg(dat4,decoded,.false.,' ') !Unpack the user message
ncount=0
if(iand(dat4(10),8).ne.0) ltext=.true.
endif
900 continue
if(nft.eq.1 .and. nhard.lt.0) decoded=' '
return
end subroutine extract
subroutine getpp(workdat,p)
use jt65_mod
integer workdat(63)
integer a(63)
a(1:63)=workdat(63:1:-1)
call interleave63(a,1)
call graycode(a,63,1,a)
psum=0.
do j=1,63
i=a(j)+1
x=s3a(i,j)
s3a(i,j)=0.
psum=psum + x
s3a(i,j)=x
enddo
p=psum/63.0
return
end subroutine getpp
@@ -0,0 +1,154 @@
integer, parameter:: N=204, K=68, M=N-K
character*17 g(136)
integer colorder(N)
data g/ & !parity generator matrix for (204,68) code
"2de7435fd27c0031d", &
"f331b40671e20ea80", &
"48bd3f8cb9a24392f", &
"d4ed71c935162aa2a", &
"c437a3284ec58bce7", &
"35a806dd5be35627c", &
"396e797c33a4739a6", &
"768f331a59c15487b", &
"c214eac24ae5e1732", &
"0b5c53ff3a6da1192", &
"99624981d2703fb97", &
"e9f5447ef7f1ff6af", &
"bd8c730f0cfdf0727", &
"26f61e63e1e098f7f", &
"ef826566137b6526f", &
"af0e4fa251e9b4926", &
"75974a8b2a24292c5", &
"71caf0f2cd10f6d4f", &
"b1103f1f26e6898b7", &
"67ceb7d6f490da64f", &
"ee0e8fbefec23008a", &
"11cc2227e8bd676ca", &
"6e71626ba1e278046", &
"005d28da267e50e13", &
"a9ae4a130aaba8219", &
"d8ab72e0158d0da70", &
"56009d42b37bd66ff", &
"c39a75eca99b0e996", &
"6886de0bf7c0bf4bb", &
"1046cd8f64162f7b5", &
"da0f15843ac21e3a5", &
"e9bf9cd19f3db3913", &
"2fb9cb42d650f47a7", &
"a2b6c5a378fa75a65", &
"41a88f3cd60b79d6c", &
"fcf175794cc3ac96a", &
"8677a3447d40a9f71", &
"97a1f08c250b4bf12", &
"0168f090a1df6e8ea", &
"418a06bf372cc67d9", &
"0f17b880c1ff51239", &
"b2afd6d585deb961b", &
"60298ac5b58dbeee0", &
"8350c03c40119feff", &
"b29c964a8accf6af4", &
"9b46f036a5c178b5d", &
"917398bff051c300a", &
"5e52c03b2f8c5128c", &
"beae6c33c87ba38ab", &
"20843f7b056a02ebf", &
"66690d65acd9de598", &
"8f025841af5b54331", &
"b43cd869d3be2c3db", &
"c9c342fe63c18df50", &
"d331b40671e28ea80", &
"62406a0f4947e6ce9", &
"d67b1495883b22e1b", &
"734534c372408895b", &
"d88750e33d9677dcd", &
"6f96964da55138687", &
"80bee98bb75d50ef2", &
"c428ef3e3f06f4c56", &
"b1a1499b125883a35", &
"ac892d4b37fa9e395", &
"458dbda0f95ab11a5", &
"6f93c9e95b1094eed", &
"2e370d713914f848e", &
"758806dd5be35627c", &
"8c52e01caec798b49", &
"c286cc25bae3669cf", &
"87c56fb895c100884", &
"e89cb1376a18fd911", &
"156ffe5f30dc354e0", &
"f20d0b121d6a6b3ee", &
"7db08891b491a95d2", &
"191fac548d5077bdf", &
"023a37d7ea5660bbc", &
"6781668b363fee682", &
"bbfaf262cab7370da", &
"feea557965b7e474f", &
"c094eb223e1d305b8", &
"2be051abdd5beea35", &
"0790449880fda9d00", &
"f9029a39ec869e7b4", &
"5a29f48926ec9a552", &
"e0463306dc1470f87", &
"9251058334d790f86", &
"3019e1d4578e8a4dc", &
"887e46631502fa111", &
"c25fcd7a42465d326", &
"cf64bcc1056b555c4", &
"3e71c0fe5f0ad733b", &
"11055ec43b076e5b2", &
"3440f64dfa3c30a96", &
"2b73885b4d3299f60", &
"2e71627ba1e268046", &
"ad23743d5e6e5b80c", &
"c9757b05f29bfdc10", &
"f7112bea739247b51", &
"3664062387998b2b1", &
"90897a3b8785aefba", &
"29e126e3201fc1d46", &
"96c9001c84d5257fc", &
"067723447d40a9f71", &
"1a019cc68f7511402", &
"4bd48eb2330032763", &
"d139a5da936b37647", &
"765ab46a4dec5f04f", &
"706f475ad19b91955", &
"1755c988fa8a55e5c", &
"2fd9ed5777eb01d6a", &
"bec27d85b954d3fe8", &
"7135a3b92c45b3f8d", &
"353237872f002163a", &
"e31e4a97aef10c729", &
"da527d5e1cbc4edb6", &
"6e33cdede17c3207e", &
"ef2d2062e84dc401f", &
"8217c84c50c1bf833", &
"12ffbac7b2219c9e0", &
"3729178706f66881f", &
"2fdd748c382a608a1", &
"dd0a00076f9dcec73", &
"46b1d37bced447035", &
"7316f33a9c05ef178", &
"152c39a6de8954cc3", &
"16efffb7b62e12ba3", &
"9d9ec2bb467affd83", &
"467723445d40a9f61", &
"87994762b3bf50697", &
"b1bfa5b51526dde9b", &
"b0a6a19d709a96148", &
"990d567c0aba31a14", &
"171f190792461b1e0", &
"166011c27d2b6b8a4", &
"170c15831244ae73e"/
data colorder/ &
0, 1, 2, 3, 4, 5, 47, 6, 7, 8, 9, 10, 11, 12, 58, 55, 13, &
14, 15, 46, 17, 18, 60, 19, 20, 21, 22, 23, 24, 25, 57, 26, 27, 49, &
28, 52, 65, 16, 50, 73, 59, 68, 63, 29, 30, 31, 32, 51, 62, 56, 66, &
45, 33, 34, 53, 67, 35, 36, 37, 61, 69, 54, 38, 71, 82, 39, 77, 80, &
83, 78, 84, 48, 41, 85, 40, 64, 75, 96, 74, 72, 76, 86, 87, 89, 90, &
79, 70, 92, 99, 93,101, 95,100, 97, 94, 42, 98,103,105,102, 43,104, &
88, 44,106, 81,107,110,108,111,112,109,113,114,117,118,116,121,115, &
119,122,120,125,129,124,127,126,128, 91,123,133,131,130,134,135,137, &
136,132,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152, &
153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169, &
170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186, &
187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203/
@@ -0,0 +1,43 @@
// Forward declaration of the circular buffer and its adaptor.
// Copyright (c) 2003-2008 Jan Gaspar
// Use, modification, and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// See www.boost.org/libs/circular_buffer for documentation.
#if !defined(BOOST_CIRCULAR_BUFFER_FWD_HPP)
#define BOOST_CIRCULAR_BUFFER_FWD_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp>
#if !defined(BOOST_NO_STD_ALLOCATOR)
#include <memory>
#else
#include <vector>
#endif
namespace boost {
#if !defined(BOOST_NO_STD_ALLOCATOR)
#define BOOST_CB_DEFAULT_ALLOCATOR(T) std::allocator<T>
#else
#define BOOST_CB_DEFAULT_ALLOCATOR(T) BOOST_DEDUCED_TYPENAME std::vector<T>::allocator_type
#endif
template <class T, class Alloc = BOOST_CB_DEFAULT_ALLOCATOR(T)>
class circular_buffer;
template <class T, class Alloc = BOOST_CB_DEFAULT_ALLOCATOR(T)>
class circular_buffer_space_optimized;
#undef BOOST_CB_DEFAULT_ALLOCATOR
} // namespace boost
#endif // #if !defined(BOOST_CIRCULAR_BUFFER_FWD_HPP)
@@ -1,719 +0,0 @@
<HTML><HEAD>
<TITLE> Sparse Modulo-2 Matrix Routines </TITLE>
</HEAD><BODY>
<H1> Sparse Modulo-2 Matrix Routines </H1>
<P>This module implements operations on matrices in which the elements
are all 0 or 1, with addition and multiplication being done modulo 2.
The matrices are represented by doubly-linked lists of entries
representing the elements in each row and column that are 1s, with
other elements being assumed to be zero.
<P>This is an appropriate representation when the matrices are sparse
(ie, 0s are much more frequent that 1s). Matrices in which 0s and 1s
are about equally likely may be better handled with the <A
HREF="mod2dense.html">dense modulo-2 matrix routines</A>. Matrices
can be converted between these two formats using the <A
HREF="mod2convert.html">module-2 matrix conversion routines</A>.
<P>All procedures in this module display an error message on standard
error and terminate the program if passed an invalid argument (indicative
of a programming error), or if memory cannot be allocated. Errors from
invalid contents of a file result in an error code being returned to the
caller, with no message being printed by this module.
<A NAME="rep"><H2>Representation of sparse matrices</H2></A>
<P>This module represents a non-zero element of a matrix (which must have
the value 1, since these are modulo-2 matrices) by a node of type
<TT>mod2entry</TT>, which contains the row and column of the element,
pointers to the next non-zero elements above and below in its column
and to the left and the right in its row, and two double-precision
floating-point numbers called <B>pr</B> and <B>lr</B>, which are
of no significance to this module, but which are used by the routines
for <A HREF="decoding.html#prprp">decoding LDPC codes by probability
propagation</A>.
<P>The <TT>mod2sparse</TT> type represents a matrix. It records the
number of rows and columns in the matrix, and contains arrays of
pointers to the <TT>mod2entry</TT> structures for the first non-zero
element in each row and the first non-zero element in each column.
<P>Matrices must be created by the <A
HREF="#allocate"><TT>mod2sparse_allocate</TT></A> procedure, which
returns a pointer to a <TT>mod2sparse</TT> structure. When a matrix
is no longer needed, the space it occupies can be freed with <A
HREF="#free"><TT>mod2sparse_free</TT></A>. Elements within a matrix,
represented by <TT>mod2entry</TT> nodes, are allocated as needed, and
if deleted, they will be reused for new elements within the same
matrix. The space they occupy is not reusable for other matrices or
other purposes until the entire matrix is either freed, with <A
HREF="#free"><TT>mod2sparse_free</TT></A>, or cleared to all zeros,
with <A HREF="#clear"><TT>mod2sparse_clear</TT></A>, or used as
the result matrix for copying or arithmetic operations.
<P><B>Header files required</B>:
<TT>mod2sparse.h</TT>
<A NAME="dimension-sec">
<P><HR>
<CENTER><BIG>Dimension Macros</BIG></CENTER>
</A>
<HR>The following macros take a pointer to a mod2sparse structure as their
argument, and return the number of rows or the number of columns in
the matrix pointed to, which will have been fixed when the matrix was
created with <A HREF="#allocate">mod2sparse_allocate</A>:
<BLOCKQUOTE><PRE>
mod2sparse_rows(m) /* Returns the number of rows in m */
mod2sparse_cols(m) /* Returns the number of columns in m */
</PRE></BLOCKQUOTE>
<A NAME="traversal-sec">
<P><HR>
<CENTER><BIG>Traversal Macros</BIG></CENTER>
</A>
<HR>The following macros are used to move around a sparse matrix by
following the pointers from one non-zero element to the next or
previous non-zero element in the same row or column. If such a
movement takes one beyond the last or before first entry in a row or
column, or if one tries to find the first or last non-zero entry in a
row or column that has no non-zero entries, the entry returned will be
a special one that can be identified using the
<TT>mod2sparse_at_end</TT> macro. If one is already at this special
entry, moving further wraps one around to the first or last entry.
<P>The macros for finding the first or last entry in a row or column
take as their arguments a pointer to the matrix (<TT>mod2sparse
*</TT>) and a row or column index, starting at zero. The other macros
take as their arguments a pointer to an entry (<TT>mod2entry *</TT>)
within some matrix.
<BLOCKQUOTE><PRE>
mod2sparse_first_in_row(m,i) /* Returns the first entry in row i of m */
mod2sparse_first_in_col(m,j) /* Returns the first entry in column j of m */
mod2sparse_last_in_row(m,i) /* Returns the last entry in row i of m */
mod2sparse_last_in_col(m,j) /* Returns the last entry in column j of m */
mod2sparse_next_in_row(e) /* Returns the entry after e in its row */
mod2sparse_next_in_col(e) /* Returns the entry after e in its column */
mod2sparse_prev_in_row(e) /* Returns the entry before e in its row */
mod2sparse_prev_in_col(e) /* Returns the entry before e in its col */
mod2sparse_row(e) /* Returns the row index of entry e */
mod2sparse_col(e) /* Returns the column index of entry e */
mod2sparse_at_end(e) /* Returns 1 if e is a special entry obtained
by moving past the end, returns 0 otherwise */
</PRE></BLOCKQUOTE>
<A NAME="alloc-sec">
<P><HR>
<CENTER><BIG>Allocating and Freeing Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="allocate"><HR><B>mod2sparse_allocate</B>:
Allocate space for a sparse module-2 matrix.</A>
<BLOCKQUOTE><PRE>
mod2sparse *mod2sparse_allocate
( int n_rows, /* Number of rows in matrix */
int n_cols /* Number of columns in matrix */
)
</PRE></BLOCKQUOTE>
Allocates space for a matrix with the given number of rows and
columns, and returns a pointer to it. The matrix will initially
be all zero.
<P>If there is not enough memory available, a message is displayed on
standard error and the program is terminated. The matrix should be
freed with <A HREF="#free"><TT>mod2sparse_free</TT></A> once it is no
longer in use.
<P><A NAME="free"><HR><B>mod2sparse_free</B>:
Free the space occupied by a sparse module-2 matrix.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_free
( mod2sparse *m /* Pointer to matrix to free */
)
</PRE></BLOCKQUOTE>
Frees the space occupied by the matrix for re-use. The pointer passed
should not be used afterward. Note that space for the individual matrix
elements (but not the matrix as a whole) is also freed when <A
HREF="#clear"><TT>mod2sparse_clear</TT></A> is called, or the matrix
is used as the destination for other operations.
<A NAME="copy-clear-sec">
<P><HR>
<CENTER><BIG>Copying and Clearing Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="clear"><HR><B>mod2sparse_clear</B>:
Set all elements of a matrix to zero.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_clear
( mod2sparse *m /* Pointer to matrix to clear */
)
</PRE></BLOCKQUOTE>
Sets all of the elements of the matrix passed to 0. The space occupied
by the previous non-zero elements is freed for use in other matrices, or
other purposes. The matrix itself is not freed, however. To do that,
use <A HREF="#free"><TT>mod2sparse_free</TT></A>.
<P><A NAME="copy"><HR><B>mod2sparse_copy</B>:
Copy the contents of one matrix to another.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_copy
( mod2sparse *m /* Pointer to matrix to copy from */
mod2sparse *r /* Pointer to matrix to receive data */
)
</PRE></BLOCKQUOTE>
Copies the contents of the first matrix passed, <B>m</B>, to the
second matrix passed, <B>r</B>, which must already have been
allocated, and must have at least as many rows and columns as the
first. If <B>r</B> is larger than <B>m</B>, its elements that have
row or column indexes greater than the dimension of <B>m</B> are set
to zeros.
<P>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use (which may include being reused immediately for
the copies of the entries in <B>m</B>).
<P><A NAME="copyrows"><HR><B>mod2sparse_copyrows</B>:
Copy selected rows from one matrix to another.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_copyrows
( mod2sparse *m, /* Pointer to matrix to copy rows from */
mod2sparse *r, /* Pointer to matrix in which to store data */
int *rows /* Indexes of rows, numbered from 0 */
)
</PRE></BLOCKQUOTE>
Copies selected rows of the first matrix, <B>m</B>, to the second
matrix, <B>r</B>, which must already have been allocated, and which
must have at least as many columns as <B>m</B>. The indexes of the
rows to copy are given in order as an array of length the same as
the number of rows in <B>r</B>; duplicates are allowed. Row
indexes start at 0. These rows are copied to <B>r</B>, with the
row indexed by the first entry in <B>rows</B> going to the
first row of <B>r</B>, and so forth. If <B>r</B> has more columns than
<B>m</B>, the extra entries in each row are set to zeros.
<P>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use (which may include being reused immediately for
the copies of the entries in <B>m</B>).
<P><A NAME="copycols"><HR><B>mod2sparse_copycols</B>:
Copy selected columns from one matrix to another.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_copycols
( mod2sparse *m, /* Pointer to matrix to copy columns from */
mod2sparse *r, /* Pointer to matrix in which to store data */
int *cols /* Indexes of columns, numbered from 0 */
)
</PRE></BLOCKQUOTE>
Copies selected columns of the first matrix, <B>m</B>, to the second
matrix, <B>r</B>, which must already have been allocated, and which
must have at least as many rows as <B>m</B>. The indexes of the
columns to copy are given in order as an array of length the same as
the number of columns in <B>r</B>; duplicates are allowed. Column
indexes start at 0. These columns are copied to <B>r</B>, with the
column indexed by the first entry in <B>cols</B> going to the
first column of <B>r</B>, and so forth. If <B>r</B> has more rows than
<B>m</B>, the extra entries in each column are set to zeros.
<P>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use (which may include being reused immediately for
the copies of the entries in <B>m</B>).
<A NAME="input-output-sec">
<P><HR>
<CENTER><BIG>Input and Output of Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="print"><HR><B>mod2sparse_print</B>:
Print a sparse modulo-2 matrix in human-readable form.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_print
( FILE *f, /* File to print to */
mod2sparse *m /* Pointer to matrix to print */
)
</PRE></BLOCKQUOTE>
The matrix is printed on standard output with one line of output per row,
of the form
<BLOCKQUOTE><PRE>
<I>row</I>: <I>col col col ...</I>
</PRE></BLOCKQUOTE>
where <I>row</I> is the index of the row, and the <I>col</I> entries are
the indexes of columns that are non-zero in that row. Row and column
indexes start at zero. Rows with no entries are printed with no column
indexes after the colon. The number of columns is not indicated in the output.
<P><A NAME="write"><HR><B>mod2sparse_write</B>:
Write a sparse modulo-2 matrix to a file in machine-readable format.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_write
( FILE *f, /* File to write data to */
mod2sparse *m /* Pointer to matrix write out */
)
</PRE></BLOCKQUOTE>
Writes a machine-readable representation the sparse matrix <B>m</B> to
the file <B>f</B>. The file should have been opened in binary mode
(with a "b" in the mode passed to fopen). The contents written will
not be text, and will not be human-readable. Other binary data may
precede or follow the data for the matrix written.
<P>The data written to the file starts with the number of rows and the
number of columns. Following this are negative integers giving row
indexes (starting at 1), which apply until the next row index, and
positive integers giving column indexes (starting at 1) for a non-zero
entry in the matrix. The data should be readable by <A
HREF="#read"><TT>mod2sparse_read</TT></A> even on a machine with a
different byte-ordering.
<P>The value returned by <TT>mod2sparse_write</TT> is one if the
operation was successful, zero if an error of some sort occurred.
<P><A NAME="read"><HR><B>mod2sparse_read</B>:
Read a sparse modulo-2 matrix from a file.</A>
<BLOCKQUOTE><PRE>
mod2sparse *mod2sparse_read
( FILE *f, /* File to read data from */
)
</PRE></BLOCKQUOTE>
Reads a sparse modulo-2 matrix from the file <B>f</B>. This file
should have been opened in binary mode (with a "b" in the mode passed
to fopen). The contents of the file at the point when
<TT>mod2sparse_read</TT> is called should have been written by <A
HREF="#write"><TT>mod2sparse_write</TT></A>. Other binary data may
precede or follow this data.
<P>The value returned is a pointer to the matrix read, for which space
will have been allocated by <TT>mod2sparse_read</TT>, or zero if an
error occurred (either an error reading the file, or data not in the
right format).
<A NAME="elementary-sec">
<P><HR>
<CENTER><BIG>Elementary Operations on Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="find"><HR><B>mod2sparse_find</B>:
Look for an entry at a given row and column.</A>
<BLOCKQUOTE><PRE>
mod2entry *mod2sparse_find
( mod2sparse *m, /* Matrix in which to look for entry */
int row, /* Row index (from 0) */
int col /* Column index (from 0) */
)
</PRE></BLOCKQUOTE>
Looks for an entry at the given row and column in the matrix <B>m</B>,
representing a non-zero element (ie, one with value 1). Returns a
pointer to this entry if it exists, or zero (a null pointer) if it
does not exist (ie, if that element of the matrix has value 0).
<P>The search strategy is to first look at the end of the row and the
end of the column. The entry might be found at one of these two
places, or it might be determinable from these end entries that no
entry exists at the given row and column. Otherwise, searches are
done from the start of the row and the start of the column, in
parallel, until an entry with the given row and column are found, or
until it can be determined that such an entry does not exist.
Searching in parallel ensures that the operation will be fast if
either the row is sparse or the column is sparse.
<P><A NAME="insert"><HR><B>mod2sparse_insert</B>:
Insert an entry at a given row and column.</A>
<BLOCKQUOTE><PRE>
mod2entry *mod2sparse_insert
( mod2sparse *m, /* Matrix in which to insert an entry */
int row, /* Row index (from 0) */
int col /* Column index (from 0) */
)
</PRE></BLOCKQUOTE>
Adds a new entry (representing an element with value 1) at the given
row and column position in the matrix <B>m</B>. If such an entry
already exists, nothing is done (this is not considered to be an
error). The new (or existing) entry is returned as the value of
this procedure.
<P>The search strategy is to first look at the end of the row for an
existing entry or for the place where the new entry belongs. If this
fails, the row is searched from the beginning. If an existing entry
is found, it is returned. Otherwise, a new entry is created, it is
inserted in its correct place in the row, and it is inserted in its
correct place in its column, once again by first looking at the end,
and then if required searching from the beginning.
<P>The effect of this strategy is that a sparse matrix can be efficiently
created by either adding entries in increasing order by row and column or in
decreasing order by row and column.
<P><A NAME="delete"><HR><B>mod2sparse_delete</B>:
Delete an entry from a sparse modulo-2 matrix.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_delete
( mod2sparse *m, /* Matrix in which to delete an entry */
mod2entry *e /* Entry to delete - MUST be in m */
)
</PRE></BLOCKQUOTE>
Deletes the entry <B>e</B> from the sparse matrix <B>m</B>, which
effectively sets to zero the element of the matrix that this entry
corresponded to. The entry is freed for future use in the same
matrix, but not (immediately, at least) for use in other matrices, or
generally. The pointer to this entry should not be used again once
it is deleted.
<P>The time required for this operation does not depend on how many
entries are currently in the matrix.
<P><B>Warning:</B> It is an error if <B>e</B> is not an entry of
<B>m</B>. This error is not currently diagnosed, but doing this may
cause serious problems, as it may lead later to entries for <B>m</B>
being erroneously freed when the matrix to which <B>e</B> properly
belongs is freed.
<A NAME="arith-sec">
<P><HR>
<CENTER><BIG>Sparse Modulo-2 Matrix Arithmetic and Comparison</BIG></CENTER>
</A>
<A NAME="transpose"><HR><B>mod2sparse_transpose</B>:
Compute the transpose of a sparse modulo-2 matrix.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_transpose
( mod2sparse *m, /* Matrix to compute transpose of */
mod2sparse *r /* Result of transpose operation */
)
</PRE></BLOCKQUOTE>
Stores the transpose of its first argument, <B>m</B>, in the matrix
pointed to by its second argument, <B>r</B>, which must already have
been allocated, and which must have as many rows as <B>m</B> has
columns, and as many columns as <B>m</B> has rows. The two matrices
<B>m</B> and <B>r</B> must not be the same (ie, the two pointers
passed must be different).
<P>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use.
<P><A NAME="add"><HR><B>mod2sparse_add</B>:
Add two sparse modulo-2 matrices.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_add
( mod2sparse *m1, /* Left operand of add */
mod2sparse *m2, /* Right operand of add */
mod2sparse *r /* Place to store result of add */
)
</PRE></BLOCKQUOTE>
Adds matrices <B>m1</B> and <B>m2</B>, storing the result in the
matrix pointed to by <B>r</B>. All three matrices must have the same
numbers of rows and columns. It is permissible for <B>r</B> to be the
same as <B>m1</B> and/or <B>m2</B>. Neither of the first two matrices is
changed by this procedure (unless they are the same as <B>r</B>).
<P>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use.
<P><A NAME="multiply"><HR><B>mod2sparse_multiply</B>:
Multiply two sparse modulo-2 matrices.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_multiply
( mod2sparse *m1, /* Left operand of multiply */
mod2sparse *m2, /* Right operand of multiply */
mod2sparse *r /* Place to store result of multiply */
)
</PRE></BLOCKQUOTE>
Does a matrix multiplication of <B>m1</B> by <B>m2</B>, and stores the
result in the matrix pointed to by <B>r</B>. The matrices must have
compatible numbers of rows and columns. Neither of the first two
matrices is changed by this procedure. The result matrix, <B>r</B>,
must not be the same as either <B>m1</B> or <B>m2</B>.
<P>The space occupied by the previous non-zero entries of <B>r</B> is
freed for general use.
<P><A NAME="mulvec"><HR><B>mod2sparse_mulvec</B>:
Multiply a vector by a sparse modulo-2 matrix.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_mulvec
( mod2sparse *m, /* Pointer to matrix to multiply by, M rows, N columns */
char *u, /* Pointer to unpacked vector to multiply, N long */
char *v /* Pointer to unpacked result vector, M long */
)
</PRE></BLOCKQUOTE>
Multiplies the vector <B>u</B> on the left by the sparse modulo-2
matrix <B>m</B>, storing the result in <B>v</B>. Both <B>u</B> and
<B>v</B> are modulo-2 vectors, but are stored unpacked, with one bit
per char. Any non-zero value in <B>u</B> is equivalent to '1'.
The vectors <B>u</B> and <B>v</B> must not overlap.
<P><A NAME="equal"><HR><B>mod2sparse_equal</B>:
Check whether two sparse modulo-2 matrices are equal.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_equal
( mod2sparse *m1, /* Pointers to the two matrices */
mod2sparse *m2 /* to compare */
)
</PRE></BLOCKQUOTE>
Returns one if every element of <B>m1</B> is equal to the
corresponding element of <B>m2</B>, and otherwise returns zero. The
two matrices must have the same number of rows and the same number of
columns.
<A NAME="row-col-ops-sec">
<P><HR>
<CENTER><BIG>Row/Column Operations on Sparse Modulo-2 Matrices</BIG>
</CENTER></A>
<A NAME="count_row"><HR><B>mod2sparse_count_row</B>:
Count the number of 1s in a row of a sparse matrix.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_count_row
( mod2sparse *m, /* Pointer to matrix */
int row /* Index of row to count (from 0) */
)
</PRE></BLOCKQUOTE>
Returns the number of 1s in the given row of the matrix, by counting
the number of entries in that row.
<P><A NAME="count_col"><HR><B>mod2sparse_count_col</B>:
Count the number of 1s in a column of a sparse matrix.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_count_col
( mod2sparse *m, /* Pointer to matrix */
int col /* Index of column to count (from 0) */
)
</PRE></BLOCKQUOTE>
Returns the number of 1s in the given column of the matrix, by counting
the number of entries in that column.
<P><A NAME="add_row"><HR><B>mod2sparse_add_row</B>:
Add a row to a row of a sparse matrix.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_add_row
( mod2sparse *m1, /* Matrix containing row to add to */
int row1, /* Index in this matrix of row to add to */
mod2sparse *m2, /* Matrix containing row to add from */
int row2 /* Index in this matrix of row to add from */
)
</PRE></BLOCKQUOTE>
Modifies the row with index <B>row1</B> in the matrix <B>m1</B> by
adding to that row the row with index <B>row2</B> in the matrix
<B>m2</B>. The matrix <B>m1</B> must have at least as many columns as
<B>m2</B>. This operation is performed by inserting entries into the
row of <B>m1</B> at positions where they exist in the row of <B>m2</B>
but not in the row of <B>m1</B>, and deleting entries in the row of
<B>m1</B> that exist in the same position in the row of <B>m2</B>.
The matrix <B>m2</B> is not modified.
<P><A NAME="add_col"><HR><B>mod2sparse_add_col</B>:
Add a column to a column of a sparse matrix.</A>
<BLOCKQUOTE><PRE>
void mod2sparse_add_col
( mod2sparse *m1, /* Matrix containing column to add to */
int col1, /* Index in this matrix of col to add to */
mod2sparse *m2, /* Matrix containing column to add from */
int col2 /* Index in this matrix of column to add from */
)
</PRE></BLOCKQUOTE>
Modifies the column with index <B>col1</B> in the matrix <B>m1</B> by
adding to that column the column with index <B>col2</B> in the matrix
<B>m2</B>. The matrix <B>m1</B> must have at least as many rows as
<B>m2</B>. This operation is performed by inserting entries into the
column of <B>m1</B> at positions where they exist in the column of
<B>m2</B> but not in the column of <B>m1</B>, and deleting entries in
the column of <B>m1</B> that exist in the same position in the column
of <B>m2</B>. The matrix <B>m2</B> is not modified.
<A NAME="lu-decomp-sec">
<P><HR>
<CENTER><BIG>LU Decomposition of Sparse Modulo-2 Matrices</BIG></CENTER>
</A>
<A NAME="decomp"><HR><B>mod2sparse_decomp</B>:
Find an LU decomposition of a sparse modulo-2 (sub-)matrix.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_decomp
( mod2sparse *A, /* Matrix to find LU decomposition within, M by N */
int K, /* Size of sub-matrix to find LU decomposition of */
mod2sparse *L, /* Matrix in which L is stored, M by K */
mod2sparse *U, /* Matrix in which U is stored, K by N */
int *rows, /* Array where row indexes are stored, M long */
int *cols, /* Array where column indexes are stored, N long */
mod2sparse_strategy strategy, /* Strategy to follow in picking rows/columns */
int abandon_number, /* Number of columns to abandon at some point */
int abandon_when /* When to abandon these columns */
)
</PRE></BLOCKQUOTE>
<P>Takes as input a matrix, <B>A</B>, having <I>M</I> rows and
<I>N</I> columns, and an integer <I>K</I>. Finds an LU decomposition
of a <I>K</I> by <I>K</I> sub-matrix of <B>A</B>. The decomposition
is stored in the matrix <B>L</B>, with <I>M</I> rows and <I>K</I>
columns, and the matrix <B>U</B>, with <I>K</I> rows and <I>N</I>
columns. The product of <B>L</B> and <B>U</B> will be equal to the
<I>K</I> by <I>K</I> submatrix of <B>A</B> obtained by taking only
rows and columns that are given in the first <I>K</I> elements of the
<B>rows</B> and <B>cols</B> arrays, which are set by this procedure,
with this sub-matrix distributed over the original <I>M</I> rows and
<I>N</I> columns. Furthermore, the ordering of the row and column
indexes in these arrays will be set so that if the rows of <B>L</B>
and the columns of <B>U</B> were rearranged in this order, <B>L</B>
would be lower triangular, with zeros in rows past row <I>K</I>, and
<B>U</B> would be upper triangular, with zeros in columns past column
<I>K</I>. The <B>rows</B> array is <I>M</I> long, and the <B>cols</B>
array is <I>N</I> long. The elements in both arrays after the first
<I>K</I> contain the indexes of the rows and columns not selected to
be part of the sub-matrix of <B>A</B>, in arbitrary order.
<P>The rows and columns of <B>A</B> are selected in order to try to
make the LU decomposition as sparse as possible, using the strategy
identified by the <B>strategy</B>, <B>abandon_number</B>, and
<B>abandon_when</B> parameters. The possible strategies are
<TT>Mod2sparse_first</TT>, <TT>Mod2sparse_mincol</TT>, and
<TT>Mod2sparse_minprod</TT>. If <B>abandon_number</B> is greater than
zero, it is possible that the matrix will appear to have linearly
dependent rows when it actually does not. See the <A
HREF="sparse-LU.html">discussion of sparse LU decomposition
methods</A> for details about these strategies.
<P>If <B>A</B> is not of rank <I>K</I> or more, <B>L</B> will contain
some number less than <I>K</I> of non-zero columns, and <B>U</B> will
contain an equal number of non-zero rows. The entries in the
<B>rows</B> and <B>cols</B> arrays for the extra zero rows or columns
will be arbitrary (but valid). The number of extra zero columns is
returned as the value of this procedure (hence a return value of zero
indicates that a <I>K</I> by <I>K</I> sub-matrix of full rank was
found).
<P>The matrix <B>A</B> is not altered. The previous contents of
<B>L</B> and <B>U</B> are cleared.
<P><A NAME="forward_sub"><HR><B>mod2sparse_forward_sub</B>:
Solve a lower-triangular system by forward substitution.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_forward_sub
( mod2sparse *L, /* Matrix that is lower triangular after reordering */
int *rows, /* Array of indexes (from 0) of rows for new order */
char *x, /* Vector on right of equation, also reordered */
char *y /* Place to store solution */
)
</PRE></BLOCKQUOTE>
<P>Solves the system of equations <B>Ly</B>=<B>x</B> for <B>y</B> by
forward substitution, based on <B>L</B> being lower triangular after
its rows are reordered according to the given index array. The
vectors <B>x</B> and <B>y</B> are stored unpacked, one bit per
character. If <B>L</B> is <I>M</I> by <I>K</I>, then <B>x</B> should
be <I>M</I> long, but only the <I>K</I> bits indexed by <B>rows</B>
are looked at. The solution vector, <B>y</B>, must be <I>K</I> long.
Only <I>K</I> rows of <B>L</B> are used, as also determined by the
<I>K</I> indexes in the <B>rows</B> argument. If <B>rows</B> is null,
the first <I>K</I> rows of <B>L</B> and the first <I>K</I> elements of
<B>x</B> are used.
<P>If the matrix <B>L</B> does not have 1s on its diagonal (after row
rearrangement), there may be no solution, depending on what <B>x</B>
is. If no solution exists, this procedure returns zero, otherwise it
returns one. Any arbitrary bits in the solution are set to zero.
<P><A NAME="backward_sub"><HR><B>mod2sparse_backward_sub</B>:
Solve an upper-triangular system by backward substitution.</A>
<BLOCKQUOTE><PRE>
int mod2sparse_backward_sub
( mod2sparse *U, /* Matrix that is upper triangular after reordering */
int *cols, /* Array of indexes (from 0) of columns for new order */
char *y, /* Vector on right of equation */
char *z /* Place to store solution, also reordered */
)
</PRE></BLOCKQUOTE>
<P>Solves <B>Uz</B>=<B>y</B> for <B>z</B> by backward substitution,
based on <B>U</B> being upper triangular after its columns are
reordered according to the given index array. The vectors <B>y</B>
and <B>z</B> are stored unpacked, one bit per character. If <B>U</B>
is <I>K</I> by <I>N</I>, then the solution vector, <I>z</I>, should be
<I>N</I> long, but only the <I>K</I> bits indexed by <B>cols</B> are
set. The vector <B>y</B> must be <I>K</I> long. Only <I>K</I> columns
of <B>U</B> are used, as also determined by the <I>K</I> indexes in
the <B>cols</B> argument. The other columns of <B>U</B> must be zero
(this is not checked, but is necessary for the method used to work).
If <B>cols</B> is null, the first <I>K</I> columns of <B>U</B> and the
first <I>K</I> elements of <B>z</B> are used.
<P>If the matrix <B>U</B> does not have 1s on its diagonal (after
column rearrangement) there may be no solution, depending on what y
is. If no solution exists, this procedure returns zero, otherwise it
returns one. Any arbitrary bits in the solution are set to zero.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>
@@ -1,3 +0,0 @@
2
3 4
.9 .1
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

@@ -1,46 +0,0 @@
#include "SplashScreen.hpp"
#include <QPixmap>
#include <QVBoxLayout>
#include <QCheckBox>
#include <QCoreApplication>
#include "revision_utils.hpp"
#include "pimpl_impl.hpp"
class SplashScreen::impl
{
public:
impl ()
: checkbox_ {"Do not show this again"}
{
main_layout_.addStretch ();
main_layout_.addWidget (&checkbox_, 0, Qt::AlignRight);
}
QVBoxLayout main_layout_;
QCheckBox checkbox_;
};
SplashScreen::SplashScreen ()
: QSplashScreen {QPixmap {":/splash.png"}, Qt::WindowStaysOnTopHint}
{
setLayout (&m_->main_layout_);
showMessage ("<h2>" + QString {"WSJT-X v" +
QCoreApplication::applicationVersion() + " " +
revision ()}.simplified () + "</h2>"
"V1.8 has many new features.<br /><br />"
"The release notes have more details.<br /><br />"
"Send issue reports to wsjtgroup@yahoogroups.com, and be sure to save .wav<br />"
"files where appropriate.<br /><br />"
"<b>Open the Help menu and select Release Notes for more details.</b><br />"
"<img src=\":/icon_128x128.png\" />"
"<img src=\":/gpl-v3-logo.svg\" height=\"80\" />", Qt::AlignCenter);
connect (&m_->checkbox_, &QCheckBox::stateChanged, [this] (int s) {
if (Qt::Checked == s) Q_EMIT disabled ();
});
}
SplashScreen::~SplashScreen ()
{
}

Some files were not shown because too many files have changed in this diff Show More