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 32171f3696
commit fba5846b49
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 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, 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 Convolutional error-control coding (ECC) uses constraint length K=32,
coding uses a convolutional code with constraint length K=16, rate rate r=1/2, and a zero tail, which leads to an encoded message length
r=1/2, and a zero tail, leading to an encoded message length of of (72+31)*2 = 206 bits. Modulation is 9-FSK: 8 tones for data, one
(72+12+15)*2 = 198 bits. Modulation is 9-FSK -- 8 tones for data, and for synchronization. Sixteen symbol intervals are used for
one for a synchronization vector. With 15 symbol intervals used for synchronization, so a transmission requires a total of 207/3 + 16 = 85
synchronization, a transmission requires a total of 198/3 + 15 = 81 channel symbols. Symbol durations tsym are set to approximately
channel symbols. Tone spacing df of the 9-FSK modulation is equal to (TRperiod-10)/85, where TRperiod is the T/R sequence length in
the keying rate; symbol duration tsym = 1/df, and the total occupied seconds. The exact symbol lengths are chosen so as to make nsps, the
bandwidth is 9*df. Transmission length is slightly less than the T/R number of samples at 12000 samples per second, a number rich in
sequence time, to allow for message decoding at time Tdec, a time factors less than 7. This choice makes for efficient FFTs. Tone
Tfree seconds before the next transmission starts. 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 Parameters of the five JT9 sub-modes are summarized in the following
(additive white Gaussian noise) channel. Parameter nsps1 is the number table, along with S/N thresholds measured by simulation on an AWGN
of samples per symbol at sample rate 12000 Hz; nsps is the same (additive white Gaussian noise) channel.
quantity at 750 Hz.
-------------------------------------------------------------------------
------------------------------------------------------------------------ Mode nsps nsps2 df tsym BW S/N* Tdec Tfree Factors
Mode nsps1 nsps df tsym BW S/N* Tdec Tfree Factors 12000 750 (Hz) (s) (Hz) (dB) (s) (s) of nsps
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-1 7168 448 1.674 0.60 15.1 -26.9 51.9 8.1 2^10 7 JT9-2 15360 960 0.781 1.28 7.0 -30.2 112.3 7.7 2^10 3 5
JT9-2 16000 1000 0.750 1.33 6.8 -30.2 111.5 8.5 2^7 5^3 JT9-5 40960 2560 0.293 3.41 2.6 -34.4 293.6 6.4 2^13 5
JT9-5 42336 2646 0.283 3.53 2.5 -34.4 289.4 10.6 2^5 3^3 7^2 JT9-10 82944 5184 0.145 6.91 1.3 -37.5 591.0 9.0 2^10 3^4
JT9-10 86400 5400 0.139 7.20 1.3 -37.5 586.7 13.3 2^7 3^3 5^2 JT9-30 250880 15750 0.048 20.91 0.4 -42.3 1788.5 11.5 2^5 3^2 5^3 7
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.
* Noise power measured in a 2500 Hz bandwidth.
Transmitting
Transmitting ------------
------------ 1. Source encode the structured message to 72 bits
1. Source encode the structured message to 72 bits 2. Convolutionally encode (K=32, r=1/2) to (72+31)*2 = 206 bits
2. Add 12-bit CRC 3. Interleave to scramble the bit order
3. Convolutionally encode (K=16, r=1/2) to (72+12+15)*2 = 198 bits 4. Assemble 3-bit groups to make (206+1)/3 = 69 symbols
4. Interleave to scramble the bit order 5. Gray-code the symbol values
5. Assemble 3-bit groups to make 198/3 = 66 symbols 6. Insert 16 sync symbols ==> 69+15=81 channel symbols, values 0-8
6. Apply Gray code to the symbol values
7. Insert 15 sync symbols ==> 66+15=81 channel symbols with values 0-8
Receiving
---------
Receiving 1. Apply noise blanking with the timf2 method
--------- 2. Filter to 500 Hz bandwidth, downsample (1/16) to 750 Hz complex
1. Apply noise blanking with the timf2 method (FIR filter with 61 taps). Complex data to array c0 (max 1.35M)
2. Filter to 500 Hz bandwidth, downsample (1/16) to 750 Hz complex 3. Compute symbol-length spectra at half-symbol steps. Use for
using FIR filter with 61 taps. Data in array c0(1800*750) (1.35M) waterfalls s(15750) and detecting sync vectors; save in ss(184,15750)
3. Compute symbol-length spectra at half-symbol steps. Use for and savg(15750)
waterfalls s(16384) and save in ss(180,16384), savg(16384) 4. At time Tdec, look for sync vectors in ss(); get estimates of DF, DT
4. At time Tdec, look for sync vectors in ss() to get estimates of DF, DT 5. Do full-length FFTs, NFFT1=96*nsps2
5. Do full-length FFTs of length NFFT1=96*nsps 6. For each candidate signal, do inverse FFT of length 1536. This
6. For each candidate JT9 signal, do inverse FFT of length 1536. This will provide 16 complex samples per symbol, and sync tone should be
gives 16 complex samples per symbol, sync tone should be close to f=0. close to f=0.
7. Use afc65b method to get improved values of DF, DT. 7. Use afc65b method to get improved values of DF, DT.
8. Tweak freq and time offset to 0. 8. Tweak freq and time offset to 0.
9. Compute 8-bin spectra of 66 data symbols: s2(8,66). Re-order the 9. Compute 8-bin spectra of 69 data symbols: s2(8,69). Re-order the
bins by removing Gray code. bins by removing Gray code.
10. Compute soft symbols for 198 bits 10. Compute soft symbols for 206 bits
11. Re-order the bits by removing interleaving. 11. Re-order the bits by removing interleaving.
12. Pack bits into bytes, send to Viterbi decoder ==> 72-bit message, 12. Pack bits into bytes, send to Fano decoder
12-bit CRC, and metric. 13. If Fano succeeds, remove source encoding and display user message.
13. Declare erasure if CRC check fails
14. If CRC is good, 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 ! values in the range 0-8. If lwave is true, also returns a generated
! waveform in iwave(nwave), at 12000 samples per second. ! waveform in iwave(nwave), at 12000 samples per second.
parameter (NMAX=1800*12000) !Max length of wave file parameter (NMAX=1800*12000) !Max length of wave file
character*22 message !Message to be generated character*22 message !Message to be generated
character*22 msgsent !Message as it will be received character*22 msgsent !Message as it will be received
character*3 cok
real*8 dt,phi,f,f0,dfgen,dphi,twopi real*8 dt,phi,f,f0,dfgen,dphi,twopi
integer*2 iwave(NMAX) !Generated wave file 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*4 d0(12) !72-bit message as 6-bit words
integer d2(11) !72+12 bits, as 8-bit words integer*1 d1(72) !72 single bits
integer*1 d3(11) !72+12 bits, as 8-bit bytes integer*4 d2(9) !72 bits as 8-bit words
integer*1 d4(198) !Encoded information-carrying bits integer*1 d3(9) !72 bits as 8-bit bytes
integer*1 d5(198) !Bits from d4, after interleaving integer*1 d4(206) !Encoded information-carrying bits
integer*1 d6(66) !Symbols from d5, values 0-7 integer*1 d5(206) !Bits from d4, after interleaving
integer*1 d7(66) !Gray-coded symbols, values 0-7 integer*4 d6(69) !Symbols from d5, values 0-7
integer*1 d8(81) !Channel symbols including sync, values 0-8 integer*4 d7(69) !Gray-coded symbols, values 0-7
integer*4 d8(85) !Channel symbols including sync, values 0-8
logical lwave logical lwave
integer isync(15) integer isync(85)
data isync/1,6,11,16,21,26,31,39,45,51,57,63,69,75,81/ 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/ data twopi/6.283185307179586476d0/
save save
call chkmsg(message,cok,nspecial,flip)
call packmsg(message,d0) !Pack message into 12 6-bit bytes call packmsg(message,d0) !Pack message into 12 6-bit bytes
d0(11)=0 !### Temporary CRC=0 ### call unpackbits(d0,12,6,d1) !Unpack into 72 bits
d0(12)=0
call unpackbits(d0,14,6,d1) !Unpack into 84 bits nbits=72
nbits=84 nbytes=9
call packbits(d1,nbits,8,d2) !Pack into 11 8-bit words call packbits(d1,nbits,8,d2) !Pack into 9 8-bit words
nbytes=(nbits+7)/8 do i=1,9
do i=1,nbytes
if(d2(i).lt.128) d3(i)=d2(i) if(d2(i).lt.128) d3(i)=d2(i)
if(d2(i).ge.128) d3(i)=d2(i)-256 if(d2(i).ge.128) d3(i)=d2(i)-256
enddo enddo
call enc216(d3,nbits,d4,nsym2,16,2) !Convolutional code, K=16, r=1/2 call encode232(d3,nbytes,d4) !Convolutional code, K=32, r=1/2
! NB: Should give nsym2 = (72+12+15)*2 = 198 nsym2=206
call interleave9(d4,1,d5)
! call interleavejt9(d4,1,d5)
d5=d4 !### TEMP ###
call packbits(d5,nsym2,3,d6) 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 nwave=0
if(lwave) then if(lwave) then
nsps1=0 nsps=0
if(minutes.eq.1) nsps1=7168 if(minutes.eq.1) nsps=6912
if(minutes.eq.2) nsps1=16000 if(minutes.eq.2) nsps=15360
if(minutes.eq.5) nsps1=42336 if(minutes.eq.5) nsps=40960
if(minutes.eq.10) nsps1=86400 if(minutes.eq.10) nsps=82944
if(minutes.eq.30) nsps1=262144 if(minutes.eq.30) nsps=250880
if(nsps1.eq.0) stop 'Bad value for minutes in genjt9.' if(nsps.eq.0) stop 'Bad value for minutes in genjt9.'
! Set up necessary constants ! Set up necessary constants
dt=1.d0/12000.d0 dt=1.d0/12000.d0
f0=1500.d0 f0=1500.d0
dfgen=12000.d0/nsps1 dfgen=12000.d0/nsps
phi=0.d0 phi=0.d0
i=0 i=0
k=0 k=0
do j=1,81 do j=1,85
f=f0 +d7(j)*dfgen f=f0 +d7(j)*dfgen
dphi=twopi*dt*f dphi=twopi*dt*f
do i=1,nsps1 do i=1,nsps
phi=phi+dphi phi=phi+dphi
if(phi.gt.twopi) phi=phi-twopi if(phi.gt.twopi) phi=phi-twopi
xphi=phi xphi=phi
@ -79,9 +88,10 @@ subroutine genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave)
iwave(k)=32767.0*sin(xphi) iwave(k)=32767.0*sin(xphi)
enddo enddo
enddo enddo
nwave=81*nsps1 nwave=85*nsps
endif endif
call unpackmsg(dgen,msgsent)
call unpackmsg(d0,msgsent)
return return
end subroutine genjt9 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) int igray_(int *n0, int *idir)
#endif
{ {
int n; int n;
unsigned long sh; 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 program jt9sim
! Generate simulated data for testing of MAP65 ! Generate simulated data for testing of WSJT-X
parameter (NMAX=1800*12000) parameter (NMAX=1800*12000)
real*4 d4(NMAX) !Floating-point data
integer ihdr(11) integer ihdr(11)
integer*2 id2(NMAX) !i*2 data integer*2 iwave !Generated waveform (no noise)
integer*2 iwave(NMAX) !Generated waveform (no noise) real*8 f0,f,dt,twopi,phi,dphi,baud,fspan
real*8 f0,f,dt,twopi,phi,dphi,baud
character msg0*22,message*22,msgsent*22,arg*8,fname*11 character msg0*22,message*22,msgsent*22,arg*8,fname*11
logical lwave logical lwave
integer*1 d7(81) integer*4 d8(85)
common/acom/dat(NMAX),iwave(NMAX)
nargs=iargc() nargs=iargc()
if(nargs.ne.9) then if(nargs.ne.6) then
print*,'Usage: jt9sim "message" fspan nsigs minutes SNR nfiles' print*,'Usage: jt9sim "message" fspan nsigs minutes SNR nfiles'
print*,'Example: "CQ K1ABC FN42" 200 20 2 -28 1' print*,'Example: "CQ K1ABC FN42" 200 20 2 -28 1'
print*,' ' print*,' '
@ -41,21 +40,21 @@ program jt9sim
fsample=12000.d0 !Sample rate (Hz) fsample=12000.d0 !Sample rate (Hz)
dt=1.d0/fsample !Sample interval (s) dt=1.d0/fsample !Sample interval (s)
twopi=8.d0*atan(1.d0) twopi=8.d0*atan(1.d0)
rad=360.0/twopi
npts=12000*(60*minutes-6) npts=12000*(60*minutes-6)
lwave=.false. lwave=.false.
nsps1=0 nsps=0
if(minutes.eq.1) nsps1=7168 if(minutes.eq.1) nsps=6912
if(minutes.eq.2) nsps1=16000 if(minutes.eq.2) nsps=15360
if(minutes.eq.5) nsps1=42336 if(minutes.eq.5) nsps=40960
if(minutes.eq.10) nsps1=86400 if(minutes.eq.10) nsps=82944
if(minutes.eq.30) nsps1=262144 if(minutes.eq.30) nsps=250880
if(nsps1.eq.0) stop 'Bad value for minutes.' if(nsps.eq.0) stop 'Bad value for minutes.'
ihdr=0 !Temporary ###
open(12,file='msgs.txt',status='old') open(12,file='msgs.txt',status='old')
write(*,1000) write(*,1000)
1000 format('File N freq S/N Message'/ & 1000 format('File N freq S/N Message'/ &
'---------------------------------------------------') '---------------------------------------------------')
do ifile=1,nfiles do ifile=1,nfiles
@ -66,10 +65,14 @@ program jt9sim
1002 format('000000_',2i2.2) 1002 format('000000_',2i2.2)
open(10,file=fname//'.wav',access='stream',status='unknown') 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 if(msg0.ne.' ') then
call genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave) call genjt9(message,minutes,lwave,msgsent,d8,iwave,nwave)
endif endif
rewind 12 rewind 12
@ -78,40 +81,48 @@ program jt9sim
if(msg0.eq.' ') then if(msg0.eq.' ') then
read(12,1004) message read(12,1004) message
1004 format(a22) 1004 format(a22)
call genjt9(message,minutes,lwave,msgsent,d7,iwave,nwave) call genjt9(message,minutes,lwave,msgsent,d8,iwave,nwave)
endif endif
f=1500.d0 f=f0
if(nsigs.gt.1) f=1500.0 - 0.5* fspan + fspan*(isig-1.0)/(nsigs-1.0) if(nsigs.gt.1) f=f0 - 0.5d0*fspan + fspan*(isig-1.d0)/(nsigs-1.d0)
snrdbx=snrdb snrdbx=snrdb
if(snrdb.ge.-1.0) snrdbx=-15.0 - 15.0*(isig-1.0)/nsigs ! 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) sig=sqrt(2500.0/12000.0) * 10.0**(0.05*snrdbx)
write(*,1020) ifile,isig,0.001*f,snrdbx,msgsent write(*,1020) ifile,isig,f,snrdbx,msgsent
1020 format(i3,i4,f8.3,f7.1,2x,a22) 1020 format(i3,i4,f10.3,f7.1,2x,a22)
phi=0. phi=0.
baud=12000.0/nsps1 baud=12000.0/nsps
k=12000 !Start at t = 1 s k=12000 !Start at t = 1 s
do isym=1,81 do isym=1,85
freq=f + d7(isym)*baud freq=f + d8(isym)*baud
dphi=twopi*freq*dt + 0.5*twopi dphi=twopi*freq*dt
do i=1,nsps1 do i=1,nsps
phi=phi + dphi phi=phi + dphi
if(phi.lt.-twopi) phi=phi+twopi if(phi.lt.-twopi) phi=phi+twopi
if(phi.gt.twopi) phi=phi-twopi if(phi.gt.twopi) phi=phi-twopi
xphi=phi xphi=phi
k=k+1 k=k+1
d4(k)=d4(k) + sin(phi) dat(k)=dat(k) + sig*sin(xphi)
enddo enddo
enddo enddo
enddo enddo
do i=1,npts do i=1,npts
id2(i)=nint(rms*d4(i)) iwave(i)=nint(rms*dat(i))
! iwave(i)=nint(100.0*dat(i))
enddo enddo
write(10) ihdr,id2(1:npts) write(10) ihdr,iwave(1:npts)
close(10) close(10)
do i=1,30000
write(71,3001) i,iwave(12000+i)
3001 format(2i8)
enddo
enddo enddo
999 end program jt9sim 999 end program jt9sim

View File

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