Reintegrate the wsjtx_exp branch into the trunk

This  merge brings  the WSPR  feature development  into the  main line
ready for release in a future v1.6 release.



git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5424 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Bill Somerville 2015-05-27 13:08:28 +00:00
parent b8ee4a604b
commit 34f8924cfc
73 changed files with 7563 additions and 1981 deletions

View File

@ -232,6 +232,7 @@ set (wsjtx_CXXSRCS
mainwindow.cpp
Configuration.cpp
main.cpp
wsprnet.cpp
)
if (WIN32)
@ -288,6 +289,7 @@ set (wsjt_FSRCS
lib/fchisq.f90
lib/fchisq65.f90
lib/fil3.f90
lib/fil3c.f90
lib/fil4.f90
lib/fil6521.f90
lib/filbig.f90
@ -302,20 +304,26 @@ set (wsjt_FSRCS
lib/gen4.f90
lib/gen65.f90
lib/gen9.f90
lib/genwspr.f90
lib/geodist.f90
lib/getlags.f90
lib/graycode.f90
lib/graycode65.f90
lib/grayline.f90
lib/grid2deg.f90
lib/hash.f90
lib/hopping.f90
lib/image.f90
lib/indexx.f90
lib/interleave4.f90
lib/interleave63.f90
lib/interleave9.f90
lib/inter_wspr.f90
lib/jt4.f90
lib/jt4a.f90
lib/jt65a.f90
lib/lpf1.f90
lib/mixlpf.f90
lib/moon2.f90
lib/moondop.f90
lib/morse.f90
@ -328,6 +336,7 @@ set (wsjt_FSRCS
lib/polyfit.f90
lib/prog_args.f90
lib/ps4.f90
lib/savec2.f90
lib/sec_midn.f90
lib/setup65.f90
lib/sleep_msec.f90
@ -344,6 +353,7 @@ set (wsjt_FSRCS
lib/sync4.f90
lib/sync9.f90
lib/timer.f90
lib/timf2.f90
lib/tm2.f90
lib/toxyz.f90
lib/twkfreq.f90
@ -355,6 +365,8 @@ set (wsjt_FSRCS
lib/xcor4.f90
lib/zplt.f90
lib/wavhdr.f90
lib/wqencode.f90
lib/wspr_downsample.f90
lib/zplot9.f90
)
@ -364,6 +376,7 @@ set (wsjt_CSRCS
lib/gran.c
lib/igray.c
lib/init_rs.c
lib/wsprd/nhash.c
lib/tmoonsub.c
lib/usleep.c
lib/wisdom.c
@ -657,7 +670,6 @@ if (NOT "${QT_LIBRARY_DIR}" STREQUAL "/lib" AND NOT "${QT_LIBRARY_DIR}" STREQUAL
set (QT_NEED_RPATH TRUE)
endif ()
#
# OpenMP
#
@ -666,10 +678,9 @@ find_package (OpenMP)
#
# fftw3 single precsion library
#
find_package (FFTW3 COMPONENTS single threads REQUIRED)
find_package (FFTW3 COMPONENTS double single threads REQUIRED)
include_directories (${FFTW3_INCLUDE_DIRS})
#
# libhamlib setup
#
@ -838,6 +849,9 @@ target_link_libraries (jt65code wsjt_fort wsjt_cxx)
add_executable (jt9code lib/jt9code.f90 wsjtx.rc)
target_link_libraries (jt9code wsjt_fort wsjt_cxx)
add_executable (wsprd lib/wsprd/wsprd.c lib/wsprd/wsprd_utils.c lib/wsprd/fano.c lib/wsprd/tab.c lib/wsprd/nhash.c)
target_link_libraries (wsprd ${FFTW3_LIBRARIES})
add_executable (jt4code lib/jt4code.f90 wsjtx.rc)
target_link_libraries (jt4code wsjt_fort wsjt_cxx)
@ -946,7 +960,7 @@ install (TARGETS wsjtx
BUNDLE DESTINATION . COMPONENT runtime
)
install (TARGETS jt9 jt65code jt9code jt4code message_aggregator
install (TARGETS jt9 jt65code jt9code jt4code wsprd message_aggregator
RUNTIME DESTINATION ${WSJT_BIN_DESTINATION} COMPONENT runtime
BUNDLE DESTINATION ${WSJT_BIN_DESTINATION} COMPONENT runtime
)

View File

@ -615,7 +615,8 @@ bool Configuration::enable_VHF_features () const {return m_->enable_VHF_features
bool Configuration::decode_at_52s () const {return m_->decode_at_52s_;}
bool Configuration::split_mode () const
{
return !m_->rig_is_dummy_ && m_->rig_params_.split_mode != TransceiverFactory::split_mode_none;
return !m_->rig_is_dummy_ and
(m_->rig_params_.split_mode != TransceiverFactory::split_mode_none);
}
QString Configuration::udp_server_name () const {return m_->udp_server_name_;}
auto Configuration::udp_server_port () const -> port_type {return m_->udp_server_port_;}
@ -704,9 +705,11 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget *
, settings_ {settings}
, doc_dir_ {QApplication::applicationDirPath ()}
, frequencies_ {
{ 136130, 474200, 1838000, 3576000, 5357000, 7076000, 10138000, 14076000, 18102000,
21076000, 24917000, 28076000, 50276000, 70091000, 144000000, 144489000, 222000000,
432000000, 902000000, 1296000000, 2301000000, 2304000000, 2320000000, 3400000000,
{ 136000, 136130, 474200, 1836600, 1838000, 3576000, 3592600, 5287200, 5357000,
7038600, 7076000, 10138000, 10138700, 14076000, 14095600, 18102000, 18104600,
21076000, 21094600, 24917000, 24924600, 28076000, 28124600, 50276000, 50293000,
70091000, 144000000, 144489000, 222000000, 432000000, 432300000,
902000000, 1296000000, 1296500000, 2301000000, 2304000000, 2320000000, 3400000000,
3456000000, 5760000000,10368000000, 24048000000 }
}
, stations_ {&bands_}

View File

@ -27,7 +27,7 @@ public:
Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned samplesPerFFT, unsigned downSampleFactor = 4u, QObject * parent = 0);
Q_SIGNAL void framesWritten (qint64) const;
void setPeriod(unsigned p) {m_period=p;}
bool reset () override;
protected:

View File

@ -24,7 +24,8 @@ double const Modulator::m_twoPi = 2.0 * 3.141592653589793238462;
// m_nspd=3072; //18.75 WPM
unsigned const Modulator::m_nspd = 2048 + 512; // 22.5 WPM
Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent)
Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds,
QObject * parent)
: AudioDevice {parent}
, m_stream {nullptr}
, m_quickClose {false}
@ -41,7 +42,10 @@ Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObjec
m_itone0=0;
}
void Modulator::start (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, double toneSpacing, SoundOutput * stream, Channel channel, bool synchronize, double dBSNR)
void Modulator::start (unsigned symbolsLength, double framesPerSymbol,
unsigned frequency, double toneSpacing,
SoundOutput * stream, Channel channel,
bool synchronize, double dBSNR)
{
Q_ASSERT (stream);
@ -264,6 +268,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
m_itone0=itone[0];
*/
m_frequency0 = m_frequency;
// qDebug() << "a" << m_frequency << m_nsps << m_toneSpacing << toneFrequency0 << baud << isym;
// done for this chunk - continue on next call
return framesGenerated * bytesPerFrame ();

View File

@ -30,6 +30,7 @@ public:
unsigned frequency () const {return m_frequency;}
bool isActive () const {return m_state != Idle;}
void setSpread(double s) {m_fSpread=s;}
void setPeriod(unsigned p) {m_period=p;}
Q_SLOT void start (unsigned symbolsLength, double framesPerSymbol, unsigned frequency, double toneSpacing, SoundOutput *, Channel = Mono, bool synchronize = true, double dBSNR = 99.);
Q_SLOT void stop (bool quick = false);

View File

@ -23,8 +23,9 @@ CAboutDlg::CAboutDlg(QWidget *parent) :
"Amateur Radio communication. <br><br>"
"&copy; 2001-2015 by Joe Taylor, K1JT, with grateful <br>"
"acknowledgment for contributions from AC6SL, AE4JY, <br>"
"DJ0OT, G4KLA, G4WJS, K3WYC, KA6MAL, KA9Q, KB1ZMX, <br>"
"KI7MT, KK1D, PY2SDR, VK3ACF, VK4BDJ, W4TI, W4TV, and W9MDB.<br>");
"DJ0OT, G4KLA, G4WJS, K3WYC, K9AN, KA6MAL, KA9Q, <br>"
"KB1ZMX, KD6EKQ, KI7MT, KK1D, ND0B, PY2SDR, <br>"
"VK3ACF, VK4BDJ, W4TI, W4TV, and W9MDB.<br>");
}
CAboutDlg::~CAboutDlg()

View File

@ -29,6 +29,7 @@ Astro::Astro(QSettings * settings, QWidget * parent)
setWindowTitle(QApplication::applicationName () + " - " + tr ("Astronomical Data"));
setStyleSheet ("QWidget {background: white;}");
read_settings ();
m_Hz=0;
ui_->text_label->clear();
}
@ -60,9 +61,8 @@ void Astro::read_settings ()
m_kHz=settings_->value("kHzAdd",100).toInt();
ui_->kHzSpinBox->setValue(m_kHz);
m_bRxAudioTrack=settings_->value("RxAudioTrack",false).toBool();
ui_->cbRxTrack->setChecked(m_bRxAudioTrack);
m_bTxAudioTrack=settings_->value("TxAudioTrack",false).toBool();
ui_->cbTxTrack->setChecked(m_bTxAudioTrack);
ui_->cbTxAudioTrack->setChecked(m_bTxAudioTrack);
move (settings_->value ("window/pos", pos ()).toPoint ());
settings_->endGroup ();
}
@ -82,10 +82,10 @@ void Astro::write_settings ()
}
void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, qint64 freqMoon,
qint32* ndop, qint32* ndop00)
qint32* ndop, qint32* ndop00, bool bTx)
{
double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx;
double ramoon,decmoon,dgrd,poloffset,xnr,techo;
double ramoon,decmoon,dgrd,poloffset,xnr,techo,width1,width2;
int ntsky;
QString date = t.date().toString("yyyy MMM dd").trimmed ();
QString utc = t.time().toString().trimmed ();
@ -95,16 +95,19 @@ void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, qint64 fre
int nhr=t.time().hour();
int nmin=t.time().minute();
double sec=t.time().second() + 0.001*t.time().msec();
int isec=sec;
double uth=nhr + nmin/60.0 + sec/3600.0;
if(freqMoon < 1) freqMoon=144000000;
int nfreq=freqMoon/1000000;
double freq8=(double)freqMoon;
QDir dataDir = QStandardPaths::writableLocation (QStandardPaths::DataLocation);
QString fname = QDir::toNativeSeparators(dataDir.absoluteFilePath ("azel.dat"));
astrosub_(&nyear, &month, &nday, &uth, &freq8, mygrid.toLatin1(),
hisgrid.toLatin1(), &azsun, &elsun, &azmoon, &elmoon,
&azmoondx, &elmoondx, &ntsky, ndop, ndop00, &ramoon, &decmoon,
&dgrd, &poloffset, &xnr, &techo, 6, 6);
&dgrd, &poloffset, &xnr, &techo, &width1, &width2, &bTx,
fname.toLatin1(), 6, 6, fname.length());
QString message;
{
@ -117,13 +120,15 @@ void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, qint64 fre
<< qSetRealNumberPrecision (1)
<< "Az: " << azmoon << "\n"
"El: " << elmoon << "\n"
"MyDop: " << *ndop00 << "\n"
"Dop: " << *ndop00 << "\n"
"Width: " << int(width1) << "\n"
<< qSetRealNumberPrecision (2)
<< "Delay: " << techo << "\n"
<< qSetRealNumberPrecision (1)
<< "DxAz: " << azmoondx << "\n"
"DxEl: " << elmoondx << "\n"
"DxDop: " << *ndop << "\n"
"DxWid: " << int(width2) << "\n"
"Dec: " << decmoon << "\n"
"SunAz: " << azsun << "\n"
"SunEl: " << elsun << "\n"
@ -134,6 +139,7 @@ void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, qint64 fre
}
ui_->text_label->setText(message);
/*
static QFile f {QDir {QStandardPaths::writableLocation (
QStandardPaths::DataLocation)}.absoluteFilePath ("azel.dat")};
if (!f.open (QIODevice::WriteOnly | QIODevice::Text)) {
@ -185,13 +191,14 @@ void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid, qint64 fre
<< qSetFieldWidth (0) << ",Doppler";
}
f.close();
*/
}
void Astro::on_cbDopplerTracking_toggled(bool b)
{
QRect g=this->geometry();
if(b) {
g.setWidth(460);
g.setWidth(430);
} else {
g.setWidth(200);
}
@ -228,15 +235,9 @@ void Astro::on_rb10Hz_clicked()
void Astro::on_rb100Hz_clicked()
{
m_stepHz=100;
}
void Astro::on_cbRxTrack_toggled(bool b)
{
m_bRxAudioTrack=b;
}
void Astro::on_cbTxTrack_toggled(bool b)
void Astro::on_cbTxAudioTrack_toggled(bool b)
{
m_bTxAudioTrack=b;
}
@ -245,3 +246,8 @@ void Astro::on_kHzSpinBox_valueChanged(int n)
{
m_kHz=n;
}
void Astro::on_HzSpinBox_valueChanged(int n)
{
m_Hz=n;
}

10
astro.h
View File

@ -23,7 +23,7 @@ public:
explicit Astro(QSettings * settings, QWidget * parent = nullptr);
~Astro ();
void astroUpdate(QDateTime t, QString mygrid, QString hisgrid, qint64 freqMoon,
qint32* ndop, qint32 *ndop00);
qint32* ndop, qint32 *ndop00, bool bTx);
bool m_bDopplerTracking;
bool m_bRxAudioTrack;
@ -31,6 +31,7 @@ public:
qint32 m_DopplerMethod;
qint32 m_kHz;
qint32 m_Hz;
qint32 m_stepHz;
protected:
@ -44,9 +45,9 @@ private slots:
void on_rb1Hz_clicked();
void on_rb10Hz_clicked();
void on_rb100Hz_clicked();
void on_cbRxTrack_toggled(bool b);
void on_cbTxTrack_toggled(bool b);
void on_cbTxAudioTrack_toggled(bool b);
void on_kHzSpinBox_valueChanged(int n);
void on_HzSpinBox_valueChanged(int n);
private:
void read_settings ();
@ -63,7 +64,8 @@ extern "C" {
double* elsun, double* azmoon, double* elmoon, double* azmoondx,
double* elmoondx, int* ntsky, int* ndop, int* ndop00,
double* ramoon, double* decmoon, double* dgrd, double* poloffset,
double* xnr, double* techo, int len1, int len2);
double* xnr, double* techo, double* width1, double* width2,
bool* bTx, const char* fname, int len1, int len2, int len3);
}
#endif // ASTRO_H

304
astro.ui
View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>460</width>
<height>420</height>
<width>400</width>
<height>440</height>
</rect>
</property>
<property name="sizePolicy">
@ -19,7 +19,7 @@
<property name="minimumSize">
<size>
<width>200</width>
<height>420</height>
<height>440</height>
</size>
</property>
<property name="styleSheet">
@ -31,7 +31,7 @@
<x>0</x>
<y>0</y>
<width>201</width>
<height>361</height>
<height>400</height>
</rect>
</property>
<property name="sizePolicy">
@ -48,7 +48,7 @@
</property>
<property name="font">
<font>
<family>Courier New</family>
<family>Courier</family>
<pointsize>14</pointsize>
<weight>75</weight>
<italic>false</italic>
@ -71,36 +71,153 @@
<number>6</number>
</property>
</widget>
<widget class="QFrame" name="frame">
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>219</x>
<y>19</y>
<width>221</width>
<height>361</height>
<x>1</x>
<y>410</y>
<width>195</width>
<height>22</height>
</rect>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
<widget class="QGroupBox" name="groupBox">
</spacer>
</item>
<item>
<widget class="QCheckBox" name="cbDopplerTracking">
<property name="text">
<string>Doppler tracking</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<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>
</widget>
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>200</x>
<y>12</y>
<width>198</width>
<height>411</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="minimumSize">
<size>
<width>196</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>60</height>
</size>
</property>
<property name="title">
<string>Frequency above nominal band edge</string>
</property>
<widget class="QSpinBox" name="kHzSpinBox">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>185</width>
<height>96</height>
<width>75</width>
<height>22</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>185</width>
<width>75</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string> kHz</string>
</property>
<property name="maximum">
<number>999</number>
</property>
<property name="value">
<number>200</number>
</property>
</widget>
<widget class="QSpinBox" name="HzSpinBox">
<property name="geometry">
<rect>
<x>100</x>
<y>20</y>
<width>75</width>
<height>22</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>75</width>
<height>0</height>
</size>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string> Hz</string>
</property>
<property name="minimum">
<number>-2000</number>
</property>
<property name="maximum">
<number>2000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="minimumSize">
<size>
<width>196</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
<property name="title">
<string>Doppler tracking</string>
</property>
@ -137,21 +254,21 @@
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="geometry">
<rect>
<x>20</x>
<y>130</y>
<width>185</width>
<height>96</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>185</width>
<width>196</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>90</height>
</size>
</property>
<property name="title">
<string>Transceiver step size</string>
</property>
@ -198,129 +315,54 @@
</property>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="minimumSize">
<size>
<width>196</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>60</height>
</size>
</property>
<property name="title">
<string>Tx audio tracking</string>
</property>
<widget class="QCheckBox" name="cbTxAudioTrack">
<property name="enabled">
<bool>false</bool>
</property>
<property name="geometry">
<rect>
<x>20</x>
<y>230</y>
<width>185</width>
<height>73</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>185</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>Audio frequency tracking</string>
</property>
<widget class="QCheckBox" name="cbRxTrack">
<property name="geometry">
<rect>
<x>10</x>
<y>23</y>
<width>36</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>Rx</string>
</property>
</widget>
<widget class="QCheckBox" name="cbTxTrack">
<property name="geometry">
<rect>
<x>10</x>
<y>46</y>
<width>35</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>Tx</string>
</property>
</widget>
</widget>
<widget class="QGroupBox" name="groupBox_4">
<property name="geometry">
<rect>
<x>20</x>
<y>310</y>
<width>185</width>
<height>51</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>185</width>
<height>0</height>
</size>
</property>
<property name="title">
<string>kHz above nominal band edge</string>
</property>
<widget class="QSpinBox" name="kHzSpinBox">
<property name="geometry">
<rect>
<x>50</x>
<y>20</y>
<width>51</width>
<height>22</height>
<width>105</width>
<height>17</height>
</rect>
</property>
<property name="maximum">
<number>999</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</widget>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>1</x>
<y>386</y>
<width>195</width>
<height>22</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<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>
<item>
<widget class="QCheckBox" name="cbDopplerTracking">
<property name="text">
<string>Doppler tracking</string>
<string>Enable</string>
</property>
</widget>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
<width>20</width>
<height>44</height>
</size>
</property>
</spacer>

View File

@ -2,7 +2,7 @@
#define COMMONS_H
#define NSMAX 6827
#define NTMAX 60
#define NTMAX 120
#define RX_SAMPLE_RATE 12000
extern struct FortranCommon {
@ -28,6 +28,7 @@ extern struct FortranCommon {
int nmode;
int minw;
int nclearave;
int minSync;
float emedelay;
float dttol;
int nlist;

View File

@ -13,4 +13,4 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this documentation. If not, see {gnu_gpl}.
Copyright (C) 2001-2014 Joseph H Taylor, Jr, {joe_taylor}.
Copyright (C) 2001-2015 Joseph H Taylor, Jr, {joe_taylor}.

View File

@ -8,10 +8,10 @@ suggestions and advice that have greatly aided the development of
_WSJT_ and its sister programs.
For _WSJT-X_ in particular, we acknowledge contributions from *AC6SL,
AE4JY, DJ0OT, G4KLA, G4WJS, K3WYC, KA6MAL, KA9Q, KB1ZMX, KI7MT, KK1D,
PY2SDR, VK3ACF, VK4BDJ, W4TI, W4TV, and W9MDB*. Each of these
amateurs has helped to bring the programs design, code, and
documentation to its present state.
AE4JY, DJ0OT, G4KLA, G4WJS, K3WYC, K9AN, KA6MAL, KA9Q, KB1ZMX, KD6EKQ,
KI7MT, KK1D, ND0B, PY2SDR, VK3ACF, VK4BDJ, W4TI, W4TV, and W9MDB*.
Each of these amateurs has helped to bring the programs design, code,
and documentation to its present state.
Most of the color palettes for the _WSJT-X_ waterfall were copied from
the excellent, well documented, open-source program _fldigi_, by *W1HKJ*

View File

@ -31,7 +31,7 @@ subroutine astro0(nyear,month,nday,uth8,freq8,mygrid,hisgrid, &
call tm2(day8,xlat2,xlon2,xl2,b2)
call tm2(day8+1.d0/1440.0,xlat1,xlon1,xl1a,b1a)
call tm2(day8+1.d0/1440.0,xlat2,xlon2,xl2a,b2a)
fghz=0.001*nfreq
fghz=1.d-9*freq8
dldt1=DEGS*(xl1a-xl1)
dbdt1=DEGS*(b1a-b1)
dldt2=DEGS*(xl2a-xl2)

View File

@ -1,14 +1,48 @@
subroutine astrosub(nyear,month,nday,uth8,freq8,mygrid,hisgrid, &
AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8,ntsky,ndop,ndop00, &
RAMoon8,DecMoon8,Dgrd8,poloffset8,xnr8,techo8)
RAMoon8,DecMoon8,Dgrd8,poloffset8,xnr8,techo8,width1,width2,bTx,fname)
implicit real*8 (a-h,o-z)
character*6 mygrid,hisgrid
character*6 mygrid,hisgrid,fname*(*),c1*1
logical*1 bTx
call astro0(nyear,month,nday,uth8,freq8,mygrid,hisgrid, &
AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8,ntsky,ndop,ndop00, &
dbMoon8,RAMoon8,DecMoon8,HA8,Dgrd8,sd8,poloffset8,xnr8,dfdt,dfdt0, &
width1,width2,w501,w502,xlst8,techo8)
return
imin=60*uth8
isec=3600*uth8
ih=uth8
im=mod(imin,60)
is=mod(isec,60)
open(15,file=fname,status='unknown',err=900)
c1='R'
nRx=1
if(bTx) then
c1='T'
nRx=0
endif
AzAux=0.
ElAux=0.
nfreq=freq8/1000000
doppler=ndop
doppler00=ndop00
write(15,1010,err=10) ih,im,is,AzMoon8,ElMoon8, &
ih,im,is,AzSun8,ElSun8, &
ih,im,is,AzAux,ElAux, &
nfreq,doppler,dfdt,doppler00,dfdt0,c1
! TXFirst,TRPeriod,poloffset,Dgrd,xnr,ave,rms,nRx
1010 format( &
i2.2,':',i2.2,':',i2.2,',',f5.1,',',f5.1,',Moon'/ &
i2.2,':',i2.2,':',i2.2,',',f5.1,',',f5.1,',Sun'/ &
i2.2,':',i2.2,':',i2.2,',',f5.1,',',f5.1,',Source'/ &
i5,',',f8.1,',',f8.2,',',f8.1,',',f8.2,',Doppler, ',a1)
! i1,',',i3,',',f8.1,','f8.1,',',f8.1,',',f12.3,',',f12.3,',',i1,',RPol')
10 close(15)
go to 999
900 print*,'Error opening azel.dat'
999 return
end subroutine astrosub

View File

@ -69,7 +69,7 @@ subroutine avg4(nutc,snrsync,dtxx,flip,nfreq,mode4,ntol,ndepth,neme, &
do i=1,nsave
csync='*'
if(flipsave(i).lt.0.0) csync='#'
write(14,1000) cused(i),iutc(i),syncsave(i),dtsave(i),nfsave(i),csync
write(14,1000) cused(i),iutc(i),syncsave(i)-5.0,dtsave(i),nfsave(i),csync
1000 format(a1,i5.4,f6.1,f6.2,i6,1x,a1)
enddo

View File

@ -39,15 +39,18 @@ program code426
do j=5,nmsgs !Find codewords up to j=nmsgs with maximum
npk=0 !distance from all the rest
do i=1,iters
call random_number(c)
ic(1:MZ,j)=int(4*c)
nd=MZ
do k=1,j-1 !Test candidate against all others in list
nd=min(nd,count(ic(1:MZ,j).ne.ic(1:MZ,k)))
enddo
if(nd.gt.npk) then
npk=nd
call random_number(c) !Generate a random codeword candidate
ic(1:MZ,j)=int(4*c) !Convert real to integer
! nd=MZ
! do k=1,j-1 !Test candidate against all others in list
! n=count(ic(1:MZ,j).ne.ic(1:MZ,k))
! nd=min(n,nd)
! enddo
call dist426(ic,j,mind)
if(mind.gt.npk) then
npk=mind
icsave=ic(1:MZ,j) !Best candidate so far, save it
! if(npk.ge.19) exit !It won't get any better...
endif
enddo
write(*,1000) j,npk,ic(1:MZ,j)

View File

@ -1,4 +1,4 @@
parameter (NTMAX=60)
parameter (NTMAX=120)
parameter (NMAX=NTMAX*12000) !Total sample intervals (one minute)
parameter (NDMAX=NTMAX*1500) !Sample intervals at 1500 Hz rate
parameter (NSMAX=6827) !Max length of saved spectra

View File

@ -23,7 +23,8 @@ subroutine decode4(dat,npts,dtx,nfreq,flip,mode4,ndepth,neme,minw, &
istart=nint((dtx+0.8)/dt) !Start index for synced FFTs
if(istart.lt.0) istart=0
nchips=0
qbest=0.0
qbest=0.
qtop=0.
deepmsg=' '
ichbest=-1
c0=0.

View File

@ -11,7 +11,8 @@ subroutine decoder(ss,id2,nfsample)
character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6
common/npar/nutc,ndiskdat,ntrperiod,nfqso,newdat,npts8,nfa,nfsplit,nfb, &
ntol,kin,nzhsym,nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave, &
emedelay,dttol,nlist,listutc(10),datetime,mycall,mygrid,hiscall,hisgrid
minsync,emedelay,dttol,nlist,listutc(10),datetime,mycall,mygrid, &
hiscall,hisgrid
common/tracer/limtrace,lu
integer onlevel(0:10)
@ -41,9 +42,9 @@ subroutine decoder(ss,id2,nfsample)
if(nfsample.eq.12000) call wav11(id2,jz,dd)
if(nfsample.eq.11025) dd(1:jz)=id2(1:jz)
endif
call jt4a(dd,jz,nutc,nfqso,newdat,nfa,nfb,ntol,emedelay,dttol, &
nagain,ndepth,nclearave,minw,nsubmode,mycall,mygrid,hiscall, &
hisgrid,nlist,listutc)
call jt4a(dd,jz,nutc,nfqso,ntol,emedelay,dttol,nagain,ndepth, &
nclearave,minsync,minw,nsubmode,mycall,hiscall,hisgrid, &
nlist,listutc)
go to 800
endif

View File

@ -3,7 +3,7 @@ subroutine encode232(dat,nsym,symbol)
! Convolutional encoder for a K=32, r=1/2 code.
integer*1 dat(13) !User data, packed 8 bits per byte
integer*1 symbol(500) !Channel symbols, one bit per byte
integer*1 symbol(206) !Channel symbols, one bit per byte
integer*1 i1
include 'conv232.f90'

72
lib/fil3c.f90 Normal file
View File

@ -0,0 +1,72 @@
subroutine fil3c(c1,n1,c2,n2)
! FIR complex-to-complex low-pass filter designed with ScopeFIR
!
!-----------------------------------------------
! fsample (Hz) 12000 Input sample rate
! Ntaps 113 Number of filter taps
! fc (Hz) 500 Cutoff frequency
! fstop (Hz) 750 Lower limit of stopband
! Ripple (dB) 0.2 Ripple in passband
! Stop Atten (dB) 50 Stopband attenuation
! fout (Hz) 1500 Output sample rate
! Suggest calling with n1 = 8*n2 + 105, where n2 is the desired number
! of 1500 Hz output samples.
parameter (NTAPS=113)
parameter (NH=NTAPS/2)
parameter (NDOWN=8) !Downsample ratio = 1/8
complex c1(n1)
complex c2(n1/NDOWN)
complex z
! Filter coefficients:
real a(-NH:NH)
data a/ &
-0.001818142144,-0.000939132050,-0.001044063556,-0.001042685542, &
-0.000908957610,-0.000628132309,-0.000202701465, 0.000346307629, &
0.000978154552, 0.001634336295, 0.002243121592, 0.002726064379, &
0.003006201675, 0.003018055983, 0.002717699575, 0.002091546534, &
0.001162489032,-0.000007904811,-0.001321554806,-0.002649908053, &
-0.003843608784,-0.004747338068,-0.005218967042,-0.005148229529, &
-0.004470167307,-0.003177923811,-0.001335998901, 0.000915924193, &
0.003386100636, 0.005818719744, 0.007939147967, 0.009465071347, &
0.010145641899, 0.009787447819, 0.008285915754, 0.005645995244, &
0.001995842303,-0.002410369720,-0.007202515555,-0.011916811719, &
-0.016028350845,-0.018993391440,-0.020297455955,-0.019503792208, &
-0.016298136197,-0.010526834635,-0.002223837363, 0.008378305829, &
0.020854478160, 0.034608532659, 0.048909701463, 0.062944127288, &
0.075874892030, 0.086903764340, 0.095332017649, 0.100619428175, &
0.102420526192, 0.100619428175, 0.095332017649, 0.086903764340, &
0.075874892030, 0.062944127288, 0.048909701463, 0.034608532659, &
0.020854478160, 0.008378305829,-0.002223837363,-0.010526834635, &
-0.016298136197,-0.019503792208,-0.020297455955,-0.018993391440, &
-0.016028350845,-0.011916811719,-0.007202515555,-0.002410369720, &
0.001995842303, 0.005645995244, 0.008285915754, 0.009787447819, &
0.010145641899, 0.009465071347, 0.007939147967, 0.005818719744, &
0.003386100636, 0.000915924193,-0.001335998901,-0.003177923811, &
-0.004470167307,-0.005148229529,-0.005218967042,-0.004747338068, &
-0.003843608784,-0.002649908053,-0.001321554806,-0.000007904811, &
0.001162489032, 0.002091546534, 0.002717699575, 0.003018055983, &
0.003006201675, 0.002726064379, 0.002243121592, 0.001634336295, &
0.000978154552, 0.000346307629,-0.000202701465,-0.000628132309, &
-0.000908957610,-0.001042685542,-0.001044063556,-0.000939132050, &
-0.001818142144/
save a
n2=(n1-NTAPS+NDOWN)/NDOWN
k0=NH-NDOWN+1
! Loop over all output samples
do i=1,n2
z=0.
k=k0 + NDOWN*i
do j=-NH,NH
z=z + c1(j+k)*a(j)
enddo
c2(i)=z
enddo
return
end subroutine fil3c

View File

@ -5,7 +5,8 @@ subroutine fillcom(nutc0,ndepth0,nrxfreq,mode,tx9,flow,fsplit,fhigh)
character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6
common/npar/nutc,ndiskdat,ntrperiod,nfqso,newdat,npts8,nfa,nfsplit,nfb, &
ntol,kin,nzhsym,nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave, &
emedelay,dttol,nlist,listutc(10),datetime,mycall,mygrid,hiscall,hisgrid
minsync,emedelay,dttol,nlist,listutc(10),datetime,mycall,mygrid, &
hiscall,hisgrid
save
nutc=nutc0

View File

@ -12,14 +12,10 @@ subroutine flat1(savg,iz,nsmo,syellow)
call pctile(savg(i-nsmo/2),nsmo,50,x(i))
x(i-nh:i+nh-1)=x(i)
enddo
do i=1,ia-1
x(i)=x(ia)
enddo
do i=ib+1,iz
x(i)=x(ib)
enddo
x(1:ia-1)=x(ia)
x(ib+1:iz)=x(ib)
x0=0.001*maxval(x(1:iz))
x0=0.001*maxval(x(iz/10:(9*iz)/10))
syellow(1:iz)=savg(1:iz)/(x(1:iz)+x0)
return

31
lib/genwspr.f90 Normal file
View File

@ -0,0 +1,31 @@
subroutine genwspr(message,msgsent,itone)
! Encode a WSPR message and generate the array of channel symbols.
character*22 message,msgsent
parameter (MAXSYM=176)
integer*1 symbol(MAXSYM)
integer*1 data0(11)
integer*4 itone(162)
integer npr3(162)
data npr3/ &
1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0, &
0,1,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1, &
0,0,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0,1, &
1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1, &
0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0,0,0,1,0, &
0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1, &
0,1,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,0,1,1, &
0,0,0,0,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0, &
0,0/
call wqencode(message,ntype,data0) !Source encoding
nbytes=(50+31+7)/8
call encode232(data0,162,symbol) !Convolutional encoding
call inter_wspr(symbol,1) !Interleaving
do i=1,162
itone(i)=npr3(i) + 2*symbol(i)
enddo
msgsent=message !### To be fixed... ?? ###
return
end subroutine genwspr

32
lib/grayline.f90 Normal file
View File

@ -0,0 +1,32 @@
subroutine grayline(nyear,month,nday,uth,mygrid,nduration,isun)
character*6 mygrid
real LST
real lat,lon
call grid2deg(MyGrid,elon,lat)
lon=-elon
uth0=uth-0.5*nduration/60.0
uth1=uth+0.5*nduration/60.0
call sun(nyear,month,nday,uth0,lon,lat,RASun,DecSun,LST, &
AzSun,ElSun0,mjd,day)
call sun(nyear,month,nday,uth1,lon,lat,RASun,DecSun,LST, &
AzSun,ElSun1,mjd,day)
elchk=-0.8333
isun=-1
if(elsun0.lt.elchk .and. elsun1.ge.elchk) then
isun=0
else if(elsun0.gt.elchk .and. elsun1.le.elchk) then
isun=2
else if(elsun1.gt.elchk) then
isun=1
else
isun=3
endif
return
end subroutine grayline

15
lib/hash.f90 Normal file
View File

@ -0,0 +1,15 @@
subroutine hash(string,len,ihash)
parameter (MASK15=32767)
character*(*) string
integer*1 ic(12)
do i=1,len
ic(i)=ichar(string(i:i))
enddo
i=nhash(ic,len,146)
ihash=iand(i,MASK15)
! print*,'C',ihash,len,string
return
end subroutine hash

81
lib/hopping.f90 Normal file
View File

@ -0,0 +1,81 @@
subroutine hopping(nyear,month,nday,uth,mygrid,nduration,npctx,isun, &
iband,ntxnext)
! Determine Rx or Tx in coordinated hopping mode.
character*6 mygrid
integer tx(10,6) !T/R array for 2 hours: 10 bands, 6 time slots
real r(6) !Random numbers
integer ii(1)
data n2hr0/-999/
save n2hr0,tx
call grayline(nyear,month,nday,uth,mygrid,nduration,isun)
ns0=uth*3600.0
pctx=npctx
nrx=0
ntxnext=0
nsec=(ns0+10)/120 !Round up to start of next 2-min slot
nsec=nsec*120
n2hr=nsec/7200 !2-hour slot number
if(n2hr.ne.n2hr0) then
! Compute a new Rx/Tx pattern for this 2-hour interval
n2hr0=n2hr !Mark this one as done
tx=0 !Clear the tx array
do j=1,10 !Loop over all 10 bands
call random_number(r)
do i=1,6,2 !Select one each of 3 pairs of the
if(r(i).gt.r(i+1)) then ! 6 slots for Tx
tx(j,i)=1
r(i+1)=0.
else
tx(j,i+1)=1
r(i)=0.
endif
enddo
if(pctx.lt.50.0) then !If pctx < 50, we may kill one Tx slot
ii=maxloc(r)
i=ii(1)
call random_number(rr)
rrtest=(50.0-pctx)/16.667
if(rr.lt.rrtest) then
tx(j,i)=0
r(i)=0.
endif
endif
if(pctx.lt.33.333) then !If pctx < 33, may kill another
ii=maxloc(r)
i=ii(1)
call random_number(rr)
rrtest=(33.333-pctx)/16.667
if(rr.lt.rrtest) then
tx(j,i)=0
r(i)=0.
endif
endif
enddo
! We now have 1 to 3 Tx periods per band in the 2-hour interval.
endif
iband=mod(nsec/120,10) + 1
iseq=mod(nsec/1200,6) + 1
if(iseq.lt.1) iseq=1
if(tx(iband,iseq).eq.1) then
ntxnext=1
else
nrx=1
endif
iband=iband-1
! write(*,3000) iband,iseq,nrx,ntxnext
!3000 format('Fortran iband, iseq,nrx,ntxnext:',4i5)
! write(*,3001) int(tx)
!3001 format(10i2)
return
end subroutine hopping

View File

@ -1,19 +1,91 @@
subroutine indexx(n,arr,indx)
subroutine indexx(arr,n,indx)
parameter (NMAX=3000)
integer indx(n)
real arr(n)
real brr(NMAX)
if(n.gt.NMAX) then
print*,'n=',n,' too big in indexx.'
stop
endif
do i=1,n
brr(i)=arr(i)
indx(i)=i
parameter (M=7,NSTACK=50)
integer n,indx(n)
integer arr(n)
integer i,indxt,ir,itemp,j,jstack,k,l,istack(NSTACK)
real a
do j=1,n
indx(j)=j
enddo
call ssort(brr,indx,n,2)
return
jstack=0
l=1
ir=n
1 if(ir-l.lt.M) then
do j=l+1,ir
indxt=indx(j)
a=arr(indxt)
do i=j-1,1,-1
if(arr(indx(i)).le.a) goto 2
indx(i+1)=indx(i)
enddo
i=0
2 indx(i+1)=indxt
enddo
if(jstack.eq.0) return
ir=istack(jstack)
l=istack(jstack-1)
jstack=jstack-2
else
k=(l+ir)/2
itemp=indx(k)
indx(k)=indx(l+1)
indx(l+1)=itemp
if(arr(indx(l+1)).gt.arr(indx(ir))) then
itemp=indx(l+1)
indx(l+1)=indx(ir)
indx(ir)=itemp
endif
if(arr(indx(l)).gt.arr(indx(ir))) then
itemp=indx(l)
indx(l)=indx(ir)
indx(ir)=itemp
endif
if(arr(indx(l+1)).gt.arr(indx(l))) then
itemp=indx(l+1)
indx(l+1)=indx(l)
indx(l)=itemp
endif
i=l+1
j=ir
indxt=indx(l)
a=arr(indxt)
3 continue
i=i+1
if(arr(indx(i)).lt.a) goto 3
4 continue
j=j-1
if(arr(indx(j)).gt.a) goto 4
if(j.lt.i) goto 5
itemp=indx(i)
indx(i)=indx(j)
indx(j)=itemp
goto 3
5 indx(l)=indx(j)
indx(j)=indxt
jstack=jstack+2
if(jstack.gt.NSTACK) stop 'NSTACK too small in indexx'
if(ir-i+1.ge.j-l)then
istack(jstack)=ir
istack(jstack-1)=i
ir=j-1
else
istack(jstack)=j-1
istack(jstack-1)=l
l=i
endif
endif
goto 1
end subroutine indexx

45
lib/inter_wspr.f90 Normal file
View File

@ -0,0 +1,45 @@
subroutine inter_wspr(id,ndir)
! Interleave (ndir=1) or de-interleave (ndir=-1) the array id.
integer*1 id(0:161),itmp(0:161)
integer j0(0:161)
logical first
data first/.true./
save
if(first) then
! Compute the interleave table using bit reversal.
k=-1
do i=0,255
n=0
ii=i
do j=0,7
n=n+n
if(iand(ii,1).ne.0) n=n+1
ii=ii/2
enddo
if(n.le.161) then
k=k+1
j0(k)=n
endif
enddo
first=.false.
endif
if(ndir.eq.1) then
do i=0,161
itmp(j0(i))=id(i)
enddo
else
do i=0,161
itmp(i)=id(j0(i))
enddo
endif
do i=0,161
id(i)=itmp(i)
enddo
return
end subroutine inter_wspr

View File

@ -1,6 +1,5 @@
subroutine jt4a(dd,jz,nutc,nfqso,newdat,nfa,nfb,ntol0,emedelay,dttol, &
nagain,ndepth,nclearave,minw,nsubmode,mycall,mygrid,hiscall,hisgrid, &
nlist0,listutc0)
subroutine jt4a(dd,jz,nutc,nfqso,ntol0,emedelay,dttol,nagain,ndepth, &
nclearave,minsync,minw,nsubmode,mycall,hiscall,hisgrid,nlist0,listutc0)
use jt4
integer listutc0(10)
@ -8,7 +7,7 @@ subroutine jt4a(dd,jz,nutc,nfqso,newdat,nfa,nfb,ntol0,emedelay,dttol, &
real*4 dat(30*12000)
character*6 cfile6
character*12 mycall,hiscall
character*6 mygrid,hisgrid
character*6 hisgrid
mode4=nch(nsubmode+1)
ntol=ntol0
@ -35,7 +34,7 @@ subroutine jt4a(dd,jz,nutc,nfqso,newdat,nfa,nfb,ntol0,emedelay,dttol, &
cfile6(5:6)=' '
call timer('wsjt4 ',0)
call wsjt4(dat,jz2,nutc,NClearAve,ntol,emedelay,dttol,mode4,minw, &
call wsjt4(dat,jz2,nutc,NClearAve,minsync,ntol,emedelay,dttol,mode4,minw, &
mycall,hiscall,hisgrid,nfqso,NAgain,ndepth,neme)
call timer('wsjt4 ',1)

View File

@ -52,8 +52,9 @@ program jt9
character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6
common/jt9com/ss(184,NSMAX),savg(NSMAX),id2(NMAX),nutc,ndiskdat, &
ntr,mousefqso,newdat,npts8a,nfa,nfsplit,nfb,ntol,kin,nzhsym, &
nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave,emedelay, &
dttol,nlist,listutc(10),datetime,mycall,mygrid,hiscall,hisgrid
nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave,minsync, &
emedelay,dttol,nlist,listutc(10),datetime,mycall,mygrid, &
hiscall,hisgrid
common/tracer/limtrace,lu
common/patience/npatience,nthreads
@ -219,7 +220,8 @@ program jt9
! Compute rough symbol spectra for the JT9 decoder
ingain=0
call timer('symspec ',0)
call symspec(k,ntrperiod,nsps,ingain,pxdb,s,df3, &
nminw=1
call symspec(k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3, &
ihsym,npts8)
call timer('symspec ',1)
endif
@ -227,8 +229,7 @@ program jt9
if(nhsym.ge.181) exit
endif
enddo
10 close(10)
close(10)
call fillcom(nutc0,ndepth,nrxfreq,mode,tx9,flow,fsplit,fhigh)
call decoder(ss,id2,nfsample)
enddo

View File

@ -4,11 +4,12 @@ subroutine jt9c(ss,savg,id2,nparams0)
real*4 ss(184*NSMAX),savg(NSMAX)
integer*2 id2(NTMAX*12000)
integer nparams0(46),nparams(46)
integer nparams0(47),nparams(47)
character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6
common/npar/nutc,ndiskdat,ntrperiod,nfqso,newdat,npts8,nfa,nfsplit,nfb, &
ntol,kin,nzhsym,nsave,nagain,ndepth,ntxmode,nmode,minw,nclearave, &
emedelay,dttol,nlist,listutc(10),datetime,mycall,mygrid,hiscall,hisgrid
minsync,emedelay,dttol,nlist,listutc(10),datetime,mycall,mygrid, &
hiscall,hisgrid
common/patience/npatience,nthreads
equivalence (nparams,nutc)

25
lib/mixlpf.f90 Normal file
View File

@ -0,0 +1,25 @@
subroutine mixlpf(x1,nbfo,c0)
real*4 x1(512)
real*8 twopi,phi,dphi
complex c1(512),c2(105+512)
complex c0(64)
data phi/0.d0/
save phi,c2
twopi=8.d0*atan(1.d0)
dphi=twopi*nbfo/12000.d0
do i=1,512
phi=phi+dphi
if(phi.gt.twopi) phi=phi-twopi
xphi=phi
c1(i)=x1(i)*cmplx(cos(xphi),sin(xphi))
enddo
c2(106:105+512)=c1
call fil3c(c2,105+512,c0,n2)
c2(1:105)=c1(512-104:512) !Save 105 trailing samples
return
end subroutine mixlpf

View File

@ -898,4 +898,90 @@ function nchar(c)
return
end function nchar
subroutine pack50(n1,n2,dat)
integer*1 dat(11),i1
i1=iand(ishft(n1,-20),255) !8 bits
dat(1)=i1
i1=iand(ishft(n1,-12),255) !8 bits
dat(2)=i1
i1=iand(ishft(n1, -4),255) !8 bits
dat(3)=i1
i1=16*iand(n1,15)+iand(ishft(n2,-18),15) !4+4 bits
dat(4)=i1
i1=iand(ishft(n2,-10),255) !8 bits
dat(5)=i1
i1=iand(ishft(n2, -2),255) !8 bits
dat(6)=i1
i1=64*iand(n2,3) !2 bits
dat(7)=i1
dat(8)=0
dat(9)=0
dat(10)=0
dat(11)=0
return
end subroutine pack50
subroutine packpfx(call1,n1,ng,nadd)
character*12 call1,call0
character*3 pfx
logical text
i1=index(call1,'/')
if(call1(i1+2:i1+2).eq.' ') then
! Single-character add-on suffix (maybe also fourth suffix letter?)
call0=call1(:i1-1)
call packcall(call0,n1,text)
nadd=1
nc=ichar(call1(i1+1:i1+1))
if(nc.ge.48 .and. nc.le.57) then
n=nc-48
else if(nc.ge.65 .and. nc.le.90) then
n=nc-65+10
else
n=38
endif
nadd=1
ng=60000-32768+n
else if(call1(i1+3:i1+3).eq.' ') then
! Two-character numerical suffix, /10 to /99
call0=call1(:i1-1)
call packcall(call0,n1,text)
nadd=1
n=10*(ichar(call1(i1+1:i1+1))-48) + ichar(call1(i1+2:i1+2)) - 48
nadd=1
ng=60000 + 26 + n
else
! Prefix of 1 to 3 characters
pfx=call1(:i1-1)
if(pfx(3:3).eq.' ') pfx=' '//pfx(1:2)
if(pfx(3:3).eq.' ') pfx=' '//pfx(1:2)
call0=call1(i1+1:)
call packcall(call0,n1,text)
ng=0
do i=1,3
nc=ichar(pfx(i:i))
if(nc.ge.48 .and. nc.le.57) then
n=nc-48
else if(nc.ge.65 .and. nc.le.90) then
n=nc-65+10
else
n=36
endif
ng=37*ng + n
enddo
nadd=0
if(ng.ge.32768) then
ng=ng-32768
nadd=1
endif
endif
return
end subroutine packpfx
end module packjt

54
lib/savec2.f90 Normal file
View File

@ -0,0 +1,54 @@
subroutine savec2(c2name,ntrseconds,f0m1500)
! Array c0() has complex samples at 1500 Hz sample rate.
! WSPR-2: downsample by 1/4 to produce c2, centered at 1500 Hz
! WSPR-15: downsample by 1/32 to produce c2, centered at 1612.5 Hz
parameter (NDMAX=120*1500) !Sample intervals at 1500 Hz rate
parameter (MAXFFT=256*1024)
character*(*) c2name
character*14 outfile
real*8 f0m1500
complex c0
complex c1(0:MAXFFT-1)
complex c2(0:65535)
common/c0com/c0(0:NDMAX-1)
ntrminutes=ntrseconds/60
npts=114*1500
nfft1=262144
if(ntrminutes.eq.15) then
npts=890*1500
nfft1=MAXFFT
endif
df1=1500.0/nfft1
fac=1.0/nfft1
c1(0:npts-1)=fac*c0(0:npts-1)
c1(npts:nfft1-1)=0.
call four2a(c1,nfft1,1,1,1) !Complex FFT to frequency domain
! Select the desired frequency range
nfft2=65536
nh2=nfft2/2
if(ntrminutes.eq.2) then
c2(0:nh2)=c1(0:nh2)
c2(nh2+1:nfft2-1)=c1(nfft1-nh2+1:nfft1-1)
else
i0=nint(112.5/df1)
c2(0:nh2)=c1(i0:i0+nh2)
c2(nh2+1:nfft2-1)=c1(i0-nh2+1:i0-1)
endif
call four2a(c2,nfft2,1,-1,1) !Shorter complex FFT, back to time domain
! Write complex time-domain data to disk.
i1=index(c2name,'.c2')
outfile=c2name(i1-11:i1+2)
open(18,file=c2name,status='unknown',access='stream')
write(18) outfile,ntrminutes,f0m1500,c2(0:45000-1)
close(18)
return
end subroutine savec2

View File

@ -11,13 +11,9 @@ subroutine smo(x,npts,y,nadd)
enddo
y(i)=sum
enddo
y(:nh)=0.
y(npts-nh+1:)=0.
fac=1.0/nadd
do i=1,npts
x(i)=fac*y(i)
enddo
x=y
x(:nh)=0.
x(npts-nh+1:)=0.
return
end subroutine smo

View File

@ -1,4 +1,4 @@
subroutine symspec(k,ntrperiod,nsps,ingain,pxdb,s,df3,ihsym,npts8)
subroutine symspec(k,ntrperiod,nsps,ingain,nminw,pxdb,s,df3,ihsym,npts8)
! Input:
! k pointer to the most recent new data
@ -11,7 +11,7 @@ subroutine symspec(k,ntrperiod,nsps,ingain,pxdb,s,df3,ihsym,npts8)
! Output:
! pxdb power (0-60 dB)
! s() current spectrum for waterfall display
! ihsym index number of this half-symbol (1-184)
! ihsym index number of this half-symbol (1-184) for 60 s modes
! jt9com
! ss() JT9 symbol spectra at half-symbol steps
@ -25,15 +25,18 @@ subroutine symspec(k,ntrperiod,nsps,ingain,pxdb,s,df3,ihsym,npts8)
real*4 tmp(NSMAX)
complex cx(0:MAXFFT3/2)
integer*2 id2
integer nch(7)
character datetime*20,mycall*12,mygrid*6,hiscall*12,hisgrid*6
common/jt9com/ss(184,NSMAX),savg(NSMAX),id2(NMAX),nutc,ndiskdat, &
ntr,mousefqso,newdat,npts8a,nfa,nfsplit,nfb,ntol,kin,nzhsym, &
nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave,emedelay, &
dttol,nlist,listutc(10),datetime,mycall,mygrid,hiscall,hisgrid
nsubmode,nagain,ndepth,ntxmode,nmode,minw,nclearave,minsync, &
emedelay,dttol,nlist,listutc(10),datetime,mycall,mygrid, &
hiscall,hisgrid
common/jt9w/syellow(NSMAX)
data rms/999.0/,k0/99999999/,nfft3z/0/
data nch/1,2,4,9,18,36,72/
equivalence (xc,cx)
save
@ -84,34 +87,33 @@ subroutine symspec(k,ntrperiod,nsps,ingain,pxdb,s,df3,ihsym,npts8)
xc(i)=0.
if(j.ge.1 .and.j.le.NMAX) xc(i)=fac0*id2(j)
enddo
if(ihsym.lt.184) ihsym=ihsym+1
ihsym=ihsym+1
xc(0:nfft3-1)=w3(1:nfft3)*xc(0:nfft3-1) !Apply window w3
call four2a(xc,nfft3,1,-1,0) !Real-to-complex FFT
n=min(184,ihsym)
df3=12000.0/nfft3 !JT9-1: 0.732 Hz = 0.42 * tone spacing
! i0=nint(1000.0/df3)
i0=0
iz=min(NSMAX,nint(5000.0/df3))
fac=(1.0/nfft3)**2
do i=1,iz
j=i0+i-1
j=i-1
if(j.lt.0) j=j+nfft3
sx=fac*(real(cx(j))**2 + aimag(cx(j))**2)
ss(n,i)=sx
if(ihsym.le.184) ss(ihsym,i)=sx
ssum(i)=ssum(i) + sx
s(i)=1000.0*gain*sx
enddo
savg=ssum/ihsym
if(mod(n,10).eq.0) then
mode4=36
if(mod(ihsym,10).eq.0) then
mode4=nch(nminw+1)
nsmo=min(10*mode4,150)
nsmo=4*nsmo
call flat1(savg,iz,nsmo,syellow)
if(mode4.ge.9) call smo(syellow,iz,tmp,mode4)
if(mode4.ge.2) call smo(syellow,iz,tmp,mode4)
if(mode4.ge.2) call smo(syellow,iz,tmp,mode4)
syellow(1:250)=0.
ia=500./df3
ib=2700.0/df3
smin=minval(syellow(ia:ib))

View File

@ -9,7 +9,6 @@ subroutine sync4(dat,jz,mode4,minw)
real dat(jz)
real psavg(NHMAX) !Average spectrum of whole record
real s2(NHMAX,NSMAX) !2d spectrum, stepped by half-symbols
real ccfblue(65) !CCF with pseudorandom sequence
real tmp(1260)
save

142
lib/timf2.f90 Normal file
View File

@ -0,0 +1,142 @@
subroutine timf2(x0,k,nfft,nwindow,nb,peaklimit,x1, &
slimit,lstrong,px,nzap)
! Sequential processing of time-domain I/Q data, using Linrad-like
! "first FFT" and "first backward FFT", treating frequencies with
! strong signals differently. Noise blanking is applied to weak
! signals only.
! x0 - real input data
! nfft - length of FFTs
! nwindow - 0 for no window, 2 for sin^2 window
! x1 - real output data
! Non-windowed processing means no overlap, so kstep=nfft.
! Sin^2 window has 50% overlap, kstep=nfft/2.
! Frequencies with strong signals are identified and separated. Back
! transforms are done separately for weak and strong signals, so that
! noise blanking can be applied to the weak-signal portion. Strong and
! weak are finally re-combined, in the time domain.
parameter (MAXFFT=1024,MAXNH=MAXFFT/2)
parameter (MAXSIGS=100)
real x0(0:nfft-1),x1(0:nfft-1)
real x(0:MAXFFT-1),xw(0:MAXFFT-1),xs(0:MAXFFT-1)
real xwov(0:MAXNH-1),xsov(0:MAXNH-1)
complex cx(0:MAXFFT-1),cxt(0:MAXFFT-1)
complex cxs(0:MAXFFT-1) !Strong signals
complex cxw(0:MAXFFT-1) !Weak signals
real*4 w(0:MAXFFT-1)
real*4 s(0:MAXNH)
logical*1 lstrong(0:MAXNH),lprev
integer ia(MAXSIGS),ib(MAXSIGS)
logical first
equivalence (x,cx),(xw,cxw),(xs,cxs)
data first/.true./
data k0/99999999/
save
if(first) then
pi=4.0*atan(1.0)
do i=0,nfft-1
w(i)=(sin(i*pi/nfft))**2
enddo
s=0.
nh=nfft/2
kstep=nfft
if(nwindow.eq.2) kstep=nh
fac=1.0/nfft
slimit=1.e30
first=.false.
endif
if(k.lt.k0) then
xsov=0.
xwov=0.
endif
k0=k
x(0:nfft-1)=x0
if(nwindow.eq.2) x(0:nfft-1)=w(0:nfft-1)*x(0:nfft-1)
call four2a(x,nfft,1,-1,0) !First forward FFT, r2c
cxt(0:nh)=cx(0:nh)
! Identify frequencies with strong signals.
do i=0,nh
p=real(cxt(i))**2 + aimag(cxt(i))**2
s(i)=p
enddo
ave=sum(s(0:nh))/nh
lstrong(0:nh)=s(0:nh).gt.10.0*ave
nsigs=0
lprev=.false.
iwid=1
ib=-99
do i=0,nh
if(lstrong(i) .and. (.not.lprev)) then
if(nsigs.lt.MAXSIGS) nsigs=nsigs+1
ia(nsigs)=i-iwid
if(ia(nsigs).lt.0) ia(nsigs)=0
endif
if(.not.lstrong(i) .and. lprev) then
ib(nsigs)=i-1+iwid
if(ib(nsigs).gt.nh) ib(nsigs)=nh
endif
lprev=lstrong(i)
enddo
if(nsigs.gt.0) then
do i=1,nsigs
ja=ia(i)
jb=ib(i)
if(ja.lt.0 .or. ja.gt.nh .or. jb.lt.0 .or. jb.gt.nh) then
cycle
endif
if(jb.eq.-99) jb=ja + min(2*iwid,nh)
lstrong(ja:jb)=.true.
enddo
endif
! Copy frequency-domain data into array cs (strong) or cw (weak).
do i=0,nh
if(lstrong(i)) then
cxs(i)=fac*cxt(i)
cxw(i)=0.
else
cxw(i)=fac*cxt(i)
cxs(i)=0.
endif
enddo
call four2a(cxw,nfft,1,1,-1) !Transform weak and strong back
call four2a(cxs,nfft,1,1,-1) !to time domain, separately (c2r)
if(nwindow.eq.2) then
xw(0:nh-1)=xw(0:nh-1)+xwov(0:nh-1) !Add previous segment's 2nd half
xwov(0:nh-1)=xw(nh:nfft-1) !Save 2nd half
xs(0:nh-1)=xs(0:nh-1)+xsov(0:nh-1) !Ditto for strong signals
xsov(0:nh-1)=xs(nh:nfft-1)
endif
! Apply noise blanking to weak data
if(nb.ne.0) then
do i=0,kstep-1
peak=abs(xw(i))
if(peak.gt.peaklimit) then
xw(i)=0.
nzap=nzap+1
endif
enddo
endif
! Compute power levels from weak data only
do i=0,kstep-1
px=px + xw(i)**2
enddo
x1(0:kstep-1)=xw(0:kstep-1) + xs(0:kstep-1) !Recombine weak + strong
return
end subroutine timf2

65
lib/wqencode.f90 Normal file
View File

@ -0,0 +1,65 @@
subroutine wqencode(msg,ntype,data0)
! Parse and encode a WSPR message.
use packjt
parameter (MASK15=32767)
character*22 msg
character*12 call1,call2
character grid4*4,grid6*6
logical lbad1,lbad2
integer*1 data0(11)
integer nu(0:9)
data nu/0,-1,1,0,-1,2,1,0,-1,1/
! Standard WSPR message (types 0 3 7 10 13 17 ... 60)
i1=index(msg,' ')
i2=index(msg,'/')
i3=index(msg,'<')
call1=msg(:i1-1)
if(i1.lt.3 .or. i1.gt.7 .or. i2.gt.0 .or. i3.gt.0) go to 10
grid4=msg(i1+1:i1+4)
call packcall(call1,n1,lbad1)
call packgrid(grid4,ng,lbad2)
if(lbad1 .or. lbad2) go to 10
ndbm=0
read(msg(i1+5:),*) ndbm
if(ndbm.lt.0) ndbm=0
if(ndbm.gt.60) ndbm=60
ndbm=ndbm+nu(mod(ndbm,10))
n2=128*ng + (ndbm+64)
call pack50(n1,n2,data0)
ntype=ndbm
go to 900
10 if(i2.ge.2 .and. i3.lt.1) then
call packpfx(call1,n1,ng,nadd)
ndbm=0
read(msg(i1+1:),*) ndbm
if(ndbm.lt.0) ndbm=0
if(ndbm.gt.60) ndbm=60
ndbm=ndbm+nu(mod(ndbm,10))
ntype=ndbm + 1 + nadd
n2=128*ng + ntype + 64
call pack50(n1,n2,data0)
else if(i3.eq.1) then
i4=index(msg,'>')
call1=msg(2:i4-1)
call hash(call1,i4-2,ih)
grid6=msg(i1+1:i1+6)
call2=grid6(2:6)//grid6(1:1)//' '
call packcall(call2,n1,lbad1)
ndbm=0
read(msg(i1+8:),*) ndbm
if(ndbm.lt.0) ndbm=0
if(ndbm.gt.60) ndbm=60
ndbm=ndbm+nu(mod(ndbm,10))
ntype=-(ndbm+1)
n2=128*ih + ntype + 64
call pack50(n1,n2,data0)
endif
go to 900
900 continue
return
end subroutine wqencode

View File

@ -1,4 +1,4 @@
subroutine wsjt4(dat,npts,nutc,NClearAve,ntol,emedelay,dttol, &
subroutine wsjt4(dat,npts,nutc,NClearAve,minsync,ntol,emedelay,dttol, &
mode4,minw,mycall,hiscall,hisgrid,nfqso,NAgain,ndepth,neme)
! Orchestrates the process of decoding JT4 messages, using data that
@ -30,8 +30,7 @@ subroutine wsjt4(dat,npts,nutc,NClearAve,ntol,emedelay,dttol, &
endif
zz=0.
! syncmin=1.0
syncmin=7.0
syncmin=5.0 + minsync
naggressive=0
if(ndepth.ge.2) naggressive=1
nq1=3
@ -102,7 +101,7 @@ subroutine wsjt4(dat,npts,nutc,NClearAve,ntol,emedelay,dttol, &
! Fano succeeded: display the message and return FANO OK
write(*,1010) nutc,nsnr,dtx,nfreq,csync,decoded,' *', &
char(ichar('A')+ich-1)
1010 format(i4.4,i4,f5.2,i5,a1,1x,a22,a2,1x,a1,i3)
1010 format(i4.4,i4,f5.2,i5,1x,a1,1x,a22,a2,1x,a1,i3)
nsave=0
go to 990
@ -176,4 +175,3 @@ subroutine wsjt4(dat,npts,nutc,NClearAve,ntol,emedelay,dttol, &
990 return
end subroutine wsjt4

76
lib/wspr_downsample.f90 Normal file
View File

@ -0,0 +1,76 @@
subroutine wspr_downsample(id2,k)
! Input:
! id2 raw 16-bit integer data, 12000 Hz sample rate
! k pointer to the most recent new data
! Output (in common/c0com)
! c0 complex data downsampled to 1500 Hz
parameter (NMAX=120*12000) !Total sample intervals per 30 minutes
parameter (NDMAX=120*1500) !Sample intervals at 1500 Hz rate
parameter (NSMAX=1366) !Max length of saved spectra
parameter (NFFT1=1024)
parameter (MAXFFT3=32768)
real*4 w3(MAXFFT3)
real*4 x0(NFFT1),x1(NFFT1)
real*4 x2(NFFT1+105)
real*4 ssum(NSMAX)
logical*1 lstrong(0:1023) !Should be (0:512)
integer*2 id2(NMAX)
complex c0
common/c0com/c0(NDMAX)
data rms/999.0/,k0/99999999/,nfft3z/0/,nsps/8192/,nbfo/1500/
save
nfft3=nsps/4
jstep=nsps/16
if(k.gt.NMAX) go to 999
if(k.lt.nfft3) go to 999 !Wait for enough samples to start
if(nfft3.ne.nfft3z) then
pi=4.0*atan(1.0)
do i=1,nfft3
w3(i)=2.0*(sin(i*pi/nfft3))**2 !Window for nfft3
enddo
nfft3z=nfft3
endif
if(k.lt.k0) then
ja=0
ssum=0.
k1=0
k8=0
x2=0.
! if(ndiskdat.eq.0) then
! id2(k+1:)=0
! c0=0. !This is necessary to prevent "ghosts". Not sure why.
! endif
endif
k0=k
nzap=0
nbslider=0
sigmas=1.0*(10.0**(0.01*nbslider)) + 0.7
peaklimit=sigmas*max(10.0,rms)
px=0.
nwindow=2
kstep1=NFFT1
if(nwindow.ne.0) kstep1=NFFT1/2
fac=2.0/NFFT1
nblks=(k-k1)/kstep1
gain=1.0
do nblk=1,nblks
do i=1,NFFT1
x0(i)=gain*id2(k1+i)
enddo
call timf2(x0,k,NFFT1,nwindow,nb,peaklimit,x1, &
slimit,lstrong,px,nzap)
! Mix at nbfo Hz, lowpass at +/-750 Hz, and downsample to 1500 Hz complex.
call mixlpf(x1,nbfo,c0(k8+1))
k1=k1+kstep1
k8=k8+kstep1/8
enddo
999 return
end subroutine wspr_downsample

39
lib/wsprd/Makefile Normal file
View File

@ -0,0 +1,39 @@
#CC = gcc
CC = clang
FC = gfortran
FFLAGS = -O2 -Wall -Wno-conversion
CFLAGS= -I/usr/include -Wall -Wno-missing-braces -O2
LDFLAGS = -L/usr/lib
LIBS = -lfftw3 -lm
# Default rules
%.o: %.c $(DEPS)
${CC} ${CFLAGS} -c $<
%.o: %.f
${FC} ${FFLAGS} -c $<
%.o: %.F
${FC} ${FFLAGS} -c $<
%.o: %.f90
${FC} ${FFLAGS} -c $<
%.o: %.F90
${FC} ${FFLAGS} -c $<
all: wsprd WSPRcode test_wspr
DEPS = fano.h
OBJS1 = wsprd.o wsprd_utils.o fano.o tab.o nhash.o
wsprd: $(OBJS1)
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) $(LIBS)
OBJS2 = test_wspr.o unpk.o wsprd_utils.o nhash.o
test_wspr: $(OBJS2) libwspr.a
$(FC) -o test_wspr $(FFLAGS) $(OBJS2) libwspr.a
OBJS3 = WSPRcode.o
WSPRcode: $(OBJS3) libwspr.a
$(FC) -o WSPRcode $(FFLAGS) $(OBJS3) libwspr.a
clean:
rm *.o wsprd

30
lib/wsprd/Makefile.MinGW Normal file
View File

@ -0,0 +1,30 @@
CC = gcc
#CC = clang
FC = gfortran
FFLAGS = -O2 -Wall -Wno-conversion
CFLAGS= -Wall -Wno-missing-braces -O2
#LDFLAGS = -L/JTSDK/fftw3f
LIBS = c:/JTSDK/fftw3f/libfftw3-3.dll -lm
# Default rules
%.o: %.c $(DEPS)
${CC} ${CFLAGS} -c $<
%.o: %.f
${FC} ${FFLAGS} -c $<
%.o: %.F
${FC} ${FFLAGS} -c $<
%.o: %.f90
${FC} ${FFLAGS} -c $<
%.o: %.F90
${FC} ${FFLAGS} -c $<
all: wsprd
DEPS = fano.h
OBJS1 = wsprd.o wsprd_utils.o fano.o tab.o nhash.o
wsprd: $(OBJS1)
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS) $(LIBS)
clean:
rm *.o wsprd

132
lib/wsprd/WSPRcode.f90 Normal file
View File

@ -0,0 +1,132 @@
program wsprcode
! This program provides examples of the source encoding, convolutional
! error-control coding, bit and symbol ordering, and synchronizing
! information contained in WSPR messages.
parameter (NSYM=162)
parameter (MAXSYM=176)
character*22 msg,msg2
integer*1 data0(7)
integer*1 data1(7)
integer*1 dat(NSYM)
integer*1 softsym(NSYM)
! Define the sync vector:
integer*1 sync(NSYM)
data sync/ &
1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0, &
0,1,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1, &
0,0,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0,1, &
1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1, &
0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0,0,0,1,0, &
0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1, &
0,1,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,0,1,1, &
0,0,0,0,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0, &
0,0/
! Metric table for decoding from soft symbols
integer mettab(0:255,0:1)
data mettab/ &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 4, &
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, &
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, &
3, 3, 3, 3, 3, 3, 3, 3, 3, 2, &
2, 2, 2, 2, 1, 1, 1, 1, 0, 0, &
-1, -1, -1, -2, -2, -3, -4, -4, -5, -6, &
-7, -7, -8, -9, -10, -11, -12, -12, -13, -14, &
-15, -16, -17, -17, -18, -19, -20, -21, -22, -22, &
-23, -24, -25, -26, -26, -27, -28, -29, -30, -30, &
-31, -32, -33, -33, -34, -35, -36, -36, -37, -38, &
-38, -39, -40, -41, -41, -42, -43, -43, -44, -45, &
-45, -46, -47, -47, -48, -49, -49, -50, -51, -51, &
-52, -53, -53, -54, -54, -55, -56, -56, -57, -57, &
-58, -59, -59, -60, -60, -61, -62, -62, -62, -63, &
-64, -64, -65, -65, -66, -67, -67, -67, -68, -69, &
-69, -70, -70, -71, -72, -72, -72, -72, -73, -74, &
-75, -75, -75, -77, -76, -76, -78, -78, -80, -81, &
-80, -79, -83, -82, -81, -82, -82, -83, -84, -84, &
-84, -87, -86, -87, -88, -89, -89, -89, -88, -87, &
-86, -87, -84, -84, -84, -83, -82, -82, -81, -82, &
-83, -79, -80, -81, -80, -78, -78, -76, -76, -77, &
-75, -75, -75, -74, -73, -72, -72, -72, -72, -71, &
-70, -70, -69, -69, -68, -67, -67, -67, -66, -65, &
-65, -64, -64, -63, -62, -62, -62, -61, -60, -60, &
-59, -59, -58, -57, -57, -56, -56, -55, -54, -54, &
-53, -53, -52, -51, -51, -50, -49, -49, -48, -47, &
-47, -46, -45, -45, -44, -43, -43, -42, -41, -41, &
-40, -39, -38, -38, -37, -36, -36, -35, -34, -33, &
-33, -32, -31, -30, -30, -29, -28, -27, -26, -26, &
-25, -24, -23, -22, -22, -21, -20, -19, -18, -17, &
-17, -16, -15, -14, -13, -12, -12, -11, -10, -9, &
-8, -7, -7, -6, -5, -4, -4, -3, -2, -2, &
-1, -1, -1, 0, 0, 1, 1, 1, 1, 2, &
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, &
3, 3, 3, 4, 4, 4, 4, 4, 4, 4, &
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, &
4, 4, 4, 4, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5/
! Get command-line argument(s)
nargs=iargc()
if(nargs.ne.1) then
print*,'Usage: WSPRcode "message"'
go to 999
endif
call getarg(1,msg) !Get message from command line
write(*,1000) msg
1000 format('Message: ',a22)
nbits=50+31 !User bits=50, constraint length=32
nbytes=(nbits+7)/8
ndelta=50
limit=20000
data0=0
call wqencode(msg,ntype0,data0) !Source encoding
write(*,1002) data0
1002 format(/'Source-encoded message (50 bits, hex):',7z3.2)
call encode232(data0,nbytes,dat,MAXSYM) !Convolutional encoding
call inter_mept(dat,1) !Interleaving
write(*,1004)
1004 format(/'Data symbols:')
write(*,1006) (dat(i),i=1,NSYM)
1006 format(5x,30i2)
write(*,1008)
1008 format(/'Sync symbols:')
write(*,1006) (sync(i),i=1,NSYM)
write(*,1010)
1010 format(/'Channel symbols:')
write(*,1006) (2*dat(i)+sync(i),i=1,NSYM)
call inter_mept(dat,-1) !Remove interleaving
softsym=-dat !Simulate soft symbols
! Call the sequential (Fano algorithm) decoder
call fano232(softsym,nbits,mettab,ndelta,limit,data1,ncycles,metric,nerr)
call wqdecode(data1,msg2,ntype1)
write(*,1020) ntype1
1020 format(/'Message type: ',i7)
write(*,1030) msg2
1030 format('Decoded message: ',a22)
999 end program wsprcode

255
lib/wsprd/fano.c Normal file
View File

@ -0,0 +1,255 @@
/*
This file is part of wsprd.
File name: fano.c
Description: Soft decision Fano sequential decoder for K=32 r=1/2
convolutional code.
Copyright 1994, Phil Karn, KA9Q
Minor modifications by Joe Taylor, K1JT
*/
#define LL 1 // Select Layland-Lushbaugh code
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "fano.h"
struct node {
unsigned long encstate; // Encoder state of next node
long gamma; // Cumulative metric to this node
int metrics[4]; // Metrics indexed by all possible tx syms
int tm[2]; // Sorted metrics for current hypotheses
int i; // Current branch being tested
};
// Convolutional coding polynomials. All are rate 1/2, K=32
#ifdef NASA_STANDARD
/* "NASA standard" code by Massey & Costello
* Nonsystematic, quick look-in, dmin=11, dfree=23
* used on Pioneer 10-12, Helios A,B
*/
#define POLY1 0xbbef6bb7
#define POLY2 0xbbef6bb5
#endif
#ifdef MJ
/* Massey-Johannesson code
* Nonsystematic, quick look-in, dmin=13, dfree>=23
* Purported to be more computationally efficient than Massey-Costello
*/
#define POLY1 0xb840a20f
#define POLY2 0xb840a20d
#endif
#ifdef LL
/* Layland-Lushbaugh code
* Nonsystematic, non-quick look-in, dmin=?, dfree=?
*/
#define POLY1 0xf2d05351
#define POLY2 0xe4613c47
#endif
/* Convolutional encoder macro. Takes the encoder state, generates
* a rate 1/2 symbol pair and stores it in 'sym'. The symbol generated from
* POLY1 goes into the 2-bit of sym, and the symbol generated from POLY2
* goes into the 1-bit.
*/
#define ENCODE(sym,encstate) {\
unsigned long _tmp;\
\
_tmp = (encstate) & POLY1;\
_tmp ^= _tmp >> 16;\
(sym) = Partab[(_tmp ^ (_tmp >> 8)) & 0xff] << 1;\
_tmp = (encstate) & POLY2;\
_tmp ^= _tmp >> 16;\
(sym) |= Partab[(_tmp ^ (_tmp >> 8)) & 0xff];\
}
/* Convolutionally encode a packet. The input data bytes are read
* high bit first and the encoded packet is written into 'symbols',
* one symbol per byte. The first symbol is generated from POLY1,
* the second from POLY2.
*
* Storing only one symbol per byte uses more space, but it is faster
* and easier than trying to pack them more compactly.
*/
int encode(
unsigned char *symbols, // Output buffer, 2*nbytes
unsigned char *data, // Input buffer, nbytes
unsigned int nbytes) // Number of bytes in data
{
unsigned long encstate;
int sym;
int i;
encstate = 0;
while(nbytes-- != 0) {
for(i=7;i>=0;i--) {
encstate = (encstate << 1) | ((*data >> i) & 1);
ENCODE(sym,encstate);
*symbols++ = sym >> 1;
*symbols++ = sym & 1;
}
data++;
}
return 0;
}
/* Decode packet with the Fano algorithm.
* Return 0 on success, -1 on timeout
*/
int fano(
unsigned int *metric, // Final path metric (returned value)
unsigned int *cycles, // Cycle count (returned value)
unsigned int *maxnp, // Progress before timeout (returned value)
unsigned char *data, // Decoded output data
unsigned char *symbols, // Raw deinterleaved input symbols
unsigned int nbits, // Number of output bits
int mettab[2][256], // Metric table, [sent sym][rx symbol]
int delta, // Threshold adjust parameter
unsigned int maxcycles) // Decoding timeout in cycles per bit
{
struct node *nodes; // First node
struct node *np; // Current node
struct node *lastnode; // Last node
struct node *tail; // First node of tail
int t; // Threshold
int m0,m1;
int ngamma;
unsigned int lsym;
unsigned int i;
if((nodes = (struct node *)malloc(nbits*sizeof(struct node))) == NULL) {
printf("malloc failed\n");
return 0;
}
lastnode = &nodes[nbits-1];
tail = &nodes[nbits-31];
*maxnp = 0;
/* Compute all possible branch metrics for each symbol pair
* This is the only place we actually look at the raw input symbols
*/
for(np=nodes;np <= lastnode;np++) {
np->metrics[0] = mettab[0][symbols[0]] + mettab[0][symbols[1]];
np->metrics[1] = mettab[0][symbols[0]] + mettab[1][symbols[1]];
np->metrics[2] = mettab[1][symbols[0]] + mettab[0][symbols[1]];
np->metrics[3] = mettab[1][symbols[0]] + mettab[1][symbols[1]];
symbols += 2;
}
np = nodes;
np->encstate = 0;
// Compute and sort branch metrics from root node */
ENCODE(lsym,np->encstate); // 0-branch (LSB is 0)
m0 = np->metrics[lsym];
/* Now do the 1-branch. To save another ENCODE call here and
* inside the loop, we assume that both polynomials are odd,
* providing complementary pairs of branch symbols.
* This code should be modified if a systematic code were used.
*/
m1 = np->metrics[3^lsym];
if(m0 > m1) {
np->tm[0] = m0; // 0-branch has better metric
np->tm[1] = m1;
} else {
np->tm[0] = m1; // 1-branch is better
np->tm[1] = m0;
np->encstate++; // Set low bit
}
np->i = 0; // Start with best branch
maxcycles *= nbits;
np->gamma = t = 0;
// Start the Fano decoder
for(i=1;i <= maxcycles;i++) {
if((int)(np-nodes) > (int)*maxnp) *maxnp=(int)(np-nodes);
#ifdef debug
printf("k=%ld, g=%ld, t=%d, m[%d]=%d, maxnp=%d\n",
np-nodes,np->gamma,t,np->i,np->tm[np->i],*maxnp);
#endif
// Look forward */
ngamma = np->gamma + np->tm[np->i];
if(ngamma >= t) {
if(np->gamma < t + delta) { // Node is acceptable
/* First time we've visited this node;
* Tighten threshold.
*
* This loop could be replaced with
* t += delta * ((ngamma - t)/delta);
* but the multiply and divide are slower.
*/
while(ngamma >= t + delta) t += delta;
}
np[1].gamma = ngamma; // Move forward
np[1].encstate = np->encstate << 1;
if(++np == lastnode) {
break; // Done!
}
/* Compute and sort metrics, starting with the
* zero branch
*/
ENCODE(lsym,np->encstate);
if(np >= tail) {
/* The tail must be all zeroes, so don't
* bother computing the 1-branches here.
*/
np->tm[0] = np->metrics[lsym];
} else {
m0 = np->metrics[lsym];
m1 = np->metrics[3^lsym];
if(m0 > m1) {
np->tm[0] = m0; // 0-branch is better
np->tm[1] = m1;
} else {
np->tm[0] = m1; // 1-branch is better
np->tm[1] = m0;
np->encstate++; // Set low bit
}
}
np->i = 0; // Start with best branch
continue;
}
// Threshold violated, can't go forward
for(;;) { // Look backward
if(np == nodes || np[-1].gamma < t) {
/* Can't back up either.
* Relax threshold and and look
* forward again to better branch.
*/
t -= delta;
if(np->i != 0) {
np->i = 0;
np->encstate ^= 1;
}
break;
}
// Back up
if(--np < tail && np->i != 1) {
np->i++; // Search next best branch
np->encstate ^= 1;
break;
} // else keep looking back
}
}
*metric = np->gamma; // Return the final path metric
// Copy decoded data to user's buffer
nbits >>= 3;
np = &nodes[7];
while(nbits-- != 0) {
*data++ = np->encstate;
np += 8;
}
*cycles = i+1;
free(nodes);
if(i >= maxcycles) return -1; // Decoder timed out
return 0; // Successful completion
}

21
lib/wsprd/fano.h Normal file
View File

@ -0,0 +1,21 @@
/*
This file is part of wsprd.
File name: fano.h
Description: Header file for sequential Fano decoder.
Copyright 1994, Phil Karn, KA9Q
Minor modifications by Joe Taylor, K1JT
*/
int fano(unsigned int *metric, unsigned int *cycles, unsigned int *maxnp,
unsigned char *data,unsigned char *symbols, unsigned int nbits,
int mettab[2][256],int delta,unsigned int maxcycles);
int encode(unsigned char *symbols,unsigned char *data,unsigned int nbytes);
extern unsigned char Partab[];

410
lib/wsprd/fftw3.h Normal file
View File

@ -0,0 +1,410 @@
/*
* Copyright (c) 2003, 2007-11 Matteo Frigo
* Copyright (c) 2003, 2007-11 Massachusetts Institute of Technology
*
* The following statement of license applies *only* to this header file,
* and *not* to the other files distributed with FFTW or derived therefrom:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/***************************** NOTE TO USERS *********************************
*
* THIS IS A HEADER FILE, NOT A MANUAL
*
* If you want to know how to use FFTW, please read the manual,
* online at http://www.fftw.org/doc/ and also included with FFTW.
* For a quick start, see the manual's tutorial section.
*
* (Reading header files to learn how to use a library is a habit
* stemming from code lacking a proper manual. Arguably, it's a
* *bad* habit in most cases, because header files can contain
* interfaces that are not part of the public, stable API.)
*
****************************************************************************/
#ifndef FFTW3_H
#define FFTW3_H
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
/* If <complex.h> is included, use the C99 complex type. Otherwise
define a type bit-compatible with C99 complex */
#if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I)
# define FFTW_DEFINE_COMPLEX(R, C) typedef R _Complex C
#else
# define FFTW_DEFINE_COMPLEX(R, C) typedef R C[2]
#endif
#define FFTW_CONCAT(prefix, name) prefix ## name
#define FFTW_MANGLE_DOUBLE(name) FFTW_CONCAT(fftw_, name)
#define FFTW_MANGLE_FLOAT(name) FFTW_CONCAT(fftwf_, name)
#define FFTW_MANGLE_LONG_DOUBLE(name) FFTW_CONCAT(fftwl_, name)
#define FFTW_MANGLE_QUAD(name) FFTW_CONCAT(fftwq_, name)
/* IMPORTANT: for Windows compilers, you should add a line
#define FFTW_DLL
here and in kernel/ifftw.h if you are compiling/using FFTW as a
DLL, in order to do the proper importing/exporting, or
alternatively compile with -DFFTW_DLL or the equivalent
command-line flag. This is not necessary under MinGW/Cygwin, where
libtool does the imports/exports automatically. */
#if defined(FFTW_DLL) && (defined(_WIN32) || defined(__WIN32__))
/* annoying Windows syntax for shared-library declarations */
# if defined(COMPILING_FFTW) /* defined in api.h when compiling FFTW */
# define FFTW_EXTERN extern __declspec(dllexport)
# else /* user is calling FFTW; import symbol */
# define FFTW_EXTERN extern __declspec(dllimport)
# endif
#else
# define FFTW_EXTERN extern
#endif
enum fftw_r2r_kind_do_not_use_me {
FFTW_R2HC=0, FFTW_HC2R=1, FFTW_DHT=2,
FFTW_REDFT00=3, FFTW_REDFT01=4, FFTW_REDFT10=5, FFTW_REDFT11=6,
FFTW_RODFT00=7, FFTW_RODFT01=8, FFTW_RODFT10=9, FFTW_RODFT11=10
};
struct fftw_iodim_do_not_use_me {
int n; /* dimension size */
int is; /* input stride */
int os; /* output stride */
};
#include <stddef.h> /* for ptrdiff_t */
struct fftw_iodim64_do_not_use_me {
ptrdiff_t n; /* dimension size */
ptrdiff_t is; /* input stride */
ptrdiff_t os; /* output stride */
};
typedef void (*fftw_write_char_func_do_not_use_me)(char c, void *);
typedef int (*fftw_read_char_func_do_not_use_me)(void *);
/*
huge second-order macro that defines prototypes for all API
functions. We expand this macro for each supported precision
X: name-mangling macro
R: real data type
C: complex data type
*/
#define FFTW_DEFINE_API(X, R, C) \
\
FFTW_DEFINE_COMPLEX(R, C); \
\
typedef struct X(plan_s) *X(plan); \
\
typedef struct fftw_iodim_do_not_use_me X(iodim); \
typedef struct fftw_iodim64_do_not_use_me X(iodim64); \
\
typedef enum fftw_r2r_kind_do_not_use_me X(r2r_kind); \
\
typedef fftw_write_char_func_do_not_use_me X(write_char_func); \
typedef fftw_read_char_func_do_not_use_me X(read_char_func); \
\
FFTW_EXTERN void X(execute)(const X(plan) p); \
\
FFTW_EXTERN X(plan) X(plan_dft)(int rank, const int *n, \
C *in, C *out, int sign, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_1d)(int n, C *in, C *out, int sign, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_2d)(int n0, int n1, \
C *in, C *out, int sign, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_3d)(int n0, int n1, int n2, \
C *in, C *out, int sign, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_many_dft)(int rank, const int *n, \
int howmany, \
C *in, const int *inembed, \
int istride, int idist, \
C *out, const int *onembed, \
int ostride, int odist, \
int sign, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_dft)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
C *in, C *out, \
int sign, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru_split_dft)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *ri, R *ii, R *ro, R *io, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_dft)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
C *in, C *out, \
int sign, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru64_split_dft)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *ri, R *ii, R *ro, R *io, \
unsigned flags); \
\
FFTW_EXTERN void X(execute_dft)(const X(plan) p, C *in, C *out); \
FFTW_EXTERN void X(execute_split_dft)(const X(plan) p, R *ri, R *ii, \
R *ro, R *io); \
\
FFTW_EXTERN X(plan) X(plan_many_dft_r2c)(int rank, const int *n, \
int howmany, \
R *in, const int *inembed, \
int istride, int idist, \
C *out, const int *onembed, \
int ostride, int odist, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_r2c)(int rank, const int *n, \
R *in, C *out, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_r2c_2d)(int n0, int n1, \
R *in, C *out, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_r2c_3d)(int n0, int n1, \
int n2, \
R *in, C *out, unsigned flags); \
\
\
FFTW_EXTERN X(plan) X(plan_many_dft_c2r)(int rank, const int *n, \
int howmany, \
C *in, const int *inembed, \
int istride, int idist, \
R *out, const int *onembed, \
int ostride, int odist, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_c2r)(int rank, const int *n, \
C *in, R *out, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_c2r_2d)(int n0, int n1, \
C *in, R *out, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_c2r_3d)(int n0, int n1, \
int n2, \
C *in, R *out, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_dft_r2c)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *in, C *out, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru_dft_c2r)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
C *in, R *out, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_split_dft_r2c)( \
int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *in, R *ro, R *io, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru_split_dft_c2r)( \
int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *ri, R *ii, R *out, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_dft_r2c)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *in, C *out, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru64_dft_c2r)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
C *in, R *out, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_split_dft_r2c)( \
int rank, const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *in, R *ro, R *io, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru64_split_dft_c2r)( \
int rank, const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *ri, R *ii, R *out, \
unsigned flags); \
\
FFTW_EXTERN void X(execute_dft_r2c)(const X(plan) p, R *in, C *out); \
FFTW_EXTERN void X(execute_dft_c2r)(const X(plan) p, C *in, R *out); \
\
FFTW_EXTERN void X(execute_split_dft_r2c)(const X(plan) p, \
R *in, R *ro, R *io); \
FFTW_EXTERN void X(execute_split_dft_c2r)(const X(plan) p, \
R *ri, R *ii, R *out); \
\
FFTW_EXTERN X(plan) X(plan_many_r2r)(int rank, const int *n, \
int howmany, \
R *in, const int *inembed, \
int istride, int idist, \
R *out, const int *onembed, \
int ostride, int odist, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_r2r)(int rank, const int *n, R *in, R *out, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_r2r_1d)(int n, R *in, R *out, \
X(r2r_kind) kind, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_r2r_2d)(int n0, int n1, R *in, R *out, \
X(r2r_kind) kind0, X(r2r_kind) kind1, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_r2r_3d)(int n0, int n1, int n2, \
R *in, R *out, X(r2r_kind) kind0, \
X(r2r_kind) kind1, X(r2r_kind) kind2, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_r2r)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *in, R *out, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_r2r)(int rank, const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *in, R *out, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN void X(execute_r2r)(const X(plan) p, R *in, R *out); \
\
FFTW_EXTERN void X(destroy_plan)(X(plan) p); \
FFTW_EXTERN void X(forget_wisdom)(void); \
FFTW_EXTERN void X(cleanup)(void); \
\
FFTW_EXTERN void X(set_timelimit)(double t); \
\
FFTW_EXTERN void X(plan_with_nthreads)(int nthreads); \
FFTW_EXTERN int X(init_threads)(void); \
FFTW_EXTERN void X(cleanup_threads)(void); \
\
FFTW_EXTERN int X(export_wisdom_to_filename)(const char *filename); \
FFTW_EXTERN void X(export_wisdom_to_file)(FILE *output_file); \
FFTW_EXTERN char *X(export_wisdom_to_string)(void); \
FFTW_EXTERN void X(export_wisdom)(X(write_char_func) write_char, \
void *data); \
FFTW_EXTERN int X(import_system_wisdom)(void); \
FFTW_EXTERN int X(import_wisdom_from_filename)(const char *filename); \
FFTW_EXTERN int X(import_wisdom_from_file)(FILE *input_file); \
FFTW_EXTERN int X(import_wisdom_from_string)(const char *input_string); \
FFTW_EXTERN int X(import_wisdom)(X(read_char_func) read_char, void *data); \
\
FFTW_EXTERN void X(fprint_plan)(const X(plan) p, FILE *output_file); \
FFTW_EXTERN void X(print_plan)(const X(plan) p); \
\
FFTW_EXTERN void *X(malloc)(size_t n); \
FFTW_EXTERN R *X(alloc_real)(size_t n); \
FFTW_EXTERN C *X(alloc_complex)(size_t n); \
FFTW_EXTERN void X(free)(void *p); \
\
FFTW_EXTERN void X(flops)(const X(plan) p, \
double *add, double *mul, double *fmas); \
FFTW_EXTERN double X(estimate_cost)(const X(plan) p); \
FFTW_EXTERN double X(cost)(const X(plan) p); \
\
FFTW_EXTERN const char X(version)[]; \
FFTW_EXTERN const char X(cc)[]; \
FFTW_EXTERN const char X(codelet_optim)[];
/* end of FFTW_DEFINE_API macro */
FFTW_DEFINE_API(FFTW_MANGLE_DOUBLE, double, fftw_complex)
FFTW_DEFINE_API(FFTW_MANGLE_FLOAT, float, fftwf_complex)
FFTW_DEFINE_API(FFTW_MANGLE_LONG_DOUBLE, long double, fftwl_complex)
/* __float128 (quad precision) is a gcc extension on i386, x86_64, and ia64
for gcc >= 4.6 (compiled in FFTW with --enable-quad-precision) */
#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) \
&& !(defined(__ICC) || defined(__INTEL_COMPILER)) \
&& (defined(__i386__) || defined(__x86_64__) || defined(__ia64__))
# if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I)
/* note: __float128 is a typedef, which is not supported with the _Complex
keyword in gcc, so instead we use this ugly __attribute__ version.
However, we can't simply pass the __attribute__ version to
FFTW_DEFINE_API because the __attribute__ confuses gcc in pointer
types. Hence redefining FFTW_DEFINE_COMPLEX. Ugh. */
# undef FFTW_DEFINE_COMPLEX
# define FFTW_DEFINE_COMPLEX(R, C) typedef _Complex float __attribute__((mode(TC))) C
# endif
FFTW_DEFINE_API(FFTW_MANGLE_QUAD, __float128, fftwq_complex)
#endif
#define FFTW_FORWARD (-1)
#define FFTW_BACKWARD (+1)
#define FFTW_NO_TIMELIMIT (-1.0)
/* documented flags */
#define FFTW_MEASURE (0U)
#define FFTW_DESTROY_INPUT (1U << 0)
#define FFTW_UNALIGNED (1U << 1)
#define FFTW_CONSERVE_MEMORY (1U << 2)
#define FFTW_EXHAUSTIVE (1U << 3) /* NO_EXHAUSTIVE is default */
#define FFTW_PRESERVE_INPUT (1U << 4) /* cancels FFTW_DESTROY_INPUT */
#define FFTW_PATIENT (1U << 5) /* IMPATIENT is default */
#define FFTW_ESTIMATE (1U << 6)
#define FFTW_WISDOM_ONLY (1U << 21)
/* undocumented beyond-guru flags */
#define FFTW_ESTIMATE_PATIENT (1U << 7)
#define FFTW_BELIEVE_PCOST (1U << 8)
#define FFTW_NO_DFT_R2HC (1U << 9)
#define FFTW_NO_NONTHREADED (1U << 10)
#define FFTW_NO_BUFFERING (1U << 11)
#define FFTW_NO_INDIRECT_OP (1U << 12)
#define FFTW_ALLOW_LARGE_GENERIC (1U << 13) /* NO_LARGE_GENERIC is default */
#define FFTW_NO_RANK_SPLITS (1U << 14)
#define FFTW_NO_VRANK_SPLITS (1U << 15)
#define FFTW_NO_VRECURSE (1U << 16)
#define FFTW_NO_SIMD (1U << 17)
#define FFTW_NO_SLOW (1U << 18)
#define FFTW_NO_FIXED_RADIX_LARGE_N (1U << 19)
#define FFTW_ALLOW_PRUNING (1U << 20)
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
#endif /* FFTW3_H */

50
lib/wsprd/genmet.f90 Normal file
View File

@ -0,0 +1,50 @@
program genmet
character*12 arg
integer hist(-128:128)
lim(x)=min(127,max(-128,nint(scale*x)))
nargs=iargc()
if(nargs.ne.4) then
print*,'Usage: genmet bw scale snr iters'
print*,'Example: genmet 1.46 20 -24 1000000'
go to 999
endif
call getarg(1,arg)
read(arg,*) bw
call getarg(2,arg)
read(arg,*) scale
call getarg(3,arg)
read(arg,*) snr
call getarg(4,arg)
read(arg,*) iters
hist=0
s=sqrt(2500.0/bw) * 10.0**(0.05*snr)
fac=1.0/sqrt(2.0)
do iter=1,iters
x1=fac*gran()
y1=fac*gran()
x0=fac*gran()
y0=fac*gran()
r=(x1+s)**2 + y1*y1 - x0*x0 - y0*y0
hist(lim(r))=hist(lim(r))+1
enddo
xln2=log(2.0)
do i=-128,127
p1=hist(i)/dfloat(iters)
j=-i
if(j.gt.127) j=127
p0=hist(j)/dfloat(iters)
xlhd0=log(max(0.001,2.0*p0/(p0+p1)))/xln2
xlhd1=log(max(0.001,2.0*p1/(p0+p1)))/xln2
write(13,1010) i/scale,hist(i)/dfloat(iters)
1010 format(f8.3,f12.9)
write(14,1012) i+128,xlhd0,xlhd1
1012 format(i4,2f8.3)
enddo
999 end program genmet

28
lib/wsprd/gran.c Normal file
View File

@ -0,0 +1,28 @@
#include <stdlib.h>
#include <math.h>
/* Generate gaussian random float with mean=0 and std_dev=1 */
float gran_()
{
float fac,rsq,v1,v2;
static float gset;
static int iset;
if(iset){
/* Already got one */
iset = 0;
return gset;
}
/* Generate two evenly distributed numbers between -1 and +1
* that are inside the unit circle
*/
do {
v1 = 2.0 * (float)rand() / RAND_MAX - 1;
v2 = 2.0 * (float)rand() / RAND_MAX - 1;
rsq = v1*v1 + v2*v2;
} while(rsq >= 1.0 || rsq == 0.0);
fac = sqrt(-2.0*log(rsq)/rsq);
gset = v1*fac;
iset++;
return v2*fac;
}

111
lib/wsprd/metric_tables.c Normal file
View File

@ -0,0 +1,111 @@
/*******************************************************************************
* 4 metric tables calculated via simulation for 2-FSK with Es/No=0,3,6,9 dB
* tables were calculated for constant rms noise level of 50. The symbol vector
* should be normalized to have rms amplitude equal to "symbol_scale".
********************************************************************************/
//float symbol_scale[4]={42.6, 53.3, 72.7, 100.2};
float metric_tables[4][256]={
0.9782, 0.9695, 0.9689, 0.9669, 0.9666, 0.9653, 0.9638, 0.9618, 0.9599, 0.9601,
0.9592, 0.9570, 0.9556, 0.9540, 0.9525, 0.9527, 0.9486, 0.9477, 0.9450, 0.9436,
0.9424, 0.9400, 0.9381, 0.9360, 0.9340, 0.9316, 0.9301, 0.9272, 0.9254, 0.9224,
0.9196, 0.9171, 0.9154, 0.9123, 0.9076, 0.9061, 0.9030, 0.9000, 0.8965, 0.8934,
0.8903, 0.8874, 0.8834, 0.8792, 0.8760, 0.8726, 0.8685, 0.8639, 0.8599, 0.8550,
0.8504, 0.8459, 0.8422, 0.8364, 0.8320, 0.8262, 0.8215, 0.8159, 0.8111, 0.8052,
0.7996, 0.7932, 0.7878, 0.7812, 0.7745, 0.7685, 0.7616, 0.7550, 0.7479, 0.7405,
0.7336, 0.7255, 0.7184, 0.7102, 0.7016, 0.6946, 0.6860, 0.6769, 0.6687, 0.6598,
0.6503, 0.6416, 0.6325, 0.6219, 0.6122, 0.6016, 0.5920, 0.5818, 0.5711, 0.5606,
0.5487, 0.5374, 0.5266, 0.5142, 0.5020, 0.4908, 0.4784, 0.4663, 0.4532, 0.4405,
0.4271, 0.4144, 0.4006, 0.3865, 0.3731, 0.3594, 0.3455, 0.3304, 0.3158, 0.3009,
0.2858, 0.2708, 0.2560, 0.2399, 0.2233, 0.2074, 0.1919, 0.1756, 0.1590, 0.1427,
0.1251, 0.1074, 0.0905, 0.0722, 0.0550, 0.0381, 0.0183, 0.0000, -0.0185, -0.0391,
-0.0571, -0.0760, -0.0966, -0.1160, -0.1370, -0.1584, -0.1787, -0.1999, -0.2214, -0.2423,
-0.2643, -0.2879, -0.3114, -0.3336, -0.3568, -0.3806, -0.4050, -0.4293, -0.4552, -0.4798,
-0.5046, -0.5296, -0.5564, -0.5836, -0.6093, -0.6372, -0.6645, -0.6933, -0.7208, -0.7495,
-0.7763, -0.8065, -0.8378, -0.8660, -0.8964, -0.9293, -0.9592, -0.9907, -1.0214, -1.0509,
-1.0850, -1.1168, -1.1528, -1.1847, -1.2157, -1.2511, -1.2850, -1.3174, -1.3540, -1.3900,
-1.4201, -1.4580, -1.4956, -1.5292, -1.5683, -1.6030, -1.6411, -1.6789, -1.7147, -1.7539,
-1.7887, -1.8289, -1.8699, -1.9043, -1.9469, -1.9849, -2.0267, -2.0610, -2.1028, -2.1391,
-2.1855, -2.2215, -2.2712, -2.3033, -2.3440, -2.3870, -2.4342, -2.4738, -2.5209, -2.5646,
-2.6016, -2.6385, -2.6868, -2.7356, -2.7723, -2.8111, -2.8524, -2.9009, -2.9428, -2.9879,
-3.0103, -3.0832, -3.1340, -3.1628, -3.2049, -3.2557, -3.3101, -3.3453, -3.4025, -3.4317,
-3.4828, -3.5270, -3.5745, -3.6181, -3.6765, -3.7044, -3.7410, -3.8118, -3.8368, -3.9549,
-3.9488, -3.9941, -4.0428, -4.0892, -4.1648, -4.1965, -4.1892, -4.2565, -4.3356, -4.3948,
-4.4481, -4.4607, -4.5533, -4.5809, -4.5927, -5.1047,
0.9978, 0.9962, 0.9961, 0.9959, 0.9958, 0.9954, 0.9949, 0.9950, 0.9947, 0.9942,
0.9940, 0.9939, 0.9933, 0.9931, 0.9928, 0.9924, 0.9921, 0.9916, 0.9911, 0.9909,
0.9903, 0.9900, 0.9892, 0.9887, 0.9883, 0.9877, 0.9869, 0.9863, 0.9857, 0.9848,
0.9842, 0.9835, 0.9825, 0.9817, 0.9808, 0.9799, 0.9791, 0.9777, 0.9767, 0.9757,
0.9744, 0.9729, 0.9716, 0.9704, 0.9690, 0.9674, 0.9656, 0.9641, 0.9625, 0.9609,
0.9587, 0.9567, 0.9548, 0.9524, 0.9501, 0.9478, 0.9453, 0.9426, 0.9398, 0.9371,
0.9339, 0.9311, 0.9277, 0.9242, 0.9206, 0.9168, 0.9131, 0.9087, 0.9043, 0.8999,
0.8953, 0.8907, 0.8857, 0.8803, 0.8747, 0.8690, 0.8632, 0.8572, 0.8507, 0.8439,
0.8368, 0.8295, 0.8217, 0.8138, 0.8058, 0.7972, 0.7883, 0.7784, 0.7694, 0.7597,
0.7489, 0.7378, 0.7269, 0.7152, 0.7030, 0.6911, 0.6782, 0.6643, 0.6506, 0.6371,
0.6211, 0.6054, 0.5897, 0.5740, 0.5565, 0.5393, 0.5214, 0.5027, 0.4838, 0.4643,
0.4436, 0.4225, 0.4004, 0.3787, 0.3562, 0.3324, 0.3089, 0.2839, 0.2584, 0.2321,
0.2047, 0.1784, 0.1499, 0.1213, 0.0915, 0.0628, 0.0314, 0.0000, -0.0321, -0.0657,
-0.0977, -0.1324, -0.1673, -0.2036, -0.2387, -0.2768, -0.3150, -0.3538, -0.3936, -0.4327,
-0.4739, -0.5148, -0.5561, -0.6000, -0.6438, -0.6889, -0.7331, -0.7781, -0.8247, -0.8712,
-0.9177, -0.9677, -1.0142, -1.0631, -1.1143, -1.1686, -1.2169, -1.2680, -1.3223, -1.3752,
-1.4261, -1.4806, -1.5356, -1.5890, -1.6462, -1.7041, -1.7591, -1.8124, -1.8735, -1.9311,
-1.9891, -2.0459, -2.1048, -2.1653, -2.2248, -2.2855, -2.3466, -2.4079, -2.4668, -2.5263,
-2.5876, -2.6507, -2.7142, -2.7761, -2.8366, -2.8995, -2.9620, -3.0279, -3.0973, -3.1576,
-3.2238, -3.2890, -3.3554, -3.4215, -3.4805, -3.5518, -3.6133, -3.6812, -3.7473, -3.8140,
-3.8781, -3.9450, -4.0184, -4.0794, -4.1478, -4.2241, -4.2853, -4.3473, -4.4062, -4.4839,
-4.5539, -4.6202, -4.6794, -4.7478, -4.8309, -4.9048, -4.9669, -5.0294, -5.1194, -5.1732,
-5.2378, -5.3094, -5.3742, -5.4573, -5.5190, -5.5728, -5.6637, -5.7259, -5.7843, -5.8854,
-5.9553, -6.0054, -6.0656, -6.1707, -6.2241, -6.3139, -6.3393, -6.4356, -6.5153, -6.5758,
-6.6506, -6.7193, -6.7542, -6.8942, -6.9219, -6.9605, -7.1013, -7.1895, -7.1549, -7.2799,
-7.4119, -7.4608, -7.5256, -7.5879, -7.7598, -8.4120,
0.9999, 0.9998, 0.9998, 0.9998, 0.9998, 0.9998, 0.9997, 0.9997, 0.9997, 0.9997,
0.9997, 0.9996, 0.9996, 0.9996, 0.9995, 0.9995, 0.9994, 0.9994, 0.9994, 0.9993,
0.9993, 0.9992, 0.9991, 0.9991, 0.9990, 0.9989, 0.9988, 0.9988, 0.9988, 0.9986,
0.9985, 0.9984, 0.9983, 0.9982, 0.9980, 0.9979, 0.9977, 0.9976, 0.9974, 0.9971,
0.9969, 0.9968, 0.9965, 0.9962, 0.9960, 0.9957, 0.9953, 0.9950, 0.9947, 0.9941,
0.9937, 0.9933, 0.9928, 0.9922, 0.9917, 0.9911, 0.9904, 0.9897, 0.9890, 0.9882,
0.9874, 0.9863, 0.9855, 0.9843, 0.9832, 0.9819, 0.9806, 0.9792, 0.9777, 0.9760,
0.9743, 0.9724, 0.9704, 0.9683, 0.9659, 0.9634, 0.9609, 0.9581, 0.9550, 0.9516,
0.9481, 0.9446, 0.9406, 0.9363, 0.9317, 0.9270, 0.9218, 0.9160, 0.9103, 0.9038,
0.8972, 0.8898, 0.8822, 0.8739, 0.8647, 0.8554, 0.8457, 0.8357, 0.8231, 0.8115,
0.7984, 0.7854, 0.7704, 0.7556, 0.7391, 0.7210, 0.7038, 0.6840, 0.6633, 0.6408,
0.6174, 0.5939, 0.5678, 0.5410, 0.5137, 0.4836, 0.4524, 0.4193, 0.3850, 0.3482,
0.3132, 0.2733, 0.2315, 0.1891, 0.1435, 0.0980, 0.0493, 0.0000, -0.0510, -0.1052,
-0.1593, -0.2177, -0.2759, -0.3374, -0.4005, -0.4599, -0.5266, -0.5935, -0.6626, -0.7328,
-0.8051, -0.8757, -0.9498, -1.0271, -1.1019, -1.1816, -1.2642, -1.3459, -1.4295, -1.5077,
-1.5958, -1.6818, -1.7647, -1.8548, -1.9387, -2.0295, -2.1152, -2.2154, -2.3011, -2.3904,
-2.4820, -2.5786, -2.6730, -2.7652, -2.8616, -2.9546, -3.0526, -3.1445, -3.2445, -3.3416,
-3.4357, -3.5325, -3.6324, -3.7313, -3.8225, -3.9209, -4.0248, -4.1278, -4.2261, -4.3193,
-4.4220, -4.5262, -4.6214, -4.7242, -4.8234, -4.9245, -5.0298, -5.1250, -5.2232, -5.3267,
-5.4332, -5.5342, -5.6431, -5.7270, -5.8401, -5.9350, -6.0407, -6.1418, -6.2363, -6.3384,
-6.4536, -6.5429, -6.6582, -6.7433, -6.8438, -6.9478, -7.0789, -7.1894, -7.2714, -7.3815,
-7.4810, -7.5575, -7.6852, -7.8071, -7.8580, -7.9724, -8.1000, -8.2207, -8.2867, -8.4017,
-8.5287, -8.6347, -8.7082, -8.8319, -8.9448, -9.0355, -9.1885, -9.2095, -9.2863, -9.4186,
-9.5064, -9.6386, -9.7207, -9.8286, -9.9453, -10.0701, -10.1735, -10.3001, -10.2858, -10.5427,
-10.5982, -10.7361, -10.7042, -10.9212, -11.0097, -11.0469, -11.1155, -11.2812, -11.3472, -11.4988,
-11.5327, -11.6692, -11.9376, -11.8606, -12.1372, -13.2539,
1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000,
1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000,
1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000,
0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999, 0.9999,
0.9999, 0.9998, 0.9998, 0.9998, 0.9998, 0.9997, 0.9997, 0.9997, 0.9997, 0.9996,
0.9996, 0.9995, 0.9995, 0.9994, 0.9994, 0.9993, 0.9992, 0.9991, 0.9991, 0.9989,
0.9988, 0.9986, 0.9985, 0.9983, 0.9981, 0.9980, 0.9977, 0.9974, 0.9971, 0.9968,
0.9965, 0.9962, 0.9956, 0.9950, 0.9948, 0.9941, 0.9933, 0.9926, 0.9919, 0.9910,
0.9899, 0.9889, 0.9877, 0.9863, 0.9845, 0.9829, 0.9811, 0.9791, 0.9769, 0.9741,
0.9716, 0.9684, 0.9645, 0.9611, 0.9563, 0.9519, 0.9463, 0.9406, 0.9344, 0.9272,
0.9197, 0.9107, 0.9016, 0.8903, 0.8791, 0.8653, 0.8523, 0.8357, 0.8179, 0.7988,
0.7779, 0.7562, 0.7318, 0.7024, 0.6753, 0.6435, 0.6089, 0.5700, 0.5296, 0.4860,
0.4366, 0.3855, 0.3301, 0.2735, 0.2114, 0.1443, 0.0682, 0.0000, -0.0715, -0.1604,
-0.2478, -0.3377, -0.4287, -0.5277, -0.6291, -0.7384, -0.8457, -0.9559, -1.0742, -1.1913,
-1.3110, -1.4238, -1.5594, -1.6854, -1.8093, -1.9414, -2.0763, -2.2160, -2.3611, -2.4876,
-2.6374, -2.7710, -2.9225, -3.0591, -3.2077, -3.3452, -3.4916, -3.6316, -3.7735, -3.9296,
-4.0682, -4.2334, -4.3607, -4.5270, -4.6807, -4.8108, -4.9753, -5.1212, -5.2631, -5.4042,
-5.5510, -5.7227, -5.8794, -6.0244, -6.1677, -6.3271, -6.4862, -6.6130, -6.7449, -6.9250,
-7.1232, -7.1736, -7.3628, -7.5596, -7.6906, -7.8129, -7.9817, -8.1440, -8.3016, -8.4797,
-8.5734, -8.7692, -8.9198, -9.0610, -9.1746, -9.3536, -9.5939, -9.6957, -9.8475, -9.9639,
-10.1730, -10.2427, -10.4573, -10.5413, -10.7303, -10.9339, -11.0215, -11.2047, -11.2894, -11.4572,
-11.6256, -11.7794, -11.8801, -12.1717, -12.2354, -12.3686, -12.6195, -12.6527, -12.8247, -12.9560,
-13.3265, -13.1667, -13.4274, -13.6064, -13.5515, -13.9501, -13.9926, -14.4049, -14.1653, -14.4348,
-14.7983, -14.7807, -15.2349, -15.3536, -15.3026, -15.2739, -15.7170, -16.2161, -15.9185, -15.9490,
-16.6258, -16.5568, -16.4318, -16.7999, -16.4101, -17.6393, -17.7643, -17.2644, -17.5973, -17.0403,
-17.7039, -18.0073, -18.1840, -18.3848, -18.6286, -20.7063};

76
lib/wsprd/mettab.c Normal file
View File

@ -0,0 +1,76 @@
/*
This file is part of wsprd.
File name: mettab.c
Description: Metric table for sequential Fano decoder.
Copyright 2008-2015, Joseph Taylor, K1JT
License: GNU GPL v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
int mettab[2][256]={
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
2, 2, 2, 2, 1, 1, 1, 1, 0, 0,
-1, -1, -1, -2, -2, -3, -4, -4, -5, -6,
-7, -7, -8, -9, -10, -11, -12, -12, -13, -14,
-15, -16, -17, -17, -18, -19, -20, -21, -22, -22,
-23, -24, -25, -26, -26, -27, -28, -29, -30, -30,
-31, -32, -33, -33, -34, -35, -36, -36, -37, -38,
-38, -39, -40, -41, -41, -42, -43, -43, -44, -45,
-45, -46, -47, -47, -48, -49, -49, -50, -51, -51,
-52, -53, -53, -54, -54, -55, -56, -56, -57, -57,
-58, -59, -59, -60, -60, -61, -62, -62, -62, -63,
-64, -64, -65, -65, -66, -67, -67, -67, -68, -69,
-69, -70, -70, -71, -72, -72, -72, -72, -73, -74,
-75, -75, -75, -77, -76, -76, -78, -78, -80, -81,
-80, -79, -83, -82, -81, -82, -82, -83, -84, -84,
-84, -87, -86, -87, -88,-105, -94,-105, -88, -87,
-86, -87, -84, -84, -84, -83, -82, -82, -81, -82,
-83, -79, -80, -81, -80, -78, -78, -76, -76, -77,
-75, -75, -75, -74, -73, -72, -72, -72, -72, -71,
-70, -70, -69, -69, -68, -67, -67, -67, -66, -65,
-65, -64, -64, -63, -62, -62, -62, -61, -60, -60,
-59, -59, -58, -57, -57, -56, -56, -55, -54, -54,
-53, -53, -52, -51, -51, -50, -49, -49, -48, -47,
-47, -46, -45, -45, -44, -43, -43, -42, -41, -41,
-40, -39, -38, -38, -37, -36, -36, -35, -34, -33,
-33, -32, -31, -30, -30, -29, -28, -27, -26, -26,
-25, -24, -23, -22, -22, -21, -20, -19, -18, -17,
-17, -16, -15, -14, -13, -12, -12, -11, -10, -9,
-8, -7, -7, -6, -5, -4, -4, -3, -2, -2,
-1, -1, -1, 0, 0, 1, 1, 1, 1, 2,
2, 2, 2, 2, 3, 3, 3, 3, 3, 3,
3, 3, 3, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
5, 5 };

376
lib/wsprd/nhash.c Normal file
View File

@ -0,0 +1,376 @@
/*
This file is part of wsprd.
File name: nhash.c
*------------------------------------------------------------------------------
*
* This file is part of the WSPR application, Weak Signal Propogation Reporter
*
* File Name: nhash.c
* Description: Functions to produce 32-bit hashes for hash table lookup
*
* Copyright (C) 2008-2014 Joseph Taylor, K1JT
* License: GNU GPL v3+
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
* Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Files: lookup3.c
* Copyright: Copyright (C) 2006 Bob Jenkins <bob_jenkins@burtleburtle.net>
* License: public-domain
* You may use this code any way you wish, private, educational, or commercial.
* It's free.
*
*-------------------------------------------------------------------------------
*/
/*
These are functions for producing 32-bit hashes for hash table lookup.
hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
are externally useful functions. Routines to test the hash are included
if SELF_TEST is defined. You can use this free for any purpose. It's in
the public domain. It has no warranty.
You probably want to use hashlittle(). hashlittle() and hashbig()
hash byte arrays. hashlittle() is is faster than hashbig() on
little-endian machines. Intel and AMD are little-endian machines.
On second thought, you probably want hashlittle2(), which is identical to
hashlittle() except it returns two 32-bit hashes for the price of one.
You could implement hashbig2() if you wanted but I haven't bothered here.
If you want to find a hash of, say, exactly 7 integers, do
a = i1; b = i2; c = i3;
mix(a,b,c);
a += i4; b += i5; c += i6;
mix(a,b,c);
a += i7;
final(a,b,c);
then use c as the hash value. If you have a variable length array of
4-byte integers to hash, use hashword(). If you have a byte array (like
a character string), use hashlittle(). If you have several byte arrays, or
a mix of things, see the comments above hashlittle().
Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
then mix those integers. This is fast (you can do a lot more thorough
mixing with 12*3 instructions on 3 integers than you can with 3 instructions
on 1 byte), but shoehorning those bytes into integers efficiently is messy.
*/
#define SELF_TEST 1
#include <stdio.h> /* defines printf for tests */
#include <time.h> /* defines time_t for timings in the test */
#ifdef Win32
#include "win_stdint.h" /* defines uint32_t etc */
#else
#include <stdint.h> /* defines uint32_t etc */
#endif
//#include <sys/param.h> /* attempt to define endianness */
//#ifdef linux
//# include <endian.h> /* attempt to define endianness */
//#endif
#define HASH_LITTLE_ENDIAN 1
#define hashsize(n) ((uint32_t)1<<(n))
#define hashmask(n) (hashsize(n)-1)
#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
/*
-------------------------------------------------------------------------------
mix -- mix 3 32-bit values reversibly.
This is reversible, so any information in (a,b,c) before mix() is
still in (a,b,c) after mix().
If four pairs of (a,b,c) inputs are run through mix(), or through
mix() in reverse, there are at least 32 bits of the output that
are sometimes the same for one pair and different for another pair.
This was tested for:
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
satisfy this are
4 6 8 16 19 4
9 15 3 18 27 15
14 9 3 7 17 3
Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
for "differ" defined as + with a one-bit base and a two-bit delta. I
used http://burtleburtle.net/bob/hash/avalanche.html to choose
the operations, constants, and arrangements of the variables.
This does not achieve avalanche. There are input bits of (a,b,c)
that fail to affect some output bits of (a,b,c), especially of a. The
most thoroughly mixed value is c, but it doesn't really even achieve
avalanche in c.
This allows some parallelism. Read-after-writes are good at doubling
the number of bits affected, so the goal of mixing pulls in the opposite
direction as the goal of parallelism. I did what I could. Rotates
seem to cost as much as shifts on every machine I could lay my hands
on, and rotates are much kinder to the top and bottom bits, so I used
rotates.
-------------------------------------------------------------------------------
*/
#define mix(a,b,c) \
{ \
a -= c; a ^= rot(c, 4); c += b; \
b -= a; b ^= rot(a, 6); a += c; \
c -= b; c ^= rot(b, 8); b += a; \
a -= c; a ^= rot(c,16); c += b; \
b -= a; b ^= rot(a,19); a += c; \
c -= b; c ^= rot(b, 4); b += a; \
}
/*
-------------------------------------------------------------------------------
final -- final mixing of 3 32-bit values (a,b,c) into c
Pairs of (a,b,c) values differing in only a few bits will usually
produce values of c that look totally different. This was tested for
* pairs that differed by one bit, by two bits, in any combination
of top bits of (a,b,c), or in any combination of bottom bits of
(a,b,c).
* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
is commonly produced by subtraction) look like a single 1-bit
difference.
* the base values were pseudorandom, all zero but one bit set, or
all zero plus a counter that starts at zero.
These constants passed:
14 11 25 16 4 14 24
12 14 25 16 4 14 24
and these came close:
4 8 15 26 3 22 24
10 8 15 26 3 22 24
11 8 15 26 3 22 24
-------------------------------------------------------------------------------
*/
#define final(a,b,c) \
{ \
c ^= b; c -= rot(b,14); \
a ^= c; a -= rot(c,11); \
b ^= a; b -= rot(a,25); \
c ^= b; c -= rot(b,16); \
a ^= c; a -= rot(c,4); \
b ^= a; b -= rot(a,14); \
c ^= b; c -= rot(b,24); \
}
/*
-------------------------------------------------------------------------------
hashlittle() -- hash a variable-length key into a 32-bit value
k : the key (the unaligned variable-length array of bytes)
length : the length of the key, counting by bytes
initval : can be any 4-byte value
Returns a 32-bit value. Every bit of the key affects every bit of
the return value. Two keys differing by one or two bits will have
totally different hash values.
The best hash table sizes are powers of 2. There is no need to do
mod a prime (mod is sooo slow!). If you need less than 32 bits,
use a bitmask. For example, if you need only 10 bits, do
h = (h & hashmask(10));
In which case, the hash table should have hashsize(10) elements.
If you are hashing n strings (uint8_t **)k, do it like this:
for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
code any way you wish, private, educational, or commercial. It's free.
Use for hash table lookup, or anything where one collision in 2^^32 is
acceptable. Do NOT use for cryptographic purposes.
-------------------------------------------------------------------------------
*/
uint32_t nhash_( const void *key, size_t length, uint32_t initval)
{
uint32_t a,b,c; /* internal state */
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
/* Set up the internal state */
a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
u.ptr = key;
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
b += k[1];
c += k[2];
mix(a,b,c);
length -= 12;
k += 3;
}
/*----------------------------- handle the last (probably partial) block */
/*
* "k[2]&0xffffff" actually reads beyond the end of the string, but
* then masks off the part it's not allowed to read. Because the
* string is aligned, the masked-off tail is in the same word as the
* rest of the string. Every machine with memory protection I've seen
* does it on word boundaries, so is OK with this. But VALGRIND will
* still catch it and complain. The masking trick does make the hash
* noticably faster for short strings (like English words).
*/
#ifndef VALGRIND
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
case 5 : b+=k[1]&0xff; a+=k[0]; break;
case 4 : a+=k[0]; break;
case 3 : a+=k[0]&0xffffff; break;
case 2 : a+=k[0]&0xffff; break;
case 1 : a+=k[0]&0xff; break;
case 0 : return c; /* zero length strings require no mixing */
}
#else /* make valgrind happy */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]; break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
case 1 : a+=k8[0]; break;
case 0 : return c;
}
#endif /* !valgrind */
} else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
const uint8_t *k8;
/*--------------- all but last block: aligned reads and different mixing */
while (length > 12)
{
a += k[0] + (((uint32_t)k[1])<<16);
b += k[2] + (((uint32_t)k[3])<<16);
c += k[4] + (((uint32_t)k[5])<<16);
mix(a,b,c);
length -= 12;
k += 6;
}
/*----------------------------- handle the last (probably partial) block */
k8 = (const uint8_t *)k;
switch(length)
{
case 12: c+=k[4]+(((uint32_t)k[5])<<16);
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
case 10: c+=k[4];
b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 9 : c+=k8[8]; /* fall through */
case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
case 6 : b+=k[2];
a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 5 : b+=k8[4]; /* fall through */
case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
break;
case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
case 2 : a+=k[0];
break;
case 1 : a+=k8[0];
break;
case 0 : return c; /* zero length requires no mixing */
}
} else { /* need to read the key one byte at a time */
const uint8_t *k = (const uint8_t *)key;
/*--------------- all but the last block: affect some 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
a += ((uint32_t)k[1])<<8;
a += ((uint32_t)k[2])<<16;
a += ((uint32_t)k[3])<<24;
b += k[4];
b += ((uint32_t)k[5])<<8;
b += ((uint32_t)k[6])<<16;
b += ((uint32_t)k[7])<<24;
c += k[8];
c += ((uint32_t)k[9])<<8;
c += ((uint32_t)k[10])<<16;
c += ((uint32_t)k[11])<<24;
mix(a,b,c);
length -= 12;
k += 12;
}
/*-------------------------------- last block: affect all 32 bits of (c) */
switch(length) /* all the case statements fall through */
{
case 12: c+=((uint32_t)k[11])<<24;
case 11: c+=((uint32_t)k[10])<<16;
case 10: c+=((uint32_t)k[9])<<8;
case 9 : c+=k[8];
case 8 : b+=((uint32_t)k[7])<<24;
case 7 : b+=((uint32_t)k[6])<<16;
case 6 : b+=((uint32_t)k[5])<<8;
case 5 : b+=k[4];
case 4 : a+=((uint32_t)k[3])<<24;
case 3 : a+=((uint32_t)k[2])<<16;
case 2 : a+=((uint32_t)k[1])<<8;
case 1 : a+=k[0];
break;
case 0 : return c;
}
}
final(a,b,c);
c=(32767&c);
return c;
}

63
lib/wsprd/t1.f90 Normal file
View File

@ -0,0 +1,63 @@
program t1
integer mettab(0:255,0:1)
data mettab/ &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 4, &
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, &
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, &
3, 3, 3, 3, 3, 3, 3, 3, 3, 2, &
2, 2, 2, 2, 1, 1, 1, 1, 0, 0, &
-1, -1, -1, -2, -2, -3, -4, -4, -5, -6, &
-7, -7, -8, -9, -10, -11, -12, -12, -13, -14, &
-15, -16, -17, -17, -18, -19, -20, -21, -22, -22, &
-23, -24, -25, -26, -26, -27, -28, -29, -30, -30, &
-31, -32, -33, -33, -34, -35, -36, -36, -37, -38, &
-38, -39, -40, -41, -41, -42, -43, -43, -44, -45, &
-45, -46, -47, -47, -48, -49, -49, -50, -51, -51, &
-52, -53, -53, -54, -54, -55, -56, -56, -57, -57, &
-58, -59, -59, -60, -60, -61, -62, -62, -62, -63, &
-64, -64, -65, -65, -66, -67, -67, -67, -68, -69, &
-69, -70, -70, -71, -72, -72, -72, -72, -73, -74, &
-75, -75, -75, -77, -76, -76, -78, -78, -80, -81, &
-80, -79, -83, -82, -81, -82, -82, -83, -84, -84, &
-84, -87, -86, -87, -88, -89, -89, -89, -88, -87, &
-86, -87, -84, -84, -84, -83, -82, -82, -81, -82, &
-83, -79, -80, -81, -80, -78, -78, -76, -76, -77, &
-75, -75, -75, -74, -73, -72, -72, -72, -72, -71, &
-70, -70, -69, -69, -68, -67, -67, -67, -66, -65, &
-65, -64, -64, -63, -62, -62, -62, -61, -60, -60, &
-59, -59, -58, -57, -57, -56, -56, -55, -54, -54, &
-53, -53, -52, -51, -51, -50, -49, -49, -48, -47, &
-47, -46, -45, -45, -44, -43, -43, -42, -41, -41, &
-40, -39, -38, -38, -37, -36, -36, -35, -34, -33, &
-33, -32, -31, -30, -30, -29, -28, -27, -26, -26, &
-25, -24, -23, -22, -22, -21, -20, -19, -18, -17, &
-17, -16, -15, -14, -13, -12, -12, -11, -10, -9, &
-8, -7, -7, -6, -5, -4, -4, -3, -2, -2, &
-1, -1, -1, 0, 0, 1, 1, 1, 1, 2, &
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, &
3, 3, 3, 4, 4, 4, 4, 4, 4, 4, &
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, &
4, 4, 4, 4, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, &
5, 5/
do i=0,255
write(*,1010) i,mettab(i,0),mettab(i,1)
1010 format(3i6)
enddo
end program t1

11
lib/wsprd/t2.f90 Normal file
View File

@ -0,0 +1,11 @@
program t2
df=375.0/65536.0
do i=1,65536
w=1.0/(1.0 + ((i-32768)/26214.0)**20)
f=(i-32768)*df
write(13,1010) f,w
1010 format(2f15.6)
enddo
end program t2

41
lib/wsprd/tab.c Normal file
View File

@ -0,0 +1,41 @@
/*
This file is part of wsprd.
File name: tab.c
Description: 8-bit parity lookup table.
*/
unsigned char Partab[] = {
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 1, 0, 1, 0, 0, 1,
1, 0, 0, 1, 0, 1, 1, 0,
};

61
lib/wsprd/test_wspr.f90 Normal file
View File

@ -0,0 +1,61 @@
program test_wspr
! This program provides examples of the source encoding, convolutional
! error-control coding, bit and symbol ordering, and synchronizing
! information contained in WSPR messages.
character*22 msg,msg2
character*23 msg3
character*1 err2,err3
integer*1 data0(11)
logical lfile
! Get command-line argument(s)
nargs=iargc()
if(nargs.ne.1) then
print*,'Usage: test_wspr "message"'
go to 999
endif
call getarg(1,msg) !Get message from command line
call unpk(data0,1,msg3) !Read the C hashtable
lfile=msg(1:2).eq."-t"
if(lfile) open(10,file="messages.txt",status="old")
do imsg=1,999
if(lfile) read(10,1001,end=900) msg
1001 format(a22)
data0=0
call wqencode(msg,ntype0,data0) !Source encoding
! write(*,1002) data0(1:7)
!1002 format('Source-encoded message (50 bits, hex):',7z3.2)
! data0(8:11)=0
call wqdecode(data0,msg2,ntype1)
! write(*,1020) ntype1
!1020 format('Message type: ',i7)
! write(*,1030) msg2
!1030 format('Decoded message: ',a22)
call unpk(data0,0,msg3)
do i=1,23
if(ichar(msg3(i:i)).eq.0) then
msg3(i:)=" "
exit
endif
enddo
err2=' '
err3=' '
if(msg2.ne.msg) err2='*'
if(msg3.ne.msg) err3='*'
write(*,1040) msg,err2,msg2,err3,msg3
1040 format(a22,1x,a1,1x,a22,1x,a1,1x,a22)
if(.not.lfile) exit
enddo
900 call unpk(data0,2,msg3)
999 end program test_wspr

123
lib/wsprd/unpk.c Normal file
View File

@ -0,0 +1,123 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include "wsprd_utils.h"
unsigned int nhash_( const void *key, size_t length, uint32_t initval);
void unpk_(signed char message[], int *nhashtab, char call_loc_pow[])
{
int i,n1,n2,n3,ndbm,ihash,nadd,noprint,nh;
char callsign[13],grid[5],grid6[7],cdbm[3];
static char hashtab[32768][13];
FILE *fhash;
if(*nhashtab==1) {
char line[80], hcall[12];
if( (fhash=fopen("hashtable.txt","r+")) ) {
while (fgets(line, sizeof(line), fhash) != NULL) {
sscanf(line,"%d %s",&nh,hcall);
strcpy(*hashtab+nh*13,hcall);
}
} else {
fhash=fopen("hashtable.txt","w+");
}
fclose(fhash);
return;
}
if(*nhashtab==2) {
fhash=fopen("hashtable.txt","w");
for (i=0; i<32768; i++) {
if( strncmp(hashtab[i],"\0",1) != 0 ) {
fprintf(fhash,"%5d %s\n",i,*hashtab+i*13);
}
}
fclose(fhash);
return;
}
unpack50(message,&n1,&n2);
unpackcall(n1,callsign);
unpackgrid(n2, grid);
int ntype = (n2&127) - 64;
callsign[12]=0;
grid[4]=0;
/*
Based on the value of ntype, decide whether this is a Type 1, 2, or
3 message.
* Type 1: 6 digit call, grid, power - ntype is positive and is a member
of the set {0,3,7,10,13,17,20...60}
* Type 2: extended callsign, power - ntype is positive but not
a member of the set of allowed powers
* Type 3: hash, 6 digit grid, power - ntype is negative.
*/
if( (ntype >= 0) && (ntype <= 62) ) {
int nu=ntype%10;
if( nu == 0 || nu == 3 || nu == 7 ) {
ndbm=ntype;
memset(call_loc_pow,0,sizeof(char)*23);
sprintf(cdbm,"%2d",ndbm);
strncat(call_loc_pow,callsign,strlen(callsign));
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,grid,4);
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,cdbm,2);
strncat(call_loc_pow,"\0",1);
ihash=nhash_(callsign,strlen(callsign),(uint32_t)146);
strcpy(*hashtab+ihash*13,callsign);
} else {
nadd=nu;
if( nu > 3 ) nadd=nu-3;
if( nu > 7 ) nadd=nu-7;
n3=n2/128+32768*(nadd-1);
unpackpfx(n3,callsign);
ndbm=ntype-nadd;
memset(call_loc_pow,0,sizeof(char)*23);
sprintf(cdbm,"%2d",ndbm);
strncat(call_loc_pow,callsign,strlen(callsign));
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,cdbm,2);
strncat(call_loc_pow,"\0",1);
ihash=nhash_(callsign,strlen(callsign),(uint32_t)146);
strcpy(*hashtab+ihash*13,callsign);
noprint=0;
}
} else if ( ntype < 0 ) {
ndbm=-(ntype+1);
memset(grid6,0,sizeof(char)*7);
strncat(grid6,callsign+5,1);
strncat(grid6,callsign,5);
ihash=(n2-ntype-64)/128;
if( strncmp(hashtab[ihash],"\0",1) != 0 ) {
sprintf(callsign,"<%s>",hashtab[ihash]);
} else {
sprintf(callsign,"%5s","<...>");
}
memset(call_loc_pow,0,sizeof(char)*23);
sprintf(cdbm,"%2d",ndbm);
strncat(call_loc_pow,callsign,strlen(callsign));
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,grid6,strlen(grid6));
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,cdbm,2);
strncat(call_loc_pow,"\0",1);
noprint=0;
// I don't know what to do with these... They show up as "A000AA" grids.
if( ntype == -64 ) noprint=1;
}
// printf("\nUnpacked in C: %s\n",call_loc_pow);
}

935
lib/wsprd/wsprd.c Normal file
View File

@ -0,0 +1,935 @@
/*
This file is part of program wsprd, a detector/demodulator/decoder
for the Weak Signal Propagation Reporter (WSPR) mode.
File name: wsprd.c
Copyright 2001-2015, Joe Taylor, K1JT
Much of the present code is based on work by Steven Franke, K9AN,
which in turn was based on earlier work by K1JT.
Copyright 2014-2015, Steven Franke, K9AN
License: GNU GPL v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <fftw3.h>
#include "fano.h"
#include "wsprd_utils.h"
#define max(x,y) ((x) > (y) ? (x) : (y))
// Possible PATIENCE options: FFTW_ESTIMATE, FFTW_ESTIMATE_PATIENT,
// FFTW_MEASURE, FFTW_PATIENT, FFTW_EXHAUSTIVE
#define PATIENCE FFTW_ESTIMATE
fftw_plan PLAN1,PLAN2,PLAN3;
unsigned char pr3[162]=
{1,1,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,
0,1,0,1,1,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,
0,0,0,0,0,0,1,0,1,1,0,0,1,1,0,1,0,0,0,1,
1,0,1,0,0,0,0,1,1,0,1,0,1,0,1,0,1,0,0,1,
0,0,1,0,1,1,0,0,0,1,1,0,1,0,1,0,0,0,1,0,
0,0,0,0,1,0,0,1,0,0,1,1,1,0,1,1,0,0,1,1,
0,1,0,0,0,1,1,1,0,0,0,0,0,1,0,1,0,0,1,1,
0,0,0,0,0,0,0,1,1,0,1,0,1,1,0,0,0,1,1,0,
0,0};
unsigned long nr;
//***************************************************************************
unsigned long readc2file(char *ptr_to_infile, double *idat, double *qdat,
double *freq, int *wspr_type)
{
float buffer[2*65536];
double dfreq;
int i,ntrmin;
char *c2file[15];
FILE* fp;
fp = fopen(ptr_to_infile,"rb");
if (fp == NULL) {
fprintf(stderr, "Cannot open data file '%s'\n", ptr_to_infile);
return 1;
}
unsigned long nread=fread(c2file,sizeof(char),14,fp);
nread=fread(&ntrmin,sizeof(int),1,fp);
nread=fread(&dfreq,sizeof(double),1,fp);
*freq=dfreq;
nread=fread(buffer,sizeof(float),2*45000,fp);
*wspr_type=ntrmin;
for(i=0; i<45000; i++) {
idat[i]=buffer[2*i];
qdat[i]=-buffer[2*i+1];
}
if( nread == 2*45000 ) {
return nread/2;
} else {
return 1;
}
}
//***************************************************************************
unsigned long readwavfile(char *ptr_to_infile, int ntrmin, double *idat, double *qdat )
{
unsigned long i, j, npoints;
int nfft1, nfft2, nh2, i0;
double df;
nfft2=46080; //this is the number of downsampled points that will be returned
nh2=nfft2/2;
if( ntrmin == 2 ) {
nfft1=nfft2*32; //need to downsample by a factor of 32
df=12000.0/nfft1;
i0=1500.0/df+0.5;
npoints=114*12000;
} else if ( ntrmin == 15 ) {
nfft1=nfft2*8*32;
df=12000.0/nfft1;
i0=(1500.0+112.5)/df+0.5;
npoints=8*114*12000;
} else {
fprintf(stderr,"This should not happen\n");
return 1;
}
double *realin;
fftw_complex *fftin, *fftout;
FILE *fp;
short int *buf2;
buf2 = malloc(npoints*sizeof(short int));
fp = fopen(ptr_to_infile,"rb");
if (fp == NULL) {
fprintf(stderr, "Cannot open data file '%s'\n", ptr_to_infile);
return 1;
}
nr=fread(buf2,2,22,fp); //Read and ignore header
nr=fread(buf2,2,npoints,fp); //Read raw data
fclose(fp);
realin=(double*) fftw_malloc(sizeof(double)*nfft1);
fftout=(fftw_complex*) fftw_malloc(sizeof(fftw_complex)*nfft1);
PLAN1 = fftw_plan_dft_r2c_1d(nfft1, realin, fftout, PATIENCE);
for (i=0; i<npoints; i++) {
realin[i]=buf2[i]/32768.0;
}
for (i=npoints; i<nfft1; i++) {
realin[i]=0.0;
}
free(buf2);
fftw_execute(PLAN1);
fftw_free(realin);
fftin=(fftw_complex*) fftw_malloc(sizeof(fftw_complex)*nfft2);
for (i=0; i<nfft2; i++) {
j=i0+i;
if( i>nh2 ) j=j-nfft2;
fftin[i][0]=fftout[j][0];
fftin[i][1]=fftout[j][1];
}
fftw_free(fftout);
fftout=(fftw_complex*) fftw_malloc(sizeof(fftw_complex)*nfft2);
PLAN2 = fftw_plan_dft_1d(nfft2, fftin, fftout, FFTW_BACKWARD, PATIENCE);
fftw_execute(PLAN2);
for (i=0; i<nfft2; i++) {
idat[i]=fftout[i][0]/1000.0;
qdat[i]=fftout[i][1]/1000.0;
}
fftw_free(fftin);
fftw_free(fftout);
return nfft2;
}
//***************************************************************************
void sync_and_demodulate(double *id, double *qd, long np,
unsigned char *symbols, float *f1, float fstep,
int *shift1, int lagmin, int lagmax, int lagstep,
float *drift1, int symfac, float *sync, int mode)
{
/***********************************************************************
* mode = 0: no frequency or drift search. find best time lag. *
* 1: no time lag or drift search. find best frequency. *
* 2: no frequency or time lag search. calculate soft-decision *
* symbols using passed frequency and shift. *
************************************************************************/
float dt=1.0/375.0, df=375.0/256.0, fbest=0.0;
int i, j, k;
double pi=4.*atan(1.0),twopidt;
float f0=0.0,fp,fplast=-10000.0,ss;
int lag;
double i0[162],q0[162],i1[162],q1[162],i2[162],q2[162],i3[162],q3[162];
double p0,p1,p2,p3,cmet,totp,syncmax,fac;
double c0[256],s0[256],c1[256],s1[256],c2[256],s2[256],c3[256],s3[256];
double dphi0, cdphi0, sdphi0, dphi1, cdphi1, sdphi1, dphi2, cdphi2, sdphi2,
dphi3, cdphi3, sdphi3;
float fsum=0.0, f2sum=0.0, fsymb[162];
int best_shift = 0, ifreq;
int ifmin=0, ifmax=0;
syncmax=-1e30;
if( mode == 0 ) {ifmin=0; ifmax=0; fstep=0.0; f0=*f1;}
if( mode == 1 ) {lagmin=*shift1;lagmax=*shift1;ifmin=-5;ifmax=5;f0=*f1;}
if( mode == 2 ) {lagmin=*shift1;lagmax=*shift1;ifmin=0;ifmax=0;f0=*f1;}
twopidt=2*pi*dt;
for(ifreq=ifmin; ifreq<=ifmax; ifreq++) {
f0=*f1+ifreq*fstep;
for(lag=lagmin; lag<=lagmax; lag=lag+lagstep) {
ss=0.0;
totp=0.0;
for (i=0; i<162; i++) {
fp = f0 + ((float)*drift1/2.0)*((float)i-81.0)/81.0;
if( i==0 || (fp != fplast) ) { // only calculate sin/cos if necessary
dphi0=2*pi*(fp-1.5*df)*dt;
cdphi0=cos(dphi0);
sdphi0=sin(dphi0);
dphi1=twopidt*(fp-0.5*df);
cdphi1=cos(dphi1);
sdphi1=sin(dphi1);
dphi2=twopidt*(fp+0.5*df);
cdphi2=cos(dphi2);
sdphi2=sin(dphi2);
dphi3=twopidt*(fp+1.5*df);
cdphi3=cos(dphi3);
sdphi3=sin(dphi3);
c0[0]=1; s0[0]=0;
c1[0]=1; s1[0]=0;
c2[0]=1; s2[0]=0;
c3[0]=1; s3[0]=0;
for (j=1; j<256; j++) {
c0[j]=c0[j-1]*cdphi0 - s0[j-1]*sdphi0;
s0[j]=c0[j-1]*sdphi0 + s0[j-1]*cdphi0;
c1[j]=c1[j-1]*cdphi1 - s1[j-1]*sdphi1;
s1[j]=c1[j-1]*sdphi1 + s1[j-1]*cdphi1;
c2[j]=c2[j-1]*cdphi2 - s2[j-1]*sdphi2;
s2[j]=c2[j-1]*sdphi2 + s2[j-1]*cdphi2;
c3[j]=c3[j-1]*cdphi3 - s3[j-1]*sdphi3;
s3[j]=c3[j-1]*sdphi3 + s3[j-1]*cdphi3;
}
fplast = fp;
}
i0[i]=0.0; q0[i]=0.0;
i1[i]=0.0; q1[i]=0.0;
i2[i]=0.0; q2[i]=0.0;
i3[i]=0.0; q3[i]=0.0;
for (j=0; j<256; j++) {
k=lag+i*256+j;
if( (k>0) & (k<np) ) {
i0[i]=i0[i] + id[k]*c0[j] + qd[k]*s0[j];
q0[i]=q0[i] - id[k]*s0[j] + qd[k]*c0[j];
i1[i]=i1[i] + id[k]*c1[j] + qd[k]*s1[j];
q1[i]=q1[i] - id[k]*s1[j] + qd[k]*c1[j];
i2[i]=i2[i] + id[k]*c2[j] + qd[k]*s2[j];
q2[i]=q2[i] - id[k]*s2[j] + qd[k]*c2[j];
i3[i]=i3[i] + id[k]*c3[j] + qd[k]*s3[j];
q3[i]=q3[i] - id[k]*s3[j] + qd[k]*c3[j];
}
}
p0=i0[i]*i0[i] + q0[i]*q0[i];
p1=i1[i]*i1[i] + q1[i]*q1[i];
p2=i2[i]*i2[i] + q2[i]*q2[i];
p3=i3[i]*i3[i] + q3[i]*q3[i];
p0=sqrt(p0);
p1=sqrt(p1);
p2=sqrt(p2);
p3=sqrt(p3);
totp=totp+p0+p1+p2+p3;
cmet=(p1+p3)-(p0+p2);
ss=ss+cmet*(2*pr3[i]-1);
if( mode == 2) { //Compute soft symbols
if(pr3[i]) {
fsymb[i]=p3-p1;
} else {
fsymb[i]=p2-p0;
}
}
}
if( ss/totp > syncmax ) { //Save best parameters
syncmax=ss/totp;
best_shift=lag;
fbest=f0;
}
} // lag loop
} //freq loop
if( mode <=1 ) { //Send best params back to caller
*sync=syncmax;
*shift1=best_shift;
*f1=fbest;
return;
}
if( mode == 2 ) {
*sync=syncmax;
for (i=0; i<162; i++) { //Normalize the soft symbols
fsum=fsum+fsymb[i]/162.0;
f2sum=f2sum+fsymb[i]*fsymb[i]/162.0;
}
fac=sqrt(f2sum-fsum*fsum);
for (i=0; i<162; i++) {
fsymb[i]=symfac*fsymb[i]/fac;
if( fsymb[i] > 127) fsymb[i]=127.0;
if( fsymb[i] < -128 ) fsymb[i]=-128.0;
symbols[i]=fsymb[i] + 128;
}
return;
}
return;
}
//***************************************************************************
void usage(void)
{
printf("Usage: wsprd [options...] infile\n");
printf(" infile must have suffix .wav or .c2\n");
printf("\n");
printf("Options:\n");
printf(" -a <path> path to writeable data files, default=\".\"\n");
printf(" -e x (x is transceiver dial frequency error in Hz)\n");
printf(" -f x (x is transceiver dial frequency in MHz)\n");
// blanking is not yet implemented. The options are accepted for compatibility
// with development version of wsprd.
// printf(" -t n (n is blanking duration in milliseconds)\n");
// printf(" -b n (n is pct of time that is blanked)\n");
printf(" -H do not use (or update) the hash table\n");
printf(" -m decode wspr-15 .wav file\n");
printf(" -n write noise estimates to file noise.dat\n");
printf(" -q quick mode - doesn't dig deep for weak signals\n");
printf(" -s slow mode - much slower, yields a few more decodes\n");
printf(" -v verbose mode\n");
printf(" -w wideband mode - decode signals within +/- 150 Hz of center\n");
printf(" -z x (x is fano metric table bias, default is 0.42)\n");
}
//***************************************************************************
int main(int argc, char *argv[])
{
extern char *optarg;
extern int optind;
int i,j,k;
unsigned char *symbols, *decdata;
signed char message[]={-9,13,-35,123,57,-39,64,0,0,0,0};
char *callsign,*grid,*grid6, *call_loc_pow, *cdbm;
char *ptr_to_infile,*ptr_to_infile_suffix;
char *data_dir=NULL;
char wisdom_fname[200],all_fname[200],spots_fname[200];
char timer_fname[200],hash_fname[200];
char uttime[5],date[7];
int c,delta,maxpts=65536,verbose=0,quickmode=0,writenoise=0,usehashtable=1,wspr_type=2;
int shift1, lagmin, lagmax, lagstep, worth_a_try, not_decoded;
unsigned int nbits;
unsigned int npoints, metric, maxcycles, cycles, maxnp;
float df=375.0/256.0/2;
float freq0[200],snr0[200],drift0[200],sync0[200];
int shift0[200];
float dt=1.0/375.0, dt_print;
double dialfreq_cmdline=0.0, dialfreq, freq_print;
float dialfreq_error=0.0;
float fmin=-110, fmax=110;
float f1, fstep, sync1, drift1, tblank=0, fblank=0;
double *idat, *qdat;
clock_t t0,t00;
double tfano=0.0,treadwav=0.0,tcandidates=0.0,tsync0=0.0;
double tsync1=0.0,tsync2=0.0,ttotal=0.0;
// Parameters used for performance-tuning:
maxcycles=10000; //Fano timeout limit
double minsync1=0.10; //First sync limit
double minsync2=0.12; //Second sync limit
int iifac=3; //Step size in final DT peakup
int symfac=50; //Soft-symbol normalizing factor
int maxdrift=4; //Maximum (+/-) drift
double minrms=52.0 * (symfac/64.0); //Final test for plausible decoding
delta=60; //Fano threshold step
t00=clock();
fftw_complex *fftin, *fftout;
#include "./metric_tables.c"
int mettab[2][256];
float bias=0.42;
idat=malloc(sizeof(double)*maxpts);
qdat=malloc(sizeof(double)*maxpts);
while ( (c = getopt(argc, argv, "a:b:e:f:Hmnqst:wvz:")) !=-1 ) {
switch (c) {
case 'a':
data_dir = optarg;
break;
case 'b':
fblank = strtof(optarg,NULL);
break;
case 'e':
dialfreq_error = strtof(optarg,NULL); // units of Hz
// dialfreq_error = dial reading - actual, correct frequency
break;
case 'f':
dialfreq_cmdline = strtod(optarg,NULL); // units of MHz
break;
case 'H':
usehashtable = 0;
break;
case 'm':
wspr_type = 15;
break;
case 'n':
writenoise = 1;
break;
case 'q':
quickmode = 1;
break;
case 's':
maxcycles=20000;
iifac=1;
break;
case 't':
tblank = strtof(optarg,NULL);
break;
case 'v':
verbose = 1;
break;
case 'w':
fmin=-150.0;
fmax=150.0;
break;
case 'z':
bias=strtof(optarg,NULL); //fano metric bias (default is 0.42)
break;
case '?':
usage();
return 1;
}
}
if( optind+1 > argc) {
usage();
return 1;
} else {
ptr_to_infile=argv[optind];
}
// setup metric table
for(i=0; i<256; i++) {
mettab[0][i]=round( 10*(metric_tables[2][i]-bias) );
mettab[1][i]=round( 10*(metric_tables[2][255-i]-bias) );
}
FILE *fp_fftw_wisdom_file, *fall_wspr, *fwsprd, *fhash, *ftimer;
strcpy(wisdom_fname,".");
strcpy(all_fname,".");
strcpy(spots_fname,".");
strcpy(timer_fname,".");
strcpy(hash_fname,".");
if(data_dir != NULL) {
strcpy(wisdom_fname,data_dir);
strcpy(all_fname,data_dir);
strcpy(spots_fname,data_dir);
strcpy(timer_fname,data_dir);
strcpy(hash_fname,data_dir);
}
strncat(wisdom_fname,"/wspr_wisdom.dat",20);
strncat(all_fname,"/ALL_WSPR.TXT",20);
strncat(spots_fname,"/wspr_spots.txt",20);
strncat(timer_fname,"/wspr_timer.out",20);
strncat(hash_fname,"/hashtable.txt",20);
if ((fp_fftw_wisdom_file = fopen(wisdom_fname, "r"))) { //Open FFTW wisdom
fftw_import_wisdom_from_file(fp_fftw_wisdom_file);
fclose(fp_fftw_wisdom_file);
}
fall_wspr=fopen(all_fname,"a");
fwsprd=fopen(spots_fname,"w");
// FILE *fdiag;
// fdiag=fopen("wsprd_diag","a");
if((ftimer=fopen(timer_fname,"r"))) {
//Accumulate timing data
nr=fscanf(ftimer,"%lf %lf %lf %lf %lf %lf %lf",
&treadwav,&tcandidates,&tsync0,&tsync1,&tsync2,&tfano,&ttotal);
fclose(ftimer);
}
ftimer=fopen(timer_fname,"w");
if( strstr(ptr_to_infile,".wav") ) {
ptr_to_infile_suffix=strstr(ptr_to_infile,".wav");
t0 = clock();
npoints=readwavfile(ptr_to_infile, wspr_type, idat, qdat);
treadwav += (double)(clock()-t0)/CLOCKS_PER_SEC;
if( npoints == 1 ) {
return 1;
}
dialfreq=dialfreq_cmdline - (dialfreq_error*1.0e-06);
} else if ( strstr(ptr_to_infile,".c2") !=0 ) {
ptr_to_infile_suffix=strstr(ptr_to_infile,".c2");
npoints=readc2file(ptr_to_infile, idat, qdat, &dialfreq, &wspr_type);
if( npoints == 1 ) {
return 1;
}
dialfreq -= (dialfreq_error*1.0e-06);
} else {
printf("Error: Failed to open %s\n",ptr_to_infile);
printf("WSPR file must have suffix .wav or .c2\n");
return 1;
}
// Parse date and time from given filename
strncpy(date,ptr_to_infile_suffix-11,6);
strncpy(uttime,ptr_to_infile_suffix-4,4);
date[6]='\0';
uttime[4]='\0';
// Do windowed ffts over 2 symbols, stepped by half symbols
int nffts=4*floor(npoints/512)-1;
fftin=(fftw_complex*) fftw_malloc(sizeof(fftw_complex)*512);
fftout=(fftw_complex*) fftw_malloc(sizeof(fftw_complex)*512);
PLAN3 = fftw_plan_dft_1d(512, fftin, fftout, FFTW_FORWARD, PATIENCE);
float ps[512][nffts];
float w[512];
for(i=0; i<512; i++) {
w[i]=sin(0.006147931*i);
}
memset(ps,0.0, sizeof(float)*512*nffts);
for (i=0; i<nffts; i++) {
for(j=0; j<512; j++ ) {
k=i*128+j;
fftin[j][0]=idat[k] * w[j];
fftin[j][1]=qdat[k] * w[j];
}
fftw_execute(PLAN3);
for (j=0; j<512; j++ ) {
k=j+256;
if( k>511 )
k=k-512;
ps[j][i]=fftout[k][0]*fftout[k][0]+fftout[k][1]*fftout[k][1];
}
}
fftw_free(fftin);
fftw_free(fftout);
// Compute average spectrum
float psavg[512];
memset(psavg,0.0, sizeof(float)*512);
for (i=0; i<nffts; i++) {
for (j=0; j<512; j++) {
psavg[j]=psavg[j]+ps[j][i];
}
}
// Smooth with 7-point window and limit spectrum to +/-150 Hz
int window[7]={1,1,1,1,1,1,1};
float smspec[411];
for (i=0; i<411; i++) {
smspec[i]=0.0;
for(j=-3; j<=3; j++) {
k=256-205+i+j;
smspec[i]=smspec[i]+window[j+3]*psavg[k];
}
}
// Sort spectrum values, then pick off noise level as a percentile
float tmpsort[411];
for (j=0; j<411; j++) {
tmpsort[j]=smspec[j];
}
qsort(tmpsort, 411, sizeof(float), floatcomp);
// Noise level of spectrum is estimated as 123/411= 30'th percentile
float noise_level = tmpsort[122];
/* Renormalize spectrum so that (large) peaks represent an estimate of snr.
* We know from experience that threshold snr is near -7dB in wspr bandwidth,
* corresponding to -7-26.3=-33.3dB in 2500 Hz bandwidth.
* The corresponding threshold is -42.3 dB in 2500 Hz bandwidth for WSPR-15. */
float min_snr, snr_scaling_factor;
min_snr = pow(10.0,-7.0/10.0); //this is min snr in wspr bw
if( wspr_type == 2 ) {
snr_scaling_factor=26.3;
} else {
snr_scaling_factor=35.3;
}
for (j=0; j<411; j++) {
smspec[j]=smspec[j]/noise_level - 1.0;
if( smspec[j] < min_snr) smspec[j]=0.1;
continue;
}
// Find all local maxima in smoothed spectrum.
for (i=0; i<200; i++) {
freq0[i]=0.0;
snr0[i]=0.0;
drift0[i]=0.0;
shift0[i]=0;
sync0[i]=0.0;
}
int npk=0;
for(j=1; j<410; j++) {
if((smspec[j]>smspec[j-1]) && (smspec[j]>smspec[j+1]) && (npk<200)) {
freq0[npk]=(j-205)*df;
snr0[npk]=10*log10(smspec[j])-snr_scaling_factor;
npk++;
}
}
// Compute corrected fmin, fmax, accounting for dial frequency error
fmin += dialfreq_error; // dialfreq_error is in units of Hz
fmax += dialfreq_error;
// Don't waste time on signals outside of the range [fmin,fmax].
i=0;
for( j=0; j<npk; j++) {
if( freq0[j] >= fmin && freq0[j] <= fmax ) {
freq0[i]=freq0[j];
snr0[i]=snr0[j];
i++;
}
}
npk=i;
t0=clock();
/* Make coarse estimates of shift (DT), freq, and drift
* Look for time offsets up to +/- 8 symbols (about +/- 5.4 s) relative
to nominal start time, which is 2 seconds into the file
* Calculates shift relative to the beginning of the file
* Negative shifts mean that signal started before start of file
* The program prints DT = shift-2 s
* Shifts that cause sync vector to fall off of either end of the data
vector are accommodated by "partial decoding", such that missing
symbols produce a soft-decision symbol value of 128
* The frequency drift model is linear, deviation of +/- drift/2 over the
span of 162 symbols, with deviation equal to 0 at the center of the
signal vector.
*/
int idrift,ifr,if0,ifd,k0;
int kindex;
float smax,ss,pow,p0,p1,p2,p3;
for(j=0; j<npk; j++) { //For each candidate...
smax=-1e30;
if0=freq0[j]/df+256;
for (ifr=if0-1; ifr<=if0+1; ifr++) { //Freq search
for( k0=-10; k0<22; k0++) { //Time search
for (idrift=-maxdrift; idrift<=maxdrift; idrift++) { //Drift search
ss=0.0;
pow=0.0;
for (k=0; k<162; k++) { //Sum over symbols
ifd=ifr+((float)k-81.0)/81.0*( (float)idrift )/(2.0*df);
kindex=k0+2*k;
if( kindex < nffts ) {
p0=ps[ifd-3][kindex];
p1=ps[ifd-1][kindex];
p2=ps[ifd+1][kindex];
p3=ps[ifd+3][kindex];
p0=sqrt(p0);
p1=sqrt(p1);
p2=sqrt(p2);
p3=sqrt(p3);
ss=ss+(2*pr3[k]-1)*((p1+p3)-(p0+p2));
pow=pow+p0+p1+p2+p3;
sync1=ss/pow;
}
}
if( sync1 > smax ) { //Save coarse parameters
smax=sync1;
shift0[j]=128*(k0+1);
drift0[j]=idrift;
freq0[j]=(ifr-256)*df;
sync0[j]=sync1;
}
}
}
}
}
tcandidates += (double)(clock()-t0)/CLOCKS_PER_SEC;
nbits=81;
symbols=malloc(sizeof(char)*nbits*2);
memset(symbols,0,sizeof(char)*nbits*2);
decdata=malloc((nbits+7)/8);
grid=malloc(sizeof(char)*5);
grid6=malloc(sizeof(char)*7);
callsign=malloc(sizeof(char)*13);
call_loc_pow=malloc(sizeof(char)*23);
cdbm=malloc(sizeof(char)*3);
float allfreqs[npk];
memset(allfreqs,0,sizeof(float)*npk);
char allcalls[npk][13];
memset(allcalls,0,sizeof(char)*npk*13);
memset(grid,0,sizeof(char)*5);
memset(grid6,0,sizeof(char)*7);
memset(callsign,0,sizeof(char)*13);
memset(call_loc_pow,0,sizeof(char)*23);
memset(cdbm,0,sizeof(char)*3);
char hashtab[32768][13];
memset(hashtab,0,sizeof(char)*32768*13);
uint32_t nhash_( const void *, size_t, uint32_t);
int nh;
if( usehashtable ) {
char line[80], hcall[12];
if( (fhash=fopen(hash_fname,"r+")) ) {
while (fgets(line, sizeof(line), fhash) != NULL) {
sscanf(line,"%d %s",&nh,hcall);
strcpy(*hashtab+nh*13,hcall);
}
} else {
fhash=fopen(hash_fname,"w+");
}
fclose(fhash);
}
int uniques=0, noprint=0;
/*
Refine the estimates of freq, shift using sync as a metric.
Sync is calculated such that it is a float taking values in the range
[0.0,1.0].
Function sync_and_demodulate has three modes of operation
mode is the last argument:
0 = no frequency or drift search. find best time lag.
1 = no time lag or drift search. find best frequency.
2 = no frequency or time lag search. Calculate soft-decision
symbols using passed frequency and shift.
NB: best possibility for OpenMP may be here: several worker threads
could each work on one candidate at a time.
*/
for (j=0; j<npk; j++) {
f1=freq0[j];
drift1=drift0[j];
shift1=shift0[j];
sync1=sync0[j];
// Fine search for best sync lag (mode 0)
fstep=0.0;
lagmin=shift1-144;
lagmax=shift1+144;
lagstep=8;
if(quickmode) lagstep=16;
t0 = clock();
sync_and_demodulate(idat, qdat, npoints, symbols, &f1, fstep, &shift1,
lagmin, lagmax, lagstep, &drift1, symfac, &sync1, 0);
tsync0 += (double)(clock()-t0)/CLOCKS_PER_SEC;
// Fine search for frequency peak (mode 1)
fstep=0.1;
t0 = clock();
sync_and_demodulate(idat, qdat, npoints, symbols, &f1, fstep, &shift1,
lagmin, lagmax, lagstep, &drift1, symfac, &sync1, 1);
tsync1 += (double)(clock()-t0)/CLOCKS_PER_SEC;
if( sync1 > minsync1 ) {
worth_a_try = 1;
} else {
worth_a_try = 0;
}
int idt=0, ii=0, jiggered_shift;
double y,sq,rms;
not_decoded=1;
while ( worth_a_try && not_decoded && idt<=(128/iifac)) {
ii=(idt+1)/2;
if( idt%2 == 1 ) ii=-ii;
ii=iifac*ii;
jiggered_shift=shift1+ii;
// Use mode 2 to get soft-decision symbols
t0 = clock();
sync_and_demodulate(idat, qdat, npoints, symbols, &f1, fstep,
&jiggered_shift, lagmin, lagmax, lagstep, &drift1, symfac,
&sync1, 2);
tsync2 += (double)(clock()-t0)/CLOCKS_PER_SEC;
sq=0.0;
for(i=0; i<162; i++) {
y=(double)symbols[i] - 128.0;
sq += y*y;
}
rms=sqrt(sq/162.0);
if((sync1 > minsync2) && (rms > minrms)) {
deinterleave(symbols);
t0 = clock();
not_decoded = fano(&metric,&cycles,&maxnp,decdata,symbols,nbits,
mettab,delta,maxcycles);
tfano += (double)(clock()-t0)/CLOCKS_PER_SEC;
/* ### Used for timing tests:
if(not_decoded) fprintf(fdiag,
"%6s %4s %4.1f %3.0f %4.1f %10.7f %-18s %2d %5u %4d %6.1f %2d\n",
date,uttime,sync1*10,snr0[j], shift1*dt-2.0, dialfreq+(1500+f1)/1e6,
"@ ", (int)drift1, cycles/81, ii, rms, maxnp);
*/
}
idt++;
if( quickmode ) break;
}
if( worth_a_try && !not_decoded ) {
for(i=0; i<11; i++) {
if( decdata[i]>127 ) {
message[i]=decdata[i]-256;
} else {
message[i]=decdata[i];
}
}
// Unpack the decoded message, update the hashtable, apply
// sanity checks on grid and power, and return
// call_loc_pow string and also callsign (for de-duping).
noprint=unpk_(message,hashtab,call_loc_pow,callsign);
// Remove dupes (same callsign and freq within 1 Hz)
int dupe=0;
for (i=0; i<npk; i++) {
if(!strcmp(callsign,allcalls[i]) &&
(fabs(f1-allfreqs[i]) <1.0)) dupe=1;
}
if( (verbose || !dupe) && !noprint) {
uniques++;
strcpy(allcalls[uniques],callsign);
allfreqs[uniques]=f1;
// Add an extra space at the end of each line so that wspr-x doesn't
// truncate the power (TNX to DL8FCL!)
if( wspr_type == 15 ) {
freq_print=dialfreq+(1500+112.5+f1/8.0)/1e6;
dt_print=shift1*8*dt-2.0;
} else {
freq_print=dialfreq+(1500+f1)/1e6;
dt_print=shift1*dt-2.0;
}
printf("%4s %3.0f %4.1f %10.6f %2d %-s \n",
uttime, snr0[j],dt_print,freq_print,
(int)drift1, call_loc_pow);
fprintf(fall_wspr,
"%6s %4s %3.0f %3.0f %4.1f %10.7f %-22s %2d %5u %4d\n",
date,uttime,sync1*10,snr0[j],
dt_print, freq_print,
call_loc_pow, (int)drift1, cycles/81, ii);
fprintf(fwsprd,"%6s %4s %3d %3.0f %4.1f %10.6f %-22s %2d %5u %4d\n",
date,uttime,(int)(sync1*10),snr0[j],
dt_print, freq_print,
call_loc_pow, (int)drift1, cycles/81, ii);
/* For timing tests
fprintf(fdiag,
"%6s %4s %4.1f %3.0f %4.1f %10.7f %-18s %2d %5u %4d %6.1f\n",
date,uttime,sync1*10,snr0[j],
shift1*dt-2.0, dialfreq+(1500+f1)/1e6,
call_loc_pow, (int)drift1, cycles/81, ii, rms);
*/
}
}
}
printf("<DecodeFinished>\n");
if ((fp_fftw_wisdom_file = fopen(wisdom_fname, "w"))) {
fftw_export_wisdom_to_file(fp_fftw_wisdom_file);
fclose(fp_fftw_wisdom_file);
}
ttotal += (double)(clock()-t00)/CLOCKS_PER_SEC;
fprintf(ftimer,"%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n\n",
treadwav,tcandidates,tsync0,tsync1,tsync2,tfano,ttotal);
fprintf(ftimer,"Code segment Seconds Frac\n");
fprintf(ftimer,"-----------------------------------\n");
fprintf(ftimer,"readwavfile %7.2f %7.2f\n",treadwav,treadwav/ttotal);
fprintf(ftimer,"Coarse DT f0 f1 %7.2f %7.2f\n",tcandidates,
tcandidates/ttotal);
fprintf(ftimer,"sync_and_demod(0) %7.2f %7.2f\n",tsync0,tsync0/ttotal);
fprintf(ftimer,"sync_and_demod(1) %7.2f %7.2f\n",tsync1,tsync1/ttotal);
fprintf(ftimer,"sync_and_demod(2) %7.2f %7.2f\n",tsync2,tsync2/ttotal);
fprintf(ftimer,"Fano decoder %7.2f %7.2f\n",tfano,tfano/ttotal);
fprintf(ftimer,"-----------------------------------\n");
fprintf(ftimer,"Total %7.2f %7.2f\n",ttotal,1.0);
fclose(fall_wspr);
fclose(fwsprd);
// fclose(fdiag);
fclose(ftimer);
fftw_destroy_plan(PLAN1);
fftw_destroy_plan(PLAN2);
fftw_destroy_plan(PLAN3);
if( usehashtable ) {
fhash=fopen(hash_fname,"w");
for (i=0; i<32768; i++) {
if( strncmp(hashtab[i],"\0",1) != 0 ) {
fprintf(fhash,"%5d %s\n",i,*hashtab+i*13);
}
}
fclose(fhash);
}
if(fblank+tblank+writenoise == 999) return -1; //Silence compiler warning
return 0;
}

24
lib/wsprd/wsprd_stats.txt Normal file
View File

@ -0,0 +1,24 @@
Linux Windows
Program Time Decodes Time Decodes
-------------------------------------------------
wsprd (Mar 2013) 2413 1451 2718 1451
k9an-wsprd 1800 2122
k9an_wsprd -q 354 1939
wsprd 399 2190 356 2190
wsprd -q 214 2034 192 2034
wsprd* 1240 2215
wsprd# 1599 2220
-------------------------------------------------
* maxcycles=30000
# maxcycles=20000, iifac=1
-------------------------------------------------
Test data: 638 *.wav files (recorded by WSJT-X)
-------------------------------------------------
Linux machine: Core 2 Duo, E6750 CPU
Windows machine: 4-Core i5-2500 CPU
wsprd git commit: eecc274
-------------------------------------------------

322
lib/wsprd/wsprd_utils.c Normal file
View File

@ -0,0 +1,322 @@
/*
This file is part of program wsprd, a detector/demodulator/decoder
for the Weak Signal Propagation Reporter (WSPR) mode.
File name: wsprd_utils.c
Copyright 2001-2015, Joe Taylor, K1JT
Most of the code is based on work by Steven Franke, K9AN, which
in turn was based on earlier work by K1JT.
Copyright 2014-2015, Steven Franke, K9AN
License: GNU GPL v3
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "wsprd_utils.h"
#ifndef int32_t
#define int32_t int
#endif
void unpack50( signed char *dat, int32_t *n1, int32_t *n2 )
{
int32_t i,i4;
i=dat[0];
i4=i&255;
*n1=i4<<20;
i=dat[1];
i4=i&255;
*n1=*n1+(i4<<12);
i=dat[2];
i4=i&255;
*n1=*n1+(i4<<4);
i=dat[3];
i4=i&255;
*n1=*n1+((i4>>4)&15);
*n2=(i4&15)<<18;
i=dat[4];
i4=i&255;
*n2=*n2+(i4<<10);
i=dat[5];
i4=i&255;
*n2=*n2+(i4<<2);
i=dat[6];
i4=i&255;
*n2=*n2+((i4>>6)&3);
}
void unpackcall( int32_t ncall, char *call )
{
char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E',
'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
'U','V','W','X','Y','Z',' '};
int32_t n;
int i;
char tmp[7];
n=ncall;
strcpy(call,"......");
if (n < 262177560 ) {
i=n%27+10;
tmp[5]=c[i];
n=n/27;
i=n%27+10;
tmp[4]=c[i];
n=n/27;
i=n%27+10;
tmp[3]=c[i];
n=n/27;
i=n%10;
tmp[2]=c[i];
n=n/10;
i=n%36;
tmp[1]=c[i];
n=n/36;
i=n;
tmp[0]=c[i];
tmp[6]='\0';
// remove leading whitespace
for(i=0; i<5; i++) {
if( tmp[i] != c[36] )
break;
}
sprintf(call,"%-6s",&tmp[i]);
// remove trailing whitespace
for(i=0; i<6; i++) {
if( call[i] == c[36] ) {
call[i]='\0';
}
}
}
}
void unpackgrid( int32_t ngrid, char *grid)
{
char c[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E',
'F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
'U','V','W','X','Y','Z',' '};
int dlat, dlong;
ngrid=ngrid>>7;
if( ngrid < 32400 ) {
dlat=(ngrid%180)-90;
dlong=(ngrid/180)*2 - 180 + 2;
if( dlong < -180 )
dlong=dlong+360;
if( dlong > 180 )
dlong=dlong+360;
int nlong = 60.0*(180.0-dlong)/5.0;
int n1 = nlong/240;
int n2 = (nlong - 240*n1)/24;
grid[0] = c[10+n1];
grid[2]= c[n2];
int nlat = 60.0*(dlat+90)/2.5;
n1 = nlat/240;
n2 = (nlat-240*n1)/24;
grid[1]=c[10+n1];
grid[3]=c[n2];
} else {
strcpy(grid,"XXXX");
}
}
void unpackpfx( int32_t nprefix, char *call)
{
char nc, pfx[4]="", tmpcall[7]="";
int i;
int32_t n;
strcpy(tmpcall,call);
if( nprefix < 60000 ) {
// add a prefix of 1 to 3 characters
n=nprefix;
for (i=2; i>=0; i--) {
nc=n%37;
if( (nc >= 0) & (nc <= 9) ) {
pfx[i]=nc+48;
}
else if( (nc >= 10) & (nc <= 35) ) {
pfx[i]=nc+55;
}
else {
pfx[i]=' ';
}
n=n/37;
}
strcpy(call,pfx);
strncat(call,"/",1);
strncat(call,tmpcall,strlen(tmpcall));
} else {
// add a suffix of 1 or 2 characters
nc=nprefix-60000;
if( (nc >= 0) & (nc <= 9) ) {
pfx[0]=nc+48;
strcpy(call,tmpcall);
strncat(call,"/",1);
strncat(call,pfx,1);
}
else if( (nc >= 10) & (nc <= 35) ) {
pfx[0]=nc+55;
strcpy(call,tmpcall);
strncat(call,"/",1);
strncat(call,pfx,1);
}
else if( (nc >= 36) & (nc <= 125) ) {
pfx[0]=(nc-26)/10+48;
pfx[1]=(nc-26)%10+48;
strcpy(call,tmpcall);
strncat(call,"/",1);
strncat(call,pfx,2);
}
}
}
void deinterleave(unsigned char *sym)
{
unsigned char tmp[162];
unsigned char p, i, j;
p=0;
i=0;
while (p<162) {
j=((i * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32;
if (j < 162 ) {
tmp[p]=sym[j];
p=p+1;
}
i=i+1;
}
for (i=0; i<162; i++) {
sym[i]=tmp[i];
}
}
// used by qsort
int floatcomp(const void* elem1, const void* elem2)
{
if(*(const float*)elem1 < *(const float*)elem2)
return -1;
return *(const float*)elem1 > *(const float*)elem2;
}
int unpk_(signed char *message, char hashtab[32768][13], char *call_loc_pow, char *callsign)
{
int n1,n2,n3,ndbm,ihash,nadd,noprint=0;
char grid[5],grid6[7],cdbm[3];
unpack50(message,&n1,&n2);
unpackcall(n1,callsign);
unpackgrid(n2, grid);
int ntype = (n2&127) - 64;
callsign[12]=0;
grid[4]=0;
/*
Based on the value of ntype, decide whether this is a Type 1, 2, or
3 message.
* Type 1: 6 digit call, grid, power - ntype is positive and is a member
of the set {0,3,7,10,13,17,20...60}
* Type 2: extended callsign, power - ntype is positive but not
a member of the set of allowed powers
* Type 3: hash, 6 digit grid, power - ntype is negative.
*/
if( (ntype >= 0) && (ntype <= 62) ) {
int nu=ntype%10;
if( nu == 0 || nu == 3 || nu == 7 ) {
ndbm=ntype;
memset(call_loc_pow,0,sizeof(char)*23);
sprintf(cdbm,"%2d",ndbm);
strncat(call_loc_pow,callsign,strlen(callsign));
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,grid,4);
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,cdbm,2);
strncat(call_loc_pow,"\0",1);
ihash=nhash_(callsign,strlen(callsign),(uint32_t)146);
strcpy(*hashtab+ihash*13,callsign);
} else {
nadd=nu;
if( nu > 3 ) nadd=nu-3;
if( nu > 7 ) nadd=nu-7;
n3=n2/128+32768*(nadd-1);
unpackpfx(n3,callsign);
ndbm=ntype-nadd;
memset(call_loc_pow,0,sizeof(char)*23);
sprintf(cdbm,"%2d",ndbm);
strncat(call_loc_pow,callsign,strlen(callsign));
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,cdbm,2);
strncat(call_loc_pow,"\0",1);
int nu=ndbm%10;
if( nu == 0 || nu == 3 || nu == 7 || nu == 10 ) { //make sure power is OK
ihash=nhash_(callsign,strlen(callsign),(uint32_t)146);
strcpy(*hashtab+ihash*13,callsign);
} else noprint=1;
}
} else if ( ntype < 0 ) {
ndbm=-(ntype+1);
memset(grid6,0,sizeof(char)*7);
strncat(grid6,callsign+5,1);
strncat(grid6,callsign,5);
int nu=ndbm%10;
if( (nu == 0 || nu == 3 || nu == 7 || nu == 10) && \
(isalpha(grid6[0]) && isalpha(grid6[1]) && \
isdigit(grid6[2]) && isdigit(grid6[3]) ) ) {
// not testing 4'th and 5'th chars because of this case: <PA0SKT/2> JO33 40
// grid is only 4 chars even though this is a hashed callsign...
// isalpha(grid6[4]) && isalpha(grid6[5]) ) ) {
ihash=nhash_(callsign,strlen(callsign),(uint32_t)146);
strcpy(*hashtab+ihash*13,callsign);
} else noprint=1;
ihash=(n2-ntype-64)/128;
if( strncmp(hashtab[ihash],"\0",1) != 0 ) {
sprintf(callsign,"<%s>",hashtab[ihash]);
} else {
sprintf(callsign,"%5s","<...>");
}
memset(call_loc_pow,0,sizeof(char)*23);
sprintf(cdbm,"%2d",ndbm);
strncat(call_loc_pow,callsign,strlen(callsign));
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,grid6,strlen(grid6));
strncat(call_loc_pow," ",1);
strncat(call_loc_pow,cdbm,2);
strncat(call_loc_pow,"\0",1);
// I don't know what to do with these... They show up as "A000AA" grids.
if( ntype == -64 ) noprint=1;
}
return noprint;
}

24
lib/wsprd/wsprd_utils.h Normal file
View File

@ -0,0 +1,24 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
void unpack50( signed char *dat, int32_t *n1, int32_t *n2 );
void unpackcall( int32_t ncall, char *call );
void unpackgrid( int32_t ngrid, char *grid);
void unpackpfx( int32_t nprefix, char *call);
void deinterleave(unsigned char *sym);
// used by qsort
int floatcomp(const void* elem1, const void* elem2);
unsigned int nhash_( const void *key, size_t length, uint32_t initval);
int unpk_( signed char *message, char hashtab[32768][13], char *call_loc_pow, char *callsign);

File diff suppressed because it is too large Load Diff

View File

@ -30,10 +30,12 @@
#include "Detector.hpp"
#include "Modulator.hpp"
#include "decodedtext.h"
#include "wsprnet.h"
#define NUM_JT4_SYMBOLS 206
#define NUM_JT65_SYMBOLS 126
#define NUM_JT9_SYMBOLS 85
#define NUM_WSPR_SYMBOLS 162
#define NUM_CW_SYMBOLS 250
#define TX_SAMPLE_RATE 48000
@ -83,6 +85,9 @@ public slots:
void readFromStdout();
void readFromStderr();
void jt9_error(QProcess::ProcessError);
void p1ReadFromStdout();
void p1ReadFromStderr();
void p1Error(QProcess::ProcessError);
void setXIT(int n);
void setFreq4(int rxFreq, int txFreq);
void clrAvg();
@ -188,6 +193,7 @@ private slots:
void band_changed (Frequency);
void monitor (bool);
void stop_tuning ();
void stopTuneATU();
void auto_tx_mode (bool);
void on_actionMessage_averaging_triggered();
void on_sbTol_valueChanged(int i);
@ -203,6 +209,28 @@ private slots:
void on_cbTx6_toggled(bool b);
void networkError (QString const&);
void on_ClrAvgButton_clicked();
void on_actionWSPR_2_triggered();
void on_actionWSPR_15_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 uploadResponse(QString response);
void p3ReadFromStdout();
void p3ReadFromStderr();
void p3Error(QProcess::ProcessError e);
void on_WSPRfreqSpinBox_valueChanged(int n);
void on_pbTxNext_clicked(bool b);
void on_cbBandHop_toggled(bool b);
void on_sunriseBands_editingFinished();
void on_pushButton_clicked();
void on_dayBands_editingFinished();
void on_sunsetBands_editingFinished();
void on_nightBands_editingFinished();
void on_tuneBands_editingFinished();
void on_graylineDuration_editingFinished();
private:
void enable_DXCC_entity (bool on);
@ -249,6 +277,7 @@ private:
QScopedPointer<MessageAveraging> m_msgAvgWidget;
Frequency m_dialFreq;
Frequency m_dialFreqRxWSPR;
Detector m_detector;
SoundInput m_soundInput;
@ -263,6 +292,7 @@ private:
qint64 m_dialFreqTx;
float m_DTtol;
float m_rxavg;
qint32 m_waterfallAvg;
qint32 m_ntx;
@ -274,6 +304,8 @@ private:
qint32 m_RxLog;
qint32 m_nutc0;
qint32 m_nrx;
qint32 m_ntr;
qint32 m_tx;
qint32 m_hsym;
qint32 m_TRperiod;
qint32 m_nsps;
@ -291,6 +323,12 @@ private:
qint32 m_nclearave;
qint32 m_DopplerMethod;
qint32 m_DopplerMethod0;
qint32 m_minSync;
qint32 m_dBm;
qint32 m_pctx;
qint32 m_nseq;
qint32 m_grayDuration;
qint32 m_band00;
bool m_btxok; //True if OK to transmit
bool m_diskData;
@ -338,6 +376,15 @@ private:
bool m_bShMsgs;
bool m_bDopplerTracking;
bool m_bDopplerTracking0;
bool m_uploadSpots;
bool m_uploading;
bool m_txNext;
bool m_grid6;
bool m_bandHopping;
bool m_hopTest;
bool m_tuneup;
bool m_bTxTime;
bool m_rxDone;
float m_pctZap;
@ -347,6 +394,8 @@ private:
QLabel * last_tx_label;
QLabel * auto_tx_label;
QProgressBar* progressBar;
QMessageBox msgBox0;
QFuture<void>* future1;
@ -357,6 +406,10 @@ private:
QFutureWatcher<void>* watcher3;
QProcess proc_jt9;
QProcess p1;
QProcess p3;
WSPRNet *wsprNet;
QTimer m_guiTimer;
QTimer* ptt1Timer; //StartTx delay
@ -364,6 +417,8 @@ private:
QTimer* logQSOTimer;
QTimer* killFileTimer;
QTimer* tuneButtonTimer;
QTimer* uploadTimer;
QTimer* tuneATU_Timer;
QString m_path;
QString m_pbdecoding_style1;
@ -389,9 +444,17 @@ private:
QString m_msgSent0;
QString m_fileToSave;
QString m_band;
QString m_c2name;
QStringList m_prefix;
QStringList m_suffix;
QStringList m_sunriseBands;
QStringList m_dayBands;
QStringList m_sunsetBands;
QStringList m_nightBands;
QStringList m_tuneBands;
QMap<QString,double> m_fWSPR;
QHash<QString,bool> m_pfx;
QHash<QString,bool> m_sfx;
@ -444,6 +507,7 @@ private:
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 bandHopping();
};
extern void getfile(QString fname, int ntrperiod);
@ -456,7 +520,7 @@ extern int ptt(int nport, int ntx, int* iptt, int* nopen);
extern "C" {
//----------------------------------------------------- C and Fortran routines
void symspec_(int* k, int* ntrperiod, int* nsps, int* ingain,
void symspec_(int* k, int* ntrperiod, int* nsps, int* ingain, int* minw,
float* px, float s[], float* df3, int* nhsym, int* npts8);
void gen4_(char* msg, int* ichk, char* msgsent, int itone[],
@ -468,6 +532,8 @@ extern "C" {
void gen65_(char* msg, int* ichk, char* msgsent, int itone[],
int* itext, int len1, int len2);
void genwspr_(char* msg, char* msgsent, int itone[], int len1, int len2);
bool stdmsg_(const char* msg, int len);
void azdist_(char* MyGrid, char* HisGrid, double* utch, int* nAz, int* nEl,
@ -481,6 +547,12 @@ extern "C" {
int fftwf_import_wisdom_from_filename(const char *);
int fftwf_export_wisdom_to_filename(const char *);
void wspr_downsample_(short int d2[], int* k);
void savec2_(char* fname, int* m_TRseconds, double* m_dialFreq, int len1);
void hopping_(int* nyear, int* month, int* nday, float* uth, char* MyGrid,
int* nduration, int* npctx, int* isun, int* iband,
int* ntxnext, int len);
}
#endif // MAINWINDOW_H

View File

@ -11,14 +11,14 @@
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>825</width>
<width>0</width>
<height>460</height>
</size>
</property>
@ -38,6 +38,9 @@
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="horizontalSpacing">
@ -556,58 +559,7 @@
<layout class="QGridLayout" name="gridLayout_5">
<item row="0" column="5" rowspan="6">
<layout class="QGridLayout" name="gridLayout_3">
<item row="7" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="labTol">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Tolerance for offset from selected Rx frequency.</string>
</property>
<property name="text">
<string> F tol 500</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbTol">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>18</width>
<height>16777215</height>
</size>
</property>
<property name="maximum">
<number>7</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="1">
<item row="6" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<spacer name="horizontalSpacer">
@ -656,7 +608,7 @@
</item>
</layout>
</item>
<item row="2" column="2">
<item row="3" column="2">
<widget class="QPushButton" name="pbT2R">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -678,7 +630,7 @@
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QCheckBox" name="cbTxLock">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Tx frequency tracks Rx frequency&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
@ -688,7 +640,7 @@
</property>
</widget>
</item>
<item row="3" column="2">
<item row="4" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>5</number>
@ -742,23 +694,7 @@
</item>
</layout>
</item>
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>18</height>
</size>
</property>
</spacer>
</item>
<item row="6" column="2">
<item row="7" column="2">
<widget class="QDoubleSpinBox" name="sbDT">
<property name="toolTip">
<string>Tolerance for expected time offset.</string>
@ -783,140 +719,7 @@
</property>
</widget>
</item>
<item row="6" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="labMinW">
<property name="toolTip">
<string>Set minimum width expected for Doppler-spread tones</string>
</property>
<property name="text">
<string>MinW A</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbMinW">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>18</width>
<height>16777215</height>
</size>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>6</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="2">
<widget class="QCheckBox" name="cbEME">
<property name="maximumSize">
<size>
<width>40</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Check to add 2.5 s to expected propagation delay.</string>
</property>
<property name="text">
<string>EME</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pbR2T">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>48</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Set Tx frequency to Rx Frequency</string>
</property>
<property name="text">
<string>Tx&lt;Rx</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="RxFreqSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>20</height>
</size>
</property>
<property name="toolTip">
<string>Audio Rx frequency</string>
</property>
<property name="suffix">
<string> Hz</string>
</property>
<property name="prefix">
<string>Rx </string>
</property>
<property name="minimum">
<number>200</number>
</property>
<property name="maximum">
<number>5000</number>
</property>
<property name="value">
<number>1500</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QCheckBox" name="txFirstCheckBox">
<property name="minimumSize">
<size>
<width>60</width>
<height>23</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>105</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Check to Tx in even minutes, uncheck for odd minutes</string>
</property>
<property name="text">
<string>Tx even</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="TxFreqSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@ -939,6 +742,9 @@
<property name="toolTip">
<string>Audio Tx frequency</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string> Hz</string>
</property>
@ -956,7 +762,7 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="1" column="1">
<widget class="QPushButton" name="pbTxMode">
<property name="enabled">
<bool>false</bool>
@ -969,7 +775,7 @@
</property>
</widget>
</item>
<item row="7" column="1">
<item row="8" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="labSubmode">
@ -1008,7 +814,7 @@
</item>
</layout>
</item>
<item row="2" column="0">
<item row="3" column="0">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -1024,6 +830,235 @@
</property>
</spacer>
</item>
<item row="5" column="2">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="syncSpinBox">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="prefix">
<string>Sync </string>
</property>
<property name="maximum">
<number>10</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="7" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLabel" name="labMinW">
<property name="toolTip">
<string>Set minimum width expected for Doppler-spread tones</string>
</property>
<property name="text">
<string>MinW A</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbMinW">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>18</width>
<height>16777215</height>
</size>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>6</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="2">
<widget class="QCheckBox" name="cbEME">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Check to add 2.5 s to expected propagation delay.</string>
</property>
<property name="text">
<string>EME</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pbR2T">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>48</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Set Tx frequency to Rx Frequency</string>
</property>
<property name="text">
<string>Tx&lt;Rx</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="RxFreqSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>20</height>
</size>
</property>
<property name="toolTip">
<string>Audio Rx frequency</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string> Hz</string>
</property>
<property name="prefix">
<string>Rx </string>
</property>
<property name="minimum">
<number>200</number>
</property>
<property name="maximum">
<number>5000</number>
</property>
<property name="value">
<number>1500</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="txFirstCheckBox">
<property name="minimumSize">
<size>
<width>60</width>
<height>23</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>105</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Check to Tx in even minutes, uncheck for odd minutes</string>
</property>
<property name="text">
<string>Tx even</string>
</property>
</widget>
</item>
<item row="8" column="2">
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLabel" name="labTol">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Tolerance for offset from selected Rx frequency.</string>
</property>
<property name="text">
<string> F tol 500</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="sbTol">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>18</width>
<height>16777215</height>
</size>
</property>
<property name="maximum">
<number>7</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item row="1" column="3">
@ -1381,7 +1416,7 @@
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -1392,6 +1427,12 @@
<height>200</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="tabPosition">
<enum>QTabWidget::West</enum>
</property>
@ -1399,7 +1440,7 @@
<enum>QTabWidget::Triangular</enum>
</property>
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -2197,6 +2238,361 @@ list. The list can be maintained in Settings (F2).</string>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_3">
<attribute name="title">
<string>3</string>
</attribute>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>30</x>
<y>22</y>
<width>200</width>
<height>171</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="0" column="0" colspan="3">
<widget class="QLabel" name="label_11">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>WSPR Mode</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QSpinBox" name="WSPRfreqSpinBox">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string> Hz</string>
</property>
<property name="prefix">
<string>Tx </string>
</property>
<property name="minimum">
<number>1400</number>
</property>
<property name="maximum">
<number>1600</number>
</property>
<property name="value">
<number>1500</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="cbUploadWSPR_Spots">
<property name="text">
<string>Upload spots</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QSpinBox" name="sbTxPercent">
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string> %</string>
</property>
<property name="prefix">
<string>Tx Pct </string>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>20</number>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>5</width>
<height>17</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<widget class="QCheckBox" name="cbBandHop">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Band hopping</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="pbTxNext">
<property name="styleSheet">
<string notr="true">QPushButton:checked {
background-color: red;
border-style: outset;
border-width: 1px;
border-radius: 5px;
border-color: black;
min-width: 5em;
padding: 3px;
}</string>
</property>
<property name="text">
<string>Tx Next</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QComboBox" name="TxPowerComboBox"/>
</item>
</layout>
</widget>
</widget>
<widget class="QWidget" name="tab_4">
<attribute name="title">
<string>4</string>
</attribute>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>100</x>
<y>190</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Test</string>
</property>
</widget>
<widget class="QWidget" name="layoutWidget1">
<property name="geometry">
<rect>
<x>30</x>
<y>30</y>
<width>211</width>
<height>152</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_7">
<item row="0" column="0">
<widget class="QLabel" name="label_12">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Sunrise:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="sunriseBands">
<property name="maximumSize">
<size>
<width>160</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>160 80 40 30 20</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_13">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Day:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="dayBands">
<property name="maximumSize">
<size>
<width>160</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>30 20 17 15 12 10</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_14">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Sunset:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="sunsetBands">
<property name="maximumSize">
<size>
<width>160</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>160 80 40 30 20</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_15">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Night:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="nightBands">
<property name="maximumSize">
<size>
<width>160</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>160 80 40 30 20</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_16">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Tune:</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="tuneBands">
<property name="maximumSize">
<size>
<width>160</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>80 40 30 20 17 15 12 10</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_17">
<property name="minimumSize">
<size>
<width>55</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Gray time:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="graylineDuration">
<property name="maximumSize">
<size>
<width>160</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>60</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</item>
</layout>
@ -2508,6 +2904,22 @@ QLabel[oob=&quot;true&quot;] {
</property>
</spacer>
</item>
<item row="6" column="3">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>1</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
@ -2588,6 +3000,8 @@ QLabel[oob=&quot;true&quot;] {
<addaction name="actionJT9_JT65"/>
<addaction name="actionJT9W_1"/>
<addaction name="actionJT4"/>
<addaction name="actionWSPR_2"/>
<addaction name="actionWSPR_15"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuView"/>
@ -2973,6 +3387,25 @@ QLabel[oob=&quot;true&quot;] {
<string>Include correlation</string>
</property>
</action>
<action name="actionWSPR_2">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>WSPR-2</string>
</property>
</action>
<action name="actionWSPR_15">
<property name="checkable">
<bool>true</bool>
</property>
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>WSPR-15</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
@ -2998,7 +3431,6 @@ QLabel[oob=&quot;true&quot;] {
<tabstop>txFirstCheckBox</tabstop>
<tabstop>TxFreqSpinBox</tabstop>
<tabstop>rptSpinBox</tabstop>
<tabstop>tabWidget</tabstop>
<tabstop>genStdMsgsPushButton</tabstop>
<tabstop>tx1</tabstop>
<tabstop>tx2</tabstop>

View File

@ -37,6 +37,7 @@ CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
m_Percent2DScreen = 30; //percent of screen used for 2D display
m_txFreq=0;
m_fftBinWidth=1500.0/2048.0;
m_bScaleOK=false;
}
CPlotter::~CPlotter() { } // Destructor
@ -92,8 +93,10 @@ void CPlotter::draw(float swide[], bool bScroll) //dr
int j,j0,y2;
float y;
double gain = pow(10.0,0.02*m_plotGain);
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));
qDebug() << m_binsPerPixel << m_waterfallAvg << m_plotGain << gain;
//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);
@ -159,7 +162,7 @@ void CPlotter::draw(float swide[], bool bScroll) //dr
}
}
if(m_bLinearAvg) { //Linear Avg
if(m_bLinearAvg) { //Linear Avg (yellow)
float sum=0.0;
int j=j0+m_binsPerPixel*i;
for(int k=0; k<m_binsPerPixel; k++) {
@ -179,9 +182,9 @@ void CPlotter::draw(float swide[], bool bScroll) //dr
if(swide[0]>1.0e29) m_line=0;
m_line++;
if(m_line == 13) {
UTCstr();
painter1.setPen(Qt::white);
painter1.drawText(5,10,m_sutc);
QString t=QDateTime::currentDateTimeUtc().toString("hh:mm") + " " + m_rxBand;
painter1.drawText(5,10,t);
}
if(m_mode=="JT4") {
@ -189,7 +192,6 @@ void CPlotter::draw(float swide[], bool bScroll) //dr
painter2D.setPen(pen3);
Font.setWeight(QFont::Bold);
painter2D.setFont(Font);
// qDebug() << "B" << m_rxFreq;
int x1=XfromFreq(m_rxFreq);
y=0.2*m_h2;
painter2D.drawText(x1-4,y,"T");
@ -201,22 +203,7 @@ void CPlotter::draw(float swide[], bool bScroll) //dr
painter2D.drawText(x1-4,y,"73");
}
update(); //trigger a new paintEvent
}
void CPlotter::UTCstr() //UTCstr
{
int ihr,imin;
if(jt9com_.ndiskdat != 0) {
ihr=jt9com_.nutc/100;
imin=jt9com_.nutc % 100;
} else {
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
imin=ms/60000;
ihr=imin/60;
imin=imin % 60;
imin=imin - (imin % (m_TRperiod/60));
}
sprintf(m_sutc,"%2.2d:%2.2d",ihr,imin);
m_bScaleOK=true;
}
void CPlotter::DrawOverlay() //DrawOverlay()
@ -225,7 +212,6 @@ void CPlotter::DrawOverlay() //DrawOverlay()
if(m_WaterfallPixmap.isNull()) return;
int w = m_WaterfallPixmap.width();
int x,y,x1,x2;
// int nHzDiv[11]={0,50,100,200,200,200,500,500,500,500,500};
float pixperdiv;
double df = m_binsPerPixel*m_fftBinWidth;
@ -314,7 +300,7 @@ void CPlotter::DrawOverlay() //DrawOverlay()
float bw=9.0*12000.0/m_nsps; //JT9
if(m_mode=="JT4") { //JT4
bw=3*11025.0/2520.0; //NB: this is max tone spacing, 3/4 of actual BW
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;
@ -347,19 +333,33 @@ void CPlotter::DrawOverlay() //DrawOverlay()
if(m_nSubMode==2) bw=4*bw;
}
if(m_mode != "JT4") {
QPen pen0(Qt::green, 3); //Mark Rx Freq with green
painter0.setPen(pen0);
if(m_mode=="WSPR-2") { //### WSPR-15 code needed here, too ###
x1=XfromFreq(1400);
x2=XfromFreq(1600);
painter0.drawLine(x1,29,x2,29);
} else {
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 != "JT4") {
QPen pen1(Qt::red, 3); //Mark Tx freq with red
painter0.setPen(pen1);
x1=XfromFreq(m_txFreq);
x2=XfromFreq(m_txFreq+bw);
if(m_mode=="WSPR-2") { //### WSPR-15 code needed here, too
bw=4*12000.0/8192.0; //WSPR
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);
@ -491,6 +491,11 @@ 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
@ -572,6 +577,11 @@ void CPlotter::setDialFreq(double d)
update();
}
void CPlotter::setRxBand(QString band)
{
m_rxBand=band;
}
void CPlotter::setFlatten(bool b)
{
m_Flatten=0;

View File

@ -32,6 +32,8 @@ public:
QSize minimumSizeHint() const;
QSize sizeHint() const;
bool m_bScaleOK;
void draw(float swide[], bool bScroll); //Update the waterfall
void SetRunningState(bool running);
void setPlotZero(int plotZero);
@ -50,6 +52,7 @@ public:
void setRxRange(int fMin);
void setBinsPerPixel(int n);
int binsPerPixel();
void setWaterfallAvg(int n);
void setRxFreq(int n);
void DrawOverlay();
int rxFreq();
@ -75,6 +78,7 @@ public:
void setColours(QVector<QColor> const& cl) {m_ColorTbl = cl;}
void setFlatten(bool b);
void setTol(int n);
void setRxBand(QString band);
signals:
void freezeDecode1(int n);
@ -88,7 +92,6 @@ protected:
private:
void MakeFrequencyStrs();
void UTCstr();
int XfromFreq(float f);
float FreqfromX(int x);
@ -106,6 +109,7 @@ private:
qint32 m_plot2dGain;
qint32 m_plot2dZero;
qint32 m_binsPerPixel;
qint32 m_waterfallAvg;
qint32 m_w;
qint32 m_Flatten;
qint32 m_nSubMode;
@ -120,6 +124,7 @@ private:
QString m_HDivText[483];
QString m_mode;
QString m_modeTx;
QString m_rxBand;
bool m_Running;
bool m_paintEventBusy;

View File

@ -53,8 +53,11 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
ui->widePlot->setFlatten(m_bFlatten);
ui->widePlot->setBreadth(m_settings->value("PlotWidth",1000).toInt());
ui->bppSpinBox->setValue(n);
m_nsmo=m_settings->value("SmoothYellow",1).toInt();
ui->smoSpinBox->setValue(m_nsmo);
m_waterfallAvg = m_settings->value("WaterfallAvg",5).toInt();
ui->waterfallAvgSpinBox->setValue(m_waterfallAvg);
ui->widePlot->setWaterfallAvg(m_waterfallAvg);
ui->widePlot->setCurrent(m_settings->value("Current",false).toBool());
ui->widePlot->setCumulative(m_settings->value("Cumulative",true).toBool());
ui->widePlot->setLinearAvg(m_settings->value("LinearAvg",false).toBool());
@ -111,6 +114,7 @@ void WideGraph::saveSettings() //saveS
m_settings->setValue ("Plot2dZero", ui->widePlot->plot2dZero());
m_settings->setValue ("PlotWidth", ui->widePlot->plotWidth ());
m_settings->setValue ("BinsPerPixel", ui->bppSpinBox->value ());
m_settings->setValue ("SmoothYellow", ui->smoSpinBox->value ());
m_settings->setValue ("WaterfallAvg", ui->waterfallAvgSpinBox->value ());
m_settings->setValue ("Current", ui->widePlot->current());
m_settings->setValue ("Cumulative", ui->widePlot->cumulative());
@ -176,6 +180,7 @@ void WideGraph::on_bppSpinBox_valueChanged(int n) //b
void WideGraph::on_waterfallAvgSpinBox_valueChanged(int n) //Navg
{
m_waterfallAvg = n;
ui->widePlot->setWaterfallAvg(n);
}
void WideGraph::keyPressEvent(QKeyEvent *e) //F11, F12
@ -282,9 +287,15 @@ void WideGraph::on_spec2dComboBox_currentIndexChanged(const QString &arg1)
ui->widePlot->setCurrent(false);
ui->widePlot->setCumulative(false);
ui->widePlot->setLinearAvg(false);
ui->smoSpinBox->setEnabled(false);
ui->labSmooth->setEnabled(false);
if(arg1=="Current") ui->widePlot->setCurrent(true);
if(arg1=="Cumulative") ui->widePlot->setCumulative(true);
if(arg1=="Linear Avg") ui->widePlot->setLinearAvg(true);
if(arg1=="Linear Avg") {
ui->widePlot->setLinearAvg(true);
ui->smoSpinBox->setEnabled(true);
ui->labSmooth->setEnabled(true);
}
}
void WideGraph::on_fSplitSpinBox_valueChanged(int n) //fSplit
@ -309,6 +320,12 @@ void WideGraph::setDialFreq(double d) //setDialFreq
ui->widePlot->setDialFreq(d);
}
void WideGraph::setRxBand(QString band)
{
ui->widePlot->setRxBand(band);
}
void WideGraph::on_fStartSpinBox_valueChanged(int n) //fStart
{
ui->widePlot->setStartFreq(n);
@ -384,12 +401,13 @@ void WideGraph::on_zeroSlider_valueChanged(int value) //Zero
void WideGraph::on_gain2dSlider_valueChanged(int value) //Gain2
{
ui->widePlot->setPlot2dGain(value);
// ui->widePlot->draw(swide);
if(ui->widePlot->m_bScaleOK) ui->widePlot->draw(swide,false);
}
void WideGraph::on_zero2dSlider_valueChanged(int value) //Zero2
{
ui->widePlot->setPlot2dZero(value);
// ui->widePlot->draw(swide,false);
}
void WideGraph::setTol(int n) //setTol
@ -398,3 +416,13 @@ void WideGraph::setTol(int n) //setTol
ui->widePlot->DrawOverlay();
ui->widePlot->update();
}
void WideGraph::on_smoSpinBox_valueChanged(int n)
{
m_nsmo=n;
}
int WideGraph::smoothYellow()
{
return m_nsmo;
}

View File

@ -40,6 +40,8 @@ public:
void setLockTxFreq(bool b);
bool flatten();
void setTol(int n);
int smoothYellow();
void setRxBand(QString band);
signals:
void freezeDecode2(int n);
@ -69,6 +71,7 @@ private slots:
void on_zeroSlider_valueChanged(int value);
void on_gain2dSlider_valueChanged(int value);
void on_zero2dSlider_valueChanged(int value);
void on_smoSpinBox_valueChanged(int n);
private:
void readPalette();
@ -88,6 +91,7 @@ private:
qint32 m_fMin;
qint32 m_fMax;
qint32 m_nSubMode;
qint32 m_nsmo;
bool m_lockTxFreq;
bool m_bFlatten;

View File

@ -95,59 +95,6 @@
</item>
</widget>
</item>
<item row="1" column="2">
<widget class="QSpinBox" name="waterfallAvgSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Number of FFTs averaged (controls waterfall scrolling rate)</string>
</property>
<property name="prefix">
<string>N Avg </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QComboBox" name="paletteComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Select waterfall palette</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QSpinBox" name="fSplitSpinBox">
<property name="sizePolicy">
@ -158,7 +105,7 @@
</property>
<property name="minimumSize">
<size>
<width>120</width>
<width>100</width>
<height>0</height>
</size>
</property>
@ -191,6 +138,72 @@
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QCheckBox" name="cbFlatten">
<property name="text">
<string>Flatten</string>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QComboBox" name="paletteComboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>125</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Select waterfall palette</string>
</property>
</widget>
</item>
<item row="1" column="7">
<widget class="QSlider" name="gain2dSlider">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Spectrum gain</string>
</property>
<property name="minimum">
<number>-50</number>
</property>
<property name="maximum">
<number>50</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="bppSpinBox">
<property name="sizePolicy">
@ -201,7 +214,7 @@
</property>
<property name="minimumSize">
<size>
<width>120</width>
<width>100</width>
<height>0</height>
</size>
</property>
@ -234,169 +247,30 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QSpinBox" name="fStartSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="0" column="9">
<widget class="QLabel" name="labSmooth">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<width>65</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Frequency (Hz) at left edge of waterfall</string>
</property>
<property name="suffix">
<string> Hz</string>
</property>
<property name="prefix">
<string>Start </string>
</property>
<property name="maximum">
<number>5000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
</widget>
</item>
<item row="0" column="9">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<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>
<item row="0" column="6">
<widget class="QCheckBox" name="cbFlatten">
<property name="text">
<string>Flatten</string>
</property>
</widget>
</item>
<item row="0" column="4">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="labPalette">
<property name="text">
<string> Palette</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="adjust_palette_push_button">
<property name="text">
<string>Adjust...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="3" rowspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="5" rowspan="2">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="1" column="7">
<widget class="QSlider" name="gain2dSlider">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Spectrum gain</string>
</property>
<property name="minimum">
<number>-50</number>
</property>
<property name="maximum">
<number>50</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
</widget>
</item>
<item row="0" column="8">
<widget class="QSlider" name="zeroSlider">
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Waterfall zero</string>
</property>
<property name="minimum">
<number>-50</number>
</property>
<property name="maximum">
<number>50</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
<string>Smoothing</string>
</property>
</widget>
</item>
<item row="0" column="7">
<widget class="QSlider" name="gainSlider">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
@ -423,8 +297,139 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QSpinBox" name="fStartSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Frequency (Hz) at left edge of waterfall</string>
</property>
<property name="suffix">
<string> Hz</string>
</property>
<property name="prefix">
<string>Start </string>
</property>
<property name="maximum">
<number>5000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
</widget>
</item>
<item row="0" column="0">
<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>
<item row="1" column="2">
<widget class="QSpinBox" name="waterfallAvgSpinBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>90</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>100</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Number of FFTs averaged (controls waterfall scrolling rate)</string>
</property>
<property name="prefix">
<string>N Avg </string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>20</number>
</property>
</widget>
</item>
<item row="0" column="5" rowspan="2">
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="3" rowspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="4">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="labPalette">
<property name="text">
<string> Palette </string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="adjust_palette_push_button">
<property name="maximumSize">
<size>
<width>65</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Adjust...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="8">
<widget class="QSlider" name="zero2dSlider">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
@ -448,6 +453,88 @@
</property>
</widget>
</item>
<item row="0" column="8">
<widget class="QSlider" name="zeroSlider">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Waterfall zero</string>
</property>
<property name="minimum">
<number>-50</number>
</property>
<property name="maximum">
<number>50</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksAbove</enum>
</property>
</widget>
</item>
<item row="1" column="9">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QSpinBox" name="smoSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>65</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Smoothing of Linear Average spectrum</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>7</number>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="10">
<spacer name="horizontalSpacer_2">
<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>
</layout>

View File

@ -90,6 +90,7 @@ SOURCES += \
mainwindow.cpp \
main.cpp \
decodedtext.cpp \
wsprnet.cpp \
messageaveraging.cpp
HEADERS += qt_helpers.hpp \
@ -102,7 +103,7 @@ HEADERS += qt_helpers.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 \
Configuration.hpp wsprnet.h \
signalmeter.h \
meterwidget.h \
logbook/logbook.h \

192
wsprnet.cpp Normal file
View File

@ -0,0 +1,192 @@
// Interface to WSPRnet website
//
// by Edson Pereira - PY2SDR
#include "wsprnet.h"
WSPRNet::WSPRNet(QObject *parent) :
QObject(parent)
{
wsprNetUrl = "http://wsprnet.org/post?";
//wsprNetUrl = "http://127.0.0.1/post.php?";
networkManager = new QNetworkAccessManager(this);
connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkReply(QNetworkReply*)));
uploadTimer = new QTimer(this);
connect( uploadTimer, SIGNAL(timeout()), this, SLOT(work()));
}
void WSPRNet::upload(QString call, QString grid, QString rfreq, QString tfreq,
QString mode, QString tpct, QString dbm, QString version,
QString fileName)
{
m_call = call;
m_grid = grid;
m_rfreq = rfreq;
m_tfreq = tfreq;
m_mode = mode;
m_tpct = tpct;
m_dbm = dbm;
m_vers = version;
m_file = fileName;
// Open the wsprd.out file
QFile wsprdOutFile(fileName);
if (!wsprdOutFile.open(QIODevice::ReadOnly | QIODevice::Text) ||
wsprdOutFile.size() == 0) {
urlQueue.enqueue( wsprNetUrl + urlEncodeNoSpot());
m_uploadType = 1;
uploadTimer->start(200);
return;
}
// Read the contents
while (!wsprdOutFile.atEnd()) {
QHash<QString,QString> query;
if ( decodeLine(wsprdOutFile.readLine(), query) ) {
// Prevent reporting data ouside of the current frequency band
float f = fabs(m_rfreq.toFloat() - query["tqrg"].toFloat());
if (f < 0.0002) {
urlQueue.enqueue( wsprNetUrl + urlEncodeSpot(query));
m_uploadType = 2;
}
}
}
m_urlQueueSize = urlQueue.size();
uploadTimer->start(200);
}
void WSPRNet::networkReply(QNetworkReply *reply)
{
QString serverResponse = reply->readAll();
if( m_uploadType == 2) {
if (!serverResponse.contains(QRegExp("spot\\(s\\) added"))) {
emit uploadStatus("Upload Failed");
urlQueue.clear();
uploadTimer->stop();
}
}
if (urlQueue.isEmpty()) {
emit uploadStatus("done");
QFile::remove(m_file);
uploadTimer->stop();
}
}
bool WSPRNet::decodeLine(QString line, QHash<QString,QString> &query)
{
// 130223 2256 7 -21 -0.3 14.097090 DU1MGA PK04 37 0 40 0
// Date Time Sync dBm DT Freq Msg
// 1 2 3 4 5 6 -------7------ 8 9 10
QRegExp rx("^(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+([+-]?\\d+)\\s+([+-]?\\d+\\.\\d+)\\s+(\\d+\\.\\d+)\\s+(.*)\\s+([+-]?\\d+)\\s+([+-]?\\d+)\\s+([+-]?\\d+)");
if (rx.indexIn(line) != -1) {
int msgType = 0;
QString msg = rx.cap(7);
msg.remove(QRegExp("\\s+$"));
msg.remove(QRegExp("^\\s+"));
QString call, grid, dbm;
QRegExp msgRx;
// Check for Message Type 1
msgRx.setPattern("^([A-Z0-9]{3,6})\\s+([A-Z]{2}\\d{2})\\s+(\\d+)");
if (msgRx.indexIn(msg) != -1) {
msgType = 1;
call = msgRx.cap(1);
grid = msgRx.cap(2);
dbm = msgRx.cap(3);
}
// Check for Message Type 2
msgRx.setPattern("^([A-Z0-9/]+)\\s+(\\d+)");
if (msgRx.indexIn(msg) != -1) {
msgType = 2;
call = msgRx.cap(1);
grid = "";
dbm = msgRx.cap(2);
}
// Check for Message Type 3
msgRx.setPattern("^<([A-Z0-9/]+)>\\s+([A-Z]{2}\\d{2}[A-Z]{2})\\s+(\\d+)");
if (msgRx.indexIn(msg) != -1) {
msgType = 3;
call = msgRx.cap(1);
grid = msgRx.cap(2);
dbm = msgRx.cap(3);
}
// Unknown message format
if (!msgType) {
return false;
}
query["function"] = "wspr";
query["date"] = rx.cap(1);
query["time"] = rx.cap(2);
query["sig"] = rx.cap(4);
query["dt"] = rx.cap(5);
query["drift"] = rx.cap(8);
query["tqrg"] = rx.cap(6);
query["tcall"] = call;
query["tgrid"] = grid;
query["dbm"] = dbm;
} else {
return false;
}
return true;
}
QString WSPRNet::urlEncodeNoSpot()
{
QString queryString;
queryString += "function=wsprstat&";
queryString += "rcall=" + m_call + "&";
queryString += "rgrid=" + m_grid + "&";
queryString += "rqrg=" + m_rfreq + "&";
queryString += "tpct=" + m_tpct + "&";
queryString += "tqrg=" + m_tfreq + "&";
queryString += "dbm=" + m_dbm + "&";
queryString += "version=" + m_vers;
if(m_mode=="WSPR-2") queryString += "&mode=2";
if(m_mode=="WSPR-15") queryString += "&mode=15";
return queryString;;
}
QString WSPRNet::urlEncodeSpot(QHash<QString,QString> query)
{
QString queryString;
queryString += "function=" + query["function"] + "&";
queryString += "rcall=" + m_call + "&";
queryString += "rgrid=" + m_grid + "&";
queryString += "rqrg=" + m_rfreq + "&";
queryString += "date=" + query["date"] + "&";
queryString += "time=" + query["time"] + "&";
queryString += "sig=" + query["sig"] + "&";
queryString += "dt=" + query["dt"] + "&";
queryString += "drift=" + query["drift"] + "&";
queryString += "tqrg=" + query["tqrg"] + "&";
queryString += "tcall=" + query["tcall"] + "&";
queryString += "tgrid=" + query["tgrid"] + "&";
queryString += "dbm=" + query["dbm"] + "&";
queryString += "version=" + m_vers;
if(m_mode=="WSPR-2") queryString += "&mode=2";
if(m_mode=="WSPR-15") queryString += "&mode=15";
return queryString;
}
void WSPRNet::work()
{
if (!urlQueue.isEmpty()) {
QUrl url(urlQueue.dequeue());
QNetworkRequest request(url);
networkManager->get(request);
QString status = "Uploading Spot " + QString::number(m_urlQueueSize - urlQueue.size()) +
"/"+ QString::number(m_urlQueueSize);
emit uploadStatus(status);
} else {
uploadTimer->stop();
}
}

37
wsprnet.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef WSPRNET_H
#define WSPRNET_H
#include <QObject>
#include <QtNetwork>
class WSPRNet : public QObject
{
Q_OBJECT
public:
explicit WSPRNet(QObject *parent = 0);
void upload(QString call, QString grid, QString rfreq, QString tfreq,
QString mode, QString tpct, QString dbm, QString version,
QString fileName);
static bool decodeLine(QString line, QHash<QString,QString> &query);
signals:
void uploadStatus(QString);
public slots:
void networkReply(QNetworkReply *);
void work();
private:
QNetworkAccessManager *networkManager;
QString wsprNetUrl;
QString m_call, m_grid, m_rfreq, m_tfreq, m_mode, m_tpct, m_dbm, m_vers, m_file;
QQueue<QString> urlQueue;
QTimer *uploadTimer;
int m_urlQueueSize;
int m_uploadType;
QString urlEncodeNoSpot();
QString urlEncodeSpot(QHash<QString,QString> spot);
};
#endif // WSPRNET_H