Merge branch 'feat-fst280' into develop

This commit is contained in:
Bill Somerville 2021-02-02 17:59:04 +00:00
commit a1150cca61
No known key found for this signature in database
GPG Key ID: D864B06D1E81618F
15 changed files with 382 additions and 357 deletions

View File

@ -1,50 +1,78 @@
Mode: Q65-30A
Data: 30A_K1JT_6m_Ionoscatter (62 files, DT 0.1 to 0.4)
Data: 30A_K1JT_6m_Ionoscatter (62 files, 6m ionoscatter DT 0.1 to 0.4)
Message: "K1JT K9AN R-16"
RxFreq: 1000/10
Commit No_AP MyCall BothCalls
-----------------------------------
ef4787: 3 10 6 14 30 33
ada5a6: 3 6 6 10 29 36
Commit No_AP MyCall BothCalls
-----------------------------------------------
ef4787: 3 10 6 14 30 33
ada5a6: 3 6 6 10 29 36
10f574: 2 7 97.6 6 10 95.4 21 33 80.7
b8ea4c: 2 7 100.5 6 10 96.9 21 33 81.0
Mode: Q65-30A
Data: 30A_N0AN_6m_Ionoscatter (69 files, DT=0 to 0.1)
Data: 30A_N0AN_6m_Ionoscatter (69 files, 6m ionoscatter)
Message: "N0AN K1JT -19"
RxFreq: 1500/10
Commit No_AP MyCall BothCalls
-----------------------------------
ef4787: 7 14 16 22 38 40
70a348: 38 43
ada5a6: 10 17 11 23 40 46
Commit No_AP MyCall BothCalls
------------------------------------------------
ef4787: 7 14 16 22 38 40
70a348: 38 43
ada5a6: 10 17 11 23 40 46
10f574: 8 16 99.4 15 24 91.8 34 44 68.8
b8ea4c: 8 16 96.0 15 23 92.4 34 44 68.8
Mode: Q65-60B
Data: 60B_1296_Troposcatter (75 files)
Message: "VK7MO VK7PD QE38"
RxFreq: 1000/10
Commit No_AP MyCall BothCalls
-----------------------------------
ef4787: 1 2 11 23 64 67
ada5a6: 1 5 14 28 64 67
Commit No_AP MyCall BothCalls
--------------------------------------------------
ef4787: 1 2 11 23 64 67
ada5a6: 1 5 14 28 64 67
10f574: 1 5 142.7 11 27 129.8 65 67 36.8
b8ea4c: 1 5 144.3 11 27 132.2 65 67 39.3
Mode: Q65-60D
Data: MsgAvg (22 files, simulated fDop = 50 Hz)
Message: "K1ABC W9XYZ EN37"
RxFreq: 1000/10
Commit No_AP MyCall BothCalls
-----------------------------------
ef4787: 0 10 21 21 22 22
ada5a6 0 11 21 21 22 22
Commit No_AP MyCall BothCalls
------------------------------------------------
ef4787: 0 10 21 21 22 22
ada5a6 0 11 21 21 22 22
10f574: 0 11 47.7 21 21 33.9 22 22 11.6
b8ea4c: 0 11 46.4 21 21 33.8 22 22 11.9
Mode: Q65-60D
Data: Nil Average (40 files, simulated fDop = 0? Hz )
Data: 60D_2 (21 files, 1296 troposcatter)
Message: "VK7MO VK3WE QF32"
RxFreq: 1200/20
Requires nsmo=1 ###
RxFreq: 1000/20
Commit No_AP MyCall BothCalls
-----------------------------------
ef4787: 1 16 24 28 39 39
Commit No_AP MyCall BothCalls
----------------------------------------------
10f574: 5 5 33.6 7 8 31.8 12 14 25.1
b8ea4v: 5 5 39.1 7 8 38.0 13 14 30.8
Mode: Q65-120D
Data: 120D (14 files, 10 GHz troposcatter)
Message: "VK7MO VK3WE QF32"
RxFreq: 1000/20
Commit No_AP MyCall BothCalls
----------------------------------------------
10f574: 0 0 24.9 0 0 25.0 1 4 25.0
b8ea4v: 0 0 39.1 0 0 25.4 1 5 40.1
Mode: Q65-60D
Data: 60D_10_GHz_EME (14 files)
Message: "VK7MO K6QPV DM12", "VK7MO K6QPV -15"
RxFreq: 1000/50
Commit No_AP MyCall BothCalls
----------------------------------------------
10f574: 9 10 13.6 10 11 12.7 14 14 7.1
b8ea4v: 9 10 13.7 10 11 12.6 14 14 7.5

View File

@ -1,16 +1,16 @@
subroutine ana64(dd,npts,c0)
subroutine ana64(iwave,npts,c0)
use timer_module, only: timer
real dd(npts) !Raw data at 12000 Hz
integer*2 iwave(npts) !Raw data at 12000 Hz
complex c0(0:npts-1) !Complex data at 6000 Hz
save
nfft1=npts
nfft2=nfft1/2
df1=12000.0/nfft1
fac=2.0/nfft1
c0(0:npts-1)=fac*dd(1:npts)
fac=2.0/(32767.0*nfft1)
c0(0:npts-1)=fac*iwave(1:npts)
call four2a(c0,nfft1,1,-1,1) !Forward c2c FFT
c0(nfft2/2+1:nfft2-1)=0.
c0(0)=0.5*c0(0)

View File

@ -205,11 +205,12 @@ subroutine multimode_decoder(ss,id2,params,nfsample)
open(17,file=trim(temp_dir)//'/red.dat',status='unknown')
open(14,file=trim(temp_dir)//'/avemsg.txt',status='unknown')
call timer('dec_q65 ',0)
call my_q65%decode(q65_decoded,id2,params%nutc,params%ntr, &
params%nsubmode,params%nfqso,params%ntol,params%ndepth, &
params%nfa,params%nfb,logical(params%nclearave), &
params%emedelay,mycall,hiscall,hisgrid,params%nQSOProgress, &
ncontest,logical(params%lapcqonly),navg0)
call my_q65%decode(q65_decoded,id2,params%nutc,params%ntr, &
params%nsubmode,params%nfqso,params%ntol,params%ndepth, &
params%nfa,params%nfb,logical(params%nclearave), &
single_decode,logical(params%nagain), &
logical(params%newdat),params%emedelay,mycall,hiscall,hisgrid, &
params%nQSOProgress,ncontest,logical(params%lapcqonly),navg0)
call timer('dec_q65 ',1)
close(17)
go to 800

View File

@ -26,9 +26,9 @@ module q65_decode
contains
subroutine decode(this,callback,iwave,nutc,ntrperiod,nsubmode,nfqso, &
ntol,ndepth,nfa0,nfb0,lclearave,emedelay,mycall,hiscall,hisgrid, &
nQSOprogress,ncontest,lapcqonly,navg0)
subroutine decode(this,callback,iwave,nutc,ntrperiod,nsubmode,nfqso, &
ntol,ndepth,nfa0,nfb0,lclearave,single_decode,lagain,lnewdat0, &
emedelay,mycall,hiscall,hisgrid,nQSOprogress,ncontest,lapcqonly,navg0)
! Top-level routine that organizes the decoding of Q65 signals
! Input: iwave Raw data, i*2
@ -49,6 +49,7 @@ contains
use packjt77
use, intrinsic :: iso_c_binding
use q65 !Shared variables
use prog_args
parameter (NMAX=300*12000) !Max TRperiod is 300 s
class(q65_decoder), intent(inout) :: this
@ -59,18 +60,26 @@ contains
character*77 c77
character*78 c78
character*6 cutc
character c6*6,c4*4,cmode*4
character*80 fmt
integer*2 iwave(NMAX) !Raw data
real, allocatable :: dd(:) !Raw data
integer dat4(13) !Decoded message as 12 6-bit integers
integer dgen(13)
logical lclearave,lapcqonly,unpk77_success
logical lclearave,lnewdat0,lapcqonly,unpk77_success
logical single_decode,lagain
complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s
complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s
! Start by setting some parameters and allocating storage for large arrays
call sec0(0,tdecode)
nfa=nfa0
nfb=nfb0
lnewdat=lnewdat0
idec=-1
idf=0
idt=0
irc=0
mode_q65=2**nsubmode
npts=ntrperiod*12000
nfft1=ntrperiod*12000
@ -106,9 +115,12 @@ contains
baud=12000.0/nsps
this%callback => callback
nFadingModel=1
ibwa=max(1,int(1.8*log(baud*mode_q65)) + 2)
ibwb=min(10,ibwa+4)
if(iand(ndepth,3).eq.3) then
ibwa=max(1,int(1.8*log(baud*mode_q65)) + 1)
ibwb=min(10,ibwa+3)
if(iand(ndepth,3).ge.2) then
ibwa=max(1,int(1.8*log(baud*mode_q65)) + 2)
ibwb=min(10,ibwa+5)
else if(iand(ndepth,3).eq.3) then
ibwa=max(1,ibwa-1)
ibwb=min(10,ibwb+1)
endif
@ -128,24 +140,16 @@ contains
call timer('q65_dec0',1)
if(idec.ge.0) then
dtdec=xdt !We have a list-decode result
dtdec=xdt !We have a list-decode result at nfqso
f0dec=f0
go to 100
endif
if(snr1.lt.2.8) then
dtdec=0. !No reliable sync, abandon decoding attempt
f0dec=0.
go to 100
endif
! Prepare for a single-period decode woth iaptype = 0, 1, or 2 (also 4?)
! Prepare for a single-period decode with iaptype = 0, 1, 2, or 4
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
call ana64(iwave,npts,c00) !Convert to complex c00() at 6000 Sa/s
call ft8apset(mycall,hiscall,ncontest,apsym0,aph10) ! Generate ap symbols
where(apsym0.eq.-1) apsym0=0
@ -196,7 +200,7 @@ contains
go to 100
endif
! There was no 'q3n' decode. Try for a 'q[012]n' decode.
! There was no 'q3n' decode. Try for a 'q[0124]n' decode.
! Call top-level routine in q65 module: establish sync and try for a q[012]n
! decode, this time using the cumulative 's1a' symbol spectra.
@ -229,17 +233,109 @@ contains
call this%callback(nutc,snr1,nsnr,dtdec,f0dec,decoded, &
idec,nused,ntrperiod)
if(iand(ndepth,128).ne.0) call q65_clravg !AutoClrAvg after decode
call sec0(1,tdecode)
open(22,file=trim(data_dir)//'/q65_decodes.dat',status='unknown', &
position='append',iostat=ios)
if(ios.eq.0) then
! Save decoding parameters to q65_decoded.dat, for later analysis.
write(cmode,'(i3)') ntrperiod
cmode(4:4)=char(ichar('A')+nsubmode)
c6=hiscall(1:6)
if(c6.eq.' ') c6='<b> '
c4=hisgrid(1:4)
if(c4.eq.' ') c4='<b> '
fmt='(i6.4,1x,a4,5i2,3i3,f6.2,f7.1,f7.2,f6.1,f6.2,'// &
'1x,a6,1x,a6,1x,a4,1x,a)'
if(ntrperiod.le.30) fmt(5:5)='6'
write(22,fmt) nutc,cmode,nQSOprogress,idec,idf,idt,ibw,nused, &
icand,ncand,xdt,f0,snr1,snr2,tdecode,mycall(1:6),c6,c4, &
trim(decoded)
close(22)
endif
else
! Report snr1, even if no decode.
nsnr=db(snr1) - 35.0
if(nsnr.lt.-35) nsnr=-35
idec=-1
call this%callback(nutc,snr1,nsnr,xdt,f0,decoded, &
call this%callback(nutc,snr1,nsnr,xdt,f0,decoded, &
idec,0,ntrperiod)
endif
navg0=1000*navg(0) + navg(1)
if(single_decode .or. lagain) go to 900
return
do icand=1,ncand
! Prepare for single-period candidate decodes with iaptype = 0, 1, 2, or 4
snr1=candidates(icand,1)
xdt= candidates(icand,2)
f0 = candidates(icand,3)
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
call ana64(iwave,npts,c00) !Convert to complex c00() at 6000 Sa/s
call ft8apset(mycall,hiscall,ncontest,apsym0,aph10) ! Generate ap symbols
where(apsym0.eq.-1) apsym0=0
npasses=2
if(nQSOprogress.eq.5) npasses=3
if(lapcqonly) npasses=1
iaptype=0
do ipass=0,npasses !Loop over AP passes
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
read(c78,1060) apmask
write(c78,1050) apsymbols1
read(c78,1060) apsymbols
endif
call timer('q65loops',0)
call q65_loops(c00,npts/2,nsps/2,nsubmode,ndepth,jpk0, &
xdt,f0,iaptype,xdt1,f1,snr2,dat4,idec)
! idec=-1 !### TEMPORARY ###
call timer('q65loops',1)
if(idec.ge.0) then
dtdec=xdt1
f0dec=f1
go to 200 !Successful decode, we're done
endif
enddo ! ipass
200 decoded=' '
if(idec.ge.0) then
! Unpack decoded message for display to user
write(c77,1000) dat4(1:12),dat4(13)/2
call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent
nsnr=nint(snr2)
call this%callback(nutc,snr1,nsnr,dtdec,f0dec,decoded, &
idec,nused,ntrperiod)
if(iand(ndepth,128).ne.0) call q65_clravg !AutoClrAvg after decode
call sec0(1,tdecode)
open(22,file=trim(data_dir)//'/q65_decodes.dat',status='unknown', &
position='append',iostat=ios)
if(ios.eq.0) then
! Save decoding parameters to q65_decoded.dat, for later analysis.
write(cmode,'(i3)') ntrperiod
cmode(4:4)=char(ichar('A')+nsubmode)
c6=hiscall(1:6)
if(c6.eq.' ') c6='<b> '
c4=hisgrid(1:4)
if(c4.eq.' ') c4='<b> '
fmt='(i6.4,1x,a4,5i2,3i3,f6.2,f7.1,f7.2,f6.1,f6.2,'// &
'1x,a6,1x,a6,1x,a4,1x,a)'
if(ntrperiod.le.30) fmt(5:5)='6'
write(22,fmt) nutc,cmode,nQSOprogress,idec,idf,idt,ibw,nused, &
icand,ncand,xdt,f0,snr1,snr2,tdecode,mycall(1:6),c6,c4, &
trim(decoded)
close(22)
endif
endif
enddo
900 return
end subroutine decode
end module q65_decode

View File

@ -11,12 +11,15 @@ module q65
38,46,50,55,60,62,66,69,74,76,85/)
integer codewords(63,206)
integer ibwa,ibwb,ncw,nsps,mode_q65,nfa,nfb
integer istep,nsmo,lag1,lag2,npasses,nused,iseq
integer idf,idt,ibw
integer istep,nsmo,lag1,lag2,npasses,nused,iseq,ncand
integer i0,j0
integer navg(0:1)
logical lnewdat
real candidates(20,3) !snr, xdt, and f0 of top candidates
real,allocatable,save :: s1a(:,:,:) !Cumulative symbol spectra
real sync(85) !sync vector
real df,dtstep,dtdec,f0dec
real df,dtstep,dtdec,f0dec,ftol
contains
@ -59,9 +62,8 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
logical first,lclearave
real, allocatable :: s1(:,:) !Symbol spectra, 1/8-symbol steps
real, allocatable :: s3(:,:) !Data-symbol energies s3(LL,63)
real, allocatable :: ccf(:,:) !CCF(freq,lag)
real, allocatable :: ccf1(:) !CCF(freq) at best lag
real, allocatable :: ccf2(:) !CCF(freq) at any lag
real, allocatable :: ccf1(:) !CCF(freq) at fixed lag (red)
real, allocatable :: ccf2(:) !Max CCF(freq) at any lag (orange)
data first/.true./
save first
@ -80,6 +82,7 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
txt=85.0*nsps/12000.0
jz=(txt+1.0)*12000.0/istep !Number of symbol/NSTEP bins
if(nsps.ge.6912) jz=(txt+2.0)*12000.0/istep !For TR 60 s and higher
ftol=ntol
ia=ntol/df
ia2=max(ia,10*mode_q65,nint(100.0/df))
nsmo=int(0.7*mode_q65*mode_q65)
@ -93,9 +96,8 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
allocate(s1(iz,jz))
allocate(s3(-64:LL-65,63))
allocate(ccf(-ia2:ia2,-53:214))
allocate(ccf1(-ia2:ia2))
allocate(ccf2(-ia2:ia2))
allocate(ccf2(iz))
if(LL.ne.LL0 .or. iz.ne.iz0 .or. jz.ne.jz0 .or. lclearave) then
if(allocated(s1a)) deallocate(s1a)
allocate(s1a(iz,jz,0:1))
@ -140,59 +142,36 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
! Try list decoding via "Deep Likelihood".
call timer('ccf_85 ',0)
! Try to synchronize using all 85 symbols
call q65_ccf_85(s1,iz,jz,nfqso,ia,ia2,ipk,jpk,f0,xdt,imsg_best,ccf,ccf1)
call q65_ccf_85(s1,iz,jz,nfqso,ia,ia2,ipk,jpk,f0,xdt,imsg_best,ccf1)
call timer('ccf_85 ',1)
call timer('list_dec',0)
call q65_dec_q3(s1,iz,jz,s3,LL,ipk,jpk,snr2,dat4,idec,decoded)
call timer('list_dec',1)
if(idec.ne.0) then
ic=ia2/4;
base=(sum(ccf1(-ia2:-ia2+ic)) + sum(ccf1(ia2-ic:ia2)))/(2.0+2.0*ic);
ccf1=ccf1-base
smax=maxval(ccf1)
if(smax.gt.10.0) ccf1=10.0*ccf1/smax
base=(sum(ccf2(-ia2:-ia2+ic)) + sum(ccf2(ia2-ic:ia2)))/(2.0+2.0*ic);
ccf2=ccf2-base
smax=maxval(ccf2)
if(smax.gt.10.0) ccf2=10.0*ccf2/smax
endif
endif
! Get 2d CCF and ccf2 using sync symbols only
call q65_ccf_22(s1,iz,jz,nfqso,ia,ia2,ipk,jpk,f0a,xdta,ccf,ccf2)
call q65_ccf_22(s1,iz,jz,nfqso,ipk,jpk,f0a,xdta,ccf2)
if(idec.lt.0) then
f0=f0a
xdt=xdta
endif
! Estimate rms on ccf baseline
sq=0.
nsq=0
jd=(lag2-lag1)/4
do i=-ia2,ia2
do j=lag1,lag2
if(abs(j-jpk).gt.jd .and. abs(i-ipk).gt.ia/2) then
sq=sq + ccf(i,j)**2
nsq=nsq+1
endif
enddo
enddo
rms=sqrt(sq/nsq)
smax=ccf(ipk,jpk)
snr1=smax/rms
ccf2=ccf2/rms
if(snr1.gt.10.0) ccf2=(10.0/snr1)*ccf2
! Estimate rms on ccf2 baseline
call q65_sync_curve(ccf2,1,iz,rms2)
smax=maxval(ccf2)
snr1=0.
if(rms2.gt.0) snr1=smax/rms2
if(idec.le.0) then
! The q3 decode attempt failed. Copy synchronied symbol spectra from s1
! The q3 decode attempt failed. Copy synchronized symbol energies from s1
! into s3 and prepare to try a more general decode.
ccf1=ccf(:,jpk)/rms
if(snr1.gt.10.0) ccf1=(10.0/snr1)*ccf1
call q65_s1_to_s3(s1,iz,jz,ipk,jpk,LL,mode_q65,sync,s3)
endif
smax=maxval(ccf1)
! Estimate frequenct spread
i1=-9999
i2=-9999
do i=-ia,ia
@ -201,16 +180,8 @@ subroutine q65_dec0(iavg,nutc,iwave,ntrperiod,nfqso,ntol,ndepth,lclearave, &
enddo
width=df*(i2-i1)
! Write data for the red and orange sync curves.
do i=-ia2,ia2
freq=nfqso + i*df
if(freq.ge.float(nfa) .and. freq.le.float(nfb)) then
write(17,1100) freq,ccf1(i),xdt,ccf2(i)
1100 format(4f10.3)
endif
enddo
rewind 17
if(ncw.eq.0) ccf1=0.
call q65_write_red(iz,ia2,xdt,ccf1,ccf2)
if(iavg.eq.2) then
call q65_dec_q012(s3,LL,snr2,dat4,idec,decoded)
@ -261,43 +232,31 @@ subroutine q65_symspec(iwave,nmax,iz,jz,s1)
call smo121(s1(1:iz,j),iz)
enddo
enddo
s1a(:,:,iseq)=s1a(:,:,iseq) + s1
navg(iseq)=navg(iseq) + 1
if(lnewdat) then
s1a(:,:,iseq)=s1a(:,:,iseq) + s1
navg(iseq)=navg(iseq) + 1
endif
return
end subroutine q65_symspec
subroutine q65_dec_q3(s1,iz,jz,s3,LL,ipk,jpk,snr2,dat4,idec,decoded)
! Copy synchronized symbol spectra from s1 into s3, then attempt a q3 decode.
! Copy synchronized symbol energies from s1 into s3, then attempt a q3 decode.
character*37 decoded
integer dat4(13)
real s1(iz,jz)
real s3(-64:LL-65,63)
i1=i0+ipk-64
i2=i1+LL-1
j=j0+jpk-7
n=0
do k=1,85
j=j+8
if(sync(k).gt.0.0) then
cycle
endif
n=n+1
if(j.ge.1 .and. j.le.jz) then
do i=0,LL-1
s3(i-64,n)=s1(i+i1,j) !Copy from s1 into s3
enddo
endif
enddo
call q65_s1_to_s3(s1,iz,jz,ipk,jpk,LL,mode_q65,sync,s3)
nsubmode=0
if(mode_q65.eq.2) nsubmode=1
if(mode_q65.eq.4) nsubmode=2
if(mode_q65.eq.8) nsubmode=3
if(mode_q65.eq.16) nsubmode=4
if(mode_q65.eq.32) nsubmode=5
baud=12000.0/nsps
do ibw=ibwa,ibwb
@ -366,17 +325,18 @@ subroutine q65_dec_q012(s3,LL,snr2,dat4,idec,decoded)
100 return
end subroutine q65_dec_q012
subroutine q65_ccf_85(s1,iz,jz,nfqso,ia,ia2,ipk,jpk,f0,xdt,imsg_best,ccf,ccf1)
subroutine q65_ccf_85(s1,iz,jz,nfqso,ia,ia2,ipk,jpk,f0,xdt,imsg_best,ccf1)
! Attempt synchronization using all 85 symbols, in advance of an
! attempt at q3 decoding. Return ccf1 for the "red sync curve".
real s1(iz,jz)
real ccf(-ia2:ia2,-53:214)
real, allocatable :: ccf(:,:) !CCF(freq,lag)
real ccf1(-ia2:ia2)
integer ijpk(2)
integer itone(85)
allocate(ccf(-ia2:ia2,-53:214))
ipk=0
jpk=0
ccf_best=0.
@ -387,10 +347,10 @@ subroutine q65_ccf_85(s1,iz,jz,nfqso,ia,ia2,ipk,jpk,f0,xdt,imsg_best,ccf,ccf1)
do j=1,85
if(j.eq.isync(i)) then
i=i+1
itone(j)=-1
itone(j)=0
else
k=k+1
itone(j)=codewords(k,imsg)
itone(j)=codewords(k,imsg) + 1
endif
enddo
@ -416,48 +376,90 @@ subroutine q65_ccf_85(s1,iz,jz,nfqso,ia,ia2,ipk,jpk,f0,xdt,imsg_best,ccf,ccf1)
ijpk=maxloc(ccf(-ia:ia,:))
ipk=ijpk(1)-ia-1
jpk=ijpk(2)-53-1
f0=nfqso + (ipk-mode_q65)*df
f0=nfqso + ipk*df
xdt=jpk*dtstep
imsg_best=imsg
ccf1=ccf(:,jpk)
endif
enddo ! imsg
deallocate(ccf)
return
end subroutine q65_ccf_85
subroutine q65_ccf_22(s1,iz,jz,nfqso,ia,ia2,ipk,jpk,f0,xdt,ccf,ccf2)
subroutine q65_ccf_22(s1,iz,jz,nfqso,ipk,jpk,f0,xdt,ccf2)
! Attempt synchronization using only the 22 sync symbols. Return ccf2
! for the "orange sync curve".
real s1(iz,jz)
real ccf(-ia2:ia2,-53:214)
real ccf2(-ia2:ia2)
integer ijpk(2)
ccf=0.
do lag=lag1,lag2
do k=1,85
n=NSTEP*(k-1) + 1
j=n+lag+j0
if(j.ge.1 .and. j.le.jz) then
do i=-ia2,ia2
if(i0+i.lt.1 .or. i0+i.gt.iz) cycle
ccf(i,lag)=ccf(i,lag) + sync(k)*s1(i0+i,j)
enddo
real s1(iz,jz)
real ccf2(iz) !Orange sync curve
real, allocatable :: xdt2(:)
integer, allocatable :: indx(:)
allocate(xdt2(iz))
allocate(indx(iz))
ccfbest=0.
ibest=0
lagpk=0
lagbest=0
do i=1,iz
ccfmax=0.
do lag=lag1,lag2
ccft=0.
do k=1,85
n=NSTEP*(k-1) + 1
j=n+lag+j0
if(j.ge.1 .and. j.le.jz) then
ccft=ccft + sync(k)*s1(i,j)
endif
enddo
if(ccft.gt.ccfmax) then
ccfmax=ccft
lagpk=lag
endif
enddo
ccf2(i)=ccfmax
xdt2(i)=lagpk*dtstep
if(ccfmax.gt.ccfbest .and. abs(i*df-nfqso).le.ftol) then
ccfbest=ccfmax
ibest=i
lagbest=lagpk
endif
enddo
do i=-ia2,ia2
ccf2(i)=maxval(ccf(i,:))
enddo
ijpk=maxloc(ccf(-ia:ia,:))
ipk=ijpk(1)-ia-1
jpk=ijpk(2)-53-1
! Parameters for the top candidate:
ipk=ibest - i0
jpk=lagbest
f0=nfqso + ipk*df
xdt=jpk*dtstep
! Save parameters for best candidates
i1=max(nfa,100)/df
i2=min(nfb,4900)/df
jzz=i2-i1+1
call pctile(ccf2(i1:i2),jzz,40,base)
ccf2=ccf2/base
call indexx(ccf2(i1:i2),jzz,indx)
ncand=0
maxcand=20
do j=1,20
i=indx(jzz-j+1)+i1-1
if(ccf2(i).lt.3.4) exit !Candidate limit
f=i*df
if(f.ge.(nfqso-ftol) .and. f.le.(nfqso+ftol)) cycle
i3=max(1,i-67*mode_q65)
i4=min(iz,i+3*mode_q65)
biggest=maxval(ccf2(i3:i4))
if(ccf2(i).ne.biggest) cycle
ncand=ncand+1
candidates(ncand,1)=ccf2(i)
candidates(ncand,2)=xdt2(i)
candidates(ncand,3)=f
if(ncand.ge.maxcand) exit
enddo
return
end subroutine q65_ccf_22
@ -539,4 +541,52 @@ subroutine q65_s1_to_s3(s1,iz,jz,ipk,jpk,LL,mode_q65,sync,s3)
return
end subroutine q65_s1_to_s3
subroutine q65_write_red(iz,ia2,xdt,ccf1,ccf2)
! Write data for the red and orange sync curves to LU 17.
real ccf1(-ia2:ia2)
real ccf2(iz)
call q65_sync_curve(ccf1,-ia2,ia2,rms1)
call q65_sync_curve(ccf2,1,iz,rms2)
rewind 17
write(17,1000) xdt
do i=1,iz
freq=i*df
ii=i-i0
if(freq.ge.float(nfa) .and. freq.le.float(nfb)) then
ccf1a=-99.0
if(ii.ge.-ia2 .and. ii.le.ia2) ccf1a=ccf1(ii)
write(17,1000) freq,ccf1a,ccf2(i)
1000 format(3f10.3)
endif
enddo
return
end subroutine q65_write_red
subroutine q65_sync_curve(ccf1,ia,ib,rms1)
! Condition the red or orange sync curve for plotting.
real ccf1(ia:ib)
ic=(ib-ia)/8;
nsum=2*(ic+1)
base1=(sum(ccf1(ia:ia+ic)) + sum(ccf1(ib-ic:ib)))/nsum
ccf1=ccf1-base1
sq=dot_product(ccf1(ia:ia+ic),ccf1(ia:ia+ic)) + &
dot_product(ccf1(ib-ic:ib),ccf1(ib-ic:ib))
rms1=0.
if(nsum.gt.0) rms1=sqrt(sq/nsum)
if(rms1.gt.0.0) ccf1=2.0*ccf1/rms1
smax1=maxval(ccf1)
if(smax1.gt.10.0) ccf1=10.0*ccf1/smax1
return
end subroutine q65_sync_curve
end module q65

View File

@ -6,7 +6,7 @@ subroutine q65_loops(c00,npts2,nsps2,nsubmode,ndepth,jpk0, &
use q65
parameter (NN=63)
parameter (LN=1152*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63
parameter (LN=2176*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63
complex c00(0:npts2-1) !Analytic representation of dd(), 6000 Hz
complex ,allocatable :: c0(:) !Ditto, with freq shift
character decoded*37
@ -51,7 +51,7 @@ subroutine q65_loops(c00,npts2,nsps2,nsubmode,ndepth,jpk0, &
jpk=jpk0 + nsps2*ndt/16 !tsym/16
if(jpk.lt.0) jpk=0
call timer('spec64 ',0)
call spec64(c0,nsps2,65,mode_q65,jpk,s3,LL,NN)
call spec64(c0,nsps2,mode_q65,jpk,s3,LL,NN)
call timer('spec64 ',1)
call pctile(s3,LL*NN,40,base)
s3=s3/base
@ -75,9 +75,6 @@ subroutine q65_loops(c00,npts2,nsps2,nsubmode,ndepth,jpk0, &
enddo ! idf (f0 loop)
100 if(irc.ge.0) then
! write(55,3055) ndepth,iaptype,idf,idt,ibw,ndist,irc,sum(s3(1:LL*NN)), &
! trim(decoded)
!3055 format(7i4,f10.1,1x,a)
idec=iaptype
snr2=esnodb - db(2500.0/baud)
xdt1=xdt0 + nsps2*ndt/(16.0*6000.0)

View File

@ -1,128 +0,0 @@
subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, &
emedelay,mycall_12,hiscall_12,hisgrid_6,sync,nsnr,dtx,nfreq,decoded,nft)
use packjt
use timer_module, only: timer
parameter (NMAX=60*12000,LN=1152*63)
character decoded*22
character*12 mycall_12,hiscall_12
character*6 mycall,hiscall,hisgrid_6
character*4 hisgrid
logical ltext
complex c00(0:720000) !Analytic signal for dd()
real dd(NMAX) !Raw data sampled at 12000 Hz
integer dat4(12) !Decoded message (as 12 integers)
data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/
save
call timer('qra64a ',0)
irc=-1
decoded=' '
nft=99
if(nfqso.lt.nf1 .or. nfqso.gt.nf2) go to 900
mycall=mycall_12(1:6) !### May need fixing? ###
hiscall=hiscall_12(1:6)
hisgrid=hisgrid_6(1:4)
call packcall(mycall,nc1,ltext)
call packcall(hiscall,nc2,ltext)
call packgrid(hisgrid,ng2,ltext)
nSubmode=0
if(mode64.eq.2) nSubmode=1
if(mode64.eq.4) nSubmode=2
if(mode64.eq.8) nSubmode=3
if(mode64.eq.16) nSubmode=4
b90=1.0
nFadingModel=1
maxaptype=4
if(iand(ndepth,64).ne.0) maxaptype=5
call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist)
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 ana64(dd,npts,c00)
call timer('sync64 ',0)
call sync64(c00,nf1,nf2,nfqso,ntol,minsync,mode64,emedelay,dtx,f0, &
jpk0,sync,sync2,width)
call timer('sync64 ',1)
nfreq=nint(f0)
if(mode64.eq.1 .and. minsync.ne.-1 .and. (sync-7.0).lt.minsync) go to 900
nsps=6912
call timer('qraloops',0)
call qra_loops(c00,npts/2,nsps,64,mode64,nsubmode,nFadingModel, &
ndepth,nc1,nc2,ng2,naptype,jpk0,dtx,f0,width,snr2,irc,dat4)
call timer('qraloops',1)
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
nft=100 + irc
nsnr=nint(snr2)
else
snr2=0.
endif
nfreq=nint(f0)
900 if(irc.lt.0) then
sy=max(1.0,sync)
if(nSubmode.eq.0) nsnr=nint(10.0*log10(sy)-35.0) !A
if(nSubmode.eq.1) nsnr=nint(10.0*log10(sy)-34.0) !B
if(nSubmode.eq.2) nsnr=nint(10.0*log10(sy)-29.0) !C
if(nSubmode.eq.3) nsnr=nint(10.0*log10(sy)-29.0) !D
if(nSubmode.eq.4) nsnr=nint(10.0*log10(sy)-24.0) !E
endif
call timer('qra64a ',1)
return
end subroutine qra64a
subroutine qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist)
! If file qra_params is present in CWD, read decoding params from it.
integer iparam(7)
logical first,ex
! data iparam/3,5,11,11,0,11,60/ !Maximum effort
data iparam/3,5,7,7,0,4,15/ !Default values
data first/.true./
save first,iparam
if(first) then
inquire(file='qra_params',exist=ex)
if(ex) then
open(29,file='qra_params',status='old')
read(29,*) iparam
close(29)
endif
first=.false.
endif
ndepth=iparam(1)
maxaptype=iparam(2)
idf0max=iparam(3)
idt0max=iparam(4)
ibwmin=iparam(5)
ibwmax=iparam(6)
maxdist=iparam(7)
return
end subroutine qra_params

View File

@ -1,4 +1,4 @@
subroutine spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN)
subroutine spec64(c0,nsps,mode_q65,jpk,s3,LL,NN)
parameter (MAXFFT=20736)
!### Fix this:
@ -11,41 +11,24 @@ subroutine spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN)
data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/
nfft=nsps
if(mode.eq.64) then
do j=1,NN
jj=j+7 !Skip first Costas array
if(j.ge.33) jj=j+14 !Skip middle Costas array
ja=jpk + (jj-1)*nfft
jb=ja+nfft-1
cs(0:nfft-1)=c0(ja:jb)
call four2a(cs,nfft,1,-1,1)
do ii=1,LL
i=ii-65
if(i.lt.0) i=i+nfft
s3(ii,j)=real(cs(i))**2 + aimag(cs(i))**2
enddo
j=0
n=1
do k=1,84
if(k.eq.isync(n)) then
n=n+1
cycle
endif
j=j+1
ja=(k-1)*nsps + jpk
jb=ja+nsps-1
cs(0:nfft-1)=c0(ja:jb)
call four2a(cs,nsps,1,-1,1) !c2c FFT to frequency
do ii=1,LL
i=ii-65+mode_q65 !mode_q65 = 1 2 4 8 16 for Q65 A B C D E
if(i.lt.0) i=i+nsps
s3(ii,j)=real(cs(i))**2 + aimag(cs(i))**2
enddo
else
j=0
n=1
do k=1,84
if(k.eq.isync(n)) then
n=n+1
cycle
endif
j=j+1
ja=(k-1)*nsps + jpk
jb=ja+nsps-1
cs(0:nfft-1)=c0(ja:jb)
call four2a(cs,nsps,1,-1,1) !c2c FFT to frequency
do ii=1,LL
i=ii-65+mode64 !mode64 = 1 2 4 8 16 for Q65 A B C D E
if(i.lt.0) i=i+nsps
s3(ii,j)=real(cs(i))**2 + aimag(cs(i))**2
enddo
enddo
endif
enddo
df=6000.0/nfft
do i=1,LL

View File

@ -73,7 +73,7 @@ program test_q65
! 1 2 3 4 5 6 7
! 123456789012345678901234567890123456789012345678901234567890123456789012345'
cmd1='q65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 0.0 1 60 100 -10.0 > junk0'
cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A -Q 3 -f 1500 *.wav > junk'
cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A -Q 3 -f 1500 *.wav > junk'
write(cmd1(10:33),'(a)') '"'//msg//'"'
cmd1(35:35)=csubmode
@ -86,10 +86,10 @@ program test_q65
write(cmd1(62:66),'(i5)') nfiles
write(cmd2(11:13),'(i3)') ntrperiod
write(cmd2(33:34),'(i2)') ndepth
write(cmd2(44:44),'(i1)') nQSOprogress
write(cmd2(49:52),'(i4)') nf0
cmd2(39:39)=csubmode
write(cmd2(33:35),'(i3)') ndepth
write(cmd2(45:45),'(i1)') nQSOprogress
write(cmd2(50:53),'(i4)') nf0
cmd2(40:40)=csubmode
call system('rm -f *.wav')
@ -142,13 +142,14 @@ program test_q65
if(line(i0:i0).ne.' ') then
i1=index(line,'q')
idec=-1
read(line(i1+1:),*) idec
endif
if(idec.lt.0) cycle
if(idec.ge.12) then
iavg=idec-10
idec=1
read(line(i1+1:i1+1),*) idec
if(line(i1+2:i1+2).eq.'*') then
iavg=10
else
read(line(i1+2:i1+2),*,end=100) iavg
endif
endif
100 if(idec.lt.0) cycle
if(decok) then
ndecn=ndecn + 1
if(iavg.le.1) ndec1=ndec1 + 1

Binary file not shown.

View File

@ -3054,6 +3054,7 @@ void MainWindow::on_ClrAvgButton_clicked()
if(m_msgAvgWidget != NULL) {
if(m_msgAvgWidget->isVisible()) m_msgAvgWidget->displayAvg("");
}
if(m_mode=="Q65") ndecodes_label.setText("0 0");
}
void MainWindow::msgAvgDecode2()

View File

@ -141,7 +141,7 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed)
//move current data down one line (must do this before attaching a QPainter object)
if(bScroll and !m_bReplot) m_WaterfallPixmap.scroll(0,1,0,0,m_w,m_h1);
QPainter painter1(&m_WaterfallPixmap);
if(m_bFirst or bRed or (!m_bQ65_Sync and !m_bQ65_MultiSync) or m_mode!=m_mode0
if(m_bFirst or bRed or !m_bQ65_Sync or m_mode!=m_mode0
or m_bResized or m_rxFreq!=m_rxFreq0) {
m_2DPixmap = m_OverlayPixmap.copy(0,0,m_w,m_h2);
m_bFirst=false;
@ -165,6 +165,7 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed)
}
static QPoint LineBuf[MAX_SCREENSIZE];
static QPoint LineBuf2[MAX_SCREENSIZE];
static QPoint LineBuf3[MAX_SCREENSIZE];
j=0;
j0=int(m_startFreq/m_fftBinWidth + 0.5);
int iz=XfromFreq(5000.0);
@ -229,7 +230,7 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed)
}
if(i==iz-1 and !m_bQ65_Sync and !m_bQ65_MultiSync) {
if(i==iz-1 and !m_bQ65_Sync) {
painter2D.drawPolyline(LineBuf,j);
}
LineBuf[j].setX(i);
@ -273,28 +274,37 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed)
painter2D.drawText(x1-4,y,"73");
}
if(bRed and (m_bQ65_Sync or m_bQ65_MultiSync)) { //Plot the Q65 red or orange sync curve
if(bRed and m_bQ65_Sync) { //Plot the Q65 red or orange sync curve
int k=0;
int k2=0;
std::ifstream f;
f.open(m_redFile.toLatin1());
if(f) {
int x,y;
float freq,sync,xdt,sync2;
float freq,xdt,sync,sync2;
f >> xdt;
for(int i=0; i<99999; i++) {
f >> freq >> sync >> xdt >> sync2;
f >> freq >> sync >> sync2;
if(f.eof()) break;
x=XfromFreq(freq);
if(m_bQ65_MultiSync) sync=sync2;
y=m_h2*(0.9 - 0.09*gain2d*sync) - m_plot2dZero;
LineBuf2[k].setX(x);
LineBuf2[k].setY(y);
if(sync > -99.0 and sync != 0.0) {
y=m_h2*(0.9 - 0.09*gain2d*sync) - m_plot2dZero - 10;
LineBuf2[k2].setX(x); //Red sync curve
LineBuf2[k2].setY(y);
k2++;
}
y=m_h2*(0.9 - 0.09*gain2d*sync2) - m_plot2dZero;
LineBuf3[k].setX(x); //Orange sync curve
LineBuf3[k].setY(y);
k++;
}
f.close();
QPen pen0(Qt::red,2);
if(m_bQ65_MultiSync) pen0.setColor("orange");
painter2D.setPen(pen0);
painter2D.drawPolyline(LineBuf2,k);
painter2D.drawPolyline(LineBuf2,k2);
pen0.setColor("orange");
painter2D.setPen(pen0);
painter2D.drawPolyline(LineBuf3,k);
if(m_bQ65_Sync) {
QString t;
t = t.asprintf("DT = %6.2f",xdt);

View File

@ -82,8 +82,7 @@ public:
bool Reference() const {return m_bReference;}
void setQ65_Sync(bool b) {m_bQ65_Sync = b;}
bool Q65_Sync() const {return m_bQ65_Sync;}
void setQ65_MultiSync(bool b) {m_bQ65_MultiSync = b;}
bool Q65_MultiSync() const {return m_bQ65_MultiSync;} void drawRed(int ia, int ib, float swide[]);
void drawRed(int ia, int ib, float swide[]);
void setVHF(bool bVHF);
void setRedFile(QString fRed);
void setFST4_FreqRange(int fLow,int fHigh);
@ -117,7 +116,6 @@ private:
bool m_bReference;
bool m_bReference0;
bool m_bQ65_Sync;
bool m_bQ65_MultiSync;
bool m_bVHF;
bool m_bSingleDecode;
bool m_bFirst=true;

View File

@ -71,13 +71,11 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
ui->widePlot->setLinearAvg(m_settings->value("LinearAvg",false).toBool());
ui->widePlot->setReference(m_settings->value("Reference",false).toBool());
ui->widePlot->setQ65_Sync(m_settings->value("Q65_Sync",false).toBool());
ui->widePlot->setQ65_MultiSync(m_settings->value("Q65_MultiSync",false).toBool());
if(ui->widePlot->current()) ui->spec2dComboBox->setCurrentIndex(0);
if(ui->widePlot->cumulative()) ui->spec2dComboBox->setCurrentIndex(1);
if(ui->widePlot->linearAvg()) ui->spec2dComboBox->setCurrentIndex(2);
if(ui->widePlot->Reference()) ui->spec2dComboBox->setCurrentIndex(3);
if(ui->widePlot->Q65_Sync()) ui->spec2dComboBox->setCurrentIndex(4);
if(ui->widePlot->Q65_MultiSync()) ui->spec2dComboBox->setCurrentIndex(5);
int nbpp=m_settings->value("BinsPerPixel",2).toInt();
ui->widePlot->setBinsPerPixel(nbpp);
ui->sbPercent2dPlot->setValue(m_Percent2DScreen);
@ -135,7 +133,6 @@ void WideGraph::saveSettings() //saveS
m_settings->setValue ("LinearAvg", ui->widePlot->linearAvg());
m_settings->setValue ("Reference", ui->widePlot->Reference());
m_settings->setValue ("Q65_Sync", ui->widePlot->Q65_Sync());
m_settings->setValue ("Q65_MultiSync", ui->widePlot->Q65_MultiSync());
m_settings->setValue ("BinsPerPixel", ui->widePlot->binsPerPixel ());
m_settings->setValue ("StartFreq", ui->widePlot->startFreq ());
m_settings->setValue ("WaterfallPalette", m_waterfallPalette);
@ -323,7 +320,6 @@ void WideGraph::on_spec2dComboBox_currentIndexChanged(int index)
ui->widePlot->setLinearAvg(false);
ui->widePlot->setReference(false);
ui->widePlot->setQ65_Sync(false);
ui->widePlot->setQ65_MultiSync(false);
ui->smoSpinBox->setEnabled(false);
switch (index)
{
@ -343,9 +339,6 @@ void WideGraph::on_spec2dComboBox_currentIndexChanged(int index)
case 4:
ui->widePlot->setQ65_Sync(true);
break;
case 5:
ui->widePlot->setQ65_MultiSync(true);
break;
}
replot();
}

View File

@ -340,11 +340,6 @@
<string>Q65_Sync</string>
</property>
</item>
<item>
<property name="text">
<string>Q65_MultiSync</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2">