Merged master 8748

This commit is contained in:
Jordan Sherer
2018-08-05 11:33:30 -04:00
parent 8f8772f1bd
commit 62899069bf
1095 changed files with 31298 additions and 367679 deletions
@@ -1,139 +0,0 @@
module ft8_decode
type :: ft8_decoder
procedure(ft8_decode_callback), pointer :: callback
contains
procedure :: decode
end type ft8_decoder
abstract interface
subroutine ft8_decode_callback (this,sync,snr,dt,freq,decoded,nap,qual)
import ft8_decoder
implicit none
class(ft8_decoder), intent(inout) :: this
real, intent(in) :: sync
integer, intent(in) :: snr
real, intent(in) :: dt
real, intent(in) :: freq
character(len=22), intent(in) :: decoded
integer, intent(in) :: nap
real, intent(in) :: qual
end subroutine ft8_decode_callback
end interface
contains
subroutine decode(this,callback,iwave,nQSOProgress,nfqso,nftx,newdat, &
nutc,nfa,nfb,nexp_decode,ndepth,nagain,lapon,napwid,mycall12, &
mygrid6,hiscall12,hisgrid6)
! use wavhdr
use timer_module, only: timer
include 'fsk4hf/ft8_params.f90'
! type(hdr) h
class(ft8_decoder), intent(inout) :: this
procedure(ft8_decode_callback) :: callback
real s(NH1,NHSYM)
real sbase(NH1)
real candidate(3,200)
real dd(15*12000)
logical, intent(in) :: lapon,nagain
logical newdat,lsubtract,ldupe,bcontest
character*12 mycall12, hiscall12
character*6 mygrid6,hisgrid6
integer*2 iwave(15*12000)
integer apsym(KK)
character datetime*13,message*22
character*22 allmessages(100)
integer allsnrs(100)
save s,dd
bcontest=iand(nexp_decode,128).ne.0
this%callback => callback
write(datetime,1001) nutc !### TEMPORARY ###
1001 format("000000_",i6.6)
call ft8apset(mycall12,mygrid6,hiscall12,hisgrid6,bcontest,apsym,iaptype)
dd=iwave
ndecodes=0
allmessages=' '
allsnrs=0
ifa=nfa
ifb=nfb
if(nagain) then
ifa=nfqso-10
ifb=nfqso+10
endif
! For now:
! ndepth=1: no subtraction, 1 pass, belief propagation only
! ndepth=2: subtraction, 3 passes, belief propagation only
! ndepth=3: subtraction, 3 passes, bp+osd
if(ndepth.eq.1) npass=1
if(ndepth.ge.2) npass=3
do ipass=1,npass
newdat=.true. ! Is this a problem? I hijacked newdat.
syncmin=1.5
if(ipass.eq.1) then
lsubtract=.true.
if(ndepth.eq.1) lsubtract=.false.
elseif(ipass.eq.2) then
n2=ndecodes
if(ndecodes.eq.0) cycle
lsubtract=.true.
elseif(ipass.eq.3) then
if((ndecodes-n2).eq.0) cycle
lsubtract=.false.
endif
call timer('sync8 ',0)
call sync8(dd,ifa,ifb,syncmin,nfqso,s,candidate,ncand,sbase)
call timer('sync8 ',1)
do icand=1,ncand
sync=candidate(3,icand)
f1=candidate(1,icand)
xdt=candidate(2,icand)
xbase=10.0**(0.1*(sbase(nint(f1/3.125))-40.0))
nsnr0=min(99,nint(10.0*log10(sync) - 25.5)) !### empirical ###
call timer('ft8b ',0)
call ft8b(dd,newdat,nQSOProgress,nfqso,nftx,ndepth,lapon,napwid, &
lsubtract,nagain,iaptype,mygrid6,bcontest,sync,f1,xdt,xbase, &
apsym,nharderrors,dmin,nbadcrc,iappass,iera,message,xsnr)
nsnr=nint(xsnr)
xdt=xdt-0.5
hd=nharderrors+dmin
call timer('ft8b ',1)
if(nbadcrc.eq.0) then
! call jtmsg(message,iflag)
if(bcontest) call fix_contest_msg(mygrid6,message)
! if(iand(iflag,31).ne.0) message(22:22)='?'
ldupe=.false.
do id=1,ndecodes
if(message.eq.allmessages(id).and.nsnr.le.allsnrs(id)) ldupe=.true.
enddo
if(.not.ldupe) then
ndecodes=ndecodes+1
allmessages(ndecodes)=message
allsnrs(ndecodes)=nsnr
endif
! write(81,1004) nutc,ncand,icand,ipass,iaptype,iappass, &
! nharderrors,dmin,hd,min(sync,999.0),nint(xsnr), &
! xdt,nint(f1),message
!1004 format(i6.6,2i4,3i2,i3,3f6.1,i4,f6.2,i5,2x,a22)
! flush(81)
if(.not.ldupe .and. associated(this%callback)) then
qual=1.0-(nharderrors+dmin)/60.0 ! scale qual to [0.0,1.0]
call this%callback(sync,nsnr,xdt,f1,message,iaptype,qual)
endif
endif
enddo
! h=default_header(12000,NMAX)
! open(10,file='subtract.wav',status='unknown',access='stream')
! iwave=nint(dd)
! write(10) h,iwave
! close(10)
enddo
return
end subroutine decode
end module ft8_decode
@@ -1,125 +0,0 @@
<HTML><HEAD>
<TITLE> Notes on Modifying the LDPC Programs </TITLE>
</HEAD><BODY>
<H1> Notes on Modifying the LDPC Programs </H1>
<P>Here are a few notes on how to modify the programs to add new types of
channel, new decoding procedures, etc. You should also look at the <A
HREF="modules.html">module documentation</A>.
<H2> Adding a new type of channel </H2>
<P>Channels are involved in two programs:
<A HREF="channel.html#transmit"><B>transmit</B></A> and
<A HREF="decoding.html#decode"><B>decode</B></A>.
Adding another type of memoryless channel should be straightforward.
Adding a channel with memory may involve more work. Here are the
steps needed if no major reorganizations are required:
<OL>
<LI> Decide on a syntax for specifying the new channel type and its
parameters, and on an internal name for the channel type. Add
the internal name as a possibility in the enumerated <TT>channel_type</TT>
declared in <A HREF="channel.h"><TT>channel.h</TT></A>. You
may also need to declare new global variables to store parameters of
the channel in <A HREF="channel.h"><TT>channel.h</TT></A> and
<A HREF="channel.c"><TT>channel.c</TT></A>.
<LI> Modify the <TT>channel_parse</TT> and
<TT>channel_usage</TT> procedures in
<A HREF="channel.c"><TT>channel.c</TT></A> to
parse the specification of the new channel and display an appropriate
usage message.
<LI> Decide on how the new channel's output is represented in a file
(eg, for an erasure channel, what the symbol for an erasure is), and
update <A HREF="transmit.c"><TT>transmit.c</TT></A> to write the
new channel's output for each transmitted bit, after randomly generating
any noise (see
the <A HREF="rand.html">documentation on random number generation</A>).
<LI> Modify <A HREF="decode.c"><TT>decode.c</TT></A> in three places to
accommodate the new channel. The three sections of code to modify
allocate space for data from the channel, read data from the channel,
and set likelihood ratios based on the data read. The setting of
likelihood ratios is based on the assumption that the channel is
memoryless (ie, data received for different bits is independent).
Adding a channel with memory would require changing this assumption,
which would involve modifications to the decoding procedures too.
<LI> Document the new channel type in <A HREF="channel.html">channel.html</A>
and <A HREF="decoding.html">decoding.html</A>.
</OL>
<H2> Adding a new decoding procedure </H2>
A new decoding method can be implemented as follows:
<OL>
<LI> Decide on a syntax for specifying the method and its parameters,
using the trailing arguments to the
<A HREF="decoding.html#decode"><TT>decode</TT></A> program. Pick an
internal name for the method, and add it as a possibility in the
enumerated <TT>decoding_method</TT> type in
<A HREF="dec.h"><TT>dec.h</TT></A>. You may also need to declare
new variables for the method's parameters in
<A HREF="dec.h"><TT>dec.h</TT></A> and <A HREF="dec.c"><TT>dec.c</TT></A>.
<LI> Modify the argument parsing code in
<A HREF="decode.c"><TT>decode.c</TT></A>
to handle specifications of the new method, and change the <TT>usage</TT>
procedure to display the syntax for specifying the new method.
<LI> Write a setup procedure for your decoding method, putting it in
<A HREF="dec.c"><TT>dec.c</TT></A>, with a declaration in
<A HREF="dec.h"><TT>dec.h</TT></A>. At a minimum, this procedure
should print headers for the table of detailed decoding information
when the <B>-T</B> option was specified.
<LI> Write a decode procedure implementing your method, putting it in
<A HREF="dec.c"><TT>dec.c</TT></A>, with a declaration in
<A HREF="dec.h"><TT>dec.h</TT></A>. This procedure should output
detailed trace information when the <B>-T</B> option was specified.
<LI> Modify <A HREF="decode.c"><TT>decode.c</TT></A> in the appropriate
places to call the setup procedure and the decode procedure you wrote.
<LI> Document the new decoding method in
<A HREF="decoding.html">decoding.html</A> and
<A HREF="decode-detail.html">decode-detail.html</A>.
</OL>
<H2> Adding a new method of making a low-density parity-check matrix </H2>
<P>The <A HREF="pchk.html#make-ldpc"><B>make-ldpc</B></A> program can be
changed to add a new method for generating a LDPC code by modifying
<A HREF="make-ldpc.c"><TT>make-ldpc.c</TT></A>. A radically different
method might better be implemented by writing a new program of similar
structure.
<H2> Adding a new encoding method </H2>
<P>A new heuristic for finding a sparse LU decomposition can be
implemented by changing <A HREF="make-gen.c">make-gen.c</A> to allow
the new heuristic to be specified on the command line, changing the <A
HREF="mod2sparse.html#decomp"><B>mod2sparse_decomp</B></A> procedure
in <A HREF="mod2sparse.c"><TT>mod2sparse.c</TT></A> to implement the
heuristic, and documenting the new heuristic in <A
HREF="encoding.html">encoding.html</A>, <A
HREF="sparse-LU.html">sparse-LU.html</A>, and <A
HREF="mod2sparse.html">mod2sparse.html</A>.
<P>To implement a completely new encoding method, you will first need
to define a new file format for a generator matrix, modify <A
HREF="make-gen.c">make-gen.c</A> appropriately to write out this new
format, and modify the <TT>read_gen</TT> procedure in <A
HREF="rcode.c"><TT>rcode.c</TT></A> to read this format. You will
need to implement the new method in a procedure in <A
HREF="enc.c">enc.c</A>, and modify <A HREF="encode.c">encode.c</A> so
that it will call this new procedure when the new method is used. The
<TT>enum_decode</TT> procedure in <A HREF="dec.c">dec.c</A> will also
need to be modified so it can call the new encoding method. Finally,
you should document the new method in <A
HREF="encoding.html">encoding.html</A>
<P>
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>
@@ -1,131 +0,0 @@
#include "NetworkMessage.hpp"
#include <exception>
#include <QString>
#include <QByteArray>
#include "pimpl_impl.hpp"
namespace NetworkMessage
{
Builder::Builder (QIODevice * device, Type type, QString const& id, quint32 schema)
: QDataStream {device}
{
common_initialization (type, id, schema);
}
Builder::Builder (QByteArray * a, Type type, QString const& id, quint32 schema)
: QDataStream {a, QIODevice::WriteOnly}
{
common_initialization (type, id, schema);
}
void Builder::common_initialization (Type type, QString const& id, quint32 schema)
{
if (schema <= 1)
{
setVersion (QDataStream::Qt_5_0); // Qt schema version
}
#if QT_VERSION >= 0x050200
else if (schema <= 2)
{
setVersion (QDataStream::Qt_5_2); // Qt schema version
}
#endif
#if QT_VERSION >= 0x050400
else if (schema <= 3)
{
setVersion (QDataStream::Qt_5_4); // Qt schema version
}
#endif
else
{
throw std::runtime_error {"Unrecognized message schema"};
}
// the following two items assume that the quint32 encoding is
// unchanged over QDataStream versions
*this << magic;
*this << schema;
*this << static_cast<quint32> (type) << id.toUtf8 ();
}
class Reader::impl
{
public:
void common_initialization (Reader * parent)
{
quint32 magic;
*parent >> magic;
if (magic != Builder::magic)
{
throw std::runtime_error {"Invalid message format"};
}
*parent >> schema_;
if (schema_ > Builder::schema_number)
{
throw std::runtime_error {"Unrecognized message schema"};
}
if (schema_ <= 1)
{
parent->setVersion (QDataStream::Qt_5_0);
}
#if QT_VERSION >= 0x050200
else if (schema_ <= 2)
{
parent->setVersion (QDataStream::Qt_5_2);
}
#endif
#if QT_VERSION >= 0x050400
else if (schema_ <= 3)
{
parent->setVersion (QDataStream::Qt_5_4);
}
#endif
quint32 type;
*parent >> type >> id_;
if (type >= maximum_message_type_)
{
throw std::runtime_error {"Unrecognized message type"};
}
type_ = static_cast<Type> (type);
}
quint32 schema_;
Type type_;
QByteArray id_;
};
Reader::Reader (QIODevice * device)
: QDataStream {device}
{
m_->common_initialization (this);
}
Reader::Reader (QByteArray const& a)
: QDataStream {a}
{
m_->common_initialization (this);
}
Reader::~Reader ()
{
}
quint32 Reader::schema () const
{
return m_->schema_;
}
Type Reader::type () const
{
return static_cast<Type> (m_->type_);
}
QString Reader::id () const
{
return QString::fromUtf8 (m_->id_);
}
}
@@ -0,0 +1,31 @@
#include <boost/crc.hpp>
#include <boost/config.hpp>
extern "C"
{
short crc14 (unsigned char const * data, int length);
bool crc14_check (unsigned char const * data, int length);
}
#define POLY 0x2757
#ifdef BOOST_NO_CXX11_CONSTEXPR
#define TRUNCATED_POLYNOMIAL POLY
#else
namespace
{
unsigned long constexpr TRUNCATED_POLYNOMIAL = POLY;
}
#endif
// assumes CRC is last 14 bits of the data and is set to zero
// caller should assign the returned CRC into the message in big endian byte order
short crc14 (unsigned char const * data, int length)
{
return boost::augmented_crc<14, TRUNCATED_POLYNOMIAL> (data, length);
}
bool crc14_check (unsigned char const * data, int length)
{
return !boost::augmented_crc<14, TRUNCATED_POLYNOMIAL> (data, length);
}
@@ -0,0 +1,316 @@
subroutine wqdec(data0,message,ntype)
use packjt
parameter (N15=32758)
integer*1 data0(11)
character*22 message
character*12 callsign
character*3 cdbm,cf
character*2 crpt
character*4 grid,psfx
character*9 name
character*36 fmt
character*6 cwx(4)
character*7 cwind(5)
character ccur*4,cxp*2
logical first
character*12 dcall(0:N15-1)
data first/.true./
data cwx/'CLEAR','CLOUDY','RAIN','SNOW'/
data cwind/'CALM','BREEZES','WINDY','DRY','HUMID'/
save first,dcall
if(first) then
dcall=' '
first=.false.
endif
message=' '
call unpack50(data0,n1,n2)
call unpackcall(n1,callsign,iv2,psfx)
i1=index(callsign,' ')
call unpackgrid(n2/128,grid)
ntype=iand(n2,127) -64
! Standard WSPR message (types 0 3 7 10 13 17 ... 60)
nu=mod(ntype,10)
if(ntype.ge.0 .and. ntype.le.60 .and. (nu.eq.0 .or. nu.eq.3 .or. &
nu.eq.7)) then
write(cdbm,'(i3)'),ntype
if(cdbm(1:1).eq.' ') cdbm=cdbm(2:)
if(cdbm(1:1).eq.' ') cdbm=cdbm(2:)
message=callsign(1:i1)//grid//' '//cdbm
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1)
! "Best DX" WSPR response (type 1)
else if(ntype.eq.1) then
message=grid//' DE '//callsign
! CQ (msg 3; types 2,4,5)
else if(ntype.eq.2) then
message='CQ '//callsign(:i1)//grid
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1)
else if(ntype.eq.4 .or. ntype.eq.5) then
ng=n2/128 + 32768*(ntype-4)
call unpackpfx(ng,callsign)
message='CQ '//callsign
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1)
! Reply to CQ (msg #2; type 6)
else if(ntype.eq.6) then
ih=(n2-64-ntype)/128
if(dcall(ih)(1:1).ne.' ') then
i2=index(dcall(ih),' ')
message='<'//dcall(ih)(:i2-1)//'> '//callsign(:i1-1)
else
message='<...> '//callsign
endif
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! Reply to CQ (msg #2; type 8)
else if(ntype.eq.8) then
message='DE '//callsign(:i1)//grid
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! Reply to CQ, DE pfx/call (msg #2; types 9, 11)
else if(ntype.eq.9 .or. ntype.eq.11) then
ng=n2/128 + 32768*(ntype-9)/2
call unpackpfx(ng,callsign)
message='DE '//callsign
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! Calls and report (msg #3; types -1 to -9)
else if(ntype.le.-1 .and. ntype.ge.-9) then
write(crpt,1010) -ntype
1010 format('S',i1)
ih=(n2-62-ntype)/128
if(dcall(ih)(1:1).ne.' ') then
i2=index(dcall(ih),' ')
message=callsign(:i1)//'<'//dcall(ih)(:i2-1)//'> '//crpt
else
message=callsign(:i1)//'<...> '//crpt
endif
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! pfx/call and report (msg #3; types -10 to -27)
else if(ntype.le.-10 .and. ntype.ge.-27) then
ng=n2/128
nrpt=-ntype-9
if(ntype.le.-19) then
ng=ng + 32768
nrpt=-ntype-18
endif
write(crpt,1010) nrpt
call unpackpfx(ng,callsign)
message=callsign//' '//crpt
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! Calls and R and report (msg #4; types -28 to -36)
else if(ntype.le.-28 .and. ntype.ge.-36) then
write(crpt,1010) -(ntype+27)
ih=(n2-64+28-ntype)/128
if(dcall(ih)(1:1).ne.' ') then
i2=index(dcall(ih),' ')
message=callsign(:i1)//'<'//dcall(ih)(:i2-1)//'> '//'R '//crpt
else
message=callsign(:i1)//'<...> '//'R '//crpt
endif
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! pfx/call R and report (msg #4; types -37 to -54)
else if(ntype.le.-37 .and. ntype.ge.-54) then
ng=n2/128
nrpt=-ntype-36
if(ntype.le.-46) then
ng=ng + 32768
nrpt=-ntype-45
endif
write(crpt,1010) nrpt
call unpackpfx(ng,callsign)
message=callsign//' R '//crpt
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! Calls and RRR (msg#5; type 12)
else if(ntype.eq.12) then
ih=(n2-64+28-ntype)/128
if(dcall(ih)(1:1).ne.' ') then
i2=index(dcall(ih),' ')
message=callsign(:i1)//'<'//dcall(ih)(:i2-1)//'> RRR'
else
message=callsign(:i1)//'<...> RRR'
endif
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! Calls and RRR (msg#5; type 14)
else if(ntype.eq.14) then
ih=(n2-64+28-ntype)/128
if(dcall(ih)(1:1).ne.' ') then
i2=index(dcall(ih),' ')
message='<'//dcall(ih)(:i2-1)//'> '//callsign(:i1)//'RRR'
else
message='<...> '//callsign(:i1)//' RRR'
endif
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! DE pfx/call and RRR (msg#5; types 15, 16)
else if(ntype.eq.15 .or. ntype.eq.16) then
ng=n2/128 + 32768*(ntype-15)
call unpackpfx(ng,callsign)
message='DE '//callsign//' RRR'
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! TNX [name] 73 GL (msg #6; type 18)
else if(ntype.eq.18) then
ng=(n2-18-64)/128
call unpackname(n1,ng,name,len)
message='TNX '//name(:len)//' 73 GL'
! OP [name] 73 GL (msg #6; type 18)
else if(ntype.eq.-56) then
ng=(n2+56-64)/128
call unpackname(n1,ng,name,len)
message='OP '//name(:len)//' 73 GL'
! 73 DE [call] [grid] (msg #6; type 19)
else if(ntype.eq.19) then
ng=(n2-19-64)/128
message='73 DE '//callsign(:i1)//grid
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! 73 DE pfx/call (msg #6; type 21, 22)
else if(ntype.eq.21 .or. ntype.eq.22) then
ng=n2/128 + (ntype-21)*32768
call unpackpfx(ng,callsign)
i1=index(callsign,' ')
message='73 DE '//callsign
call hash(callsign,i1-1,ih)
dcall(ih)=callsign(:i1-1)
! [power] W [gain] DBD 73 GL (msg#6; type 24, 25)
else if(ntype.eq.24 .or. ntype.eq.25) then
ng=(n2-24-64)/128 - 32
i1=1
if(n1.gt.0) i1=log10(float(n1)) + 1
i2=1
if(ng.ge.10) i2=2
if(ng.lt.0) i2=i2+1
if(n1.le.3000) then
if(ntype.eq.24) fmt="(i4,' W ',i2,' DBD 73 GL')"
if(ntype.eq.25) fmt="(i4,' W ',i2,' DBD ')"
fmt(3:3)=char(48+i1)
fmt(12:12)=char(48+i2)
if(ng.le.100) then
write(message,fmt) n1,ng
else
if(ng.eq.30000) fmt=fmt(1:8)//"DIPOLE')"
if(ng.eq.30001) fmt=fmt(1:8)//"VERTICAL')"
write(message,fmt) n1
endif
else
mw=n1-3000
if(ntype.eq.24) fmt="('0.',i3.3,' W ',i2,' DBD 73 GL')"
if(ntype.eq.25) fmt="('0.',i3.3,' W ',i2,' DBD ')"
fmt(19:19)=char(48+i2)
if(ng.le.100) then
write(message,fmt) mw,ng
else
if(ng.eq.30000) fmt=fmt(1:15)//"DIPOLE')"
if(ng.eq.30001) fmt=fmt(1:15)//"VERTICAL')"
write(message,fmt) n1
endif
if(index(message,'***').gt.0) go to 700
endif
! QRZ call (msg #3; type 26)
else if(ntype.eq.26) then
ng=(n2-24-64)/128 - 32
message='QRZ '//callsign
! PSE QSY [nnn] KHZ (msg #6; type 28)
else if(ntype.eq.28) then
if(n1.gt.0) i1=log10(float(n1)) + 1
fmt="('PSE QSY ',i2,' KHZ')"
fmt(14:14)=char(48+i1)
write(message,fmt) n1
! WX wx temp C/F wind (msg #6; type 29)
else if(ntype.eq.29) then
nwx=n1/10000
ntemp=mod(n1,10000) - 100
cf=' F '
if(ntemp.gt.800) then
ntemp=ntemp-1000
cf=' C '
endif
n2a=n2/128
if(nwx.ge.1 .and. nwx.le.4 .and. n2a.ge.1 .and. n2a.le.5) then
write(message,1020) cwx(nwx),ntemp,cf,cwind(n2/128)
1020 format('WX ',a6,i3,a3,a7)
else
message='WX'//' (BadMsg)'
endif
! Hexadecimal data (type 62)
else if(ntype.eq.62) then
ng=n2/128
write(message,'(z4.4,z7.7)') ng,n1
! Solar/geomagnetic/ionospheric data (type 63)
else if(ntype.eq.63) then
ih=(n2-64-ntype)/128
if(dcall(ih)(1:1).ne.' ') then
i2=index(dcall(ih),' ')
message='<'//dcall(ih)(:i2-1)//'> '
else
message='<...> '
endif
call unpackprop(n1,k,muf,ccur,cxp)
i2=index(message,'>')
write(message(i2+1:),'(i3,i3)') k,muf
message=message(:i2+7)//ccur//' '//cxp
! [plain text] (msg #6; type -57)
else if(ntype.eq.-57) then
ng=n2/128
call unpacktext2(n1,ng,message)
else
go to 700
endif
go to 750
! message='<Unknown message type>'
700 i1=index(callsign,' ')
if(i1.lt.1) i1=12
message=callsign(:i1)//' (BadMsg)'
750 do i=1,22
if(ichar(message(i:i)).eq.0) message(i:i)=' '
enddo
do i=22,1,-1
if(message(i:i).ne.' ') go to 800
enddo
800 i2=i
do n=1,20
i1=index(message(:i2),' ')
if(i1.le.0) go to 900
message=message(1:i1)//message(i1+2:)
i2=i2-1
enddo
900 return
end subroutine wqdec
@@ -1,119 +0,0 @@
// Status=review
.Main Window:
- Select *JT9+JT65* on the *Mode* menu.
- Toggle the *Tx mode* button to read *Tx JT65*, and set the Tx and Rx
frequencies to 1718 Hz.
- Double-click on *Erase* to clear both text windows.
.Wide Graph Settings:
- *Bins/Pixel* = 7
- *JT65 .... JT9* = 2500
- Adjust the width of the Wide Graph window so that the upper
frequency limit is approximately 4000 Hz.
.Open a Wave File:
- Select *File | Open* and navigate to +...\save\samples\JT9+JT65\130610_2343.wav+.
The waterfall should look something like this:
//.130610_2343.wav Decode
[[X14]]
image::130610_2343-wav-80.png[align="left",alt="Wide Graph Decode 130610_2343"]
The position of the blue marker on the waterfall scale is
set by the spinner control *JT65 nnnn JT9*, where nnnn is an audio
frequency in Hz. In *JT9+JT65* mode the program will automatically
decode JT9 signals only above this frequency. JT65 signals will be
decoded over the full displayed frequency range.
JT9 signals appear in the *Cumulative* spectrum as nearly rectangular
shapes about 16 Hz wide. They have no clearly visible sync tone like
the one at the low-frequency edge of all JT65 signals. By convention
the nominal frequency of both JT9 and JT65 signals is taken to be that
of the lowest tone, at the left edge of its spectrum.
This sample file contains 17 decodable signals — nine in JT65 mode
(flagged with the character # in the decoded text windows), and eight
in JT9 mode (flagged with @). On multi-core computers the decoders
for JT9 and JT65 modes run simultaneously, so their results will be
interspersed. The *Band Activity* window contains all decodes (you
might need to scroll back in the window to see some of them). A
signal at the frequency specified by the green marker is given
decoding priority, and its message is displayed also in the *Rx
Frequency* window.
[[FigDecodes]]
image::decodes.png[align="center"]
- Confirm that mouse-click behavior is similar to that described
earlier, in <<TUT_EX1,Example 1>>. _WSJT-X_ automatically determines
the mode of each JT9 or JT65 message.
TIP: When you double-click on a signal in the waterfall it will be
properly decoded even if on the "`wrong`" side of the *JT65 nnnn JT9*
marker. The Tx mode automatically switches to that of the decoded
signal and the Rx and Tx frequency markers on the waterfall scale
resize themselves accordingly. When selecting a JT65 signal, click on
the sync tone at its left edge.
- Double-click on the waterfall near 815 Hz: a JT65 message
originating from W7VP will be decoded and appear in the *Rx Frequency*
window. Between the *UTC* and *Freq* columns on the decoded text line
you will find *dB*, the measured signal-to-noise ratio, and *DT*, the
signal's time offset in seconds relative to your computer clock.
[width="80%",align="center",cols="^10,2*^8,2*^10,54",options="header"]
|===
|UTC|dB|DT|Freq|Mode|Message
|+2343+|+-7+|+0.3+|+815+|+#+|+KK4DSD W7VP -16+
|===
- Double-click on the waterfall at 3196 Hz. The program will decode a
JT9 message from IZ0MIT:
[width="80%",align="center",cols="^10,2*^8,2*^10,54",options="header"]
|===
|UTC|dB|DT|Freq|Mode|Message
|+2343+|+-7+|+0.3+|+3196+|+@+|+WB8QPG IZ0MIT -11+
|===
- Scroll back in the *Band Activity* window and double-click on the
message `CQ DL7ACA JO40`. The program will set *Tx mode* to JT65 and Tx
and Rx frequencies to that of DL7ACA, 975 Hz. If you had checked
*Double-click on call sets Tx Enable* on the *Setup* menu, the program
would configure itself to start a QSO with DL7ACA.
- Double-click on the decoded JT65 message `CQ TA4A KM37`. The program
will set Tx mode to JT9 and the Rx and Tx frequencies to 3567 Hz. The
program is now configured properly for a JT9 QSO with TA4A.
.Reopen the First Sample File:
- Select *File | Open* and navigate to `...\save\samples\130418_1742.wav`.
Taking full advantage of the wide-band, dual-mode capability of
_WSJT-X_ requires a receiver bandwidth of at least 4 kHz. These
data were recorded with a much narrower Rx bandwidth, roughly 200 to
2400 Hz. If you have no Rx filter wider than about 2.7 kHz, you will
be using data like this. For best viewing, adjust *Bins/Pixel* and the
width of the Wide Graph so that only the active part of the spectrum
shows, say 200 to 2400 Hz. Re-open the example file after any change of
*Bins/Pixel* or Wide Graph width, to refresh the waterfall.
The signals in this file are all JT9 signals. To decode them
automatically in *JT9+JT65* mode youll need to move the *JT65 nnnn JT9*
delimiter down to 1000 Hz or less.
.Waterfall Controls
Now is a good time to experiment with the *Start* control and the
sliders controlling gain and zero-point of the waterfall and spectrum
plots. *Start* determines the frequency displayed at the left side of
the waterfall scale. Sliders set the baseline level and gain for the
waterfall and the several types of spectra. Good starting values
should be close to mid-scale. You might want to uncheck *Flatten*
when adjusting the sliders. Re-open the wave file after each change,
to see the new results.
IMPORTANT: When finished with this Tutorial, dont forget to re-enter
your own callsign as *My Call* on the *Settings | General* tab.
File diff suppressed because it is too large Load Diff