2020-10-25 13:58:18 -04:00
|
|
|
module q65_decode
|
2020-08-01 09:24:59 -04:00
|
|
|
|
2020-10-25 13:58:18 -04:00
|
|
|
type :: q65_decoder
|
|
|
|
procedure(q65_decode_callback), pointer :: callback
|
2020-08-01 09:24:59 -04:00
|
|
|
contains
|
|
|
|
procedure :: decode
|
2020-10-25 13:58:18 -04:00
|
|
|
end type q65_decoder
|
2020-08-01 09:24:59 -04:00
|
|
|
|
|
|
|
abstract interface
|
2020-10-25 13:58:18 -04:00
|
|
|
subroutine q65_decode_callback (this,nutc,sync,nsnr,dt,freq, &
|
2020-11-30 13:14:18 -05:00
|
|
|
decoded,nap,ntrperiod)
|
2020-10-25 13:58:18 -04:00
|
|
|
import q65_decoder
|
2020-08-01 09:24:59 -04:00
|
|
|
implicit none
|
2020-10-25 13:58:18 -04:00
|
|
|
class(q65_decoder), intent(inout) :: this
|
2020-08-01 09:24:59 -04:00
|
|
|
integer, intent(in) :: nutc
|
|
|
|
real, intent(in) :: sync
|
|
|
|
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
|
2020-10-25 13:58:18 -04:00
|
|
|
end subroutine q65_decode_callback
|
2020-08-01 09:24:59 -04:00
|
|
|
end interface
|
|
|
|
|
|
|
|
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
|
|
|
|
2020-10-25 13:58:18 -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)
|
2020-11-11 11:14:02 -05:00
|
|
|
! 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
|
2020-10-27 13:08:07 -04:00
|
|
|
use packjt77
|
2020-08-01 09:24:59 -04:00
|
|
|
use, intrinsic :: iso_c_binding
|
2020-12-28 15:27:10 -05:00
|
|
|
use q65 !Shared variables
|
2020-12-27 15:27:26 -05:00
|
|
|
|
2020-10-09 13:16:25 -04:00
|
|
|
parameter (NMAX=300*12000) !Max TRperiod is 300 s
|
2020-10-25 13:58:18 -04:00
|
|
|
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
|
2020-10-27 13:08:07 -04:00
|
|
|
character*77 c77
|
2020-10-30 11:07:44 -04:00
|
|
|
character*78 c78
|
2020-08-08 09:14:12 -04:00
|
|
|
integer*2 iwave(NMAX) !Raw data
|
2020-10-17 13:16:46 -04:00
|
|
|
real, allocatable :: dd(:) !Raw data
|
2020-10-27 13:22:02 -04:00
|
|
|
integer dat4(13) !Decoded message as 12 6-bit integers
|
2020-10-30 11:07:44 -04:00
|
|
|
integer apsym0(58),aph10(10)
|
|
|
|
integer apmask1(78),apsymbols1(78)
|
2020-11-22 13:58:29 -05:00
|
|
|
integer dgen(13)
|
2020-12-15 11:03:06 -05:00
|
|
|
integer codewords(63,206)
|
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
|
2020-08-01 12:13:49 -04:00
|
|
|
|
2020-11-30 13:14:18 -05:00
|
|
|
id1=0
|
|
|
|
id2=0
|
2020-09-25 12:21:57 -04:00
|
|
|
mode65=2**nsubmode
|
2020-11-15 12:21:08 -05:00
|
|
|
npts=ntrperiod*12000
|
2020-08-08 09:14:12 -04:00
|
|
|
nfft1=ntrperiod*12000
|
|
|
|
nfft2=ntrperiod*6000
|
2020-11-15 12:21:08 -05:00
|
|
|
allocate(dd(npts))
|
2020-10-08 16:48:11 -04:00
|
|
|
allocate (c00(0:nfft1-1))
|
2020-08-08 13:57:24 -04:00
|
|
|
allocate (c0(0:nfft1-1))
|
2020-08-09 11:04:49 -04:00
|
|
|
|
2020-08-08 09:14:12 -04:00
|
|
|
if(ntrperiod.eq.15) then
|
|
|
|
nsps=1800
|
|
|
|
else if(ntrperiod.eq.30) then
|
|
|
|
nsps=3600
|
|
|
|
else if(ntrperiod.eq.60) then
|
2020-10-25 14:10:38 -04:00
|
|
|
nsps=7200
|
2020-08-08 09:14:12 -04:00
|
|
|
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
|
|
|
|
baud=12000.0/nsps
|
|
|
|
df1=12000.0/nfft1
|
2020-10-29 10:53:30 -04:00
|
|
|
this%callback => callback
|
2020-10-09 14:12:34 -04:00
|
|
|
nFadingModel=1
|
2020-12-28 15:27:10 -05:00
|
|
|
! 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
|
2020-12-28 15:27:10 -05:00
|
|
|
call q65_enc(dgen,codewords) !Initialize the Q65 codec
|
2020-10-09 14:12:34 -04:00
|
|
|
call timer('sync_q65',0)
|
2020-12-28 15:27:10 -05:00
|
|
|
call q65_sync(nutc,iwave,ntrperiod,mode65,codewords,ncw,nsps, &
|
|
|
|
nfqso,ntol,ndepth,lclearave,emedelay,xdt,f0,snr1,width,dat4, &
|
2020-12-29 16:41:48 -05:00
|
|
|
snr2,idec)
|
2020-10-09 14:12:34 -04:00
|
|
|
call timer('sync_q65',1)
|
2020-12-29 16:41:48 -05:00
|
|
|
if(idec.ge.0) then
|
2020-12-28 15:27:10 -05:00
|
|
|
xdt1=xdt !We have a list-decode result
|
2020-11-30 09:52:47 -05:00
|
|
|
f1=f0
|
2020-12-29 16:41:48 -05:00
|
|
|
go to 100
|
2020-11-30 09:52:47 -05:00
|
|
|
endif
|
|
|
|
|
2020-12-21 15:59:33 -05:00
|
|
|
if(snr1.lt.2.8) then
|
2020-12-28 15:27:10 -05:00
|
|
|
xdt1=0. !No reliable sync, abandon decoding attempt
|
2020-12-21 15:59:33 -05:00
|
|
|
f1=0.
|
|
|
|
go to 100
|
|
|
|
endif
|
2020-12-28 15:27:10 -05:00
|
|
|
|
|
|
|
jpk0=(xdt+1.0)*6000 !Index of nominal start of signal
|
|
|
|
if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !For shortest sequences
|
2020-10-30 11:07:44 -04:00
|
|
|
if(jpk0.lt.0) jpk0=0
|
|
|
|
fac=1.0/32767.0
|
2020-11-15 12:21:08 -05:00
|
|
|
dd=fac*iwave(1:npts)
|
2020-12-28 15:27:10 -05:00
|
|
|
call ana64(dd,npts,c00) !Convert to complex c00() at 6000 Sa/s
|
|
|
|
|
|
|
|
! Generate ap symbols as in FT8
|
2020-10-30 11:07:44 -04:00
|
|
|
call ft8apset(mycall,hiscall,ncontest,apsym0,aph10)
|
|
|
|
where(apsym0.eq.-1) apsym0=0
|
|
|
|
|
2020-12-28 15:27:10 -05:00
|
|
|
! Main decoding loop starts here
|
2020-10-30 11:07:44 -04:00
|
|
|
npasses=2
|
|
|
|
if(nQSOprogress.eq.5) npasses=3
|
|
|
|
if(lapcqonly) npasses=1
|
2020-11-11 15:06:24 -05:00
|
|
|
iaptype=0
|
2020-10-30 11:07:44 -04:00
|
|
|
do ipass=0,npasses
|
2020-12-28 15:27:10 -05:00
|
|
|
apmask=0 !Try first with no AP information
|
2020-10-30 11:07:44 -04:00
|
|
|
apsymbols=0
|
2020-12-28 15:27:10 -05:00
|
|
|
|
2020-10-30 11:07:44 -04:00
|
|
|
if(ipass.ge.1) then
|
2020-12-28 15:27:10 -05:00
|
|
|
! Subsequent passes use AP information appropiate for nQSOprogress
|
2020-11-11 15:06:24 -05:00
|
|
|
call q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,iaptype, &
|
|
|
|
apsym0,apmask1,apsymbols1)
|
2020-10-30 11:07:44 -04:00
|
|
|
write(c78,1050) apmask1
|
|
|
|
1050 format(78i1)
|
|
|
|
read(c78,1060) apmask
|
|
|
|
1060 format(13b6.6)
|
|
|
|
write(c78,1050) apsymbols1
|
|
|
|
read(c78,1060) apsymbols
|
2020-11-22 13:58:29 -05:00
|
|
|
if(iaptype.eq.4) then
|
|
|
|
do j=1,3
|
|
|
|
ng15=32401+j
|
|
|
|
write(c78(60:74),'(b15.15)') ng15
|
|
|
|
read(c78,1060) dgen
|
|
|
|
call q65_enc(dgen,codewords(1,j))
|
|
|
|
enddo
|
|
|
|
endif
|
2020-10-30 11:07:44 -04:00
|
|
|
endif
|
2020-12-28 15:27:10 -05:00
|
|
|
|
2020-10-27 13:08:07 -04:00
|
|
|
call timer('q65loops',0)
|
2020-12-28 18:53:13 -05:00
|
|
|
call q65_loops(c00,npts/2,nsps/2,mode65,nsubmode,ndepth,jpk0, &
|
2020-12-29 16:41:48 -05:00
|
|
|
xdt,f0,width,iaptype,xdt1,f1,snr2,dat4,idec)
|
2020-10-27 13:08:07 -04:00
|
|
|
call timer('q65loops',1)
|
2020-12-28 15:27:10 -05:00
|
|
|
if(id2.gt.0) exit !Exit main loop after a successful decode
|
2020-10-30 11:07:44 -04:00
|
|
|
enddo
|
|
|
|
|
2020-12-28 15:27:10 -05:00
|
|
|
! No single-transmission decode.
|
2020-12-29 16:41:48 -05:00
|
|
|
if(iand(ndepth,16).eq.16) then
|
|
|
|
call q65_avg2(nutc,ntrperiod,LL,ntol,lclearave, &
|
|
|
|
baud,nsubmode,ibwa,ibwb,codewords,ncw,xdt,f0,snr1,s3,dat4,idec)
|
|
|
|
endif
|
2020-12-28 18:53:13 -05:00
|
|
|
|
2020-10-30 11:07:44 -04:00
|
|
|
100 decoded=' '
|
2020-12-29 16:41:48 -05:00
|
|
|
if(idec.gt.0) then
|
2020-12-28 15:27:10 -05:00
|
|
|
! Unpack decoded message for display to user
|
2020-11-11 15:06:24 -05:00
|
|
|
write(c77,1000) dat4(1:12),dat4(13)/2
|
2020-10-27 13:08:07 -04:00
|
|
|
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)
|
2020-11-13 13:40:16 -05:00
|
|
|
call this%callback(nutc,sync,nsnr,xdt1,f1,decoded, &
|
2020-11-30 13:14:18 -05:00
|
|
|
idec,ntrperiod)
|
2020-08-01 09:24:59 -04:00
|
|
|
else
|
2020-11-02 15:59:10 -05:00
|
|
|
! Report sync, even if no decode.
|
2020-10-27 16:08:50 -04:00
|
|
|
nsnr=db(snr1) - 35.0
|
2020-11-30 14:13:37 -05:00
|
|
|
idec=-1
|
2020-11-13 13:40:16 -05:00
|
|
|
call this%callback(nutc,sync,nsnr,xdt1,f1,decoded, &
|
2020-11-30 13:14:18 -05:00
|
|
|
idec,ntrperiod)
|
2020-08-01 09:24:59 -04:00
|
|
|
endif
|
2020-08-01 15:12:37 -04:00
|
|
|
|
2020-08-01 09:24:59 -04:00
|
|
|
return
|
|
|
|
end subroutine decode
|
|
|
|
|
2020-10-25 13:58:18 -04:00
|
|
|
end module q65_decode
|