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-08-01 09:24:59 -04:00
|
|
|
decoded,nap,qual,ntrperiod,fmid,w50)
|
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
|
|
|
|
real, intent(in) :: qual
|
|
|
|
integer, intent(in) :: ntrperiod
|
|
|
|
real, intent(in) :: fmid
|
|
|
|
real, intent(in) :: w50
|
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-08-09 11:04:49 -04:00
|
|
|
subroutine decode(this,callback,iwave,nutc,ntrperiod,nsubmode,nfqso, &
|
|
|
|
ntol,ndepth,mycall,hiscall,hisgrid)
|
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)
|
|
|
|
! ndepth Optional decoding level (???)
|
|
|
|
! Output: sent to the callback routine for display to user
|
|
|
|
|
2020-08-01 09:24:59 -04:00
|
|
|
use timer_module, only: timer
|
|
|
|
use packjt
|
|
|
|
use, intrinsic :: iso_c_binding
|
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-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-09 13:16:25 -04:00
|
|
|
integer dat4(12) !Decoded message as 12 6-bit integers
|
|
|
|
logical ltext
|
|
|
|
complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s
|
|
|
|
complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s
|
2020-08-09 11:04:49 -04:00
|
|
|
data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/,nsubmodez/-1/
|
2020-10-09 14:12:34 -04:00
|
|
|
save nc1z,nc2z,ng2z,maxaptypez,nsubmodez
|
2020-08-01 12:13:49 -04:00
|
|
|
|
2020-09-25 12:21:57 -04:00
|
|
|
mode65=2**nsubmode
|
2020-08-08 09:14:12 -04:00
|
|
|
nfft1=ntrperiod*12000
|
|
|
|
nfft2=ntrperiod*6000
|
2020-10-17 13:16:46 -04:00
|
|
|
allocate(dd(NMAX))
|
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
|
|
|
|
npts=ntrperiod*12000
|
|
|
|
baud=12000.0/nsps
|
|
|
|
df1=12000.0/nfft1
|
|
|
|
this%callback => callback
|
|
|
|
if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning
|
2020-08-01 09:24:59 -04:00
|
|
|
|
|
|
|
! Prime the QRA decoder for possible use of AP
|
2020-10-09 14:12:34 -04:00
|
|
|
call packcall(mycall(1:6),nc1,ltext)
|
|
|
|
call packcall(hiscall(1:6),nc2,ltext)
|
|
|
|
call packgrid(hisgrid(1:4),ng2,ltext)
|
|
|
|
b90=20.0 !8 to 25 is OK; not very critical
|
|
|
|
nFadingModel=1
|
2020-08-02 11:15:10 -04:00
|
|
|
|
2020-08-04 11:52:29 -04:00
|
|
|
! AP control could be done differently, but this works well:
|
2020-10-09 14:12:34 -04:00
|
|
|
maxaptype=0
|
2020-10-13 13:49:09 -04:00
|
|
|
! if(ndepth.eq.2) maxaptype=3
|
|
|
|
! if(ndepth.eq.3) maxaptype=5
|
|
|
|
if(ndepth.ge.2) maxaptype=5 !###
|
2020-10-14 11:49:27 -04:00
|
|
|
minsync=-2
|
2020-10-25 13:58:18 -04:00
|
|
|
call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist)
|
2020-10-09 14:12:34 -04:00
|
|
|
|
|
|
|
if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. &
|
|
|
|
maxaptype.ne.maxaptypez) then
|
|
|
|
do naptype=0,maxaptype
|
|
|
|
if(naptype.eq.2 .and. maxaptype.eq.4) cycle
|
|
|
|
call qra64_dec(s3dummy,nc1,nc2,ng2,naptype,1,nSubmode,b90, &
|
|
|
|
nFadingModel,dat4,snr2,irc)
|
|
|
|
enddo
|
|
|
|
nc1z=nc1
|
|
|
|
nc2z=nc2
|
|
|
|
ng2z=ng2
|
|
|
|
maxaptypez=maxaptype
|
|
|
|
endif
|
|
|
|
naptype=maxaptype
|
|
|
|
|
|
|
|
call timer('sync_q65',0)
|
2020-10-25 13:58:18 -04:00
|
|
|
call sync_q65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1)
|
2020-10-09 14:12:34 -04:00
|
|
|
call timer('sync_q65',1)
|
|
|
|
|
2020-10-19 15:24:32 -04:00
|
|
|
irc=-1
|
2020-10-20 22:05:43 -04:00
|
|
|
if(snr1.ge.2.5) then
|
2020-10-22 19:07:21 -04:00
|
|
|
jpk0=(xdt+1.0)*6000 !###
|
|
|
|
if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !###
|
2020-10-19 15:24:32 -04:00
|
|
|
if(jpk0.lt.0) jpk0=0
|
|
|
|
fac=1.0/32767.0
|
|
|
|
dd=fac*iwave
|
|
|
|
nmode=65
|
|
|
|
call ana64(dd,npts,c00)
|
|
|
|
call timer('qraloops',0)
|
2020-10-22 15:56:20 -04:00
|
|
|
call qra_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, &
|
2020-10-19 15:24:32 -04:00
|
|
|
ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4)
|
|
|
|
call timer('qraloops',1)
|
|
|
|
snr2=snr2 + db(6912.0/nsps)
|
|
|
|
endif
|
2020-08-01 09:24:59 -04:00
|
|
|
decoded=' '
|
|
|
|
if(irc.ge.0) then
|
|
|
|
call unpackmsg(dat4,decoded) !Unpack the user message
|
|
|
|
call fmtmsg(decoded,iz)
|
|
|
|
if(index(decoded,"000AAA ").ge.1) then
|
|
|
|
! Suppress a certain type of garbage decode.
|
|
|
|
decoded=' '
|
|
|
|
irc=-1
|
|
|
|
endif
|
|
|
|
nsnr=nint(snr2)
|
2020-08-01 12:13:49 -04:00
|
|
|
call this%callback(nutc,sync,nsnr,xdt,f0,decoded, &
|
|
|
|
irc,qual,ntrperiod,fmid,w50)
|
2020-08-01 09:24:59 -04:00
|
|
|
else
|
2020-10-19 15:24:32 -04:00
|
|
|
nsnr=db(snr1) - 32.0
|
2020-08-01 15:12:37 -04:00
|
|
|
!### TEMPORARY? ###
|
|
|
|
call this%callback(nutc,sync,nsnr,xdt,f0,decoded, &
|
|
|
|
irc,qual,ntrperiod,fmid,w50)
|
|
|
|
!###
|
2020-08-01 09:24:59 -04:00
|
|
|
endif
|
2020-08-01 15:12:37 -04:00
|
|
|
|
2020-08-04 10:49:14 -04:00
|
|
|
! write(61,3061) nutc,irc,xdt,f0,snr1,snr2,trim(decoded)
|
|
|
|
!3061 format(i6.6,i4,4f10.2,2x,a)
|
|
|
|
|
2020-08-01 09:24:59 -04:00
|
|
|
return
|
|
|
|
end subroutine decode
|
|
|
|
|
2020-10-25 13:58:18 -04:00
|
|
|
end module q65_decode
|