Merged master 8748

This commit is contained in:
Jordan Sherer
2018-08-05 11:33:30 -04:00
parent 8f8772f1bd
commit 62899069bf
1222 changed files with 70382 additions and 406763 deletions
@@ -1,283 +0,0 @@
<HTML><HEAD>
<TITLE> Encoding Message Blocks </TITLE>
</HEAD><BODY>
<H1> Encoding Message Blocks </H1>
To use a code to send messages, we must define a mapping from a bit
vector, <B>s</B>, of length <I>K</I>, representing a source message,
to a codeword, <B>x</B>, of length <I>N</I>&gt;<I>K</I>. We will
consider only linear mappings, which can be written in the form
<B>x</B>=<B>G</B><SUP><SMALL>T</SMALL></SUP><B>s</B>, where <B>G</B>
is a <I>generator matrix</I>. For a code with parity check matrix
<B>H</B>, whose codewords satisfy <B>Hx</B>=<B>0</B>, the generator
matrix must satisfy <B>HG</B><SUP><SMALL>T</SMALL></SUP>=<B>0</B>.
This software assumes that the number of rows in the parity check
matrix, <I>M</I>, is equal to <I>N-K</I>, as would normally be the
case.
<P>This software deals only with <I>systematic</I> encodings, in which
the <I>K</I> bits of <B>s</B> are copied unchanged to some subset of
the <I>N</i> bits of <B>x</B> (the <I>message bits</I>), and the
remaining <I>M=N-K</I> <I>check bits</I> of <B>x</B> are then set so
as to make the result a codeword. For a linear code, a systematic
encoding scheme always exists, for some choice of which bits of a
codeword are message bits. It is conventional to rearrange the order
of the bits in a codeword so that the message bits come first. The
first <I>K</I> columns of the <I>K</I> by <I>N</I> generator matrix
will then be the identity matrix.
<P>However, this software does <I>not</I> assume that the message bits
come first, since different encoding methods prefer different
locations for the message bits. Instead, a vector of indexes of where
each message bit is located within a codeword is recorded in a file
along with a representation of the part of the generator matrix that
produces the check bits. More than one such generator matrix file can
be created for a single parity check file, in which the locations of
the message bits may be different. Decoding of a received message
into a codeword (with <A
HREF="decoding.html#decode"><TT>decode</TT></A>) does not depend on
knowing which are the message bits, though this does need to be known
in order to reconstruct the original message (with <A
HREF="decoding.html#extract"><TT>extract</TT></A>).
<P>This software stores representations of generator matrices in files
in a format that is not human-readable (except by using the <A
HREF="#print-gen"><TT>print-gen</TT></A> program). However, these
files <I>are</I> readable on a machine with a different architecture
than they were written on.
<A NAME="gen-rep"><H2>Generator matrix representations</H2></A>
<P>For simplicity of exposition, it will be assumed for the next few
paragraphs that the message bits are located at the <I>end</I> of the
codeword, so a codeword can be divided into <I>M</I> check bits,
<B>c</B>, followed by <I>K</I> message bits, <B>s</B>.
<P>On the above assumption, the parity check matrix, <B>H</B>, can be divided
into an <I>M</I> by <I>M</I> matrix <B>A</B> occupying
the first <I>M</I> columns of <B>H</B> and an <I>M</I> by <I>K</I> matrix
<B>B</B> occupying the remaining columns of <B>H</B>. The requirement that
a codeword, <B>x</B>, satisfy all parity checks (ie, that <B>Hx</B>=<B>0</B>)
can then be written as
<BLOCKQUOTE>
<B>Ac</B> + <B>Bs</B> = <B>0</B>
</BLOCKQUOTE>
Provided that <B>A</B> is non-singular, it follows that
<BLOCKQUOTE>
<B>c</B> = <B>A</B><SUP><SMALL>-1</SMALL></SUP><B>Bs</B>
</BLOCKQUOTE>
<B>A</B> may be singular for some choices of which codeword bits are message
bits, but a choice for which <B>A</B> is non-singular always exists if the
rows of <B>H</B> are linearly independent. It is possible, however, that the
rows of <B>H</B> are not linearly independent (ie, some rows are redundant).
This is an exceptional
and not particularly interesting case, which is mostly ignored in the
descriptions below; see the discussion of <A HREF="dep-H.html">linear
dependence in parity check matrices</A> for the details.
<P>The equation <B>c</B> = <B>A</B><SUP><SMALL>-1</SMALL></SUP><B>Bs</B>
defines what the check bits should be, but actual computation of these
check bits can be done in several ways, three of which are implemented
in this software. Each method involves a different representation of
the generator matrix. (Note that none of these methods involves the
explicit representation of the matrix <B>G</B> mentioned above.)
<P>In the <I>dense representation</I>, the <I>M</I> by <I>K</I> matrix
<B>A</B><SUP><SMALL>-1</SMALL></SUP><B>B</B> is computed, and stored
in a dense format (see the <A HREF="mod2dense.html">dense modulo-2
matrix package</A>). A message is encoded by multiplying the
source bits, <B>s</B>, by this matrix to obtain the required check bits.
<P>In the <I>mixed representation</I>, the <I>M</I> by <I>M</I> matrix
<B>A</B><SUP><SMALL>-1</SMALL></SUP> is computed and stored in a dense
format, and the <I>M</I> by <I>K</I> matrix <B>B</B>, the right
portion of the parity check matrix, is also stored, in a sparse format
(see the <A HREF="mod2sparse.html">sparse modulo-2 matrix package</A>).
To encode a message, the source vector <B>s</B> is first multiplied on
the left by <B>B</B>, an operation which can be done very quickly if
<B>B</B> is sparse (as it will be for LDPC codes). The result is then
multiplied on the left by <B>A</B><SUP><SMALL>-1</SMALL></SUP>. If
<I>M</I>&lt;<I>K</I>, the total time may be less than when using the
dense representation above.
<P>The <I>sparse representation</I> goes further, and avoids
explicitly computing <B>A</B><SUP><SMALL>-1</SMALL></SUP>, which tends
to be dense even if <B>H</B> is sparse. Instead, a <I>LU
decomposition</I> of <B>A</B> is found, consisting of a lower
triangular matrix <B>L</B> and an upper triangular matrix <B>U</B> for
which <B>LU</B>=<B>A</B>. The effect of multiplying <B>Bs</B>=<B>z</B> by
<B>A</B><SUP><SMALL>-1</SMALL></SUP> can then be obtained by
<BLOCKQUOTE>
Solving <B>Ly</B>=<B>z</B> for <B>y</B> using forward substitution.<BR>
Solving <B>Uc</B>=<B>y</B> for <B>c</B> using backward substitution.
</BLOCKQUOTE>
Both of these operations will be fast if <B>L</B> and <B>U</B> are
sparse. Heuristics are used to try to achieve this, by rearranging the
rows and columns of <B>H</B> in the process of selecting <B>A</B> and
finding its LU decomposition.
<P><A NAME="make-gen"><HR><B>make-gen</B>: Make a generator matrix from
a parity check matrix.
<BLOCKQUOTE><PRE>
make-gen <I>pchk-file gen-file method</I>
</PRE>
<BLOCKQUOTE>
where <TT><I>method</I></TT> is one of the following:
<BLOCKQUOTE><PRE>
sparse [ first | mincol | minprod ] [ <I>abandon-num abandon-when</I> ]
dense [ <I>other-gen-file </I> ]
mixed [ <I>other-gen-file </I> ]
</PRE></BLOCKQUOTE>
</BLOCKQUOTE>
</BLOCKQUOTE>
<P>Finds a generator matrix for the code whose parity check matrix is
in <TT><I>pchk-file</I></TT>, and writes a representation of this
generator matrix to <TT><I>gen-file</I></TT>. The remaining arguments
specify what representation of the generator matrix is to be used (see
the <A HREF="#gen-rep">description above</A>), and the method to be
used in finding it. A message regarding the density of 1s in the
resulting representation is displayed on standard error. For a sparse
representation, a smaller number of 1s will produce faster encoding.
<P>All representations include a specification for how the columns of
the parity check matrix should be re-ordered so that the message bits
come last. References to columns of the parity check matrix below
refer to their order after this reordering. For the <I>dense</I> and
<I>mixed</I> representations, an <TT><I>other-gen-file</I></TT> may be
specified, in which case the ordering of columns will be the same as
the ordering stored in that file (which must produce a non-singular
<B>A</B> matrix; redundant rows of <B>H</B> are not allowed with this
option). Otherwise, <TT>make-gen</TT> decides on an appropriate
ordering of columns itself. Note that the column rearrangement is
recorded as part of the representation of the generator matrix; the
parity check matrix as stored in its file is not altered.
<P>The <I>dense</I> representation consists of a dense representation
of the matrix <B>A</B><SUP><SMALL>-1</SMALL></SUP><B>B</B>, where
<B>A</B> is the matrix consisting of the first <I>M</I> columns (after
reordering) of the parity check matrix, and <B>B</B> is the remaining
columns. If <B>H</B> contains redundant rows, there is an additional
reordering of columns of <B>A</B> in order create the same effect as
if the redundant rows came last.
<P>The <I>mixed</I> representation consists of a dense representation
of the matrix <B>A</B><SUP><SMALL>-1</SMALL></SUP>, where <B>A</B> is
the matrix consisting of the first <I>M</I> columns (after reordering)
of the parity check matrix. The remaining columns of the parity check
matrix, making up the matrix <B>B</B>, are also part of the
representation, but are not written to <TT><I>gen-file</I></TT>, since
they can be obtained from <TT><I>pchk-file</I></TT>. As for mixed
representations, an additional reordering of columns of <B>A</B> may
be needed if <B>H</B> has redundant rows.
<P>A <I>sparse</I> representation consists of sparse representations
of the <B>L</B> and <B>U</B> matrices, whose product is <B>A</B>, the
first <I>M</I> columns of the parity check matrix (whose columns and
rows may both have been reordered). The matrix <B>B</B>, consisting
of the remaining columns of the parity check matrix, is also part of
the representation, but it is not written to <TT><I>gen-file</I></TT>,
since it can be obtained from <TT><I>pchk-file</I></TT>.
<P>If a sparse representation is chosen, arguments after
<TT>sparse</TT> specify what heuristic is used when reordering columns
and rows in order to try to make <B>L</B> and <B>U</B> as sparse as
possible. The default if no heuristic is specified is
<TT>minprod</TT>. If the <TT><I>abandon-num</I></TT> and
<TT><I>abandon-when</I></TT> options are given, some information is
discarded in order to speed up the process of finding <B>L</B> and
<B>U</B>, at a possible cost in terms of how good a result is
obtained. For details on these heuristics, see the descriptions of <A
HREF="sparse-LU.html">sparse LU decomposition methods</A>.
<P><B>Example:</B> A dense representation of a generator matrix for the
Hamming code created by the example for <A
HREF="pchk.html#make-pchk"><TT>make-pchk</TT></A> can be created as follows:
<UL><PRE>
<LI>make-gen ham7.pchk ham7.gen dense
Number of 1s per check in Inv(A) X B is 3.0
</PRE></UL>
<P><A NAME="print-gen"><HR><B>print-gen</B>: Print a representation of a
generator matrix.
<BLOCKQUOTE><PRE>
print-gen [ -d ] <I>gen-file</I>
</PRE></BLOCKQUOTE>
<P>Prints in human-readable form the representation of the generator
matrix that is stored in <TT><I>gen-file</I></TT>. The <B>-d</B>
option causes the matrices involved to be printed in a dense format,
even if they are stored in the file in a sparse format. See the <A
HREF="#gen-rep">description above</A> for details of generator matrix
representations. Note that the <B>L</B> matrix for a sparse representation
will be lower triangular only after the rows are rearranged, and the <B>U</B>
matrix will be upper triangular only after the columns are rearranged.
The matrix <B>B</B> that is part of the sparse
and mixed representations is not printed, since it is not stored
in the <TT><I>gen-file</I></TT>, but is rather a subset of columns
of the parity check matrix.
<P><B>Example:</B> The generator matrix for the
Hamming code created by the example for <A
HREF="#make-gen"><TT>make-gen</TT></A> can be printed as follows:
<UL><PRE>
<LI>print-gen ham7.gen
Generator matrix (dense representation):
Column order:
0 1 2 3 4 5 6
Inv(A) X B:
1 1 1 0
1 1 0 1
0 1 1 1
</PRE></UL>
For this example, the columns did not need to be rearranged, and hence the
message bits will be in positions 3, 4, 5, and 6 of a codeword.
<P><A NAME="encode"><HR><B>encode</B>: Encode message blocks as codewords
<BLOCKQUOTE><PRE>
encode [ -f ] <I>pchk-file gen-file source-file encoded-file</I>
</PRE></BLOCKQUOTE>
Encodes message blocks of length <I>K</I>, read from
<TT><I>source-file</I></TT>, as codewords of length <I>N</I>, which
are written to <TT><I>encoded-file</I></TT>, replacing any previous
data in this file. Here, <I>N</I> is the number of columns in the
parity check matrix in <TT><I>pchk-file</I></TT>, and
<I>K</I>=<I>N-M</I>, where <I>M</I> is the number of rows in the
parity check matrix. The generator matrix used, from
<TT><I>gen-file</I></TT>, determines which bits of the codeword are
set to the message bits, and how the remaining check bits are
computed. The generator matrix is created from
<TT><I>pchk-file</I></TT> using <A HREF="#make-gen"><TT>make-gen</TT></A>.
<P>A newline is output at the end of each block written to
<TT><I>encoded-file</I></TT>. Newlines in <TT><I>source-file</I></TT>
are ignored.
<P>If the <B>-f</B> option is given, output to <TT><I>encoded-file</I></TT>
is flushed after each block. This allows one to use encode as a server,
reading blocks to encode from a named pipe, and writing the encoded block
to another named pipe.
<HR>
<A HREF="index.html">Back to index for LDPC software</A>
</BODY></HTML>
@@ -1,126 +0,0 @@
program ft8sim
! Generate simulated data for a 15-second HF/6m mode using 8-FSK.
! Output is saved to a *.wav file.
use wavhdr
include 'ft8_params.f90' !Set various constants
type(hdr) h !Header for .wav file
character arg*12,fname*17,sorm*1
character msg*22,msgsent*22
character*6 mygrid6
logical bcontest
complex c0(0:NMAX-1)
complex c(0:NMAX-1)
integer itone(NN)
integer*1 msgbits(KK)
integer*2 iwave(NMAX) !Generated full-length waveform
data mygrid6/'EM48 '/
! Get command-line argument(s)
nargs=iargc()
if(nargs.ne.8) then
print*,'Usage: ft8sim "message" s|m f0 DT fdop del nfiles snr'
print*,'Example: ft8sim "K1ABC W9XYZ EN37" m 1500.0 0.0 0.1 1.0 10 -18'
print*,'s|m: "s" for single signal at 1500 Hz, "m" for 25 signals'
print*,'f0 is ignored when sorm = m'
print*,'Make nfiles negative to invoke 72-bit contest mode.'
go to 999
endif
call getarg(1,msg) !Message to be transmitted
call getarg(2,sorm) !s for single signal, m for multiple sigs
if(sorm.eq."s") then
print*,"Generating single signal at 1500 Hz."
nsig=1
elseif( sorm.eq."m") then
print*,"Generating 25 signals per file."
nsig=25
else
print*,"sorm parameter must be s (single) or m (multiple)."
goto 999
endif
call getarg(3,arg)
read(arg,*) f0 !Frequency (only used for single-signal)
call getarg(4,arg)
read(arg,*) xdt !Time offset from nominal (s)
call getarg(5,arg)
read(arg,*) fspread !Watterson frequency spread (Hz)
call getarg(6,arg)
read(arg,*) delay !Watterson delay (ms)
call getarg(7,arg)
read(arg,*) nfiles !Number of files
call getarg(8,arg)
read(arg,*) snrdb !SNR_2500
bcontest=nfiles.lt.0
nfiles=abs(nfiles)
twopi=8.0*atan(1.0)
fs=12000.0 !Sample rate (Hz)
dt=1.0/fs !Sample interval (s)
tt=NSPS*dt !Duration of symbols (s)
baud=1.0/tt !Keying rate (baud)
bw=8*baud !Occupied bandwidth (Hz)
txt=NZ*dt !Transmission length (s)
bandwidth_ratio=2500.0/(fs/2.0)
sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb)
if(snrdb.gt.90.0) sig=1.0
txt=NN*NSPS/12000.0
i3bit=0 ! ### TEMPORARY ??? ###
! Source-encode, then get itone()
call genft8(msg,mygrid6,bcontest,i3bit,msgsent,msgbits,itone)
write(*,1000) f0,xdt,txt,snrdb,bw,msgsent
1000 format('f0:',f9.3,' DT:',f6.2,' TxT:',f6.1,' SNR:',f6.1, &
' BW:',f4.1,2x,a22)
write(*,'(28i1,1x,28i1)') msgbits(1:56)
write(*,'(16i1)') msgbits(57:72)
write(*,'(3i1)') msgbits(73:75)
write(*,'(12i1)') msgbits(76:87)
! call sgran()
do ifile=1,nfiles
c=0.
do isig=1,nsig
c0=0.
if(nsig.eq.25) then
f0=(isig+2)*100.0
endif
k=-1 + nint((xdt+0.5+0.01*gran())/dt)
! k=-1 + nint((xdt+0.5)/dt)
phi=0.0
do j=1,NN !Generate complex waveform
dphi=twopi*(f0+itone(j)*baud)*dt
do i=1,NSPS
k=k+1
phi=mod(phi+dphi,twopi)
if(k.ge.0 .and. k.lt.NMAX) c0(k)=cmplx(cos(phi),sin(phi))
enddo
enddo
if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c0,NMAX,fs,delay,fspread)
c=c+sig*c0
enddo
if(snrdb.lt.90) then
do i=0,NMAX-1 !Add gaussian noise at specified SNR
xnoise=gran()
ynoise=gran()
c(i)=c(i) + cmplx(xnoise,ynoise)
enddo
endif
fac=32767.0
rms=100.0
if(snrdb.ge.90.0) iwave(1:NMAX)=nint(fac*real(c))
if(snrdb.lt.90.0) iwave(1:NMAX)=nint(rms*real(c))
h=default_header(12000,NMAX)
write(fname,1102) ifile
1102 format('000000_',i6.6,'.wav')
open(10,file=fname,status='unknown',access='stream')
write(10) h,iwave !Save to *.wav file
close(10)
write(*,1110) ifile,xdt,f0,snrdb,fname
1110 format(i4,f7.2,f8.2,f7.1,2x,a17)
enddo
999 end program ft8sim
@@ -1,163 +0,0 @@
make-ldpc ex-wrong-model.pchk 1000 1800 1 evenboth 3 no4cycle
Eliminated 19 cycles of length four by moving checks within column
make-gen ex-wrong-model.pchk ex-wrong-model.gen dense
Number of 1s per check in Inv(A) X B is 318.6
rand-src ex-wrong-model.src 1 800x1000
encode ex-wrong-model.pchk ex-wrong-model.gen ex-wrong-model.src \
ex-wrong-model.enc
Encoded 1000 blocks, source block size 800, encoded block size 1800
# FIRST SET OF TESTS, TRANSMITTING THROUGH AWGN CHANNEL WITH SIGMA=0.90
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awgn 0.90
Transmitted 1800000 bits
# DECODING WITH CORRECT AWGN NOISE MODEL, SIGMA=0.90
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 910 valid. Average 25.8 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 90, with src errs 89, both 89
Bit error rate (on message bits only): 6.484e-03
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 909 valid. Average 25.7 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 91, with src errs 91, both 91
Bit error rate (on message bits only): 6.540e-03
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 900 valid. Average 27.7 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 100, with src errs 100, both 100
Bit error rate (on message bits only): 7.604e-03
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.40
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.40 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 755 valid. Average 42.3 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 245, with src errs 245, both 245
Bit error rate (on message bits only): 1.884e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 827 valid. Average 34.7 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 173, with src errs 172, both 172
Bit error rate (on message bits only): 1.306e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.50
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 849 valid. Average 31.7 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 151, with src errs 151, both 151
Bit error rate (on message bits only): 1.069e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 855 valid. Average 32.3 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 145, with src errs 145, both 145
Bit error rate (on message bits only): 1.022e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.60
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.60 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 790 valid. Average 40.0 iterations, 13% bit changes
Block counts: tot 1000, with chk errs 210, with src errs 210, both 210
Bit error rate (on message bits only): 1.452e-02
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.65
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.65 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 540 valid. Average 63.3 iterations, 11% bit changes
Block counts: tot 1000, with chk errs 460, with src errs 460, both 460
Bit error rate (on message bits only): 3.247e-02
# SECOND SET OF TESTS, TRANSMITTING THROUGH AWLN CHANNEL WITH WIDTH=0.50
transmit ex-wrong-model.enc ex-wrong-model.rec 1 awln 0.50
Transmitted 1800000 bits
# DECODING WITH CORRECT AWLN NOISE MODEL, WIDTH=0.50
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.50 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 914 valid. Average 25.1 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 86, with src errs 86, both 86
Bit error rate (on message bits only): 6.130e-03
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.55
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.55 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 907 valid. Average 25.6 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 93, with src errs 93, both 93
Bit error rate (on message bits only): 6.474e-03
# DECODING WITH AWLN NOISE MODEL, WIDTH=0.45
decode ex-wrong-model.pchk ex-wrong-model.rec - awln 0.45 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 893 valid. Average 27.5 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 107, with src errs 107, both 107
Bit error rate (on message bits only): 7.744e-03
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.80
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.80 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 702 valid. Average 44.9 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 298, with src errs 298, both 298
Bit error rate (on message bits only): 2.245e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.85
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.85 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 765 valid. Average 39.4 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 235, with src errs 235, both 235
Bit error rate (on message bits only): 1.693e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.90
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.90 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 808 valid. Average 35.7 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 192, with src errs 192, both 192
Bit error rate (on message bits only): 1.374e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=0.95
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 0.95 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 814 valid. Average 34.6 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 186, with src errs 186, both 186
Bit error rate (on message bits only): 1.291e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.00
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.00 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 808 valid. Average 35.6 iterations, 12% bit changes
Block counts: tot 1000, with chk errs 192, with src errs 192, both 192
Bit error rate (on message bits only): 1.320e-02
# DECODING WITH AWGN NOISE MODEL, SIGMA=1.05
decode ex-wrong-model.pchk ex-wrong-model.rec - awgn 1.05 prprp 100 \
| verify ex-wrong-model.pchk - ex-wrong-model.gen ex-wrong-model.src
Decoded 1000 blocks, 771 valid. Average 40.7 iterations, 11% bit changes
Block counts: tot 1000, with chk errs 229, with src errs 228, both 228
Bit error rate (on message bits only): 1.524e-02
@@ -1,310 +0,0 @@
subroutine ft8b(dd0,newdat,nfqso,ndepth,lapon,napwid,lsubtract,iaptype,icand, &
sync0,f1,xdt,apsym,nharderrors,dmin,nbadcrc,iap,ipass,iera,message,xsnr)
use timer_module, only: timer
include 'ft8_params.f90'
parameter(NRECENT=10,NP2=2812)
character message*22,msgsent*22
character*12 recent_calls(NRECENT)
real a(5)
real s1(0:7,ND),s2(0:7,NN)
real ps(0:7)
real rxdata(3*ND),rxdatap(3*ND)
real llr(3*ND),llra(3*ND),llr0(3*ND),llrap(3*ND) !Soft symbols
real dd0(15*12000)
integer*1 decoded(KK),apmask(3*ND),cw(3*ND)
integer*1 msgbits(KK)
integer apsym(KK),rr73(11),cq(28)
integer itone(NN)
integer icos7(0:6),ip(1)
complex cd0(3200)
complex ctwk(32)
complex csymb(32)
logical newdat,lsubtract,lapon
data icos7/2,5,6,0,4,1,3/
data rr73/-1,1,1,1,1,1,1,-1,1,1,-1/
data cq/1,1,1,1,1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,1,1,-1,-1,1/
max_iterations=30
nharderrors=-1
fs2=12000.0/NDOWN
dt2=1.0/fs2
twopi=8.0*atan(1.0)
delfbest=0.
ibest=0
call timer('ft8_down',0)
call ft8_downsample(dd0,newdat,f1,cd0) !Mix f1 to baseband and downsample
call timer('ft8_down',1)
i0=nint((xdt+0.5)*fs2) !Initial guess for start of signal
smax=0.0
do idt=i0-8,i0+8 !Search over +/- one quarter symbol
call sync8d(cd0,idt,ctwk,0,sync)
if(sync.gt.smax) then
smax=sync
ibest=idt
endif
enddo
xdt2=ibest*dt2 !Improved estimate for DT
! Now peak up in frequency
i0=nint(xdt2*fs2)
smax=0.0
do ifr=-5,5 !Search over +/- 2.5 Hz
delf=ifr*0.5
dphi=twopi*delf*dt2
phi=0.0
do i=1,32
ctwk(i)=cmplx(cos(phi),sin(phi))
phi=mod(phi+dphi,twopi)
enddo
call sync8d(cd0,i0,ctwk,1,sync)
if( sync .gt. smax ) then
smax=sync
delfbest=delf
endif
enddo
a=0.0
a(1)=-delfbest
call twkfreq1(cd0,NP2,fs2,a,cd0)
xdt=xdt2
f1=f1+delfbest !Improved estimate of DF
call sync8d(cd0,i0,ctwk,2,sync)
j=0
do k=1,NN
i1=ibest+(k-1)*32
csymb=cmplx(0.0,0.0)
if( i1.ge.1 .and. i1+31 .le. NP2 ) csymb=cd0(i1:i1+31)
call four2a(csymb,32,1,-1,1)
s2(0:7,k)=abs(csymb(1:8))
enddo
! sync quality check
is1=0
is2=0
is3=0
do k=1,7
ip=maxloc(s2(:,k))
if(icos7(k-1).eq.(ip(1)-1)) is1=is1+1
ip=maxloc(s2(:,k+36))
if(icos7(k-1).eq.(ip(1)-1)) is2=is2+1
ip=maxloc(s2(:,k+72))
if(icos7(k-1).eq.(ip(1)-1)) is3=is3+1
enddo
! hard sync sum - max is 21
nsync=is1+is2+is3
if(nsync .le. 6) then ! bail out
nbadcrc=1
return
endif
j=0
do k=1,NN
if(k.le.7) cycle
if(k.ge.37 .and. k.le.43) cycle
if(k.gt.72) cycle
j=j+1
s1(0:7,j)=s2(0:7,k)
enddo
do j=1,ND
ps=s1(0:7,j)
where (ps.gt.0.0) ps=log(ps)
r1=max(ps(1),ps(3),ps(5),ps(7))-max(ps(0),ps(2),ps(4),ps(6))
r2=max(ps(2),ps(3),ps(6),ps(7))-max(ps(0),ps(1),ps(4),ps(5))
r4=max(ps(4),ps(5),ps(6),ps(7))-max(ps(0),ps(1),ps(2),ps(3))
i4=3*j-2
i2=3*j-1
i1=3*j
rxdata(i4)=r4
rxdata(i2)=r2
rxdata(i1)=r1
rxdatap(i4)=r4
rxdatap(i2)=r2
rxdatap(i1)=r1
! When bits 88:115 are set as ap bits, bit 115 lives in symbol 39 along
! with no-ap bits 116 and 117. Take care of metrics for bits 116 and 117.
! if(j.eq.39) then ! take care of bits that live in symbol 39
! if(apsym(28).lt.0) then
! rxdatap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
! rxdatap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
! else
! rxdatap(i2)=max(ps(6),ps(7))-max(ps(4),ps(5))
! rxdatap(i1)=max(ps(5),ps(7))-max(ps(4),ps(6))
! endif
! endif
! When bits 116:143 are set as ap bits, bit 115 lives in symbol 39 along
! with ap bits 116 and 117. Take care of metric for bit 115.
if(j.eq.39) then ! take care of bit 115
iii=2*(apsym(29)+1)/2 + (apsym(30)+1)/2 ! known values of bits 116 & 117
if(iii.eq.0) rxdatap(i4)=ps(4)-ps(0)
if(iii.eq.1) rxdatap(i4)=ps(5)-ps(1)
if(iii.eq.2) rxdatap(i4)=ps(6)-ps(2)
if(iii.eq.3) rxdatap(i4)=ps(7)-ps(3)
endif
! bit 144 lives in symbol 48 and will be 1 if it is set as an ap bit.
! take care of metrics for bits 142 and 143
if(j.eq.48) then ! bit 144 is always 1
rxdatap(i4)=max(ps(5),ps(7))-max(ps(1),ps(3))
rxdatap(i2)=max(ps(3),ps(7))-max(ps(1),ps(5))
endif
! bit 154 lives in symbol 52 and will be 0 if it is set as an ap bit
! take care of metrics for bits 155 and 156
if(j.eq.52) then ! bit 154 will be 0 if it is set as an ap bit.
rxdatap(i2)=max(ps(2),ps(3))-max(ps(0),ps(1))
rxdatap(i1)=max(ps(1),ps(3))-max(ps(0),ps(2))
endif
enddo
rxav=sum(rxdata)/(3.0*ND)
rx2av=sum(rxdata*rxdata)/(3.0*ND)
var=rx2av-rxav*rxav
if( var .gt. 0.0 ) then
rxsig=sqrt(var)
else
rxsig=sqrt(rx2av)
endif
rxdata=rxdata/rxsig
! Let's just assume that rxsig is OK for rxdatap too...
rxdatap=rxdatap/rxsig
ss=0.84
llr0=2.0*rxdata/(ss*ss)
llra=2.0*rxdatap/(ss*ss) ! llr's for use with ap
apmag=4.0
! If DxCall exists, only do "MyCall DxCall ???" for candidates within nfqso +/- napwid
nap=0
if(lapon.and.(iaptype.eq.1 .or. (iaptype.eq.2.and.abs(nfqso-f1).le.napwid))) nap=2
if(lapon.and.iaptype.eq.2.and.abs(nfqso-f1).gt.napwid) nap=1
do iap=0,nap
nera=1
if(iap.eq.0) nera=3
do iera=1,nera
llr=llr0
nblank=0
if(nera.eq.3 .and. iera.eq.1) nblank=0
if(nera.eq.3 .and. iera.eq.2) nblank=24
if(nera.eq.3 .and. iera.eq.3) nblank=48
if(nblank.gt.0) llr(1:nblank)=0.
if(iap.eq.0) then
apmask=0
! apmask(160:162)=1
llrap=llr
! llrap(160:162)=apmag*apsym(73:75)/ss
endif
if(iaptype.eq.1) then
if(iap.eq.1) then ! look for plain CQ
apmask=0
apmask(88:115)=1 ! plain CQ
apmask(144)=1 ! not free text
! apmask(160:162)=1 ! 3 extra bits
llrap=llr
llrap(88:115)=apmag*cq/ss
llrap(116:117)=llra(116:117)
llrap(142:143)=llra(142:143)
llrap(144)=-apmag/ss
! llrap(160:162)=apmag*apsym(73:75)/ss
endif
if(iap.eq.2) then ! look for mycall
apmask=0
apmask(88:115)=1 ! mycall
apmask(144)=1 ! not free text
! apmask(160:162)=1 ! 3 extra bits
llrap=llr
llrap(88:115)=apmag*apsym(1:28)/ss
llrap(116:117)=llra(116:117)
llrap(142:143)=llra(142:143)
llrap(144)=-apmag/ss
! llrap(160:162)=apmag*apsym(73:75)/ss
endif
endif
if(iaptype.eq.2) then
if(iap.eq.1) then ! look for dxcall
apmask=0
! apmask(88:115)=1 ! mycall
apmask(116:143)=1 ! hiscall
apmask(144)=1 ! not free text
! apmask(160:162)=1 ! 3 extra bits
llrap=llr
! llrap(88:143)=apmag*apsym(1:56)/ss
llrap(115)=llra(115)
llrap(116:143)=apmag*apsym(29:56)/ss
llrap(144)=-apmag/ss
! llrap(160:162)=apmag*apsym(73:75)/ss
endif
if(iap.eq.2) then ! look mycall, dxcall
apmask=0
apmask(88:115)=1 ! mycall
apmask(116:143)=1 ! hiscall
apmask(144)=1 ! not free text
! apmask(144:154)=1 ! RRR or 73
! apmask(160:162)=1 ! 3 extra bits
llrap=llr
llrap(88:143)=apmag*apsym(1:56)/ss
llrap(144)=-apmag/ss
! llrap(144:154)=apmag*rr73/ss
! llrap(155:156)=llra(155:156)
! llrap(160:162)=apmag*apsym(73:75)/ss
endif
endif
cw=0
call timer('bpd174 ',0)
call bpdecode174(llrap,apmask,max_iterations,decoded,cw,nharderrors, &
niterations)
call timer('bpd174 ',1)
dmin=0.0
if(ndepth.eq.3 .and. nharderrors.lt.0) then
norder=1
if(abs(nfqso-f1).le.napwid) then
if(iap.eq.0) then
norder=2
else
norder=3
endif
endif
call timer('osd174 ',0)
call osd174(llrap,apmask,norder,decoded,cw,nharderrors,dmin)
call timer('osd174 ',1)
endif
nbadcrc=1
message=' '
xsnr=-99.0
if(count(cw.eq.0).eq.174) cycle !Reject the all-zero codeword
if(any(decoded(75:75).ne.0)) cycle !Reject if any of the 3 extra bits are nonzero
if(nharderrors.ge.0 .and. nharderrors+dmin.lt.60.0 .and. &
.not.(sync.lt.2.0 .and. nharderrors.gt.35) .and. &
.not.(iap.gt.0 .and. nharderrors.gt.39) .and. &
.not.(iera.ge.2 .and. nharderrors.gt.30) &
) then
call chkcrc12a(decoded,nbadcrc)
else
nharderrors=-1
cycle
endif
if(nbadcrc.eq.0) then
call extractmessage174(decoded,message,ncrcflag,recent_calls,nrecent)
call genft8(message,msgsent,msgbits,itone)
if(lsubtract) call subtractft8(dd0,itone,f1,xdt2)
xsig=0.0
xnoi=0.0
do i=1,79
xsig=xsig+s2(itone(i),i)**2
ios=mod(itone(i)+4,7)
xnoi=xnoi+s2(ios,i)**2
enddo
xsnr=0.001
if(xnoi.gt.0 .and. xnoi.lt.xsig) xsnr=xsig/xnoi-1.0
xsnr=10.0*log10(xsnr)-27.0
if(xsnr .lt. -24.0) xsnr=-24.0
return
endif
enddo
enddo
return
end subroutine ft8b