Merge branch 'feat-fst280' into develop

This commit is contained in:
Bill Somerville 2020-07-31 15:03:56 +01:00
commit f300c9afc5
No known key found for this signature in database
GPG Key ID: D864B06D1E81618F
75 changed files with 7508 additions and 1384 deletions

5
.gitignore vendored
View File

@ -11,3 +11,8 @@ jnq*
*.txt
cmake-build-debug
cmake-build-release
CMakeFiles
fnd
lib/77bit/tmp
lib/tmp
lib/ftrsd

View File

@ -359,6 +359,8 @@ endif (WIN32)
set (wsjt_FSRCS
# put module sources first in the hope that they get rebuilt before use
lib/types.f90
lib/C_interface_module.f90
lib/shmem.f90
lib/crc.f90
lib/fftw3mod.f90
@ -370,6 +372,7 @@ set (wsjt_FSRCS
lib/jt65_mod.f90
lib/ft8_decode.f90
lib/ft4_decode.f90
lib/fst4_decode.f90
lib/jt9_decode.f90
lib/options.f90
lib/packjt.f90
@ -396,6 +399,7 @@ set (wsjt_FSRCS
lib/badmsg.f90
lib/ft8/baseline.f90
lib/ft4/ft4_baseline.f90
lib/blanker.f90
lib/bpdecode40.f90
lib/bpdecode128_90.f90
lib/ft8/bpdecode174_91.f90
@ -545,6 +549,7 @@ set (wsjt_FSRCS
lib/qra64a.f90
lib/refspectrum.f90
lib/savec2.f90
lib/sec0.f90
lib/sec_midn.f90
lib/setup65.f90
lib/sh65.f90
@ -596,6 +601,20 @@ set (wsjt_FSRCS
lib/wqencode.f90
lib/wspr_downsample.f90
lib/zplot9.f90
lib/fst4/decode240_101.f90
lib/fst4/decode240_74.f90
lib/fst4/encode240_101.f90
lib/fst4/encode240_74.f90
lib/fst4/fst4sim.f90
lib/fst4/gen_fst4wave.f90
lib/fst4/genfst4.f90
lib/fst4/get_fst4_bitmetrics.f90
lib/fst4/get_fst4_bitmetrics2.f90
lib/fst4/ldpcsim240_101.f90
lib/fst4/ldpcsim240_74.f90
lib/fst4/osd240_101.f90
lib/fst4/osd240_74.f90
lib/fst4/get_crc24.f90
)
# temporary workaround for a gfortran v7.3 ICE on Fedora 27 64-bit
@ -1356,6 +1375,15 @@ target_link_libraries (ft4sim_mult wsjt_fort wsjt_cxx)
add_executable (record_time_signal Audio/tools/record_time_signal.cpp)
target_link_libraries (record_time_signal wsjt_cxx wsjt_qtmm wsjt_qt)
add_executable (fst4sim lib/fst4/fst4sim.f90 wsjtx.rc)
target_link_libraries (fst4sim wsjt_fort wsjt_cxx)
add_executable (ldpcsim240_101 lib/fst4/ldpcsim240_101.f90 wsjtx.rc)
target_link_libraries (ldpcsim240_101 wsjt_fort wsjt_cxx)
add_executable (ldpcsim240_74 lib/fst4/ldpcsim240_74.f90 wsjtx.rc)
target_link_libraries (ldpcsim240_74 wsjt_fort wsjt_cxx)
endif(WSJT_BUILD_UTILS)
# build the main application
@ -1495,7 +1523,7 @@ install (TARGETS jt9 wsprd fmtave fcal fmeasure
if(WSJT_BUILD_UTILS)
install (TARGETS ft8code jt65code qra64code qra64sim jt9code jt4code
msk144code
msk144code fst4sim
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime
)

View File

@ -357,7 +357,7 @@
<item row="0" column="1">
<widget class="QCheckBox" name="enable_VHF_features_check_box">
<property name="text">
<string>Enable VHF/UHF/Microwave features</string>
<string>Enable VHF and submode features</string>
</property>
</widget>
</item>
@ -3119,9 +3119,9 @@ Right click for insert and delete options.</string>
<buttongroup name="TX_mode_button_group"/>
<buttongroup name="CAT_handshake_button_group"/>
<buttongroup name="TX_audio_source_button_group"/>
<buttongroup name="special_op_activity_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="split_mode_button_group"/>
<buttongroup name="CAT_stop_bits_button_group"/>
<buttongroup name="CAT_data_bits_button_group"/>
<buttongroup name="special_op_activity_button_group"/>
</buttongroups>
</ui>

3
Decoder/decodedtext.pri Normal file
View File

@ -0,0 +1,3 @@
SOURCES += Decoder/decodedtext.cpp
HEADERS += Decoder/decodedtext.h

3
Detector/Detector.pri Normal file
View File

@ -0,0 +1,3 @@
SOURCES += Detector/Detector.cpp
HEADERS += Detector/Detector.hpp

View File

@ -45,11 +45,12 @@ Modulator::Modulator (unsigned frameRate, double periodLengthInSeconds,
{
}
void Modulator::start (unsigned symbolsLength, double framesPerSymbol,
void Modulator::start (QString mode, unsigned symbolsLength, double framesPerSymbol,
double frequency, double toneSpacing,
SoundOutput * stream, Channel channel,
bool synchronize, bool fastMode, double dBSNR, double TRperiod)
{
// qDebug () << "mode:" << mode << "symbolsLength:" << symbolsLength << "framesPerSymbol:" << framesPerSymbol << "frequency:" << frequency << "toneSpacing:" << toneSpacing << "channel:" << channel << "synchronize:" << synchronize << "fastMode:" << fastMode << "dBSNR:" << dBSNR << "TRperiod:" << TRperiod;
Q_ASSERT (stream);
// Time according to this computer which becomes our base time
qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000;
@ -69,8 +70,8 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol,
m_bFastMode=fastMode;
m_TRperiod=TRperiod;
unsigned delay_ms=1000;
if(m_nsps==1920) delay_ms=500; //FT8
if(m_nsps==576) delay_ms=300; //FT4
if(mode=="FT8" or (mode=="FST4" and m_nsps==720)) delay_ms=500; //FT8, FST4-15
if(mode=="FT4") delay_ms=300; //FT4
// noise generator parameters
if (m_addNoise) {
@ -79,26 +80,30 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol,
if (m_snr > 1.0) m_fac = 3000.0 / m_snr;
}
// round up to an exact portion of a second that allows for startup delays
m_ic = (mstr / delay_ms) * m_frameRate * delay_ms / 1000;
if(m_bFastMode) m_ic=0;
m_silentFrames = 0;
// calculate number of silent frames to send, so that audio will start at
// the nominal time "delay_ms" into the Tx sequence.
if (synchronize && !m_tuning && !m_bFastMode) {
m_silentFrames = m_ic + m_frameRate / (1000 / delay_ms) - (mstr * (m_frameRate / 1000));
}
// qDebug() << "aa" << QDateTime::currentDateTimeUtc().toString("hh:mm:ss.zzz")
// << m_ic << m_silentFrames << m_silentFrames/48000.0
// << mstr << fmod(double(ms0),1000.0*m_period);
m_ic=0;
if (!m_tuning && !m_bFastMode)
{
// calculate number of silent frames to send, so that audio will
// start at the nominal time "delay_ms" into the Tx sequence.
if (synchronize)
{
if(delay_ms > mstr) m_silentFrames = (delay_ms - mstr) * m_frameRate / 1000;
}
// adjust for late starts
if(!m_silentFrames && mstr >= delay_ms)
{
m_ic = (mstr - delay_ms) * m_frameRate / 1000;
}
}
initialize (QIODevice::ReadOnly, channel);
Q_EMIT stateChanged ((m_state = (synchronize && m_silentFrames) ?
Synchronizing : Active));
// qDebug() << "delay_ms:" << delay_ms << "mstr:" << mstr << "m_silentFrames:" << m_silentFrames << "m_ic:" << m_ic << "m_state:" << m_state;
m_stream = stream;
if (m_stream) m_stream->restart (this);
}
@ -137,6 +142,8 @@ void Modulator::close ()
qint64 Modulator::readData (char * data, qint64 maxSize)
{
// qDebug () << "readData: maxSize:" << maxSize;
double toneFrequency=1500.0;
if(m_nsps==6) {
toneFrequency=1000.0;
@ -152,21 +159,28 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
qint16 * end (samples + numFrames * (bytesPerFrame () / sizeof (qint16)));
qint64 framesGenerated (0);
// if(m_ic==0) qDebug() << "Modulator::readData" << 0.001*(QDateTime::currentMSecsSinceEpoch() % (1000*m_TRperiod));
// if(m_ic==0) qDebug() << "aa" << 0.001*(QDateTime::currentMSecsSinceEpoch() % qint64(1000*m_TRperiod))
// << m_state << m_TRperiod << m_silentFrames << m_ic << foxcom_.wave[m_ic];
switch (m_state)
{
case Synchronizing:
{
if (m_silentFrames) { // send silence up to first second
if (m_silentFrames) { // send silence up to end of start delay
framesGenerated = qMin (m_silentFrames, numFrames);
for ( ; samples != end; samples = load (0, samples)) { // silence
}
m_silentFrames -= framesGenerated;
return framesGenerated * bytesPerFrame ();
do
{
samples = load (0, samples); // silence
} while (--m_silentFrames && samples != end);
qDebug () << "played:" << framesGenerated << "silent frames";
if (!m_silentFrames)
{
Q_EMIT stateChanged ((m_state = Active));
}
}
Q_EMIT stateChanged ((m_state = Active));
// qDebug() << "m_silentFrames:" << m_silentFrames << "m_ic:" << m_ic << "m_state:" << m_state;
m_cwLevel = false;
m_ramp = 0; // prepare for CW wave shaping
}
@ -260,7 +274,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
qint16 sample;
for (unsigned i = 0; i < numFrames && m_ic <= i1; ++i) {
while (samples != end && m_ic <= i1) {
isym=0;
if(!m_tuning and m_TRperiod!=3.0) isym=m_ic/(4.0*m_nsps); //Actual fsample=48000
if(m_bFastMode) isym=isym%m_symbolsLength;
@ -305,12 +319,19 @@ qint64 Modulator::readData (char * data, qint64 maxSize)
m_amp=32767.0;
sample=qRound(m_amp*foxcom_.wave[m_ic]);
}
/*
if((m_ic<1000 or (4*m_symbolsLength*m_nsps - m_ic) < 1000) and (m_ic%10)==0) {
qDebug() << "cc" << QDateTime::currentDateTimeUtc().toString("hh:mm:ss.zzz") << m_ic << sample;
}
*/
samples = load(postProcessSample(sample), samples);
++framesGenerated;
++m_ic;
}
// qDebug() << "dd" << QDateTime::currentDateTimeUtc().toString("hh:mm:ss.zzz")
// << m_ic << i1 << foxcom_.wave[m_ic] << framesGenerated;
if (m_amp == 0.0) { // TODO G4WJS: compare double with zero might not be wise
if (icw[0] == 0) {
// no CW ID to send

View File

@ -35,7 +35,7 @@ public:
void set_nsym(int n) {m_symbolsLength=n;}
void set_ms0(qint64 ms) {m_ms0=ms;}
Q_SLOT void start (unsigned symbolsLength, double framesPerSymbol, double frequency,
Q_SLOT void start (QString mode, unsigned symbolsLength, double framesPerSymbol, double frequency,
double toneSpacing, SoundOutput *, Channel = Mono,
bool synchronize = true, bool fastMode = false,
double dBSNR = 99., double TRperiod=60.0);

3
Modulator/Modulator.pri Normal file
View File

@ -0,0 +1,3 @@
SOURCES += Modulator/Modulator.cpp
HEADERS += Modulator/Mpdulator.hpp

View File

@ -8,6 +8,8 @@
#include <QTimer>
#include <QFile>
#include <QRegExp>
#include <QRegularExpression>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
@ -18,215 +20,314 @@
namespace
{
char const * const wsprNetUrl = "http://wsprnet.org/post?";
// char const * const wsprNetUrl = "http://127.0.0.1/post?";
char const * const wsprNetUrl = "http://wsprnet.org/post/";
//char const * const wsprNetUrl = "http://127.0.0.1:5000/post/";
//
// tested with this python REST mock of WSPRNet.org
//
/*
# Mock WSPRNet.org RESTful API
from flask import Flask, request, url_for
from flask_restful import Resource, Api
app = Flask(__name__)
@app.route ('/post/', methods=['GET', 'POST'])
def spot ():
if request.method == 'POST':
print (request.form)
return "1 spot(s) added"
with app.test_request_context ():
print (url_for ('spot'))
*/
// regexp to parse FST4W decodes
QRegularExpression fst4_re {R"(
(?<time>\d{4})
\s+(?<db>[-+]?\d+)
\s+(?<dt>[-+]?\d+\.\d+)
\s+(?<freq>\d+)
\s+`
\s+<?(?<call>[A-Z0-9/]+)>?(?:\s(?<grid>[A-R]{2}[0-9]{2}(?:[A-X]{2})?))?(?:\s+(?<dBm>\d+))?
)", QRegularExpression::ExtendedPatternSyntaxOption};
// regexp to parse wspr_spots.txt from wsprd
//
// 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
QRegularExpression wspr_re(R"(^(\d+)\s+(\d+)\s+(\d+)\s+([+-]?\d+)\s+([+-]?\d+\.\d+)\s+(\d+\.\d+)\s+([^ ].*[^ ])\s+([+-]?\d+)\s+([+-]?\d+)\s+([+-]?\d+))");
};
WSPRNet::WSPRNet(QNetworkAccessManager * manager, QObject *parent)
: QObject{parent}
, networkManager {manager}
, uploadTimer {new QTimer {this}}
, m_urlQueueSize {0}
WSPRNet::WSPRNet (QNetworkAccessManager * manager, QObject *parent)
: QObject {parent}
, network_manager_ {manager}
, spots_to_send_ {0}
{
connect(networkManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(networkReply(QNetworkReply*)));
connect( uploadTimer, SIGNAL(timeout()), this, SLOT(work()));
connect (network_manager_, &QNetworkAccessManager::finished, this, &WSPRNet::networkReply);
connect (&upload_timer_, &QTimer::timeout, this, &WSPRNet::work);
}
void WSPRNet::upload(QString const& call, QString const& grid, QString const& rfreq, QString const& tfreq,
QString const& mode, QString const& tpct, QString const& dbm, QString const& version,
QString const& fileName)
void WSPRNet::upload (QString const& call, QString const& grid, QString const& rfreq, QString const& tfreq,
QString const& mode, float TR_period, QString const& tpct, QString const& dbm,
QString const& version, QString const& 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;
m_call = call;
m_grid = grid;
m_rfreq = rfreq;
m_tfreq = tfreq;
m_mode = mode;
TR_period_ = TR_period;
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;
// Open the wsprd.out file
QFile wsprdOutFile (fileName);
if (!wsprdOutFile.open (QIODevice::ReadOnly | QIODevice::Text) || !wsprdOutFile.size ())
{
spot_queue_.enqueue (urlEncodeNoSpot ());
m_uploadType = 1;
}
// 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;
else
{
// Read the contents
while (!wsprdOutFile.atEnd())
{
SpotQueue::value_type query;
if (decodeLine (wsprdOutFile.readLine(), query))
{
// Prevent reporting data ouside of the current frequency band
float f = fabs (m_rfreq.toFloat() - query.queryItemValue ("tqrg", QUrl::FullyDecoded).toFloat());
if (f < 0.0002)
{
spot_queue_.enqueue(urlEncodeSpot (query));
m_uploadType = 2;
}
}
}
}
}
m_urlQueueSize = urlQueue.size();
uploadTimer->start(200);
spots_to_send_ = spot_queue_.size ();
upload_timer_.start (200);
}
void WSPRNet::networkReply(QNetworkReply *reply)
void WSPRNet::post (QString const& call, QString const& grid, QString const& rfreq, QString const& tfreq,
QString const& mode, float TR_period, QString const& tpct, QString const& dbm,
QString const& version, QString const& decode_text)
{
m_call = call;
m_grid = grid;
m_rfreq = rfreq;
m_tfreq = tfreq;
m_mode = mode;
TR_period_ = TR_period;
m_tpct = tpct;
m_dbm = dbm;
m_vers = version;
if (!decode_text.size ())
{
if (!spot_queue_.size ())
{
spot_queue_.enqueue (urlEncodeNoSpot ());
m_uploadType = 1;
}
spots_to_send_ = spot_queue_.size ();
upload_timer_.start (200);
}
else
{
auto const& match = fst4_re.match (decode_text);
if (match.hasMatch ())
{
SpotQueue::value_type query;
// Prevent reporting data ouside of the current frequency band
auto tqrg = match.captured ("freq").toInt ();
if (tqrg >= 1400 && tqrg <= 1600)
{
query.addQueryItem ("function", "wspr");
// use time as at 3/4 of T/R period before current to
// ensure date is in Rx period
auto const& date = QDateTime::currentDateTimeUtc ().addSecs (-TR_period * 3. / 4.).date ();
query.addQueryItem ("date", date.toString ("yyMMdd"));
query.addQueryItem ("time", match.captured ("time"));
query.addQueryItem ("sig", match.captured ("db"));
query.addQueryItem ("dt", match.captured ("dt"));
query.addQueryItem ("tqrg", QString::number (rfreq.toDouble () + (tqrg - 1500) / 1e6, 'f', 6));
query.addQueryItem ("tcall", match.captured ("call"));
query.addQueryItem ("drift", "0");
query.addQueryItem ("tgrid", match.captured ("grid"));
query.addQueryItem ("dbm", match.captured ("dBm"));
spot_queue_.enqueue (urlEncodeSpot (query));
m_uploadType = 2;
}
}
}
}
void WSPRNet::networkReply (QNetworkReply * reply)
{
// check if request was ours
if (m_outstandingRequests.removeOne (reply)) {
if (QNetworkReply::NoError != reply->error ()) {
Q_EMIT uploadStatus (QString {"Error: %1"}.arg (reply->error ()));
// not clearing queue or halting queuing as it may be a transient
// one off request error
}
else {
QString serverResponse = reply->readAll();
if( m_uploadType == 2) {
if (!serverResponse.contains(QRegExp("spot\\(s\\) added"))) {
emit uploadStatus(QString {"Upload Failed: %1"}.arg (serverResponse));
urlQueue.clear();
uploadTimer->stop();
if (m_outstandingRequests.removeOne (reply))
{
if (QNetworkReply::NoError != reply->error ())
{
Q_EMIT uploadStatus (QString {"Error: %1"}.arg (reply->error ()));
// not clearing queue or halting queuing as it may be a
// transient one off request error
}
}
else
{
QString serverResponse = reply->readAll ();
if (m_uploadType == 2)
{
if (!serverResponse.contains(QRegExp("spot\\(s\\) added")))
{
Q_EMIT uploadStatus (QString {"Upload Failed: %1"}.arg (serverResponse));
spot_queue_.clear ();
upload_timer_.stop ();
}
}
if (urlQueue.isEmpty()) {
emit uploadStatus("done");
QFile::remove(m_file);
uploadTimer->stop();
}
if (!spot_queue_.size ())
{
Q_EMIT uploadStatus("done");
QFile f {m_file};
if (f.exists ()) f.remove ();
upload_timer_.stop ();
}
}
qDebug () << QString {"WSPRnet.org %1 outstanding requests"}.arg (m_outstandingRequests.size ());
// delete request object instance on return to the event loop otherwise it is leaked
reply->deleteLater ();
}
}
bool WSPRNet::decodeLine (QString const& line, SpotQueue::value_type& query)
{
auto const& rx_match = wspr_re.match (line);
if (rx_match.hasMatch ()) {
int msgType = 0;
QString msg = rx_match.captured (7);
QString call, grid, dbm;
QRegularExpression msgRx;
// Check for Message Type 1
msgRx.setPattern(R"(^([A-Z0-9]{3,6})\s+([A-R]{2}\d{2})\s+(\d+))");
auto match = msgRx.match (msg);
if (match.hasMatch ()) {
msgType = 1;
call = match.captured (1);
grid = match.captured (2);
dbm = match.captured (3);
}
qDebug () << QString {"WSPRnet.org %1 outstanding requests"}.arg (m_outstandingRequests.size ());
// Check for Message Type 2
msgRx.setPattern(R"(^([A-Z0-9/]+)\s+(\d+))");
match = msgRx.match (msg);
if (match.hasMatch ()) {
msgType = 2;
call = match.captured (1);
grid = "";
dbm = match.captured (2);
}
// delete request object instance on return to the event loop otherwise it is leaked
reply->deleteLater ();
// Check for Message Type 3
msgRx.setPattern(R"(^<([A-Z0-9/]+)>\s+([A-R]{2}\d{2}[A-X]{2})\s+(\d+))");
match = msgRx.match (msg);
if (match.hasMatch ()) {
msgType = 3;
call = match.captured (1);
grid = match.captured (2);
dbm = match.captured (3);
}
// Unknown message format
if (!msgType) {
return false;
}
query.addQueryItem ("function", "wspr");
query.addQueryItem ("date", rx_match.captured (1));
query.addQueryItem ("time", rx_match.captured (2));
query.addQueryItem ("sig", rx_match.captured (4));
query.addQueryItem ("dt", rx_match.captured(5));
query.addQueryItem ("drift", rx_match.captured(8));
query.addQueryItem ("tqrg", rx_match.captured(6));
query.addQueryItem ("tcall", call);
query.addQueryItem ("tgrid", grid);
query.addQueryItem ("dbm", dbm);
} else {
return false;
}
return true;
}
bool WSPRNet::decodeLine(QString const& line, QHash<QString,QString> &query)
auto WSPRNet::urlEncodeNoSpot () -> SpotQueue::value_type
{
// 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;
SpotQueue::value_type query;
query.addQueryItem ("function", "wsprstat");
query.addQueryItem ("rcall", m_call);
query.addQueryItem ("rgrid", m_grid);
query.addQueryItem ("rqrg", m_rfreq);
query.addQueryItem ("tpct", m_tpct);
query.addQueryItem ("tqrg", m_tfreq);
query.addQueryItem ("dbm", m_dbm);
query.addQueryItem ("version", m_vers);
if (m_mode == "WSPR") query.addQueryItem ("mode", "2");
if (m_mode == "WSPR-15") query.addQueryItem ("mode", "15");
if (m_mode == "FST4W")
{
query.addQueryItem ("mode", QString::number (static_cast<int> ((TR_period_ / 60.)+.5)));
}
return true;
return query;;
}
QString WSPRNet::urlEncodeNoSpot()
auto WSPRNet::urlEncodeSpot (SpotQueue::value_type& query) -> SpotQueue::value_type
{
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") queryString += "&mode=2";
if(m_mode=="WSPR-15") queryString += "&mode=15";
return queryString;;
}
QString WSPRNet::urlEncodeSpot(QHash<QString,QString> const& 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") queryString += "&mode=2";
if(m_mode=="WSPR-15") queryString += "&mode=15";
return queryString;
query.addQueryItem ("version", m_vers);
query.addQueryItem ("rcall", m_call);
query.addQueryItem ("rgrid", m_grid);
query.addQueryItem ("rqrg", m_rfreq);
if (m_mode == "WSPR") query.addQueryItem ("mode", "2");
if (m_mode == "WSPR-15") query.addQueryItem ("mode", "15");
if (m_mode == "FST4W")
{
query.addQueryItem ("mode", QString::number (static_cast<int> ((TR_period_ / 60.)+.5)));
}
return query;
}
void WSPRNet::work()
{
if (!urlQueue.isEmpty()) {
if (spots_to_send_ && spot_queue_.size ())
{
#if QT_VERSION < QT_VERSION_CHECK (5, 15, 0)
if (QNetworkAccessManager::Accessible != networkManager->networkAccessible ()) {
// try and recover network access for QNAM
networkManager->setNetworkAccessible (QNetworkAccessManager::Accessible);
}
if (QNetworkAccessManager::Accessible != network_manager_->networkAccessible ()) {
// try and recover network access for QNAM
network_manager_->setNetworkAccessible (QNetworkAccessManager::Accessible);
}
#endif
QUrl url(urlQueue.dequeue());
QNetworkRequest request(url);
m_outstandingRequests << networkManager->get(request);
emit uploadStatus(QString {"Uploading Spot %1/%2"}.arg (m_urlQueueSize - urlQueue.size()).arg (m_urlQueueSize));
} else {
uploadTimer->stop();
}
QNetworkRequest request (QUrl {wsprNetUrl});
request.setHeader (QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
auto const& spot = spot_queue_.dequeue ();
m_outstandingRequests << network_manager_->post (request, spot.query (QUrl::FullyEncoded).toUtf8 ());
Q_EMIT uploadStatus(QString {"Uploading Spot %1/%2"}.arg (spots_to_send_ - spot_queue_.size()).arg (spots_to_send_));
}
else
{
upload_timer_.stop ();
}
}
void WSPRNet::abortOutstandingRequests () {
urlQueue.clear ();
spot_queue_.clear ();
for (auto& request : m_outstandingRequests) {
request->abort ();
}
m_urlQueueSize = 0;
}

View File

@ -2,45 +2,58 @@
#define WSPRNET_H
#include <QObject>
#include <QTimer>
#include <QString>
#include <QList>
#include <QHash>
#include <QUrlQuery>
#include <QQueue>
class QNetworkAccessManager;
class QTimer;
class QNetworkReply;
class WSPRNet : public QObject
{
Q_OBJECT;
Q_OBJECT
using SpotQueue = QQueue<QUrlQuery>;
public:
explicit WSPRNet(QNetworkAccessManager *, QObject *parent = nullptr);
void upload(QString const& call, QString const& grid, QString const& rfreq, QString const& tfreq,
QString const& mode, QString const& tpct, QString const& dbm, QString const& version,
QString const& fileName);
static bool decodeLine(QString const& line, QHash<QString,QString> &query);
explicit WSPRNet (QNetworkAccessManager *, QObject *parent = nullptr);
void upload (QString const& call, QString const& grid, QString const& rfreq, QString const& tfreq,
QString const& mode, float TR_peirod, QString const& tpct, QString const& dbm,
QString const& version, QString const& fileName);
void post (QString const& call, QString const& grid, QString const& rfreq, QString const& tfreq,
QString const& mode, float TR_period, QString const& tpct, QString const& dbm,
QString const& version, QString const& decode_text = QString {});
signals:
void uploadStatus(QString);
void uploadStatus (QString);
public slots:
void networkReply(QNetworkReply *);
void work();
void abortOutstandingRequests ();
void networkReply (QNetworkReply *);
void work ();
void abortOutstandingRequests ();
private:
QNetworkAccessManager *networkManager;
QList<QNetworkReply *> m_outstandingRequests;
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;
bool decodeLine (QString const& line, SpotQueue::value_type& query);
SpotQueue::value_type urlEncodeNoSpot ();
SpotQueue::value_type urlEncodeSpot (SpotQueue::value_type& spot);
QString urlEncodeNoSpot();
QString urlEncodeSpot(QHash<QString,QString> const& spot);
QNetworkAccessManager * network_manager_;
QList<QNetworkReply *> m_outstandingRequests;
QString m_call;
QString m_grid;;
QString m_rfreq;
QString m_tfreq;
QString m_mode;
QString m_tpct;
QString m_dbm;
QString m_vers;
QString m_file;
float TR_period_;
int spots_to_send_;
SpotQueue spot_queue_;
QTimer upload_timer_;
int m_uploadType;
};
#endif // WSPRNET_H

View File

@ -2,7 +2,7 @@
#define COMMONS_H
#define NSMAX 6827
#define NTMAX 300
#define NTMAX 30*60
#define RX_SAMPLE_RATE 12000
#ifdef __cplusplus
@ -85,7 +85,7 @@ extern struct {
} echocom_;
extern struct {
float wave[606720];
float wave[(160+2)*134400*4]; /* (nsym+2)*nsps scaled up to 48kHz */
int nslots;
int nfreq;
int i3bit[5];

View File

@ -1,25 +1,26 @@
Here are the "displayWidgets()" strings for WSJT-X modes
1 2 3
012345678901234567890123456789012
0123456789012345678901234567890123
----------------------------------------------
JT4 111010000000110000110000000000000
JT4/VHF 111110010010110110111100000000000
JT9 111010000000111000010000000000001
JT9/VHF 111110101000111110010000000000000
JT9+JT65 111010000001111000010000000000001
JT65 111010000000111000010000000000001
JT65/VHF 111110010000110110101100010000000
QRA64 111110010110110110000000001000000
ISCAT 100111000000000110000000000000000
MSK144 101111110100000000010001000000000
WSPR 000000000000000001010000000000000
Echo 000000000000000000000010000000000
FCal 001101000000000000000000000001000
FT8 111010000100111000010000100110001
FT8/VHF 111010000100111000010000100110001
FT8/Fox 111010000100111000010000000000100
FT8/Hound 111010000100111000010000000000110
JT4 1110100000001100001100000000000000
JT4/VHF 1111100100101101101111000000000000
JT9 1110100000001110000100000000000010
JT9/VHF 1111101010001111100100000000000000
JT9+JT65 1110100000011110000100000000000010
JT65 1110100000001110000100000000000010
JT65/VHF 1111100100001101101011000100000000
QRA64 1111100101101101100000000010000000
ISCAT 1001110000000001100000000000000000
MSK144 1011111101000000000100010000000000
WSPR 0000000000000000010100000000000000
FST4W 0000000000000000010100000000000001
Echo 0000000000000000000000100000000000
FCal 0011010000000000000000000000010000
FT8 1110100001001110000100001001100010
FT8/VHF 1110100001001110000100001001100010
FT8/Fox 1110100001001110000100000000001000
FT8/Hound 1110100001001110000100000000001100
----------------------------------------------
1 2 3
012345678901234567890123456789012
@ -60,3 +61,4 @@ Mapping of column numbers to widgets
30. labDXped
31. cbRxAll
32. cbCQonly
33. sbTR_FST4W

View File

@ -1,4 +1,4 @@
// Status=review
// Status=edited
A *Status Bar* at the bottom edge of the main window provides useful
information about operating conditions.
@ -9,15 +9,15 @@ image::status-bar-a.png[align="left",alt="Status Bar"]
Labels on the *Status Bar* display such information as the program's
current operating state, configuration name, operating mode, and the
content of your most recent transmitted message. The first label
(operating state) can be Receiving, Tx (for Transmitting), Tune, or
the name of file opened from the *File* menu; this label is
(operating state) can be Receiving, Tx (for Transmitting), Tx: Tune, or
the name of the file opened from the *File* menu. This label is
highlighted in green for Receiving, yellow for Tx, red for Tune, and
light blue for a file name. When transmitting, the Tx message is
displayed exactly as it will be decoded by receiving stations. The
second label (as shown above) will be absent if you are using the
*Default* setting on the *Configurations* menu. A progress bar shows
the elapsed fraction of a Tx or Rx sequence. Finally, if the Watchdog
(WD) timer was enabled on the *Settings | General* tab, a label in the
(WD) timer was enabled on the *Files | Settings | General* tab, a label in the
lower right-hand corner displays the number of minutes remaining
before timeout.

View File

@ -1,4 +1,4 @@
// Status=review
// Status=edited
The following controls appear at the bottom of the Wide Graph window.
Decoding occurs only in the displayed frequency range; otherwise, with
@ -29,7 +29,7 @@ slower, as desired.
- A dropdown list below the *Palette* label lets you select from a
wide range of waterfall color palettes.
- Click *Adjust* to activate a window that allows you to create a
- Click *Adjust* to activate a window that allows you to import or export a
user-defined palette.
- Check *Flatten* if you want _WSJT-X_ to compensate for a sloping or
@ -50,10 +50,10 @@ about right, depending on the input signal level, the chosen palette,
and your own preferences. Hover the mouse over a control to display a
tip reminding you of its function.
- The *Spec nn%* control may be used to set the fractional height of
- The *Spec nn%* control is used to set the fractional height of
the spectrum plotted below the waterfall.
- *Smooth* is active only when *Linear Average* has been selected.
- *Smooth* is active only when *Linear Average* is selected.
Smoothing the displayed spectrum over more than one bin can enhance
your ability to detect weak EME signals with Doppler spread more than
a few Hz.
@ -66,7 +66,7 @@ selected on the Wide Graph. Three sliders at the bottom of the Fast
Graph window can be used to optimize gain and zero-offset for the
displayed information. Hover the mouse over a control to display a
tip reminding you of its function. Clicking the *Auto Level* button
will produce reasonable settings as a starting point.
produces reasonable settings as a starting point.
image::fast-graph-controls.png[align="center",alt="Fast Graph Controls"]
@ -89,7 +89,7 @@ spectra, thereby smoothing the curves over multiple bins.
- Label *N* shows the number of echo pulses averaged.
- Click the *Colors* button to cycle through 6 possible choices of
- Click the *Colors* button to cycle through six possible choices of
color and line width for the plots.
[[CONTROLS_MISCELLANEOUS]]

View File

@ -1,3 +1,5 @@
// Status: edited
_WSJT-X_ is programmed to cooperate closely with several other useful
programs.
@ -38,10 +40,10 @@ logging applications Aether, MacLoggerDX, RUMlog or RUMlogNG. It
checks QSO and QSL status of the call and DXCC entity, as well as many
other features.
* {n1mm_logger} is a free full feature contest logging application. It
* {n1mm_logger} is a free, full-feature contest logging application. It
is only available for Windows. _WSJT-X_ can send logged QSO
information to it via a network connection.
* {writelog} is a non-free full feature contest logging
* {writelog} is a non-free, full-feature contest logging
application. It is only available for Windows. _WSJT-X_ can send
logged QSO information to it via a network connection.

View File

@ -1,19 +1,21 @@
[[AP_Decoding]]
// Status: edited
=== AP Decoding
The _WSJT-X_ decoders for FT4, FT8, JT65, and QRA64 include optional
procedures that take advantage of naturally accumulating information
during a minimal QSO. This _a priori_ (AP) information increases
sensitivity of the decoder by up to 4 dB, at the cost of a slightly
higher rate of false decodes.
The _WSJT-X_ decoders for FT4, FT8, JT65, QRA64, include
procedures that use naturally accumulating information during a
minimal QSO. This _a priori_ (AP) information increases sensitivity
of the decoder by up to 4 dB, at the cost of a slightly higher rate of
false decodes. AP is optional in FT8, JT65, and QRA64, but is always
enabled for FT4.
For example: when you decide to answer a CQ, you already know your own
callsign and that of your potential QSO partner. The software
therefore "`knows`" what might be expected for at least 57 message
bits (28 for each of two callsigns, 1 or more for message type) in the
next received message. The decoder's task can thus be reduced to
bits (28 for each of two callsigns, one or more for message type) in the
next received message. The decoder's task is thus reduced to
determining the remaining 15 bits of the message and ensuring that the
resulting solution is consistent with the message's parity symbols.
resulting solution is reliable.
AP decoding starts by setting AP bits to the hypothesized values, as
if they had been received correctly. We then determine whether the
@ -21,12 +23,12 @@ remaining message and parity bits are consistent with the hypothesized
AP bits, with a specified level of confidence. Successful AP decodes
are labeled with an end-of-line indicator of the form `aP`, where `P`
is one of the single-digit AP decoding types listed in Table 1. For
example, `a2` indicates that the successful decode used *MyCall* as
example, `a2` indicates that the successful decode used MyCall as
hypothetically known information.
[[FT8_AP_INFO_TABLE]]
.FT4 and FT8 AP information types
[width="50%",cols="h10,<m20",frame=topbot,options="header"]
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===============================================
|aP | Message components
|a1 | CQ &#160; &#160; ? &#160; &#160; ?
@ -49,7 +51,7 @@ be attempted in each state.
[[FT8_AP_DECODING_TYPES_TABLE]]
.FT4 and FT8 AP decoding types for each QSO state
[width="50%",cols="h10,<m20",frame=topbot,options="header"]
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===========================================
|State |AP type
|CALLING STN | 2, 3
@ -60,14 +62,12 @@ be attempted in each state.
|CALLING CQ | 1, 2
|===========================================
Decoding with _a priori_ information behaves slightly differently in
JT65. Some details are provided in Tables 3 and 4. Notations such as
`a63`, use a second digit to indicate the number of Rx intervals
averaged to obtain the decode.
Decoding with _a priori_ information behaves slightly differently
in JT65. Some details are provided in Tables 3 and 4.
[[JT65_AP_INFO_TABLE]]
.JT65 AP information types
[width="50%",cols="h10,<m20",frame=topbot,options="header"]
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===============================================
|aP | Message components
|a1 | CQ &#160; &#160; ? &#160; &#160; ?
@ -81,7 +81,7 @@ averaged to obtain the decode.
[[JT65_AP_DECODING_TYPES_TABLE]]
.JT65 AP decoding types for each QSO state
[width="50%",cols="h10,<m20",frame=topbot,options="header"]
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===========================================
|State |AP type
|CALLING STN | 2, 3, 6, 7
@ -93,7 +93,6 @@ averaged to obtain the decode.
|===========================================
[[Decoded_Lines]]
=== Decoded Lines
Displayed information accompanying decoded messages generally includes UTC,
@ -110,7 +109,7 @@ summarized in the following Table:
[width="50%",cols="h,3*^",frame=topbot,options="header"]
|===========================================
|Mode |Mode character|Sync character|End of line information
|FT4 | + | | ? &#160; aP
|FT4 | ~ | | ? &#160; aP
|FT8 | ~ | | ? &#160; aP
|JT4 | $ | *, # | f, fN, dCN
|JT9 | @ | |
@ -126,7 +125,7 @@ Sync character::
End of line information::
`?` - Decoded with lower confidence +
`a` - Decoded with aid of some a priori (AP) information +
`a` - Decoded with aid of some _a priori_ (AP) information +
`C` - Confidence indicator [ISCAT and Deep Search; (0-9,*)] +
`d` - Deep Search algorithm +
`f` - Franke-Taylor or Fano algorithm +
@ -140,7 +139,7 @@ Table 6 below shows the meaning of the return codes R in QRA64 mode.
[[QRA64_AP_INFO_TABLE]]
.QRA64 AP return codes
[width="50%",cols="h10,<m20",frame=topbot,options="header"]
[width="35%",cols="h10,<m20",frame=topbot,options="header"]
|===============================================
|rc | Message components
|0 | ? &#160; &#160; ? &#160; &#160; ?

View File

@ -1,10 +1,12 @@
// Status: edited
////
Questions:
Should be short one liners (in the .adoc file) ending with ?::
If your question is too long for one line, consider multiple questions or rephrase
Should be short one-liners (in the .adoc file) ending with ?::
If your question is too long for one line, consider multiple questions or rephrase.
Answers:
Can be bullet or paragraphs. Bullets make for easier reading.
Can be bullets or paragraphs. Bullets make for easier reading.
Bullet Usage:
* = a circle bullet single intent
@ -53,19 +55,18 @@ You need to install suitable _OpenSSL_ libraries - see <<OPENSSL,Instructions to
I occasionally get Rig Control Errors if I adjust my Icom rig's VFO. What's wrong?::
By default, most Icom transceivers have *CI-V Tranceive Mode" enabled,
this will cause unsolicited CAT traffic from the rig that disrupts CAT
By default, most Icom transceivers have *CI-V Transceive Mode" enabled. This will cause unsolicited CAT traffic from the rig that disrupts CAT
control by a PC. Disable this option in the rig's menu.
I want to control my transceiver with another application as well as _WSJT-X_, is that possible?::
This only possible to do reliably via some kind of rig control server,
that server must be able to accept both _WSJT-X_ and the other
This only possible to do reliably via some kind of rig control server.
That server must be able to accept both _WSJT-X_ and the other
application(s) as clients. Using a dumb serial port splitter like the
VSPE tool is not supported, it may work but it is not reliable due to
VSPE tool is not supported; it may work but it is not reliable due to
unmanaged CAT control collisions. Applications like the _Hamlib Rig
Control Server (rigctld)_, _{omnirig}_, and _{dxlsuite} Commander_ are
potentially suitable and _WSJT-X_ can act as a client to them all.
potentially suitable; _WSJT-X_ can act as a client to them all.
Rig control through _OmniRig_ seems to fail when I click *Test CAT*. What can I do about it?::
@ -79,7 +80,7 @@ You may see delays up to 20 seconds or so in frequency changes or
other radio commands, due to a bug in HRD. HRD folks are aware of the
problem, and are working to resolve it.
I am running _WSJT-X_ under Ubuntu. The program starts, but menu bar is missing from the top of the main window and the hot-keys don't work.::
I am running _WSJT-X_ under Ubuntu. The program starts, but the menu bar is missing from the top of the main window and the hot-keys don't work.::
Ubuntu's new "`Unity`" desktop puts the menu for the currently active
window at the top of the primary display screen. You can restore menu
@ -100,10 +101,10 @@ I am running _WSJT-X_ on Linux using a KDE desktop. Why does *Menu->Configuratio
The KDE development team have added code to Qt that tries to
automatically add shortcut accelerator keys to all buttons including
pop up menu buttons, this interferes with operation of the application
pop up menu buttons. This interferes with operation of the application
(many other Qt applications have similar issues with KDE). Until this
is fixed by the KDE team you must disable this misfeature. Edit the
file ~/.config/kdeglobals and add a section containing the following:
is fixed by the KDE team you must disable this feature. Edit the
file `~/.config/kdeglobals` and add a section containing the following:
[Development]
AutoCheckAccelerators=false

View File

@ -38,8 +38,8 @@ FN42`, it means that s/he will listen on 50.290 and respond there to
any replies.) A numerical signal report of the form `nn` or
`Rnn` can be sent in place of a grid locator. (As originally
defined, numerical signal reports `nn` were required to fall between -01
and -30 dB. Recent program versions accommodate reports between
-50 and +49 dB.) A country prefix or portable suffix may be
and -30 dB. Program versions 2.3 and later accommodate reports between
-50 and +50 dB.) A country prefix or portable suffix may be
attached to one of the callsigns. When this feature is used the
additional information is sent in place of the grid locator or by
encoding additional information into some of the 6 million available

View File

@ -65,12 +65,18 @@ starts. This feature can be used to activate an automatic antenna
tuner (ATU) to tune a multi-band antenna to the newly selected band.
- Depending on your station and antenna setup, band changes might
require other switching besides retuning your radio. To make this
require other switching besides retuning your radio. To make this
possible in an automated way, whenever _WSJT-X_ executes a successful
band-change command to a CAT-controlled radio, it looks for a file
named `user_hardware.bat`, `user_hardware.cmd`, `user_hardware.exe`,
or `user_hardware` in the working directory. If one of these is found,
_WSJT-X_ tries to execute the command
band-change command to a CAT-controlled radio, it looks for an
executable file or script named `user_hardware`. This is done using
`CMD /C user_hardware <band>` on Windows, or `/bin/sh -c user_hardware
<band>` on other platforms, where band is described below. On Windows
the first file with any extension listed on the PATHEXT environment
variable added to the file name root `user_hardware`, and found in the
directories listed on the PATH environment variable will be executed.
On other platforms, the first executable script, or program, named
`user_hardware` found in a directory listed on the PATH environment
variable will be executed.
user_hardware nnn
@ -78,6 +84,11 @@ _WSJT-X_ tries to execute the command
meters. You must write your own program, script, or batch file to do
the necessary switching at your station.
IMPORTANT: The use of the PATH (and PATHEXT on Windows) environment
variables is a new feature. To emulate previous behavior make sure
that the location of your user_hardware script or program is on the
PATH environment variable used by _WSJT-X_.
The following screen shot is an example of WSPR operation with
band hopping enabled:

21
lib/77bit/call_to_c28.f90 Normal file
View File

@ -0,0 +1,21 @@
program call_to_c28
parameter (NTOKENS=2063592,MAX22=4194304)
character*6 call_std
character a1*37,a2*36,a3*10,a4*27
data a1/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'/
data a2/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'/
data a3/'0123456789'/
data a4/' ABCDEFGHIJKLMNOPQRSTUVWXYZ'/
! call_std must be right adjusted, length 6
call_std=' K1ABC' !Redefine as needed
i1=index(a1,call_std(1:1))-1
i2=index(a2,call_std(2:2))-1
i3=index(a3,call_std(3:3))-1
i4=index(a4,call_std(4:4))-1
i5=index(a4,call_std(5:5))-1
i6=index(a4,call_std(6:6))-1
n28=NTOKENS + MAX22 + 36*10*27*27*27*i1 + 10*27*27*27*i2 + &
27*27*27*i3 + 27*27*i4 + 27*i5 + i6
write(*,1000) call_std,n28
1000 format('Callsign: ',a6,2x,'c28 as decimal integer:',i10)
end program call_to_c28

58
lib/77bit/free_text.f90 Normal file
View File

@ -0,0 +1,58 @@
program free_text
character*13 c13,w
character*71 f71
character*42 c
character*1 qa(10),qb(10)
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+-./?'/
c13='TNX BOB 73 GL' !Redefine as needed
call mp_short_init
qa=char(0)
w=adjustr(c13)
do i=1,13
j=index(c,w(i:i))-1
if(j.lt.0) j=0
call mp_short_mult(qb,qa(2:10),9,42) !qb(1:9)=42*qa(2:9)
call mp_short_add(qa,qb(2:10),9,j) !qa(1:9)=qb(2:9)+j
enddo
write(f71,1000) qa(2:10)
1000 format(b7.7,8b8.8)
write(*,1010) c13,f71
1010 format('Free text: ',a13/'f71: ',a71)
end program free_text
subroutine mp_short_ops(w,u)
! Multi-precision arithmetic with storage in character arrays.
character*1 w(*),u(*)
integer i,ireg,j,n,ir,iv,ii1,ii2
character*1 creg(4)
save ii1,ii2
equivalence (ireg,creg)
entry mp_short_init
ireg=256*ichar('2')+ichar('1')
do j=1,4
if (creg(j).eq.'1') ii1=j
if (creg(j).eq.'2') ii2=j
enddo
return
entry mp_short_add(w,u,n,iv)
ireg=256*iv
do j=n,1,-1
ireg=ichar(u(j))+ichar(creg(ii2))
w(j+1)=creg(ii1)
enddo
w(1)=creg(ii2)
return
entry mp_short_mult(w,u,n,iv)
ireg=0
do j=n,1,-1
ireg=ichar(u(j))*iv+ichar(creg(ii2))
w(j+1)=creg(ii1)
enddo
w(1)=creg(ii2)
return
return
end subroutine mp_short_ops

View File

@ -0,0 +1,13 @@
program nonstd_to_c58
integer*8 n58
character*11 call_nonstd
character*38 c
data c/' 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/'/
call_nonstd='PJ4/K1ABC' !Redifine as needed
n58=0
do i=1,11
n58=n58*38 + index(c,call_nonstd(i:i)) - 1
enddo
write(*,1000) call_nonstd,n58
1000 format('Callsign: ',a11,2x,'c58 as decimal integer:',i20)
end program nonstd_to_c58

View File

@ -124,12 +124,14 @@ subroutine pack77(msg0,i3,n3,c77)
integer ntel(3)
msg=msg0
if(i3.eq.0 .and. n3.eq.5) go to 5
i3_hint=i3
n3_hint=n3
i3=-1
n3=-1
if(i3_hint.eq.0 .and. n3_hint.eq.5) go to 5
! Convert msg to upper case; collapse multiple blanks; parse into words.
call split77(msg,nwords,nw,w)
i3=-1
n3=-1
if(msg(1:3).eq.'CQ ' .or. msg(1:3).eq.'DE ' .or. msg(1:4).eq.'QRZ ') go to 100
! Check 0.1 (DXpedition mode)
@ -160,7 +162,7 @@ subroutine pack77(msg0,i3,n3,c77)
go to 900
endif
100 call pack77_06(nwords,w,i3,n3,c77)
100 call pack77_06(nwords,w,i3,n3,c77,i3_hint,n3_hint)
if(i3.ge.0) go to 900
! Check Type 1 (Standard 77-bit message) or Type 2, with optional "/P"
@ -203,7 +205,7 @@ subroutine unpack77(c77,nrx,msg,unpk77_success)
integer ntel(3)
character*77 c77
character*37 msg
character*13 call_1,call_2,call_3
character*13 call_1,call_2,call_3,call_1a
character*13 mycall13_0,dxcall13_0
character*11 c11
character*3 crpt,cntx,cpfx
@ -281,6 +283,10 @@ subroutine unpack77(c77,nrx,msg,unpk77_success)
call unpacktext77(c77(1:71),msg(1:13))
msg(14:)=' '
msg=adjustl(msg)
if(msg(1:1).eq.' ') then
unpk77_success=.false.
return
endif
else if(i3.eq.0 .and. n3.eq.1) then
! 0.1 K1ABC RR73; W9XYZ <KH1/KH7Z> -11 28 28 10 5 71 DXpedition Mode
@ -346,11 +352,11 @@ subroutine unpack77(c77,nrx,msg,unpk77_success)
msg=adjustl(msg)
else if(i3.eq.0 .and. n3.eq.6) then
read(c77(50:50),'(b1)') j2a
j2b=0
if(j2a.eq.0) read(c77(49:49),'(b1)') j2b
j2=2*j2a+j2b
if(j2.eq.0) then
read(c77(49:50),'(2b1)') j2a,j2b
itype=2
if(j2b.eq.0 .and. j2a.eq.0) itype=1
if(j2b.eq.0 .and. j2a.eq.1) itype=3
if(itype.eq.1) then
! WSPR Type 1
read(c77,2010) n28,igrid4,idbm
2010 format(b28.28,b15.15,b5.5)
@ -360,24 +366,17 @@ subroutine unpack77(c77,nrx,msg,unpk77_success)
call to_grid4(igrid4,grid4)
write(crpt,'(i3)') idbm
msg=trim(call_1)//' '//grid4//' '//trim(adjustl(crpt))
call save_hash_call(call_1,n10,n12,n22) !### Is this OK here? ###
else if(j2.eq.1) then
else if(itype.eq.2) then
! WSPR Type 2
read(c77,2030) n28,igrid6
2030 format(b22.22,b25.25)
call unpack28(n28,call_1,unpk28_success)
if(.not.unpk28_success) unpk77_success=.false.
call to_grid6(igrid6,grid6)
msg=trim(call_1)//' '//grid6
else if(j2.eq.2) then
! WSPR Type 3
read(c77,2020) n28,npfx,idbm
2020 format(b28.28,b16.16,b5.5)
idbm=nint(idbm*10.0/3.0)
call unpack28(n28,call_1,unpk28_success)
if(.not.unpk28_success) unpk77_success=.false.
write(crpt,'(i3)') idbm
cpfx=' '
if(npfx.lt.nzzz) then
! Prefix
do i=3,1,-1
@ -387,10 +386,11 @@ subroutine unpack77(c77,nrx,msg,unpk77_success)
if(npfx.eq.0) exit
enddo
msg=trim(adjustl(cpfx))//'/'//trim(call_1)//' '//trim(adjustl(crpt))
call_1a=trim(adjustl(cpfx))//'/'//trim(call_1)
call save_hash_call(call_1a,n10,n12,n22) !### Is this OK here? ###
else
! Suffix
npfx=npfx-nzzz
cpfx=' '
if(npfx.le.35) then
cpfx(1:1)=a2(npfx+1:npfx+1)
else if(npfx.gt.35 .and. npfx.le.1295) then
@ -405,7 +405,20 @@ subroutine unpack77(c77,nrx,msg,unpk77_success)
return
endif
msg=trim(call_1)//'/'//trim(adjustl(cpfx))//' '//trim(adjustl(crpt))
call_1a=trim(call_1)//'/'//trim(adjustl(cpfx))
call save_hash_call(call_1a,n10,n12,n22) !### Is this OK here? ###
endif
else if(itype.eq.3) then
! WSPR Type 3
read(c77,2030) n22,igrid6
2030 format(b22.22,b25.25)
n28=n22+2063592
call unpack28(n28,call_1,unpk28_success)
if(.not.unpk28_success) unpk77_success=.false.
call to_grid(igrid6,grid6)
msg=trim(call_1)//' '//grid6
endif
@ -446,7 +459,9 @@ subroutine unpack77(c77,nrx,msg,unpk77_success)
if(irpt.eq.3) msg=trim(call_1)//' '//trim(call_2)//' RR73'
if(irpt.eq.4) msg=trim(call_1)//' '//trim(call_2)//' 73'
if(irpt.ge.5) then
write(crpt,'(i3.2)') irpt-35
isnr=irpt-35
if(isnr.gt.50) isnr=isnr-101
write(crpt,'(i3.2)') isnr
if(crpt(1:1).eq.' ') crpt(1:1)='+'
if(ir.eq.0) msg=trim(call_1)//' '//trim(call_2)//' '//crpt
if(ir.eq.1) msg=trim(call_1)//' '//trim(call_2)//' R'//crpt
@ -897,7 +912,7 @@ subroutine pack77_03(nwords,w,i3,n3,c77)
ntx=-1
j=len(trim(w(nwords-1)))-1
read(w(nwords-1)(1:j),*,err=1) ntx !Number of transmitters
read(w(nwords-1)(1:j),*,err=1,end=1) ntx !Number of transmitters
1 if(ntx.lt.1 .or. ntx.gt.32) return
nclass=ichar(w(nwords-1)(j+1:j+1))-ichar('A')
@ -925,7 +940,7 @@ subroutine pack77_03(nwords,w,i3,n3,c77)
end subroutine pack77_03
subroutine pack77_06(nwords,w,i3,n3,c77)
subroutine pack77_06(nwords,w,i3,n3,c77,i3_hint,n3_hint)
character*13 w(19)
character*77 c77
@ -942,13 +957,14 @@ subroutine pack77_06(nwords,w,i3,n3,c77)
grid4(3:3).ge.'0' .and. grid4(3:3).le.'9' .and. &
grid4(4:4).ge.'0' .and. grid4(4:4).le.'9'
is_grid6(grid6)=len(trim(grid6)).eq.6 .and. &
is_grid6(grid6)=(len(trim(grid6)).eq.6.or.len(trim(grid6)).eq.4).and. &
grid6(1:1).ge.'A' .and. grid6(1:1).le.'R' .and. &
grid6(2:2).ge.'A' .and. grid6(2:2).le.'R' .and. &
grid6(3:3).ge.'0' .and. grid6(3:3).le.'9' .and. &
grid6(4:4).ge.'0' .and. grid6(4:4).le.'9' .and. &
grid6(5:5).ge.'A' .and. grid6(5:5).le.'X' .and. &
grid6(6:6).ge.'A' .and. grid6(6:6).le.'X'
(len(trim(grid6)).eq.4.or. &
(grid6(5:5).ge.'A' .and. grid6(5:5).le.'X' .and. &
grid6(6:6).ge.'A' .and. grid6(6:6).le.'X'))
is_digit(c)=c.ge.'0' .and. c.le.'9'
@ -1020,22 +1036,32 @@ subroutine pack77_06(nwords,w,i3,n3,c77)
go to 900
endif
if(nwords.eq.2 .and. m1.ge.5 .and. m1.le.12 .and. m2.le.6) then
if(i3_hint.eq.0.and.n3_hint.eq.6.and.nwords.eq.2 .and. m1.ge.5 &
.and. m1.le.12 .and. m2.le.6) then
! WSPR Type 3
!n3_hint=6 and i3_hint=0 is a hint that the caller wanted a
!50-bit encoding rather than the possible alternative n3=4 77-bit
!encoding
if(index(w(1),'<').lt.1 .or. index(w(1),'>').lt.1) go to 900
grid6=w(2)(1:6)
if(.not.is_grid6(grid6)) go to 900
i3=0
n3=6
call pack28(w(1),n28)
k1=(ichar(grid6(1:1))-ichar('A'))*18*10*10*24*24
k2=(ichar(grid6(2:2))-ichar('A'))*10*10*24*24
k3=(ichar(grid6(3:3))-ichar('0'))*10*24*24
k4=(ichar(grid6(4:4))-ichar('0'))*24*24
k5=(ichar(grid6(5:5))-ichar('A'))*24
k6=(ichar(grid6(6:6))-ichar('A'))
igrid6=k1+k2+k3+k4+k5+k6
write(c77,1030) n28,igrid6,2,0,n3,i3
n22=n28-2063592
k1=(ichar(grid6(1:1))-ichar('A'))*18*10*10*25*25
k2=(ichar(grid6(2:2))-ichar('A'))*10*10*25*25
k3=(ichar(grid6(3:3))-ichar('0'))*10*25*25
k4=(ichar(grid6(4:4))-ichar('0'))*25*25
if (grid6(5:6).eq.' ') then
igrid6=k1+k2+k3+k4+24*25+24
else
k5=(ichar(grid6(5:5))-ichar('A'))*25
k6=(ichar(grid6(6:6))-ichar('A'))
igrid6=k1+k2+k3+k4+k5+k6
endif
write(c77,1030) n22,igrid6,2,0,n3,i3
1030 format(b22.22,b25.25,b3.3,b21.21,2b3.3)
endif
@ -1083,10 +1109,12 @@ subroutine pack77_1(nwords,w,i3,n3,c77)
if(c1.eq.'+' .or. c1.eq.'-') then
ir=0
read(w(nwords),*,err=900) irpt
if(irpt.ge.-50 .and. irpt.le.-31) irpt=irpt+101
irpt=irpt+35
else if(c2.eq.'R+' .or. c2.eq.'R-') then
ir=1
read(w(nwords)(2:),*) irpt
if(irpt.ge.-50 .and. irpt.le.-31) irpt=irpt+101
irpt=irpt+35
else if(trim(w(nwords)).eq.'RRR') then
ir=0
@ -1507,4 +1535,31 @@ subroutine to_grid6(n,grid6)
return
end subroutine to_grid6
subroutine to_grid(n,grid6)
! 4-, or 6-character grid
character*6 grid6
j1=n/(18*10*10*25*25)
n=n-j1*18*10*10*25*25
j2=n/(10*10*25*25)
n=n-j2*10*10*25*25
j3=n/(10*25*25)
n=n-j3*10*25*25
j4=n/(25*25)
n=n-j4*25*25
j5=n/25
j6=n-j5*25
grid6=''
grid6(1:1)=char(j1+ichar('A'))
grid6(2:2)=char(j2+ichar('A'))
grid6(3:3)=char(j3+ichar('0'))
grid6(4:4)=char(j4+ichar('0'))
if (j5.ne.24.or.j6.ne.24) then
grid6(5:5)=char(j5+ichar('A'))
grid6(6:6)=char(j6+ichar('A'))
endif
return
end subroutine to_grid
end module packjt77

441
lib/C_interface_module.f90 Normal file
View File

@ -0,0 +1,441 @@
! FILE: c_interface_module.f90
! PURPOSE: Supplement ISO-C-Binding to provide type aliases and interfaces
! to common ISO-C string functions to aid working with strings.
! AUTHOR: Joseph M. Krahn
! STATUS: Still in development. Reasonably complete, but somewhat limited testing.
!
! The idea is to provide type aliases for all ISO-C types, so that the
! Fortran interface code more explicitly defines the actual C interface.
! This should be updated to support F2008 variable-length allocatable
! strings.
!
! Entity names all have the "C_" prefix, as with ISO-C-Binding, with a
! few exceptions.
!
! Sourced from: http://fortranwiki.org/fortran/show/c_interface_module
!
! One FORALL statement reverted to a DO loop to avoid a gfortran 4.9.2 ICE
!
module C_interface_module
use, intrinsic :: ISO_C_Binding, &
! C type aliases for pointer derived types:
C_ptr => C_ptr , &
C_char_ptr => C_ptr, &
C_const_char_ptr => C_ptr, &
C_void_ptr => C_ptr, &
C_const_void_ptr => C_ptr
implicit none
public
!----------------------------------------------------------------------------
! C type aliases for intrinsic type KIND parameters:
! NOTE: a C enum may not always be a standard C int
integer, parameter :: C_enum = C_int
! Defining off_t is difficult, because it may depend on "LARGEFILE" selection.
! integer, parameter :: C_off_t = ??
! C string terminator alais using the 3-letter ASCII name.
! The C_ prefix is not used because it is just an ASCII character.
character(len=1,kind=C_char), parameter :: NUL = C_NULL_char
! NOTE: In C, "char" is distinct from "signed char", unlike integers.
! The plain "char" type is specific for text/string values, whereas
! "signed char" should indicate 1-byte integer data.
!
! Most ISO-C systems have wide chars "wchar_t", but Fortran compilers
! have limited support for different character kinds. UTF encoding
! adds more complexity. This should be updated as Fortran compilers
! include support for more character types.
!
! Fortran does not (yet) support unsigned types.
integer, parameter :: &
C_unsigned = C_int, &
C_unsigned_short = C_short, &
C_unsigned_long = C_long, &
C_unsigned_long_long = C_long_long, &
C_unsigned_char = C_signed_char, &
C_ssize_t = C_size_t, &
C_uint8_t = C_int8_t, &
C_uint16_t = C_int16_t, &
C_uint32_t = C_int32_t, &
C_uint64_t = C_int64_t, &
C_uint_least8_t = C_int_least8_t, &
C_uint_least16_t = C_int_least16_t, &
C_uint_least32_t = C_int_least32_t, &
C_uint_least64_t = C_int_least64_t, &
C_uint_fast8_t = C_int_fast8_t, &
C_uint_fast16_t = C_int_fast16_t, &
C_uint_fast32_t = C_int_fast32_t, &
C_uint_fast64_t = C_int_fast64_t, &
C_uintmax_t = C_intmax_t
! Note: ptrdiff_t cannot be reliably defined from other types.
! When practical, it is larger than a pointer because it benefits
! from the full unsigned range in both positive and negative directions.
! Integer versions including 'int', where the 'int' is optional:
integer, parameter :: &
C_short_int = C_short, &
C_long_int = C_long, &
C_long_long_int = C_long_long, &
C_unsigned_int = C_unsigned, &
C_unsigned_short_int = C_short, &
C_unsigned_long_int = C_long, &
C_unsigned_long_long_int = C_long_long
interface C_F_string
module procedure C_F_string_ptr
module procedure C_F_string_chars
end interface C_F_string
interface F_C_string
module procedure F_C_string_ptr
module procedure F_C_string_chars
end interface F_C_string
!=======================================================================
! Some useful ISO C library string functions from <string.h>
! These are based on GCC header sections marked as NAMESPACE_STD
interface
! Copy N bytes of SRC to DEST, no aliasing or overlapping allowed.
! extern void *memcpy (void *dest, const void *src, size_t n);
function C_memcpy(dest, src, n) result(result) bind(C,name="memcpy")
import C_void_ptr, C_size_t
type(C_void_ptr) :: result
type(C_void_ptr), value, intent(in) :: dest ! target=intent(out)
type(C_void_ptr), value, intent(in) :: src ! target=intent(in)
integer(C_size_t), value, intent(in) :: n
end function C_memcpy
! Copy N bytes of SRC to DEST, guaranteeing correct behavior for overlapping strings.
!extern void *memmove (void *dest, const void *src, size_t n)
function C_memmove(dest, src, n) result(result) bind(C,name="memmove")
import C_void_ptr, C_size_t
type(C_void_ptr) :: result
type(C_void_ptr), value, intent(in) :: dest ! target=intent(out)
type(C_void_ptr), value, intent(in) :: src
integer(C_size_t), value, intent(in) :: n
end function C_memmove
! Set N bytes of S to C.
!extern void *memset (void *s, int c, size_t n)
function C_memset(s, c, n) result(result) bind(C,name="memset")
import C_void_ptr, C_int, C_size_t
type(C_void_ptr) :: result
type(C_void_ptr), value, intent(in) :: s ! target=intent(out)
integer(C_int), value, intent(in) :: c
integer(C_size_t), value, intent(in) :: n
end function C_memset
! Compare N bytes of S1 and S2.
!extern int memcmp (const void *s1, const void *s2, size_t n)
pure function C_memcmp(s1, s2, n) result(result) bind(C,name="memcmp")
import C_int, C_void_ptr, C_size_t
integer(C_int) :: result
type(C_void_ptr), value, intent(in) :: s1
type(C_void_ptr), value, intent(in) :: s2
integer(C_size_t), value, intent(in) :: n
end function C_memcmp
! Search N bytes of S for C.
!extern void *memchr (const void *s, int c, size_t n)
pure function C_memchr(s, c, n) result(result) bind(C,name="memchr")
import C_void_ptr, C_int, C_size_t
type(C_void_ptr) :: result
type(C_void_ptr), value, intent(in) :: s
integer(C_int), value, intent(in) :: c
integer(C_size_t), value, intent(in) :: n
end function C_memchr
! Copy SRC to DEST.
!extern char *strcpy (char *dest, const char *src)
function C_strcpy(dest, src) result(result) bind(C,name="strcpy")
import C_char_ptr, C_size_t
type(C_char_ptr) :: result
type(C_char_ptr), value, intent(in) :: dest ! target=intent(out)
type(C_char_ptr), value, intent(in) :: src
end function C_strcpy
! Copy no more than N characters of SRC to DEST.
!extern char *strncpy (char *dest, const char *src, size_t n)
function C_strncpy(dest, src, n) result(result) bind(C,name="strncpy")
import C_char_ptr, C_size_t
type(C_char_ptr) :: result
type(C_char_ptr), value, intent(in) :: dest ! target=intent(out)
type(C_char_ptr), value, intent(in) :: src
integer(C_size_t), value, intent(in) :: n
end function C_strncpy
! Append SRC onto DEST.
!extern char *strcat (char *dest, const char *src)
function C_strcat(dest, src) result(result) bind(C,name="strcat")
import C_char_ptr, C_size_t
type(C_char_ptr) :: result
type(C_char_ptr), value, intent(in) :: dest ! target=intent(out)
type(C_char_ptr), value, intent(in) :: src
end function C_strcat
! Append no more than N characters from SRC onto DEST.
!extern char *strncat (char *dest, const char *src, size_t n)
function C_strncat(dest, src, n) result(result) bind(C,name="strncat")
import C_char_ptr, C_size_t
type(C_char_ptr) :: result
type(C_char_ptr), value, intent(in) :: dest ! target=intent(out)
type(C_char_ptr), value, intent(in) :: src
integer(C_size_t), value, intent(in) :: n
end function C_strncat
! Compare S1 and S2.
!extern int strcmp (const char *s1, const char *s2)
pure function C_strcmp(s1, s2) result(result) bind(C,name="strcmp")
import C_int, C_char_ptr, C_size_t
integer(C_int) :: result
type(C_char_ptr), value, intent(in) :: s1
type(C_char_ptr), value, intent(in) :: s2
end function C_strcmp
! Compare N characters of S1 and S2.
!extern int strncmp (const char *s1, const char *s2, size_t n)
pure function C_strncmp(s1, s2, n) result(result) bind(C,name="strncmp")
import C_int, C_char_ptr, C_size_t
integer(C_int) :: result
type(C_char_ptr), value, intent(in) :: s1
type(C_char_ptr), value, intent(in) :: s2
integer(C_size_t), value, intent(in) :: n
end function C_strncmp
! Return the length of S.
!extern size_t strlen (const char *s)
pure function C_strlen(s) result(result) bind(C,name="strlen")
import C_char_ptr, C_size_t
integer(C_size_t) :: result
type(C_char_ptr), value, intent(in) :: s !character(len=*), intent(in)
end function C_strlen
end interface
! End of <string.h>
!=========================================================================
! Standard ISO-C malloc routines:
interface
! void *calloc(size_t nmemb, size_t size);
type(C_void_ptr) function C_calloc(nmemb, size) bind(C,name="calloc")
import C_void_ptr, C_size_t
integer(C_size_t), value, intent(in) :: nmemb, size
end function C_calloc
! void *malloc(size_t size);
type(C_void_ptr) function C_malloc(size) bind(C,name="malloc")
import C_void_ptr, C_size_t
integer(C_size_t), value, intent(in) :: size
end function C_malloc
! void free(void *ptr);
subroutine C_free(ptr) bind(C,name="free")
import C_void_ptr
type(C_void_ptr), value, intent(in) :: ptr
end subroutine C_free
! void *realloc(void *ptr, size_t size);
type(C_void_ptr) function C_realloc(ptr,size) bind(C,name="realloc")
import C_void_ptr, C_size_t
type(C_void_ptr), value, intent(in) :: ptr
integer(C_size_t), value, intent(in) :: size
end function C_realloc
end interface
interface assignment(=)
module procedure F_string_assign_C_string
end interface assignment(=)
!==========================================================================
contains
! HACK: For some reason, C_associated was not defined as pure.
pure logical function C_associated_pure(ptr) result(associated)
type(C_ptr), intent(in) :: ptr
integer(C_intptr_t) :: iptr
iptr = transfer(ptr,iptr)
associated = (iptr /= 0)
end function C_associated_pure
! Set a fixed-length Fortran string to the value of a C string.
subroutine F_string_assign_C_string(F_string, C_string)
character(len=*), intent(out) :: F_string
type(C_ptr), intent(in) :: C_string
character(len=1,kind=C_char), pointer :: p_chars(:)
integer :: i
if (.not. C_associated(C_string) ) then
F_string = ' '
else
call C_F_pointer(C_string,p_chars,[huge(0)])
i=1
do while(p_chars(i)/=NUL .and. i<=len(F_string))
F_string(i:i) = p_chars(i)
i=i+1
end do
if (i<len(F_string)) F_string(i:) = ' '
end if
end subroutine F_string_assign_C_string
! Copy a C string, passed by pointer, to a Fortran string.
! If the C pointer is NULL, the Fortran string is blanked.
! C_string must be NUL terminated, or at least as long as F_string.
! If C_string is longer, it is truncated. Otherwise, F_string is
! blank-padded at the end.
subroutine C_F_string_ptr(C_string, F_string)
type(C_ptr), intent(in) :: C_string
character(len=*), intent(out) :: F_string
character(len=1,kind=C_char), dimension(:), pointer :: p_chars
integer :: i
if (.not. C_associated(C_string)) then
F_string = ' '
else
call C_F_pointer(C_string,p_chars,[huge(0)])
i=1
do while(p_chars(i)/=NUL .and. i<=len(F_string))
F_string(i:i) = p_chars(i)
i=i+1
end do
if (i<len(F_string)) F_string(i:) = ' '
end if
end subroutine C_F_string_ptr
! Copy a C string, passed as a char-array reference, to a Fortran string.
subroutine C_F_string_chars(C_string, F_string)
character(len=1,kind=C_char), intent(in) :: C_string(*)
character(len=*), intent(out) :: F_string
integer :: i
i=1
do while(C_string(i)/=NUL .and. i<=len(F_string))
F_string(i:i) = C_string(i)
i=i+1
end do
if (i<len(F_string)) F_string(i:) = ' '
end subroutine C_F_string_chars
! Copy a Fortran string to an allocated C string pointer.
! If the C pointer is NULL, no action is taken. (Maybe auto allocate via libc call?)
! If the length is not passed, the C string must be at least: len(F_string)+1
! If the length is passed and F_string is too long, it is truncated.
subroutine F_C_string_ptr(F_string, C_string, C_string_len)
character(len=*), intent(in) :: F_string
type(C_ptr), intent(in) :: C_string ! target = intent(out)
integer, intent(in), optional :: C_string_len ! Max string length,
! INCLUDING THE TERMINAL NUL
character(len=1,kind=C_char), dimension(:), pointer :: p_chars
integer :: i, strlen
strlen = len(F_string)
if (present(C_string_len)) then
if (C_string_len <= 0) return
strlen = min(strlen,C_string_len)
end if
if (.not. C_associated(C_string)) then
return
end if
call C_F_pointer(C_string,p_chars,[strlen+1])
forall (i=1:strlen)
p_chars(i) = F_string(i:i)
end forall
p_chars(strlen+1) = NUL
end subroutine F_C_string_ptr
pure function C_strlen_safe(s) result(length)
integer(C_size_t) :: length
type(C_char_ptr), value, intent(in) :: s
if (.not. C_associated_pure(s)) then
length = 0
else
length = C_strlen(s)
end if
end function C_strlen_safe
function C_string_value(C_string) result(F_string)
type(C_ptr), intent(in) :: C_string
character(len=C_strlen_safe(C_string)) :: F_string
character(len=1,kind=C_char), dimension(:), pointer :: p_chars
integer :: i, length
length = len(F_string)
if (length/=0) then
call C_F_pointer(C_string,p_chars,[length])
forall (i=1:length)
F_string(i:i) = p_chars(i)
end forall
end if
end function C_string_value
! Copy a Fortran string to a C string passed by char-array reference.
! If the length is not passed, the C string must be at least: len(F_string)+1
! If the length is passed and F_string is too long, it is truncated.
subroutine F_C_string_chars(F_string, C_string, C_string_len)
character(len=*), intent(in) :: F_string
character(len=1,kind=C_char), dimension(*), intent(out) :: C_string
integer, intent(in), optional :: C_string_len ! Max string length,
! INCLUDING THE TERMINAL NUL
integer :: i, strlen
strlen = len(F_string)
if (present(C_string_len)) then
if (C_string_len <= 0) return
strlen = min(strlen,C_string_len)
end if
forall (i=1:strlen)
C_string(i) = F_string(i:i)
end forall
C_string(strlen+1) = NUL
end subroutine F_C_string_chars
! NOTE: Strings allocated here must be freed by the
! C library, such as via C_free() or C_string_free(),
type(C_ptr) function F_C_string_dup(F_string,length) result(C_string)
character(len=*), intent(in) :: F_string
integer, intent(in), optional :: length
character(len=1,kind=C_char), pointer :: C_string_ptr(:)
integer :: i
integer(C_size_t) :: strlen
if (present(length)) then
strlen = length
else
strlen = len(F_string)
end if
if (strlen <= 0) then
C_string = C_NULL_ptr
else
C_string = C_malloc(strlen+1)
if (C_associated(C_string)) then
call C_F_pointer(C_string,C_string_ptr,[strlen+1])
forall (i=1:strlen)
C_string_ptr(i) = F_string(i:i)
end forall
C_string_ptr(strlen+1) = NUL
end if
end if
end function F_C_string_dup
! NOTE: Strings allocated here must be freed by the
! C library, such as via C_free() or C_string_free(),
type(C_ptr) function C_string_alloc(length) result(C_string)
integer(C_size_t), intent(in) :: length
character(len=1,kind=C_char), pointer :: C_charptr
C_string = C_malloc(length+1)
if (C_associated(C_string)) then
call C_F_pointer(C_string,C_charptr)
C_charptr = NUL
end if
end function C_string_alloc
subroutine C_string_free(string)
type(C_ptr), intent(inout) :: string
if (C_associated(string)) then
call C_free(string)
string = C_NULL_ptr
end if
end subroutine C_string_free
end module C_interface_module

View File

@ -1,5 +1,4 @@
module astro_module
use, intrinsic :: iso_c_binding, only : c_int, c_double, c_bool, c_char, c_ptr, c_size_t, c_f_pointer
implicit none
private
@ -7,50 +6,37 @@ module astro_module
contains
subroutine astrosub(nyear,month,nday,uth8,freq8,mygrid_cp,mygrid_len, &
hisgrid_cp,hisgrid_len,AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8, &
subroutine astrosub(nyear,month,nday,uth8,freq8,mygrid_cp, &
hisgrid_cp,AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8, &
ntsky,ndop,ndop00,RAMoon8,DecMoon8,Dgrd8,poloffset8,xnr8,techo8,width1, &
width2,bTx,AzElFileName_cp,AzElFileName_len,jpleph_cp,jpleph_len) &
width2,bTx,AzElFileName_cp,jpleph_file_name_cp) &
bind (C, name="astrosub")
integer, parameter :: dp = selected_real_kind(15, 50)
use :: types, only: dp
use :: C_interface_module, only: C_int, C_double, C_bool, C_ptr, C_string_value, assignment(=)
integer(c_int), intent(in), value :: nyear, month, nday
real(c_double), intent(in), value :: uth8, freq8
real(c_double), intent(out) :: AzSun8, ElSun8, AzMoon8, ElMoon8, AzMoonB8, &
integer(C_int), intent(in), value :: nyear, month, nday
real(C_double), intent(in), value :: uth8, freq8
real(C_double), intent(out) :: AzSun8, ElSun8, AzMoon8, ElMoon8, AzMoonB8, &
ElMoonB8, Ramoon8, DecMoon8, Dgrd8, poloffset8, xnr8, techo8, width1, &
width2
integer(c_int), intent(out) :: ntsky, ndop, ndop00
logical(c_bool), intent(in), value :: bTx
type(c_ptr), intent(in), value :: mygrid_cp, hisgrid_cp, AzElFileName_cp, jpleph_cp
integer(c_size_t), intent(in), value :: mygrid_len, hisgrid_len, AzElFileName_len, jpleph_len
integer(C_int), intent(out) :: ntsky, ndop, ndop00
logical(C_bool), intent(in), value :: bTx
type(C_ptr), value, intent(in) :: mygrid_cp, hisgrid_cp, AzElFileName_cp, &
jpleph_file_name_cp
character(len=6) :: mygrid, hisgrid
character(kind=c_char, len=:), allocatable :: AzElFileName
character(len=:), allocatable :: AzElFileName
character(len=1) :: c1
integer :: ih, im, imin, is, isec, nfreq, nRx
real(dp) :: AzAux, ElAux, dbMoon8, dfdt, dfdt0, doppler, doppler00, HA8, sd8, xlst8
character*256 jpleph_file_name
common/jplcom/jpleph_file_name
block
character(kind=c_char, len=mygrid_len), pointer :: mygrid_fp
character(kind=c_char, len=hisgrid_len), pointer :: hisgrid_fp
character(kind=c_char, len=AzElFileName_len), pointer :: AzElFileName_fp
character(kind=c_char, len=jpleph_len), pointer :: jpleph_fp
call c_f_pointer(cptr=mygrid_cp, fptr=mygrid_fp)
mygrid = mygrid_fp
mygrid_fp => null()
call c_f_pointer(cptr=hisgrid_cp, fptr=hisgrid_fp)
hisgrid = hisgrid_fp
hisgrid_fp => null()
call c_f_pointer(cptr=AzElFileName_cp, fptr=AzElFileName_fp)
AzElFileName = AzElFileName_fp
AzElFileName_fp => null()
call c_f_pointer(cptr=jpleph_cp, fptr=jpleph_fp)
jpleph_file_name = jpleph_fp
jpleph_fp => null()
end block
mygrid = mygrid_cp
hisgrid = hisgrid_cp
AzElFileName = C_string_value (AzElFileName_cp)
jpleph_file_name = jpleph_file_name_cp
call astro0(nyear,month,nday,uth8,freq8,mygrid,hisgrid, &
AzSun8,ElSun8,AzMoon8,ElMoon8,AzMoonB8,ElMoonB8,ntsky,ndop,ndop00, &

55
lib/blanker.f90 Normal file
View File

@ -0,0 +1,55 @@
subroutine blanker(iwave,nz,ndropmax,npct,c_bigfft)
integer*2 iwave(nz)
complex c_bigfft(0:nz/2)
integer hist(0:32768)
real fblank !Fraction of points to be blanked
fblank=0.01*npct
hist=0
do i=1,nz
n=abs(iwave(i))
hist(n)=hist(n)+1
enddo
n=0
do i=32768,0,-1
n=n+hist(i)
if(n.ge.nint(nz*fblank/ndropmax)) exit
enddo
nthresh=i
ndrop=0
ndropped=0
xx=0.
do i=1,nz
i0=iwave(i)
if(ndrop.gt.0) then
i0=0
ndropped=ndropped+1
ndrop=ndrop-1
endif
! Start to apply blanking
if(abs(i0).gt.nthresh) then
i0=0
ndropped=ndropped+1
ndrop=ndropmax
endif
! Now copy the data into c_bigfft
if(iand(i,1).eq.1) then
xx=i0
else
yy=i0
j=i/2 - 1
c_bigfft(j)=cmplx(xx,yy)
endif
enddo
fblanked=fblanked + 0.1*(float(ndropped)/nz - fblanked)
fblanked=float(ndropped)/nz
! write(*,3001) npct,nthresh,fblanked
!3001 format(2i5,f7.3)
return
end subroutine blanker

View File

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

View File

@ -8,6 +8,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
use jt9_decode
use ft8_decode
use ft4_decode
use fst4_decode
include 'jt9com.f90'
include 'timer_common.inc'
@ -32,6 +33,10 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
integer :: decoded
end type counting_ft4_decoder
type, extends(fst4_decoder) :: counting_fst4_decoder
integer :: decoded
end type counting_fst4_decoder
real ss(184,NSMAX)
logical baddata,newdat65,newdat9,single_decode,bVHF,bad0,newdat,ex
integer*2 id2(NTMAX*12000)
@ -48,6 +53,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
type(counting_jt9_decoder) :: my_jt9
type(counting_ft8_decoder) :: my_ft8
type(counting_ft4_decoder) :: my_ft4
type(counting_fst4_decoder) :: my_fst4
!cast C character arrays to Fortran character strings
datetime=transfer(params%datetime, datetime)
@ -62,6 +68,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
my_jt9%decoded = 0
my_ft8%decoded = 0
my_ft4%decoded = 0
my_fst4%decoded = 0
! For testing only: return Rx messages stored in a file as decodes
inquire(file='rx_messages.txt',exist=ex)
@ -180,8 +187,37 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
go to 800
endif
rms=sqrt(dot_product(float(id2(300000:310000)), &
float(id2(300000:310000)))/10000.0)
if(params%nmode.eq.240) then
! We're in FST4 mode
ndepth=iand(params%ndepth,3)
iwspr=0
if(iand(params%ndepth,128).ne.0) iwspr=2
call timer('dec240 ',0)
call my_fst4%decode(fst4_decoded,id2,params%nutc, &
params%nQSOProgress,params%nfqso,params%nfa,params%nfb, &
params%nsubmode,ndepth,params%ntr,params%nexp_decode, &
params%ntol,params%emedelay, &
logical(params%lapcqonly),mycall,hiscall,params%nfsplit,iwspr)
call timer('dec240 ',1)
go to 800
endif
if(params%nmode.eq.241) then
! We're in FST4W mode
ndepth=iand(params%ndepth,3)
iwspr=1
call timer('dec240 ',0)
call my_fst4%decode(fst4_decoded,id2,params%nutc, &
params%nQSOProgress,params%nfqso,params%nfa,params%nfb, &
params%nsubmode,ndepth,params%ntr,params%nexp_decode, &
params%ntol,params%emedelay, &
logical(params%lapcqonly),mycall,hiscall,params%nfsplit,iwspr)
call timer('dec240 ',1)
go to 800
endif
rms=sqrt(dot_product(float(id2(60001:61000)), &
float(id2(60001:61000)))/1000.0)
if(rms.lt.2.0) go to 800
! Zap data at start that might come from T/R switching transient?
@ -299,7 +335,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
! JT65 is not yet producing info for nsynced, ndecoded.
800 ndecoded = my_jt4%decoded + my_jt65%decoded + my_jt9%decoded + &
my_ft8%decoded + my_ft4%decoded
my_ft8%decoded + my_ft4%decoded + my_fst4%decoded
if(params%nmode.eq.8 .and. params%nzhsym.eq.41) ndec41=ndecoded
if(params%nmode.eq.8 .and. params%nzhsym.eq.47) ndec47=ndecoded
if(params%nmode.eq.8 .and. params%nzhsym.eq.50) then
@ -660,4 +696,67 @@ contains
return
end subroutine ft4_decoded
subroutine fst4_decoded (this,nutc,sync,nsnr,dt,freq,decoded,nap, &
qual,ntrperiod,lwspr,fmid,w50)
use fst4_decode
implicit none
class(fst4_decoder), intent(inout) :: this
integer, intent(in) :: nutc
real, intent(in) :: sync
integer, intent(in) :: nsnr
real, intent(in) :: dt
real, intent(in) :: freq
character(len=37), intent(in) :: decoded
integer, intent(in) :: nap
real, intent(in) :: qual
integer, intent(in) :: ntrperiod
logical, intent(in) :: lwspr
real, intent(in) :: fmid
real, intent(in) :: w50
character*2 annot
character*37 decoded0
character*70 line
decoded0=decoded
annot=' '
if(nap.ne.0) then
write(annot,'(a1,i1)') 'a',nap
if(qual.lt.0.17) decoded0(37:37)='?'
endif
if(ntrperiod.lt.60) then
write(line,1001) nutc,nsnr,dt,nint(freq),decoded0,annot
1001 format(i6.6,i4,f5.1,i5,' ` ',1x,a37,1x,a2)
write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded0
1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' FST4')
else
write(line,1003) nutc,nsnr,dt,nint(freq),decoded0,annot
1003 format(i4.4,i4,f5.1,i5,' ` ',1x,a37,1x,a2,2f7.3)
write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded0
1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' FST4')
endif
if(fmid.ne.-999.0) then
if(w50.lt.0.95) write(line(65:70),'(f6.3)') w50
if(w50.ge.0.95) write(line(65:70),'(f6.2)') w50
endif
write(*,1005) line
1005 format(a70)
call flush(6)
call flush(13)
select type(this)
type is (counting_fst4_decoder)
this%decoded = this%decoded + 1
end select
return
end subroutine fst4_decoded
end subroutine multimode_decoder

BIN
lib/fsk4hf/.DS_Store vendored Normal file

Binary file not shown.

562
lib/fst280_decode.f90 Normal file
View File

@ -0,0 +1,562 @@
module fst280_decode
type :: fst280_decoder
procedure(fst280_decode_callback), pointer :: callback
contains
procedure :: decode
end type fst280_decoder
abstract interface
subroutine fst280_decode_callback (this,nutc,sync,nsnr,dt,freq, &
decoded,nap,qual,ntrperiod)
import fst280_decoder
implicit none
class(fst280_decoder), intent(inout) :: this
integer, intent(in) :: nutc
real, intent(in) :: sync
integer, intent(in) :: nsnr
real, intent(in) :: dt
real, intent(in) :: freq
character(len=37), intent(in) :: decoded
integer, intent(in) :: nap
real, intent(in) :: qual
integer, intent(in) :: ntrperiod
end subroutine fst280_decode_callback
end interface
contains
subroutine decode(this,callback,iwave,nutc,nQSOProgress,nfqso, &
nfa,nfb,nsubmode,ndeep,ntrperiod,nexp_decode,ntol)
use timer_module, only: timer
use packjt77
include 'fst280/fst280_params.f90'
parameter (MAXCAND=100)
class(fst280_decoder), intent(inout) :: this
procedure(fst280_decode_callback) :: callback
character*37 decodes(100)
character*37 msg
character*77 c77
complex, allocatable :: c2(:)
complex, allocatable :: cframe(:)
complex, allocatable :: c_bigfft(:) !Complex waveform
real, allocatable :: r_data(:)
real llr(280),llra(280),llrb(280),llrc(280),llrd(280)
real candidates(100,4)
real bitmetrics(328,4)
real s4(0:3,NN)
integer itone(NN)
integer hmod
integer*1 apmask(280),cw(280)
integer*1 hbits(328)
integer*1 message101(101),message74(74)
logical badsync,unpk77_success,single_decode
integer*2 iwave(300*12000)
this%callback => callback
hmod=2**nsubmode
if(nfqso+nqsoprogress.eq.-999) return
Keff=91
iwspr=0
nmax=15*12000
single_decode=iand(nexp_decode,32).eq.32
if(ntrperiod.eq.15) then
nsps=800
nmax=15*12000
ndown=20/hmod
if(hmod.eq.8) ndown=2
else if(ntrperiod.eq.30) then
nsps=1680
nmax=30*12000
ndown=42/hmod
if(hmod.eq.4) ndown=10
if(hmod.eq.8) ndown=5
else if(ntrperiod.eq.60) then
nsps=3888
nmax=60*12000
ndown=96/hmod
if(hmod.eq.1) ndown=108
else if(ntrperiod.eq.120) then
nsps=8200
nmax=120*12000
if(hmod.eq.1) ndown=205
ndown=100/hmod
else if(ntrperiod.eq.300) then
nsps=21168
nmax=300*12000
ndown=504/hmod
end if
nss=nsps/ndown
fs=12000.0 !Sample rate
fs2=fs/ndown
nspsec=nint(fs2)
dt=1.0/fs !Sample interval (s)
dt2=1.0/fs2
tt=nsps*dt !Duration of "itone" symbols (s)
baud=1.0/tt
nfft1=2*int(nmax/2)
nh1=nfft1/2
allocate( r_data(1:nfft1+2) )
allocate( c_bigfft(0:nfft1/2) )
nfft2=nfft1/ndown
allocate( c2(0:nfft2-1) )
allocate( cframe(0:164*nss-1) )
npts=nmax
if(single_decode) then
fa=max(100,nint(nfqso+1.5*hmod*baud-ntol))
fb=min(4800,nint(nfqso+1.5*hmod*baud+ntol))
else
fa=max(100,nfa)
fb=min(4800,nfb)
endif
if(ndeep.eq.3) then
ntmax=4 ! number of block sizes to try
jittermax=2
norder=3
elseif(ndeep.eq.2) then
ntmax=3
jittermax=2
norder=3
elseif(ndeep.eq.1) then
ntmax=1
jittermax=2
norder=2
endif
! The big fft is done once and is used for calculating the smoothed spectrum
! and also for downconverting/downsampling each candidate.
r_data(1:nfft1)=iwave(1:nfft1)
r_data(nfft1+1:nfft1+2)=0.0
call four2a(r_data,nfft1,1,-1,0)
c_bigfft=cmplx(r_data(1:nfft1+2:2),r_data(2:nfft1+2:2))
! Get first approximation of candidate frequencies
call get_candidates_fst280(c_bigfft,nfft1,nsps,hmod,fs,fa,fb, &
ncand,candidates,base)
ndecodes=0
decodes=' '
isbest1=0
isbest8=0
fc21=0.
fc28=0.
do icand=1,ncand
fc0=candidates(icand,1)
detmet=candidates(icand,2)
! Downconvert and downsample a slice of the spectrum centered on the
! rough estimate of the candidates frequency.
! Output array c2 is complex baseband sampled at 12000/ndown Sa/sec.
! The size of the downsampled c2 array is nfft2=nfft1/ndown
call fst280_downsample(c_bigfft,nfft1,ndown,fc0,c2)
call timer('sync280 ',0)
do isync=0,1
if(isync.eq.0) then
fc1=0.0
is0=1.5*nint(fs2)
ishw=1.5*is0
isst=4*hmod
ifhw=12
df=.1*baud
else if(isync.eq.1) then
fc1=fc21
if(hmod.eq.1) fc1=fc28
is0=isbest1
if(hmod.eq.1) is0=isbest8
ishw=4*hmod
isst=1*hmod
ifhw=7
df=.02*baud
endif
smax1=0.0
smax8=0.0
do if=-ifhw,ifhw
fc=fc1+df*if
do istart=max(1,is0-ishw),is0+ishw,isst
call sync_fst280(c2,istart,fc,hmod,1,nfft2,nss,fs2,sync1)
call sync_fst280(c2,istart,fc,hmod,8,nfft2,nss,fs2,sync8)
if(sync8.gt.smax8) then
fc28=fc
isbest8=istart
smax8=sync8
endif
if(sync1.gt.smax1) then
fc21=fc
isbest1=istart
smax1=sync1
endif
enddo
enddo
enddo
call timer('sync280 ',1)
if(smax8/smax1 .lt. 0.65 ) then
fc2=fc21
isbest=isbest1
if(hmod.gt.1) ntmax=1
njitter=2
else
fc2=fc28
isbest=isbest8
if(hmod.gt.1) ntmax=1
njitter=2
endif
fc_synced = fc0 + fc2
dt_synced = (isbest-fs2)*dt2 !nominal dt is 1 second so frame starts at sample fs2
candidates(icand,3)=fc_synced
candidates(icand,4)=isbest
enddo
! remove duplicate candidates
do icand=1,ncand
fc=candidates(icand,3)
isbest=nint(candidates(icand,4))
do ic2=1,ncand
fc2=candidates(ic2,3)
isbest2=nint(candidates(ic2,4))
if(ic2.ne.icand .and. fc2.gt.0.0) then
if(abs(fc2-fc).lt.0.05*baud) then ! same frequency
if(abs(isbest2-isbest).le.2) then
candidates(ic2,3)=-1
endif
endif
endif
enddo
enddo
ic=0
do icand=1,ncand
if(candidates(icand,3).gt.0) then
ic=ic+1
candidates(ic,:)=candidates(icand,:)
endif
enddo
ncand=ic
do icand=1,ncand
sync=candidates(icand,2)
fc_synced=candidates(icand,3)
isbest=nint(candidates(icand,4))
xdt=(isbest-nspsec)/fs2
call fst280_downsample(c_bigfft,nfft1,ndown,fc_synced,c2)
do ijitter=0,jittermax
if(ijitter.eq.0) ioffset=0
if(ijitter.eq.1) ioffset=1
if(ijitter.eq.2) ioffset=-1
is0=isbest+ioffset
if(is0.lt.0) cycle
cframe=c2(is0:is0+164*nss-1)
bitmetrics=0
call get_fst280_bitmetrics(cframe,nss,hmod,ntmax,bitmetrics,s4,badsync)
if(badsync) cycle
hbits=0
where(bitmetrics(:,1).ge.0) hbits=1
ns1=count(hbits( 71: 78).eq.(/0,0,0,1,1,0,1,1/))
ns2=count(hbits( 79: 86).eq.(/0,1,0,0,1,1,1,0/))
ns3=count(hbits(157:164).eq.(/0,0,0,1,1,0,1,1/))
ns4=count(hbits(165:172).eq.(/0,1,0,0,1,1,1,0/))
ns5=count(hbits(243:250).eq.(/0,0,0,1,1,0,1,1/))
ns6=count(hbits(251:258).eq.(/0,1,0,0,1,1,1,0/))
nsync_qual=ns1+ns2+ns3+ns4+ns5+ns6
if(nsync_qual.lt. 26) cycle !### Value ?? ###
scalefac=2.83
llra( 1: 14)=bitmetrics( 1: 14, 1)
llra( 15: 28)=bitmetrics(315:328, 1)
llra( 29: 42)=bitmetrics( 15: 28, 1)
llra( 43: 56)=bitmetrics(301:314, 1)
llra( 57: 98)=bitmetrics( 29: 70, 1)
llra( 99:168)=bitmetrics( 87:156, 1)
llra(169:238)=bitmetrics(173:242, 1)
llra(239:280)=bitmetrics(259:300, 1)
llra=scalefac*llra
llrb( 1: 14)=bitmetrics( 1: 14, 2)
llrb( 15: 28)=bitmetrics(315:328, 2)
llrb( 29: 42)=bitmetrics( 15: 28, 2)
llrb( 43: 56)=bitmetrics(301:314, 2)
llrb( 57: 98)=bitmetrics( 29: 70, 2)
llrb( 99:168)=bitmetrics( 87:156, 2)
llrb(169:238)=bitmetrics(173:242, 2)
llrb(239:280)=bitmetrics(259:300, 2)
llrb=scalefac*llrb
llrc( 1: 14)=bitmetrics( 1: 14, 3)
llrc( 15: 28)=bitmetrics(315:328, 3)
llrc( 29: 42)=bitmetrics( 15: 28, 3)
llrc( 43: 56)=bitmetrics(301:314, 3)
llrc( 57: 98)=bitmetrics( 29: 70, 3)
llrc( 99:168)=bitmetrics( 87:156, 3)
llrc(169:238)=bitmetrics(173:242, 3)
llrc(239:280)=bitmetrics(259:300, 3)
llrc=scalefac*llrc
llrd( 1: 14)=bitmetrics( 1: 14, 4)
llrd( 15: 28)=bitmetrics(315:328, 4)
llrd( 29: 42)=bitmetrics( 15: 28, 4)
llrd( 43: 56)=bitmetrics(301:314, 4)
llrd( 57: 98)=bitmetrics( 29: 70, 4)
llrd( 99:168)=bitmetrics( 87:156, 4)
llrd(169:238)=bitmetrics(173:242, 4)
llrd(239:280)=bitmetrics(259:300, 4)
llrd=scalefac*llrd
apmask=0
do itry=1,ntmax
if(itry.eq.1) llr=llra
if(itry.eq.2) llr=llrb
if(itry.eq.3) llr=llrc
if(itry.eq.4) llr=llrd
dmin=0.0
nharderrors=-1
unpk77_success=.false.
if(iwspr.eq.0) then
maxosd=2
call timer('d280_101',0)
call decode280_101(llr,Keff,maxosd,norder,apmask,message101, &
cw,ntype,nharderrors,dmin)
call timer('d280_101',1)
else
maxosd=2
call timer('d280_74 ',0)
call decode280_74(llr,Keff,maxosd,norder,apmask,message74,cw, &
ntype,nharderrors,dmin)
call timer('d280_74 ',1)
endif
if(nharderrors .ge.0) then
if(iwspr.eq.0) then
write(c77,'(77i1)') message101(1:77)
call unpack77(c77,0,msg,unpk77_success)
else
write(c77,'(50i1)') message74(1:50)
c77(51:77)='000000000000000000000110000'
call unpack77(c77,0,msg,unpk77_success)
endif
if(unpk77_success) then
idupe=0
do i=1,ndecodes
if(decodes(i).eq.msg) idupe=1
enddo
if(idupe.eq.1) exit
ndecodes=ndecodes+1
decodes(ndecodes)=msg
if(iwspr.eq.0) then
call get_fst280_tones_from_bits(message101,itone,iwspr)
xsig=0
do i=1,NN
xsig=xsig+s4(itone(i),i)**2
enddo
arg=400.0*(xsig/base)-1.0
if(arg.gt.0.0) then
xsnr=10*log10(arg)-21.0-11.7*log10(nsps/800.0)
else
xsnr=-99.9
endif
endif
nsnr=nint(xsnr)
iaptype=0
qual=0.
fsig=fc_synced - 1.5*hmod*baud
!write(21,'(8i4,f7.1,f7.2,3f7.1,1x,a37)') &
! nutc,icand,itry,iaptype,ijitter,ntype,nsync_qual,nharderrors,dmin,sync,xsnr,xdt,fsig,msg
call this%callback(nutc,smax1,nsnr,xdt,fsig,msg, &
iaptype,qual,ntrperiod)
goto 2002
else
cycle
endif
endif
enddo ! metrics
enddo ! istart jitter
2002 continue
enddo !candidate list!ws
return
end subroutine decode
subroutine sync_fst280(cd0,i0,f0,hmod,ncoh,np,nss,fs,sync)
! Compute sync power for a complex, downsampled FST280 signal.
include 'fst280/fst280_params.f90'
complex cd0(0:np-1)
complex, allocatable, save :: csync(:)
complex, allocatable, save :: csynct(:)
complex ctwk(8*nss)
complex z1,z2,z3
logical first
integer hmod,isyncword(0:7)
real f0save
data isyncword/0,1,3,2,1,0,2,3/
data first/.true./,f0save/0.0/,nss0/-1/
save first,twopi,dt,fac,f0save,nss0
p(z1)=(real(z1*fac)**2 + aimag(z1*fac)**2)**0.5 !Compute power
if(nss.ne.nss0 .and. allocated(csync)) deallocate(csync,csynct)
if(first .or. nss.ne.nss0) then
allocate( csync(8*nss) )
allocate( csynct(8*nss) )
twopi=8.0*atan(1.0)
dt=1/fs
k=1
phi=0.0
do i=0,7
dphi=twopi*hmod*(isyncword(i)-1.5)/real(nss)
do j=1,nss
csync(k)=cmplx(cos(phi),sin(phi))
phi=mod(phi+dphi,twopi)
k=k+1
enddo
enddo
first=.false.
nss0=nss
fac=1.0/(8.0*nss)
endif
if(f0.ne.f0save) then
dphi=twopi*f0*dt
phi=0.0
do i=1,8*nss
ctwk(i)=cmplx(cos(phi),sin(phi))
phi=mod(phi+dphi,twopi)
enddo
csynct=ctwk*csync
f0save=f0
endif
i1=i0+35*nss !Costas arrays
i2=i0+78*nss
i3=i0+121*nss
s1=0.0
s2=0.0
s3=0.0
nsec=8/ncoh
do i=1,nsec
is=(i-1)*ncoh*nss
z1=0
if(i1+is.ge.1) then
z1=sum(cd0(i1+is:i1+is+ncoh*nss-1)*conjg(csynct(is+1:is+ncoh*nss)))
endif
z2=sum(cd0(i2+is:i2+is+ncoh*nss-1)*conjg(csynct(is+1:is+ncoh*nss)))
z3=0
if(i3+is+ncoh*nss-1.le.np) then
z3=sum(cd0(i3+is:i3+is+ncoh*nss-1)*conjg(csynct(is+1:is+ncoh*nss)))
endif
s1=s1+abs(z1)/(8*nss)
s2=s2+abs(z2)/(8*nss)
s3=s3+abs(z3)/(8*nss)
enddo
sync = s1+s2+s3
return
end subroutine sync_fst280
subroutine fst280_downsample(c_bigfft,nfft1,ndown,f0,c1)
! Output: Complex data in c(), sampled at 12000/ndown Hz
complex c_bigfft(0:nfft1/2)
complex c1(0:nfft1/ndown-1)
df=12000.0/nfft1
i0=nint(f0/df)
c1(0)=c_bigfft(i0)
nfft2=nfft1/ndown
do i=1,nfft2/2
if(i0+i.le.nfft1/2) c1(i)=c_bigfft(i0+i)
if(i0-i.ge.0) c1(nfft2-i)=c_bigfft(i0-i)
enddo
c1=c1/nfft2
call four2a(c1,nfft2,1,1,1) !c2c FFT back to time domain
return
end subroutine fst280_downsample
subroutine get_candidates_fst280(c_bigfft,nfft1,nsps,hmod,fs,fa,fb, &
ncand,candidates,base)
complex c_bigfft(0:nfft1/2)
integer hmod
integer indx(100)
real candidates(100,4)
real candidates0(100,4)
real snr_cand(100)
real s(18000)
real s2(18000)
data nfft1z/-1/
save nfft1z
nh1=nfft1/2
df1=fs/nfft1
baud=fs/nsps
df2=baud/2.0
nd=df2/df1
ndh=nd/2
ia=nint(max(100.0,fa)/df2)
ib=nint(min(4800.0,fb)/df2)
signal_bw=4*(12000.0/nsps)*hmod
analysis_bw=min(4800.0,fb)-max(100.0,fa)
noise_bw=10.0*signal_bw
if(analysis_bw.gt.noise_bw) then
ina=ia
inb=ib
else
fcenter=(fa+fb)/2.0
fl = max(100.0,fcenter-noise_bw/2.)/df2
fh = min(4800.0,fcenter+noise_bw/2.)/df2
ina=nint(fl)
inb=nint(fh)
endif
s=0.
do i=ina,inb ! noise analysis window includes signal analysis window
j0=nint(i*df2/df1)
do j=j0-ndh,j0+ndh
s(i)=s(i) + real(c_bigfft(j))**2 + aimag(c_bigfft(j))**2
enddo
enddo
ina=max(ina,1+3*hmod)
inb=min(inb,18000-3*hmod)
s2=0.
do i=ina,inb
s2(i)=s(i-hmod*3) + s(i-hmod) +s(i+hmod) +s(i+hmod*3)
enddo
call pctile(s2(ina+hmod*3:inb-hmod*3),inb-ina+1-hmod*6,30,base)
s2=s2/base
thresh=1.25
ncand=0
candidates=0
if(ia.lt.3) ia=3
if(ib.gt.18000-2) ib=18000-2
do i=ia,ib
if((s2(i).gt.s2(i-2)).and. &
(s2(i).gt.s2(i+2)).and. &
(s2(i).gt.thresh).and.ncand.lt.100) then
ncand=ncand+1
candidates(ncand,1)=df2*i
candidates(ncand,2)=s2(i)
endif
enddo
snr_cand=0.
snr_cand(1:ncand)=candidates(1:ncand,2)
call indexx(snr_cand,ncand,indx)
nmax=min(ncand,20)
do i=1,nmax
j=indx(ncand+1-i)
candidates0(i,1:4)=candidates(j,1:4)
enddo
ncand=nmax
candidates(1:ncand,1:4)=candidates0(1:ncand,1:4)
candidates(ncand+1:,1:4)=0.
return
end subroutine get_candidates_fst280
end module fst280_decode

View File

@ -0,0 +1,111 @@
subroutine bpdecode240_101(llr,apmask,maxiterations,message101,cw,nharderror,iter,ncheck)
!
! A log-domain belief propagation decoder for the (240,101) code.
!
integer, parameter:: N=240, K=101, M=N-K
integer*1 cw(N),apmask(N)
integer*1 decoded(K)
integer*1 message101(101)
integer nrw(M),ncw
integer Nm(6,M)
integer Mn(3,N) ! 3 checks per bit
integer synd(M)
real tov(3,N)
real toc(6,M)
real tanhtoc(6,M)
real zn(N)
real llr(N)
real Tmn
include "ldpc_240_101_parity.f90"
decoded=0
toc=0
tov=0
tanhtoc=0
! initialize messages to checks
do j=1,M
do i=1,nrw(j)
toc(i,j)=llr((Nm(i,j)))
enddo
enddo
ncnt=0
nclast=0
do iter=0,maxiterations
! Update bit log likelihood ratios (tov=0 in iteration 0).
do i=1,N
if( apmask(i) .ne. 1 ) then
zn(i)=llr(i)+sum(tov(1:ncw,i))
else
zn(i)=llr(i)
endif
enddo
! Check to see if we have a codeword (check before we do any iteration).
cw=0
where( zn .gt. 0. ) cw=1
ncheck=0
do i=1,M
synd(i)=sum(cw(Nm(1:nrw(i),i)))
if( mod(synd(i),2) .ne. 0 ) ncheck=ncheck+1
! if( mod(synd(i),2) .ne. 0 ) write(*,*) 'check ',i,' unsatisfied'
enddo
if( ncheck .eq. 0 ) then ! we have a codeword - if crc is good, return it
decoded=cw(1:101)
call get_crc24(decoded,101,nbadcrc)
nharderror=count( (2*cw-1)*llr .lt. 0.0 )
if(nbadcrc.eq.0) then
message101=decoded(1:101)
return
endif
endif
if( iter.gt.0 ) then ! this code block implements an early stopping criterion
! if( iter.gt.10000 ) then ! this code block implements an early stopping criterion
nd=ncheck-nclast
if( nd .lt. 0 ) then ! # of unsatisfied parity checks decreased
ncnt=0 ! reset counter
else
ncnt=ncnt+1
endif
! write(*,*) iter,ncheck,nd,ncnt
if( ncnt .ge. 5 .and. iter .ge. 10 .and. ncheck .gt. 15) then
nharderror=-1
return
endif
endif
nclast=ncheck
! Send messages from bits to check nodes
do j=1,M
do i=1,nrw(j)
ibj=Nm(i,j)
toc(i,j)=zn(ibj)
do kk=1,ncw ! subtract off what the bit had received from the check
if( Mn(kk,ibj) .eq. j ) then
toc(i,j)=toc(i,j)-tov(kk,ibj)
endif
enddo
enddo
enddo
! send messages from check nodes to variable nodes
do i=1,M
tanhtoc(1:6,i)=tanh(-toc(1:6,i)/2)
enddo
do j=1,N
do i=1,ncw
ichk=Mn(i,j) ! Mn(:,j) are the checks that include bit j
Tmn=product(tanhtoc(1:nrw(ichk),ichk),mask=Nm(1:nrw(ichk),ichk).ne.j)
call platanh(-Tmn,y)
! y=atanh(-Tmn)
tov(i,j)=2*y
enddo
enddo
enddo
nharderror=-1
return
end subroutine bpdecode240_101

154
lib/fst4/decode240_101.f90 Normal file
View File

@ -0,0 +1,154 @@
subroutine decode240_101(llr,Keff,maxosd,norder,apmask,message101,cw,ntype,nharderror,dmin)
!
! A hybrid bp/osd decoder for the (240,101) code.
!
! maxosd<0: do bp only
! maxosd=0: do bp and then call osd once with channel llrs
! maxosd>1: do bp and then call osd maxosd times with saved bp outputs
! norder : osd decoding depth
!
integer, parameter:: N=240, K=101, M=N-K
integer*1 cw(N),apmask(N)
integer*1 nxor(N),hdec(N)
integer*1 message101(101),m101(101)
integer nrw(M),ncw
integer Nm(6,M)
integer Mn(3,N) ! 3 checks per bit
integer synd(M)
real tov(3,N)
real toc(6,M)
real tanhtoc(6,M)
real zn(N),zsum(N),zsave(N,3)
real llr(N)
real Tmn
include "ldpc_240_101_parity.f90"
maxiterations=30
nosd=0
if(maxosd.gt.3) maxosd=3
if(maxosd.eq.0) then ! osd with channel llrs
nosd=1
zsave(:,1)=llr
elseif(maxosd.gt.0) then !
nosd=maxosd
elseif(maxosd.lt.0) then ! just bp
nosd=0
endif
toc=0
tov=0
tanhtoc=0
! initialize messages to checks
do j=1,M
do i=1,nrw(j)
toc(i,j)=llr((Nm(i,j)))
enddo
enddo
ncnt=0
nclast=0
zsum=0.0
do iter=0,maxiterations
! Update bit log likelihood ratios (tov=0 in iteration 0).
do i=1,N
if( apmask(i) .ne. 1 ) then
zn(i)=llr(i)+sum(tov(1:ncw,i))
else
zn(i)=llr(i)
endif
enddo
zsum=zsum+zn
if(iter.gt.0 .and. iter.le.maxosd) then
zsave(:,iter)=zsum
endif
! Check to see if we have a codeword (check before we do any iteration).
cw=0
where( zn .gt. 0. ) cw=1
ncheck=0
do i=1,M
synd(i)=sum(cw(Nm(1:nrw(i),i)))
if( mod(synd(i),2) .ne. 0 ) ncheck=ncheck+1
enddo
if( ncheck .eq. 0 ) then ! we have a codeword - if crc is good, return it
m101=0
m101(1:101)=cw(1:101)
call get_crc24(m101,101,nbadcrc)
if(nbadcrc.eq.0) then
message101=cw(1:101)
hdec=0
where(llr .ge. 0) hdec=1
nxor=ieor(hdec,cw)
nharderror=sum(nxor)
dmin=sum(nxor*abs(llr))
ntype=1
return
endif
endif
if( iter.gt.0 ) then ! this code block implements an early stopping criterion
! if( iter.gt.10000 ) then ! this code block implements an early stopping criterion
nd=ncheck-nclast
if( nd .lt. 0 ) then ! # of unsatisfied parity checks decreased
ncnt=0 ! reset counter
else
ncnt=ncnt+1
endif
! write(*,*) iter,ncheck,nd,ncnt
if( ncnt .ge. 5 .and. iter .ge. 10 .and. ncheck .gt. 15) then
nharderror=-1
exit
endif
endif
nclast=ncheck
! Send messages from bits to check nodes
do j=1,M
do i=1,nrw(j)
ibj=Nm(i,j)
toc(i,j)=zn(ibj)
do kk=1,ncw ! subtract off what the bit had received from the check
if( Mn(kk,ibj) .eq. j ) then
toc(i,j)=toc(i,j)-tov(kk,ibj)
endif
enddo
enddo
enddo
! send messages from check nodes to variable nodes
do i=1,M
tanhtoc(1:6,i)=tanh(-toc(1:6,i)/2)
enddo
do j=1,N
do i=1,ncw
ichk=Mn(i,j) ! Mn(:,j) are the checks that include bit j
Tmn=product(tanhtoc(1:nrw(ichk),ichk),mask=Nm(1:nrw(ichk),ichk).ne.j)
call platanh(-Tmn,y)
! y=atanh(-Tmn)
tov(i,j)=2*y
enddo
enddo
enddo ! bp iterations
do i=1,nosd
zn=zsave(:,i)
call osd240_101(zn,Keff,apmask,norder,message101,cw,nharderror,dminosd)
if(nharderror.gt.0) then
hdec=0
where(llr .ge. 0) hdec=1
nxor=ieor(hdec,cw)
dmin=sum(nxor*abs(llr))
ntype=2
return
endif
enddo
ntype=0
nharderror=-1
dminosd=0.0
return
end subroutine decode240_101

154
lib/fst4/decode240_74.f90 Normal file
View File

@ -0,0 +1,154 @@
subroutine decode240_74(llr,Keff,maxosd,norder,apmask,message74,cw,ntype,nharderror,dmin)
!
! A hybrid bp/osd decoder for the (240,74) code.
!
! maxosd<0: do bp only
! maxosd=0: do bp and then call osd once with channel llrs
! maxosd>1: do bp and then call osd maxosd times with saved bp outputs
! norder : osd decoding depth
!
integer, parameter:: N=240, K=74, M=N-K
integer*1 cw(N),apmask(N)
integer*1 nxor(N),hdec(N)
integer*1 message74(74),m74(74)
integer nrw(M),ncw
integer Nm(5,M)
integer Mn(3,N) ! 3 checks per bit
integer synd(M)
real tov(3,N)
real toc(5,M)
real tanhtoc(5,M)
real zn(N),zsum(N),zsave(N,3)
real llr(N)
real Tmn
include "ldpc_240_74_parity.f90"
maxiterations=30
nosd=0
if(maxosd.gt.3) maxosd=3
if(maxosd.eq.0) then ! osd with channel llrs
nosd=1
zsave(:,1)=llr
elseif(maxosd.gt.0) then !
nosd=maxosd
elseif(maxosd.lt.0) then ! just bp
nosd=0
endif
toc=0
tov=0
tanhtoc=0
! initialize messages to checks
do j=1,M
do i=1,nrw(j)
toc(i,j)=llr((Nm(i,j)))
enddo
enddo
ncnt=0
nclast=0
zsum=0.0
do iter=0,maxiterations
! Update bit log likelihood ratios (tov=0 in iteration 0).
do i=1,N
if( apmask(i) .ne. 1 ) then
zn(i)=llr(i)+sum(tov(1:ncw,i))
else
zn(i)=llr(i)
endif
enddo
zsum=zsum+zn
if(iter.gt.0 .and. iter.le.maxosd) then
zsave(:,iter)=zsum
endif
! Check to see if we have a codeword (check before we do any iteration).
cw=0
where( zn .gt. 0. ) cw=1
ncheck=0
do i=1,M
synd(i)=sum(cw(Nm(1:nrw(i),i)))
if( mod(synd(i),2) .ne. 0 ) ncheck=ncheck+1
enddo
if( ncheck .eq. 0 ) then ! we have a codeword - if crc is good, return it
m74=0
m74(1:74)=cw(1:74)
call get_crc24(m74,74,nbadcrc)
if(nbadcrc.eq.0) then
message74=cw(1:74)
hdec=0
where(llr .ge. 0) hdec=1
nxor=ieor(hdec,cw)
nharderror=sum(nxor)
dmin=sum(nxor*abs(llr))
ntype=1
return
endif
endif
if( iter.gt.0 ) then ! this code block implements an early stopping criterion
! if( iter.gt.10000 ) then ! this code block implements an early stopping criterion
nd=ncheck-nclast
if( nd .lt. 0 ) then ! # of unsatisfied parity checks decreased
ncnt=0 ! reset counter
else
ncnt=ncnt+1
endif
! write(*,*) iter,ncheck,nd,ncnt
if( ncnt .ge. 5 .and. iter .ge. 10 .and. ncheck .gt. 15) then
nharderror=-1
exit
endif
endif
nclast=ncheck
! Send messages from bits to check nodes
do j=1,M
do i=1,nrw(j)
ibj=Nm(i,j)
toc(i,j)=zn(ibj)
do kk=1,ncw ! subtract off what the bit had received from the check
if( Mn(kk,ibj) .eq. j ) then
toc(i,j)=toc(i,j)-tov(kk,ibj)
endif
enddo
enddo
enddo
! send messages from check nodes to variable nodes
do i=1,M
tanhtoc(1:5,i)=tanh(-toc(1:5,i)/2)
enddo
do j=1,N
do i=1,ncw
ichk=Mn(i,j) ! Mn(:,j) are the checks that include bit j
Tmn=product(tanhtoc(1:nrw(ichk),ichk),mask=Nm(1:nrw(ichk),ichk).ne.j)
call platanh(-Tmn,y)
! y=atanh(-Tmn)
tov(i,j)=2*y
enddo
enddo
enddo ! bp iterations
do i=1,nosd
zn=zsave(:,i)
call osd240_74(zn,Keff,apmask,norder,message74,cw,nharderror,dminosd)
if(nharderror.gt.0) then
hdec=0
where(llr .ge. 0) hdec=1
nxor=ieor(hdec,cw)
dmin=sum(nxor*abs(llr))
ntype=2
return
endif
enddo
ntype=0
nharderror=-1
dminosd=0.0
return
end subroutine decode240_74

View File

@ -0,0 +1,46 @@
subroutine encode240_101(message,codeword)
use, intrinsic :: iso_c_binding
use iso_c_binding, only: c_loc,c_size_t
use crc
integer, parameter:: N=240, K=101, M=N-K
character*24 c24
integer*1 codeword(N)
integer*1 gen(M,K)
integer*1 message(K)
integer*1 pchecks(M)
integer*4 ncrc24
include "ldpc_240_101_generator.f90"
logical first
data first/.true./
save first,gen
if( first ) then ! fill the generator matrix
gen=0
do i=1,M
do j=1,26
read(g(i)(j:j),"(Z1)") istr
ibmax=4
if(j.eq.26) ibmax=1
do jj=1, ibmax
icol=(j-1)*4+jj
if( btest(istr,4-jj) ) gen(i,icol)=1
enddo
enddo
enddo
first=.false.
endif
do i=1,M
nsum=0
do j=1,K
nsum=nsum+message(j)*gen(i,j)
enddo
pchecks(i)=mod(nsum,2)
enddo
codeword(1:K)=message
codeword(K+1:N)=pchecks
return
end subroutine encode240_101

46
lib/fst4/encode240_74.f90 Normal file
View File

@ -0,0 +1,46 @@
subroutine encode240_74(message,codeword)
use, intrinsic :: iso_c_binding
use iso_c_binding, only: c_loc,c_size_t
use crc
integer, parameter:: N=240, K=74, M=N-K
character*24 c24
integer*1 codeword(N)
integer*1 gen(M,K)
integer*1 message(K)
integer*1 pchecks(M)
integer*4 ncrc24
include "ldpc_240_74_generator.f90"
logical first
data first/.true./
save first,gen
if( first ) then ! fill the generator matrix
gen=0
do i=1,M
do j=1,19
read(g(i)(j:j),"(Z1)") istr
ibmax=4
if(j.eq.19) ibmax=2
do jj=1, ibmax
icol=(j-1)*4+jj
if( btest(istr,4-jj) ) gen(i,icol)=1
enddo
enddo
enddo
first=.false.
endif
do i=1,M
nsum=0
do j=1,K
nsum=nsum+message(j)*gen(i,j)
enddo
pchecks(i)=mod(nsum,2)
enddo
codeword(1:K)=message
codeword(K+1:N)=pchecks
return
end subroutine encode240_74

7
lib/fst4/fst4_params.f90 Normal file
View File

@ -0,0 +1,7 @@
! FST4
! LDPC(240,101)/CRC24 code, five 8x4 sync
parameter (KK=77) !Information bits (77 + CRC24)
parameter (ND=120) !Data symbols
parameter (NS=40) !Sync symbols
parameter (NN=NS+ND) !Sync and data symbols (160)

155
lib/fst4/fst4sim.f90 Normal file
View File

@ -0,0 +1,155 @@
program fst4sim
! Generate simulated signals for experimental slow FT4 mode
use wavhdr
use packjt77
include 'fst4_params.f90' !Set various constants
type(hdr) h !Header for .wav file
logical*1 wspr_hint
character arg*12,fname*17
character msg37*37,msgsent37*37,c77*77
complex, allocatable :: c0(:)
complex, allocatable :: c(:)
real, allocatable :: wave(:)
integer hmod
integer itone(NN)
integer*1 msgbits(101)
integer*2, allocatable :: iwave(:) !Generated full-length waveform
! Get command-line argument(s)
nargs=iargc()
if(nargs.ne.10) then
print*,'Need 10 arguments, got ',nargs
print*,'Usage: fst4sim "message" TRsec f0 DT h fdop del nfiles snr W'
print*,'Examples: fst4sim "K1JT K9AN EN50" 60 1500 0.0 1 0.1 1.0 10 -15 F'
print*,'W (T or F) argument is hint to encoder to use WSPR message when there is abiguity'
go to 999
endif
call getarg(1,msg37) !Message to be transmitted
call getarg(2,arg)
read(arg,*) nsec !TR sequence length, seconds
call getarg(3,arg)
read(arg,*) f00 !Frequency (only used for single-signal)
call getarg(4,arg)
read(arg,*) xdt !Time offset from nominal (s)
call getarg(5,arg)
read(arg,*) hmod !Modulation index, h
call getarg(6,arg)
read(arg,*) fspread !Watterson frequency spread (Hz)
call getarg(7,arg)
read(arg,*) delay !Watterson delay (ms)
call getarg(8,arg)
read(arg,*) nfiles !Number of files
call getarg(9,arg)
read(arg,*) snrdb !SNR_2500
call getarg(10,arg)
read(arg,*) wspr_hint !0:break ties as 77-bit 1:break ties as 50-bit
nfiles=abs(nfiles)
twopi=8.0*atan(1.0)
fs=12000.0 !Sample rate (Hz)
dt=1.0/fs !Sample interval (s)
nsps=0
if(nsec.eq.15) nsps=720
if(nsec.eq.30) nsps=1680
if(nsec.eq.60) nsps=3888
if(nsec.eq.120) nsps=8200
if(nsec.eq.300) nsps=21504
if(nsec.eq.900) nsps=66560
if(nsec.eq.1800) nsps=134400
if(nsps.eq.0) then
print*,'Invalid TR sequence length.'
go to 999
endif
baud=12000.0/nsps !Keying rate (baud)
nmax=nsec*12000
nz=nsps*NN
txt=nz*dt !Transmission length (s)
tt=nsps*dt !Duration of symbols (s)
nwave=max(nmax,(NN+2)*nsps)
allocate( c0(0:nwave-1) )
allocate( c(0:nwave-1) )
allocate( wave(nwave) )
allocate( iwave(nmax) )
bandwidth_ratio=2500.0/(fs/2.0)
sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb)
if(snrdb.gt.90.0) sig=1.0
if(wspr_hint) then
i3=0
n3=6
else
i3=-1
n3=-1
endif
call pack77(msg37,i3,n3,c77)
if(i3.eq.0.and.n3.eq.6) iwspr=1
call genfst4(msg37,0,msgsent37,msgbits,itone,iwspr)
write(*,*)
write(*,'(a9,a37,a3,L2,a7,i2)') 'Message: ',msgsent37,'W:',wspr_hint,' iwspr:',iwspr
write(*,1000) f00,xdt,hmod,txt,snrdb
1000 format('f0:',f9.3,' DT:',f6.2,' hmod:',i6,' TxT:',f6.1,' SNR:',f6.1)
write(*,*)
if(i3.eq.1) then
write(*,*) ' mycall hiscall hisgrid'
write(*,'(28i1,1x,i1,1x,28i1,1x,i1,1x,i1,1x,15i1,1x,3i1)') msgbits(1:77)
else
write(*,'(a14)') 'Message bits: '
write(*,'(77i1,1x,24i1)') msgbits
endif
write(*,*)
write(*,'(a17)') 'Channel symbols: '
write(*,'(10i1)') itone
write(*,*)
! call sgran()
fsample=12000.0
icmplx=1
f0=f00+1.5*hmod*baud
call gen_fst4wave(itone,NN,nsps,nwave,fsample,hmod,f0,icmplx,c0,wave)
k=nint((xdt+1.0)/dt)
if(nsec.eq.15) k=nint((xdt+0.5)/dt)
c0=cshift(c0,-k)
if(k.gt.0) c0(0:k-1)=0.0
if(k.lt.0) c0(nmax+k:nmax-1)=0.0
do ifile=1,nfiles
c=c0
if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c,nwave,NZ,fs,delay,fspread)
c=sig*c
wave=real(c)
if(snrdb.lt.90) then
do i=1,nmax !Add gaussian noise at specified SNR
xnoise=gran()
wave(i)=wave(i) + xnoise
enddo
endif
gain=100.0
if(snrdb.lt.90.0) then
wave=gain*wave
else
datpk=maxval(abs(wave))
fac=32766.9/datpk
wave=fac*wave
endif
if(any(abs(wave).gt.32767.0)) print*,"Warning - data will be clipped."
iwave=nint(wave(:size(iwave)))
h=default_header(12000,nmax)
if(nmax/12000.le.30) then
write(fname,1102) ifile
1102 format('000000_',i6.6,'.wav')
else
write(fname,1104) ifile
1104 format('000000_',i4.4,'.wav')
endif
open(10,file=trim(fname),status='unknown',access='stream')
write(10) h,iwave !Save to *.wav file
close(10)
write(*,1110) ifile,xdt,f00,snrdb,fname
1110 format(i4,f7.2,f8.2,f7.1,2x,a17)
enddo
999 end program fst4sim

91
lib/fst4/gen_fst4wave.f90 Normal file
View File

@ -0,0 +1,91 @@
subroutine gen_fst4wave(itone,nsym,nsps,nwave,fsample,hmod,f0, &
icmplx,cwave,wave)
parameter(NTAB=65536)
real wave(nwave)
complex cwave(nwave),ctab(0:NTAB-1)
real, allocatable, save :: pulse(:)
real, allocatable :: dphi(:)
integer hmod
integer itone(nsym)
logical first
data first/.true./
data nsps0/-99/
save first,twopi,dt,tsym,nsps0,ctab
if(first) then
twopi=8.0*atan(1.0)
do i=0,NTAB-1
phi=i*twopi/NTAB
ctab(i)=cmplx(cos(phi),sin(phi))
enddo
endif
if(first.or.nsps.ne.nsps0) then
if(allocated(pulse)) deallocate(pulse)
allocate(pulse(1:3*nsps))
dt=1.0/fsample
tsym=nsps/fsample
! Compute the smoothed frequency-deviation pulse
do i=1,3*nsps
tt=(i-1.5*nsps)/real(nsps)
pulse(i)=gfsk_pulse(2.0,tt)
enddo
first=.false.
nsps0=nsps
endif
! Compute the smoothed frequency waveform.
! Length = (nsym+2)*nsps samples, zero-padded
allocate( dphi(0:(nsym+2)*nsps-1) )
dphi_peak=twopi*hmod/real(nsps)
dphi=0.0
do j=1,nsym
ib=(j-1)*nsps
ie=ib+3*nsps-1
dphi(ib:ie) = dphi(ib:ie) + dphi_peak*pulse(1:3*nsps)*itone(j)
enddo
! Calculate and insert the audio waveform
phi=0.0
dphi = dphi + twopi*(f0-1.5*hmod/tsym)*dt !Shift frequency up by f0
if(icmplx.eq.0) wave=0.
if(icmplx.eq.1) cwave=0.
k=0
do j=0,(nsym+2)*nsps-1
k=k+1
i=phi*float(NTAB)/twopi
i=iand(i,NTAB-1)
if(icmplx.eq.0) then
wave(k)=real(ctab(i))
else
cwave(k)=ctab(i)
endif
phi=phi+dphi(j)
if(phi.gt.twopi) phi=phi-twopi
enddo
! Compute the ramp-up and ramp-down symbols
kshift=nsps
if(icmplx.eq.0) then
wave(1:nsps)=0.0
wave(nsps+1:nsps+nsps/4)=wave(nsps+1:nsps+nsps/4) * &
(1.0-cos(twopi*(/(i,i=0,nsps/4-1)/)/real(nsps/2)))/2.0
k1=nsym*nsps+3*nsps/4+1
wave((nsym+1)*nsps+1:)=0.0
wave(k1:k1+nsps/4)=wave(k1:k1+nsps/4) * &
(1.0+cos(twopi*(/(i,i=0,nsps/4)/)/real(nsps/2)))/2.0
wave=cshift(wave,kshift)
else
cwave(1:nsps)=0.0
cwave(nsps+1:nsps+nsps/4)=cwave(nsps+1:nsps+nsps/4) * &
(1.0-cos(twopi*(/(i,i=0,nsps/4-1)/)/real(nsps/2)))/2.0
k1=nsym*nsps+3*nsps/4+1
cwave((nsym+1)*nsps+1:)=0.0
cwave(k1:k1+nsps/4)=cwave(k1:k1+nsps/4) * &
(1.0+cos(twopi*(/(i,i=0,nsps/4)/)/real(nsps/2)))/2.0
cwave=cshift(cwave,kshift)
endif
return
end subroutine gen_fst4wave

111
lib/fst4/genfst4.f90 Normal file
View File

@ -0,0 +1,111 @@
subroutine genfst4(msg0,ichk,msgsent,msgbits,i4tone,iwspr)
! Input:
! - msg0 requested message to be transmitted
! - ichk if ichk=1, return only msgsent
! - msgsent message as it will be decoded
! - i4tone array of audio tone values, {0,1,2,3}
! - iwspr in: 0: FST4 1: FST4W
! out 0: (240,101)/crc24, 1: (240,74)/crc24
!
! Frame structure:
! s8 d30 s8 d30 s8 d30 s8 d30 s8
use packjt77
include 'fst4_params.f90'
character*37 msg0
character*37 message !Message to be generated
character*37 msgsent !Message as it will be received
character*77 c77
character*24 c24
integer*4 i4tone(NN),itmp(ND)
integer*1 codeword(2*ND)
integer*1 msgbits(101),rvec(77)
integer isyncword1(8),isyncword2(8)
integer ncrc24
logical unpk77_success
data isyncword1/0,1,3,2,1,0,2,3/
data isyncword2/2,3,1,0,3,2,0,1/
data rvec/0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,0,1,1,0, &
1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,0,1,1,1,1,0,0,1,0,1, &
0,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,0,1/
message=msg0
do i=1, 37
if(ichar(message(i:i)).eq.0) then
message(i:37)=' '
exit
endif
enddo
do i=1,37 !Strip leading blanks
if(message(1:1).ne.' ') exit
message=message(i+1:)
enddo
i3=-1
n3=-1
if(iwspr.eq.1) then
i3=0
n3=6
endif
call pack77(message,i3,n3,c77)
call unpack77(c77,0,msgsent,unpk77_success) !Unpack to get msgsent
msgbits=0
iwspr=0
if(i3.eq.0.and.n3.eq.6) then
iwspr=1
read(c77,'(50i1)') msgbits(1:50)
call get_crc24(msgbits,74,ncrc24)
write(c24,'(b24.24)') ncrc24
read(c24,'(24i1)') msgbits(51:74)
else
read(c77,'(77i1)') msgbits(1:77)
msgbits(1:77)=mod(msgbits(1:77)+rvec,2)
call get_crc24(msgbits,101,ncrc24)
write(c24,'(b24.24)') ncrc24
read(c24,'(24i1)') msgbits(78:101)
endif
if(ichk.eq.1) go to 999
if(unpk77_success) go to 2
1 msgbits=0
itone=0
msgsent='*** bad message *** '
go to 999
entry get_fst4_tones_from_bits(msgbits,i4tone,iwspr)
2 continue
if(iwspr.eq.0) then
call encode240_101(msgbits,codeword)
else
call encode240_74(msgbits(1:74),codeword)
endif
! Grayscale mapping:
! bits tone
! 00 0
! 01 1
! 11 2
! 10 3
do i=1,ND
is=codeword(2*i)+2*codeword(2*i-1)
if(is.le.1) itmp(i)=is
if(is.eq.2) itmp(i)=3
if(is.eq.3) itmp(i)=2
enddo
i4tone( 1: 8)=isyncword1
i4tone( 9: 38)=itmp( 1: 30)
i4tone( 39: 46)=isyncword2
i4tone( 47: 76)=itmp( 31: 60)
i4tone( 77: 84)=isyncword1
i4tone( 85:114)=itmp( 61: 90)
i4tone(115:122)=isyncword2
i4tone(123:152)=itmp( 91:120)
i4tone(153:160)=isyncword1
999 return
end subroutine genfst4

25
lib/fst4/get_crc24.f90 Normal file
View File

@ -0,0 +1,25 @@
subroutine get_crc24(mc,len,ncrc)
!
! 1. To calculate 24-bit CRC, mc(1:len-24) is the message and mc(len-23:len) are zero.
! 2. To check a received CRC, mc(1:len) is the received message plus CRC.
! ncrc will be zero if the received message/CRC are consistent.
!
character c24*24
integer*1 mc(len)
integer*1 r(25),p(25)
integer ncrc
! polynomial for 24-bit CRC 0x100065b
data p/1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,0,1,1,0,1,1/
! divide by polynomial
r=mc(1:25)
do i=0,len-25
r(25)=mc(i+25)
r=mod(r+r(1)*p,2)
r=cshift(r,1)
enddo
write(c24,'(24b1)') r(1:24)
read(c24,'(b24.24)') ncrc
end subroutine get_crc24

View File

@ -0,0 +1,131 @@
subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,badsync)
include 'fst4_params.f90'
complex cd(0:NN*nss-1)
complex cs(0:3,NN)
complex csymb(nss)
complex, allocatable, save :: c1(:,:) ! ideal waveforms, 20 samples per symbol, 4 tones
complex cp(0:3) ! accumulated phase shift over symbol types 0:3
complex csum,cterm
integer isyncword1(0:7),isyncword2(0:7)
integer graymap(0:3)
integer ip(1)
integer hmod
logical one(0:65535,0:15) ! 65536 8-symbol sequences, 16 bits
logical first
logical badsync
real bitmetrics(2*NN,4)
real s2(0:65535)
real s4(0:3,NN)
data isyncword1/0,1,3,2,1,0,2,3/
data isyncword2/2,3,1,0,3,2,0,1/
data graymap/0,1,3,2/
data first/.true./,nss0/-1/
save first,one,cp,nss0
if(nss.ne.nss0 .and. allocated(c1)) deallocate(c1)
if(first .or. nss.ne.nss0) then
allocate(c1(nss,0:3))
one=.false.
do i=0,65535
do j=0,15
if(iand(i,2**j).ne.0) one(i,j)=.true.
enddo
enddo
twopi=8.0*atan(1.0)
dphi=twopi*hmod/nss
do itone=0,3
dp=(itone-1.5)*dphi
phi=0.0
do j=1,nss
c1(j,itone)=cmplx(cos(phi),sin(phi))
phi=mod(phi+dp,twopi)
enddo
cp(itone)=cmplx(cos(phi),sin(phi))
enddo
first=.false.
endif
do k=1,NN
i1=(k-1)*NSS
csymb=cd(i1:i1+NSS-1)
do itone=0,3
cs(itone,k)=sum(csymb*conjg(c1(:,itone)))
enddo
s4(0:3,k)=abs(cs(0:3,k))
enddo
! Sync quality check
is1=0
is2=0
is3=0
is4=0
is5=0
badsync=.false.
ibmax=0
do k=1,8
ip=maxloc(s4(:,k))
if(isyncword1(k-1).eq.(ip(1)-1)) is1=is1+1
ip=maxloc(s4(:,k+38))
if(isyncword2(k-1).eq.(ip(1)-1)) is2=is2+1
ip=maxloc(s4(:,k+76))
if(isyncword1(k-1).eq.(ip(1)-1)) is3=is3+1
ip=maxloc(s4(:,k+114))
if(isyncword2(k-1).eq.(ip(1)-1)) is4=is4+1
ip=maxloc(s4(:,k+152))
if(isyncword1(k-1).eq.(ip(1)-1)) is5=is5+1
enddo
nsync=is1+is2+is3+is4+is5 !Number of correct hard sync symbols, 0-40
badsync=.false.
if(nsync .lt. 16) then
badsync=.true.
return
endif
bitmetrics=0.0
do nseq=1,nmax !Try coherent sequences of 1, 2, and 4 symbols
if(nseq.eq.1) nsym=1
if(nseq.eq.2) nsym=2
if(nhicoh.eq.0) then
if(nseq.eq.3) nsym=3
if(nseq.eq.4) nsym=4
else
if(nseq.eq.3) nsym=4
if(nseq.eq.4) nsym=8
endif
nt=4**nsym
do ks=1,NN-nsym+1,nsym
s2=0
do i=0,nt-1
csum=0
cterm=1
do j=0,nsym-1
ntone=mod(i/4**(nsym-1-j),4)
csum=csum+cs(graymap(ntone),ks+j)*cterm
cterm=cterm*conjg(cp(graymap(ntone)))
enddo
s2(i)=abs(csum)
enddo
ipt=1+(ks-1)*2
if(nsym.eq.1) ibmax=1
if(nsym.eq.2) ibmax=3
if(nsym.eq.3) ibmax=5
if(nsym.eq.4) ibmax=7
if(nsym.eq.8) ibmax=15
do ib=0,ibmax
bm=maxval(s2(0:nt-1),one(0:nt-1,ibmax-ib)) - &
maxval(s2(0:nt-1),.not.one(0:nt-1,ibmax-ib))
if(ipt+ib.gt.2*NN) cycle
bitmetrics(ipt+ib,nseq)=bm
enddo
enddo
enddo
call normalizebmet(bitmetrics(:,1),2*NN)
call normalizebmet(bitmetrics(:,2),2*NN)
call normalizebmet(bitmetrics(:,3),2*NN)
call normalizebmet(bitmetrics(:,4),2*NN)
return
end subroutine get_fst4_bitmetrics

View File

@ -0,0 +1,131 @@
subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4hmod,badsync)
include 'fst4_params.f90'
complex cd(0:NN*nss-1)
complex csymb(nss)
complex, allocatable, save :: c1(:,:) ! ideal waveforms, 4 tones
complex cp(0:3) ! accumulated phase shift over symbol types 0:3
complex csum,cterm
integer isyncword1(0:7),isyncword2(0:7)
integer graymap(0:3)
integer ip(1)
integer hmod
logical one(0:65535,0:15) ! 65536 8-symbol sequences, 16 bits
logical first
logical badsync
real bitmetrics(2*NN,4)
real s2(0:65535)
real s4(0:3,NN,4),s4hmod(0:3,NN)
data isyncword1/0,1,3,2,1,0,2,3/
data isyncword2/2,3,1,0,3,2,0,1/
data graymap/0,1,3,2/
data first/.true./,nss0/-1/
save first,one,cp,nss0
if(nss.ne.nss0 .and. allocated(c1)) deallocate(c1)
if(first .or. nss.ne.nss0) then
allocate(c1(nss,0:3))
one=.false.
do i=0,65535
do j=0,15
if(iand(i,2**j).ne.0) one(i,j)=.true.
enddo
enddo
twopi=8.0*atan(1.0)
dphi=twopi*hmod/nss
do itone=0,3
dp=(itone-1.5)*dphi
phi=0.0
do j=1,nss
c1(j,itone)=cmplx(cos(phi),sin(phi))
phi=mod(phi+dp,twopi)
enddo
cp(itone)=cmplx(cos(phi),sin(phi))
enddo
first=.false.
endif
do k=1,NN
i1=(k-1)*NSS
csymb=cd(i1:i1+NSS-1)
do itone=0,3
s4(itone,k,1)=abs(sum(csymb*conjg(c1(:,itone))))
s4(itone,k,2)=abs(sum(csymb( 1:nss/2)*conjg(c1( 1:nss/2,itone)))) + &
abs(sum(csymb(nss/2+1: nss)*conjg(c1(nss/2+1: nss,itone))))
s4(itone,k,3)=abs(sum(csymb( 1: nss/4)*conjg(c1( 1: nss/4,itone)))) + &
abs(sum(csymb( nss/4+1: nss/2)*conjg(c1( nss/4+1: nss/2,itone)))) + &
abs(sum(csymb( nss/2+1:3*nss/4)*conjg(c1( nss/2+1:3*nss/4,itone)))) + &
abs(sum(csymb(3*nss/4+1: nss)*conjg(c1(3*nss/4+1: nss,itone))))
s4(itone,k,4)=abs(sum(csymb( 1: nss/8)*conjg(c1( 1: nss/8,itone)))) + &
abs(sum(csymb( nss/8+1: nss/4)*conjg(c1( nss/8+1: nss/4,itone)))) + &
abs(sum(csymb( nss/4+1:3*nss/8)*conjg(c1( nss/4+1:3*nss/8,itone)))) + &
abs(sum(csymb(3*nss/8+1: nss/2)*conjg(c1(3*nss/8+1: nss/2,itone)))) + &
abs(sum(csymb( nss/2+1:5*nss/8)*conjg(c1( nss/2+1:5*nss/8,itone)))) + &
abs(sum(csymb(5*nss/8+1:3*nss/4)*conjg(c1(5*nss/8+1:3*nss/4,itone)))) + &
abs(sum(csymb(3*nss/4+1:7*nss/8)*conjg(c1(3*nss/4+1:7*nss/8,itone)))) + &
abs(sum(csymb(7*nss/8+1: nss)*conjg(c1(7*nss/8+1: nss,itone))))
enddo
enddo
! Sync quality check
is1=0
is2=0
is3=0
is4=0
is5=0
badsync=.false.
ibmax=0
is1=0; is2=0; is3=0; is4=0; is5=0
do k=1,8
ip=maxloc(s4(:,k,1))
if(isyncword1(k-1).eq.(ip(1)-1)) is1=is1+1
ip=maxloc(s4(:,k+38,1))
if(isyncword2(k-1).eq.(ip(1)-1)) is2=is2+1
ip=maxloc(s4(:,k+76,1))
if(isyncword1(k-1).eq.(ip(1)-1)) is3=is3+1
ip=maxloc(s4(:,k+114,1))
if(isyncword2(k-1).eq.(ip(1)-1)) is4=is4+1
ip=maxloc(s4(:,k+152,1))
if(isyncword1(k-1).eq.(ip(1)-1)) is5=is5+1
enddo
nsync=is1+is2+is3+is4+is5 !Number of correct hard sync symbols, 0-40
badsync=.false.
if(nsync .lt. 16) then
badsync=.true.
return
endif
bitmetrics=0.0
do nsub=1,nsizes
do ks=1,NN
s2=0
do i=0,3
s2(i)=s4(graymap(i),ks,nsub)
enddo
ipt=1+(ks-1)*2
ibmax=1
do ib=0,ibmax
bm=maxval(s2(0:3),one(0:3,ibmax-ib)) - &
maxval(s2(0:3),.not.one(0:3,ibmax-ib))
if(ipt+ib.gt.2*NN) cycle
bitmetrics(ipt+ib,nsub)=bm
enddo
enddo
enddo
call normalizebmet(bitmetrics(:,1),2*NN)
call normalizebmet(bitmetrics(:,2),2*NN)
call normalizebmet(bitmetrics(:,3),2*NN)
call normalizebmet(bitmetrics(:,4),2*NN)
! Return the s4 array corresponding to N=1/hmod. Will be used for SNR calculation
if(hmod.eq.1) s4hmod(:,:)=s4(:,:,1)
if(hmod.eq.2) s4hmod(:,:)=s4(:,:,2)
if(hmod.eq.4) s4hmod(:,:)=s4(:,:,3)
if(hmod.eq.8) s4hmod(:,:)=s4(:,:,4)
return
end subroutine get_fst4_bitmetrics2

View File

@ -0,0 +1,142 @@
character*26 g(139)
data g/ &
"e28df133efbc554bcd30eb1828", &
"b1adf97787f81b4ac02e0caff8", &
"e70c43adce5036f847af367560", &
"c26663f7f7acafdf5abacb6f30", &
"eba93204ddfa3bcf994aea8998", &
"126b51e33c6a740afa0d5ce990", &
"b41a1569e6fede1f2f5395cb68", &
"1d3af0bb43fddbc670a291cc70", &
"e0aebd9921e2c9e1d453ffccb0", &
"897d1370f0df94b8b27a5e4fb8", &
"5e97539338003b13fa8198ad38", &
"7276b87da4a4d777e2752fdd48", &
"989888bd3a85835e2bc6a560f8", &
"7ec4f4a56199ab0a8d6e102478", &
"207007665090258782d1b38a98", &
"1ea1f61cd7f0b7eed7dd346ab8", &
"08f150b27c7f18a027783de0e8", &
"d42324a4e21b62d548d7865858", &
"2e029656269d4fe46e167d21d0", &
"7d84acb7737b0ca6b6f2ef5eb0", &
"6674ca04528ad4782bf5e15248", &
"118ce9825f563ae4963af7a0b0", &
"fb06248cc985e314b1b36ccd38", &
"1c478b7a5aec7e1cfc9c24eb70", &
"185a0f06a84f7f4f484c455020", &
"98b840a3a70688cd58588e3e30", &
"cfb7719de83a3baf582e5b2aa0", &
"9d8cc6b5a01fdbfa307a769048", &
"ed776a728ca162d6fcc8996760", &
"8d2b068128dfb2f8d22c79db50", &
"bd2ba50007789ffb7324aa9190", &
"fd95008fe88812025e78065610", &
"3027849be8e99f9ef68eac1020", &
"88574e1ea39d87414b15e803a8", &
"89365b330e76e6dde740dced08", &
"c83f37b913ed0f6b802aaf21d8", &
"bdca7c1959caa7488b7eb13030", &
"794e0b4888e1ef42992287dd98", &
"526ac87fbaa790c6cd58864e08", &
"940518ba1a51c1da55bc8b2d70", &
"59c5e51ebfbd02ab30ff822378", &
"c81fff87866e04f8f3948c7f10", &
"7913513f3e2a3c0f76b69f6d68", &
"e43cc04da189c44803c4f740a0", &
"fdca7c1959ca85488b7eb13030", &
"95b07fce9b7b1bf4f057ca61b8", &
"d7db48a86691a0c0c9305aac90", &
"0d50bf79a59464597c43ba8058", &
"4a9c34b23fd5eaff8c9dc215e0", &
"3d5305a6f0427938eeb9d1c118", &
"55d8b6b58039f7a3a2d592a900", &
"784f349ecb74c4abbdbb073b90", &
"5973bbb2205f9d6a5c9a55c238", &
"5d2ee61006fec94f69f6b0f460", &
"9e1f52ef1e6589990dd0ce0cc8", &
"85b7b48f4b45775c9f8a36cc90", &
"ae1d6a0171168f6d70804b79f8", &
"a467aa9aa6cdc7094677c730d8", &
"dcf2f56c9ae20fb57e89b916d0", &
"3ae98d26ae96ea714c1a5146d0", &
"103c89581446805b8c71b2e638", &
"6783f3dfec835dd4e92131cc20", &
"52f88428c50f12c55876f7d8a8", &
"51fcb0e56a22fa3b7140aeaa80", &
"07c54871155603e65325f66cd8", &
"a8dd4fac47a113ee5706eef180", &
"f6cdc6f4cc1fa7e4db15bf86f8", &
"2e1c6a0171168f6d70c04a79f8", &
"2a90ab82bef6424db981752dc8", &
"845a1db59c193249d937e889d0", &
"a929d379f1769cb4baa4e41e90", &
"0c2a5829548d82223d6f566d48", &
"420087bc5c4e2f5bc139ad0220", &
"6df8d880ae7209fe52c69ede00", &
"dfbdcef29a985fd40d052d1a88", &
"8567fc332342b1ed8408f5fa00", &
"c908feb4e1866a24ca0c702a08", &
"645f5ee59f9f64fd43a5f2ec30", &
"bee56991e877baf3e9cf11b770", &
"649ea2e4194ca51be28abf3430", &
"90e7394c551bd58d00686d5420", &
"4e3cf731f8f89e8414214afaf0", &
"dcbf16aa8180a7712571e94f98", &
"9b456c015999c52b7fbd1ab390", &
"397ab76924659c4b8b3be4ac58", &
"4f5038c4f9da4b02bdfa178278", &
"4892fada978c98dd4fd363c450", &
"6c8af64b426bc474431c110c98", &
"84a553be5ef0e57390a5af05b0", &
"bed4a9347c9a2064f6d63ac0f8", &
"d973bbb2605f9d6a5c9a57c238", &
"1e3bee9a99fe10d3864ee669d8", &
"a590771ff185d807cb32f46000", &
"9a498fc4b549d81c625f80fc90", &
"28b3e72878aadee7e0e2617950", &
"96ce025d621a91396aa8f3ec20", &
"4f5a77becf838a590d6d406ea8", &
"52d3856dfb9fe78012f10e25c0", &
"b45323c2b28b4752ca0675d2e0", &
"3bae5a8452a785beb35851ad18", &
"65098832d20d915e75bea336e8", &
"5eb6f3c331098e8c0fbfa3aee0", &
"ef19d974a25540c8998fbf1df0", &
"403ea58feff08cf92d5cacc780", &
"6ba93204ddfa7bcb994aea8998", &
"653909166aa7bead4bd9c90020", &
"089cb20e639bc5a44da66f17c0", &
"10f803949961359e994f5ade88", &
"15b7ec1e6106cd55ef7d996590", &
"c99e99de9d85d2b999a17a95d8", &
"ca3e161b97148bac6dd28a6178", &
"e1ab199c992cb4c22aee115358", &
"ea8a4d0e96d3d9f827899b6d88", &
"8af4992d60223f021569a8ab60", &
"5087771abceb87a6d872291fe8", &
"d045e0812e217bb7bbdac92f30", &
"ccccd78ae5fa6e191f21c06908", &
"54545f37df6fed4734ef6509b0", &
"b0780327d899cbc03d95a81a48", &
"a4229c31f2b85e44a322273d50", &
"d182ab001c2085ea7be26a20d0", &
"1a82c30b4fba7dfaafb8d287a8", &
"d974fba598e7fb0630c1587db0", &
"b5c078a8cbab3e73728659ea20", &
"626bbf9eed1a8715c3a7d38f60", &
"c1efe9aa67130865fda93d8be8", &
"d39796dbce155df6306e7b77c0", &
"c7e7c1f032d7209b4549e84aa8", &
"d5799b30a1605baf6b9cd04960", &
"0baf2d21051a926dfd87046d70", &
"da8bf7d1e305c499b573c02cc8", &
"0ccaa7fffb9ae3e42dd0688328", &
"b951b62e18f5290ac13c195130", &
"79b006f001961fb233be80d0e8", &
"56637b6dedfd6e050f06404a48", &
"e0c4bf71a15597523bbd57bde0", &
"1312231ffa04426a34a8fab038", &
"db5f6f0455d24b8358d1cbc3d8", &
"d559e31b34d21f48e1f501af30"/

View File

@ -0,0 +1,393 @@
data Mn/ &
57, 100, 134, &
56, 99, 136, &
1, 12, 15, &
2, 23, 72, &
3, 133, 137, &
4, 93, 125, &
5, 68, 139, &
6, 38, 55, &
7, 40, 78, &
8, 30, 84, &
9, 17, 122, &
10, 34, 95, &
11, 36, 138, &
13, 90, 132, &
14, 50, 117, &
16, 57, 83, &
18, 22, 121, &
19, 60, 89, &
20, 98, 107, &
21, 37, 61, &
24, 26, 75, &
25, 88, 115, &
27, 49, 127, &
28, 74, 119, &
29, 111, 114, &
31, 91, 129, &
32, 96, 104, &
30, 33, 130, &
35, 65, 135, &
41, 42, 87, &
44, 108, 131, &
45, 94, 101, &
45, 46, 97, &
47, 102, 134, &
48, 64, 104, &
19, 51, 116, &
20, 52, 67, &
53, 104, 113, &
12, 54, 103, &
58, 66, 88, &
62, 80, 124, &
63, 70, 71, &
73, 114, 123, &
76, 85, 128, &
77, 106, 109, &
46, 79, 126, &
61, 81, 110, &
82, 92, 120, &
86, 105, 112, &
66, 100, 118, &
23, 51, 136, &
1, 40, 53, &
2, 73, 81, &
3, 63, 130, &
4, 68, 136, &
5, 60, 78, &
6, 72, 131, &
7, 115, 124, &
8, 89, 120, &
9, 15, 44, &
10, 22, 93, &
11, 49, 100, &
13, 55, 80, &
14, 76, 95, &
16, 54, 111, &
17, 41, 110, &
18, 69, 139, &
21, 24, 116, &
25, 39, 71, &
26, 69, 90, &
27, 101, 133, &
28, 64, 126, &
29, 94, 103, &
31, 56, 57, &
32, 91, 102, &
33, 35, 129, &
34, 47, 128, &
36, 86, 117, &
37, 74, 75, &
38, 79, 106, &
42, 82, 123, &
43, 77, 99, &
48, 70, 92, &
50, 109, 118, &
52, 112, 119, &
58, 62, 108, &
59, 84, 134, &
57, 65, 122, &
67, 97, 113, &
83, 127, 135, &
85, 121, 125, &
87, 132, 137, &
96, 98, 105, &
73, 107, 138, &
1, 83, 89, &
2, 41, 70, &
3, 35, 131, &
4, 111, 128, &
5, 29, 99, &
6, 25, 31, &
7, 19, 96, &
1, 39, 110, &
2, 7, 117, &
3, 49, 109, &
4, 81, 96, &
5, 100, 108, &
6, 51, 124, &
2, 20, 132, &
8, 80, 137, &
9, 56, 67, &
10, 63, 102, &
11, 16, 101, &
12, 115, 122, &
13, 32, 128, &
14, 15, 130, &
14, 70, 99, &
11, 51, 69, &
17, 89, 105, &
18, 83, 99, &
19, 44, 79, &
20, 106, 133, &
10, 21, 123, &
22, 23, 61, &
16, 22, 60, &
24, 38, 114, &
25, 37, 42, &
26, 43, 52, &
27, 68, 71, &
28, 65, 139, &
29, 62, 69, &
30, 92, 126, &
31, 78, 123, &
13, 44, 78, &
33, 40, 120, &
7, 34, 119, &
4, 35, 77, &
12, 36, 52, &
25, 98, 136, &
5, 24, 133, &
1, 80, 91, &
33, 96, 97, &
34, 41, 91, &
32, 37, 117, &
26, 72, 125, &
19, 65, 75, &
45, 131, 136, &
46, 55, 70, &
47, 48, 50, &
6, 48, 94, &
3, 74, 79, &
39, 50, 126, &
23, 118, 127, &
21, 36, 113, &
53, 77, 134, &
30, 54, 55, &
17, 46, 135, &
9, 92, 102, &
57, 85, 87, &
58, 125, 138, &
59, 76, 93, &
60, 66, 107, &
47, 132, 138, &
29, 85, 131, &
43, 73, 108, &
64, 75, 129, &
28, 38, 53, &
61, 106, 122, &
56, 71, 114, &
27, 57, 120, &
62, 67, 130, &
54, 104, 118, &
8, 68, 115, &
72, 86, 111, &
73, 74, 94, &
49, 105, 113, &
42, 86, 121, &
40, 59, 109, &
35, 88, 95, &
31, 107, 112, &
58, 64, 87, &
68, 79, 104, &
1, 5, 121, &
15, 82, 93, &
18, 88, 116, &
82, 84, 119, &
7, 71, 103, &
4, 80, 94, &
63, 81, 84, &
66, 76, 137, &
83, 124, 129, &
90, 112, 116, &
89, 111, 134, &
6, 21, 120, &
3, 16, 25, &
12, 28, 131, &
45, 95, 110, &
17, 93, 124, &
97, 121, 127, &
98, 103, 135, &
8, 99, 138, &
41, 101, 139, &
13, 24, 105, &
14, 53, 107, &
10, 64, 98, &
11, 35, 78, &
90, 100, 103, &
9, 72, 101, &
18, 74, 92, &
15, 73, 87, &
2, 88, 113, &
20, 55, 85, &
19, 67, 110, &
26, 27, 95, &
22, 50, 114, &
29, 49, 81, &
32, 52, 83, &
30, 37, 77, &
39, 128, 135, &
23, 128, 130, &
36, 76, 126, &
33, 132, 139, &
34, 89, 118, &
38, 58, 127, &
31, 54, 125, &
40, 70, 75, &
41, 109, 116, &
43, 60, 63, &
44, 84, 86, &
42, 47, 62, &
45, 82, 90, &
43, 46, 91, &
48, 112, 122, &
51, 102, 133, &
59, 61, 108, &
65, 117, 137, &
56, 66, 96, &
59, 69, 104, &
39, 69, 119, &
97, 115, 123, &
106, 111, 129/
data Nm/ &
3, 52, 95, 102, 140, 182, &
4, 53, 96, 103, 108, 210, &
5, 54, 97, 104, 150, 194, &
6, 55, 98, 105, 136, 187, &
7, 56, 99, 106, 139, 182, &
8, 57, 100, 107, 149, 193, &
9, 58, 101, 103, 135, 186, &
10, 59, 109, 172, 200, 0, &
11, 60, 110, 157, 207, 0, &
12, 61, 111, 122, 204, 0, &
13, 62, 112, 117, 205, 0, &
3, 39, 113, 137, 195, 0, &
14, 63, 114, 133, 202, 0, &
15, 64, 115, 116, 203, 0, &
3, 60, 115, 183, 209, 0, &
16, 65, 112, 124, 194, 0, &
11, 66, 118, 156, 197, 0, &
17, 67, 119, 184, 208, 0, &
18, 36, 101, 120, 145, 212, &
19, 37, 108, 121, 211, 0, &
20, 68, 122, 153, 193, 0, &
17, 61, 123, 124, 214, 0, &
4, 51, 123, 152, 219, 0, &
21, 68, 125, 139, 202, 0, &
22, 69, 100, 126, 138, 194, &
21, 70, 127, 144, 213, 0, &
23, 71, 128, 169, 213, 0, &
24, 72, 129, 166, 195, 0, &
25, 73, 99, 130, 163, 215, &
10, 28, 131, 155, 217, 0, &
26, 74, 100, 132, 179, 224, &
27, 75, 114, 143, 216, 0, &
28, 76, 134, 141, 221, 0, &
12, 77, 135, 142, 222, 0, &
29, 76, 97, 136, 178, 205, &
13, 78, 137, 153, 220, 0, &
20, 79, 126, 143, 217, 0, &
8, 80, 125, 166, 223, 0, &
69, 102, 151, 218, 238, 0, &
9, 52, 134, 177, 225, 0, &
30, 66, 96, 142, 201, 226, &
30, 81, 126, 176, 229, 0, &
82, 127, 164, 227, 231, 0, &
31, 60, 120, 133, 228, 0, &
32, 33, 146, 196, 230, 0, &
33, 46, 147, 156, 231, 0, &
34, 77, 148, 162, 229, 0, &
35, 83, 148, 149, 232, 0, &
23, 62, 104, 175, 215, 0, &
15, 84, 148, 151, 214, 0, &
36, 51, 107, 117, 233, 0, &
37, 85, 127, 137, 216, 0, &
38, 52, 154, 166, 203, 0, &
39, 65, 155, 171, 224, 0, &
8, 63, 147, 155, 211, 0, &
2, 74, 110, 168, 236, 0, &
1, 16, 74, 88, 158, 169, &
40, 86, 159, 180, 223, 0, &
87, 160, 177, 234, 237, 0, &
18, 56, 124, 161, 227, 0, &
20, 47, 123, 167, 234, 0, &
41, 86, 130, 170, 229, 0, &
42, 54, 111, 188, 227, 0, &
35, 72, 165, 180, 204, 0, &
29, 88, 129, 145, 235, 0, &
40, 50, 161, 189, 236, 0, &
37, 89, 110, 170, 212, 0, &
7, 55, 128, 172, 181, 0, &
67, 70, 117, 130, 237, 238, &
42, 83, 96, 116, 147, 225, &
42, 69, 128, 168, 186, 0, &
4, 57, 144, 173, 207, 0, &
43, 53, 94, 164, 174, 209, &
24, 79, 150, 174, 208, 0, &
21, 79, 145, 165, 225, 0, &
44, 64, 160, 189, 220, 0, &
45, 82, 136, 154, 217, 0, &
9, 56, 132, 133, 205, 0, &
46, 80, 120, 150, 181, 0, &
41, 63, 109, 140, 187, 0, &
47, 53, 105, 188, 215, 0, &
48, 81, 183, 185, 230, 0, &
16, 90, 95, 119, 190, 216, &
10, 87, 185, 188, 228, 0, &
44, 91, 158, 163, 211, 0, &
49, 78, 173, 176, 228, 0, &
30, 92, 158, 180, 209, 0, &
22, 40, 178, 184, 210, 0, &
18, 59, 95, 118, 192, 222, &
14, 70, 191, 206, 230, 0, &
26, 75, 140, 142, 231, 0, &
48, 83, 131, 157, 208, 0, &
6, 61, 160, 183, 197, 0, &
32, 73, 149, 174, 187, 0, &
12, 64, 178, 196, 213, 0, &
27, 93, 101, 105, 141, 236, &
33, 89, 141, 198, 239, 0, &
19, 93, 138, 199, 204, 0, &
2, 82, 99, 116, 119, 200, &
1, 50, 62, 106, 206, 0, &
32, 71, 112, 201, 207, 0, &
34, 75, 111, 157, 233, 0, &
39, 73, 186, 199, 206, 0, &
27, 35, 38, 171, 181, 237, &
49, 93, 118, 175, 202, 0, &
45, 80, 121, 167, 240, 0, &
19, 94, 161, 179, 203, 0, &
31, 86, 106, 164, 234, 0, &
45, 84, 104, 177, 226, 0, &
47, 66, 102, 196, 212, 0, &
25, 65, 98, 173, 192, 240, &
49, 85, 179, 191, 232, 0, &
38, 89, 153, 175, 210, 0, &
25, 43, 125, 168, 214, 0, &
22, 58, 113, 172, 239, 0, &
36, 68, 184, 191, 226, 0, &
15, 78, 103, 143, 235, 0, &
50, 84, 152, 171, 222, 0, &
24, 85, 135, 185, 238, 0, &
48, 59, 134, 169, 193, 0, &
17, 91, 176, 182, 198, 0, &
11, 88, 113, 167, 232, 0, &
43, 81, 122, 132, 239, 0, &
41, 58, 107, 190, 197, 0, &
6, 91, 144, 159, 224, 0, &
46, 72, 131, 151, 220, 0, &
23, 90, 152, 198, 223, 0, &
44, 77, 98, 114, 218, 219, &
26, 76, 165, 190, 240, 0, &
28, 54, 115, 170, 219, 0, &
31, 57, 97, 146, 163, 195, &
14, 92, 108, 162, 221, 0, &
5, 71, 121, 139, 233, 0, &
1, 34, 87, 154, 192, 0, &
29, 90, 156, 199, 218, 0, &
2, 51, 55, 138, 146, 0, &
5, 92, 109, 189, 235, 0, &
13, 94, 159, 162, 200, 0, &
7, 67, 129, 201, 221, 0/
data nrw/ &
6,6,6,6,6,6,6,5,5,5,5,5,5,5,5,5,5,5,6,5, &
5,5,5,5,6,5,5,5,6,5,6,5,5,5,6,5,5,5,5,5, &
6,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,5,5,5, &
5,5,5,5,5,5,5,5,6,6,5,5,6,5,5,5,5,5,5,5, &
5,5,6,5,5,5,5,5,6,5,5,5,5,5,5,6,5,5,6,5, &
5,5,5,6,5,5,5,5,5,5,6,5,5,5,5,5,5,5,5,5, &
5,5,5,5,5,5,5,6,5,5,6,5,5,5,5,5,5,5,5/
ncw=3

View File

@ -0,0 +1,170 @@
character*19 g(166)
data g/ &
"de8b3201e3c59f55a14", &
"2e06d352ebc5b74c4fc", &
"2e16d6cf5a725c3244c", &
"84f5587edca6d777de4", &
"e152b1e2b5965093ecc", &
"244b4828a2ccf2b5f58", &
"5fbbaade810e123c730", &
"6b7e92a99a918df3d44", &
"bbcec6a63ab757a7278", &
"f5f3f0b89a21ceccdb0", &
"a248c5f1ec2bc816290", &
"c84bbad839a5fe76d0c", &
"ad724129bbf4c7f4570", &
"91adb56e7623a2575cc", &
"cbe995bdf156df2c9e4", &
"92ff6ea492c08c150e0", &
"c4ddbe5a02f6a933384", &
"d2e9befc131dc483858", &
"68567543d1eebcb080c", &
"21fa61d559f9baf6abc", &
"911c4fbbafc72e3db28", &
"7c0b534af4b7d583d50", &
"12ce371b90ee9dfe72c", &
"15a604148872e251ec4", &
"3a3c9f3eb0e0f96edc0", &
"705919ffb636f96b390", &
"43daaaa8163d6bc2bd4", &
"96e11ea798b74b10e98", &
"811150609c9dee8230c", &
"be713f85ab34380f4b0", &
"5a02c4abaaccb8f24c4", &
"67bdebb8863d04768cc", &
"5a449cd90c3dbdfe844", &
"9c7a54d1c4ef7418b84", &
"cd82fefaaf9cd28cd8c", &
"ca47e847fabb0054a38", &
"f0b30cef6aab9e37f98", &
"d948d912fbcc1708710", &
"cce1a7b355053d98270", &
"4cf227c225a9063dd48", &
"2db92612e9ba1418e24", &
"3d215c04c762c3d6a28", &
"77de65500b5624ceb0c", &
"fd1a1df99ded2fb9d88", &
"2a19392c71438410fb8", &
"a9b486a9d26ed579754", &
"b698d244ac78d97a498", &
"3d7975b74d727a5e704", &
"38094225a2bce0e1940", &
"3d3e58fae40fac342b0", &
"7732e839a066e337714", &
"69356c082b7753a47b0", &
"3e868a55dc403a802ac", &
"a0157a14a6bf7fdbbcc", &
"1ab628e11a7ab4a7c44", &
"9da3a2247d7449052f4", &
"199a8a7b114816b97f4", &
"b1c5cde2542061704cc", &
"432fa8d3a153eafbdc8", &
"c4ece7e400d8a89c448", &
"316ecf74e4b983f007c", &
"6a14fa8e713bb5e8adc", &
"da4b957ded8374e3640", &
"0a804dba7c7e4533300", &
"52c342ed033f86580e0", &
"1667da8d6fcf4272470", &
"da2f7038d550fa88d8c", &
"685bcbab1d9dd2c2a44", &
"4c93008b3156b3636bc", &
"726998d6327ac797c3c", &
"44ece7e400d8a8dc448", &
"01f9add00dfe823a948", &
"dbb95f5ce9e371ad720", &
"fc746ee5c76827a8728", &
"b25408029506467f4b4", &
"9b5c9219e21126b7cf8", &
"39ae9f48ba9d1a24f04", &
"7de2699623eb507f938", &
"b9c6e903ee91dd32934", &
"397510d2c6cb5e81de8", &
"20157a14aebf7fdbbec", &
"067f76ea5817a465980", &
"9248f3cea0869feb994", &
"23cde2678004ebe5f80", &
"5b81fe6848f58e3cfa8", &
"a9099ace96bff092904", &
"4afa4b0802b33215438", &
"f4f740396b030360858", &
"fc613f77a35ee1163b8", &
"1a4dc27d7e8cc835ff4", &
"e9b056f153b39def7ec", &
"b62eb777a2f953c7efc", &
"388ae4de514b62d238c", &
"891529af40e85317160", &
"474f1afeb724dbd2ba8", &
"11d70880fd88fdd307c", &
"29f26a3acb76e6a517c", &
"df3e902ff9cadcf776c", &
"e3c42da8445965c09f0", &
"ce277a6aeccc316dc58", &
"4d7841fb71543abd9b8", &
"e63230d2d465fb44750", &
"b6e11fa798b74b14e98", &
"05f189d37c5616547b4", &
"ebdb51a81d1e883baa8", &
"bf5bc736663bcd53ae0", &
"2f8d1cc0936142c08fc", &
"436b22fc36d917b6928", &
"044b482822ccf2b5f58", &
"37b2e839a066e3b7714", &
"2a9b4b765c581f0c51c", &
"10a7d44cecf8e6628dc", &
"ad95f02df6d5502dd4c", &
"bbd34f8afd63deaf564", &
"cabddfeb01fce632788", &
"66b57babeedd6124114", &
"7813e0454fbd462be8c", &
"b6105ed6f01ea621d04", &
"9f68bbcec679d1c088c", &
"673da96e414fc7a0f40", &
"5568adb935e11084abc", &
"f6dd308de5e5c4f6fb0", &
"3b49e80d40ae596c7b4", &
"a3cde2478004ebe5f80", &
"dd8e4f309e919d5ed94", &
"5a4020d387757d7bc28", &
"64f9e02ae32362a255c", &
"630d5942d392334b0dc", &
"0bd7e9f4229b2dee210", &
"bca549a9467d3a2550c", &
"2fef7b1f578c5e28d04", &
"f35e0fdda1be4b3b35c", &
"69ed575e7cc537d2394", &
"7dfdcfbfd5ef3093680", &
"b3b2921af97f251d328", &
"5622d0fe90363522364", &
"fcd4fc7fa04a69d2ac4", &
"1119ea451502ed9ab34", &
"970ee777ec969a41754", &
"688d14f8afec76783dc", &
"4d0b8a1028578407420", &
"d3d2138d9fa268da3e8", &
"df1bdbff898e006394c", &
"8ac478a916bb0b77684", &
"93881997428e2c17a94", &
"4aa510e746245e90c08", &
"e00cb8543f85a5d58b8", &
"9100d8eb74031073044", &
"38710e4235bd1e4003c", &
"6aef311cac4c4dccfd4", &
"58430f577f51c36b3e0", &
"12082fa5d4268a95b4c", &
"7a7435a0aca071e64d0", &
"cd8250ebadc95de15b0", &
"debad40c852e99d64dc", &
"4e6caa5e7c86efef748", &
"a5d4cbb97e726e3c580", &
"7e3a0a2c73ef8553640", &
"b60bfc2fd2bd8f530dc", &
"32dbef097a5f84b0318", &
"4cc7c1cf434300be380", &
"896840945be8eabf7f0", &
"36c9b10ec694819a0a0", &
"349f46a799ef95a47c8", &
"9bdcd4ce2563e560b74", &
"b19fcd7111a335c52ec"/

View File

@ -0,0 +1,423 @@
data Mn/ &
84, 101, 144, &
10, 14, 138, &
87, 148, 166, &
1, 50, 67, &
2, 53, 74, &
3, 83, 113, &
4, 90, 121, &
5, 63, 128, &
6, 124, 138, &
8, 22, 108, &
11, 28, 159, &
12, 18, 142, &
13, 24, 145, &
15, 131, 149, &
16, 44, 93, &
17, 41, 47, &
19, 37, 129, &
20, 33, 94, &
21, 100, 154, &
23, 71, 141, &
25, 89, 95, &
26, 105, 153, &
27, 36, 58, &
29, 59, 166, &
30, 52, 126, &
31, 61, 77, &
32, 84, 111, &
34, 97, 155, &
38, 98, 127, &
39, 76, 143, &
40, 55, 92, &
42, 147, 158, &
43, 82, 148, &
45, 49, 109, &
46, 70, 86, &
48, 78, 139, &
51, 101, 104, &
54, 63, 96, &
56, 81, 125, &
57, 117, 164, &
60, 75, 107, &
39, 62, 132, &
64, 110, 118, &
24, 65, 146, &
66, 80, 134, &
68, 91, 114, &
69, 123, 162, &
72, 88, 152, &
79, 99, 130, &
85, 112, 124, &
99, 103, 157, &
106, 115, 133, &
116, 120, 140, &
119, 161, 165, &
64, 122, 137, &
34, 89, 135, &
136, 138, 163, &
93, 144, 159, &
35, 130, 150, &
62, 151, 164, &
104, 153, 160, &
1, 106, 166, &
2, 132, 152, &
3, 11, 105, &
4, 18, 160, &
5, 53, 91, &
6, 109, 141, &
7, 111, 113, &
8, 54, 136, &
9, 61, 92, &
10, 40, 101, &
12, 30, 146, &
13, 37, 82, &
14, 29, 95, &
1, 47, 131, &
2, 8, 139, &
3, 58, 130, &
4, 96, 115, &
5, 119, 129, &
6, 60, 148, &
7, 95, 163, &
2, 35, 56, &
9, 67, 79, &
10, 75, 122, &
11, 17, 121, &
12, 137, 145, &
13, 36, 152, &
14, 15, 155, &
15, 134, 143, &
16, 106, 125, &
11, 106, 157, &
18, 99, 118, &
19, 50, 94, &
20, 126, 158, &
21, 41, 135, &
22, 24, 71, &
23, 42, 136, &
22, 109, 161, &
25, 39, 46, &
26, 45, 55, &
27, 77, 82, &
28, 73, 166, &
29, 69, 76, &
30, 108, 150, &
31, 91, 146, &
14, 32, 147, &
33, 35, 107, &
34, 103, 111, &
8, 94, 122, &
13, 70, 151, &
32, 37, 142, &
3, 38, 87, &
25, 51, 92, &
40, 57, 72, &
21, 108, 153, &
23, 26, 142, &
43, 44, 48, &
30, 43, 62, &
7, 45, 154, &
16, 46, 149, &
1, 53, 75, &
33, 44, 160, &
49, 86, 157, &
19, 80, 159, &
51, 116, 138, &
52, 92, 98, &
6, 12, 47, &
54, 83, 101, &
24, 55, 102, &
56, 63, 120, &
17, 57, 82, &
38, 154, 162, &
59, 74, 151, &
53, 144, 164, &
61, 85, 117, &
62, 66, 90, &
48, 113, 145, &
64, 65, 128, &
27, 29, 65, &
58, 63, 134, &
9, 74, 83, &
68, 109, 113, &
41, 61, 69, &
36, 60, 155, &
42, 64, 144, &
40, 90, 130, &
28, 110, 135, &
20, 59, 112, &
70, 110, 124, &
54, 76, 105, &
4, 77, 111, &
78, 104, 143, &
66, 67, 91, &
80, 81, 88, &
50, 101, 132, &
71, 97, 120, &
72, 131, 158, &
84, 133, 141, &
5, 85, 99, &
49, 89, 133, &
87, 132, 140, &
34, 88, 104, &
89, 105, 147, &
6, 76, 102, &
18, 31, 163, &
52, 96, 140, &
93, 102, 165, &
79, 104, 165, &
81, 100, 126, &
95, 121, 152, &
97, 123, 153, &
37, 98, 114, &
8, 91, 155, &
100, 114, 160, &
2, 26, 28, &
93, 116, 150, &
68, 103, 166, &
78, 117, 125, &
86, 107, 127, &
4, 59, 136, &
9, 37, 97, &
7, 30, 75, &
80, 148, 153, &
73, 138, 164, &
10, 39, 103, &
39, 146, 156, &
48, 129, 136, &
5, 17, 51, &
112, 149, 161, &
11, 24, 126, &
1, 70, 78, &
14, 113, 118, &
10, 119, 141, &
13, 33, 105, &
19, 57, 89, &
12, 25, 56, &
16, 18, 54, &
84, 124, 162, &
20, 41, 134, &
15, 45, 82, &
115, 118, 123, &
128, 139, 149, &
127, 156, 159, &
21, 141, 152, &
23, 130, 156, &
3, 160, 164, &
22, 90, 110, &
35, 61, 109, &
31, 87, 158, &
42, 60, 106, &
137, 140, 157, &
27, 114, 124, &
32, 62, 125, &
34, 38, 128, &
40, 123, 139, &
29, 66, 86, &
36, 52, 161, &
43, 63, 133, &
46, 73, 108, &
44, 135, 146, &
47, 115, 127, &
49, 74, 116, &
58, 102, 122, &
55, 85, 132, &
50, 65, 150, &
67, 145, 162, &
53, 71, 77, &
69, 88, 142, &
68, 72, 93, &
9, 64, 95, &
92, 94, 111, &
81, 83, 119, &
98, 143, 163, &
73, 79, 96, &
35, 129, 131, &
99, 100, 151, &
7, 112, 159, &
117, 137, 156, &
120, 147, 154, &
107, 121, 165/
data Nm/ &
4, 62, 75, 121, 191, &
5, 63, 76, 82, 175, &
6, 64, 77, 112, 206, &
7, 65, 78, 151, 180, &
8, 66, 79, 159, 188, &
9, 67, 80, 127, 164, &
68, 81, 119, 182, 237, &
10, 69, 76, 109, 173, &
70, 83, 141, 181, 230, &
2, 71, 84, 185, 193, &
11, 64, 85, 91, 190, &
12, 72, 86, 127, 196, &
13, 73, 87, 110, 194, &
2, 74, 88, 106, 192, &
14, 88, 89, 200, 0, &
15, 90, 120, 197, 0, &
16, 85, 131, 188, 0, &
12, 65, 92, 165, 197, &
17, 93, 124, 195, 0, &
18, 94, 148, 199, 0, &
19, 95, 115, 204, 0, &
10, 96, 98, 207, 0, &
20, 97, 116, 205, 0, &
13, 44, 96, 129, 190, &
21, 99, 113, 196, 0, &
22, 100, 116, 175, 0, &
23, 101, 139, 212, 0, &
11, 102, 147, 175, 0, &
24, 74, 103, 139, 216, &
25, 72, 104, 118, 182, &
26, 105, 165, 209, 0, &
27, 106, 111, 213, 0, &
18, 107, 122, 194, 0, &
28, 56, 108, 162, 214, &
59, 82, 107, 208, 235, &
23, 87, 144, 217, 0, &
17, 73, 111, 172, 181, &
29, 112, 132, 214, 0, &
30, 42, 99, 185, 186, &
31, 71, 114, 146, 215, &
16, 95, 143, 199, 0, &
32, 97, 145, 210, 0, &
33, 117, 118, 218, 0, &
15, 117, 122, 220, 0, &
34, 100, 119, 200, 0, &
35, 99, 120, 219, 0, &
16, 75, 127, 221, 0, &
36, 117, 137, 187, 0, &
34, 123, 160, 222, 0, &
4, 93, 155, 225, 0, &
37, 113, 125, 188, 0, &
25, 126, 166, 217, 0, &
5, 66, 121, 134, 227, &
38, 69, 128, 150, 197, &
31, 100, 129, 224, 0, &
39, 82, 130, 196, 0, &
40, 114, 131, 195, 0, &
23, 77, 140, 223, 0, &
24, 133, 148, 180, 0, &
41, 80, 144, 210, 0, &
26, 70, 135, 143, 208, &
42, 60, 118, 136, 213, &
8, 38, 130, 140, 218, &
43, 55, 138, 145, 230, &
44, 138, 139, 225, 0, &
45, 136, 153, 216, 0, &
4, 83, 153, 226, 0, &
46, 142, 177, 229, 0, &
47, 103, 143, 228, 0, &
35, 110, 149, 191, 0, &
20, 96, 156, 227, 0, &
48, 114, 157, 229, 0, &
102, 184, 219, 234, 0, &
5, 133, 141, 222, 0, &
41, 84, 121, 182, 0, &
30, 103, 150, 164, 0, &
26, 101, 151, 227, 0, &
36, 152, 178, 191, 0, &
49, 83, 168, 234, 0, &
45, 124, 154, 183, 0, &
39, 154, 169, 232, 0, &
33, 73, 101, 131, 200, &
6, 128, 141, 232, 0, &
1, 27, 158, 198, 0, &
50, 135, 159, 224, 0, &
35, 123, 179, 216, 0, &
3, 112, 161, 209, 0, &
48, 154, 162, 228, 0, &
21, 56, 160, 163, 195, &
7, 136, 146, 207, 0, &
46, 66, 105, 153, 173, &
31, 70, 113, 126, 231, &
15, 58, 167, 176, 229, &
18, 93, 109, 231, 0, &
21, 74, 81, 170, 230, &
38, 78, 166, 234, 0, &
28, 156, 171, 181, 0, &
29, 126, 172, 233, 0, &
49, 51, 92, 159, 236, &
19, 169, 174, 236, 0, &
1, 37, 71, 128, 155, &
129, 164, 167, 223, 0, &
51, 108, 177, 185, 0, &
37, 61, 152, 162, 168, &
22, 64, 150, 163, 194, &
52, 62, 90, 91, 210, &
41, 107, 179, 240, 0, &
10, 104, 115, 219, 0, &
34, 67, 98, 142, 208, &
43, 147, 149, 207, 0, &
27, 68, 108, 151, 231, &
50, 148, 189, 237, 0, &
6, 68, 137, 142, 192, &
46, 172, 174, 212, 0, &
52, 78, 201, 221, 0, &
53, 125, 176, 222, 0, &
40, 135, 178, 238, 0, &
43, 92, 192, 201, 0, &
54, 79, 193, 232, 0, &
53, 130, 156, 239, 0, &
7, 85, 170, 240, 0, &
55, 84, 109, 223, 0, &
47, 171, 201, 215, 0, &
9, 50, 149, 198, 212, &
39, 90, 178, 213, 0, &
25, 94, 169, 190, 0, &
29, 179, 203, 221, 0, &
8, 138, 202, 214, 0, &
17, 79, 187, 235, 0, &
49, 59, 77, 146, 205, &
14, 75, 157, 235, 0, &
42, 63, 155, 161, 224, &
52, 158, 160, 218, 0, &
45, 89, 140, 199, 0, &
56, 95, 147, 220, 0, &
57, 69, 97, 180, 187, &
55, 86, 211, 238, 0, &
2, 9, 57, 125, 184, &
36, 76, 202, 215, 0, &
53, 161, 166, 211, 0, &
20, 67, 158, 193, 204, &
12, 111, 116, 228, 0, &
30, 89, 152, 233, 0, &
1, 58, 134, 145, 0, &
13, 86, 137, 226, 0, &
44, 72, 105, 186, 220, &
32, 106, 163, 239, 0, &
3, 33, 80, 183, 0, &
14, 120, 189, 202, 0, &
59, 104, 176, 225, 0, &
60, 110, 133, 236, 0, &
48, 63, 87, 170, 204, &
22, 61, 115, 171, 183, &
19, 119, 132, 239, 0, &
28, 88, 144, 173, 0, &
186, 203, 205, 238, 0, &
51, 91, 123, 211, 0, &
32, 94, 157, 209, 0, &
11, 58, 124, 203, 237, &
61, 65, 122, 174, 206, &
54, 98, 189, 217, 0, &
47, 132, 198, 226, 0, &
57, 81, 165, 233, 0, &
40, 60, 134, 184, 206, &
54, 167, 168, 240, 0, &
3, 24, 62, 102, 177/
data nrw/ &
5,5,5,5,5,5,5,5,5,5,5,5,5,5,4,4,4,5,4,4, &
4,4,4,5,4,4,4,4,5,5,4,4,4,5,5,4,5,4,5,5, &
4,4,4,4,4,4,4,4,4,4,4,4,5,5,4,4,4,4,4,4, &
5,5,5,5,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, &
4,5,4,4,4,4,4,4,5,4,5,5,5,4,5,4,4,4,5,4, &
5,4,4,5,5,5,4,4,5,4,5,4,5,4,4,4,4,4,4,4, &
4,4,4,5,4,4,4,4,4,5,4,5,4,4,4,5,4,5,4,4, &
5,4,4,4,4,5,4,4,4,4,4,5,5,4,4,4,4,4,5,5, &
4,4,4,5,4,5/
ncw=3

137
lib/fst4/ldpcsim240_101.f90 Normal file
View File

@ -0,0 +1,137 @@
program ldpcsim240_101
! End-to-end test of the (240,101)/crc24 encoder and decoders.
use packjt77
parameter(N=240, K=101, M=N-K)
character*8 arg
character*37 msg0,msg
character*77 c77
character*24 c24
integer*1 msgbits(101)
integer*1 apmask(240)
integer*1 cw(240)
integer*1 codeword(N),message101(101)
integer ncrc24
real rxdata(N),llr(N)
logical first,unpk77_success
data first/.true./
nargs=iargc()
if(nargs.ne.5 .and. nargs.ne.6) then
print*,'Usage: ldpcsim niter ndeep #trials s K [msg]'
print*,'e.g. ldpcsim240_101 20 5 1000 0.85 91 "K9AN K1JT FN20"'
print*,'s : if negative, then value is ignored and sigma is calculated from SNR.'
print*,'niter: is the number of BP iterations.'
print*,'ndeep: -1 is BP only, ndeep>=0 is OSD order'
print*,'K :is the number of message+CRC bits and must be in the range [77,101]'
print*,'WSPR-format message is optional'
return
endif
call getarg(1,arg)
read(arg,*) max_iterations
call getarg(2,arg)
read(arg,*) norder
call getarg(3,arg)
read(arg,*) ntrials
call getarg(4,arg)
read(arg,*) s
call getarg(5,arg)
read(arg,*) Keff
msg0='K9AN K1JT FN20 '
if(nargs.eq.6) call getarg(6,msg0)
call pack77(msg0,i3,n3,c77)
rate=real(Keff)/real(N)
write(*,*) "code rate: ",rate
write(*,*) "niter : ",max_iterations
write(*,*) "norder : ",norder
write(*,*) "s : ",s
write(*,*) "K : ",Keff
msgbits=0
read(c77,'(77i1)') msgbits(1:77)
write(*,*) 'message'
write(*,'(77i1)') msgbits(1:77)
call get_crc24(msgbits,101,ncrc24)
write(c24,'(b24.24)') ncrc24
read(c24,'(24i1)') msgbits(78:101)
write(*,'(24i1)') msgbits(78:101)
write(*,*) 'message with crc24'
write(*,'(101i1)') msgbits(1:101)
call encode240_101(msgbits,codeword)
call init_random_seed()
call sgran()
write(*,*) 'codeword'
write(*,'(77i1,1x,24i1,1x,73i1)') codeword
write(*,*) "Eb/N0 Es/N0 ngood nundetected sigma symbol error rate"
do idb = 8,-3,-1
db=idb/2.0-1.0
sigma=1/sqrt( 2*rate*(10**(db/10.0)) ) ! to make db represent Eb/No
! sigma=1/sqrt( 2*(10**(db/10.0)) ) ! db represents Es/No
ngood=0
nue=0
nberr=0
do itrial=1, ntrials
! Create a realization of a noisy received word
do i=1,N
rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran()
enddo
nerr=0
do i=1,N
if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1
enddo
nberr=nberr+nerr
rxav=sum(rxdata)/N
rx2av=sum(rxdata*rxdata)/N
rxsig=sqrt(rx2av-rxav*rxav)
rxdata=rxdata/rxsig
if( s .lt. 0 ) then
ss=sigma
else
ss=s
endif
llr=2.0*rxdata/(ss*ss)
apmask=0
dmin=0.0
maxosd=2
call decode240_101(llr, Keff, maxosd, norder, apmask, message101, cw, ntype, nharderror, dmin)
if(nharderror.ge.0) then
n2err=0
do i=1,N
if( cw(i).ne.codeword(i) ) n2err=n2err+1
enddo
if(n2err.eq.0) then
ngood=ngood+1
else
nue=nue+1
endif
endif
enddo
! snr2500=db+10*log10(200.0/116.0/2500.0)
esn0=db+10*log10(rate)
pberr=real(nberr)/(real(ntrials*N))
write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,8x,f5.2,8x,e10.3)") db,esn0,ngood,nue,ss,pberr
if(first) then
write(c77,'(77i1)') message101(1:77)
write(*,'(101i1)') message101
call unpack77(c77,0,msg,unpk77_success)
if(unpk77_success) then
write(*,1100) msg(1:37)
1100 format('Decoded message: ',a37)
else
print*,'Error unpacking message'
endif
first=.false.
endif
enddo
end program ldpcsim240_101

125
lib/fst4/ldpcsim240_74.f90 Normal file
View File

@ -0,0 +1,125 @@
program ldpcsim240_74
! End-to-end test of the (240,74)/crc24 encoder and decoders.
use packjt77
parameter(N=240, K=74, M=N-K)
character*8 arg
character*37 msg0,msg
character*77 c77
character*24 c24
integer*1 msgbits(74)
integer*1 apmask(240)
integer*1 cw(240)
integer*1 codeword(N),message74(74)
integer ncrc24
real rxdata(N),llr(N)
logical first,unpk77_success
data first/.true./
nargs=iargc()
if(nargs.ne.5 .and. nargs.ne.6) then
print*,'Usage: ldpcsim niter ndeep #trials s K [msg]'
print*,'e.g. ldpcsim240_74 20 5 1000 0.85 64 "K9AN K1JT FN20"'
print*,'s : if negative, then value is ignored and sigma is calculated from SNR.'
print*,'niter: is the number of BP iterations.'
print*,'ndeep: -1 is BP only, ndeep>=0 is OSD order'
print*,'K :is the number of message+CRC bits and must be in the range [50,74]'
print*,'WSPR-format message is optional'
return
endif
call getarg(1,arg)
read(arg,*) max_iterations
call getarg(2,arg)
read(arg,*) norder
call getarg(3,arg)
read(arg,*) ntrials
call getarg(4,arg)
read(arg,*) s
call getarg(5,arg)
read(arg,*) Keff
msg0='K9AN K1JT FN20 '
if(nargs.eq.6) call getarg(6,msg0)
call pack77(msg0,i3,n3,c77)
rate=real(Keff)/real(N)
write(*,*) "code rate: ",rate
write(*,*) "niter : ",max_iterations
write(*,*) "norder : ",norder
write(*,*) "s : ",s
write(*,*) "K : ",Keff
msgbits=0
read(c77,'(50i1)') msgbits(1:50)
write(*,*) 'message'
write(*,'(50i1)') msgbits(1:50)
call get_crc24(msgbits,74,ncrc24)
write(c24,'(b24.24)') ncrc24
read(c24,'(24i1)') msgbits(51:74)
write(*,'(24i1)') msgbits(51:74)
write(*,*) 'message with crc24'
write(*,'(74i1)') msgbits(1:74)
call encode240_74(msgbits,codeword)
call init_random_seed()
call sgran()
write(*,*) 'codeword'
write(*,'(77i1,1x,24i1,1x,73i1)') codeword
write(*,*) "Eb/N0 Es/N0 ngood nundetected sigma symbol error rate"
do idb = 8,-3,-1
db=idb/2.0-1.0
sigma=1/sqrt( 2*rate*(10**(db/10.0)) ) ! to make db represent Eb/No
! sigma=1/sqrt( 2*(10**(db/10.0)) ) ! db represents Es/No
ngood=0
nue=0
nberr=0
do itrial=1, ntrials
! Create a realization of a noisy received word
do i=1,N
rxdata(i) = 2.0*codeword(i)-1.0 + sigma*gran()
enddo
nerr=0
do i=1,N
if( rxdata(i)*(2*codeword(i)-1.0) .lt. 0 ) nerr=nerr+1
enddo
nberr=nberr+nerr
rxav=sum(rxdata)/N
rx2av=sum(rxdata*rxdata)/N
rxsig=sqrt(rx2av-rxav*rxav)
rxdata=rxdata/rxsig
if( s .lt. 0 ) then
ss=sigma
else
ss=s
endif
llr=2.0*rxdata/(ss*ss)
apmask=0
dmin=0.0
maxosd=0
call decode240_74(llr, Keff, maxosd, norder, apmask, message74, cw, ntype, nharderror, dmin)
if(nharderror.ge.0) then
n2err=0
do i=1,N
if( cw(i).ne.codeword(i) ) n2err=n2err+1
enddo
if(n2err.eq.0) then
ngood=ngood+1
else
nue=nue+1
endif
endif
enddo
! snr2500=db+10*log10(200.0/116.0/2500.0)
esn0=db+10*log10(rate)
pberr=real(nberr)/(real(ntrials*N))
write(*,"(f4.1,4x,f5.1,1x,i8,1x,i8,8x,e10.3)") db,esn0,ngood,nue,pberr
enddo
end program ldpcsim240_74

403
lib/fst4/osd240_101.f90 Normal file
View File

@ -0,0 +1,403 @@
subroutine osd240_101(llr,k,apmask,ndeep,message101,cw,nhardmin,dmin)
!
! An ordered-statistics decoder for the (240,101) code.
! Message payload is 77 bits. Any or all of a 24-bit CRC can be
! used for detecting incorrect codewords. The remaining CRC bits are
! cascaded with the LDPC code for the purpose of improving the
! distance spectrum of the code.
!
! If p1 (0.le.p1.le.24) is the number of CRC24 bits that are
! to be used for bad codeword detection, then the argument k should
! be set to 77+p1.
!
! Valid values for k are in the range [77,101].
!
character*24 c24
integer, parameter:: N=240
integer*1 apmask(N),apmaskr(N)
integer*1, allocatable, save :: gen(:,:)
integer*1, allocatable :: genmrb(:,:),g2(:,:)
integer*1, allocatable :: temp(:),m0(:),me(:),mi(:),misub(:),e2sub(:),e2(:),ui(:)
integer*1, allocatable :: r2pat(:)
integer indices(N),nxor(N)
integer*1 cw(N),ce(N),c0(N),hdec(N)
integer*1, allocatable :: decoded(:)
integer*1 message101(101)
integer indx(N)
real llr(N),rx(N),absrx(N)
logical first,reset
data first/.true./
save first
allocate( genmrb(k,N), g2(N,k) )
allocate( temp(k), m0(k), me(k), mi(k), misub(k), e2sub(N-k), e2(N-k), ui(N-k) )
allocate( r2pat(N-k), decoded(k) )
if( first ) then ! fill the generator matrix
!
! Create generator matrix for partial CRC cascaded with LDPC code.
!
! Let p2=101-k and p1+p2=24.
!
! The last p2 bits of the CRC24 are cascaded with the LDPC code.
!
! The first p1=k-77 CRC24 bits will be used for error detection.
!
allocate( gen(k,N) )
gen=0
do i=1,k
message101=0
message101(i)=1
if(i.le.77) then
call get_crc24(message101,101,ncrc24)
write(c24,'(b24.24)') ncrc24
read(c24,'(24i1)') message101(78:101)
message101(78:k)=0
endif
call encode240_101(message101,cw)
gen(i,:)=cw
enddo
first=.false.
endif
rx=llr
apmaskr=apmask
! Hard decisions on the received word.
hdec=0
where(rx .ge. 0) hdec=1
! Use magnitude of received symbols as a measure of reliability.
absrx=abs(rx)
call indexx(absrx,N,indx)
! Re-order the columns of the generator matrix in order of decreasing reliability.
do i=1,N
genmrb(1:k,i)=gen(1:k,indx(N+1-i))
indices(i)=indx(N+1-i)
enddo
! Do gaussian elimination to create a generator matrix with the most reliable
! received bits in positions 1:k in order of decreasing reliability (more or less).
do id=1,k ! diagonal element indices
do icol=id,k+20 ! The 20 is ad hoc - beware
iflag=0
if( genmrb(id,icol) .eq. 1 ) then
iflag=1
if( icol .ne. id ) then ! reorder column
temp(1:k)=genmrb(1:k,id)
genmrb(1:k,id)=genmrb(1:k,icol)
genmrb(1:k,icol)=temp(1:k)
itmp=indices(id)
indices(id)=indices(icol)
indices(icol)=itmp
endif
do ii=1,k
if( ii .ne. id .and. genmrb(ii,id) .eq. 1 ) then
genmrb(ii,1:N)=ieor(genmrb(ii,1:N),genmrb(id,1:N))
endif
enddo
exit
endif
enddo
enddo
g2=transpose(genmrb)
! The hard decisions for the k MRB bits define the order 0 message, m0.
! Encode m0 using the modified generator matrix to find the "order 0" codeword.
! Flip various combinations of bits in m0 and re-encode to generate a list of
! codewords. Return the member of the list that has the smallest Euclidean
! distance to the received word.
hdec=hdec(indices) ! hard decisions from received symbols
m0=hdec(1:k) ! zero'th order message
absrx=absrx(indices)
rx=rx(indices)
apmaskr=apmaskr(indices)
call mrbencode101(m0,c0,g2,N,k)
nxor=ieor(c0,hdec)
nhardmin=sum(nxor)
dmin=sum(nxor*absrx)
cw=c0
ntotal=0
nrejected=0
npre1=0
npre2=0
if(ndeep.eq.0) goto 998 ! norder=0
if(ndeep.gt.6) ndeep=6
if( ndeep.eq. 1) then
nord=1
npre1=0
npre2=0
nt=40
ntheta=12
elseif(ndeep.eq.2) then
nord=1
npre1=1
npre2=0
nt=40
ntheta=12
elseif(ndeep.eq.3) then
nord=1
npre1=1
npre2=1
nt=40
ntheta=12
ntau=14
elseif(ndeep.eq.4) then
nord=2
npre1=1
npre2=1
nt=40
ntheta=12
ntau=17
elseif(ndeep.eq.5) then
nord=3
npre1=1
npre2=1
nt=40
ntheta=12
ntau=15
elseif(ndeep.eq.6) then
nord=4
npre1=1
npre2=1
nt=95
ntheta=12
ntau=15
endif
do iorder=1,nord
misub(1:k-iorder)=0
misub(k-iorder+1:k)=1
iflag=k-iorder+1
do while(iflag .ge.0)
if(iorder.eq.nord .and. npre1.eq.0) then
iend=iflag
else
iend=1
endif
d1=0.
do n1=iflag,iend,-1
mi=misub
mi(n1)=1
if(any(iand(apmaskr(1:k),mi).eq.1)) cycle
ntotal=ntotal+1
me=ieor(m0,mi)
if(n1.eq.iflag) then
call mrbencode101(me,ce,g2,N,k)
e2sub=ieor(ce(k+1:N),hdec(k+1:N))
e2=e2sub
nd1kpt=sum(e2sub(1:nt))+1
d1=sum(ieor(me(1:k),hdec(1:k))*absrx(1:k))
else
e2=ieor(e2sub,g2(k+1:N,n1))
nd1kpt=sum(e2(1:nt))+2
endif
if(nd1kpt .le. ntheta) then
call mrbencode101(me,ce,g2,N,k)
nxor=ieor(ce,hdec)
if(n1.eq.iflag) then
dd=d1+sum(e2sub*absrx(k+1:N))
else
dd=d1+ieor(ce(n1),hdec(n1))*absrx(n1)+sum(e2*absrx(k+1:N))
endif
if( dd .lt. dmin ) then
dmin=dd
cw=ce
nhardmin=sum(nxor)
nd1kptbest=nd1kpt
endif
else
nrejected=nrejected+1
endif
enddo
! Get the next test error pattern, iflag will go negative
! when the last pattern with weight iorder has been generated.
call nextpat101(misub,k,iorder,iflag)
enddo
enddo
if(npre2.eq.1) then
reset=.true.
ntotal=0
do i1=k,1,-1
do i2=i1-1,1,-1
ntotal=ntotal+1
mi(1:ntau)=ieor(g2(k+1:k+ntau,i1),g2(k+1:k+ntau,i2))
call boxit101(reset,mi(1:ntau),ntau,ntotal,i1,i2)
enddo
enddo
ncount2=0
ntotal2=0
reset=.true.
! Now run through again and do the second pre-processing rule
misub(1:k-nord)=0
misub(k-nord+1:k)=1
iflag=k-nord+1
do while(iflag .ge.0)
me=ieor(m0,misub)
call mrbencode101(me,ce,g2,N,k)
e2sub=ieor(ce(k+1:N),hdec(k+1:N))
do i2=0,ntau
ntotal2=ntotal2+1
ui=0
if(i2.gt.0) ui(i2)=1
r2pat=ieor(e2sub,ui)
778 continue
call fetchit101(reset,r2pat(1:ntau),ntau,in1,in2)
if(in1.gt.0.and.in2.gt.0) then
ncount2=ncount2+1
mi=misub
mi(in1)=1
mi(in2)=1
if(sum(mi).lt.nord+npre1+npre2.or.any(iand(apmaskr(1:k),mi).eq.1)) cycle
me=ieor(m0,mi)
call mrbencode101(me,ce,g2,N,k)
nxor=ieor(ce,hdec)
dd=sum(nxor*absrx)
if( dd .lt. dmin ) then
dmin=dd
cw=ce
nhardmin=sum(nxor)
endif
goto 778
endif
enddo
call nextpat101(misub,k,nord,iflag)
enddo
endif
998 continue
! Re-order the codeword to [message bits][parity bits] format.
cw(indices)=cw
hdec(indices)=hdec
message101=cw(1:101)
call get_crc24(message101,101,nbadcrc)
if(nbadcrc.ne.0) nhardmin=-nhardmin
return
end subroutine osd240_101
subroutine mrbencode101(me,codeword,g2,N,K)
integer*1 me(K),codeword(N),g2(N,K)
! fast encoding for low-weight test patterns
codeword=0
do i=1,K
if( me(i) .eq. 1 ) then
codeword=ieor(codeword,g2(1:N,i))
endif
enddo
return
end subroutine mrbencode101
subroutine nextpat101(mi,k,iorder,iflag)
integer*1 mi(k),ms(k)
! generate the next test error pattern
ind=-1
do i=1,k-1
if( mi(i).eq.0 .and. mi(i+1).eq.1) ind=i
enddo
if( ind .lt. 0 ) then ! no more patterns of this order
iflag=ind
return
endif
ms=0
ms(1:ind-1)=mi(1:ind-1)
ms(ind)=1
ms(ind+1)=0
if( ind+1 .lt. k ) then
nz=iorder-sum(ms)
ms(k-nz+1:k)=1
endif
mi=ms
do i=1,k ! iflag will point to the lowest-index 1 in mi
if(mi(i).eq.1) then
iflag=i
exit
endif
enddo
return
end subroutine nextpat101
subroutine boxit101(reset,e2,ntau,npindex,i1,i2)
integer*1 e2(1:ntau)
integer indexes(5000,2),fp(0:525000),np(5000)
logical reset
common/boxes/indexes,fp,np
if(reset) then
patterns=-1
fp=-1
np=-1
sc=-1
indexes=-1
reset=.false.
endif
indexes(npindex,1)=i1
indexes(npindex,2)=i2
ipat=0
do i=1,ntau
if(e2(i).eq.1) then
ipat=ipat+ishft(1,ntau-i)
endif
enddo
ip=fp(ipat) ! see what's currently stored in fp(ipat)
if(ip.eq.-1) then
fp(ipat)=npindex
else
do while (np(ip).ne.-1)
ip=np(ip)
enddo
np(ip)=npindex
endif
return
end subroutine boxit101
subroutine fetchit101(reset,e2,ntau,i1,i2)
integer indexes(5000,2),fp(0:525000),np(5000)
integer lastpat
integer*1 e2(ntau)
logical reset
common/boxes/indexes,fp,np
save lastpat,inext
if(reset) then
lastpat=-1
reset=.false.
endif
ipat=0
do i=1,ntau
if(e2(i).eq.1) then
ipat=ipat+ishft(1,ntau-i)
endif
enddo
index=fp(ipat)
if(lastpat.ne.ipat .and. index.gt.0) then ! return first set of indices
i1=indexes(index,1)
i2=indexes(index,2)
inext=np(index)
elseif(lastpat.eq.ipat .and. inext.gt.0) then
i1=indexes(inext,1)
i2=indexes(inext,2)
inext=np(inext)
else
i1=-1
i2=-1
inext=-1
endif
lastpat=ipat
return
end subroutine fetchit101

403
lib/fst4/osd240_74.f90 Normal file
View File

@ -0,0 +1,403 @@
subroutine osd240_74(llr,k,apmask,ndeep,message74,cw,nhardmin,dmin)
!
! An ordered-statistics decoder for the (240,74) code.
! Message payload is 50 bits. Any or all of a 24-bit CRC can be
! used for detecting incorrect codewords. The remaining CRC bits are
! cascaded with the LDPC code for the purpose of improving the
! distance spectrum of the code.
!
! If p1 (0.le.p1.le.24) is the number of CRC24 bits that are
! to be used for bad codeword detection, then the argument k should
! be set to 77+p1.
!
! Valid values for k are in the range [50,74].
!
character*24 c24
integer, parameter:: N=240
integer*1 apmask(N),apmaskr(N)
integer*1, allocatable, save :: gen(:,:)
integer*1, allocatable :: genmrb(:,:),g2(:,:)
integer*1, allocatable :: temp(:),m0(:),me(:),mi(:),misub(:),e2sub(:),e2(:),ui(:)
integer*1, allocatable :: r2pat(:)
integer indices(N),nxor(N)
integer*1 cw(N),ce(N),c0(N),hdec(N)
integer*1, allocatable :: decoded(:)
integer*1 message74(74)
integer indx(N)
real llr(N),rx(N),absrx(N)
logical first,reset
data first/.true./
save first
allocate( genmrb(k,N), g2(N,k) )
allocate( temp(k), m0(k), me(k), mi(k), misub(k), e2sub(N-k), e2(N-k), ui(N-k) )
allocate( r2pat(N-k), decoded(k) )
if( first ) then ! fill the generator matrix
!
! Create generator matrix for partial CRC cascaded with LDPC code.
!
! Let p2=74-k and p1+p2=24.
!
! The last p2 bits of the CRC24 are cascaded with the LDPC code.
!
! The first p1=k-50 CRC24 bits will be used for error detection.
!
allocate( gen(k,N) )
gen=0
do i=1,k
message74=0
message74(i)=1
if(i.le.50) then
call get_crc24(message74,74,ncrc24)
write(c24,'(b24.24)') ncrc24
read(c24,'(24i1)') message74(51:74)
message74(51:k)=0
endif
call encode240_74(message74,cw)
gen(i,:)=cw
enddo
first=.false.
endif
rx=llr
apmaskr=apmask
! Hard decisions on the received word.
hdec=0
where(rx .ge. 0) hdec=1
! Use magnitude of received symbols as a measure of reliability.
absrx=abs(rx)
call indexx(absrx,N,indx)
! Re-order the columns of the generator matrix in order of decreasing reliability.
do i=1,N
genmrb(1:k,i)=gen(1:k,indx(N+1-i))
indices(i)=indx(N+1-i)
enddo
! Do gaussian elimination to create a generator matrix with the most reliable
! received bits in positions 1:k in order of decreasing reliability (more or less).
do id=1,k ! diagonal element indices
do icol=id,k+20 ! The 20 is ad hoc - beware
iflag=0
if( genmrb(id,icol) .eq. 1 ) then
iflag=1
if( icol .ne. id ) then ! reorder column
temp(1:k)=genmrb(1:k,id)
genmrb(1:k,id)=genmrb(1:k,icol)
genmrb(1:k,icol)=temp(1:k)
itmp=indices(id)
indices(id)=indices(icol)
indices(icol)=itmp
endif
do ii=1,k
if( ii .ne. id .and. genmrb(ii,id) .eq. 1 ) then
genmrb(ii,1:N)=ieor(genmrb(ii,1:N),genmrb(id,1:N))
endif
enddo
exit
endif
enddo
enddo
g2=transpose(genmrb)
! The hard decisions for the k MRB bits define the order 0 message, m0.
! Encode m0 using the modified generator matrix to find the "order 0" codeword.
! Flip various combinations of bits in m0 and re-encode to generate a list of
! codewords. Return the member of the list that has the smallest Euclidean
! distance to the received word.
hdec=hdec(indices) ! hard decisions from received symbols
m0=hdec(1:k) ! zero'th order message
absrx=absrx(indices)
rx=rx(indices)
apmaskr=apmaskr(indices)
call mrbencode74(m0,c0,g2,N,k)
nxor=ieor(c0,hdec)
nhardmin=sum(nxor)
dmin=sum(nxor*absrx)
cw=c0
ntotal=0
nrejected=0
npre1=0
npre2=0
if(ndeep.eq.0) goto 998 ! norder=0
if(ndeep.gt.6) ndeep=6
if( ndeep.eq. 1) then
nord=1
npre1=0
npre2=0
nt=40
ntheta=12
elseif(ndeep.eq.2) then
nord=1
npre1=1
npre2=0
nt=40
ntheta=12
elseif(ndeep.eq.3) then
nord=1
npre1=1
npre2=1
nt=40
ntheta=12
ntau=14
elseif(ndeep.eq.4) then
nord=2
npre1=1
npre2=1
nt=40
ntheta=12
ntau=17
elseif(ndeep.eq.5) then
nord=3
npre1=1
npre2=1
nt=40
ntheta=12
ntau=15
elseif(ndeep.eq.6) then
nord=4
npre1=1
npre2=1
nt=95
ntheta=12
ntau=15
endif
do iorder=1,nord
misub(1:k-iorder)=0
misub(k-iorder+1:k)=1
iflag=k-iorder+1
do while(iflag .ge.0)
if(iorder.eq.nord .and. npre1.eq.0) then
iend=iflag
else
iend=1
endif
d1=0.
do n1=iflag,iend,-1
mi=misub
mi(n1)=1
if(any(iand(apmaskr(1:k),mi).eq.1)) cycle
ntotal=ntotal+1
me=ieor(m0,mi)
if(n1.eq.iflag) then
call mrbencode74(me,ce,g2,N,k)
e2sub=ieor(ce(k+1:N),hdec(k+1:N))
e2=e2sub
nd1kpt=sum(e2sub(1:nt))+1
d1=sum(ieor(me(1:k),hdec(1:k))*absrx(1:k))
else
e2=ieor(e2sub,g2(k+1:N,n1))
nd1kpt=sum(e2(1:nt))+2
endif
if(nd1kpt .le. ntheta) then
call mrbencode74(me,ce,g2,N,k)
nxor=ieor(ce,hdec)
if(n1.eq.iflag) then
dd=d1+sum(e2sub*absrx(k+1:N))
else
dd=d1+ieor(ce(n1),hdec(n1))*absrx(n1)+sum(e2*absrx(k+1:N))
endif
if( dd .lt. dmin ) then
dmin=dd
cw=ce
nhardmin=sum(nxor)
nd1kptbest=nd1kpt
endif
else
nrejected=nrejected+1
endif
enddo
! Get the next test error pattern, iflag will go negative
! when the last pattern with weight iorder has been generated.
call nextpat74(misub,k,iorder,iflag)
enddo
enddo
if(npre2.eq.1) then
reset=.true.
ntotal=0
do i1=k,1,-1
do i2=i1-1,1,-1
ntotal=ntotal+1
mi(1:ntau)=ieor(g2(k+1:k+ntau,i1),g2(k+1:k+ntau,i2))
call boxit74(reset,mi(1:ntau),ntau,ntotal,i1,i2)
enddo
enddo
ncount2=0
ntotal2=0
reset=.true.
! Now run through again and do the second pre-processing rule
misub(1:k-nord)=0
misub(k-nord+1:k)=1
iflag=k-nord+1
do while(iflag .ge.0)
me=ieor(m0,misub)
call mrbencode74(me,ce,g2,N,k)
e2sub=ieor(ce(k+1:N),hdec(k+1:N))
do i2=0,ntau
ntotal2=ntotal2+1
ui=0
if(i2.gt.0) ui(i2)=1
r2pat=ieor(e2sub,ui)
778 continue
call fetchit74(reset,r2pat(1:ntau),ntau,in1,in2)
if(in1.gt.0.and.in2.gt.0) then
ncount2=ncount2+1
mi=misub
mi(in1)=1
mi(in2)=1
if(sum(mi).lt.nord+npre1+npre2.or.any(iand(apmaskr(1:k),mi).eq.1)) cycle
me=ieor(m0,mi)
call mrbencode74(me,ce,g2,N,k)
nxor=ieor(ce,hdec)
dd=sum(nxor*absrx)
if( dd .lt. dmin ) then
dmin=dd
cw=ce
nhardmin=sum(nxor)
endif
goto 778
endif
enddo
call nextpat74(misub,k,nord,iflag)
enddo
endif
998 continue
! Re-order the codeword to [message bits][parity bits] format.
cw(indices)=cw
hdec(indices)=hdec
message74=cw(1:74)
call get_crc24(message74,74,nbadcrc)
if(nbadcrc.ne.0) nhardmin=-nhardmin
return
end subroutine osd240_74
subroutine mrbencode74(me,codeword,g2,N,K)
integer*1 me(K),codeword(N),g2(N,K)
! fast encoding for low-weight test patterns
codeword=0
do i=1,K
if( me(i) .eq. 1 ) then
codeword=ieor(codeword,g2(1:N,i))
endif
enddo
return
end subroutine mrbencode74
subroutine nextpat74(mi,k,iorder,iflag)
integer*1 mi(k),ms(k)
! generate the next test error pattern
ind=-1
do i=1,k-1
if( mi(i).eq.0 .and. mi(i+1).eq.1) ind=i
enddo
if( ind .lt. 0 ) then ! no more patterns of this order
iflag=ind
return
endif
ms=0
ms(1:ind-1)=mi(1:ind-1)
ms(ind)=1
ms(ind+1)=0
if( ind+1 .lt. k ) then
nz=iorder-sum(ms)
ms(k-nz+1:k)=1
endif
mi=ms
do i=1,k ! iflag will point to the lowest-index 1 in mi
if(mi(i).eq.1) then
iflag=i
exit
endif
enddo
return
end subroutine nextpat74
subroutine boxit74(reset,e2,ntau,npindex,i1,i2)
integer*1 e2(1:ntau)
integer indexes(5000,2),fp(0:525000),np(5000)
logical reset
common/boxes/indexes,fp,np
if(reset) then
patterns=-1
fp=-1
np=-1
sc=-1
indexes=-1
reset=.false.
endif
indexes(npindex,1)=i1
indexes(npindex,2)=i2
ipat=0
do i=1,ntau
if(e2(i).eq.1) then
ipat=ipat+ishft(1,ntau-i)
endif
enddo
ip=fp(ipat) ! see what's currently stored in fp(ipat)
if(ip.eq.-1) then
fp(ipat)=npindex
else
do while (np(ip).ne.-1)
ip=np(ip)
enddo
np(ip)=npindex
endif
return
end subroutine boxit74
subroutine fetchit74(reset,e2,ntau,i1,i2)
integer indexes(5000,2),fp(0:525000),np(5000)
integer lastpat
integer*1 e2(ntau)
logical reset
common/boxes/indexes,fp,np
save lastpat,inext
if(reset) then
lastpat=-1
reset=.false.
endif
ipat=0
do i=1,ntau
if(e2(i).eq.1) then
ipat=ipat+ishft(1,ntau-i)
endif
enddo
index=fp(ipat)
if(lastpat.ne.ipat .and. index.gt.0) then ! return first set of indices
i1=indexes(index,1)
i2=indexes(index,2)
inext=np(index)
elseif(lastpat.eq.ipat .and. inext.gt.0) then
i1=indexes(inext,1)
i2=indexes(inext,2)
inext=np(inext)
else
i1=-1
i2=-1
inext=-1
endif
lastpat=ipat
return
end subroutine fetchit74

915
lib/fst4_decode.f90 Normal file
View File

@ -0,0 +1,915 @@
module fst4_decode
type :: fst4_decoder
procedure(fst4_decode_callback), pointer :: callback
contains
procedure :: decode
end type fst4_decoder
abstract interface
subroutine fst4_decode_callback (this,nutc,sync,nsnr,dt,freq, &
decoded,nap,qual,ntrperiod,lwspr,fmid,w50)
import fst4_decoder
implicit none
class(fst4_decoder), intent(inout) :: this
integer, intent(in) :: nutc
real, intent(in) :: sync
integer, intent(in) :: nsnr
real, intent(in) :: dt
real, intent(in) :: freq
character(len=37), intent(in) :: decoded
integer, intent(in) :: nap
real, intent(in) :: qual
integer, intent(in) :: ntrperiod
logical, intent(in) :: lwspr
real, intent(in) :: fmid
real, intent(in) :: w50
end subroutine fst4_decode_callback
end interface
contains
subroutine decode(this,callback,iwave,nutc,nQSOProgress,nfqso, &
nfa,nfb,nsubmode,ndepth,ntrperiod,nexp_decode,ntol, &
emedelay,lapcqonly,mycall,hiscall,nfsplit,iwspr)
use timer_module, only: timer
use packjt77
use, intrinsic :: iso_c_binding
include 'fst4/fst4_params.f90'
parameter (MAXCAND=100)
class(fst4_decoder), intent(inout) :: this
procedure(fst4_decode_callback) :: callback
character*37 decodes(100)
character*37 msg,msgsent
character*77 c77
character*12 mycall,hiscall
character*12 mycall0,hiscall0
complex, allocatable :: c2(:)
complex, allocatable :: cframe(:)
complex, allocatable :: c_bigfft(:) !Complex waveform
real llr(240),llra(240),llrb(240),llrc(240),llrd(240)
real candidates(100,4)
real bitmetrics(320,4)
real s4(0:3,NN)
real minsync
logical lapcqonly
integer itone(NN)
integer hmod
integer*1 apmask(240),cw(240)
integer*1 hbits(320)
integer*1 message101(101),message74(74),message77(77)
integer*1 rvec(77)
integer apbits(240)
integer nappasses(0:5) ! # of decoding passes for QSO states 0-5
integer naptypes(0:5,4) ! (nQSOProgress,decoding pass)
integer mcq(29),mrrr(19),m73(19),mrr73(19)
logical badsync,unpk77_success,single_decode
logical first,nohiscall,lwspr,ex
integer*2 iwave(30*60*12000)
data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/
data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/
data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/
data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/
data rvec/0,1,0,0,1,0,1,0,0,1,0,1,1,1,1,0,1,0,0,0,1,0,0,1,1,0,1,1,0, &
1,0,0,1,0,1,1,0,0,0,0,1,0,0,0,1,0,1,0,0,1,1,1,1,0,0,1,0,1, &
0,1,0,1,0,1,1,0,1,1,1,1,1,0,0,0,1,0,1/
data first/.true./
save first,apbits,nappasses,naptypes,mycall0,hiscall0
this%callback => callback
dxcall13=hiscall ! initialize for use in packjt77
mycall13=mycall
fMHz=1.0
if(iwspr.ne.0.and.iwspr.ne.1) return
if(first) then
mcq=2*mod(mcq+rvec(1:29),2)-1
mrrr=2*mod(mrrr+rvec(59:77),2)-1
m73=2*mod(m73+rvec(59:77),2)-1
mrr73=2*mod(mrr73+rvec(59:77),2)-1
nappasses(0)=2
nappasses(1)=2
nappasses(2)=2
nappasses(3)=2
nappasses(4)=2
nappasses(5)=3
! iaptype
!------------------------
! 1 CQ ??? ??? (29 ap bits)
! 2 MyCall ??? ??? (29 ap bits)
! 3 MyCall DxCall ??? (58 ap bits)
! 4 MyCall DxCall RRR (77 ap bits)
! 5 MyCall DxCall 73 (77 ap bits)
! 6 MyCall DxCall RR73 (77 ap bits)
!********
naptypes(0,1:4)=(/1,2,0,0/) ! Tx6 selected (CQ)
naptypes(1,1:4)=(/2,3,0,0/) ! Tx1
naptypes(2,1:4)=(/2,3,0,0/) ! Tx2
naptypes(3,1:4)=(/3,6,0,0/) ! Tx3
naptypes(4,1:4)=(/3,6,0,0/) ! Tx4
naptypes(5,1:4)=(/3,1,2,0/) ! Tx5
mycall0=''
hiscall0=''
first=.false.
endif
l1=index(mycall,char(0))
if(l1.ne.0) mycall(l1:)=" "
l1=index(hiscall,char(0))
if(l1.ne.0) hiscall(l1:)=" "
if(mycall.ne.mycall0 .or. hiscall.ne.hiscall0) then
apbits=0
apbits(1)=99
apbits(30)=99
if(len(trim(mycall)) .lt. 3) go to 10
nohiscall=.false.
hiscall0=hiscall
if(len(trim(hiscall0)).lt.3) then
hiscall0=mycall ! use mycall for dummy hiscall - mycall won't be hashed.
nohiscall=.true.
endif
msg=trim(mycall)//' '//trim(hiscall0)//' RR73'
i3=-1
n3=-1
call pack77(msg,i3,n3,c77)
call unpack77(c77,1,msgsent,unpk77_success)
if(i3.ne.1 .or. (msg.ne.msgsent) .or. .not.unpk77_success) go to 10
read(c77,'(77i1)') message77
message77=mod(message77+rvec,2)
call encode174_91(message77,cw)
apbits=2*cw-1
if(nohiscall) apbits(30)=99
10 continue
mycall0=mycall
hiscall0=hiscall
endif
!************************************
hmod=2**nsubmode
if(nfqso+nqsoprogress.eq.-999) return
Keff=91
nmax=15*12000
single_decode=iand(nexp_decode,32).eq.32
if(ntrperiod.eq.15) then
nsps=720
nmax=15*12000
ndown=18/hmod !nss=40,80,160,400
if(hmod.eq.4) ndown=4
if(hmod.eq.8) ndown=2
nfft1=int(nmax/ndown)*ndown
else if(ntrperiod.eq.30) then
nsps=1680
nmax=30*12000
ndown=42/hmod !nss=40,80,168,336
nfft1=359856 !nfft2=8568=2^3*3^2*7*17
if(hmod.eq.4) then
ndown=10
nfft1=nmax
endif
if(hmod.eq.8) then
ndown=5
nfft1=nmax
endif
else if(ntrperiod.eq.60) then
nsps=3888
nmax=60*12000
ndown=96/hmod !nss=36,81,162,324
if(hmod.eq.1) ndown=108
nfft1=7500*96 ! nfft2=7500=2^2*3*5^4
else if(ntrperiod.eq.120) then
nsps=8200
nmax=120*12000
ndown=200/hmod !nss=40,82,164,328
if(hmod.eq.1) ndown=205
nfft1=7200*200 ! nfft2=7200=2^5*3^2*5^2
else if(ntrperiod.eq.300) then
nsps=21504
nmax=300*12000
ndown=512/hmod !nss=42,84,168,336
nfft1=7020*512 ! nfft2=7020=2^2*3^3*5*13
else if(ntrperiod.eq.900) then
nsps=66560
nmax=900*12000
ndown=1664/hmod !nss=40,80,160,320
nfft1=6480*1664 ! nfft2=6480=2^4*3^4*5
else if(ntrperiod.eq.1800) then
nsps=134400
nmax=1800*12000
ndown=3360/hmod !nss=40,80,160,320
nfft1=6426*3360 ! nfft2=6426=2*3^3*7*17
end if
nss=nsps/ndown
fs=12000.0 !Sample rate
fs2=fs/ndown
nspsec=nint(fs2)
dt=1.0/fs !Sample interval (s)
dt2=1.0/fs2
tt=nsps*dt !Duration of "itone" symbols (s)
baud=1.0/tt
sigbw=4.0*hmod*baud
nfft2=nfft1/ndown !make sure that nfft1 is exactly nfft2*ndown
nfft1=nfft2*ndown
nh1=nfft1/2
allocate( c_bigfft(0:nfft1/2) )
allocate( c2(0:nfft2-1) )
allocate( cframe(0:160*nss-1) )
if(ndepth.eq.3) then
nblock=4
jittermax=2
norder=3
elseif(ndepth.eq.2) then
nblock=1
if(hmod.eq.1) nblock=3
jittermax=0
norder=3
elseif(ndepth.eq.1) then
nblock=1
jittermax=0
norder=3
endif
ndropmax=1
npct=nexp_decode/256
call blanker(iwave,nfft1,ndropmax,npct,c_bigfft)
! The big fft is done once and is used for calculating the smoothed spectrum
! and also for downconverting/downsampling each candidate.
call four2a(c_bigfft,nfft1,1,-1,0) !r2c
! call blank2(nfa,nfb,nfft1,c_bigfft,iwave)
if(hmod.eq.1) then
if(fMHz.lt.2.0) then
nsyncoh=8 ! Use N=8 for sync
nhicoh=1 ! Use N=1,2,4,8 for symbol estimation
else
nsyncoh=4 ! Use N=4 for sync
nhicoh=0 ! Use N=1,2,3,4 for symbol estimation
endif
else
if(hmod.eq.2) nsyncoh=1
if(hmod.eq.4) nsyncoh=-2
if(hmod.eq.8) nsyncoh=-4
endif
if( single_decode ) then
fa=max(100,nint(nfqso+1.5*hmod*baud-ntol))
fb=min(4800,nint(nfqso+1.5*hmod*baud+ntol))
else
fa=max(100,nfa)
fb=min(4800,nfb)
endif
if(hmod.eq.1) then
if(ntrperiod.eq.15) minsync=1.15
if(ntrperiod.gt.15) minsync=1.20
elseif(hmod.gt.1) then
minsync=1.2
endif
! Get first approximation of candidate frequencies
call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb, &
minsync,ncand,candidates,base)
ndecodes=0
decodes=' '
isbest=0
fc2=0.
do icand=1,ncand
fc0=candidates(icand,1)
detmet=candidates(icand,2)
! Downconvert and downsample a slice of the spectrum centered on the
! rough estimate of the candidates frequency.
! Output array c2 is complex baseband sampled at 12000/ndown Sa/sec.
! The size of the downsampled c2 array is nfft2=nfft1/ndown
call fst4_downsample(c_bigfft,nfft1,ndown,fc0,sigbw,c2)
call timer('sync240 ',0)
fc1=0.0
if(emedelay.lt.0.1) then ! search offsets from 0 s to 2 s
is0=1.5*nspsec
ishw=1.5*nspsec
else ! search plus or minus 1.5 s centered on emedelay
is0=nint((emedelay+1.0)*nspsec)
ishw=1.5*nspsec
endif
smax=-1.e30
do if=-12,12
fc=fc1 + 0.1*baud*if
do istart=max(1,is0-ishw),is0+ishw,4*hmod
call sync_fst4(c2,istart,fc,hmod,nsyncoh,nfft2,nss, &
ntrperiod,fs2,sync)
if(sync.gt.smax) then
fc2=fc
isbest=istart
smax=sync
endif
enddo
enddo
fc1=fc2
is0=isbest
ishw=4*hmod
isst=1*hmod
smax=0.0
do if=-7,7
fc=fc1 + 0.02*baud*if
do istart=max(1,is0-ishw),is0+ishw,isst
call sync_fst4(c2,istart,fc,hmod,nsyncoh,nfft2,nss, &
ntrperiod,fs2,sync)
if(sync.gt.smax) then
fc2=fc
isbest=istart
smax=sync
endif
enddo
enddo
call timer('sync240 ',1)
fc_synced = fc0 + fc2
dt_synced = (isbest-fs2)*dt2 !nominal dt is 1 second so frame starts at sample fs2
candidates(icand,3)=fc_synced
candidates(icand,4)=isbest
enddo
! remove duplicate candidates
do icand=1,ncand
fc=candidates(icand,3)
isbest=nint(candidates(icand,4))
do ic2=1,ncand
fc2=candidates(ic2,3)
isbest2=nint(candidates(ic2,4))
if(ic2.ne.icand .and. fc2.gt.0.0) then
if(abs(fc2-fc).lt.0.10*baud) then ! same frequency
if(abs(isbest2-isbest).le.2) then
candidates(ic2,3)=-1
endif
endif
endif
enddo
enddo
ic=0
do icand=1,ncand
if(candidates(icand,3).gt.0) then
ic=ic+1
candidates(ic,:)=candidates(icand,:)
endif
enddo
ncand=ic
xsnr=0.
do icand=1,ncand
sync=candidates(icand,2)
fc_synced=candidates(icand,3)
isbest=nint(candidates(icand,4))
xdt=(isbest-nspsec)/fs2
if(ntrperiod.eq.15) xdt=(isbest-real(nspsec)/2.0)/fs2
call fst4_downsample(c_bigfft,nfft1,ndown,fc_synced,sigbw,c2)
do ijitter=0,jittermax
if(ijitter.eq.0) ioffset=0
if(ijitter.eq.1) ioffset=1
if(ijitter.eq.2) ioffset=-1
is0=isbest+ioffset
if(is0.lt.0) cycle
cframe=c2(is0:is0+160*nss-1)
bitmetrics=0
if(hmod.eq.1) then
call get_fst4_bitmetrics(cframe,nss,hmod,nblock,nhicoh,bitmetrics,s4,badsync)
else
call get_fst4_bitmetrics2(cframe,nss,hmod,nblock,bitmetrics,s4,badsync)
endif
if(badsync) cycle
hbits=0
where(bitmetrics(:,1).ge.0) hbits=1
ns1=count(hbits( 1: 16).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/))
ns2=count(hbits( 77: 92).eq.(/1,1,1,0,0,1,0,0,1,0,1,1,0,0,0,1/))
ns3=count(hbits(153:168).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/))
ns4=count(hbits(229:244).eq.(/1,1,1,0,0,1,0,0,1,0,1,1,0,0,0,1/))
ns5=count(hbits(305:320).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/))
nsync_qual=ns1+ns2+ns3+ns4+ns5
! if(nsync_qual.lt. 46) cycle !### Value ?? ###
scalefac=2.83
llra( 1: 60)=bitmetrics( 17: 76, 1)
llra( 61:120)=bitmetrics( 93:152, 1)
llra(121:180)=bitmetrics(169:228, 1)
llra(181:240)=bitmetrics(245:304, 1)
llra=scalefac*llra
llrb( 1: 60)=bitmetrics( 17: 76, 2)
llrb( 61:120)=bitmetrics( 93:152, 2)
llrb(121:180)=bitmetrics(169:228, 2)
llrb(181:240)=bitmetrics(245:304, 2)
llrb=scalefac*llrb
llrc( 1: 60)=bitmetrics( 17: 76, 3)
llrc( 61:120)=bitmetrics( 93:152, 3)
llrc(121:180)=bitmetrics(169:228, 3)
llrc(181:240)=bitmetrics(245:304, 3)
llrc=scalefac*llrc
llrd( 1: 60)=bitmetrics( 17: 76, 4)
llrd( 61:120)=bitmetrics( 93:152, 4)
llrd(121:180)=bitmetrics(169:228, 4)
llrd(181:240)=bitmetrics(245:304, 4)
llrd=scalefac*llrd
apmag=maxval(abs(llra))*1.1
ntmax=nblock+nappasses(nQSOProgress)
if(lapcqonly) ntmax=nblock+1
if(ndepth.eq.1) ntmax=nblock
apmask=0
if(iwspr.eq.1) then ! 50-bit msgs, no ap decoding
nblock=4
ntmax=nblock
endif
do itry=1,ntmax
if(itry.eq.1) llr=llra
if(itry.eq.2.and.itry.le.nblock) llr=llrb
if(itry.eq.3.and.itry.le.nblock) llr=llrc
if(itry.eq.4.and.itry.le.nblock) llr=llrd
if(itry.le.nblock) then
apmask=0
iaptype=0
endif
if(itry.gt.nblock) then
llr=llra
if(nblock.gt.1) then
if(hmod.eq.1) llr=llrd
if(hmod.eq.2) llr=llrb
if(hmod.eq.4) llr=llrc
if(hmod.eq.8) llr=llrd
endif
iaptype=naptypes(nQSOProgress,itry-nblock)
if(lapcqonly) iaptype=1
if(iaptype.ge.2 .and. apbits(1).gt.1) cycle ! No, or nonstandard, mycall
if(iaptype.ge.3 .and. apbits(30).gt.1) cycle ! No, or nonstandard, dxcall
if(iaptype.eq.1) then ! CQ
apmask=0
apmask(1:29)=1
llr(1:29)=apmag*mcq(1:29)
endif
if(iaptype.eq.2) then ! MyCall ??? ???
apmask=0
apmask(1:29)=1
llr(1:29)=apmag*apbits(1:29)
endif
if(iaptype.eq.3) then ! MyCall DxCall ???
apmask=0
apmask(1:58)=1
llr(1:58)=apmag*apbits(1:58)
endif
if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype .eq.6) then
apmask=0
apmask(1:77)=1
llr(1:58)=apmag*apbits(1:58)
if(iaptype.eq.4) llr(59:77)=apmag*mrrr(1:19)
if(iaptype.eq.5) llr(59:77)=apmag*m73(1:19)
if(iaptype.eq.6) llr(59:77)=apmag*mrr73(1:19)
endif
endif
dmin=0.0
nharderrors=-1
unpk77_success=.false.
if(iwspr.eq.0) then
maxosd=2
Keff=91
norder=3
call timer('d240_101',0)
call decode240_101(llr,Keff,maxosd,norder,apmask,message101, &
cw,ntype,nharderrors,dmin)
call timer('d240_101',1)
elseif(iwspr.eq.1) then
maxosd=2
call timer('d240_74 ',0)
Keff=64
norder=4
call decode240_74(llr,Keff,maxosd,norder,apmask,message74,cw, &
ntype,nharderrors,dmin)
call timer('d240_74 ',1)
endif
if(nharderrors .ge.0) then
if(count(cw.eq.1).eq.0) then
nharderrors=-nharderrors
cycle
endif
if(iwspr.eq.0) then
write(c77,'(77i1)') mod(message101(1:77)+rvec,2)
call unpack77(c77,1,msg,unpk77_success)
else
write(c77,'(50i1)') message74(1:50)
c77(51:77)='000000000000000000000110000'
call unpack77(c77,1,msg,unpk77_success)
endif
if(unpk77_success) then
idupe=0
do i=1,ndecodes
if(decodes(i).eq.msg) idupe=1
enddo
if(idupe.eq.1) goto 2002
ndecodes=ndecodes+1
decodes(ndecodes)=msg
if(iwspr.eq.0) then
call get_fst4_tones_from_bits(message101,itone,0)
else
call get_fst4_tones_from_bits(message74,itone,1)
endif
inquire(file='plotspec',exist=ex)
fmid=-999.0
if(ex) then
call dopspread(itone,iwave,nsps,nmax,ndown,hmod, &
isbest,fc_synced,fmid,w50)
endif
xsig=0
do i=1,NN
xsig=xsig+s4(itone(i),i)**2
enddo
arg=600.0*(xsig/base)-1.0
if(arg.gt.0.0) then
xsnr=10*log10(arg)-35.5-12.5*log10(nsps/8200.0)
if(ntrperiod.eq. 15) xsnr=xsnr+2
if(ntrperiod.eq. 30) xsnr=xsnr+1
if(ntrperiod.eq. 900) xsnr=xsnr+1
if(ntrperiod.eq.1800) xsnr=xsnr+2
else
xsnr=-99.9
endif
else
cycle
endif
nsnr=nint(xsnr)
qual=0.
fsig=fc_synced - 1.5*hmod*baud
if(ex) then
write(21,3021) nutc,icand,itry,nsyncoh,iaptype, &
ijitter,ntype,nsync_qual,nharderrors,dmin, &
sync,xsnr,xdt,fsig,w50,trim(msg)
3021 format(i6.6,6i3,2i4,f6.1,f7.2,f6.1,f6.2,f7.1,f7.3,1x,a)
flush(21)
endif
call this%callback(nutc,smax1,nsnr,xdt,fsig,msg, &
iaptype,qual,ntrperiod,lwspr,fmid,w50)
goto 2002
endif
enddo ! metrics
enddo ! istart jitter
2002 enddo !candidate list
return
end subroutine decode
subroutine sync_fst4(cd0,i0,f0,hmod,ncoh,np,nss,ntr,fs,sync)
! Compute sync power for a complex, downsampled FST4 signal.
use timer_module, only: timer
include 'fst4/fst4_params.f90'
complex cd0(0:np-1)
complex csync1,csync2,csynct1,csynct2
complex ctwk(3200)
complex z1,z2,z3,z4,z5
integer hmod,isyncword1(0:7),isyncword2(0:7)
real f0save
common/sync240com/csync1(3200),csync2(3200),csynct1(3200),csynct2(3200)
data isyncword1/0,1,3,2,1,0,2,3/
data isyncword2/2,3,1,0,3,2,0,1/
data f0save/-99.9/,nss0/-1/,ntr0/-1/
save twopi,dt,fac,f0save,nss0,ntr0
p(z1)=(real(z1*fac)**2 + aimag(z1*fac)**2)**0.5 !Compute power
nz=8*nss
call timer('sync240a',0)
if(nss.ne.nss0 .or. ntr.ne.ntr0) then
twopi=8.0*atan(1.0)
dt=1/fs
k=1
phi1=0.0
phi2=0.0
do i=0,7
dphi1=twopi*hmod*(isyncword1(i)-1.5)/real(nss)
dphi2=twopi*hmod*(isyncword2(i)-1.5)/real(nss)
do j=1,nss
csync1(k)=cmplx(cos(phi1),sin(phi1))
csync2(k)=cmplx(cos(phi2),sin(phi2))
phi1=mod(phi1+dphi1,twopi)
phi2=mod(phi2+dphi2,twopi)
k=k+1
enddo
enddo
fac=1.0/(8.0*nss)
nss0=nss
ntr0=ntr
f0save=-1.e30
endif
if(f0.ne.f0save) then
dphi=twopi*f0*dt
phi=0.0
do i=1,nz
ctwk(i)=cmplx(cos(phi),sin(phi))
phi=mod(phi+dphi,twopi)
enddo
csynct1(1:nz)=ctwk(1:nz)*csync1(1:nz)
csynct2(1:nz)=ctwk(1:nz)*csync2(1:nz)
f0save=f0
nss0=nss
endif
call timer('sync240a',1)
i1=i0 !Costas arrays
i2=i0+38*nss
i3=i0+76*nss
i4=i0+114*nss
i5=i0+152*nss
s1=0.0
s2=0.0
s3=0.0
s4=0.0
s5=0.0
if(ncoh.gt.0) then
nsec=8/ncoh
do i=1,nsec
is=(i-1)*ncoh*nss
z1=0
if(i1+is.ge.1) then
z1=sum(cd0(i1+is:i1+is+ncoh*nss-1)*conjg(csynct1(is+1:is+ncoh*nss)))
endif
z2=sum(cd0(i2+is:i2+is+ncoh*nss-1)*conjg(csynct2(is+1:is+ncoh*nss)))
z3=sum(cd0(i3+is:i3+is+ncoh*nss-1)*conjg(csynct1(is+1:is+ncoh*nss)))
z4=sum(cd0(i4+is:i4+is+ncoh*nss-1)*conjg(csynct2(is+1:is+ncoh*nss)))
z5=0
if(i5+is+ncoh*nss-1.le.np) then
z5=sum(cd0(i5+is:i5+is+ncoh*nss-1)*conjg(csynct1(is+1:is+ncoh*nss)))
endif
s1=s1+abs(z1)/nz
s2=s2+abs(z2)/nz
s3=s3+abs(z3)/nz
s4=s4+abs(z4)/nz
s5=s5+abs(z5)/nz
enddo
else
nsub=-ncoh
nps=nss/nsub
do i=1,8
do isub=1,nsub
is=(i-1)*nss+(isub-1)*nps
z1=0.0
if(i1+is.ge.1) then
z1=sum(cd0(i1+is:i1+is+nps-1)*conjg(csynct1(is+1:is+nps)))
endif
z2=sum(cd0(i2+is:i2+is+nps-1)*conjg(csynct2(is+1:is+nps)))
z3=sum(cd0(i3+is:i3+is+nps-1)*conjg(csynct1(is+1:is+nps)))
z4=sum(cd0(i4+is:i4+is+nps-1)*conjg(csynct2(is+1:is+nps)))
z5=0.0
if(i5+is+ncoh*nss-1.le.np) then
z5=sum(cd0(i5+is:i5+is+nps-1)*conjg(csynct1(is+1:is+nps)))
endif
s1=s1+abs(z1)/(8*nss)
s2=s2+abs(z2)/(8*nss)
s3=s3+abs(z3)/(8*nss)
s4=s4+abs(z4)/(8*nss)
s5=s5+abs(z5)/(8*nss)
enddo
enddo
endif
sync = s1+s2+s3+s4+s5
return
end subroutine sync_fst4
subroutine fst4_downsample(c_bigfft,nfft1,ndown,f0,sigbw,c1)
! Output: Complex data in c(), sampled at 12000/ndown Hz
complex c_bigfft(0:nfft1/2)
complex c1(0:nfft1/ndown-1)
df=12000.0/nfft1
i0=nint(f0/df)
ih=nint( ( f0 + 1.3*sigbw/2.0 )/df)
nbw=ih-i0+1
c1=0.
c1(0)=c_bigfft(i0)
nfft2=nfft1/ndown
do i=1,nbw
if(i0+i.le.nfft1/2) c1(i)=c_bigfft(i0+i)
if(i0-i.ge.0) c1(nfft2-i)=c_bigfft(i0-i)
enddo
c1=c1/nfft2
call four2a(c1,nfft2,1,1,1) !c2c FFT back to time domain
return
end subroutine fst4_downsample
subroutine get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb, &
minsync,ncand,candidates,base)
complex c_bigfft(0:nfft1/2) !Full length FFT of raw data
integer hmod !Modulation index (submode)
integer im(1) !For maxloc
real candidates(100,4) !Candidate list
real, allocatable :: s(:) !Low resolution power spectrum
real, allocatable :: s2(:) !CCF of s() with 4 tones
real xdb(-3:3) !Model 4-tone CCF peaks
real minsync
data xdb/0.25,0.50,0.75,1.0,0.75,0.50,0.25/
nh1=nfft1/2
df1=fs/nfft1
baud=fs/nsps !Keying rate
df2=baud/2.0
nd=df2/df1 !s() sums this many bins of big FFT
ndh=nd/2
ia=nint(max(100.0,fa)/df2) !Low frequency search limit
ib=nint(min(4800.0,fb)/df2) !High frequency limit
signal_bw=4*(12000.0/nsps)*hmod
analysis_bw=min(4800.0,fb)-max(100.0,fa)
xnoise_bw=10.0*signal_bw !Is this a good compromise?
if(analysis_bw.gt.xnoise_bw) then
ina=ia
inb=ib
else
fcenter=(fa+fb)/2.0 !If noise_bw > analysis_bw,
fl = max(100.0,fcenter-xnoise_bw/2.)/df2 !we'll search over noise_bw
fh = min(4800.0,fcenter+xnoise_bw/2.)/df2
ina=nint(fl)
inb=nint(fh)
endif
nnw=nint(48000.*nsps*2./fs)
allocate (s(nnw))
s=0. !Compute low-resloution power spectrum
do i=ina,inb ! noise analysis window includes signal analysis window
j0=nint(i*df2/df1)
do j=j0-ndh,j0+ndh
s(i)=s(i) + real(c_bigfft(j))**2 + aimag(c_bigfft(j))**2
enddo
enddo
ina=max(ina,1+3*hmod) !Don't run off the ends
inb=min(inb,nnw-3*hmod)
allocate (s2(nnw))
s2=0.
do i=ina,inb !Compute CCF of s() and 4 tones
s2(i)=s(i-hmod*3) + s(i-hmod) +s(i+hmod) +s(i+hmod*3)
enddo
call pctile(s2(ina+hmod*3:inb-hmod*3),inb-ina+1-hmod*6,30,base)
s2=s2/base !Normalize wrt noise level
ncand=0
candidates=0
if(ia.lt.3) ia=3
if(ib.gt.nnw-2) ib=nnw-2
! Find candidates, using the CLEAN algorithm to remove a model of each one
! from s2() after it has been found.
pval=99.99
do while(ncand.lt.100)
im=maxloc(s2(ia:ib))
iploc=ia+im(1)-1 !Index of CCF peak
pval=s2(iploc) !Peak value
if(pval.lt.minsync) exit
do i=-3,+3 !Remove 0.9 of a model CCF at
k=iploc+2*hmod*i !this frequency from s2()
if(k.ge.ia .and. k.le.ib) then
s2(k)=max(0.,s2(k)-0.9*pval*xdb(i))
endif
enddo
ncand=ncand+1
candidates(ncand,1)=df2*iploc !Candidate frequency
candidates(ncand,2)=pval !Rough estimate of SNR
enddo
return
end subroutine get_candidates_fst4
subroutine dopspread(itone,iwave,nsps,nmax,ndown,hmod,i0,fc,fmid,w50)
! On "plotspec" special request, compute Doppler spread for a decoded signal
include 'fst4/fst4_params.f90'
complex, allocatable :: cwave(:) !Reconstructed complex signal
complex, allocatable :: g(:) !Channel gain, g(t) in QEX paper
real,allocatable :: ss(:) !Computed power spectrum of g(t)
real,allocatable,save :: ssavg(:) !Computed power spectrum of g(t)
integer itone(160) !Tones for this message
integer*2 iwave(nmax) !Raw Rx data
integer hmod !Modulation index
data ncall/0/
save ncall
ncall=ncall+1
nfft=2*nmax
nwave=max(nmax,(NN+2)*nsps)
allocate(cwave(0:nwave-1))
allocate(g(0:nfft-1))
wave=0
fsample=12000.0
call gen_fst4wave(itone,NN,nsps,nwave,fsample,hmod,fc,1,cwave,wave)
cwave=cshift(cwave,-i0*ndown)
fac=1.0/32768
g(0:nmax-1)=fac*float(iwave)*conjg(cwave(:nmax-1))
g(nmax:)=0.
call four2a(g,nfft,1,-1,1) !Forward c2c FFT
df=12000.0/nfft
ia=1.0/df
smax=0.
do i=-ia,ia !Find smax in +/- 1 Hz around 0.
j=i
if(j.lt.0) j=i+nfft
s=real(g(j))**2 + aimag(g(j))**2
smax=max(s,smax)
enddo
ia=10.1/df
allocate(ss(-ia:ia)) !Allocate space for +/- 10 Hz
sum1=0.
sum2=0.
nns=0
do i=-ia,ia
j=i
if(j.lt.0) j=i+nfft
ss(i)=(real(g(j))**2 + aimag(g(j))**2)/smax
f=i*df
if(f.ge.-4.0 .and. f.le.-2.0) then
sum1=sum1 + ss(i) !Power between -2 and -4 Hz
nns=nns+1
else if(f.ge.2.0 .and. f.le.4.0) then
sum2=sum2 + ss(i) !Power between +2 and +4 Hz
endif
enddo
avg=min(sum1/nns,sum2/nns) !Compute avg from smaller sum
sum1=0.
do i=-ia,ia
f=i*df
if(abs(f).le.1.0) sum1=sum1 + ss(i)-avg !Power in abs(f) < 1 Hz
enddo
ia=nint(1.0/df) + 1
sum2=0.0
xi1=-999
xi2=-999
xi3=-999
sum2z=0.
do i=-ia,ia !Find freq range that has 50% of signal power
sum2=sum2 + ss(i)-avg
if(sum2.ge.0.25*sum1 .and. xi1.eq.-999.0) then
xi1=i - 1 + (sum2-0.25*sum1)/(sum2-sum2z)
endif
if(sum2.ge.0.50*sum1 .and. xi2.eq.-999.0) then
xi2=i - 1 + (sum2-0.50*sum1)/(sum2-sum2z)
endif
if(sum2.ge.0.75*sum1) then
xi3=i - 1 + (sum2-0.75*sum1)/(sum2-sum2z)
exit
endif
sum2z=sum2
enddo
xdiff=sqrt(1.0+(xi3-xi1)**2) !Keep small values from fluctuating too widely
w50=xdiff*df !Compute Doppler spread
fmid=xi2*df !Frequency midpoint of signal powere
do i=-ia,ia !Save the spectrum for plotting
y=ncall-1
j=i+nint(xi2)
if(abs(j*df).lt.10.0) y=0.99*ss(i+nint(xi2)) + ncall-1
write(52,1010) i*df,y
1010 format(f12.6,f12.6)
enddo
return
end subroutine dopspread
end module fst4_decode

View File

@ -15,7 +15,8 @@ subroutine foxgen()
! common block.
parameter (NN=79,ND=58,NSPS=4*1920)
parameter (NWAVE=NN*NSPS,NFFT=614400,NH=NFFT/2)
parameter (NWAVE=(160+2)*134400*4) !the biggest waveform we generate (FST4-1800 at 48kHz)
parameter (NFFT=614400,NH=NFFT/2)
character*40 cmsg
character*37 msg,msgsent
integer itone(79)
@ -60,34 +61,10 @@ subroutine foxgen()
peak1=maxval(abs(wave))
wave=wave/peak1
! call plotspec(1,wave) !Plot the spectrum
! Apply compression
! rms=sqrt(dot_product(wave,wave)/kz)
! wave=wave/rms
! do i=1,NWAVE
! wave(i)=h1(wave(i))
! enddo
! peak2=maxval(abs(wave))
! wave=wave/peak2
! call plotspec(2,wave) !Plot the spectrum
width=50.0
call foxfilt(nslots,nfreq,width,wave)
peak3=maxval(abs(wave))
wave=wave/peak3
! nadd=1000
! j=0
! do i=1,NWAVE,nadd
! sx=dot_product(wave(i:i+nadd-1),wave(i:i+nadd-1))
! j=j+1
! write(30,3001) j,sx/nadd
!3001 format(i8,f12.6)
! enddo
! call plotspec(3,wave) !Plot the spectrum
return
end subroutine foxgen

View File

@ -1,7 +1,7 @@
subroutine foxgen_wrap(msg40,msgbits,itone)
parameter (NN=79,ND=58,KK=77,NSPS=4*1920)
parameter (NWAVE=NN*NSPS)
parameter (NWAVE=(160+2)*134400) !the biggest waveform we generate (FST4-1800)
character*40 msg40,cmsg
character*12 mycall12

View File

@ -17,19 +17,20 @@ program jt9
integer(C_INT) iret
type(wav_header) wav
real*4 s(NSMAX)
real*8 TRperiod
character c
character(len=500) optarg, infile
character wisfile*80
!### ndepth was defined as 60001. Why???
integer :: arglen,stat,offset,remain,mode=0,flow=200,fsplit=2700, &
fhigh=4000,nrxfreq=1500,ntrperiod=1,ndepth=1,nexp_decode=0
fhigh=4000,nrxfreq=1500,ndepth=1,nexp_decode=0,nQSOProg=0
logical :: read_files = .true., tx9 = .false., display_help = .false., &
bLowSidelobes = .false.
type (option) :: long_options(26) = [ &
type (option) :: long_options(29) = [ &
option ('help', .false., 'h', 'Display this help message', ''), &
option ('shmem',.true.,'s','Use shared memory for sample data','KEY'), &
option ('tr-period', .true., 'p', 'Tx/Rx period, default MINUTES=1', &
'MINUTES'), &
option ('tr-period', .true., 'p', 'Tx/Rx period, default SECONDS=60', &
'SECONDS'), &
option ('executable-path', .true., 'e', &
'Location of subordinate executables (KVASD) default PATH="."', &
'PATH'), &
@ -52,13 +53,17 @@ program jt9
'THREADS'), &
option ('jt4', .false., '4', 'JT4 mode', ''), &
option ('ft4', .false., '5', 'FT4 mode', ''), &
option ('jt65', .false.,'6', 'JT65 mode', ''), &
option ('jt65', .false.,'6', 'JT65 mode', ''), &
option ('fst4', .false., '7', 'FST4 mode', ''), &
option ('fst4w', .false., 'W', 'FST4W mode', ''), &
option ('ft8', .false., '8', 'FT8 mode', ''), &
option ('jt9', .false., '9', 'JT9 mode', ''), &
option ('qra64', .false., 'q', 'QRA64 mode', ''), &
option ('QSOprog', .true., 'Q', 'QSO progress (0-5), default PROGRESS=1',&
'QSOprogress'), &
option ('sub-mode', .true., 'b', 'Sub mode, default SUBMODE=A', 'A'), &
option ('depth', .true., 'd', &
'JT9 decoding depth (1-3), default DEPTH=1', 'DEPTH'), &
'Decoding depth (1-3), default DEPTH=1', 'DEPTH'), &
option ('tx-jt9', .false., 'T', 'Tx mode is JT9', ''), &
option ('my-call', .true., 'c', 'my callsign', 'CALL'), &
option ('my-grid', .true., 'G', 'my grid locator', 'GRID'), &
@ -74,12 +79,14 @@ program jt9
character(len=6) :: mygrid='', hisgrid='EN37'
common/patience/npatience,nthreads
common/decstats/ntry65a,ntry65b,n65a,n65b,num9,numfano
data npatience/1/,nthreads/1/
data npatience/1/,nthreads/1/,wisfile/' '/
iwspr=0
nsubmode = 0
TRperiod=60.d0
do
call getopt('hs:e:a:b:r:m:p:d:f:w:t:98654qTL:S:H:c:G:x:g:X:', &
call getopt('hs:e:a:b:r:m:p:d:f:w:t:987654WqTL:S:H:c:G:x:g:X:Q:', &
long_options,c,optarg,arglen,stat,offset,remain,.true.)
if (stat .ne. 0) then
exit
@ -101,7 +108,7 @@ program jt9
case ('m')
read (optarg(:arglen), *) nthreads
case ('p')
read (optarg(:arglen), *) ntrperiod
read (optarg(:arglen), *) TRperiod
case ('d')
read (optarg(:arglen), *) ndepth
case ('f')
@ -114,20 +121,28 @@ program jt9
read (optarg(:arglen), *) fhigh
case ('q')
mode = 164
case ('Q')
read (optarg(:arglen), *) nQSOProg
case ('4')
mode = 4
case ('5')
mode = 5
case ('6')
if (mode.lt.65) mode = mode + 65
case ('9')
if (mode.lt.9.or.mode.eq.65) mode = mode + 9
case ('7')
mode = 240
iwspr=0
case ('8')
mode = 8
case ('9')
if (mode.lt.9.or.mode.eq.65) mode = mode + 9
case ('T')
tx9 = .true.
case ('w')
read (optarg(:arglen), *) npatience
case ('W')
mode = 241
iwspr=1
case ('c')
read (optarg(:arglen), *) mycall
case ('G')
@ -182,7 +197,6 @@ program jt9
allocate(shared_data)
nflatten=0
do iarg = offset + 1, offset + remain
call get_command_argument (iarg, optarg, arglen)
infile = optarg(:arglen)
@ -197,34 +211,16 @@ program jt9
endif
go to 2
1 nutc=0
2 nsps=0
if(ntrperiod.eq.1) then
nsps=6912
shared_data%params%nzhsym=181
else if(ntrperiod.eq.2) then
nsps=15360
shared_data%params%nzhsym=178
else if(ntrperiod.eq.5) then
nsps=40960
shared_data%params%nzhsym=172
else if(ntrperiod.eq.10) then
nsps=82944
shared_data%params%nzhsym=171
else if(ntrperiod.eq.30) then
nsps=252000
shared_data%params%nzhsym=167
endif
if(nsps.eq.0) stop 'Error: bad TRperiod'
2 nsps=6912
npts=TRperiod*12000.d0
kstep=nsps/2
k=0
nhsym=0
nhsym0=-999
npts=(60*ntrperiod-6)*12000
if(iarg .eq. offset + 1) then
call init_timer (trim(data_dir)//'/timer.out')
call timer('jt9 ',0)
endif
shared_data%id2=0 !??? Why is this necessary ???
if(mode.eq.5) npts=21*3456
do iblk=1,npts/kstep
@ -244,18 +240,18 @@ program jt9
ingain=0
call timer('symspec ',0)
nminw=1
call symspec(shared_data,k,ntrperiod,nsps,ingain,bLowSidelobes,nminw,pxdb, &
s,df3,ihsym,npts8,pxdbmax)
call symspec(shared_data,k,Tperiod,nsps,ingain, &
bLowSidelobes,nminw,pxdb,s,df3,ihsym,npts8,pxdbmax)
call timer('symspec ',1)
endif
nhsym0=nhsym
if(nhsym.ge.181) exit
if(nhsym.ge.181 .and. mode.ne.240 .and. mode.ne.241) exit
endif
enddo
close(unit=wav%lun)
shared_data%params%nutc=nutc
shared_data%params%ndiskdat=.true.
shared_data%params%ntr=60
shared_data%params%ntr=TRperiod
shared_data%params%nfqso=nrxfreq
shared_data%params%newdat=.true.
shared_data%params%npts8=74736
@ -264,23 +260,18 @@ program jt9
shared_data%params%nfb=fhigh
shared_data%params%ntol=20
shared_data%params%kin=64800
shared_data%params%nzhsym=181
if(mode.eq.240) shared_data%params%kin=720000 !### 60 s periods ###
shared_data%params%nzhsym=nhsym
if(mode.eq.240 .and. iwspr.eq.1) ndepth=ior(ndepth,128)
shared_data%params%ndepth=ndepth
shared_data%params%lft8apon=.true.
shared_data%params%ljt65apon=.true.
shared_data%params%napwid=75
shared_data%params%dttol=3.
! shared_data%params%minsync=0 !### TEST ONLY
! shared_data%params%nfqso=1500 !### TEST ONLY
! mycall="G3WDG " !### TEST ONLY
! hiscall="VK7MO " !### TEST ONLY
! hisgrid="QE37 " !### TEST ONLY
if(mode.eq.164 .and. nsubmode.lt.100) nsubmode=nsubmode+100
shared_data%params%naggressive=0
shared_data%params%n2pass=2
! shared_data%params%nranera=8 !### ntrials=10000
shared_data%params%nQSOprogress=nQSOProg
shared_data%params%nranera=6 !### ntrials=3000
shared_data%params%nrobust=.false.
shared_data%params%nexp_decode=nexp_decode
@ -334,13 +325,8 @@ program jt9
999 continue
! Output decoder statistics
call fini_timer ()
! open (unit=12, file=trim(data_dir)//'/timer.out', status='unknown', position='append')
! write(12,1100) n65a,ntry65a,n65b,ntry65b,numfano,num9
!1100 format(58('-')/' JT65_1 Tries_1 JT65_2 Tries_2 JT9 Tries'/ &
! 58('-')/6i8)
! Save wisdom and free memory
iret=fftwf_export_wisdom_to_filename(wisfile)
! Save FFTW wisdom and free memory
if(len(trim(wisfile)).gt.0) iret=fftwf_export_wisdom_to_filename(wisfile)
call four2a(a,-1,1,1,1)
call filbig(a,-1,1,0.0,0,0,0,0,0) !used for FFT plans
call fftwf_cleanup_threads()

21
lib/sec0.f90 Normal file
View File

@ -0,0 +1,21 @@
subroutine sec0(n,t)
! Simple execution timer.
! call sec0(0,t)
! ... statements to be timed ...
! call sec0(1,t)
! print*,'Execution time:',t
integer*8 count0,count1,clkfreq
save count0
call system_clock(count1,clkfreq)
if(n.eq.0) then
count0=count1
return
else
t=float(count1-count0)/float(clkfreq)
endif
return
end subroutine sec0

View File

@ -1,14 +1,12 @@
subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,bLowSidelobes, &
nminw,pxdb,s,df3,ihsym,npts8,pxdbmax)
subroutine symspec(shared_data,k,TRperiod,nsps,ingain,bLowSidelobes, &
nminw,pxdb,s,df3,ihsym,npts8,pxdbmax,npct)
! Input:
! k pointer to the most recent new data
! ntrperiod T/R sequence length, minutes
! TRperiod T/R sequence length, seconds
! nsps samples per symbol, at 12000 Hz
! bLowSidelobes true to use windowed FFTs
! ndiskdat 0/1 to indicate if data from disk
! nb 0/1 status of noise blanker (off/on)
! nbslider NB setting, 0-100
! Output:
! pxdb raw power (0-90 dB)
@ -23,6 +21,7 @@ subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,bLowSidelobes, &
include 'jt9com.f90'
type(dec_data) :: shared_data
real*8 TRperiod
real*4 w3(MAXFFT3)
real*4 s(NSMAX)
real*4 ssum(NSMAX)
@ -38,7 +37,7 @@ subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,bLowSidelobes, &
equivalence (xc,cx)
save
if(ntrperiod.eq.-999) stop !Silence compiler warning
if(TRperiod.lt.0.d0) stop !Silence compiler warning
nfft3=16384 !df=12000.0/16384 = 0.732422
jstep=nsps/2 !Step size = half-symbol in id2()
if(k.gt.NMAX) go to 900
@ -64,6 +63,11 @@ subroutine symspec(shared_data,k,ntrperiod,nsps,ingain,bLowSidelobes, &
gain=10.0**(0.1*ingain)
sq=0.
pxmax=0.;
! dwell_time=0.0001
! if(k.gt.k0 .and. npct.gt.0) call blanker(shared_data%id2(k0+1:k), &
! k-k0,dwell_time,npct)
do i=k0+1,k
x1=shared_data%id2(i)
if (abs(x1).gt.pxmax) pxmax = abs(x1);

View File

@ -1,56 +0,0 @@
program t6
parameter (MAXFFT=1404)
complex c(0:MAXFFT-1)
real s(0:MAXFFT-1)
m1=45
m2=67
m3=89
nsym=3*11 + m1 + m2 + m3
nfft=6*nsym
nh=nfft/2
best=9999.
! do m1=22,67
! do m2=37,97
do m1=30,67
do m2=26,100
m3=201-m2-m1
if(m3.lt.13) cycle
c=0.
n1=6*(11+m1)
n2=n1+6*(11+m2)
c(1:66)=1.
c(1+n1:66+n1)=1.
c(1+n2:66+n2)=1.
call four2a(c,nfft,1,-1,1) !c2c FFT
df=12000.0/nfft
smax=0.
do i=0,nfft-1
s(i)=real(c(i))**2 + aimag(c(i))**2
if(i.ne.0) smax=max(s(i),smax)
enddo
sidelobe=db(smax/s(0))
if(sidelobe.lt.best) then
write(*,1000) m1,m2,m3,sidelobe
1000 format(3i5,f8.2)
best=sidelobe
s=s/s(0)
rewind 13
do j=0,nfft-1
i=mod(j+nh,nfft)
f=i*df
if(i.gt.nh) f=f-12000.0
write(13,1020) f,s(i)
1020 format(2f12.4)
enddo
endif
enddo
enddo
end program t6

10
lib/types.f90 Normal file
View File

@ -0,0 +1,10 @@
module types
use, intrinsic :: iso_fortran_env
implicit none
! use the Fortran 2008 intrinsic constants to define real kinds
integer, parameter :: sp = REAL32
integer, parameter :: dp = REAL64
integer, parameter :: qp = REAL128
end module types

View File

@ -373,13 +373,14 @@ int main(int argc, char *argv[])
}
if (!mem_jt9.attach ())
{
if (!mem_jt9.create (sizeof (struct dec_data)))
if (!mem_jt9.create (sizeof (dec_data)))
{
splash.hide ();
MessageBox::critical_message (nullptr, a.translate ("main", "Shared memory error"),
a.translate ("main", "Unable to create shared memory segment"));
throw std::runtime_error {"Shared memory error"};
}
qDebug () << "shmem size:" << mem_jt9.size ();
}
else
{

View File

@ -46,16 +46,22 @@ namespace
{20000000, Modes::FreqCal, IARURegions::ALL},
{136000, Modes::WSPR, IARURegions::ALL},
{136200, Modes::FST4W, IARURegions::ALL},
{136130, Modes::JT65, IARURegions::ALL},
{136130, Modes::JT9, IARURegions::ALL},
{136130, Modes::FST4, IARURegions::ALL},
{474200, Modes::JT65, IARURegions::ALL},
{474200, Modes::JT9, IARURegions::ALL},
{474200, Modes::FST4, IARURegions::ALL},
{474200, Modes::WSPR, IARURegions::ALL},
{474400, Modes::FST4W, IARURegions::ALL},
{1836600, Modes::WSPR, IARURegions::ALL},
{1836800, Modes::FST4W, IARURegions::ALL},
{1838000, Modes::JT65, IARURegions::ALL}, // squeezed allocations
{1839000, Modes::JT9, IARURegions::ALL},
{1839000, Modes::FST4, IARURegions::ALL},
{1840000, Modes::FT8, IARURegions::ALL},
// Band plans (all USB dial unless stated otherwise)
@ -87,8 +93,10 @@ namespace
//
{3570000, Modes::JT65, IARURegions::ALL}, // JA compatible
{3572000, Modes::JT9, IARURegions::ALL},
{3572000, Modes::FST4, IARURegions::ALL},
{3573000, Modes::FT8, IARURegions::ALL}, // above as below JT65 is out of DM allocation
{3568600, Modes::WSPR, IARURegions::ALL}, // needs guard marker and lock out
{3568800, Modes::FST4W, IARURegions::ALL},
{3575000, Modes::FT4, IARURegions::ALL}, // provisional
{3568000, Modes::FT4, IARURegions::R3}, // provisional
@ -124,9 +132,11 @@ namespace
// 7110 LSB EMCOMM
//
{7038600, Modes::WSPR, IARURegions::ALL},
{7038800, Modes::FST4W, IARURegions::ALL},
{7074000, Modes::FT8, IARURegions::ALL},
{7076000, Modes::JT65, IARURegions::ALL},
{7078000, Modes::JT9, IARURegions::ALL},
{7078000, Modes::FST4, IARURegions::ALL},
{7047500, Modes::FT4, IARURegions::ALL}, // provisional - moved
// up 500Hz to clear
// W1AW code practice QRG
@ -160,7 +170,9 @@ namespace
{10136000, Modes::FT8, IARURegions::ALL},
{10138000, Modes::JT65, IARURegions::ALL},
{10138700, Modes::WSPR, IARURegions::ALL},
{10138900, Modes::FST4W, IARURegions::ALL},
{10140000, Modes::JT9, IARURegions::ALL},
{10140000, Modes::FST4, IARURegions::ALL},
{10140000, Modes::FT4, IARURegions::ALL}, // provisional
// Band plans (all USB dial unless stated otherwise)
@ -201,9 +213,11 @@ namespace
// 14106.5 OLIVIA 1000 (main QRG)
//
{14095600, Modes::WSPR, IARURegions::ALL},
{14095800, Modes::FST4W, IARURegions::ALL},
{14074000, Modes::FT8, IARURegions::ALL},
{14076000, Modes::JT65, IARURegions::ALL},
{14078000, Modes::JT9, IARURegions::ALL},
{14078000, Modes::FST4, IARURegions::ALL},
{14080000, Modes::FT4, IARURegions::ALL}, // provisional
// Band plans (all USB dial unless stated otherwise)
@ -236,25 +250,33 @@ namespace
{18100000, Modes::FT8, IARURegions::ALL},
{18102000, Modes::JT65, IARURegions::ALL},
{18104000, Modes::JT9, IARURegions::ALL},
{18104000, Modes::FST4, IARURegions::ALL},
{18104000, Modes::FT4, IARURegions::ALL}, // provisional
{18104600, Modes::WSPR, IARURegions::ALL},
{18104800, Modes::FST4W, IARURegions::ALL},
{21074000, Modes::FT8, IARURegions::ALL},
{21076000, Modes::JT65, IARURegions::ALL},
{21078000, Modes::JT9, IARURegions::ALL},
{21078000, Modes::FST4, IARURegions::ALL},
{21094600, Modes::WSPR, IARURegions::ALL},
{21094800, Modes::FST4W, IARURegions::ALL},
{21140000, Modes::FT4, IARURegions::ALL},
{24915000, Modes::FT8, IARURegions::ALL},
{24917000, Modes::JT65, IARURegions::ALL},
{24919000, Modes::JT9, IARURegions::ALL},
{24919000, Modes::FST4, IARURegions::ALL},
{24919000, Modes::FT4, IARURegions::ALL}, // provisional
{24924600, Modes::WSPR, IARURegions::ALL},
{24924800, Modes::FST4W, IARURegions::ALL},
{28074000, Modes::FT8, IARURegions::ALL},
{28076000, Modes::JT65, IARURegions::ALL},
{28078000, Modes::JT9, IARURegions::ALL},
{28078000, Modes::FST4, IARURegions::ALL},
{28124600, Modes::WSPR, IARURegions::ALL},
{28124800, Modes::FST4W, IARURegions::ALL},
{28180000, Modes::FT4, IARURegions::ALL},
{50200000, Modes::Echo, IARURegions::ALL},
@ -265,8 +287,11 @@ namespace
{50260000, Modes::MSK144, IARURegions::R3},
{50293000, Modes::WSPR, IARURegions::R2},
{50293000, Modes::WSPR, IARURegions::R3},
{50293200, Modes::FST4W, IARURegions::R2},
{50293200, Modes::FST4W, IARURegions::R3},
{50310000, Modes::JT65, IARURegions::ALL},
{50312000, Modes::JT9, IARURegions::ALL},
{50312000, Modes::FST4, IARURegions::ALL},
{50313000, Modes::FT8, IARURegions::ALL},
{50318000, Modes::FT4, IARURegions::ALL}, // provisional
{50323000, Modes::FT8, IARURegions::ALL},
@ -275,6 +300,7 @@ namespace
{70102000, Modes::JT65, IARURegions::R1},
{70104000, Modes::JT9, IARURegions::R1},
{70091000, Modes::WSPR, IARURegions::R1},
{70091200, Modes::FST4W, IARURegions::R2},
{70230000, Modes::MSK144, IARURegions::R1},
{144120000, Modes::JT65, IARURegions::ALL},
@ -284,6 +310,7 @@ namespace
{144360000, Modes::MSK144, IARURegions::R1},
{144150000, Modes::MSK144, IARURegions::R2},
{144489000, Modes::WSPR, IARURegions::ALL},
{144489200, Modes::FST4W, IARURegions::R2},
{144120000, Modes::QRA64, IARURegions::ALL},
{222065000, Modes::Echo, IARURegions::R2},

View File

@ -24,7 +24,9 @@ namespace
"QRA64",
"FreqCal",
"FT8",
"FT4"
"FT4",
"FST4",
"FST4W"
};
std::size_t constexpr mode_names_size = sizeof (mode_names) / sizeof (mode_names[0]);
}

View File

@ -50,6 +50,8 @@ public:
FreqCal,
FT8,
FT4,
FST4,
FST4W,
MODES_END_SENTINAL_AND_COUNT // this must be last
};
Q_ENUM (Mode)

View File

@ -5,6 +5,7 @@
#include <QWidget>
#include <QStyle>
#include <QVariant>
#include <QDateTime>
QString font_as_stylesheet (QFont const& font)
{
@ -35,3 +36,15 @@ void update_dynamic_property (QWidget * widget, char const * property, QVariant
widget->style ()->polish (widget);
widget->update ();
}
QDateTime qt_round_date_time_to (QDateTime dt, int seconds)
{
dt.setSecsSinceEpoch (dt.addSecs (seconds - 1).toSecsSinceEpoch () / seconds * seconds);
return dt;
}
QDateTime qt_truncate_date_time_to (QDateTime dt, int seconds)
{
dt.setSecsSinceEpoch (dt.toSecsSinceEpoch () / seconds * seconds);
return dt;
}

View File

@ -69,6 +69,12 @@ QString font_as_stylesheet (QFont const&);
// conditional style sheet updates
void update_dynamic_property (QWidget *, char const * property, QVariant const& value);
// round a QDateTime instance to an interval
QDateTime qt_round_date_time_to (QDateTime dt, int seconds);
// truncate a QDateTime to an interval
QDateTime qt_truncate_date_time_to (QDateTime dt, int seconds);
template <class T>
class VPtr
{

View File

@ -25,13 +25,13 @@
extern "C" {
void astrosub(int nyear, int month, int nday, double uth, double freqMoon,
const char * mygrid, size_t mygrid_len, const char * hisgrid,
size_t hisgrid_len, double * azsun, double * elsun, double * azmoon,
const char * mygrid, const char * hisgrid,
double * azsun, double * elsun, double * azmoon,
double * elmoon, double * azmoondx, double * elmoondx, int * ntsky,
int * ndop, int * ndop00, double * ramoon, double * decmoon, double * dgrd,
double * poloffset, double * xnr, double * techo, double * width1,
double * width2, bool bTx, const char * AzElFileName, size_t AzElFileName_len,
const char * jpleph, size_t jpleph_len);
double * width2, bool bTx, const char * AzElFileName,
const char * jpleph);
}
Astro::Astro(QSettings * settings, Configuration const * configuration, QWidget * parent)
@ -112,14 +112,14 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const
auto const& jpleph = configuration_->data_dir ().absoluteFilePath ("JPLEPH");
astrosub(nyear, month, nday, uth, static_cast<double> (freq_moon),
mygrid.toLatin1 ().constData (), mygrid.size (),
hisgrid.toLatin1().constData(), hisgrid.size (),
mygrid.toLatin1 ().data (),
hisgrid.toLatin1().data(),
&azsun, &elsun, &azmoon, &elmoon,
&azmoondx, &elmoondx, &ntsky, &m_dop, &m_dop00, &ramoon, &decmoon,
&dgrd, &poloffset, &xnr, &techo, &width1, &width2,
bTx,
AzElFileName.toLatin1().constData(), AzElFileName.size (),
jpleph.toLatin1().constData(), jpleph.size ());
AzElFileName.toLatin1().data(),
jpleph.toLatin1().data());
if(!hisgrid.size ()) {
azmoondx=0.0;
@ -224,14 +224,14 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const
double sec {target_date_time.time().second() + 0.001*target_date_time.time().msec()};
double uth {nhr + nmin/60.0 + sec/3600.0};
astrosub(nyear, month, nday, uth, static_cast<double> (freq_moon),
mygrid.toLatin1 ().constData (), mygrid.size (),
hisgrid.toLatin1().constData(), hisgrid.size (),
mygrid.toLatin1 ().data (),
hisgrid.toLatin1().data(),
&azsun, &elsun, &azmoon, &elmoon,
&azmoondx, &elmoondx, &ntsky, &m_dop, &m_dop00, &ramoon, &decmoon,
&dgrd, &poloffset, &xnr, &techo, &width1, &width2,
bTx,
AzElFileName.toLatin1().constData(), AzElFileName.size (),
jpleph.toLatin1().constData(), jpleph.size ());
nullptr, // don't overwrite azel.dat
jpleph.toLatin1().data());
FrequencyDelta offset {0};
switch (m_DopplerMethod)
{

View File

@ -241,10 +241,9 @@ void DisplayText::new_period ()
QString DisplayText::appendWorkedB4 (QString message, QString call, QString const& grid,
QColor * bg, QColor * fg, LogBook const& logBook,
QString const& currentBand, QString const& currentMode)
QString const& currentBand, QString const& currentMode,
QString extra)
{
// allow for seconds
int padding {message.indexOf (" ") > 4 ? 2 : 0};
QString countryName;
bool callB4;
bool callB4onBand;
@ -278,7 +277,6 @@ QString DisplayText::appendWorkedB4 (QString message, QString call, QString cons
}
message = message.trimmed ();
QString appendage;
highlight_types types;
// no shortcuts here as some types may be disabled
@ -329,20 +327,20 @@ QString DisplayText::appendWorkedB4 (QString message, QString call, QString cons
{
case Highlight::Continent:
case Highlight::ContinentBand:
appendage = AD1CCty::continent (looked_up.continent);
extra += AD1CCty::continent (looked_up.continent);
break;
case Highlight::CQZone:
case Highlight::CQZoneBand:
appendage = QString {"CQ Zone %1"}.arg (looked_up.CQ_zone);
extra += QString {"CQ Zone %1"}.arg (looked_up.CQ_zone);
break;
case Highlight::ITUZone:
case Highlight::ITUZoneBand:
appendage = QString {"ITU Zone %1"}.arg (looked_up.ITU_zone);
extra += QString {"ITU Zone %1"}.arg (looked_up.ITU_zone);
break;
default:
if (m_bPrincipalPrefix)
{
appendage = looked_up.primary_prefix;
extra += looked_up.primary_prefix;
}
else
{
@ -368,26 +366,38 @@ QString DisplayText::appendWorkedB4 (QString message, QString call, QString cons
countryName.replace ("European", "EU");
countryName.replace ("African", "AF");
appendage += countryName;
extra += countryName;
}
}
m_CQPriority=DecodeHighlightingModel::highlight_name(top_highlight);
// use a nbsp to save the start of appended text so we can find
// it again later, align appended data at a fixed column if
// there is space otherwise let it float to the right
int space_count {40 + padding - message.size ()};
if (space_count > 0) {
message += QString {space_count, QChar {' '}};
}
message += QChar::Nbsp + appendage;
return leftJustifyAppendage (message, extra);
}
QString DisplayText::leftJustifyAppendage (QString message, QString const& appendage) const
{
if (appendage.size ())
{
// allow for seconds
int padding {message.indexOf (" ") > 4 ? 2 : 0};
// use a nbsp to save the start of appended text so we can find
// it again later, align appended data at a fixed column if
// there is space otherwise let it float to the right
int space_count {40 + padding - message.size ()};
if (space_count > 0) {
message += QString {space_count, QChar {' '}};
}
message += QChar::Nbsp + appendage;
}
return message;
}
void DisplayText::displayDecodedText(DecodedText const& decodedText, QString const& myCall,
QString const& mode,
bool displayDXCCEntity, LogBook const& logBook,
QString const& currentBand, bool ppfx, bool bCQonly)
QString const& currentBand, bool ppfx, bool bCQonly,
bool haveFSpread, float fSpread)
{
m_bPrincipalPrefix=ppfx;
QColor bg;
@ -420,7 +430,18 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
decodedText.deCallAndGrid (/*out*/ dxCall, dxGrid);
QRegularExpression grid_regexp {"\\A(?![Rr]{2}73)[A-Ra-r]{2}[0-9]{2}([A-Xa-x]{2}){0,1}\\z"};
if(!dxGrid.contains(grid_regexp)) dxGrid="";
message = message.left (message.indexOf (QChar::Nbsp)); // strip appended info
message = message.left (message.indexOf (QChar::Nbsp)).trimmed (); // strip appended info
QString extra;
if (haveFSpread)
{
extra += QString {"%1"}.arg (fSpread, 5, 'f', fSpread < 0.95 ? 3 : 2) + QChar {' '};
}
auto ap_pos = message.lastIndexOf (QRegularExpression {R"((?:\?\s)?a[0-9]$)"});
if (ap_pos >= 0)
{
extra += message.mid (ap_pos) + QChar {' '};
message = message.left (ap_pos).trimmed ();
}
m_CQPriority="";
if (CQcall)
{
@ -434,10 +455,11 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
currentMode = decodedText.isJT65 () ? "JT65" : "JT9";
}
message = appendWorkedB4 (message, decodedText.CQersCall(), dxGrid, &bg, &fg
, logBook, currentBand, currentMode);
, logBook, currentBand, currentMode, extra);
}
else
{
message = leftJustifyAppendage (message, extra);
highlight_types types {Highlight::CQ};
if (m_config && m_config->lotw_users ().user (decodedText.CQersCall()))
{
@ -446,12 +468,17 @@ void DisplayText::displayDecodedText(DecodedText const& decodedText, QString con
set_colours (m_config, &bg, &fg, types);
}
}
else
{
message = leftJustifyAppendage (message, extra);
}
appendText (message.trimmed (), bg, fg, decodedText.call (), dxCall);
}
void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 txFreq,bool bFastMode)
void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 txFreq,
bool bFastMode, double TRperiod)
{
QString t1=" @ ";
if(modeTx=="FT4") t1=" + ";
@ -459,10 +486,11 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx
if(modeTx=="JT4") t1=" $ ";
if(modeTx=="JT65") t1=" # ";
if(modeTx=="MSK144") t1=" & ";
if(modeTx=="FST4") t1=" ` ";
QString t2;
t2 = t2.asprintf("%4d",txFreq);
QString t;
if(bFastMode or modeTx=="FT8" or modeTx=="FT4") {
if(bFastMode or modeTx=="FT8" or modeTx=="FT4" or (TRperiod<60)) {
t = QDateTime::currentDateTimeUtc().toString("hhmmss") + \
" Tx " + t2 + t1 + text;
} else if(modeTx.mid(0,6)=="FT8fox") {

View File

@ -30,8 +30,9 @@ public:
void insertLineSpacer(QString const&);
void displayDecodedText(DecodedText const& decodedText, QString const& myCall, QString const& mode,
bool displayDXCCEntity, LogBook const& logBook,
QString const& currentBand=QString {}, bool ppfx=false, bool bCQonly=false);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq, bool bFastMode);
QString const& currentBand=QString {}, bool ppfx=false, bool bCQonly=false,
bool haveFSpread = false, float fSpread = 0.);
void displayTransmittedText(QString text, QString modeTx, qint32 txFreq, bool bFastMode, double TRperiod);
void displayQSY(QString text);
void displayFoxToBeCalled(QString t, QColor bg = QColor {}, QColor fg = QColor {});
void new_period ();
@ -46,6 +47,7 @@ public:
Q_SLOT void highlight_callsign (QString const& callsign, QColor const& bg, QColor const& fg, bool last_period_only);
private:
QString leftJustifyAppendage (QString message, QString const& appendage) const;
void mouseDoubleClickEvent (QMouseEvent *) override;
void extend_vertical_scrollbar (int min, int max);
@ -56,7 +58,7 @@ private:
QString appendWorkedB4(QString message, QString callsign
, QString const& grid, QColor * bg, QColor * fg
, LogBook const& logBook, QString const& currentBand
, QString const& currentMode);
, QString const& currentMode, QString extra);
QFont char_font_;
QAction * erase_action_;
QHash<QString, QPair<QColor, QColor>> highlighted_calls_;

File diff suppressed because it is too large Load Diff

View File

@ -45,15 +45,14 @@
#define NUM_JT65_SYMBOLS 126 //63 data + 63 sync
#define NUM_JT9_SYMBOLS 85 //69 data + 16 sync
#define NUM_WSPR_SYMBOLS 162 //(50+31)*2, embedded sync
#define NUM_WSPR_LF_SYMBOLS 412 //300 data + 109 sync + 3 ramp
#define NUM_ISCAT_SYMBOLS 1291 //30*11025/256
#define NUM_MSK144_SYMBOLS 144 //s8 + d48 + s8 + d80
#define NUM_QRA64_SYMBOLS 84 //63 data + 21 sync
#define NUM_FT8_SYMBOLS 79
#define NUM_FT4_SYMBOLS 105
#define NUM_FST4_SYMBOLS 160 //240/2 data + 5*8 sync
#define NUM_CW_SYMBOLS 250
#define TX_SAMPLE_RATE 48000
#define N_WIDGETS 33
#define NRING 3456000
extern int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols
@ -206,6 +205,8 @@ private slots:
void on_actionJT4_triggered();
void on_actionFT4_triggered();
void on_actionFT8_triggered();
void on_actionFST4_triggered();
void on_actionFST4W_triggered();
void on_TxFreqSpinBox_valueChanged(int arg1);
void on_actionSave_decoded_triggered();
void on_actionQuickDecode_toggled (bool);
@ -278,13 +279,12 @@ private slots:
void networkError (QString const&);
void on_ClrAvgButton_clicked();
void on_actionWSPR_triggered();
void on_actionWSPR_LF_triggered();
void on_syncSpinBox_valueChanged(int n);
void on_TxPowerComboBox_currentIndexChanged(int);
void on_sbTxPercent_valueChanged(int n);
void on_cbUploadWSPR_Spots_toggled(bool b);
void WSPR_config(bool b);
void uploadSpots();
void uploadWSPRSpots (bool direct_post = false, QString const& decode_text = QString {});
void TxAgain();
void uploadResponse(QString response);
void on_WSPRfreqSpinBox_valueChanged(int n);
@ -298,6 +298,7 @@ private slots:
void on_actionErase_reference_spectrum_triggered();
void on_actionMeasure_phase_response_triggered();
void on_sbTR_valueChanged (int);
void on_sbTR_FST4W_valueChanged (int);
void on_sbFtol_valueChanged (int);
void on_cbFast9_clicked(bool b);
void on_sbCQTxFreq_valueChanged(int n);
@ -315,6 +316,7 @@ private slots:
void not_GA_warning_message ();
void checkMSK144ContestType();
void on_pbBestSP_clicked();
void on_RoundRobin_currentTextChanged(QString text);
int setTxMsg(int n);
bool stdCall(QString const& w);
void remote_configure (QString const& mode, quint32 frequency_tolerance, QString const& submode
@ -337,8 +339,8 @@ private:
Q_SIGNAL void transmitFrequency (double) const;
Q_SIGNAL void endTransmitMessage (bool quick = false) const;
Q_SIGNAL void tune (bool = true) const;
Q_SIGNAL void sendMessage (unsigned symbolsLength, double framesPerSymbol,
double frequency, double toneSpacing,
Q_SIGNAL void sendMessage (QString mode, unsigned symbolsLength,
double framesPerSymbol, double frequency, double toneSpacing,
SoundOutput *, AudioDevice::Channel = AudioDevice::Mono,
bool synchronize = true, bool fastMode = false, double dBSNR = 99.,
int TRperiod=60) const;
@ -500,7 +502,7 @@ private:
QString m_tBlankLine;
bool m_bShMsgs;
bool m_bSWL;
bool m_uploadSpots;
bool m_uploadWSPRSpots;
bool m_uploading;
bool m_txNext;
bool m_grid6;
@ -677,7 +679,6 @@ private:
bool m_tx_watchdog; // true when watchdog triggered
bool m_block_pwr_tooltip;
bool m_PwrBandSetOK;
bool m_bVHFwarned;
bool m_bDisplayedOnce;
Frequency m_lastMonitoredFrequency;
double m_toneSpacing;
@ -716,7 +717,7 @@ private:
void pskPost(DecodedText const& decodedtext);
void displayDialFrequency ();
void transmitDisplay (bool);
void processMessage(DecodedText const&, Qt::KeyboardModifiers = Qt::NoModifier);
void processMessage(DecodedText const& message, Qt::KeyboardModifiers = Qt::NoModifier);
void replyToCQ (QTime, qint32 snr, float delta_time, quint32 delta_frequency, QString const& mode, QString const& message_text, bool low_confidence, quint8 modifiers);
void locationChange(QString const& location);
void replayDecodes ();
@ -728,7 +729,8 @@ private:
void freqCalStep();
void setRig (Frequency = 0); // zero frequency means no change
void WSPR_history(Frequency dialFreq, int ndecodes);
QString WSPR_hhmm(int n);
QString beacon_start_time (int n = 0);
QString WSPR_message();
void fast_config(bool b);
void CQTxFreq();
void useNextCall();
@ -762,7 +764,6 @@ private:
void tx_watchdog (bool triggered);
qint64 nWidgets(QString t);
void displayWidgets(qint64 n);
void vhfWarning();
QChar current_submode () const; // returns QChar {0} if submode is not appropriate
void write_transmit_entry (QString const& file_name);
void selectHound(QString t);

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,7 @@ CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
setAutoFillBackground(false);
setAttribute(Qt::WA_OpaquePaintEvent, false);
setAttribute(Qt::WA_NoSystemBackground, true);
setMouseTracking(true);
m_bReplot=false;
// contextual pop up menu
@ -184,7 +185,6 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed)
if (swide[i]<1.e29) painter1.setPen(g_ColorTbl[y1]);
painter1.drawPoint(i,m_j);
}
m_line++;
float y2min=1.e30;
@ -211,7 +211,7 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed)
for(int k=0; k<m_binsPerPixel; k++) {
sum+=spectra_.syellow[j++];
}
y2=gain2d*sum/m_binsPerPixel + m_plot2dZero;
y2=2.0*gain2d*sum/m_binsPerPixel + m_plot2dZero;
}
if(m_bReference) { //Reference (red)
@ -330,7 +330,6 @@ void CPlotter::DrawOverlay() //DrawOverlay()
double df = m_binsPerPixel*m_fftBinWidth;
QPen penOrange(QColor(255,165,0),3);
// QPen penGreen(Qt::green, 3); //Mark Tol range with green line
QPen penGreen(QColor(15,153,105), 3); //Mark Tol range or BW with dark green line
QPen penRed(Qt::red, 3); //Mark Tx freq with red
QPainter painter(&m_OverlayPixmap);
@ -415,7 +414,18 @@ void CPlotter::DrawOverlay() //DrawOverlay()
float bw=9.0*12000.0/m_nsps; //JT9
if(m_mode=="FT4") bw=3*12000.0/576.0; //FT4 ### (3x, or 4x???) ###
if(m_mode=="FT8") bw=7*12000.0/1920.0; //FT8
if(m_mode.startsWith("FST4")) {
int h=int(pow(2.0,m_nSubMode));
int nsps=800;
if(m_TRperiod==30) nsps=1680;
if(m_TRperiod==60) nsps=4000;
if(m_TRperiod==120) nsps=8400;
if(m_TRperiod==300) nsps=21504;
if(m_TRperiod==900) nsps=66560;
if(m_TRperiod==1800) nsps=134400;
float baud=12000.0/nsps;
bw=3.0*h*baud;
}
if(m_mode=="JT4") { //JT4
bw=3*11025.0/2520.0; //Max tone spacing (3/4 of actual BW)
if(m_nSubMode==1) bw=2*bw;
@ -471,13 +481,13 @@ void CPlotter::DrawOverlay() //DrawOverlay()
if(m_mode=="WSPR") {
x1=XfromFreq(1400);
x2=XfromFreq(1600);
painter0.drawLine(x1,29,x2,29);
painter0.drawLine(x1,26,x2,26);
}
if(m_mode=="WSPR-LF") {
x1=XfromFreq(1600);
x2=XfromFreq(1700);
painter0.drawLine(x1,29,x2,29);
if(m_mode=="FST4W") {
x1=XfromFreq(2600);
x2=XfromFreq(2700);
painter0.drawLine(x1,26,x2,26);
}
if(m_mode=="FreqCal") { //FreqCal
@ -492,7 +502,8 @@ void CPlotter::DrawOverlay() //DrawOverlay()
int yTxTop=12;
int yRxBottom=yTxTop + 2*yh + 4;
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65"
or m_mode=="QRA64" or m_mode=="FT8" or m_mode=="FT4") {
or m_mode=="QRA64" or m_mode=="FT8" or m_mode=="FT4"
or m_mode.startsWith("FST4")) {
if(m_mode=="QRA64" or (m_mode=="JT65" and m_bVHF)) {
painter0.setPen(penGreen);
@ -523,13 +534,17 @@ void CPlotter::DrawOverlay() //DrawOverlay()
painter0.drawLine(x1,yRxBottom-yh,x1,yRxBottom);
painter0.drawLine(x1,yRxBottom,x2,yRxBottom);
painter0.drawLine(x2,yRxBottom-yh,x2,yRxBottom);
if(m_mode.startsWith("FST4")) {
x1=XfromFreq(m_rxFreq-m_tol);
x2=XfromFreq(m_rxFreq+m_tol);
painter0.drawLine(x1,26,x2,26); // Mark the Tol range
}
}
}
if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or
m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="FT8"
or m_mode=="FT4") {
or m_mode=="FT4" or m_mode.startsWith("FST4")) {
painter0.setPen(penRed);
x1=XfromFreq(m_txFreq);
x2=XfromFreq(m_txFreq+bw);
@ -538,11 +553,6 @@ void CPlotter::DrawOverlay() //DrawOverlay()
x1=XfromFreq(m_txFreq-0.5*bw);
x2=XfromFreq(m_txFreq+0.5*bw);
}
if(m_mode=="WSPR-LF") {
bw=3*12000.0/8640.0; //WSPR-LF
x1=XfromFreq(m_txFreq-0.5*bw);
x2=XfromFreq(m_txFreq+0.5*bw);
}
// Draw the red "goal post"
painter0.drawLine(x1,yTxTop,x1,yTxTop+yh);
painter0.drawLine(x1,yTxTop,x2,yTxTop);
@ -688,9 +698,16 @@ void CPlotter::setRxFreq (int x) //setRxFreq
int CPlotter::rxFreq() {return m_rxFreq;} //rxFreq
void CPlotter::mouseMoveEvent (QMouseEvent * event)
{
int x=event->x();
QToolTip::showText(event->globalPos(),QString::number(int(FreqfromX(x))));
QWidget::mouseMoveEvent(event);
}
void CPlotter::mouseReleaseEvent (QMouseEvent * event)
{
if (Qt::LeftButton == event->button ()) {
if (Qt::LeftButton == event->button () and m_mode!="FST4W") {
int x=event->x();
if(x<0) x=0;
if(x>m_Size.width()) x=m_Size.width();

View File

@ -13,6 +13,7 @@
#include <QImage>
#include <QVector>
#include <QColor>
#include <QToolTip>
#define VERT_DIVS 7 //specify grid screen divisions
#define HORZ_DIVS 20
@ -91,6 +92,7 @@ protected:
//re-implemented widget event handlers
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent* event) override;
void mouseMoveEvent(QMouseEvent * event) override;
void mouseReleaseEvent (QMouseEvent * event) override;
void mouseDoubleClickEvent (QMouseEvent * event) override;

View File

@ -294,7 +294,7 @@ void WideGraph::setTxFreq(int n) //setTxFreq
void WideGraph::setMode(QString mode) //setMode
{
m_mode=mode;
ui->fSplitSpinBox->setEnabled(m_mode=="JT9+JT65");
ui->fSplitSpinBox->setEnabled(m_mode=="JT9+JT65" or m_mode.startsWith("FST4"));
ui->widePlot->setMode(mode);
ui->widePlot->DrawOverlay();
ui->widePlot->update();
@ -368,7 +368,7 @@ void WideGraph::setRxBand (QString const& band)
else
{
ui->fSplitSpinBox->setValue (m_fMinPerBand.value (band, 2500).toUInt ());
ui->fSplitSpinBox->setEnabled (m_mode=="JT9+JT65");
ui->fSplitSpinBox->setEnabled (m_mode=="JT9+JT65" or m_mode.startsWith("FST4"));
}
ui->widePlot->setRxBand(band);
setRxRange ();

View File

@ -362,10 +362,10 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Decode JT9 only above this frequency&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="suffix">
<string> JT9</string>
<string> Hz</string>
</property>
<property name="prefix">
<string>JT65 </string>
<string>Split </string>
</property>
<property name="minimum">
<number>0</number>
@ -393,7 +393,7 @@
<number>1</number>
</property>
<property name="maximum">
<number>50</number>
<number>500</number>
</property>
</widget>
</item>

View File

@ -53,6 +53,8 @@ include(item_delegates/item_delegates.pri)
include(logbook/logbook.pri)
include(widgets/widgets.pri)
include(Decoder/decodedtext.pri)
include(Detector/Detector.pri)
include(Modulator/Modulator.pri)
SOURCES += \
Radio.cpp NetworkServerLookup.cpp revision_utils.cpp \