Program jt9sim is now basically functional.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@2603 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Joe Taylor 2012-09-28 18:07:07 +00:00
parent 9507a4e8a3
commit 23ab527e4d
8 changed files with 209 additions and 156 deletions

128
jt9.txt
View File

@ -1,65 +1,63 @@
JT9 is a mode designed for amateur QSOs and beacon-like transmissions
at MF and LF. The mode uses the same 72-bit user messages as JT65,
augmented by a 12-bit cyclic redundancy check (CRC). Error-control
coding uses a convolutional code with constraint length K=16, rate
r=1/2, and a zero tail, leading to an encoded message length of
(72+12+15)*2 = 198 bits. Modulation is 9-FSK -- 8 tones for data, and
one for a synchronization vector. With 15 symbol intervals used for
synchronization, a transmission requires a total of 198/3 + 15 = 81
channel symbols. Tone spacing df of the 9-FSK modulation is equal to
the keying rate; symbol duration tsym = 1/df, and the total occupied
bandwidth is 9*df. Transmission length is slightly less than the T/R
sequence time, to allow for message decoding at time Tdec, a time
Tfree seconds before the next transmission starts.
Parameters of the five JT9 sub-modes are summarized in the following
table, along with S/N thresholds measured by simulation on an AWGN
(additive white Gaussian noise) channel. Parameter nsps1 is the number
of samples per symbol at sample rate 12000 Hz; nsps is the same
quantity at 750 Hz.
------------------------------------------------------------------------
Mode nsps1 nsps df tsym BW S/N* Tdec Tfree Factors
12000 750 (Hz) (s) (Hz) (dB) (s) (s) of nsps
------------------------------------------------------------------------
JT9-1 7168 448 1.674 0.60 15.1 -26.9 51.9 8.1 2^10 7
JT9-2 16000 1000 0.750 1.33 6.8 -30.2 111.5 8.5 2^7 5^3
JT9-5 42336 2646 0.283 3.53 2.5 -34.4 289.4 10.6 2^5 3^3 7^2
JT9-10 86400 5400 0.139 7.20 1.3 -37.5 586.7 13.3 2^7 3^3 5^2
JT9-30 262144 16384 0.046 21.85 0.4 -42.3 1773.4 26.6 2^18
------------------------------------------------------------------------
* Noise power measured in a 2500 Hz bandwidth.
Transmitting
------------
1. Source encode the structured message to 72 bits
2. Add 12-bit CRC
3. Convolutionally encode (K=16, r=1/2) to (72+12+15)*2 = 198 bits
4. Interleave to scramble the bit order
5. Assemble 3-bit groups to make 198/3 = 66 symbols
6. Apply Gray code to the symbol values
7. Insert 15 sync symbols ==> 66+15=81 channel symbols with values 0-8
Receiving
---------
1. Apply noise blanking with the timf2 method
2. Filter to 500 Hz bandwidth, downsample (1/16) to 750 Hz complex
using FIR filter with 61 taps. Data in array c0(1800*750) (1.35M)
3. Compute symbol-length spectra at half-symbol steps. Use for
waterfalls s(16384) and save in ss(180,16384), savg(16384)
4. At time Tdec, look for sync vectors in ss() to get estimates of DF, DT
5. Do full-length FFTs of length NFFT1=96*nsps
6. For each candidate JT9 signal, do inverse FFT of length 1536. This
gives 16 complex samples per symbol, sync tone should be close to f=0.
7. Use afc65b method to get improved values of DF, DT.
8. Tweak freq and time offset to 0.
9. Compute 8-bin spectra of 66 data symbols: s2(8,66). Re-order the
bins by removing Gray code.
10. Compute soft symbols for 198 bits
11. Re-order the bits by removing interleaving.
12. Pack bits into bytes, send to Viterbi decoder ==> 72-bit message,
12-bit CRC, and metric.
13. Declare erasure if CRC check fails
14. If CRC is good, remove source encoding and display user message.
JT9 is a mode designed for amateur QSOs and beacon-like transmissions
at MF and LF. The mode uses the same 72-bit user messages as JT65.
Convolutional error-control coding (ECC) uses constraint length K=32,
rate r=1/2, and a zero tail, which leads to an encoded message length
of (72+31)*2 = 206 bits. Modulation is 9-FSK: 8 tones for data, one
for synchronization. Sixteen symbol intervals are used for
synchronization, so a transmission requires a total of 207/3 + 16 = 85
channel symbols. Symbol durations tsym are set to approximately
(TRperiod-10)/85, where TRperiod is the T/R sequence length in
seconds. The exact symbol lengths are chosen so as to make nsps, the
number of samples at 12000 samples per second, a number rich in
factors less than 7. This choice makes for efficient FFTs. Tone
spacing of the 9-FSK modulation is df=1/tsym, the same as the keying
rate. The total occupied bandwidth is 9*df.
Parameters of the five JT9 sub-modes are summarized in the following
table, along with S/N thresholds measured by simulation on an AWGN
(additive white Gaussian noise) channel.
-------------------------------------------------------------------------
Mode nsps nsps2 df tsym BW S/N* Tdec Tfree Factors
12000 750 (Hz) (s) (Hz) (dB) (s) (s) of nsps
-------------------------------------------------------------------------
JT9-1 6912 432 1.736 0.58 15.6 -26.9 52.5 7.5 2^8 3^3
JT9-2 15360 960 0.781 1.28 7.0 -30.2 112.3 7.7 2^10 3 5
JT9-5 40960 2560 0.293 3.41 2.6 -34.4 293.6 6.4 2^13 5
JT9-10 82944 5184 0.145 6.91 1.3 -37.5 591.0 9.0 2^10 3^4
JT9-30 250880 15750 0.048 20.91 0.4 -42.3 1788.5 11.5 2^5 3^2 5^3 7
-------------------------------------------------------------------------
* Noise power measured in a 2500 Hz bandwidth.
Transmitting
------------
1. Source encode the structured message to 72 bits
2. Convolutionally encode (K=32, r=1/2) to (72+31)*2 = 206 bits
3. Interleave to scramble the bit order
4. Assemble 3-bit groups to make (206+1)/3 = 69 symbols
5. Gray-code the symbol values
6. Insert 16 sync symbols ==> 69+15=81 channel symbols, values 0-8
Receiving
---------
1. Apply noise blanking with the timf2 method
2. Filter to 500 Hz bandwidth, downsample (1/16) to 750 Hz complex
(FIR filter with 61 taps). Complex data to array c0 (max 1.35M)
3. Compute symbol-length spectra at half-symbol steps. Use for
waterfalls s(15750) and detecting sync vectors; save in ss(184,15750)
and savg(15750)
4. At time Tdec, look for sync vectors in ss(); get estimates of DF, DT
5. Do full-length FFTs, NFFT1=96*nsps2
6. For each candidate signal, do inverse FFT of length 1536. This
will provide 16 complex samples per symbol, and sync tone should be
close to f=0.
7. Use afc65b method to get improved values of DF, DT.
8. Tweak freq and time offset to 0.
9. Compute 8-bin spectra of 69 data symbols: s2(8,69). Re-order the
bins by removing Gray code.
10. Compute soft symbols for 206 bits
11. Re-order the bits by removing interleaving.
12. Pack bits into bytes, send to Fano decoder
13. If Fano succeeds, remove source encoding and display user message.

View File

@ -1,77 +1,86 @@
subroutine genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave)
subroutine genjt9(message,minutes,lwave,msgsent,d8,iwave,nwave)
! Encodes a "JT9-minutes" message and returns array d7(81) of tone
! Encodes a "JT9-minutes" message and returns array d7(85) of tone
! values in the range 0-8. If lwave is true, also returns a generated
! waveform in iwave(nwave), at 12000 samples per second.
parameter (NMAX=1800*12000) !Max length of wave file
character*22 message !Message to be generated
character*22 msgsent !Message as it will be received
character*3 cok
real*8 dt,phi,f,f0,dfgen,dphi,twopi
integer*2 iwave(NMAX) !Generated wave file
integer d0(14) !72-bit message + 12-bit CRC, as 6-bit bytes
integer*1 d1(84) !72+12 = 84 single bits
integer d2(11) !72+12 bits, as 8-bit words
integer*1 d3(11) !72+12 bits, as 8-bit bytes
integer*1 d4(198) !Encoded information-carrying bits
integer*1 d5(198) !Bits from d4, after interleaving
integer*1 d6(66) !Symbols from d5, values 0-7
integer*1 d7(66) !Gray-coded symbols, values 0-7
integer*1 d8(81) !Channel symbols including sync, values 0-8
integer*4 d0(12) !72-bit message as 6-bit words
integer*1 d1(72) !72 single bits
integer*4 d2(9) !72 bits as 8-bit words
integer*1 d3(9) !72 bits as 8-bit bytes
integer*1 d4(206) !Encoded information-carrying bits
integer*1 d5(206) !Bits from d4, after interleaving
integer*4 d6(69) !Symbols from d5, values 0-7
integer*4 d7(69) !Gray-coded symbols, values 0-7
integer*4 d8(85) !Channel symbols including sync, values 0-8
logical lwave
integer isync(15)
data isync/1,6,11,16,21,26,31,39,45,51,57,63,69,75,81/
integer isync(85)
data isync/ &
1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0, &
1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0, &
0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0, &
0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0, &
1,0,0,0,1/
data twopi/6.283185307179586476d0/
save
call chkmsg(message,cok,nspecial,flip)
call packmsg(message,d0) !Pack message into 12 6-bit bytes
d0(11)=0 !### Temporary CRC=0 ###
d0(12)=0
call unpackbits(d0,14,6,d1) !Unpack into 84 bits
nbits=84
call packbits(d1,nbits,8,d2) !Pack into 11 8-bit words
nbytes=(nbits+7)/8
do i=1,nbytes
call unpackbits(d0,12,6,d1) !Unpack into 72 bits
nbits=72
nbytes=9
call packbits(d1,nbits,8,d2) !Pack into 9 8-bit words
do i=1,9
if(d2(i).lt.128) d3(i)=d2(i)
if(d2(i).ge.128) d3(i)=d2(i)-256
enddo
call enc216(d3,nbits,d4,nsym2,16,2) !Convolutional code, K=16, r=1/2
! NB: Should give nsym2 = (72+12+15)*2 = 198
! call interleavejt9(d4,1,d5)
d5=d4 !### TEMP ###
call encode232(d3,nbytes,d4) !Convolutional code, K=32, r=1/2
nsym2=206
call interleave9(d4,1,d5)
call packbits(d5,nsym2,3,d6)
! call graycode(d6,nsym2,1,d7)
call graycode(d6,69,1,d7)
! Now insert sync symbols and add 1 to the tone numbers.
! Insert sync symbols (ntone=0) and add 1 to the data-tone numbers.
j=0
do i=1,85
if(isync(i).eq.1) then
d8(i)=0
else
j=j+1
d8(i)=d7(j)+1
endif
enddo
nwave=0
if(lwave) then
nsps1=0
if(minutes.eq.1) nsps1=7168
if(minutes.eq.2) nsps1=16000
if(minutes.eq.5) nsps1=42336
if(minutes.eq.10) nsps1=86400
if(minutes.eq.30) nsps1=262144
if(nsps1.eq.0) stop 'Bad value for minutes in genjt9.'
nsps=0
if(minutes.eq.1) nsps=6912
if(minutes.eq.2) nsps=15360
if(minutes.eq.5) nsps=40960
if(minutes.eq.10) nsps=82944
if(minutes.eq.30) nsps=250880
if(nsps.eq.0) stop 'Bad value for minutes in genjt9.'
! Set up necessary constants
dt=1.d0/12000.d0
f0=1500.d0
dfgen=12000.d0/nsps1
dfgen=12000.d0/nsps
phi=0.d0
i=0
k=0
do j=1,81
do j=1,85
f=f0 +d7(j)*dfgen
dphi=twopi*dt*f
do i=1,nsps1
do i=1,nsps
phi=phi+dphi
if(phi.gt.twopi) phi=phi-twopi
xphi=phi
@ -79,9 +88,10 @@ subroutine genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave)
iwave(k)=32767.0*sin(xphi)
enddo
enddo
nwave=81*nsps1
nwave=85*nsps
endif
call unpackmsg(dgen,msgsent)
call unpackmsg(d0,msgsent)
return
end subroutine genjt9

View File

@ -1,10 +0,0 @@
subroutine graycode(dat,n,idir)
integer dat(n)
do i=1,n
dat(i)=igray(dat(i),idir)
enddo
return
end

9
libm65/graycode.f90 Normal file
View File

@ -0,0 +1,9 @@
subroutine graycode(ia,n,idir,ib)
integer ia(n),ib(n)
do i=1,n
ib(i)=igray(ia(i),idir)
enddo
return
end subroutine graycode

View File

@ -1,8 +1,4 @@
#ifdef CVF
extern int __stdcall IGRAY(int *n0, int *idir)
#else
int igray_(int *n0, int *idir)
#endif
{
int n;
unsigned long sh;

39
libm65/interleave9.f90 Normal file
View File

@ -0,0 +1,39 @@
subroutine interleave9(ia,ndir,ib)
integer*1 ia(0:205),ib(0:205)
integer j0(0:205)
logical first
data first/.true./
save first,j0
if(first) then
k=-1
do i=0,255
m=i
n=iand(m,1)
n=2*n + iand(m/2,1)
n=2*n + iand(m/4,1)
n=2*n + iand(m/8,1)
n=2*n + iand(m/16,1)
n=2*n + iand(m/32,1)
n=2*n + iand(m/64,1)
n=2*n + iand(m/128,1)
if(n.le.205) then
k=k+1
j0(k)=n
endif
enddo
! first=.false.
endif
if(ndir.gt.0) then
do i=0,205
ib(j0(i))=ia(i)
enddo
else
do i=0,205
ib(i)=ia(j0(i))
enddo
endif
return
end subroutine interleave9

View File

@ -1,19 +1,18 @@
program jt9sim
! Generate simulated data for testing of MAP65
! Generate simulated data for testing of WSJT-X
parameter (NMAX=1800*12000)
real*4 d4(NMAX) !Floating-point data
integer ihdr(11)
integer*2 id2(NMAX) !i*2 data
integer*2 iwave(NMAX) !Generated waveform (no noise)
real*8 f0,f,dt,twopi,phi,dphi,baud
integer*2 iwave !Generated waveform (no noise)
real*8 f0,f,dt,twopi,phi,dphi,baud,fspan
character msg0*22,message*22,msgsent*22,arg*8,fname*11
logical lwave
integer*1 d7(81)
integer*4 d8(85)
common/acom/dat(NMAX),iwave(NMAX)
nargs=iargc()
if(nargs.ne.9) then
if(nargs.ne.6) then
print*,'Usage: jt9sim "message" fspan nsigs minutes SNR nfiles'
print*,'Example: "CQ K1ABC FN42" 200 20 2 -28 1'
print*,' '
@ -41,21 +40,21 @@ program jt9sim
fsample=12000.d0 !Sample rate (Hz)
dt=1.d0/fsample !Sample interval (s)
twopi=8.d0*atan(1.d0)
rad=360.0/twopi
npts=12000*(60*minutes-6)
lwave=.false.
nsps1=0
if(minutes.eq.1) nsps1=7168
if(minutes.eq.2) nsps1=16000
if(minutes.eq.5) nsps1=42336
if(minutes.eq.10) nsps1=86400
if(minutes.eq.30) nsps1=262144
if(nsps1.eq.0) stop 'Bad value for minutes.'
nsps=0
if(minutes.eq.1) nsps=6912
if(minutes.eq.2) nsps=15360
if(minutes.eq.5) nsps=40960
if(minutes.eq.10) nsps=82944
if(minutes.eq.30) nsps=250880
if(nsps.eq.0) stop 'Bad value for minutes.'
ihdr=0 !Temporary ###
open(12,file='msgs.txt',status='old')
write(*,1000)
1000 format('File N freq S/N Message'/ &
1000 format('File N freq S/N Message'/ &
'---------------------------------------------------')
do ifile=1,nfiles
@ -66,10 +65,14 @@ program jt9sim
1002 format('000000_',2i2.2)
open(10,file=fname//'.wav',access='stream',status='unknown')
call noisegen(d4,npts) !Generate Gaussian noise
if(snrdb.lt.90) then
call noisegen(dat,npts) !Generate Gaussian noise
else
dat(1:npts)=0.
endif
if(msg0.ne.' ') then
call genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave)
call genjt9(message,minutes,lwave,msgsent,d8,iwave,nwave)
endif
rewind 12
@ -78,40 +81,48 @@ program jt9sim
if(msg0.eq.' ') then
read(12,1004) message
1004 format(a22)
call genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave)
call genjt9(message,minutes,lwave,msgsent,d8,iwave,nwave)
endif
f=1500.d0
if(nsigs.gt.1) f=1500.0 - 0.5* fspan + fspan*(isig-1.0)/(nsigs-1.0)
f=f0
if(nsigs.gt.1) f=f0 - 0.5d0*fspan + fspan*(isig-1.d0)/(nsigs-1.d0)
snrdbx=snrdb
if(snrdb.ge.-1.0) snrdbx=-15.0 - 15.0*(isig-1.0)/nsigs
sig=sqrt(2.2*2500.0/96000.0) * 10.0**(0.05*snrdbx)
write(*,1020) ifile,isig,0.001*f,snrdbx,msgsent
1020 format(i3,i4,f8.3,f7.1,2x,a22)
! if(snrdb.ge.-1.0) snrdbx=-15.0 - 15.0*(isig-1.0)/nsigs
sig=sqrt(2500.0/12000.0) * 10.0**(0.05*snrdbx)
write(*,1020) ifile,isig,f,snrdbx,msgsent
1020 format(i3,i4,f10.3,f7.1,2x,a22)
phi=0.
baud=12000.0/nsps1
baud=12000.0/nsps
k=12000 !Start at t = 1 s
do isym=1,81
freq=f + d7(isym)*baud
dphi=twopi*freq*dt + 0.5*twopi
do i=1,nsps1
do isym=1,85
freq=f + d8(isym)*baud
dphi=twopi*freq*dt
do i=1,nsps
phi=phi + dphi
if(phi.lt.-twopi) phi=phi+twopi
if(phi.gt.twopi) phi=phi-twopi
xphi=phi
k=k+1
d4(k)=d4(k) + sin(phi)
dat(k)=dat(k) + sig*sin(xphi)
enddo
enddo
enddo
do i=1,npts
id2(i)=nint(rms*d4(i))
iwave(i)=nint(rms*dat(i))
! iwave(i)=nint(100.0*dat(i))
enddo
write(10) ihdr,id2(1:npts)
write(10) ihdr,iwave(1:npts)
close(10)
do i=1,30000
write(71,3001) i,iwave(12000+i)
3001 format(2i8)
enddo
enddo
999 end program jt9sim

View File

@ -1,4 +1,4 @@
//---------------------------------------------------------------- MainWindow
//--------------------------------------------------------------- MainWindow
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "devsetup.h"