2016-12-17 16:18:47 -05:00
|
|
|
subroutine mskrtd(id2,nutc0,tsec,ntol,nrxfreq,ndepth,mycall,mygrid,hiscall, &
|
2018-07-10 15:09:42 -04:00
|
|
|
bshmsg,btrain,pcoeffs,bswl,datadir,line)
|
2016-09-20 12:35:00 -04:00
|
|
|
|
|
|
|
! Real-time decoder for MSK144.
|
|
|
|
! Analysis block size = NZ = 7168 samples, t_block = 0.597333 s
|
|
|
|
! Called from hspec() at half-block increments, about 0.3 s
|
|
|
|
|
2018-09-24 16:10:57 -04:00
|
|
|
use packjt77
|
|
|
|
|
2016-09-20 12:35:00 -04:00
|
|
|
parameter (NZ=7168) !Block size
|
|
|
|
parameter (NSPM=864) !Number of samples per message frame
|
|
|
|
parameter (NFFT1=8192) !FFT size for making analytic signal
|
2016-09-22 15:42:05 -04:00
|
|
|
parameter (NPATTERNS=4) !Number of frame averaging patterns to try
|
2017-01-04 22:35:33 -05:00
|
|
|
parameter (NSHMEM=50) !Number of recent SWL messages to remember
|
2016-09-20 12:35:00 -04:00
|
|
|
|
2017-07-09 20:01:20 -04:00
|
|
|
character*4 decsym !"&" for mskspd or "^" for long averages
|
2018-07-07 11:35:59 -04:00
|
|
|
character*37 msgreceived !Decoded message
|
2018-10-05 21:56:22 -04:00
|
|
|
character*37 msglast,msglastswl !Used for dupechecking
|
2016-09-20 12:35:00 -04:00
|
|
|
character*80 line !Formatted line with UTC dB T Freq Msg
|
2016-10-04 10:01:02 -04:00
|
|
|
character*12 mycall,hiscall
|
2016-12-17 16:18:47 -05:00
|
|
|
character*6 mygrid
|
2018-09-24 13:31:17 -04:00
|
|
|
character*37 recent_shmsgs(NSHMEM)
|
2017-01-21 22:20:46 -05:00
|
|
|
character*512 datadir
|
2016-09-20 12:35:00 -04:00
|
|
|
|
|
|
|
complex cdat(NFFT1) !Analytic signal
|
|
|
|
complex c(NSPM) !Coherently averaged complex data
|
|
|
|
complex ct(NSPM)
|
|
|
|
|
2016-09-21 20:03:44 -04:00
|
|
|
integer*2 id2(NZ) !Raw 16-bit data
|
|
|
|
integer iavmask(8)
|
2016-09-22 15:42:05 -04:00
|
|
|
integer iavpatterns(8,NPATTERNS)
|
|
|
|
integer npkloc(10)
|
2018-09-24 16:10:57 -04:00
|
|
|
integer nhasharray(MAXRECENT,MAXRECENT)
|
2017-01-04 21:26:55 -05:00
|
|
|
integer nsnrlast,nsnrlastswl
|
2016-09-20 12:35:00 -04:00
|
|
|
|
|
|
|
real d(NFFT1)
|
2016-09-24 20:16:29 -04:00
|
|
|
real pow(8)
|
2016-12-19 22:01:43 -05:00
|
|
|
real softbits(144)
|
2016-09-22 15:42:05 -04:00
|
|
|
real xmc(NPATTERNS)
|
2017-02-23 11:21:26 -05:00
|
|
|
real*8 pcoeffs(5)
|
2016-10-04 10:01:02 -04:00
|
|
|
|
2018-07-10 15:09:42 -04:00
|
|
|
logical*1 bshmsg,btrain,bswl
|
2017-01-01 11:34:20 -05:00
|
|
|
logical*1 first
|
|
|
|
logical*1 bshdecode
|
2017-01-04 21:26:55 -05:00
|
|
|
logical*1 seenb4
|
|
|
|
logical*1 bflag
|
2017-01-15 16:43:40 -05:00
|
|
|
logical*1 bvar
|
2017-01-01 11:34:20 -05:00
|
|
|
|
2016-09-20 12:35:00 -04:00
|
|
|
data first/.true./
|
2016-09-21 20:03:44 -04:00
|
|
|
data iavpatterns/ &
|
2016-09-22 15:42:05 -04:00
|
|
|
1,1,1,1,0,0,0,0, &
|
|
|
|
0,0,1,1,1,1,0,0, &
|
2016-09-21 20:03:44 -04:00
|
|
|
1,1,1,1,1,0,0,0, &
|
|
|
|
1,1,1,1,1,1,1,0/
|
2016-10-04 10:01:02 -04:00
|
|
|
data xmc/2.0,4.5,2.5,3.5/ !Used to set time at center of averaging mask
|
2017-02-20 21:13:13 -05:00
|
|
|
save first,tsec0,nutc00,pnoise,cdat,msglast,msglastswl, &
|
2018-12-20 16:08:29 -05:00
|
|
|
nsnrlast,nsnrlastswl,nhasharray,recent_shmsgs
|
|
|
|
! nsnrlast,nsnrlastswl,nhasharray,recent_shmsgs,mycall13
|
2016-09-20 12:35:00 -04:00
|
|
|
|
|
|
|
if(first) then
|
2016-09-29 10:46:12 -04:00
|
|
|
tsec0=tsec
|
2016-09-22 15:42:05 -04:00
|
|
|
nutc00=nutc0
|
|
|
|
pnoise=-1.0
|
2018-09-24 16:10:57 -04:00
|
|
|
do i=1,MAXRECENT
|
|
|
|
recent_calls(i)(1:13)=' '
|
2016-12-30 21:05:51 -05:00
|
|
|
enddo
|
2017-01-04 21:26:55 -05:00
|
|
|
do i=1,nshmem
|
2018-09-24 13:31:17 -04:00
|
|
|
recent_shmsgs(i)(1:37)=' '
|
2017-01-04 21:26:55 -05:00
|
|
|
enddo
|
2018-09-24 13:31:17 -04:00
|
|
|
msglast=' '
|
|
|
|
msglastswl=' '
|
2017-01-04 21:26:55 -05:00
|
|
|
nsnrlast=-99
|
|
|
|
nsnrlastswl=-99
|
2018-12-20 16:08:29 -05:00
|
|
|
mycall13=mycall//' '
|
|
|
|
dxcall13=hiscall//' '
|
2016-09-24 20:16:29 -04:00
|
|
|
first=.false.
|
2016-09-20 12:35:00 -04:00
|
|
|
endif
|
|
|
|
|
2016-09-24 20:16:29 -04:00
|
|
|
fc=nrxfreq
|
2016-09-23 18:28:11 -04:00
|
|
|
|
2018-12-20 16:08:29 -05:00
|
|
|
! Reset if mycall or dxcall changes
|
|
|
|
if(mycall13(1:12).ne.mycall .or. dxcall13(1:12).ne.hiscall) first=.true.
|
2018-10-06 12:14:57 -04:00
|
|
|
|
2016-12-19 22:01:43 -05:00
|
|
|
! Dupe checking setup
|
2016-09-29 10:46:12 -04:00
|
|
|
if(nutc00.ne.nutc0 .or. tsec.lt.tsec0) then ! reset dupe checker
|
2018-09-24 13:31:17 -04:00
|
|
|
msglast=' '
|
|
|
|
msglastswl=' '
|
2016-09-22 15:42:05 -04:00
|
|
|
nsnrlast=-99
|
2017-01-04 21:26:55 -05:00
|
|
|
nsnrlastswl=-99
|
2016-09-22 15:42:05 -04:00
|
|
|
nutc00=nutc0
|
|
|
|
endif
|
|
|
|
|
|
|
|
tframe=float(NSPM)/12000.0
|
|
|
|
line=char(0)
|
2018-09-24 13:31:17 -04:00
|
|
|
msgreceived=' '
|
2016-09-20 12:35:00 -04:00
|
|
|
max_iterations=10
|
|
|
|
niterations=0
|
|
|
|
d(1:NZ)=id2
|
|
|
|
rms=sqrt(sum(d(1:NZ)*d(1:NZ))/NZ)
|
2016-09-29 10:46:12 -04:00
|
|
|
if(rms.lt.1.0) go to 999
|
2016-09-20 12:35:00 -04:00
|
|
|
fac=1.0/rms
|
|
|
|
d(1:NZ)=fac*d(1:NZ)
|
|
|
|
d(NZ+1:NFFT1)=0.
|
2017-02-20 21:13:13 -05:00
|
|
|
bvar=.true.
|
2017-01-15 16:43:40 -05:00
|
|
|
if( btrain ) bvar=.false. ! if training, turn off rx eq
|
2017-02-21 15:13:36 -05:00
|
|
|
call analytic(d,NZ,NFFT1,cdat,pcoeffs,bvar)
|
2016-09-21 20:03:44 -04:00
|
|
|
|
2016-09-24 20:16:29 -04:00
|
|
|
! Calculate average power for each frame and for the entire block.
|
|
|
|
! If decode is successful, largest power will be taken as signal+noise.
|
|
|
|
! If no decode, entire-block average will be used to update noise estimate.
|
2016-09-22 15:42:05 -04:00
|
|
|
pmax=-99
|
2016-09-24 20:16:29 -04:00
|
|
|
do i=1,8
|
2016-10-12 13:33:49 -04:00
|
|
|
ib=(i-1)*NSPM+1
|
|
|
|
ie=ib+NSPM-1
|
|
|
|
pow(i)=real(dot_product(cdat(ib:ie),cdat(ib:ie)))*rms**2
|
|
|
|
pmax=max(pmax,pow(i))
|
2016-09-22 15:42:05 -04:00
|
|
|
enddo
|
2016-09-24 20:16:29 -04:00
|
|
|
pavg=sum(pow)/8.0
|
2016-09-28 18:13:07 -04:00
|
|
|
|
2016-09-24 20:16:29 -04:00
|
|
|
! Short ping decoder uses squared-signal spectrum to determine where to
|
|
|
|
! center a 3-frame analysis window and attempts to decode each of the
|
|
|
|
! 3 frames along with 2- and 3-frame averages.
|
2016-09-23 18:28:11 -04:00
|
|
|
np=8*NSPM
|
2017-01-04 21:26:55 -05:00
|
|
|
call msk144spd(cdat,np,ntol,ndecodesuccess,msgreceived,fc,fest,tdec,navg,ct, &
|
2018-09-24 16:10:57 -04:00
|
|
|
softbits)
|
2018-10-20 14:55:02 -04:00
|
|
|
bshdecode=.false.
|
2017-01-06 14:01:29 -05:00
|
|
|
if(ndecodesuccess.eq.0 .and. (bshmsg.or.bswl)) then
|
2018-10-05 21:56:22 -04:00
|
|
|
call msk40spd(cdat,np,ntol,mycall,hiscall,bswl,nhasharray, &
|
|
|
|
ndecodesuccess,msgreceived,fc,fest,tdec,navg)
|
2018-10-20 14:55:02 -04:00
|
|
|
if(ndecodesuccess .ge.1) bshdecode=.true.
|
2016-10-03 16:18:53 -04:00
|
|
|
endif
|
2017-01-04 21:26:55 -05:00
|
|
|
if( ndecodesuccess .ge. 1 ) then
|
2016-09-21 20:03:44 -04:00
|
|
|
tdec=tsec+tdec
|
2016-10-03 13:08:02 -04:00
|
|
|
ipk=0
|
|
|
|
is=0
|
2016-09-29 10:46:12 -04:00
|
|
|
goto 900
|
2016-09-21 20:03:44 -04:00
|
|
|
endif
|
2016-09-24 20:16:29 -04:00
|
|
|
|
2016-09-28 18:13:07 -04:00
|
|
|
! If short ping decoder doesn't find a decode,
|
2016-09-29 11:35:45 -04:00
|
|
|
! Fast - short ping decoder only.
|
|
|
|
! Normal - try 4-frame averages
|
2016-09-28 18:13:07 -04:00
|
|
|
! Deep - try 4-, 5- and 7-frame averages.
|
|
|
|
npat=NPATTERNS
|
2016-09-28 23:01:32 -04:00
|
|
|
if( ndepth .eq. 1 ) npat=0
|
|
|
|
if( ndepth .eq. 2 ) npat=2
|
2016-09-28 18:13:07 -04:00
|
|
|
do iavg=1,npat
|
2016-09-21 20:03:44 -04:00
|
|
|
iavmask=iavpatterns(1:8,iavg)
|
|
|
|
navg=sum(iavmask)
|
2016-10-03 13:08:02 -04:00
|
|
|
deltaf=10.0/real(navg) ! search increment for frequency sync
|
2016-09-21 20:03:44 -04:00
|
|
|
npeaks=2
|
2017-01-04 21:26:55 -05:00
|
|
|
call msk144sync(cdat(1:8*NSPM),8,ntol,deltaf,iavmask,npeaks,fc, &
|
2016-10-03 13:08:02 -04:00
|
|
|
fest,npkloc,nsyncsuccess,xmax,c)
|
2016-09-22 15:42:05 -04:00
|
|
|
if( nsyncsuccess .eq. 0 ) cycle
|
2016-09-20 12:35:00 -04:00
|
|
|
|
2016-09-22 15:42:05 -04:00
|
|
|
do ipk=1,npeaks
|
2016-12-22 12:21:23 -05:00
|
|
|
do is=1,3
|
2016-09-22 15:42:05 -04:00
|
|
|
ic0=npkloc(ipk)
|
2016-09-20 12:35:00 -04:00
|
|
|
if(is.eq.2) ic0=max(1,ic0-1)
|
|
|
|
if(is.eq.3) ic0=min(NSPM,ic0+1)
|
|
|
|
ct=cshift(c,ic0-1)
|
2018-09-24 16:10:57 -04:00
|
|
|
call msk144decodeframe(ct,softbits,msgreceived,ndecodesuccess)
|
2016-09-22 15:42:05 -04:00
|
|
|
if(ndecodesuccess .gt. 0) then
|
2016-10-03 13:08:02 -04:00
|
|
|
tdec=tsec+xmc(iavg)*tframe
|
|
|
|
goto 900
|
2016-09-20 12:35:00 -04:00
|
|
|
endif
|
|
|
|
enddo !Slicer dither
|
|
|
|
enddo !Peak loop
|
|
|
|
enddo
|
|
|
|
|
2016-10-03 16:18:53 -04:00
|
|
|
|
2016-09-20 12:35:00 -04:00
|
|
|
msgreceived=' '
|
2016-09-22 15:42:05 -04:00
|
|
|
|
2016-09-23 18:28:11 -04:00
|
|
|
! no decode - update noise level used for calculating displayed snr.
|
2016-09-22 15:42:05 -04:00
|
|
|
if( pnoise .lt. 0 ) then ! initialize noise level
|
|
|
|
pnoise=pavg
|
|
|
|
elseif( pavg .gt. pnoise ) then ! noise level is slow to rise
|
|
|
|
pnoise=0.9*pnoise+0.1*pavg
|
|
|
|
elseif( pavg .lt. pnoise ) then ! and quick to fall
|
|
|
|
pnoise=pavg
|
|
|
|
endif
|
2016-09-29 10:46:12 -04:00
|
|
|
go to 999
|
2016-09-23 18:28:11 -04:00
|
|
|
|
2016-09-29 10:46:12 -04:00
|
|
|
900 continue
|
2016-12-19 22:01:43 -05:00
|
|
|
! Successful decode - estimate snr
|
2016-09-22 15:42:05 -04:00
|
|
|
if( pnoise .gt. 0.0 ) then
|
|
|
|
snr0=10.0*log10(pmax/pnoise-1.0)
|
|
|
|
else
|
|
|
|
snr0=0.0
|
|
|
|
endif
|
|
|
|
nsnr=nint(snr0)
|
|
|
|
|
2017-01-01 11:34:20 -05:00
|
|
|
if(.not. bshdecode) then
|
|
|
|
call msk144signalquality(ct,snr0,fest,tdec,softbits,msgreceived,hiscall, &
|
2017-01-21 22:20:46 -05:00
|
|
|
btrain,datadir,ncorrected,eyeopening,pcoeffs)
|
2017-01-04 21:26:55 -05:00
|
|
|
endif
|
|
|
|
|
2017-07-09 20:01:20 -04:00
|
|
|
decsym=' & '
|
|
|
|
if( btrain ) decsym=' ^ '
|
2018-09-24 13:31:17 -04:00
|
|
|
if( bshdecode ) then
|
2017-01-04 21:26:55 -05:00
|
|
|
ncorrected=0
|
|
|
|
eyeopening=0.0
|
2017-01-01 11:34:20 -05:00
|
|
|
endif
|
2016-12-19 22:01:43 -05:00
|
|
|
|
2017-01-04 21:26:55 -05:00
|
|
|
if( nsnr .lt. -8 ) nsnr=-8
|
|
|
|
if( nsnr .gt. 24 ) nsnr=24
|
|
|
|
|
|
|
|
! Dupe check.
|
|
|
|
bflag=ndecodesuccess.eq.1 .and. &
|
|
|
|
(msgreceived.ne.msglast .or. nsnr.gt.nsnrlast .or. tsec.lt.tsec0)
|
|
|
|
if(bflag) then
|
2016-09-29 10:46:12 -04:00
|
|
|
msglast=msgreceived
|
|
|
|
nsnrlast=nsnr
|
2017-01-01 11:34:20 -05:00
|
|
|
if(.not. bshdecode) then
|
2018-12-20 16:08:29 -05:00
|
|
|
call update_msk40_hasharray(nhasharray)
|
2016-12-17 16:18:47 -05:00
|
|
|
endif
|
2018-09-26 10:02:45 -04:00
|
|
|
write(line,1021) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived,char(0)
|
|
|
|
1021 format(i6.6,i4,f5.1,i5,a4,a37,a1)
|
2017-01-04 21:26:55 -05:00
|
|
|
elseif(bswl .and. ndecodesuccess.ge.2) then
|
|
|
|
seenb4=.false.
|
|
|
|
do i=1,nshmem
|
|
|
|
if( msgreceived .eq. recent_shmsgs(i) ) then
|
|
|
|
seenb4=.true.
|
|
|
|
endif
|
|
|
|
enddo
|
|
|
|
call update_recent_shmsgs(msgreceived,recent_shmsgs,nshmem)
|
|
|
|
bflag=seenb4 .and. &
|
|
|
|
(msgreceived.ne.msglastswl .or. nsnr.gt.nsnrlastswl .or. tsec.lt.tsec0) &
|
|
|
|
.and. nsnr.gt.-6
|
|
|
|
if(bflag) then
|
|
|
|
msglastswl=msgreceived
|
|
|
|
nsnrlastswl=nsnr
|
2018-09-26 10:02:45 -04:00
|
|
|
write(line,1021) nutc0,nsnr,tdec,nint(fest),decsym,msgreceived,char(0)
|
2017-01-04 21:26:55 -05:00
|
|
|
endif
|
2016-09-29 10:46:12 -04:00
|
|
|
endif
|
|
|
|
999 tsec0=tsec
|
|
|
|
|
2016-09-20 12:35:00 -04:00
|
|
|
return
|
|
|
|
end subroutine mskrtd
|
2016-09-23 18:28:11 -04:00
|
|
|
|
2017-01-04 21:26:55 -05:00
|
|
|
subroutine update_recent_shmsgs(message,msgs,nsize)
|
2018-09-24 13:31:17 -04:00
|
|
|
character*37 msgs(nsize)
|
|
|
|
character*37 message
|
2017-01-04 21:26:55 -05:00
|
|
|
logical*1 seen
|
|
|
|
|
|
|
|
seen=.false.
|
|
|
|
do i=1,nsize
|
|
|
|
if( msgs(i) .eq. message ) seen=.true.
|
|
|
|
enddo
|
|
|
|
|
|
|
|
if( .not. seen ) then
|
|
|
|
do i=nsize,2,-1
|
|
|
|
msgs(i)=msgs(i-1)
|
|
|
|
enddo
|
|
|
|
msgs(1)=message
|
|
|
|
endif
|
|
|
|
|
|
|
|
return
|
|
|
|
end subroutine update_recent_shmsgs
|