WSJT-X/lib/q65_decode.f90

202 lines
6.4 KiB
Fortran
Raw Normal View History

module q65_decode
2020-08-01 09:24:59 -04:00
2021-01-12 11:28:46 -05:00
type :: q65_decoder
procedure(q65_decode_callback), pointer :: callback
2020-08-01 09:24:59 -04:00
contains
2021-01-12 11:28:46 -05:00
procedure :: decode
end type q65_decoder
2020-08-01 09:24:59 -04:00
2021-01-12 11:28:46 -05:00
abstract interface
2021-01-13 10:55:01 -05:00
subroutine q65_decode_callback (this,nutc,snr1,nsnr,dt,freq, &
2021-01-12 11:28:46 -05:00
decoded,nap,ntrperiod)
import q65_decoder
implicit none
class(q65_decoder), intent(inout) :: this
integer, intent(in) :: nutc
2021-01-13 10:55:01 -05:00
real, intent(in) :: snr1
2021-01-12 11:28:46 -05:00
integer, intent(in) :: nsnr
real, intent(in) :: dt
real, intent(in) :: freq
character(len=37), intent(in) :: decoded
integer, intent(in) :: nap
integer, intent(in) :: ntrperiod
end subroutine q65_decode_callback
end interface
2020-08-01 09:24:59 -04:00
contains
2020-12-24 09:51:02 -05:00
subroutine decode(this,callback,iwave,nutc,ntrperiod,nsubmode,nfqso, &
ntol,ndepth,lclearave,emedelay,mycall,hiscall,hisgrid,nQSOprogress, &
ncontest,lapcqonly)
2020-08-01 09:24:59 -04:00
! Decodes Q65 signals
2020-10-09 13:16:25 -04:00
! Input: iwave Raw data, i*2
! nutc UTC for time-tagging the decode
! ntrperiod T/R sequence length (s)
! nsubmode Tone-spacing indicator, 0-4 for A-E
! nfqso Target signal frequency (Hz)
! ntol Search range around nfqso (Hz)
! ndepth Optional decoding level
2020-10-09 13:16:25 -04:00
! Output: sent to the callback routine for display to user
2020-08-01 09:24:59 -04:00
use timer_module, only: timer
use packjt77
2020-08-01 09:24:59 -04:00
use, intrinsic :: iso_c_binding
use q65 !Shared variables
2020-10-09 13:16:25 -04:00
parameter (NMAX=300*12000) !Max TRperiod is 300 s
class(q65_decoder), intent(inout) :: this
procedure(q65_decode_callback) :: callback
2020-10-09 13:16:25 -04:00
character(len=12) :: mycall, hiscall !Used for AP decoding
2020-08-01 09:24:59 -04:00
character(len=6) :: hisgrid
2020-10-09 13:16:25 -04:00
character*37 decoded !Decoded message
character*77 c77
character*78 c78
integer*2 iwave(NMAX) !Raw data
2020-10-17 13:16:46 -04:00
real, allocatable :: dd(:) !Raw data
integer dat4(13) !Decoded message as 12 6-bit integers
integer apmask1(78),apsymbols1(78)
integer dgen(13)
2020-12-24 09:51:02 -05:00
logical lclearave,lapcqonly,unpk77_success
2020-10-09 13:16:25 -04:00
complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s
complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s
idec=-1
mode65=2**nsubmode
npts=ntrperiod*12000
nfft1=ntrperiod*12000
nfft2=ntrperiod*6000
if(lclearave) nsave=0
allocate(dd(npts))
allocate (c00(0:nfft1-1))
allocate (c0(0:nfft1-1))
if(ntrperiod.eq.15) then
nsps=1800
else if(ntrperiod.eq.30) then
nsps=3600
else if(ntrperiod.eq.60) then
nsps=7200
else if(ntrperiod.eq.120) then
nsps=16000
else if(ntrperiod.eq.300) then
nsps=41472
else
2020-10-09 14:12:34 -04:00
stop 'Invalid TR period'
endif
2020-10-09 14:12:34 -04:00
baud=12000.0/nsps
df1=12000.0/nfft1
this%callback => callback
2020-10-09 14:12:34 -04:00
nFadingModel=1
ibwa=max(1,int(1.8*log(baud*mode65)) + 2)
ibwb=min(10,ibwa+4)
if(iand(ndepth,3).eq.3) then
ibwa=max(1,ibwa-1)
ibwb=min(10,ibwb+1)
endif
! Set up the codewords for full-AP list decoding
call q65_set_list(mycall,hiscall,hisgrid,codewords,ncw)
2020-11-30 09:52:47 -05:00
dgen=0
call q65_enc(dgen,codewords) !Initialize the Q65 codec
2020-10-09 14:12:34 -04:00
call timer('sync_q65',0)
2021-01-13 11:07:20 -05:00
call q65_sync(nutc,iwave,ntrperiod,mode65, &
nfqso,ntol,ndepth,lclearave,emedelay,xdt,f0,snr1,width,dat4, &
snr2,idec)
2020-10-09 14:12:34 -04:00
call timer('sync_q65',1)
if(idec.ge.0) then
xdt1=xdt !We have a list-decode result
2020-11-30 09:52:47 -05:00
f1=f0
go to 100
2020-11-30 09:52:47 -05:00
endif
if(snr1.lt.2.8) then
xdt1=0. !No reliable sync, abandon decoding attempt
f1=0.
go to 100
endif
jpk0=(xdt+1.0)*6000 !Index of nominal start of signal
if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !For shortest sequences
if(jpk0.lt.0) jpk0=0
fac=1.0/32767.0
dd=fac*iwave(1:npts)
call ana64(dd,npts,c00) !Convert to complex c00() at 6000 Sa/s
! Generate ap symbols as in FT8
call ft8apset(mycall,hiscall,ncontest,apsym0,aph10)
where(apsym0.eq.-1) apsym0=0
! Main decoding loop starts here
npasses=2
if(nQSOprogress.eq.5) npasses=3
if(lapcqonly) npasses=1
iaptype=0
do ipass=0,npasses
apmask=0 !Try first with no AP information
apsymbols=0
if(ipass.ge.1) then
! Subsequent passes use AP information appropiate for nQSOprogress
call q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,iaptype, &
apsym0,apmask1,apsymbols1)
write(c78,1050) apmask1
1050 format(78i1)
read(c78,1060) apmask
1060 format(13b6.6)
write(c78,1050) apsymbols1
read(c78,1060) apsymbols
endif
call timer('q65loops',0)
2020-12-28 18:53:13 -05:00
call q65_loops(c00,npts/2,nsps/2,mode65,nsubmode,ndepth,jpk0, &
xdt,f0,iaptype,xdt1,f1,snr2,dat4,idec)
call timer('q65loops',1)
if(idec.gt.0) go to 100 !Successful decode, we're done
enddo
! There was no single-transmission decode.
if(iand(ndepth,16).eq.16) then
2021-01-09 11:02:54 -05:00
! Try for an average decode.
call timer('q65_avg2',0)
! call q65_avg2(ntrperiod,baud,nsubmode,nQSOprogress,lapcqonly, &
! codewords,ncw,xdt,f0,snr2,dat4,idec)
2021-01-09 11:02:54 -05:00
call timer('q65_avg2',1)
endif
2020-12-28 18:53:13 -05:00
100 decoded=' '
if(idec.gt.0) then
! ------------------------------------------------------
! idec Meaning
! ------------------------------------------------------
! -1: No decode
! 1: Decode with AP for "MyCall DxCall ?"
! 2: Decode without AP information
! 3: Decode with AP for "CQ ? ?"
! 4: Decode with AP for "MyCall ? ?"
! ------------------------------------------------------
! Second digit (if any) is number of sequences averaged.
! ------------------------------------------------------
! Unpack decoded message for display to user
write(c77,1000) dat4(1:12),dat4(13)/2
1000 format(12b6.6,b5.5)
call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent
2020-08-01 09:24:59 -04:00
nsnr=nint(snr2)
2021-01-13 10:55:01 -05:00
call this%callback(nutc,snr1,nsnr,xdt1,f1,decoded,idec,ntrperiod)
call q65_clravg
2020-08-01 09:24:59 -04:00
else
2021-01-13 10:55:01 -05:00
! Report snr1, even if no decode.
nsnr=db(snr1) - 35.0
idec=-1
2021-01-13 10:55:01 -05:00
call this%callback(nutc,snr1,nsnr,xdt1,f1,decoded, &
idec,ntrperiod)
2020-08-01 09:24:59 -04:00
endif
2020-08-01 09:24:59 -04:00
return
end subroutine decode
end module q65_decode