From ee24f03d09393e9235de730b076cbb9d5e1efcae Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 31 Jul 2020 09:27:36 -0400 Subject: [PATCH 001/206] Modify genqra64.f90 so it can also be used for a "QRA66" mode. --- lib/genqra64.f90 | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/genqra64.f90 b/lib/genqra64.f90 index 4931342eb..babe7d692 100644 --- a/lib/genqra64.f90 +++ b/lib/genqra64.f90 @@ -4,15 +4,17 @@ subroutine genqra64(msg0,ichk,msgsent,itone,itype) use packjt character*22 msg0 - character*22 message !Message to be generated - character*22 msgsent !Message as it will be received - integer itone(84) - character*3 cok !' ' or 'OOO' + character*22 message !Message to be generated + character*22 msgsent !Message as it will be received + integer itone(85) !QRA64 uses only 84 + character*3 cok !' ' or 'OOO' logical old_qra_sync integer dgen(13) integer sent(63) + integer b11(11) !Barker 11 code integer icos7(0:6) - data icos7/2,5,6,0,4,1,3/ !Defines a 7x7 Costas array + data icos7/2,5,6,0,4,1,3/ !Defines a 7x7 Costas array + data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 definition save if(msg0(1:1).eq.'@') then @@ -39,18 +41,31 @@ subroutine genqra64(msg0,ichk,msgsent,itone,itype) call chkmsg(message,cok,nspecial,flip) call packmsg(message,dgen,itype) !Pack message into 72 bits call unpackmsg(dgen,msgsent) !Unpack to get message sent - if(ichk.ne.0) go to 999 !Return if checking only + if(ichk.eq.1) go to 999 !Return if checking only call qra64_enc(dgen,sent) !Encode using QRA64 - nsync=10 - inquire(file='old_qra_sync',exist=old_qra_sync) - if(old_qra_sync) nsync=1 - - itone(1:7)=nsync*icos7 !Insert 7x7 Costas array in 3 places - itone(8:39)=sent(1:32) - itone(40:46)=nsync*icos7 - itone(47:77)=sent(33:63) - itone(78:84)=nsync*icos7 + if(ichk.eq.66) then +! Experimental QRA66 (FST66?) mode + j=0 + k=0 + do i=1,85 + if(mod(i,4).eq.1) then + j=j+1 !Index for next sync symbol + if(j.eq.12) j=1 + itone(i)=b11(j) !Insert a sync symbol + else + k=k+1 + itone(i)=sent(k) + 2 + endif + enddo + else +! Original QRA64 mode + itone(1:7)=10*icos7 !Insert 7x7 Costas array in 3 places + itone(8:39)=sent(1:32) + itone(40:46)=10*icos7 + itone(47:77)=sent(33:63) + itone(78:84)=10*icos7 + endif endif 999 return From 9146ce9667855f12f885344145c1182d94e2070f Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 31 Jul 2020 10:58:30 -0400 Subject: [PATCH 002/206] Correct a flaw in qra64sim. --- lib/qra/qra64/qra64sim.f90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/qra/qra64/qra64sim.f90 b/lib/qra/qra64/qra64sim.f90 index b7ca2e130..278c1797d 100644 --- a/lib/qra/qra64/qra64sim.f90 +++ b/lib/qra/qra64/qra64sim.f90 @@ -107,7 +107,7 @@ program qra64sim twopi=8*atan(1.0) cspread(0)=1.0 cspread(NH)=0. - b=6.0 !Lorenzian 3/28 onward + b=6.0 !Use truncated Lorenzian shape for fspread do i=1,NH f=i*df x=b*f/fspread @@ -129,13 +129,13 @@ program qra64sim cspread(NFFT-i)=z enddo - do i=0,NFFT-1 - f=i*df - if(i.gt.NH) f=(i-nfft)*df - s=real(cspread(i))**2 + aimag(cspread(i))**2 +! do i=0,NFFT-1 +! f=i*df +! if(i.gt.NH) f=(i-nfft)*df +! s=real(cspread(i))**2 + aimag(cspread(i))**2 ! write(13,3000) i,f,s,cspread(i) !3000 format(i5,f10.3,3f12.6) - enddo +! enddo ! s=real(cspread(0))**2 + aimag(cspread(0))**2 ! write(13,3000) 1024,0.0,s,cspread(0) From 09686b99584ef6f642fe73475265fe8071efa0ac Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 31 Jul 2020 10:59:05 -0400 Subject: [PATCH 003/206] Add a simulator for experimental mode QRA66. --- CMakeLists.txt | 3 + lib/qra/qra66/qra66sim.f90 | 160 +++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 lib/qra/qra66/qra66sim.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 35ab08fc3..376401c46 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1324,6 +1324,9 @@ target_link_libraries (sumsim wsjt_fort wsjt_cxx) add_executable (qra64sim lib/qra/qra64/qra64sim.f90 wsjtx.rc) target_link_libraries (qra64sim wsjt_fort wsjt_cxx) +add_executable (qra66sim lib/qra/qra66/qra66sim.f90 wsjtx.rc) +target_link_libraries (qra66sim wsjt_fort wsjt_cxx) + add_executable (jt49sim lib/jt49sim.f90 wsjtx.rc) target_link_libraries (jt49sim wsjt_fort wsjt_cxx) diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 new file mode 100644 index 000000000..6043b3aed --- /dev/null +++ b/lib/qra/qra66/qra66sim.f90 @@ -0,0 +1,160 @@ +program qra66sim + +! Generate simulated QRA66 data for testing the decoder. + + use wavhdr + use packjt + parameter (NMAX=15*12000) !180,000 + parameter (NFFT=NMAX,NH=NFFT/2) + type(hdr) h !Header for .wav file + integer*2 iwave(NMAX) !Generated waveform + integer*4 itone(85) !Channel symbols (values 0-65) + real*4 xnoise(NMAX) !Generated random noise + real*4 dat(NMAX) !Generated real data + complex cdat(NMAX) !Generated complex waveform + complex cspread(0:NFFT-1) !Complex amplitude for Rayleigh fading + complex z + real*8 f0,dt,twopi,phi,dphi,baud,fsample,freq + character msg*22,fname*13,csubmode*1,arg*12 + character msgsent*22 + + nargs=iargc() + if(nargs.ne.6) then + print *, 'Usage: qra66sim "msg" A|B fDop DT Nfiles SNR' + print *, 'Example qra66sim "K1ABC W9XYZ EN37" A 0.2 0.0 1 -10' + go to 999 + endif + call getarg(1,msg) + call getarg(2,csubmode) + mode66=2**(ichar(csubmode)-ichar('A')) + call getarg(3,arg) + read(arg,*) fspread + call getarg(4,arg) + read(arg,*) xdt + call getarg(5,arg) + read(arg,*) nfiles + call getarg(6,arg) + read(arg,*) snrdb + + rms=100. + fsample=12000.d0 !Sample rate (Hz) + dt=1.d0/fsample !Sample interval (s) + twopi=8.d0*atan(1.d0) + npts=NMAX !Total samples in .wav file + nsps=1920 + baud=12000.d0/nsps !Keying rate = 6.25 baud + nsym=85 !Number of channel symbols + h=default_header(12000,npts) + ichk=66 !Flag sent to genqra64 + + write(*,1000) +1000 format('File Freq A|B S/N DT Dop Message'/60('-')) + + do ifile=1,nfiles !Loop over requested number of files + write(fname,1002) ifile !Output filename +1002 format('000000_',i6.6) + open(10,file=fname//'.wav',access='stream',status='unknown') + xnoise=0. + cdat=0. + if(snrdb.lt.90) then + do i=1,npts + xnoise(i)=gran() !Generate gaussian noise + enddo + endif + + f0=1500.0 + bandwidth_ratio=2500.0/6000.0 + sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snrdb) + if(snrdb.gt.90.0) sig=1.0 + call genqra64(msg,ichk,msgsent,itone,itype) + write(*,1020) ifile,f0,csubmode,xsnr,xdt,fspread,msgsent +1020 format(i4,f10.3,2x,a1,2x,f5.1,f6.2,f6.1,1x,a22) + phi=0.d0 + dphi=0.d0 + k=(xdt+0.5)*12000 !Start audio at t = xdt + 0.5 s + isym0=-99 + do i=1,npts !Add this signal into cdat() + isym=i/nsps + 1 + if(isym.gt.nsym) exit + if(isym.ne.isym0) then + freq=f0 + itone(isym)*baud*mode66 + dphi=twopi*freq*dt + isym0=isym + endif + phi=phi + dphi + if(phi.gt.twopi) phi=phi-twopi + xphi=phi + z=cmplx(cos(xphi),sin(xphi)) + k=k+1 + if(k.ge.1) cdat(k)=cdat(k) + sig*z + enddo + + if(fspread.ne.0) then !Apply specified Doppler spread + df=12000.0/nfft + cspread(0)=1.0 + cspread(NH)=0. + b=6.0 !Use truncated Lorenzian shape for fspread + do i=1,NH + f=i*df + x=b*f/fspread + z=0. + a=0. + if(x.lt.3.0) then !Cutoff beyond x=3 + a=sqrt(1.111/(1.0+x*x)-0.1) !Lorentzian amplitude + call random_number(r1) + phi1=twopi*r1 !Random phase + z=a*cmplx(cos(phi1),sin(phi1)) + endif + cspread(i)=z + z=0. + if(x.lt.3.0) then !Same thing for negative freqs + call random_number(r2) + phi2=twopi*r2 + z=a*cmplx(cos(phi2),sin(phi2)) + endif + cspread(NFFT-i)=z + enddo + +! do i=0,NFFT-1 +! f=i*df +! if(i.gt.NH) f=(i-nfft)*df +! s=real(cspread(i))**2 + aimag(cspread(i))**2 +! write(13,3000) i,f,s,cspread(i) +!3000 format(i5,f10.3,3f12.6) +! enddo +! s=real(cspread(0))**2 + aimag(cspread(0))**2 +! write(13,3000) 1024,0.0,s,cspread(0) + + call four2a(cspread,NFFT,1,1,1) !Transform to time domain + + sum=0. + do i=0,NFFT-1 + p=real(cspread(i))**2 + aimag(cspread(i))**2 + sum=sum+p + enddo + avep=sum/NFFT + fac=sqrt(1.0/avep) + cspread=fac*cspread !Normalize to constant avg power + cdat=cspread*cdat !Apply Rayleigh fading + +! do i=0,NFFT-1 +! p=real(cspread(i))**2 + aimag(cspread(i))**2 +! write(14,3010) i,p,cspread(i) +!3010 format(i8,3f12.6) +! enddo + endif + + dat=aimag(cdat) + xnoise !Add generated AWGN noise + fac=32767.0 + if(snrdb.ge.90.0) iwave(1:npts)=nint(fac*dat(1:npts)) + if(snrdb.lt.90.0) iwave(1:npts)=nint(rms*dat(1:npts)) + write(10) h,iwave(1:npts) !Save the .wav file + close(10) + +! do i=1,NMAX +! write(15,3020) i/12000.0,iwave(i) +!3020 format(f10.6,i8) +! enddo + enddo + +999 end program qra66sim From 77b7e714249d00871bde27ce4b9eae5a8bfcbff6 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 31 Jul 2020 11:16:03 -0400 Subject: [PATCH 004/206] Enable mode QRA66B in qra66sim. --- lib/qra/qra66/qra66sim.f90 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 index 6043b3aed..934239189 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra66/qra66sim.f90 @@ -42,8 +42,12 @@ program qra66sim twopi=8.d0*atan(1.d0) npts=NMAX !Total samples in .wav file nsps=1920 - baud=12000.d0/nsps !Keying rate = 6.25 baud nsym=85 !Number of channel symbols + if(csubmode.eq.'B') then + nsps=960 + nsym=169 + endif + baud=12000.d0/nsps !Keying rate = 6.25 baud h=default_header(12000,npts) ichk=66 !Flag sent to genqra64 @@ -76,8 +80,9 @@ program qra66sim do i=1,npts !Add this signal into cdat() isym=i/nsps + 1 if(isym.gt.nsym) exit + if(csubmode.eq.'B' .and. isym.gt.84) isym=isym-84 if(isym.ne.isym0) then - freq=f0 + itone(isym)*baud*mode66 + freq=f0 + itone(isym)*baud dphi=twopi*freq*dt isym0=isym endif From 4b0ae524bfedc23c5ca50fd6ded8c0f21fe112db Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Fri, 31 Jul 2020 14:15:49 -0500 Subject: [PATCH 005/206] Set unpk77_success=.false. for messages with i3=0 and n3>6. --- lib/77bit/packjt77.f90 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/77bit/packjt77.f90 b/lib/77bit/packjt77.f90 index a2499625c..a110864fb 100644 --- a/lib/77bit/packjt77.f90 +++ b/lib/77bit/packjt77.f90 @@ -278,6 +278,7 @@ subroutine unpack77(c77,nrx,msg,unpk77_success) read(c77(72:77),'(2b3)') n3,i3 msg=repeat(' ',37) + if(i3.eq.0 .and. n3.eq.0) then ! 0.0 Free text call unpacktext77(c77(1:71),msg(1:13)) @@ -421,7 +422,10 @@ subroutine unpack77(c77,nrx,msg,unpk77_success) endif - + + else if(i3.eq.0 .and. n3.gt.6) then + unpk77_success=.false. + else if(i3.eq.1 .or. i3.eq.2) then ! Type 1 (standard message) or Type 2 ("/P" form for EU VHF contest) read(c77,1000) n28a,ipa,n28b,ipb,ir,igrid4,i3 From c4ef1e3e25d01bfaf2ca2049891de46061b1d3cc Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 31 Jul 2020 16:38:21 -0400 Subject: [PATCH 006/206] Starting on a decoder for QRA66. Now have found xdt and f0 from the sync vector. --- CMakeLists.txt | 2 ++ lib/decoder.f90 | 78 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/jt9.f90 | 7 +++-- 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 376401c46..9726caee0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -377,6 +377,7 @@ set (wsjt_FSRCS lib/options.f90 lib/packjt.f90 lib/77bit/packjt77.f90 + lib/qra66_decode.f90 lib/readwav.f90 lib/timer_C_wrapper.f90 lib/timer_impl.f90 @@ -575,6 +576,7 @@ set (wsjt_FSRCS lib/symspec65.f90 lib/sync4.f90 lib/sync64.f90 + lib/sync66.f90 lib/sync65.f90 lib/ft4/getcandidates4.f90 lib/ft4/get_ft4_bitmetrics.f90 diff --git a/lib/decoder.f90 b/lib/decoder.f90 index a3269aef9..4faae181b 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -9,6 +9,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) use ft8_decode use ft4_decode use fst4_decode + use qra66_decode include 'jt9com.f90' include 'timer_common.inc' @@ -37,6 +38,10 @@ subroutine multimode_decoder(ss,id2,params,nfsample) integer :: decoded end type counting_fst4_decoder + type, extends(qra66_decoder) :: counting_qra66_decoder + integer :: decoded + end type counting_qra66_decoder + real ss(184,NSMAX) logical baddata,newdat65,newdat9,single_decode,bVHF,bad0,newdat,ex integer*2 id2(NTMAX*12000) @@ -54,6 +59,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) type(counting_ft8_decoder) :: my_ft8 type(counting_ft4_decoder) :: my_ft4 type(counting_fst4_decoder) :: my_fst4 + type(counting_qra66_decoder) :: my_qra66 !cast C character arrays to Fortran character strings datetime=transfer(params%datetime, datetime) @@ -69,6 +75,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) my_ft8%decoded = 0 my_ft4%decoded = 0 my_fst4%decoded = 0 + my_qra66%decoded = 0 ! For testing only: return Rx messages stored in a file as decodes inquire(file='rx_messages.txt',exist=ex) @@ -187,6 +194,16 @@ subroutine multimode_decoder(ss,id2,params,nfsample) go to 800 endif + if(params%nmode.eq.66) then +! We're in QRA66 mode + call timer('decqra66',0) + call my_qra66%decode(qra66_decoded,id2,params%nutc,params%nfa, & + params%nfb,params%nfqso,params%ndepth,logical(params%lapcqonly), & + mycall,hiscall,hisgrid) + call timer('decqra66',1) + go to 800 + endif + if(params%nmode.eq.240) then ! We're in FST4 mode ndepth=iand(params%ndepth,3) @@ -759,4 +776,65 @@ contains return end subroutine fst4_decoded + subroutine qra66_decoded (this,nutc,sync,nsnr,dt,freq,decoded,nap, & + qual,ntrperiod,fmid,w50) + + use qra66_decode + implicit none + + class(qra66_decoder), intent(inout) :: this + 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 + + character*2 annot + character*37 decoded0 + character*70 line + + decoded0=decoded + annot=' ' + if(nap.ne.0) then + write(annot,'(a1,i1)') 'a',nap + if(qual.lt.0.17) decoded0(37:37)='?' + endif + + if(ntrperiod.lt.60) then + write(line,1001) nutc,nsnr,dt,nint(freq),decoded0,annot +1001 format(i6.6,i4,f5.1,i5,' ` ',1x,a37,1x,a2) + write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded0 +1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' FST4') + else + write(line,1003) nutc,nsnr,dt,nint(freq),decoded0,annot +1003 format(i4.4,i4,f5.1,i5,' ` ',1x,a37,1x,a2,2f7.3) + write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded0 +1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' FST4') + endif + + if(fmid.ne.-999.0) then + if(w50.lt.0.95) write(line(65:70),'(f6.3)') w50 + if(w50.ge.0.95) write(line(65:70),'(f6.2)') w50 + endif + + write(*,1005) line +1005 format(a70) + + call flush(6) + call flush(13) + + select type(this) + type is (counting_qra66_decoder) + this%decoded = this%decoded + 1 + end select + + return + end subroutine qra66_decoded + end subroutine multimode_decoder diff --git a/lib/jt9.f90 b/lib/jt9.f90 index a08a20cb2..3c017ac18 100644 --- a/lib/jt9.f90 +++ b/lib/jt9.f90 @@ -26,7 +26,7 @@ program jt9 fhigh=4000,nrxfreq=1500,ndepth=1,nexp_decode=0,nQSOProg=0 logical :: read_files = .true., tx9 = .false., display_help = .false., & bLowSidelobes = .false. - type (option) :: long_options(29) = [ & + type (option) :: long_options(30) = [ & option ('help', .false., 'h', 'Display this help message', ''), & option ('shmem',.true.,'s','Use shared memory for sample data','KEY'), & option ('tr-period', .true., 'p', 'Tx/Rx period, default SECONDS=60', & @@ -51,6 +51,7 @@ program jt9 option ('fft-threads', .true., 'm', & 'Number of threads to process large FFTs, default THREADS=1', & 'THREADS'), & + option ('qra66', .false., '3', 'QRA66 mode', ''), & option ('jt4', .false., '4', 'JT4 mode', ''), & option ('ft4', .false., '5', 'FT4 mode', ''), & option ('jt65', .false.,'6', 'JT65 mode', ''), & @@ -86,7 +87,7 @@ program jt9 TRperiod=60.d0 do - call getopt('hs:e:a:b:r:m:p:d:f:w:t:987654WqTL:S:H:c:G:x:g:X:Q:', & + call getopt('hs:e:a:b:r:m:p:d:f:w:t:9876543WqTL:S:H:c:G:x:g:X:Q:', & long_options,c,optarg,arglen,stat,offset,remain,.true.) if (stat .ne. 0) then exit @@ -123,6 +124,8 @@ program jt9 mode = 164 case ('Q') read (optarg(:arglen), *) nQSOProg + case ('3') + mode = 66 case ('4') mode = 4 case ('5') From f45c6174226032596d7e4e3a3893bae30f64c3e8 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 1 Aug 2020 09:24:59 -0400 Subject: [PATCH 007/206] First working QRA66 decoder. --- CMakeLists.txt | 1 + lib/qra/qra66/qra66sim.f90 | 10 ++- lib/qra66_decode.f90 | 157 +++++++++++++++++++++++++++++++++++++ lib/spec66.f90 | 44 +++++++++++ lib/sync66.f90 | 60 ++++++++++++++ 5 files changed, 269 insertions(+), 3 deletions(-) create mode 100644 lib/qra66_decode.f90 create mode 100644 lib/spec66.f90 create mode 100644 lib/sync66.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9726caee0..49cb6ad57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -565,6 +565,7 @@ set (wsjt_FSRCS lib/softsym9w.f90 lib/shell.f90 lib/spec64.f90 + lib/spec66.f90 lib/spec9f.f90 lib/stdmsg.f90 lib/subtract65.f90 diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 index 934239189..a482e4cc3 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra66/qra66sim.f90 @@ -47,12 +47,17 @@ program qra66sim nsps=960 nsym=169 endif + + ichk=66 !Flag sent to genqra64 + call genqra64(msg,ichk,msgsent,itone,itype) + write(*,1001) itone +1001 format('Channel symbols:'/(20i3)) + baud=12000.d0/nsps !Keying rate = 6.25 baud h=default_header(12000,npts) - ichk=66 !Flag sent to genqra64 write(*,1000) -1000 format('File Freq A|B S/N DT Dop Message'/60('-')) +1000 format('File Freq A|B S/N DT Dop Message'/60('-')) do ifile=1,nfiles !Loop over requested number of files write(fname,1002) ifile !Output filename @@ -70,7 +75,6 @@ program qra66sim bandwidth_ratio=2500.0/6000.0 sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snrdb) if(snrdb.gt.90.0) sig=1.0 - call genqra64(msg,ichk,msgsent,itone,itype) write(*,1020) ifile,f0,csubmode,xsnr,xdt,fspread,msgsent 1020 format(i4,f10.3,2x,a1,2x,f5.1,f6.2,f6.1,1x,a22) phi=0.d0 diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 new file mode 100644 index 000000000..53243e78c --- /dev/null +++ b/lib/qra66_decode.f90 @@ -0,0 +1,157 @@ +module qra66_decode + + type :: qra66_decoder + procedure(qra66_decode_callback), pointer :: callback + contains + procedure :: decode + end type qra66_decoder + + abstract interface + subroutine qra66_decode_callback (this,nutc,sync,nsnr,dt,freq, & + decoded,nap,qual,ntrperiod,fmid,w50) + import qra66_decoder + implicit none + class(qra66_decoder), intent(inout) :: this + 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 + end subroutine qra66_decode_callback + end interface + +contains + + subroutine decode(this,callback,iwave,nutc,nfa,nfb,nfqso,ndepth,lapdx, & + mycall,hiscall,hisgrid) + + use timer_module, only: timer + use packjt + use, intrinsic :: iso_c_binding + parameter (NFFT1=15*12000,NFFT2=15*6000) + class(qra66_decoder), intent(inout) :: this + procedure(qra66_decode_callback) :: callback + character(len=12) :: mycall, hiscall + character(len=6) :: hisgrid + character*37 decoded + integer*2 iwave(NFFT1) !Raw data + integer ipk(1) + integer dat4(12) + logical lapdx,ltext + complex c0(0:NFFT1-1) !Spectrum, then analytic signal + real s(900) + real s3a(-64:127,63) + real s3(-64:127,63) + real a(5) + data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ + save + + this%callback => callback + nsps=1920 + baud=12000.0/nsps + df1=12000.0/NFFT1 + + if(nutc.eq.-999) print*,mycall,hiscall,hisgrid,lapdx,ndepth,nfa,nfb,nfqso + +! Prime the QRA decoder for possible use of AP + call packcall(mycall(1:6),nc1,ltext) + call packcall(hiscall(1:6),nc2,ltext) + call packgrid(hisgrid(1:4),ng2,ltext) + nSubmode=0 + b90=1.0 + nFadingModel=1 + maxaptype=4 + if(iand(ndepth,64).ne.0) maxaptype=5 + 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(s3,nc1,nc2,ng2,naptype,1,nSubmode,b90, & + nFadingModel,dat4,snr2,irc) + enddo + nc1z=nc1 + nc2z=nc2 + ng2z=ng2 + maxaptypez=maxaptype + endif + naptype=maxaptype + +! Compute the full-length spectrum + fac=2.0/NFFT1 + c0=fac*iwave + call four2a(c0,NFFT1,1,-1,1) !Forward c2c FFT + + nadd=101 + nh=nadd/2 + df2=nh*df1 + iz=3000.0/df2 + do i=1,iz !Compute smoothed spectrum + s(i)=0. + j0=nh*i + do j=j0-nh,j0+nh + s(i)=s(i) + real(c0(j))**2 + aimag(c0(j))**2 + enddo + enddo + call smo121(s,iz) + ipk=maxloc(s) + f0=df2*ipk(1) - 0.5*baud !Candidate sync frequency + +! do i=1,iz +! write(51,3051) i*df2,s(i) +!3051 format(f12.6,e12.3) +! enddo + + c0(NFFT2/2+1:NFFT2)=0. !Zero the top half + c0(0)=0.5*c0(0) + call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT + call sync66(c0,f0,jpk,sync) !c0 is analytic signal at 6000 S/s + xdt=jpk/6000.0 - 0.5 + + a=0. + a(1)=-(f0 + 1.5*baud) + call twkfreq(c0,c0,85*NSPS,6000.0,a) + call spec66(c0(jpk:jpk+85*NSPS-1),s3a) + s3=s3a/maxval(s3a) +! do j=1,63 +! ipk=maxloc(s3(-64:127,j)) +! write(54,3054) j,ipk(1)-65 +!3054 format(2i8) +! do i=-64,127 +! write(53,3053) i,2*s3(i,j)+j-1 +!3053 format(i8,f12.6) +! enddo +! enddo + + call qra64_dec(s3a,nc1,nc2,ng2,naptype,0,nSubmode,b90, & + nFadingModel,dat4,snr2,irc) + if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) + + 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. + call this%callback(nutc,sYNC,nsnr,xdt,fsig,decoded, & + iaptype,qual,ntrperiod,fmid,w50) + endif +! print*,'QRA66 decoder',nutc,jpk,xdt,f0,sync,snr2,irc,decoded + print*,decoded + + return + end subroutine decode + +end module qra66_decode diff --git a/lib/spec66.f90 b/lib/spec66.f90 new file mode 100644 index 000000000..9242f6a59 --- /dev/null +++ b/lib/spec66.f90 @@ -0,0 +1,44 @@ +subroutine spec66(c0,s3) + + parameter (LL=3*64) !Frequency channels + parameter (NN=63) !Data symbols + parameter (NSPS=960) !Samples per symbol at 6000 Hz + parameter (NMAX=85*NSPS) + complex c0(0:NMAX-1) !Synchrinized complex data + complex cs(0:NSPS-1) !Complex symbol spectrum + real s3(LL,NN) !Synchronized symbol spectra + real xbase0(LL),xbase(LL) + + fac=1.0/NSPS + ja=-NSPS + do j=1,NN + ja=ja+NSPS + if(mod(ja/NSPS,4).eq.0) ja=ja+NSPS + jb=ja+NSPS-1 + cs=fac*c0(ja:jb) + call four2a(cs,NSPS,1,-1,1) !c2c FFT to frequency + do ii=1,LL + i=ii-65 + if(i.lt.0) i=i+NSPS + s3(ii,j)=real(cs(i))**2 + aimag(cs(i))**2 + enddo + enddo + + df=6000.0/NSPS + do i=1,LL + call pctile(s3(i,1:NN),NN,45,xbase0(i)) !Get baseline for passband shape + enddo + + nh=9 + xbase(1:nh-1)=sum(xbase0(1:nh-1))/(nh-1.0) + xbase(LL-nh+1:LL)=sum(xbase0(LL-nh+1:LL))/(nh-1.0) + do i=nh,LL-nh + xbase(i)=sum(xbase0(i-nh+1:i+nh))/(2*nh+1) !Smoothed passband shape + enddo + + do i=1,LL + s3(i,1:NN)=s3(i,1:NN)/(xbase(i)+0.001) !Apply frequency equalization + enddo + + return +end subroutine spec66 diff --git a/lib/sync66.f90 b/lib/sync66.f90 new file mode 100644 index 000000000..bc8b41805 --- /dev/null +++ b/lib/sync66.f90 @@ -0,0 +1,60 @@ +subroutine sync66(c0,f0,jpk,sync) + +! Use the sync vector to find xdt (and improved f0 ?) + + PARAMETER (NMAX=15*6000) + parameter (NSPS=960) !Samples per symbol at 6000 Hz + complex c0(0:NMAX-1) !Complex data at 6000 S/s + complex csync0(0:NSPS-1) + complex csync1(0:NSPS-1) + complex z + integer b11(11) !Barker 11 code + data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 definition + data mode66z/-1/ + save + + twopi=8.0*atan(1.0) + baud=6000.0/NSPS + dt=1.0/6000.0 + + dphi0=twopi*f0**dt + dphi1=twopi*(f0+baud)*dt + phi0=0. + phi1=0. + + do i=0,NSPS-1 !Compute csync for f0 and f0+baud + csync0(i)=cmplx(cos(phi0),sin(phi0)) + csync1(i)=cmplx(cos(phi1),sin(phi1)) + phi0=phi0 + dphi0 + phi1=phi1 + dphi1 + if(phi0.gt.twopi) phi0=phi0-twopi + if(phi1.gt.twopi) phi1=phi1-twopi + enddo + + sqmax=0. + jstep=NSPS/8 + do j0=0,6000,jstep + sq=0. + do k=1,22 + i=k + if(i.gt.11) i=i-11 + j1=j0 + 4*(k-1)*NSPS + if(b11(i).eq.0) then + z=dot_product(c0(j1:j1+NSPS-1),csync0) + else + z=dot_product(c0(j1:j1+NSPS-1),csync1) + endif + z=0.001*z + sq=sq + real(z)**2 + aimag(z)**2 + enddo + write(52,3052) j0/6000.0,sq,j0,j1 +3052 format(f10.6,f12.3,2i8) + if(sq.gt.smax) then + smax=sq + jpk=j0 + endif + enddo + sync=smax + + return +end subroutine sync66 From e751a4404f945411065700a82add4fdee1935cdd Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Sat, 1 Aug 2020 10:58:21 -0500 Subject: [PATCH 008/206] Use squared metric for fst4 - works better on fading channel. --- lib/fst4/get_fst4_bitmetrics.f90 | 2 +- lib/fst4/get_fst4_bitmetrics2.f90 | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/fst4/get_fst4_bitmetrics.f90 b/lib/fst4/get_fst4_bitmetrics.f90 index 76a00dc2e..125777568 100644 --- a/lib/fst4/get_fst4_bitmetrics.f90 +++ b/lib/fst4/get_fst4_bitmetrics.f90 @@ -105,7 +105,7 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,badsync) csum=csum+cs(graymap(ntone),ks+j)*cterm cterm=cterm*conjg(cp(graymap(ntone))) enddo - s2(i)=abs(csum) + s2(i)=abs(csum)**2 enddo ipt=1+(ks-1)*2 if(nsym.eq.1) ibmax=1 diff --git a/lib/fst4/get_fst4_bitmetrics2.f90 b/lib/fst4/get_fst4_bitmetrics2.f90 index da0a6a230..6a669bd4c 100644 --- a/lib/fst4/get_fst4_bitmetrics2.f90 +++ b/lib/fst4/get_fst4_bitmetrics2.f90 @@ -49,21 +49,21 @@ subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4hmod,badsync) i1=(k-1)*NSS csymb=cd(i1:i1+NSS-1) do itone=0,3 - s4(itone,k,1)=abs(sum(csymb*conjg(c1(:,itone)))) - s4(itone,k,2)=abs(sum(csymb( 1:nss/2)*conjg(c1( 1:nss/2,itone)))) + & - abs(sum(csymb(nss/2+1: nss)*conjg(c1(nss/2+1: nss,itone)))) - s4(itone,k,3)=abs(sum(csymb( 1: nss/4)*conjg(c1( 1: nss/4,itone)))) + & - abs(sum(csymb( nss/4+1: nss/2)*conjg(c1( nss/4+1: nss/2,itone)))) + & - abs(sum(csymb( nss/2+1:3*nss/4)*conjg(c1( nss/2+1:3*nss/4,itone)))) + & - abs(sum(csymb(3*nss/4+1: nss)*conjg(c1(3*nss/4+1: nss,itone)))) - s4(itone,k,4)=abs(sum(csymb( 1: nss/8)*conjg(c1( 1: nss/8,itone)))) + & - abs(sum(csymb( nss/8+1: nss/4)*conjg(c1( nss/8+1: nss/4,itone)))) + & - abs(sum(csymb( nss/4+1:3*nss/8)*conjg(c1( nss/4+1:3*nss/8,itone)))) + & - abs(sum(csymb(3*nss/8+1: nss/2)*conjg(c1(3*nss/8+1: nss/2,itone)))) + & - abs(sum(csymb( nss/2+1:5*nss/8)*conjg(c1( nss/2+1:5*nss/8,itone)))) + & - abs(sum(csymb(5*nss/8+1:3*nss/4)*conjg(c1(5*nss/8+1:3*nss/4,itone)))) + & - abs(sum(csymb(3*nss/4+1:7*nss/8)*conjg(c1(3*nss/4+1:7*nss/8,itone)))) + & - abs(sum(csymb(7*nss/8+1: nss)*conjg(c1(7*nss/8+1: nss,itone)))) + s4(itone,k,1)=abs(sum(csymb*conjg(c1(:,itone))))**2 + s4(itone,k,2)=abs(sum(csymb( 1:nss/2)*conjg(c1( 1:nss/2,itone))))**2 + & + abs(sum(csymb(nss/2+1: nss)*conjg(c1(nss/2+1: nss,itone))))**2 + s4(itone,k,3)=abs(sum(csymb( 1: nss/4)*conjg(c1( 1: nss/4,itone))))**2 + & + abs(sum(csymb( nss/4+1: nss/2)*conjg(c1( nss/4+1: nss/2,itone))))**2 + & + abs(sum(csymb( nss/2+1:3*nss/4)*conjg(c1( nss/2+1:3*nss/4,itone))))**2 + & + abs(sum(csymb(3*nss/4+1: nss)*conjg(c1(3*nss/4+1: nss,itone))))**2 + s4(itone,k,4)=abs(sum(csymb( 1: nss/8)*conjg(c1( 1: nss/8,itone))))**2 + & + abs(sum(csymb( nss/8+1: nss/4)*conjg(c1( nss/8+1: nss/4,itone))))**2 + & + abs(sum(csymb( nss/4+1:3*nss/8)*conjg(c1( nss/4+1:3*nss/8,itone))))**2 + & + abs(sum(csymb(3*nss/8+1: nss/2)*conjg(c1(3*nss/8+1: nss/2,itone))))**2 + & + abs(sum(csymb( nss/2+1:5*nss/8)*conjg(c1( nss/2+1:5*nss/8,itone))))**2 + & + abs(sum(csymb(5*nss/8+1:3*nss/4)*conjg(c1(5*nss/8+1:3*nss/4,itone))))**2 + & + abs(sum(csymb(3*nss/4+1:7*nss/8)*conjg(c1(3*nss/4+1:7*nss/8,itone))))**2 + & + abs(sum(csymb(7*nss/8+1: nss)*conjg(c1(7*nss/8+1: nss,itone))))**2 enddo enddo From 3867c452e60a4989f97bfcac2f8ad5ae0006a09b Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 1 Aug 2020 12:13:49 -0400 Subject: [PATCH 009/206] Changes to GUI to accommodate QRA66. It's basically functional, I think. --- lib/decoder.f90 | 38 +++++------------------------- lib/qra66_decode.f90 | 9 ++++--- widgets/mainwindow.cpp | 53 +++++++++++++++++++++++++++++++++++------- widgets/mainwindow.h | 2 ++ widgets/mainwindow.ui | 9 +++++++ 5 files changed, 66 insertions(+), 45 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 4faae181b..41f1d0f7e 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -776,7 +776,7 @@ contains return end subroutine fst4_decoded - subroutine qra66_decoded (this,nutc,sync,nsnr,dt,freq,decoded,nap, & + subroutine qra66_decoded (this,nutc,sync,nsnr,dt,freq,decoded,irc, & qual,ntrperiod,fmid,w50) use qra66_decode @@ -789,42 +789,16 @@ contains real, intent(in) :: dt real, intent(in) :: freq character(len=37), intent(in) :: decoded - integer, intent(in) :: nap + integer, intent(in) :: irc real, intent(in) :: qual integer, intent(in) :: ntrperiod real, intent(in) :: fmid real, intent(in) :: w50 - character*2 annot - character*37 decoded0 - character*70 line - - decoded0=decoded - annot=' ' - if(nap.ne.0) then - write(annot,'(a1,i1)') 'a',nap - if(qual.lt.0.17) decoded0(37:37)='?' - endif - - if(ntrperiod.lt.60) then - write(line,1001) nutc,nsnr,dt,nint(freq),decoded0,annot -1001 format(i6.6,i4,f5.1,i5,' ` ',1x,a37,1x,a2) - write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded0 -1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' FST4') - else - write(line,1003) nutc,nsnr,dt,nint(freq),decoded0,annot -1003 format(i4.4,i4,f5.1,i5,' ` ',1x,a37,1x,a2,2f7.3) - write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded0 -1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' FST4') - endif - - if(fmid.ne.-999.0) then - if(w50.lt.0.95) write(line(65:70),'(f6.3)') w50 - if(w50.ge.0.95) write(line(65:70),'(f6.2)') w50 - endif - - write(*,1005) line -1005 format(a70) + write(*,1001) nutc,nsnr,dt,nint(freq),decoded,irc +1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2) + write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded +1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA66') call flush(6) call flush(13) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 53243e78c..d402acc15 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -52,6 +52,8 @@ contains data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ save +! print*,nutc,nfa,nfb,nfqso,ndepth,lapdx,mycall,hiscall,hisgrid + this%callback => callback nsps=1920 baud=12000.0/nsps @@ -141,15 +143,12 @@ contains decoded=' ' irc=-1 endif - nft=100 + irc nsnr=nint(snr2) + call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & + irc,qual,ntrperiod,fmid,w50) else snr2=0. - call this%callback(nutc,sYNC,nsnr,xdt,fsig,decoded, & - iaptype,qual,ntrperiod,fmid,w50) endif -! print*,'QRA66 decoder',nutc,jpk,xdt,f0,sync,snr2,irc,decoded - print*,decoded return end subroutine decode diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 528184278..ceea26659 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -592,6 +592,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionISCAT->setActionGroup(modeGroup); ui->actionMSK144->setActionGroup(modeGroup); ui->actionQRA64->setActionGroup(modeGroup); + ui->actionQRA66->setActionGroup(modeGroup); ui->actionFreqCal->setActionGroup(modeGroup); QActionGroup* saveGroup = new QActionGroup(this); @@ -1365,6 +1366,8 @@ void MainWindow::fixStop() } else if (m_mode=="QRA64"){ m_hsymStop=179; if(m_config.decode_at_52s()) m_hsymStop=186; + } else if (m_mode=="QRA66"){ + m_hsymStop=49; } else if (m_mode=="FreqCal"){ m_hsymStop=((int(m_TRperiod/0.288))/8)*8; } else if (m_mode=="FT8") { @@ -2341,6 +2344,8 @@ void MainWindow::setup_status_bar (bool vhf) mode_label.setStyleSheet ("QLabel{background-color: #66ff66}"); } else if ("QRA64" == m_mode) { mode_label.setStyleSheet ("QLabel{background-color: #99ff33}"); + } else if ("QRA66" == m_mode) { + mode_label.setStyleSheet ("QLabel{background-color: #99ff33}"); } else if ("MSK144" == m_mode) { mode_label.setStyleSheet ("QLabel{background-color: #ff6666}"); } else if ("FT4" == m_mode) { @@ -2540,8 +2545,8 @@ void MainWindow::on_actionCopyright_Notice_triggered() "General Public License, you must display the following copyright " "notice prominently in your derivative work:\n\n" "\"The algorithms, source code, look-and-feel of WSJT-X and related " - "programs, and protocol specifications for the modes FSK441, FT8, JT4, " - "JT6M, JT9, JT65, JTMS, QRA64, ISCAT, MSK144 are Copyright (C) " + "programs, and protocol specifications for the modes FSK441, FST4, FT8, " + "JT4, JT6M, JT9, JT65, JTMS, QRA64, QRA66, ISCAT, MSK144 are Copyright (C) " "2001-2020 by one or more of the following authors: Joseph Taylor, " "K1JT; Bill Somerville, G4WJS; Steven Franke, K9AN; Nico Palermo, " "IV3NWV; Greg Beam, KI7MT; Michael Black, W9MDB; Edson Pereira, PY2SDR; " @@ -3065,6 +3070,8 @@ void MainWindow::decode() //decode() ui->actionEnable_AP_JT65->isChecked (); if(m_mode=="QRA64") dec_data.params.nmode=164; if(m_mode=="QRA64") dec_data.params.ntxmode=164; + if(m_mode=="QRA66") dec_data.params.nmode=66; + if(m_mode=="QRA66") dec_data.params.ntxmode=66; if(m_mode=="JT9+JT65") dec_data.params.nmode=9+65; // = 74 if(m_mode=="JT4") { dec_data.params.nmode=4; @@ -3465,8 +3472,8 @@ void MainWindow::readFromStdout() //readFromStdout //### I think this is where we are preventing Hounds from spotting Fox ### if(m_mode!="FT8" or (SpecOp::HOUND != m_config.special_op_id())) { - if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="QRA64" or m_mode=="JT4" - or m_mode=="JT65" or m_mode=="JT9" or m_mode=="FST4") { + if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="QRA64" or m_mode=="QRA66" + or m_mode=="JT4" or m_mode=="JT65" or m_mode=="JT9" or m_mode=="FST4") { auto_sequence (decodedtext, 25, 50); } @@ -3677,6 +3684,7 @@ void MainWindow::guiUpdate() if(m_modeTx=="JT9") txDuration=1.0 + 85.0*m_nsps/12000.0; // JT9 if(m_modeTx=="JT65") txDuration=1.0 + 126*4096/11025.0; // JT65 if(m_modeTx=="QRA64") txDuration=1.0 + 84*6912/12000.0; // QRA64 + if(m_modeTx=="QRA66") txDuration=0.5 + 85*1920/12000.0; // QRA66 if(m_modeTx=="WSPR") txDuration=2.0 + 162*8192/12000.0; // WSPR if(m_modeTx=="FST4" or m_mode=="FST4W") { //FST4, FST4W if(m_TRperiod==15) txDuration=1.0 + 160*720/12000.0; @@ -3936,6 +3944,11 @@ void MainWindow::guiUpdate() &m_currentMessageType, 22, 22); if(m_modeTx=="QRA64") genqra64_(message, &ichk, msgsent, const_cast (itone), &m_currentMessageType, 22, 22); + if(m_modeTx=="QRA66") { + int ichk66=66; + genqra64_(message, &ichk66, msgsent, const_cast (itone), + &m_currentMessageType, 22, 22); + } if(m_modeTx=="WSPR") genwspr_(message, msgsent, const_cast (itone), 22, 22); if(m_modeTx=="MSK144" or m_modeTx=="FT8" or m_modeTx=="FT4" @@ -4669,7 +4682,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie || ("JT9" == m_mode && mode != "@") || ("MSK144" == m_mode && !("&" == mode || "^" == mode)) || ("QRA64" == m_mode && mode.left (1) != ":")) { - return; //Currently we do auto-sequencing only in FT4, FT8, MSK144, and FST4 + return; //Currently we do auto-sequencing only in FT4, FT8, MSK144, FST4, and QRA66 } //Skip the rest if no decoded text extracted @@ -4777,7 +4790,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie ui->TxFreqSpinBox->setValue(frequency); } if(m_mode != "JT4" && m_mode != "JT65" && !m_mode.startsWith ("JT9") && - m_mode != "QRA64" && m_mode!="FT8" && m_mode!="FT4") { + m_mode != "QRA64" && m_mode != "QRA66" && m_mode!="FT8" && m_mode!="FT4") { return; } } @@ -6401,6 +6414,20 @@ void MainWindow::on_actionQRA64_triggered() statusChanged(); } +void MainWindow::on_actionQRA66_triggered() +{ + on_actionFST4_triggered(); + m_mode="QRA66"; + m_modeTx="QRA66"; + ui->actionQRA66->setChecked(true); + switch_mode (Modes::QRA64); + setup_status_bar (false); + m_hsymStop=49; + m_wideGraph->setMode(m_mode); + m_wideGraph->setModeTx(m_modeTx); + m_TRperiod=15.0; +} + void MainWindow::on_actionISCAT_triggered() { m_mode="ISCAT"; @@ -6449,8 +6476,9 @@ void MainWindow::on_actionMSK144_triggered() if("JT65"==m_mode) ui->actionJT65->setChecked(true); if("JT9_JT65"==m_mode) ui->actionJT9_JT65->setChecked(true); if("ISCAT"==m_mode) ui->actionISCAT->setChecked(true); - if("QRA64"==m_mode) ui->actionQRA64->setChecked(true); - if("WSPR"==m_mode) ui->actionWSPR->setChecked(true); + if("QRA64"==m_mode) ui->actionQRA64->setChecked(true); + if("QRA66"==m_mode) ui->actionQRA66->setChecked(true); + if("WSPR"==m_mode) ui->actionWSPR->setChecked(true); if("Echo"==m_mode) ui->actionEcho->setChecked(true); if("FreqCal"==m_mode) ui->actionFreqCal->setChecked(true); if("FST4"==m_mode) ui->actionFST4->setChecked(true); @@ -7358,6 +7386,14 @@ void MainWindow::transmit (double snr) true, false, snr, m_TRperiod); } + if (m_modeTx == "QRA66") { + toneSpacing=12000.0/1920.0; + Q_EMIT sendMessage (m_mode, NUM_QRA66_SYMBOLS, + 1920.0, ui->TxFreqSpinBox->value () - m_XIT, + toneSpacing, m_soundOutput, m_config.audio_output_channel (), + true, false, snr, m_TRperiod); + } + if (m_modeTx == "JT9") { int nsub=pow(2,m_nSubMode); int nsps[]={480,240,120,60}; @@ -9278,6 +9314,7 @@ void MainWindow::set_mode (QString const& mode) else if ("JT9+JT65" == mode) on_actionJT9_JT65_triggered (); else if ("JT65" == mode) on_actionJT65_triggered (); else if ("QRA64" == mode) on_actionQRA64_triggered (); + else if ("QRA66" == mode) on_actionQRA66_triggered (); else if ("FreqCal" == mode) on_actionFreqCal_triggered (); else if ("ISCAT" == mode) on_actionISCAT_triggered (); else if ("MSK144" == mode) on_actionMSK144_triggered (); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 79f65d080..ed528cc26 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -48,6 +48,7 @@ #define NUM_ISCAT_SYMBOLS 1291 //30*11025/256 #define NUM_MSK144_SYMBOLS 144 //s8 + d48 + s8 + d80 #define NUM_QRA64_SYMBOLS 84 //63 data + 21 sync +#define NUM_QRA66_SYMBOLS 85 //63 data + 22 sync #define NUM_FT8_SYMBOLS 79 #define NUM_FT4_SYMBOLS 105 #define NUM_FST4_SYMBOLS 160 //240/2 data + 5*8 sync @@ -305,6 +306,7 @@ private slots: void on_cbCQTx_toggled(bool b); void on_actionMSK144_triggered(); void on_actionQRA64_triggered(); + void on_actionQRA66_triggered(); void on_actionFreqCal_triggered(); void splash_done (); void on_measure_check_box_stateChanged (int); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index c777609b0..c586e9892 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -3001,6 +3001,7 @@ QLabel[oob="true"] { + @@ -3642,6 +3643,14 @@ QLabel[oob="true"] { Also FST4W + + + true + + + QRA66 + + From e32c5b699d709bc9ae130b34f5a0c184227305c0 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 1 Aug 2020 13:37:31 -0400 Subject: [PATCH 010/206] Update Wide Graph and plotter.cpp for QRA66. --- widgets/mainwindow.cpp | 3 ++- widgets/plotter.cpp | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index ceea26659..0fc6ec684 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6423,9 +6423,10 @@ void MainWindow::on_actionQRA66_triggered() switch_mode (Modes::QRA64); setup_status_bar (false); m_hsymStop=49; + m_TRperiod=15.0; m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); - m_TRperiod=15.0; + m_wideGraph->setPeriod(m_TRperiod,6912); } void MainWindow::on_actionISCAT_triggered() diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index c21d7e5f0..15057f4a8 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -471,6 +471,9 @@ void CPlotter::DrawOverlay() //DrawOverlay() if(m_nSubMode==4) bw=16*bw; //E } + if(m_mode=="QRA66") { //QRA66 + bw=65.0*12000.0/1920.0; + } if(m_modeTx=="JT65") { //JT65 bw=65.0*11025.0/4096.0; if(m_nSubMode==1) bw=2*bw; //B @@ -502,7 +505,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() int yTxTop=12; int yRxBottom=yTxTop + 2*yh + 4; if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" - or m_mode=="QRA64" or m_mode=="FT8" or m_mode=="FT4" + or m_mode=="QRA64" or m_mode=="QRA66" or m_mode=="FT8" or m_mode=="FT4" or m_mode.startsWith("FST4")) { if(m_mode=="QRA64" or (m_mode=="JT65" and m_bVHF)) { @@ -543,7 +546,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() } if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or - m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="FT8" + m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="QRA66" or m_mode=="FT8" or m_mode=="FT4" or m_mode.startsWith("FST4")) { painter0.setPen(penRed); x1=XfromFreq(m_txFreq); From 910e8bfd816ec3190cd998bb55962233f99fc3b1 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 1 Aug 2020 13:52:52 -0400 Subject: [PATCH 011/206] Correct the Tx start time for QRA66 in Modulator.cpp. --- Modulator/Modulator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modulator/Modulator.cpp b/Modulator/Modulator.cpp index 52319eb2a..bd19f374b 100644 --- a/Modulator/Modulator.cpp +++ b/Modulator/Modulator.cpp @@ -70,7 +70,7 @@ void Modulator::start (QString mode, unsigned symbolsLength, double framesPerSym m_bFastMode=fastMode; m_TRperiod=TRperiod; unsigned delay_ms=1000; - if(mode=="FT8" or (mode=="FST4" and m_nsps==720)) delay_ms=500; //FT8, FST4-15 + if(mode=="FT8" or (mode=="FST4" and m_nsps==720) or mode=="QRA66") delay_ms=500; //FT8, FST4-15, QRA66 if(mode=="FT4") delay_ms=300; //FT4 // noise generator parameters From fb3c23492f22f5253b669cf380c3b180851c2c27 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 1 Aug 2020 15:12:37 -0400 Subject: [PATCH 012/206] Adjustments to the QRA66 decoder. Still need to implement looping over b90 values. --- lib/qra66_decode.f90 | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index d402acc15..749fccd9c 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -50,23 +50,21 @@ contains real s3(-64:127,63) real a(5) data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ - save - -! print*,nutc,nfa,nfb,nfqso,ndepth,lapdx,mycall,hiscall,hisgrid + save nc1z,nc2z,ng2z,maxaptypez this%callback => callback nsps=1920 baud=12000.0/nsps df1=12000.0/NFFT1 - if(nutc.eq.-999) print*,mycall,hiscall,hisgrid,lapdx,ndepth,nfa,nfb,nfqso + if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning ! Prime the QRA decoder for possible use of AP call packcall(mycall(1:6),nc1,ltext) call packcall(hiscall(1:6),nc2,ltext) call packgrid(hisgrid(1:4),ng2,ltext) nSubmode=0 - b90=1.0 + b90=10.0 nFadingModel=1 maxaptype=4 if(iand(ndepth,64).ne.0) maxaptype=5 @@ -115,11 +113,14 @@ contains call sync66(c0,f0,jpk,sync) !c0 is analytic signal at 6000 S/s xdt=jpk/6000.0 - 0.5 +! write(*,3003) jpk,f0,sync +!3003 format('A',i6,f8.2,f12.1) + a=0. a(1)=-(f0 + 1.5*baud) call twkfreq(c0,c0,85*NSPS,6000.0,a) call spec66(c0(jpk:jpk+85*NSPS-1),s3a) - s3=s3a/maxval(s3a) +! s3=s3a/maxval(s3a) ! do j=1,63 ! ipk=maxloc(s3(-64:127,j)) ! write(54,3054) j,ipk(1)-65 @@ -148,8 +149,15 @@ contains irc,qual,ntrperiod,fmid,w50) else snr2=0. + nsnr=nint(db(sync)) +!### TEMPORARY? ### + call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & + irc,qual,ntrperiod,fmid,w50) +!### endif - +! write(*,3001) snr2,xdt,f0,decoded(1:22) +!3001 format('B',f5.1,f6.2,f7.1,2x,a22) + return end subroutine decode From 45dac5bd18295fd16da6ae3177f75416d3869ed7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 2 Aug 2020 09:42:22 -0400 Subject: [PATCH 013/206] Change random number generation in qra66sim so results are exactly repeateble. --- lib/gran.c | 6 ++++++ lib/qra/qra66/qra66sim.f90 | 6 ++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/gran.c b/lib/gran.c index 24b986503..ac41c7fe4 100644 --- a/lib/gran.c +++ b/lib/gran.c @@ -26,3 +26,9 @@ float gran_() iset++; return v2*fac; } + +/* Generates evenly distributed numbers between 0 and 1. */ +float rran_() +{ + return (float)rand()/(float)RAND_MAX; +} diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 index a482e4cc3..0e1910490 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra66/qra66sim.f90 @@ -110,15 +110,13 @@ program qra66sim a=0. if(x.lt.3.0) then !Cutoff beyond x=3 a=sqrt(1.111/(1.0+x*x)-0.1) !Lorentzian amplitude - call random_number(r1) - phi1=twopi*r1 !Random phase + phi1=twopi*rran() !Random phase z=a*cmplx(cos(phi1),sin(phi1)) endif cspread(i)=z z=0. if(x.lt.3.0) then !Same thing for negative freqs - call random_number(r2) - phi2=twopi*r2 + phi2=twopi*rran() z=a*cmplx(cos(phi2),sin(phi2)) endif cspread(NFFT-i)=z From dd471c6b5e8e2f7bd4a364891855d828007c8281 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 2 Aug 2020 11:15:10 -0400 Subject: [PATCH 014/206] Improvements to QRA66 decoder. Still needs work. --- lib/qra66_decode.f90 | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 749fccd9c..8891d394a 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -64,10 +64,15 @@ contains call packcall(hiscall(1:6),nc2,ltext) call packgrid(hisgrid(1:4),ng2,ltext) nSubmode=0 - b90=10.0 + b90=20 nFadingModel=1 - maxaptype=4 - if(iand(ndepth,64).ne.0) maxaptype=5 + +! These probably need work: + maxaptype=0 + if(ndepth.eq.2) maxaptype=3 + if(ndepth.eq.3) maxaptype=11 + +! Prime the decoder for possible AP decoding if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & maxaptype.ne.maxaptypez) then do naptype=0,maxaptype @@ -119,18 +124,24 @@ contains a=0. a(1)=-(f0 + 1.5*baud) call twkfreq(c0,c0,85*NSPS,6000.0,a) - call spec66(c0(jpk:jpk+85*NSPS-1),s3a) -! s3=s3a/maxval(s3a) + call spec66(c0(jpk:jpk+85*NSPS-1),s3) + s3a=s3/maxval(s3) ! do j=1,63 -! ipk=maxloc(s3(-64:127,j)) +! ipk=maxloc(s3a(-64:127,j)) ! write(54,3054) j,ipk(1)-65 !3054 format(2i8) ! do i=-64,127 -! write(53,3053) i,2*s3(i,j)+j-1 +! write(53,3053) i,2*s3a(i,j)+j-1 !3053 format(i8,f12.6) ! enddo ! enddo - + + call pctile(s3a,192*63,40,base) + s3a=s3a/base + print*,'A',maxval(s3a),ndepth,maxaptype,naptype + s3lim=10. + where(s3a(-64:127,1:63)>s3lim) s3a(-64:127,1:63)=s3lim + call qra64_dec(s3a,nc1,nc2,ng2,naptype,0,nSubmode,b90, & nFadingModel,dat4,snr2,irc) if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) From dc5d85f850726fe44089eaf8ee82d0a768ee55d1 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 2 Aug 2020 11:40:03 -0400 Subject: [PATCH 015/206] Remove a diagnostic print. Correct the maxAP value. --- lib/qra66_decode.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 8891d394a..289c34427 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -70,7 +70,7 @@ contains ! These probably need work: maxaptype=0 if(ndepth.eq.2) maxaptype=3 - if(ndepth.eq.3) maxaptype=11 + if(ndepth.eq.3) maxaptype=5 ! Prime the decoder for possible AP decoding if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & @@ -138,7 +138,7 @@ contains call pctile(s3a,192*63,40,base) s3a=s3a/base - print*,'A',maxval(s3a),ndepth,maxaptype,naptype +! print*,'A',maxval(s3a),ndepth,maxaptype,naptype s3lim=10. where(s3a(-64:127,1:63)>s3lim) s3a(-64:127,1:63)=s3lim From 2846a6422a6eae46234f5d1df025fb0680599849 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 2 Aug 2020 13:33:15 -0400 Subject: [PATCH 016/206] Temporary: limit Rx search range to 15-- +/- 50 Hz. --- lib/qra66_decode.f90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 289c34427..c605d0694 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -104,6 +104,10 @@ contains enddo enddo call smo121(s,iz) + ia=1450/df2 + ib=1550/df2 + s(:ia)=0. + s(ib:)=0. ipk=maxloc(s) f0=df2*ipk(1) - 0.5*baud !Candidate sync frequency From c91baddb2ced6d8f784e79898b8b5ee986acc145 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 3 Aug 2020 16:30:29 -0400 Subject: [PATCH 017/206] New sync66a subroutine for QRA66. --- CMakeLists.txt | 5 ++- lib/qra66_decode.f90 | 34 ++++++++-------- lib/sync66a.f90 | 94 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 19 deletions(-) create mode 100644 lib/sync66a.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e24f521c..fe32cc8f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -577,7 +577,7 @@ set (wsjt_FSRCS lib/symspec65.f90 lib/sync4.f90 lib/sync64.f90 - lib/sync66.f90 + lib/sync66a.f90 lib/sync65.f90 lib/ft4/getcandidates4.f90 lib/ft4/get_ft4_bitmetrics.f90 @@ -1327,6 +1327,9 @@ target_link_libraries (qra64sim wsjt_fort wsjt_cxx) add_executable (qra66sim lib/qra/qra66/qra66sim.f90 wsjtx.rc) target_link_libraries (qra66sim wsjt_fort wsjt_cxx) +#add_executable (test_sync66 lib/test_sync66.f90 wsjtx.rc) +#target_link_libraries (test_sync66 wsjt_fort wsjt_cxx) + add_executable (jt49sim lib/jt49sim.f90 wsjtx.rc) target_link_libraries (jt49sim wsjt_fort wsjt_cxx) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index c605d0694..fc907c73f 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -119,30 +119,30 @@ contains c0(NFFT2/2+1:NFFT2)=0. !Zero the top half c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT - call sync66(c0,f0,jpk,sync) !c0 is analytic signal at 6000 S/s - xdt=jpk/6000.0 - 0.5 +! call sync66(c0,f0,jpk,sync) !c0 is analytic signal at 6000 S/s -! write(*,3003) jpk,f0,sync -!3003 format('A',i6,f8.2,f12.1) + ntol=100 + call sync66a(iwave,15*12000,nsps,nfqso,ntol,xdt,f0) + jpk=(xdt+0.5)*6000 + if(jpk.lt.0) jpk=0 + +! Genie sync: +! jpk=3600 +! xdt=jpk/6000.0 - 0.5 +! f0=1510 +! f0=1490 a=0. - a(1)=-(f0 + 1.5*baud) - call twkfreq(c0,c0,85*NSPS,6000.0,a) +! a(1)=-(f0 + 1.5*baud) !For sync66 + a(1)=-(f0 + 2.0*baud) !For sync66a + + + call twkfreq(c0,c0,15*6000,6000.0,a) call spec66(c0(jpk:jpk+85*NSPS-1),s3) s3a=s3/maxval(s3) -! do j=1,63 -! ipk=maxloc(s3a(-64:127,j)) -! write(54,3054) j,ipk(1)-65 -!3054 format(2i8) -! do i=-64,127 -! write(53,3053) i,2*s3a(i,j)+j-1 -!3053 format(i8,f12.6) -! enddo -! enddo call pctile(s3a,192*63,40,base) s3a=s3a/base -! print*,'A',maxval(s3a),ndepth,maxaptype,naptype s3lim=10. where(s3a(-64:127,1:63)>s3lim) s3a(-64:127,1:63)=s3lim @@ -170,8 +170,6 @@ contains irc,qual,ntrperiod,fmid,w50) !### endif -! write(*,3001) snr2,xdt,f0,decoded(1:22) -!3001 format('B',f5.1,f6.2,f7.1,2x,a22) return end subroutine decode diff --git a/lib/sync66a.f90 b/lib/sync66a.f90 new file mode 100644 index 000000000..ba88616cb --- /dev/null +++ b/lib/sync66a.f90 @@ -0,0 +1,94 @@ +subroutine sync66a(iwave,nmax,nsps,nfqso,ntol,xdt,f0) + + parameter (NSTEP=4) !Quarter-symbol steps + parameter (IZ=1600,JZ=352,NSPSMAX=1920) + integer*2 iwave(0:nmax-1) !Raw data + integer b11(11) !Barker 11 code + integer ijpk(2) !Indices i and j at peak of sync_sig + real s1(IZ,JZ) !Symbol spectra + real x(JZ) !Work array; 2FSK sync modulation + real sync(4*85) !sync vector + real sync_sig(-64:64,-15:15) + complex c0(0:NSPSMAX) !Complex spectrum of symbol + data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 code + data sync(1)/99.0/ + save sync + + if(sync(1).eq.99.0) then + sync=0. + do k=1,22 + kk=k + if(kk.gt.11) kk=k-11 + sync(16*k-15)=2.0*b11(kk) - 1.0 + enddo + endif + + nfft=2*NSPS + df=12000.0/nfft !3.125 Hz + istep=nsps/NSTEP + fac=1/32767.0 + do j=1,JZ !Compute symbol spectra + ia=(j-1)*istep + ib=ia+nsps-1 + k=-1 + do i=ia,ib,2 + xx=iwave(i) + yy=iwave(i+1) + k=k+1 + c0(k)=fac*cmplx(xx,yy) + enddo + c0(k+1:nfft/2)=0. + call four2a(c0,nfft,1,-1,0) !r2c FFT + do i=1,IZ + s1(i,j)=real(c0(i))**2 + aimag(c0(i))**2 + enddo + enddo + + i0=nint(nfqso/df) + call pctile(s1(i0-64:i0+192,1:JZ),129*JZ,40,base) + s1=s1/base + s1max=20.0 + +! Make this simpler: just add the 22 nonzero values. + do j=1,JZ + x(j)=maxval(s1(i0-64:i0+192,j)) + if(x(j).gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/x(j) + enddo + + dt4=nsps/(NSTEP*12000.0) + j0=0.5/dt4 + + sync_sig=0. + ia=min(64,nint(ntol/df)) + do i=-ia,ia + x=s1(i0+2+i,:)-s1(i0+i,:) + do lag=-15,15 + do n=1,4*85 + j=n+lag+11 + if(j.ge.1 .and. j.le.JZ) sync_sig(i,lag)=sync_sig(i,lag) + sync(n)*x(j) + enddo + enddo + enddo + + ijpk=maxloc(sync_sig) + ii=ijpk(1)-65 + jj=ijpk(2)-16 + +! Use peakup() here? + f0=nfqso + ii*df + jdt=jj + tsym=nsps/12000.0 + xdt=jdt*tsym/4.0 + +! do i=-64,64 +! write(13,3013) nfqso+i*df,sync_sig(i,jj) +!3013 format(2f12.3) +! enddo + +! do j=-15,15 +! write(14,3014) j,j*dt4,sync_sig(ii,j) +!3014 format(i5,2f12.3) +! enddo + + return +end subroutine sync66a From 802f078386244fe5e30f63b7718c2a7912985f7c Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Tue, 4 Aug 2020 09:15:44 -0500 Subject: [PATCH 018/206] Fix SNR calculation for B,C,D submodes. --- lib/fst4/get_fst4_bitmetrics.f90 | 2 +- lib/fst4/get_fst4_bitmetrics2.f90 | 11 ++++------- lib/fst4_decode.f90 | 2 +- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/fst4/get_fst4_bitmetrics.f90 b/lib/fst4/get_fst4_bitmetrics.f90 index 125777568..9cf1e2470 100644 --- a/lib/fst4/get_fst4_bitmetrics.f90 +++ b/lib/fst4/get_fst4_bitmetrics.f90 @@ -52,7 +52,7 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,badsync) do itone=0,3 cs(itone,k)=sum(csymb*conjg(c1(:,itone))) enddo - s4(0:3,k)=abs(cs(0:3,k)) + s4(0:3,k)=abs(cs(0:3,k))**2 enddo ! Sync quality check diff --git a/lib/fst4/get_fst4_bitmetrics2.f90 b/lib/fst4/get_fst4_bitmetrics2.f90 index 6a669bd4c..9badef231 100644 --- a/lib/fst4/get_fst4_bitmetrics2.f90 +++ b/lib/fst4/get_fst4_bitmetrics2.f90 @@ -1,4 +1,4 @@ -subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4hmod,badsync) +subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4snr,badsync) include 'fst4_params.f90' complex cd(0:NN*nss-1) @@ -15,7 +15,7 @@ subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4hmod,badsync) logical badsync real bitmetrics(2*NN,4) real s2(0:65535) - real s4(0:3,NN,4),s4hmod(0:3,NN) + real s4(0:3,NN,4),s4snr(0:3,NN) data isyncword1/0,1,3,2,1,0,2,3/ data isyncword2/2,3,1,0,3,2,0,1/ data graymap/0,1,3,2/ @@ -121,11 +121,8 @@ subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4hmod,badsync) call normalizebmet(bitmetrics(:,3),2*NN) call normalizebmet(bitmetrics(:,4),2*NN) -! Return the s4 array corresponding to N=1/hmod. Will be used for SNR calculation - if(hmod.eq.1) s4hmod(:,:)=s4(:,:,1) - if(hmod.eq.2) s4hmod(:,:)=s4(:,:,2) - if(hmod.eq.4) s4hmod(:,:)=s4(:,:,3) - if(hmod.eq.8) s4hmod(:,:)=s4(:,:,4) +! Return the s4 array corresponding to N=1. Will be used for SNR calculation + s4snr(:,:)=s4(:,:,1) return end subroutine get_fst4_bitmetrics2 diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index caf9a4b4f..72041bc3f 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -550,7 +550,7 @@ contains endif xsig=0 do i=1,NN - xsig=xsig+s4(itone(i),i)**2 + xsig=xsig+s4(itone(i),i) enddo arg=600.0*(xsig/base)-1.0 if(arg.gt.0.0) then From 7b2e9c4e5dc636a78066eaa6df315c6386d862dd Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 4 Aug 2020 10:49:14 -0400 Subject: [PATCH 019/206] Many improvements to QRA66 decoder. --- lib/qra66_decode.f90 | 54 ++++++++++++++++++++------------------------ lib/sync66a.f90 | 16 ++++++++----- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index fc907c73f..b24dd9cd9 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -44,9 +44,9 @@ contains integer ipk(1) integer dat4(12) logical lapdx,ltext - complex c0(0:NFFT1-1) !Spectrum, then analytic signal + complex c00(0:NFFT1-1) !Spectrum, then analytic signal + complex c0(0:NFFT1-1) !Snalytic signal real s(900) - real s3a(-64:127,63) real s3(-64:127,63) real a(5) data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ @@ -64,7 +64,7 @@ contains call packcall(hiscall(1:6),nc2,ltext) call packgrid(hisgrid(1:4),ng2,ltext) nSubmode=0 - b90=20 + b90=20.0 !8 to 25 is OK; not very critical nFadingModel=1 ! These probably need work: @@ -111,43 +111,36 @@ contains ipk=maxloc(s) f0=df2*ipk(1) - 0.5*baud !Candidate sync frequency -! do i=1,iz -! write(51,3051) i*df2,s(i) -!3051 format(f12.6,e12.3) -! enddo - c0(NFFT2/2+1:NFFT2)=0. !Zero the top half c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT -! call sync66(c0,f0,jpk,sync) !c0 is analytic signal at 6000 S/s ntol=100 - call sync66a(iwave,15*12000,nsps,nfqso,ntol,xdt,f0) - jpk=(xdt+0.5)*6000 + call sync66a(iwave,15*12000,nsps,nfqso,ntol,xdt,f0,snr1) + jpk=(xdt+0.5)*6000 - 384 !### Empirical ### if(jpk.lt.0) jpk=0 - -! Genie sync: -! jpk=3600 -! xdt=jpk/6000.0 - 0.5 -! f0=1510 -! f0=1490 - + c00=c0 a=0. -! a(1)=-(f0 + 1.5*baud) !For sync66 a(1)=-(f0 + 2.0*baud) !For sync66a + call twkfreq(c00,c0,15*6000,6000.0,a) + xdt=jpk/6000.0 - 0.5 + call spec66(c0(jpk:jpk+85*NSPS/2-1),s3) - - call twkfreq(c0,c0,15*6000,6000.0,a) - call spec66(c0(jpk:jpk+85*NSPS-1),s3) - s3a=s3/maxval(s3) + do j=1,63 + call pctile(s3(:,j),192,40,base) + s3(:,j)=s3(:,j)/base + enddo - call pctile(s3a,192*63,40,base) - s3a=s3a/base - s3lim=10. - where(s3a(-64:127,1:63)>s3lim) s3a(-64:127,1:63)=s3lim - - call qra64_dec(s3a,nc1,nc2,ng2,naptype,0,nSubmode,b90, & +! Apply AGC + s3max=20.0 + do j=1,63 + xx=maxval(s3(-64:127,j)) + if(xx.gt.s3max) s3(-64:127,j)=s3(-64:127,j)*s3max/xx + enddo + + call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & nFadingModel,dat4,snr2,irc) + snr2=snr2 + 6.0 if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) decoded=' ' @@ -171,6 +164,9 @@ contains !### endif +! write(61,3061) nutc,irc,xdt,f0,snr1,snr2,trim(decoded) +!3061 format(i6.6,i4,4f10.2,2x,a) + return end subroutine decode diff --git a/lib/sync66a.f90 b/lib/sync66a.f90 index ba88616cb..249c3b742 100644 --- a/lib/sync66a.f90 +++ b/lib/sync66a.f90 @@ -1,4 +1,4 @@ -subroutine sync66a(iwave,nmax,nsps,nfqso,ntol,xdt,f0) +subroutine sync66a(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) parameter (NSTEP=4) !Quarter-symbol steps parameter (IZ=1600,JZ=352,NSPSMAX=1920) @@ -49,7 +49,7 @@ subroutine sync66a(iwave,nmax,nsps,nfqso,ntol,xdt,f0) s1=s1/base s1max=20.0 -! Make this simpler: just add the 22 nonzero values. +! Apply AGC do j=1,JZ x(j)=maxval(s1(i0-64:i0+192,j)) if(x(j).gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/x(j) @@ -63,6 +63,7 @@ subroutine sync66a(iwave,nmax,nsps,nfqso,ntol,xdt,f0) do i=-ia,ia x=s1(i0+2+i,:)-s1(i0+i,:) do lag=-15,15 +! Make this simpler: just add the 22 nonzero values? do n=1,4*85 j=n+lag+11 if(j.ge.1 .and. j.le.JZ) sync_sig(i,lag)=sync_sig(i,lag) + sync(n)*x(j) @@ -80,15 +81,18 @@ subroutine sync66a(iwave,nmax,nsps,nfqso,ntol,xdt,f0) tsym=nsps/12000.0 xdt=jdt*tsym/4.0 + snr1=maxval(sync_sig)/22.0 + ! do i=-64,64 -! write(13,3013) nfqso+i*df,sync_sig(i,jj) -!3013 format(2f12.3) +! write(62,3062) nfqso+i*df,sync_sig(i,jj) +!3062 format(2f12.3) ! enddo ! do j=-15,15 -! write(14,3014) j,j*dt4,sync_sig(ii,j) -!3014 format(i5,2f12.3) +! write(63,3063) j,j*dt4,sync_sig(ii,j) +!3063 format(i5,2f12.3) ! enddo return end subroutine sync66a + From 55d83f068b3862652d750fc906dbf2b82a7c9161 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Tue, 4 Aug 2020 09:15:44 -0500 Subject: [PATCH 020/206] Fix SNR calculation for B,C,D submodes. --- lib/fst4/get_fst4_bitmetrics.f90 | 2 +- lib/fst4/get_fst4_bitmetrics2.f90 | 11 ++++------- lib/fst4_decode.f90 | 28 +++++++++++++++------------- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/fst4/get_fst4_bitmetrics.f90 b/lib/fst4/get_fst4_bitmetrics.f90 index 125777568..9cf1e2470 100644 --- a/lib/fst4/get_fst4_bitmetrics.f90 +++ b/lib/fst4/get_fst4_bitmetrics.f90 @@ -52,7 +52,7 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,badsync) do itone=0,3 cs(itone,k)=sum(csymb*conjg(c1(:,itone))) enddo - s4(0:3,k)=abs(cs(0:3,k)) + s4(0:3,k)=abs(cs(0:3,k))**2 enddo ! Sync quality check diff --git a/lib/fst4/get_fst4_bitmetrics2.f90 b/lib/fst4/get_fst4_bitmetrics2.f90 index 6a669bd4c..9badef231 100644 --- a/lib/fst4/get_fst4_bitmetrics2.f90 +++ b/lib/fst4/get_fst4_bitmetrics2.f90 @@ -1,4 +1,4 @@ -subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4hmod,badsync) +subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4snr,badsync) include 'fst4_params.f90' complex cd(0:NN*nss-1) @@ -15,7 +15,7 @@ subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4hmod,badsync) logical badsync real bitmetrics(2*NN,4) real s2(0:65535) - real s4(0:3,NN,4),s4hmod(0:3,NN) + real s4(0:3,NN,4),s4snr(0:3,NN) data isyncword1/0,1,3,2,1,0,2,3/ data isyncword2/2,3,1,0,3,2,0,1/ data graymap/0,1,3,2/ @@ -121,11 +121,8 @@ subroutine get_fst4_bitmetrics2(cd,nss,hmod,nsizes,bitmetrics,s4hmod,badsync) call normalizebmet(bitmetrics(:,3),2*NN) call normalizebmet(bitmetrics(:,4),2*NN) -! Return the s4 array corresponding to N=1/hmod. Will be used for SNR calculation - if(hmod.eq.1) s4hmod(:,:)=s4(:,:,1) - if(hmod.eq.2) s4hmod(:,:)=s4(:,:,2) - if(hmod.eq.4) s4hmod(:,:)=s4(:,:,3) - if(hmod.eq.8) s4hmod(:,:)=s4(:,:,4) +! Return the s4 array corresponding to N=1. Will be used for SNR calculation + s4snr(:,:)=s4(:,:,1) return end subroutine get_fst4_bitmetrics2 diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index caf9a4b4f..d32873c42 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -49,7 +49,7 @@ contains complex, allocatable :: cframe(:) complex, allocatable :: c_bigfft(:) !Complex waveform real llr(240),llra(240),llrb(240),llrc(240),llrd(240) - real candidates(100,4) + real candidates(200,4) real bitmetrics(320,4) real s4(0:3,NN) real minsync @@ -253,6 +253,7 @@ contains call four2a(c_bigfft,nfft1,1,-1,0) !r2c ! call blank2(nfa,nfb,nfft1,c_bigfft,iwave) + nhicoh=0 if(hmod.eq.1) then if(fMHz.lt.2.0) then nsyncoh=8 ! Use N=8 for sync @@ -277,7 +278,7 @@ contains if(hmod.eq.1) then if(ntrperiod.eq.15) minsync=1.15 - if(ntrperiod.gt.15) minsync=1.20 + if(ntrperiod.gt.15) minsync=1.25 elseif(hmod.gt.1) then minsync=1.2 endif @@ -410,7 +411,7 @@ contains ns4=count(hbits(229:244).eq.(/1,1,1,0,0,1,0,0,1,0,1,1,0,0,0,1/)) ns5=count(hbits(305:320).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/)) nsync_qual=ns1+ns2+ns3+ns4+ns5 -! if(nsync_qual.lt. 46) cycle !### Value ?? ### + if(nsync_qual.lt. 46) cycle !### Value ?? ### scalefac=2.83 llra( 1: 60)=bitmetrics( 17: 76, 1) llra( 61:120)=bitmetrics( 93:152, 1) @@ -457,7 +458,7 @@ contains if(itry.gt.nblock) then llr=llra if(nblock.gt.1) then - if(hmod.eq.1) llr=llrd + if(hmod.eq.1) llr=llrc if(hmod.eq.2) llr=llrb if(hmod.eq.4) llr=llrc if(hmod.eq.8) llr=llrd @@ -550,7 +551,7 @@ contains endif xsig=0 do i=1,NN - xsig=xsig+s4(itone(i),i)**2 + xsig=xsig+s4(itone(i),i) enddo arg=600.0*(xsig/base)-1.0 if(arg.gt.0.0) then @@ -737,7 +738,7 @@ contains complex c_bigfft(0:nfft1/2) !Full length FFT of raw data integer hmod !Modulation index (submode) integer im(1) !For maxloc - real candidates(100,4) !Candidate list + real candidates(200,4) !Candidate list real, allocatable :: s(:) !Low resolution power spectrum real, allocatable :: s2(:) !CCF of s() with 4 tones real xdb(-3:3) !Model 4-tone CCF peaks @@ -794,17 +795,18 @@ contains ! Find candidates, using the CLEAN algorithm to remove a model of each one ! from s2() after it has been found. pval=99.99 - do while(ncand.lt.100) + do while(ncand.lt.200) im=maxloc(s2(ia:ib)) iploc=ia+im(1)-1 !Index of CCF peak pval=s2(iploc) !Peak value if(pval.lt.minsync) exit - do i=-3,+3 !Remove 0.9 of a model CCF at - k=iploc+2*hmod*i !this frequency from s2() - if(k.ge.ia .and. k.le.ib) then - s2(k)=max(0.,s2(k)-0.9*pval*xdb(i)) - endif - enddo +! do i=-3,+3 !Remove 0.9 of a model CCF at +! k=iploc+2*hmod*i !this frequency from s2() +! if(k.ge.ia .and. k.le.ib) then +! s2(k)=max(0.,s2(k)-0.9*pval*xdb(i)) +! endif +! enddo + s2(max(1,iploc-2*hmod*3):min(nnw,iploc+2*hmod*3))=0.0 ncand=ncand+1 candidates(ncand,1)=df2*iploc !Candidate frequency candidates(ncand,2)=pval !Rough estimate of SNR From 4225241720b653b56562f304279fcbdb6ea0dcb6 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Tue, 4 Aug 2020 10:25:09 -0500 Subject: [PATCH 021/206] Changes to the llrs that are used as the basis for AP decoding. --- lib/fst4_decode.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index d32873c42..88572dfb7 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -459,9 +459,9 @@ contains llr=llra if(nblock.gt.1) then if(hmod.eq.1) llr=llrc - if(hmod.eq.2) llr=llrb - if(hmod.eq.4) llr=llrc - if(hmod.eq.8) llr=llrd + if(hmod.eq.2) llr=llra + if(hmod.eq.4) llr=llrb + if(hmod.eq.8) llr=llrc endif iaptype=naptypes(nQSOProgress,itry-nblock) if(lapcqonly) iaptype=1 From aff22a904d8f2494e940404ac2959b4d0be3702a Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 4 Aug 2020 11:51:40 -0400 Subject: [PATCH 022/206] Better marking of QRA66 Rx freq range and Tol on Wide Graph. --- widgets/plotter.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index 15057f4a8..fde2a707b 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -508,13 +508,13 @@ void CPlotter::DrawOverlay() //DrawOverlay() or m_mode=="QRA64" or m_mode=="QRA66" or m_mode=="FT8" or m_mode=="FT4" or m_mode.startsWith("FST4")) { - if(m_mode=="QRA64" or (m_mode=="JT65" and m_bVHF)) { + if(m_mode=="QRA64" or m_mode=="QRA66" or (m_mode=="JT65" and m_bVHF)) { painter0.setPen(penGreen); x1=XfromFreq(m_rxFreq-m_tol); x2=XfromFreq(m_rxFreq+m_tol); - painter0.drawLine(x1,28,x2,28); + painter0.drawLine(x1,27,x2,27); x1=XfromFreq(m_rxFreq); - painter0.drawLine(x1,24,x1,30); + painter0.drawLine(x1,21,x1,27); if(m_mode=="JT65") { painter0.setPen(penOrange); @@ -527,7 +527,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() } painter0.setPen(penGreen); x6=XfromFreq(m_rxFreq+bw); //Highest tone - painter0.drawLine(x6,24,x6,30); + painter0.drawLine(x6,21,x6,27); } else { // Draw the green "goal post" From 668631180d68bd1c9686ddba51245509bc4d1caa Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 4 Aug 2020 11:52:29 -0400 Subject: [PATCH 023/206] Code cleanup. --- lib/decoder.f90 | 5 ++--- lib/qra66_decode.f90 | 49 +++++++++++--------------------------------- 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 41f1d0f7e..de2a31df5 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -197,9 +197,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) if(params%nmode.eq.66) then ! We're in QRA66 mode call timer('decqra66',0) - call my_qra66%decode(qra66_decoded,id2,params%nutc,params%nfa, & - params%nfb,params%nfqso,params%ndepth,logical(params%lapcqonly), & - mycall,hiscall,hisgrid) + call my_qra66%decode(qra66_decoded,id2,params%nutc,params%nfqso, & + params%ntol,params%ndepth,mycall,hiscall,hisgrid) call timer('decqra66',1) go to 800 endif diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index b24dd9cd9..ade80d638 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -28,7 +28,7 @@ module qra66_decode contains - subroutine decode(this,callback,iwave,nutc,nfa,nfb,nfqso,ndepth,lapdx, & + subroutine decode(this,callback,iwave,nutc,nfqso,ntol,ndepth, & mycall,hiscall,hisgrid) use timer_module, only: timer @@ -41,12 +41,9 @@ contains character(len=6) :: hisgrid character*37 decoded integer*2 iwave(NFFT1) !Raw data - integer ipk(1) integer dat4(12) logical lapdx,ltext - complex c00(0:NFFT1-1) !Spectrum, then analytic signal - complex c0(0:NFFT1-1) !Snalytic signal - real s(900) + complex c0(0:NFFT1-1) !Analytic signal, 6000 S/s real s3(-64:127,63) real a(5) data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ @@ -67,12 +64,11 @@ contains b90=20.0 !8 to 25 is OK; not very critical nFadingModel=1 -! These probably need work: +! AP control could be done differently, but this works well: maxaptype=0 if(ndepth.eq.2) maxaptype=3 if(ndepth.eq.3) maxaptype=5 -! Prime the decoder for possible AP decoding if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & maxaptype.ne.maxaptypez) then do naptype=0,maxaptype @@ -87,60 +83,39 @@ contains endif naptype=maxaptype -! Compute the full-length spectrum +! Downsample to give complex data at 6000 S/s fac=2.0/NFFT1 c0=fac*iwave call four2a(c0,NFFT1,1,-1,1) !Forward c2c FFT - - nadd=101 - nh=nadd/2 - df2=nh*df1 - iz=3000.0/df2 - do i=1,iz !Compute smoothed spectrum - s(i)=0. - j0=nh*i - do j=j0-nh,j0+nh - s(i)=s(i) + real(c0(j))**2 + aimag(c0(j))**2 - enddo - enddo - call smo121(s,iz) - ia=1450/df2 - ib=1550/df2 - s(:ia)=0. - s(ib:)=0. - ipk=maxloc(s) - f0=df2*ipk(1) - 0.5*baud !Candidate sync frequency - c0(NFFT2/2+1:NFFT2)=0. !Zero the top half c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT ntol=100 call sync66a(iwave,15*12000,nsps,nfqso,ntol,xdt,f0,snr1) - jpk=(xdt+0.5)*6000 - 384 !### Empirical ### + jpk=(xdt+0.5)*6000 - 384 !### Empirical ### if(jpk.lt.0) jpk=0 - c00=c0 a=0. - a(1)=-(f0 + 2.0*baud) !For sync66a - call twkfreq(c00,c0,15*6000,6000.0,a) + a(1)=-(f0 + 2.0*baud) !Data tones start 2 bins higher + call twkfreq(c0,c0,15*6000,6000.0,a) xdt=jpk/6000.0 - 0.5 call spec66(c0(jpk:jpk+85*NSPS/2-1),s3) - do j=1,63 + do j=1,63 !Normalize to symbol baseline call pctile(s3(:,j),192,40,base) s3(:,j)=s3(:,j)/base enddo -! Apply AGC s3max=20.0 - do j=1,63 + do j=1,63 !Apply AGC to suppress pings xx=maxval(s3(-64:127,j)) if(xx.gt.s3max) s3(-64:127,j)=s3(-64:127,j)*s3max/xx enddo - + +!Call Nico's QRA64 decoder call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & nFadingModel,dat4,snr2,irc) - snr2=snr2 + 6.0 + snr2=snr2 + 5.563 !10*log(6912/1920) if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) decoded=' ' From 902bb4d5e070196d5ce17299ddbf6724936a57fd Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 4 Aug 2020 11:58:09 -0400 Subject: [PATCH 024/206] Add timer calls in qra66_decode. --- lib/qra66_decode.f90 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index ade80d638..ecef6a870 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -92,7 +92,9 @@ contains call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT ntol=100 + call timer('sync66 ',0) call sync66a(iwave,15*12000,nsps,nfqso,ntol,xdt,f0,snr1) + call timer('sync66 ',1) jpk=(xdt+0.5)*6000 - 384 !### Empirical ### if(jpk.lt.0) jpk=0 a=0. @@ -113,8 +115,10 @@ contains enddo !Call Nico's QRA64 decoder + call timer('qra64_de',0) call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & nFadingModel,dat4,snr2,irc) + call timer('qra64_de',1) snr2=snr2 + 5.563 !10*log(6912/1920) if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) From 88102af49d72337e34754e8c4cd5c6488cb92d36 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 4 Aug 2020 12:53:37 -0400 Subject: [PATCH 025/206] Fic the transfer of ntol from GUI to qra66_decode(). --- lib/qra66_decode.f90 | 1 - widgets/plotter.cpp | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index ecef6a870..8892769d0 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -91,7 +91,6 @@ contains c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT - ntol=100 call timer('sync66 ',0) call sync66a(iwave,15*12000,nsps,nfqso,ntol,xdt,f0,snr1) call timer('sync66 ',1) diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index fde2a707b..d3416db02 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -512,22 +512,22 @@ void CPlotter::DrawOverlay() //DrawOverlay() painter0.setPen(penGreen); x1=XfromFreq(m_rxFreq-m_tol); x2=XfromFreq(m_rxFreq+m_tol); - painter0.drawLine(x1,27,x2,27); + painter0.drawLine(x1,26,x2,26); x1=XfromFreq(m_rxFreq); - painter0.drawLine(x1,21,x1,27); + painter0.drawLine(x1,20,x1,26); if(m_mode=="JT65") { painter0.setPen(penOrange); x3=XfromFreq(m_rxFreq+20.0*bw/65.0); //RO - painter0.drawLine(x3,24,x3,30); + painter0.drawLine(x3,20,x3,26); x4=XfromFreq(m_rxFreq+30.0*bw/65.0); //RRR - painter0.drawLine(x4,24,x4,30); + painter0.drawLine(x4,20,x4,26); x5=XfromFreq(m_rxFreq+40.0*bw/65.0); //73 - painter0.drawLine(x5,24,x5,30); + painter0.drawLine(x5,20,x5,26); } painter0.setPen(penGreen); x6=XfromFreq(m_rxFreq+bw); //Highest tone - painter0.drawLine(x6,21,x6,27); + painter0.drawLine(x6,20,x6,26); } else { // Draw the green "goal post" From 9b4b3a6623d78ebf87b258851b9ee0931715fa51 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Tue, 4 Aug 2020 11:56:32 -0500 Subject: [PATCH 026/206] Remove some unneeded code. --- lib/fst4_decode.f90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 88572dfb7..e56fa27a8 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -149,8 +149,7 @@ contains if(i3.ne.1 .or. (msg.ne.msgsent) .or. .not.unpk77_success) go to 10 read(c77,'(77i1)') message77 message77=mod(message77+rvec,2) - call encode174_91(message77,cw) - apbits=2*cw-1 + apbits(1:77)=2*message77-1 if(nohiscall) apbits(30)=99 10 continue From 2e893e8994e75e567bdce0f8804ded20da076149 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 4 Aug 2020 13:12:51 -0400 Subject: [PATCH 027/206] Add Tx freq as command-line argument for qra66sim. --- lib/qra/qra66/qra66sim.f90 | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 index 0e1910490..e7903eee4 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra66/qra66sim.f90 @@ -19,21 +19,23 @@ program qra66sim character msgsent*22 nargs=iargc() - if(nargs.ne.6) then - print *, 'Usage: qra66sim "msg" A|B fDop DT Nfiles SNR' - print *, 'Example qra66sim "K1ABC W9XYZ EN37" A 0.2 0.0 1 -10' + if(nargs.ne.7) then + print *, 'Usage: qra66sim "msg" A|B freq fDop DT Nfiles SNR' + print *, 'Example: qra66sim "K1ABC W9XYZ EN37" A 1500 0.2 0.0 1 -10' go to 999 endif call getarg(1,msg) call getarg(2,csubmode) mode66=2**(ichar(csubmode)-ichar('A')) call getarg(3,arg) - read(arg,*) fspread + read(arg,*) f0 call getarg(4,arg) - read(arg,*) xdt + read(arg,*) fspread call getarg(5,arg) - read(arg,*) nfiles + read(arg,*) xdt call getarg(6,arg) + read(arg,*) nfiles + call getarg(7,arg) read(arg,*) snrdb rms=100. @@ -71,7 +73,6 @@ program qra66sim enddo endif - f0=1500.0 bandwidth_ratio=2500.0/6000.0 sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snrdb) if(snrdb.gt.90.0) sig=1.0 From 335cc41faa09462ee60c8e78d59c468a6579d03d Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 4 Aug 2020 13:13:49 -0400 Subject: [PATCH 028/206] More code cleanup. Rename sync66a to sync66. --- CMakeLists.txt | 2 +- lib/qra66_decode.f90 | 2 +- lib/sync66.f90 | 142 +++++++++++++++++++++++++++---------------- lib/sync66a.f90 | 98 ----------------------------- 4 files changed, 92 insertions(+), 152 deletions(-) delete mode 100644 lib/sync66a.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index fe32cc8f5..de57adccb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -577,7 +577,7 @@ set (wsjt_FSRCS lib/symspec65.f90 lib/sync4.f90 lib/sync64.f90 - lib/sync66a.f90 + lib/sync66.f90 lib/sync65.f90 lib/ft4/getcandidates4.f90 lib/ft4/get_ft4_bitmetrics.f90 diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 8892769d0..f914a1fb2 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -92,7 +92,7 @@ contains call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT call timer('sync66 ',0) - call sync66a(iwave,15*12000,nsps,nfqso,ntol,xdt,f0,snr1) + call sync66(iwave,15*12000,nsps,nfqso,ntol,xdt,f0,snr1) call timer('sync66 ',1) jpk=(xdt+0.5)*6000 - 384 !### Empirical ### if(jpk.lt.0) jpk=0 diff --git a/lib/sync66.f90 b/lib/sync66.f90 index bc8b41805..e259f04ac 100644 --- a/lib/sync66.f90 +++ b/lib/sync66.f90 @@ -1,60 +1,98 @@ -subroutine sync66(c0,f0,jpk,sync) +subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) -! Use the sync vector to find xdt (and improved f0 ?) - - PARAMETER (NMAX=15*6000) - parameter (NSPS=960) !Samples per symbol at 6000 Hz - complex c0(0:NMAX-1) !Complex data at 6000 S/s - complex csync0(0:NSPS-1) - complex csync1(0:NSPS-1) - complex z - integer b11(11) !Barker 11 code - data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 definition - data mode66z/-1/ - save + parameter (NSTEP=4) !Quarter-symbol steps + parameter (IZ=1600,JZ=352,NSPSMAX=1920) + integer*2 iwave(0:nmax-1) !Raw data + integer b11(11) !Barker 11 code + integer ijpk(2) !Indices i and j at peak of sync_sig + real s1(IZ,JZ) !Symbol spectra + real x(JZ) !Work array; 2FSK sync modulation + real sync(4*85) !sync vector + real sync_sig(-64:64,-15:15) + complex c0(0:NSPSMAX) !Complex spectrum of symbol + data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 code + data sync(1)/99.0/ + save sync - twopi=8.0*atan(1.0) - baud=6000.0/NSPS - dt=1.0/6000.0 - - dphi0=twopi*f0**dt - dphi1=twopi*(f0+baud)*dt - phi0=0. - phi1=0. - - do i=0,NSPS-1 !Compute csync for f0 and f0+baud - csync0(i)=cmplx(cos(phi0),sin(phi0)) - csync1(i)=cmplx(cos(phi1),sin(phi1)) - phi0=phi0 + dphi0 - phi1=phi1 + dphi1 - if(phi0.gt.twopi) phi0=phi0-twopi - if(phi1.gt.twopi) phi1=phi1-twopi - enddo - - sqmax=0. - jstep=NSPS/8 - do j0=0,6000,jstep - sq=0. + if(sync(1).eq.99.0) then + sync=0. do k=1,22 - i=k - if(i.gt.11) i=i-11 - j1=j0 + 4*(k-1)*NSPS - if(b11(i).eq.0) then - z=dot_product(c0(j1:j1+NSPS-1),csync0) - else - z=dot_product(c0(j1:j1+NSPS-1),csync1) - endif - z=0.001*z - sq=sq + real(z)**2 + aimag(z)**2 + kk=k + if(kk.gt.11) kk=k-11 + sync(16*k-15)=2.0*b11(kk) - 1.0 + enddo + endif + + nfft=2*NSPS + df=12000.0/nfft !3.125 Hz + istep=nsps/NSTEP + fac=1/32767.0 + do j=1,JZ !Compute symbol spectra + ia=(j-1)*istep + ib=ia+nsps-1 + k=-1 + do i=ia,ib,2 + xx=iwave(i) + yy=iwave(i+1) + k=k+1 + c0(k)=fac*cmplx(xx,yy) + enddo + c0(k+1:nfft/2)=0. + call four2a(c0,nfft,1,-1,0) !r2c FFT + do i=1,IZ + s1(i,j)=real(c0(i))**2 + aimag(c0(i))**2 enddo - write(52,3052) j0/6000.0,sq,j0,j1 -3052 format(f10.6,f12.3,2i8) - if(sq.gt.smax) then - smax=sq - jpk=j0 - endif enddo - sync=smax + + i0=nint(nfqso/df) + call pctile(s1(i0-64:i0+192,1:JZ),129*JZ,40,base) + s1=s1/base + s1max=20.0 + +! Apply AGC + do j=1,JZ + x(j)=maxval(s1(i0-64:i0+192,j)) + if(x(j).gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/x(j) + enddo + + dt4=nsps/(NSTEP*12000.0) + j0=0.5/dt4 + + sync_sig=0. + ia=min(64,nint(ntol/df)) + do i=-ia,ia + x=s1(i0+2+i,:)-s1(i0+i,:) + do lag=-15,15 +! Make this simpler: just add the 22 nonzero values? + do n=1,4*85 + j=n+lag+11 + if(j.ge.1 .and. j.le.JZ) sync_sig(i,lag)=sync_sig(i,lag) + sync(n)*x(j) + enddo + enddo + enddo + + ijpk=maxloc(sync_sig) + ii=ijpk(1)-65 + jj=ijpk(2)-16 + +! Use peakup() here? + f0=nfqso + ii*df + jdt=jj + tsym=nsps/12000.0 + xdt=jdt*tsym/4.0 + + snr1=maxval(sync_sig)/22.0 + +! do i=-64,64 +! write(62,3062) nfqso+i*df,sync_sig(i,jj) +!3062 format(2f12.3) +! enddo + +! do j=-15,15 +! write(63,3063) j,j*dt4,sync_sig(ii,j) +!3063 format(i5,2f12.3) +! enddo return end subroutine sync66 + diff --git a/lib/sync66a.f90 b/lib/sync66a.f90 deleted file mode 100644 index 249c3b742..000000000 --- a/lib/sync66a.f90 +++ /dev/null @@ -1,98 +0,0 @@ -subroutine sync66a(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) - - parameter (NSTEP=4) !Quarter-symbol steps - parameter (IZ=1600,JZ=352,NSPSMAX=1920) - integer*2 iwave(0:nmax-1) !Raw data - integer b11(11) !Barker 11 code - integer ijpk(2) !Indices i and j at peak of sync_sig - real s1(IZ,JZ) !Symbol spectra - real x(JZ) !Work array; 2FSK sync modulation - real sync(4*85) !sync vector - real sync_sig(-64:64,-15:15) - complex c0(0:NSPSMAX) !Complex spectrum of symbol - data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 code - data sync(1)/99.0/ - save sync - - if(sync(1).eq.99.0) then - sync=0. - do k=1,22 - kk=k - if(kk.gt.11) kk=k-11 - sync(16*k-15)=2.0*b11(kk) - 1.0 - enddo - endif - - nfft=2*NSPS - df=12000.0/nfft !3.125 Hz - istep=nsps/NSTEP - fac=1/32767.0 - do j=1,JZ !Compute symbol spectra - ia=(j-1)*istep - ib=ia+nsps-1 - k=-1 - do i=ia,ib,2 - xx=iwave(i) - yy=iwave(i+1) - k=k+1 - c0(k)=fac*cmplx(xx,yy) - enddo - c0(k+1:nfft/2)=0. - call four2a(c0,nfft,1,-1,0) !r2c FFT - do i=1,IZ - s1(i,j)=real(c0(i))**2 + aimag(c0(i))**2 - enddo - enddo - - i0=nint(nfqso/df) - call pctile(s1(i0-64:i0+192,1:JZ),129*JZ,40,base) - s1=s1/base - s1max=20.0 - -! Apply AGC - do j=1,JZ - x(j)=maxval(s1(i0-64:i0+192,j)) - if(x(j).gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/x(j) - enddo - - dt4=nsps/(NSTEP*12000.0) - j0=0.5/dt4 - - sync_sig=0. - ia=min(64,nint(ntol/df)) - do i=-ia,ia - x=s1(i0+2+i,:)-s1(i0+i,:) - do lag=-15,15 -! Make this simpler: just add the 22 nonzero values? - do n=1,4*85 - j=n+lag+11 - if(j.ge.1 .and. j.le.JZ) sync_sig(i,lag)=sync_sig(i,lag) + sync(n)*x(j) - enddo - enddo - enddo - - ijpk=maxloc(sync_sig) - ii=ijpk(1)-65 - jj=ijpk(2)-16 - -! Use peakup() here? - f0=nfqso + ii*df - jdt=jj - tsym=nsps/12000.0 - xdt=jdt*tsym/4.0 - - snr1=maxval(sync_sig)/22.0 - -! do i=-64,64 -! write(62,3062) nfqso+i*df,sync_sig(i,jj) -!3062 format(2f12.3) -! enddo - -! do j=-15,15 -! write(63,3063) j,j*dt4,sync_sig(ii,j) -!3063 format(i5,2f12.3) -! enddo - - return -end subroutine sync66a - From f1c8f041361bd8bb69e97655fc6e9771adf1d206 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 4 Aug 2020 14:18:23 -0400 Subject: [PATCH 029/206] Report failed QRA66 decode as SNR = -22 dB. --- lib/qra66_decode.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index f914a1fb2..3f4b63f4a 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -135,7 +135,7 @@ contains irc,qual,ntrperiod,fmid,w50) else snr2=0. - nsnr=nint(db(sync)) + nsnr=-22 !### TEMPORARY? ### call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) From 2bb9566731049106a1f3f82df5830f73cc20dd6e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 5 Aug 2020 09:37:03 -0400 Subject: [PATCH 030/206] In QRA66 mode, make unused widgets invisible. --- widgets/mainwindow.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 0fc6ec684..d78d05ec4 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -3389,7 +3389,7 @@ void MainWindow::readFromStdout() //readFromStdout //Right (Rx Frequency) window bool bDisplayRight=bAvgMsg; int audioFreq=decodedtext.frequencyOffset(); - if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="FST4") { + if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="FST4" or m_mode=="QRA66") { auto const& parts = decodedtext.string().remove("<").remove(">") .split (' ', SkipEmptyParts); if (parts.size() > 6) { @@ -6427,7 +6427,9 @@ void MainWindow::on_actionQRA66_triggered() m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); m_wideGraph->setPeriod(m_TRperiod,6912); -} +// 0123456789012345678901234567890123 + displayWidgets(nWidgets("1111100001001100000100000001000000")); + statusChanged();} void MainWindow::on_actionISCAT_triggered() { From 7256d70016646454085a2d91087b668d5fc17748 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 5 Aug 2020 11:06:18 -0400 Subject: [PATCH 031/206] QRA66: change NSPS from 1920 to 1800. TxT=85*1800/12000=12.75 s. --- lib/jt9.f90 | 1 + lib/qra/qra66/qra66sim.f90 | 6 +++--- lib/qra66_decode.f90 | 6 ++++-- lib/spec66.f90 | 30 ++++++++++++++---------------- widgets/mainwindow.cpp | 4 ++-- 5 files changed, 24 insertions(+), 23 deletions(-) diff --git a/lib/jt9.f90 b/lib/jt9.f90 index 3c017ac18..052d35cb9 100644 --- a/lib/jt9.f90 +++ b/lib/jt9.f90 @@ -226,6 +226,7 @@ program jt9 endif shared_data%id2=0 !??? Why is this necessary ??? if(mode.eq.5) npts=21*3456 + if(mode.eq.66) npts=15*12000 do iblk=1,npts/kstep k=iblk*kstep if(mode.eq.8 .and. k.gt.179712) exit diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 index e7903eee4..901f72e84 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra66/qra66sim.f90 @@ -43,11 +43,11 @@ program qra66sim dt=1.d0/fsample !Sample interval (s) twopi=8.d0*atan(1.d0) npts=NMAX !Total samples in .wav file - nsps=1920 + nsps=1800 nsym=85 !Number of channel symbols if(csubmode.eq.'B') then - nsps=960 - nsym=169 + nsps=nsps/2 + nsym=2*nsym-1 endif ichk=66 !Flag sent to genqra64 diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 3f4b63f4a..0fdd47579 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -50,7 +50,7 @@ contains save nc1z,nc2z,ng2z,maxaptypez this%callback => callback - nsps=1920 + nsps=1800 baud=12000.0/nsps df1=12000.0/NFFT1 @@ -100,11 +100,13 @@ contains a(1)=-(f0 + 2.0*baud) !Data tones start 2 bins higher call twkfreq(c0,c0,15*6000,6000.0,a) xdt=jpk/6000.0 - 0.5 - call spec66(c0(jpk:jpk+85*NSPS/2-1),s3) + call spec66(c0(jpk:),nsps/2,s3) do j=1,63 !Normalize to symbol baseline call pctile(s3(:,j),192,40,base) s3(:,j)=s3(:,j)/base + write(71,3071)j,maxloc(s3(:,j)) +3071 format(2i5) enddo s3max=20.0 diff --git a/lib/spec66.f90 b/lib/spec66.f90 index 9242f6a59..0d381cf78 100644 --- a/lib/spec66.f90 +++ b/lib/spec66.f90 @@ -1,30 +1,28 @@ -subroutine spec66(c0,s3) +subroutine spec66(c0,nsps,s3) - parameter (LL=3*64) !Frequency channels - parameter (NN=63) !Data symbols - parameter (NSPS=960) !Samples per symbol at 6000 Hz - parameter (NMAX=85*NSPS) - complex c0(0:NMAX-1) !Synchrinized complex data - complex cs(0:NSPS-1) !Complex symbol spectrum - real s3(LL,NN) !Synchronized symbol spectra + parameter (LL=3*64) !Frequency channels + parameter (NN=63) !Data symbols + complex c0(0:85*nsps-1) !Synchronized complex data at 6000 S/s + complex cs(0:nsps-1) !Complex symbol spectrum + real s3(LL,NN) !Synchronized symbol spectra real xbase0(LL),xbase(LL) - fac=1.0/NSPS - ja=-NSPS + fac=1.0/nsps + ja=-nsps do j=1,NN - ja=ja+NSPS - if(mod(ja/NSPS,4).eq.0) ja=ja+NSPS - jb=ja+NSPS-1 + ja=ja+nsps + if(mod(ja/nsps,4).eq.0) ja=ja+nsps + jb=ja+nsps-1 cs=fac*c0(ja:jb) - call four2a(cs,NSPS,1,-1,1) !c2c FFT to frequency + call four2a(cs,nsps,1,-1,1) !c2c FFT to frequency do ii=1,LL i=ii-65 - if(i.lt.0) i=i+NSPS + if(i.lt.0) i=i+nsps s3(ii,j)=real(cs(i))**2 + aimag(cs(i))**2 enddo enddo - df=6000.0/NSPS + df=6000.0/nsps do i=1,LL call pctile(s3(i,1:NN),NN,45,xbase0(i)) !Get baseline for passband shape enddo diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index d78d05ec4..557f95488 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -7390,9 +7390,9 @@ void MainWindow::transmit (double snr) } if (m_modeTx == "QRA66") { - toneSpacing=12000.0/1920.0; + toneSpacing=12000.0/1800.0; Q_EMIT sendMessage (m_mode, NUM_QRA66_SYMBOLS, - 1920.0, ui->TxFreqSpinBox->value () - m_XIT, + 1800.0, ui->TxFreqSpinBox->value () - m_XIT, toneSpacing, m_soundOutput, m_config.audio_output_channel (), true, false, snr, m_TRperiod); } From 6c8c9183aae50b683c402ea6efdf2b5af85c476e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 5 Aug 2020 11:16:56 -0400 Subject: [PATCH 032/206] SNR for QRA66 non-decodes now set to -25. --- lib/qra66_decode.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 0fdd47579..6eb76352d 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -137,7 +137,7 @@ contains irc,qual,ntrperiod,fmid,w50) else snr2=0. - nsnr=-22 + nsnr=-25 !### TEMPORARY? ### call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) From 30e34bf1c46d0467d613829972b467fc944ea478 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 5 Aug 2020 16:34:49 -0400 Subject: [PATCH 033/206] Implement message averaging (very basic) for QRA66. --- lib/qra66_decode.f90 | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 6eb76352d..39e7371f6 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -45,9 +45,10 @@ contains logical lapdx,ltext complex c0(0:NFFT1-1) !Analytic signal, 6000 S/s real s3(-64:127,63) + real s3a(-64:127,63) real a(5) data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ - save nc1z,nc2z,ng2z,maxaptypez + save nc1z,nc2z,ng2z,maxaptypez,nsave,s3a this%callback => callback nsps=1800 @@ -80,6 +81,8 @@ contains nc2z=nc2 ng2z=ng2 maxaptypez=maxaptype + s3a=0. + nsave=0 endif naptype=maxaptype @@ -115,16 +118,31 @@ contains if(xx.gt.s3max) s3(-64:127,j)=s3(-64:127,j)*s3max/xx enddo -!Call Nico's QRA64 decoder +! Call Nico's QRA64 decoder call timer('qra64_de',0) call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & nFadingModel,dat4,snr2,irc) call timer('qra64_de',1) + + if(irc.lt.0) then +! No luck so far. Try for an average decode. + call timer('qra64_av',0) + s3a=s3a+s3 + nsave=nsave+1 + if(nsave.ge.2) then + call qra64_dec(s3a,nc1,nc2,ng2,naptype,0,nSubmode,b90, & + nFadingModel,dat4,snr2,irc) + if(irc.ge.0) irc=10*nsave + irc + endif + call timer('qra64_av',1) + endif snr2=snr2 + 5.563 !10*log(6912/1920) if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) decoded=' ' if(irc.ge.0) then + nsave=0 + s3a=0. call unpackmsg(dat4,decoded) !Unpack the user message call fmtmsg(decoded,iz) if(index(decoded,"000AAA ").ge.1) then From 254e2f61fa08da93a82333712d465f6cc4b9952e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 6 Aug 2020 07:07:16 -0400 Subject: [PATCH 034/206] Remove diagnostic write to fort.71. --- lib/qra66_decode.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 39e7371f6..308dd97a2 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -108,8 +108,8 @@ contains do j=1,63 !Normalize to symbol baseline call pctile(s3(:,j),192,40,base) s3(:,j)=s3(:,j)/base - write(71,3071)j,maxloc(s3(:,j)) -3071 format(2i5) +! write(71,3071)j,maxloc(s3(:,j)) +!3071 format(2i5) enddo s3max=20.0 From 2de28746724bd65e3d5f6619548d89b2db7f9091 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 6 Aug 2020 14:23:39 -0400 Subject: [PATCH 035/206] Allow for larger irc created by message averaging. Commit test_qra66.f90 --- lib/decoder.f90 | 2 +- lib/test_qra66.f90 | 100 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 lib/test_qra66.f90 diff --git a/lib/decoder.f90 b/lib/decoder.f90 index de2a31df5..887201dda 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -795,7 +795,7 @@ contains real, intent(in) :: w50 write(*,1001) nutc,nsnr,dt,nint(freq),decoded,irc -1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2) +1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i4) write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded 1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA66') diff --git a/lib/test_qra66.f90 b/lib/test_qra66.f90 new file mode 100644 index 000000000..cd20ceaf9 --- /dev/null +++ b/lib/test_qra66.f90 @@ -0,0 +1,100 @@ +program test_qra66 + + character*70 cmd1,cmd2,line + character*22 msg + character*8 arg + integer nretcode(0:11) + integer fDop + real fspread + logical decok + + nargs=iargc() + if(nargs.ne.7) then + print*,'Usage: test_qra66 "msg" ndepth freq DT fDop nfiles SNR' + print*,'Example: test_qra66 "K1ABC W9XYZ EN37" 3 1500 0.0 5 100 0' + print*,' SNR = 0 to loop over all relevant SNRs' + go to 999 + endif + call getarg(1,msg) + call getarg(2,arg) + read(arg,*) ndepth + call getarg(3,arg) + read(arg,*) nf0 + call getarg(4,arg) + read(arg,*) dt + call getarg(5,arg) + read(arg,*) fDop + call getarg(6,arg) + read(arg,*) nfiles + call getarg(7,arg) + read(arg,*) nsnr + +! 1 2 3 4 5 6 +! 1234567890123456789012345678901234567890123456789012345678901234' + cmd1='qra66sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 100 -10 > junk0' + cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 1 *.wav > junk' + + write(cmd1(10:33),'(a)') '"'//msg//'"' + write(cmd1(37:40),'(i4)') nf0 + write(cmd1(41:45),'(i5)') fDop + write(cmd1(46:50),'(f5.2)') dt + write(cmd1(51:55),'(i5)') nfiles + write(cmd2(32:32),'(i1)') ndepth + call system('rm -f *.wav') + + write(*,1000) (j,j=0,11) + write(12,1000) (j,j=0,11) +1000 format(/'SNR d Dop Sync Dec1 DecN Bad',i5,11i4,' tdec'/83('-')) + ia=-12 + ib=-30 + if(nsnr.ne.0) then + ia=nsnr + ib=nsnr + endif + + do nsnr=ia,ib,-1 + nsync=0 + ndecodes=0 + nfalse=0 + nretcode=0 + navg=0 + write(cmd1(57:59),'(i3)') nsnr + call system(cmd1) + call sec0(0,tdec) + call system(cmd2) + call sec0(1,tdec) + open(10,file='junk',status='unknown') + n=0 + do iline=1,9999 + read(10,'(a70)',end=10) line + if(len(trim(line)).lt.60) cycle + read(line(11:20),*) xdt,nf + if(abs(xdt-dt).lt.0.15 .and. abs(nf-nf0).lt.4) nsync=nsync+1 + read(line(60:),*) irc + if(irc.lt.0) cycle + decok=index(line,'W9XYZ').gt.0 + if(decok) then + i=irc + if(i.le.11) then + ndecodes=ndecodes + 1 + navg=navg + 1 + else + i=mod(i,10) + navg=navg + 1 + endif + nretcode(i)=nretcode(i) + 1 + else + nfalse=nfalse + 1 + print*,'False: ',line + endif + enddo +10 close(10) + write(*,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode,tdec/nfiles + write(12,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode,tdec/nfiles +1100 format(i3,i2,i3,3i5,i4,i6,11i4,f6.2) + enddo + +999 end program test_qra66 + + include 'sec0.f90' + From bf38f4416c9186943090e1b0b03b4010aeb9c238 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 8 Aug 2020 09:14:12 -0400 Subject: [PATCH 036/206] Modifications to give QRA64 use of longer TR periods and tone-spacing submodes. Noy yet finished, or tested! --- displayWidgets.txt | 1 + lib/decoder.f90 | 8 +++-- lib/jt9.f90 | 2 +- lib/qra/qra66/qra66sim.f90 | 68 +++++++++++++++++++++++--------------- lib/qra66_decode.f90 | 46 ++++++++++++++++++-------- lib/sync66.f90 | 19 +++++++---- lib/test_qra66.f90 | 4 ++- widgets/mainwindow.cpp | 3 +- widgets/plotter.cpp | 2 +- 9 files changed, 98 insertions(+), 55 deletions(-) diff --git a/displayWidgets.txt b/displayWidgets.txt index 2f6c382e2..afdbd44e1 100644 --- a/displayWidgets.txt +++ b/displayWidgets.txt @@ -11,6 +11,7 @@ JT9+JT65 1110100000011110000100000000000010 JT65 1110100000001110000100000000000010 JT65/VHF 1111100100001101101011000100000000 QRA64 1111100101101101100000000010000000 +QRA66 1111110101101101000100000011000000 ISCAT 1001110000000001100000000000000000 MSK144 1011111101000000000100010000000000 WSPR 0000000000000000010100000000000000 diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 887201dda..269d70423 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -197,7 +197,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) if(params%nmode.eq.66) then ! We're in QRA66 mode call timer('decqra66',0) - call my_qra66%decode(qra66_decoded,id2,params%nutc,params%nfqso, & + call my_qra66%decode(qra66_decoded,id2,params%nutc,params%ntr,params%nfqso, & params%ntol,params%ndepth,mycall,hiscall,hisgrid) call timer('decqra66',1) go to 800 @@ -793,9 +793,11 @@ contains integer, intent(in) :: ntrperiod real, intent(in) :: fmid real, intent(in) :: w50 + integer navg - write(*,1001) nutc,nsnr,dt,nint(freq),decoded,irc -1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i4) + navg=irc/100 + write(*,1001) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg +1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded 1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA66') diff --git a/lib/jt9.f90 b/lib/jt9.f90 index 052d35cb9..1f23f3c5d 100644 --- a/lib/jt9.f90 +++ b/lib/jt9.f90 @@ -226,7 +226,7 @@ program jt9 endif shared_data%id2=0 !??? Why is this necessary ??? if(mode.eq.5) npts=21*3456 - if(mode.eq.66) npts=15*12000 + if(mode.eq.66) npts=TRperiod*12000 do iblk=1,npts/kstep k=iblk*kstep if(mode.eq.8 .and. k.gt.179712) exit diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 index 901f72e84..0ed23af30 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra66/qra66sim.f90 @@ -4,24 +4,23 @@ program qra66sim use wavhdr use packjt - parameter (NMAX=15*12000) !180,000 - parameter (NFFT=NMAX,NH=NFFT/2) + parameter (NMAX=300*12000) !Total samples in .wav file type(hdr) h !Header for .wav file integer*2 iwave(NMAX) !Generated waveform integer*4 itone(85) !Channel symbols (values 0-65) real*4 xnoise(NMAX) !Generated random noise real*4 dat(NMAX) !Generated real data complex cdat(NMAX) !Generated complex waveform - complex cspread(0:NFFT-1) !Complex amplitude for Rayleigh fading + complex cspread(0:NMAX-1) !Complex amplitude for Rayleigh fading complex z real*8 f0,dt,twopi,phi,dphi,baud,fsample,freq character msg*22,fname*13,csubmode*1,arg*12 character msgsent*22 nargs=iargc() - if(nargs.ne.7) then - print *, 'Usage: qra66sim "msg" A|B freq fDop DT Nfiles SNR' - print *, 'Example: qra66sim "K1ABC W9XYZ EN37" A 1500 0.2 0.0 1 -10' + if(nargs.ne.8) then + print *, 'Usage: qra66sim "msg" A-E freq fDop DT TRp Nfiles SNR' + print *, 'Example: qra66sim "K1ABC W9XYZ EN37" A 1500 0.2 0.0 15 1 -10' go to 999 endif call getarg(1,msg) @@ -34,32 +33,48 @@ program qra66sim call getarg(5,arg) read(arg,*) xdt call getarg(6,arg) - read(arg,*) nfiles + read(arg,*) ntrperiod call getarg(7,arg) + read(arg,*) nfiles + call getarg(8,arg) read(arg,*) snrdb - + + if(ntrperiod.eq.15) then + nsps=1800 + else if(ntrperiod.eq.30) then + nsps=3600 + else if(ntrperiod.eq.60) then + nsps=7680 + else if(ntrperiod.eq.120) then + nsps=16000 + else if(ntrperiod.eq.300) then + nsps=41472 + else + print*,'Invalid TR period' + go to 999 + endif + rms=100. fsample=12000.d0 !Sample rate (Hz) + npts=fsample*ntrperiod !Total samples in .wav file + nfft=npts + nh=nfft/2 dt=1.d0/fsample !Sample interval (s) twopi=8.d0*atan(1.d0) - npts=NMAX !Total samples in .wav file - nsps=1800 nsym=85 !Number of channel symbols - if(csubmode.eq.'B') then - nsps=nsps/2 - nsym=2*nsym-1 - endif + mode66=2**(ichar(csubmode) - ichar('A')) + print*,csubmode,mode66 ichk=66 !Flag sent to genqra64 call genqra64(msg,ichk,msgsent,itone,itype) write(*,1001) itone 1001 format('Channel symbols:'/(20i3)) - baud=12000.d0/nsps !Keying rate = 6.25 baud + baud=12000.d0/nsps !Keying rate (6.67 baud fot 15-s sequences) h=default_header(12000,npts) write(*,1000) -1000 format('File Freq A|B S/N DT Dop Message'/60('-')) +1000 format('File Freq A-E S/N DT Dop Message'/60('-')) do ifile=1,nfiles !Loop over requested number of files write(fname,1002) ifile !Output filename @@ -85,9 +100,8 @@ program qra66sim do i=1,npts !Add this signal into cdat() isym=i/nsps + 1 if(isym.gt.nsym) exit - if(csubmode.eq.'B' .and. isym.gt.84) isym=isym-84 if(isym.ne.isym0) then - freq=f0 + itone(isym)*baud + freq=f0 + itone(isym)*baud*mode66 dphi=twopi*freq*dt isym0=isym endif @@ -102,9 +116,9 @@ program qra66sim if(fspread.ne.0) then !Apply specified Doppler spread df=12000.0/nfft cspread(0)=1.0 - cspread(NH)=0. + cspread(nh)=0. b=6.0 !Use truncated Lorenzian shape for fspread - do i=1,NH + do i=1,nh f=i*df x=b*f/fspread z=0. @@ -120,12 +134,12 @@ program qra66sim phi2=twopi*rran() z=a*cmplx(cos(phi2),sin(phi2)) endif - cspread(NFFT-i)=z + cspread(nfft-i)=z enddo -! do i=0,NFFT-1 +! do i=0,nfft-1 ! f=i*df -! if(i.gt.NH) f=(i-nfft)*df +! if(i.gt.nh) f=(i-nfft)*df ! s=real(cspread(i))**2 + aimag(cspread(i))**2 ! write(13,3000) i,f,s,cspread(i) !3000 format(i5,f10.3,3f12.6) @@ -133,19 +147,19 @@ program qra66sim ! s=real(cspread(0))**2 + aimag(cspread(0))**2 ! write(13,3000) 1024,0.0,s,cspread(0) - call four2a(cspread,NFFT,1,1,1) !Transform to time domain + call four2a(cspread,nfft,1,1,1) !Transform to time domain sum=0. - do i=0,NFFT-1 + do i=0,nfft-1 p=real(cspread(i))**2 + aimag(cspread(i))**2 sum=sum+p enddo - avep=sum/NFFT + avep=sum/nfft fac=sqrt(1.0/avep) cspread=fac*cspread !Normalize to constant avg power cdat=cspread*cdat !Apply Rayleigh fading -! do i=0,NFFT-1 +! do i=0,nfft-1 ! p=real(cspread(i))**2 + aimag(cspread(i))**2 ! write(14,3010) i,p,cspread(i) !3010 format(i8,3f12.6) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 308dd97a2..c1d6dd804 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -28,32 +28,51 @@ module qra66_decode contains - subroutine decode(this,callback,iwave,nutc,nfqso,ntol,ndepth, & + subroutine decode(this,callback,iwave,nutc,ntrperiod,nfqso,ntol,ndepth, & mycall,hiscall,hisgrid) use timer_module, only: timer use packjt use, intrinsic :: iso_c_binding - parameter (NFFT1=15*12000,NFFT2=15*6000) + parameter (NMAX=60*12000) !### Needs to be 300*12000 ### class(qra66_decoder), intent(inout) :: this procedure(qra66_decode_callback) :: callback character(len=12) :: mycall, hiscall character(len=6) :: hisgrid character*37 decoded - integer*2 iwave(NFFT1) !Raw data + integer*2 iwave(NMAX) !Raw data integer dat4(12) logical lapdx,ltext - complex c0(0:NFFT1-1) !Analytic signal, 6000 S/s + complex c0(0:NMAX-1) !Analytic signal, 6000 S/s real s3(-64:127,63) real s3a(-64:127,63) real a(5) data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ save nc1z,nc2z,ng2z,maxaptypez,nsave,s3a - this%callback => callback - nsps=1800 + nfft1=ntrperiod*12000 + nfft2=ntrperiod*6000 + if(ntrperiod.eq.15) then + nsps=1800 + else if(ntrperiod.eq.30) then + nsps=3600 + else if(ntrperiod.eq.60) then + nsps=7680 + else if(ntrperiod.eq.120) then + nsps=16000 + else if(ntrperiod.eq.300) then + nsps=41472 + else + stop 'Invalid TR period' + endif baud=12000.0/nsps - df1=12000.0/NFFT1 + df1=12000.0/nfft1 + print*,'aaa',ntrperiod,hisgrid,nsps,baud + do i=1,NMAX + write(61,3061) i/12000.0,iwave(i)/32767.0 +3061 format(2f12.6) + enddo + this%callback => callback if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning @@ -87,15 +106,14 @@ contains naptype=maxaptype ! Downsample to give complex data at 6000 S/s - fac=2.0/NFFT1 + fac=2.0/nfft1 c0=fac*iwave - call four2a(c0,NFFT1,1,-1,1) !Forward c2c FFT - c0(NFFT2/2+1:NFFT2)=0. !Zero the top half + call four2a(c0,nfft1,1,-1,1) !Forward c2c FFT + c0(nfft2/2+1:nfft2)=0. !Zero the top half c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT - call timer('sync66 ',0) - call sync66(iwave,15*12000,nsps,nfqso,ntol,xdt,f0,snr1) + call sync66(iwave,60*12000,nsps,nfqso,ntol,xdt,f0,snr1) !### 300*12000 ### call timer('sync66 ',1) jpk=(xdt+0.5)*6000 - 384 !### Empirical ### if(jpk.lt.0) jpk=0 @@ -132,11 +150,11 @@ contains if(nsave.ge.2) then call qra64_dec(s3a,nc1,nc2,ng2,naptype,0,nSubmode,b90, & nFadingModel,dat4,snr2,irc) - if(irc.ge.0) irc=10*nsave + irc + if(irc.ge.0) irc=100*nsave + irc endif call timer('qra64_av',1) endif - snr2=snr2 + 5.563 !10*log(6912/1920) + snr2=snr2 + db(6912.0/nsps) if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) decoded=' ' diff --git a/lib/sync66.f90 b/lib/sync66.f90 index e259f04ac..6fbd89b27 100644 --- a/lib/sync66.f90 +++ b/lib/sync66.f90 @@ -1,19 +1,27 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) parameter (NSTEP=4) !Quarter-symbol steps - parameter (IZ=1600,JZ=352,NSPSMAX=1920) integer*2 iwave(0:nmax-1) !Raw data integer b11(11) !Barker 11 code integer ijpk(2) !Indices i and j at peak of sync_sig - real s1(IZ,JZ) !Symbol spectra - real x(JZ) !Work array; 2FSK sync modulation + real, allocatable :: s1(:,:) !Symbol spectra + real, allocatable :: x(:) !Work array; 2FSK sync modulation real sync(4*85) !sync vector real sync_sig(-64:64,-15:15) - complex c0(0:NSPSMAX) !Complex spectrum of symbol + complex, allocatable :: c0(:) !Complex spectrum of symbol data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 code data sync(1)/99.0/ save sync + nfft=2*NSPS + df=12000.0/nfft + istep=nsps/NSTEP + iz=5000.0/df + jz=352 + allocate(s1(iz,jz)) + allocate(x(jz)) + allocate(c0(0:nsps)) + if(sync(1).eq.99.0) then sync=0. do k=1,22 @@ -23,9 +31,6 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) enddo endif - nfft=2*NSPS - df=12000.0/nfft !3.125 Hz - istep=nsps/NSTEP fac=1/32767.0 do j=1,JZ !Compute symbol spectra ia=(j-1)*istep diff --git a/lib/test_qra66.f90 b/lib/test_qra66.f90 index cd20ceaf9..8ff97829c 100644 --- a/lib/test_qra66.f90 +++ b/lib/test_qra66.f90 @@ -70,7 +70,7 @@ program test_qra66 if(len(trim(line)).lt.60) cycle read(line(11:20),*) xdt,nf if(abs(xdt-dt).lt.0.15 .and. abs(nf-nf0).lt.4) nsync=nsync+1 - read(line(60:),*) irc + read(line(60:),*) irc,iavg if(irc.lt.0) cycle decok=index(line,'W9XYZ').gt.0 if(decok) then @@ -92,6 +92,8 @@ program test_qra66 write(*,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode,tdec/nfiles write(12,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode,tdec/nfiles 1100 format(i3,i2,i3,3i5,i4,i6,11i4,f6.2) + flush(6) + flush(12) enddo 999 end program test_qra66 diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 557f95488..168bf5505 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6428,7 +6428,8 @@ void MainWindow::on_actionQRA66_triggered() m_wideGraph->setModeTx(m_modeTx); m_wideGraph->setPeriod(m_TRperiod,6912); // 0123456789012345678901234567890123 - displayWidgets(nWidgets("1111100001001100000100000001000000")); +//displayWidgets(nWidgets("1111100001001100000100000001000000")); + displayWidgets(nWidgets("1111110101101101000100000011000000")); statusChanged();} void MainWindow::on_actionISCAT_triggered() diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index d3416db02..96f8e81df 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -472,7 +472,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() } if(m_mode=="QRA66") { //QRA66 - bw=65.0*12000.0/1920.0; + bw=65.0*12000.0/1800.0; } if(m_modeTx=="JT65") { //JT65 bw=65.0*11025.0/4096.0; From e4fad77fa52aa67a86131214fd61c4c8db166a59 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 8 Aug 2020 13:57:24 -0400 Subject: [PATCH 037/206] QRA66 now works with qra66sim and jt9 and TR periods 15 30 60 120 300 s. --- lib/jt9.f90 | 2 +- lib/qra/qra66/qra66sim.f90 | 19 ++++---------- lib/qra66_decode.f90 | 26 +++++++++++-------- lib/sync66.f90 | 51 ++++++++++++++++++++++++-------------- 4 files changed, 54 insertions(+), 44 deletions(-) diff --git a/lib/jt9.f90 b/lib/jt9.f90 index 1f23f3c5d..2139c66aa 100644 --- a/lib/jt9.f90 +++ b/lib/jt9.f90 @@ -249,7 +249,7 @@ program jt9 call timer('symspec ',1) endif nhsym0=nhsym - if(nhsym.ge.181 .and. mode.ne.240 .and. mode.ne.241) exit + if(nhsym.ge.181 .and. mode.ne.240 .and. mode.ne.241 .and. mode.ne.66) exit endif enddo close(unit=wav%lun) diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 index 0ed23af30..41aa55c50 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra66/qra66sim.f90 @@ -74,7 +74,7 @@ program qra66sim h=default_header(12000,npts) write(*,1000) -1000 format('File Freq A-E S/N DT Dop Message'/60('-')) +1000 format('File TR Freq Mode S/N DT Dop Message'/60('-')) do ifile=1,nfiles !Loop over requested number of files write(fname,1002) ifile !Output filename @@ -91,11 +91,12 @@ program qra66sim bandwidth_ratio=2500.0/6000.0 sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snrdb) if(snrdb.gt.90.0) sig=1.0 - write(*,1020) ifile,f0,csubmode,xsnr,xdt,fspread,msgsent -1020 format(i4,f10.3,2x,a1,2x,f5.1,f6.2,f6.1,1x,a22) + write(*,1020) ifile,ntrperiod,f0,csubmode,xsnr,xdt,fspread,msgsent +1020 format(i4,i6,f7.1,2x,a1,2x,f5.1,f6.2,f6.1,1x,a22) phi=0.d0 dphi=0.d0 - k=(xdt+0.5)*12000 !Start audio at t = xdt + 0.5 s + k=(xdt+0.5)*12000 !Start audio at t=xdt+0.5 s (TR=15 and 30 s) + if(ntrperiod.ge.60) k=(xdt+1.0)*12000 !TR 60+ at t = xdt + 1.0 s isym0=-99 do i=1,npts !Add this signal into cdat() isym=i/nsps + 1 @@ -137,16 +138,6 @@ program qra66sim cspread(nfft-i)=z enddo -! do i=0,nfft-1 -! f=i*df -! if(i.gt.nh) f=(i-nfft)*df -! s=real(cspread(i))**2 + aimag(cspread(i))**2 -! write(13,3000) i,f,s,cspread(i) -!3000 format(i5,f10.3,3f12.6) -! enddo -! s=real(cspread(0))**2 + aimag(cspread(0))**2 -! write(13,3000) 1024,0.0,s,cspread(0) - call four2a(cspread,nfft,1,1,1) !Transform to time domain sum=0. diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index c1d6dd804..3996ffdf4 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -34,7 +34,7 @@ contains use timer_module, only: timer use packjt use, intrinsic :: iso_c_binding - parameter (NMAX=60*12000) !### Needs to be 300*12000 ### + parameter (NMAX=300*12000) !### Needs to be 300*12000 ### class(qra66_decoder), intent(inout) :: this procedure(qra66_decode_callback) :: callback character(len=12) :: mycall, hiscall @@ -43,7 +43,7 @@ contains integer*2 iwave(NMAX) !Raw data integer dat4(12) logical lapdx,ltext - complex c0(0:NMAX-1) !Analytic signal, 6000 S/s + complex, allocatable :: c0(:) !Analytic signal, 6000 S/s real s3(-64:127,63) real s3a(-64:127,63) real a(5) @@ -52,6 +52,8 @@ contains nfft1=ntrperiod*12000 nfft2=ntrperiod*6000 + allocate (c0(0:nfft1-1)) + if(ntrperiod.eq.15) then nsps=1800 else if(ntrperiod.eq.30) then @@ -67,11 +69,12 @@ contains endif baud=12000.0/nsps df1=12000.0/nfft1 - print*,'aaa',ntrperiod,hisgrid,nsps,baud - do i=1,NMAX - write(61,3061) i/12000.0,iwave(i)/32767.0 -3061 format(2f12.6) - enddo + +! do i=1,NMAX +! write(61,3061) i/12000.0,iwave(i)/32767.0 +!3061 format(2f12.6) +! enddo + this%callback => callback if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning @@ -107,19 +110,20 @@ contains ! Downsample to give complex data at 6000 S/s fac=2.0/nfft1 - c0=fac*iwave + c0=fac*iwave(1:nfft1) call four2a(c0,nfft1,1,-1,1) !Forward c2c FFT c0(nfft2/2+1:nfft2)=0. !Zero the top half c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT call timer('sync66 ',0) - call sync66(iwave,60*12000,nsps,nfqso,ntol,xdt,f0,snr1) !### 300*12000 ### + call sync66(iwave,ntrperiod*12000,nsps,nfqso,ntol,xdt,f0,snr1) call timer('sync66 ',1) - jpk=(xdt+0.5)*6000 - 384 !### Empirical ### + jpk=(xdt+0.5)*6000 - 384 !### Empirical ### + if(ntrperiod.ge.60) jpk=(xdt+1.0)*6000 - 384 !### TBD ### if(jpk.lt.0) jpk=0 a=0. a(1)=-(f0 + 2.0*baud) !Data tones start 2 bins higher - call twkfreq(c0,c0,15*6000,6000.0,a) + call twkfreq(c0,c0,ntrperiod*6000,6000.0,a) xdt=jpk/6000.0 - 0.5 call spec66(c0(jpk:),nsps/2,s3) diff --git a/lib/sync66.f90 b/lib/sync66.f90 index 6fbd89b27..0c966ebf3 100644 --- a/lib/sync66.f90 +++ b/lib/sync66.f90 @@ -5,7 +5,7 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) integer b11(11) !Barker 11 code integer ijpk(2) !Indices i and j at peak of sync_sig real, allocatable :: s1(:,:) !Symbol spectra - real, allocatable :: x(:) !Work array; 2FSK sync modulation + real, allocatable :: x(:) !Work array; demoduated 2FSK sync signal real sync(4*85) !sync vector real sync_sig(-64:64,-15:15) complex, allocatable :: c0(:) !Complex spectrum of symbol @@ -13,11 +13,13 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) data sync(1)/99.0/ save sync - nfft=2*NSPS + nfft=2*nsps df=12000.0/nfft istep=nsps/NSTEP - iz=5000.0/df - jz=352 + iz=5000.0/df !Uppermost frequency bin, at 5000 Hz + txt=85.0*nsps/12000.0 + jz=(txt+1.0)*12000.0/istep !Number of quarter-symbol steps + if(nsps.ge.7680) jz=(txt+2.0)*12000.0/istep !For TR 60 s and higher allocate(s1(iz,jz)) allocate(x(jz)) allocate(c0(0:nsps)) @@ -27,12 +29,13 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) do k=1,22 kk=k if(kk.gt.11) kk=k-11 - sync(16*k-15)=2.0*b11(kk) - 1.0 + i=4*NSTEP*(k-1) + 1 + sync(i)=2.0*b11(kk) - 1.0 enddo endif fac=1/32767.0 - do j=1,JZ !Compute symbol spectra + do j=1,jz !Compute symbol spectra at quarter-symbol steps ia=(j-1)*istep ib=ia+nsps-1 k=-1 @@ -44,34 +47,43 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) enddo c0(k+1:nfft/2)=0. call four2a(c0,nfft,1,-1,0) !r2c FFT - do i=1,IZ + do i=1,iz s1(i,j)=real(c0(i))**2 + aimag(c0(i))**2 enddo enddo i0=nint(nfqso/df) - call pctile(s1(i0-64:i0+192,1:JZ),129*JZ,40,base) + call pctile(s1(i0-64:i0+192,1:jz),129*jz,40,base) s1=s1/base s1max=20.0 ! Apply AGC - do j=1,JZ + do j=1,jz x(j)=maxval(s1(i0-64:i0+192,j)) if(x(j).gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/x(j) enddo - dt4=nsps/(NSTEP*12000.0) - j0=0.5/dt4 - sync_sig=0. ia=min(64,nint(ntol/df)) + dt4=nsps/(NSTEP*12000.0) !duration of 1/4 symbol + lag2=nint(0.5/dt4) + if(nsps.ge.7680) lag2=nint(1.0/dt4) + lag1=-lag2 + + jadd=11 + if(nsps.ge.3600) jadd=7 + if(nsps.ge.7680) jadd=6 + if(nsps.ge.16000) jadd=3 + if(nsps.ge.41472) jadd=1 + do i=-ia,ia - x=s1(i0+2+i,:)-s1(i0+i,:) + x=s1(i0+2+i,:)-s1(i0+i,:) !Do the 2FSK demodulation +! do lag=lag1,lag2 do lag=-15,15 -! Make this simpler: just add the 22 nonzero values? - do n=1,4*85 - j=n+lag+11 - if(j.ge.1 .and. j.le.JZ) sync_sig(i,lag)=sync_sig(i,lag) + sync(n)*x(j) + do k=1,22 + n=4*NSTEP*(k-1) + 1 + j=n+lag+jadd + if(j.ge.1 .and. j.le.jz) sync_sig(i,lag)=sync_sig(i,lag) + sync(n)*x(j) enddo enddo enddo @@ -83,6 +95,10 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) ! Use peakup() here? f0=nfqso + ii*df jdt=jj + +! j0=0.5/dt4 +! if(nsps.ge.7680) j0=1.0/dt4 + tsym=nsps/12000.0 xdt=jdt*tsym/4.0 @@ -100,4 +116,3 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) return end subroutine sync66 - From d683cb6b8ee82e932e0c3d17d64058c551964adf Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 8 Aug 2020 14:37:01 -0400 Subject: [PATCH 038/206] Updates to GUI for different QRA66 sequence lengths and submodes. --- widgets/mainwindow.cpp | 47 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 168bf5505..678dfce87 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -1367,7 +1367,11 @@ void MainWindow::fixStop() m_hsymStop=179; if(m_config.decode_at_52s()) m_hsymStop=186; } else if (m_mode=="QRA66"){ - m_hsymStop=49; + m_hsymStop=48; + if(m_TRperiod==30) m_hsymStop=96; + if(m_TRperiod==60) m_hsymStop=196; + if(m_TRperiod==120) m_hsymStop=401; + if(m_TRperiod==300) m_hsymStop=1027; } else if (m_mode=="FreqCal"){ m_hsymStop=((int(m_TRperiod/0.288))/8)*8; } else if (m_mode=="FT8") { @@ -3684,7 +3688,13 @@ void MainWindow::guiUpdate() if(m_modeTx=="JT9") txDuration=1.0 + 85.0*m_nsps/12000.0; // JT9 if(m_modeTx=="JT65") txDuration=1.0 + 126*4096/11025.0; // JT65 if(m_modeTx=="QRA64") txDuration=1.0 + 84*6912/12000.0; // QRA64 - if(m_modeTx=="QRA66") txDuration=0.5 + 85*1920/12000.0; // QRA66 + if(m_modeTx=="QRA66") { // QRA66 + if(m_TRperiod==15) txDuration=0.5 + 85*1800/12000.0; + if(m_TRperiod==30) txDuration=0.5 + 85*3600/12000.0; + if(m_TRperiod==60) txDuration=1.0 + 85*7680/12000.0; + if(m_TRperiod==120) txDuration=1.0 + 85*16000/12000.0; + if(m_TRperiod==300) txDuration=1.0 + 85*41472/12000.0; + } if(m_modeTx=="WSPR") txDuration=2.0 + 162*8192/12000.0; // WSPR if(m_modeTx=="FST4" or m_mode=="FST4W") { //FST4, FST4W if(m_TRperiod==15) txDuration=1.0 + 160*720/12000.0; @@ -4248,7 +4258,7 @@ void MainWindow::guiUpdate() //Once per second: if(nsec != m_sec0) { -// qDebug() << "AAA" << nsec; +// qDebug() << "onesec" << m_hsymStop << m_TRperiod; m_currentBand=m_config.bands()->find(m_freqNominal); if( SpecOp::HOUND == m_config.special_op_id() ) { qint32 tHound=QDateTime::currentMSecsSinceEpoch()/1000 - m_tAutoOn; @@ -6423,7 +6433,8 @@ void MainWindow::on_actionQRA66_triggered() switch_mode (Modes::QRA64); setup_status_bar (false); m_hsymStop=49; - m_TRperiod=15.0; + ui->sbTR->values ({15, 30, 60, 120, 300}); + on_sbTR_valueChanged (ui->sbTR->value()); m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); m_wideGraph->setPeriod(m_TRperiod,6912); @@ -7391,9 +7402,15 @@ void MainWindow::transmit (double snr) } if (m_modeTx == "QRA66") { - toneSpacing=12000.0/1800.0; + int nsps=1800; + if(m_TRperiod==30) nsps=3600; + if(m_TRperiod==60) nsps=7680; + if(m_TRperiod==120) nsps=16000; + if(m_TRperiod==300) nsps=41472; + int mode66=pow(2.0,double(m_nSubMode)); + toneSpacing=mode66*12000.0/nsps; Q_EMIT sendMessage (m_mode, NUM_QRA66_SYMBOLS, - 1800.0, ui->TxFreqSpinBox->value () - m_XIT, + double(nsps), ui->TxFreqSpinBox->value () - m_XIT, toneSpacing, m_soundOutput, m_config.audio_output_channel (), true, false, snr, m_TRperiod); } @@ -7651,23 +7668,17 @@ void::MainWindow::VHF_features_enabled(bool b) void MainWindow::on_sbTR_valueChanged(int value) { // if(!m_bFastMode and n>m_nSubMode) m_MinW=m_nSubMode; - if(m_bFastMode or m_mode=="FreqCal" or m_mode=="FST4" or m_mode=="FST4W") { + if(m_bFastMode or m_mode=="FreqCal" or m_mode=="FST4" or m_mode=="FST4W" or m_mode=="QRA66") { m_TRperiod = value; - if (m_mode == "FST4" || m_mode == "FST4W") - { - if (m_TRperiod < 60) - { + if (m_mode == "FST4" or m_mode == "FST4W" or m_mode=="QRA66") { + if (m_TRperiod < 60) { ui->decodedTextLabel->setText(" UTC dB DT Freq " + tr ("Message")); - if (m_mode != "FST4W") - { + if (m_mode != "FST4W") { ui->decodedTextLabel2->setText(" UTC dB DT Freq " + tr ("Message")); } - } - else - { + } else { ui->decodedTextLabel->setText("UTC dB DT Freq " + tr ("Message")); - if (m_mode != "FST4W") - { + if (m_mode != "FST4W") { ui->decodedTextLabel2->setText("UTC dB DT Freq " + tr ("Message")); } } From de0476bf3c70b0eb0ea48f763f530226c74879f0 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 8 Aug 2020 16:53:28 -0400 Subject: [PATCH 039/206] More changes to allow longer sequences in QRA66 mode. --- lib/decoder.f90 | 15 +++++++++++---- lib/qra/qra66/qra66sim.f90 | 14 ++++++++++---- widgets/plotter.cpp | 9 ++++++++- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 269d70423..33146a593 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -197,8 +197,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) if(params%nmode.eq.66) then ! We're in QRA66 mode call timer('decqra66',0) - call my_qra66%decode(qra66_decoded,id2,params%nutc,params%ntr,params%nfqso, & - params%ntol,params%ndepth,mycall,hiscall,hisgrid) + call my_qra66%decode(qra66_decoded,id2,params%nutc,params%ntr, & + params%nfqso,params%ntol,params%ndepth,mycall,hiscall,hisgrid) call timer('decqra66',1) go to 800 endif @@ -796,11 +796,18 @@ contains integer navg navg=irc/100 - write(*,1001) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg -1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) + if(ntrperiod.lt.60) then + write(*,1001) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg +1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded 1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA66') + else + write(*,1003) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg +1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) + write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded +1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA66') + endif call flush(6) call flush(13) diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 index 41aa55c50..1171542ad 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra66/qra66sim.f90 @@ -14,7 +14,7 @@ program qra66sim complex cspread(0:NMAX-1) !Complex amplitude for Rayleigh fading complex z real*8 f0,dt,twopi,phi,dphi,baud,fsample,freq - character msg*22,fname*13,csubmode*1,arg*12 + character msg*22,fname*17,csubmode*1,arg*12 character msgsent*22 nargs=iargc() @@ -77,9 +77,15 @@ program qra66sim 1000 format('File TR Freq Mode S/N DT Dop Message'/60('-')) do ifile=1,nfiles !Loop over requested number of files - write(fname,1002) ifile !Output filename -1002 format('000000_',i6.6) - open(10,file=fname//'.wav',access='stream',status='unknown') + if(ntrperiod.lt.60) then + write(fname,1002) ifile !Output filename +1002 format('000000_',i6.6,'.wav') + else + write(fname,1104) ifile +1104 format('000000_',i4.4,'.wav') + endif + + open(10,file=trim(fname),access='stream',status='unknown') xnoise=0. cdat=0. if(snrdb.lt.90) then diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index 96f8e81df..fcac2d707 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -472,7 +472,14 @@ void CPlotter::DrawOverlay() //DrawOverlay() } if(m_mode=="QRA66") { //QRA66 - bw=65.0*12000.0/1800.0; + int h=int(pow(2.0,m_nSubMode)); + int nsps=1800; + if(m_TRperiod==30) nsps=3600; + if(m_TRperiod==60) nsps=7680; + if(m_TRperiod==120) nsps=16000; + if(m_TRperiod==300) nsps=41472; + float baud=12000.0/nsps; + bw=65.0*h*baud; } if(m_modeTx=="JT65") { //JT65 bw=65.0*11025.0/4096.0; From 84e53960cda3c9e4286a4d6bc771beccbfdb33da Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 9 Aug 2020 11:04:49 -0400 Subject: [PATCH 040/206] QRA66 now works up for submodes A-D up to 300 s periods. Submode E presently NG. --- lib/decoder.f90 | 7 ++++--- lib/qra66_decode.f90 | 40 +++++++++++++++++++++++++--------------- lib/spec66.f90 | 8 ++++---- lib/sync66.f90 | 12 ++++++------ 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 33146a593..d3fb4c866 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -197,8 +197,9 @@ subroutine multimode_decoder(ss,id2,params,nfsample) if(params%nmode.eq.66) then ! We're in QRA66 mode call timer('decqra66',0) - call my_qra66%decode(qra66_decoded,id2,params%nutc,params%ntr, & - params%nfqso,params%ntol,params%ndepth,mycall,hiscall,hisgrid) + call my_qra66%decode(qra66_decoded,id2,params%nutc,params%ntr, & + params%nsubmode,params%nfqso,params%ntol,params%ndepth, & + mycall,hiscall,hisgrid) call timer('decqra66',1) go to 800 endif @@ -209,7 +210,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) iwspr=0 if(iand(params%ndepth,128).ne.0) iwspr=2 call timer('dec240 ',0) - call my_fst4%decode(fst4_decoded,id2,params%nutc, & + call my_fst4%decode(fst4_decoded,id2,params%nutc, & params%nQSOProgress,params%nfqso,params%nfa,params%nfb, & params%nsubmode,ndepth,params%ntr,params%nexp_decode, & params%ntol,params%emedelay, & diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index 3996ffdf4..f175fb0ba 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -28,8 +28,8 @@ module qra66_decode contains - subroutine decode(this,callback,iwave,nutc,ntrperiod,nfqso,ntol,ndepth, & - mycall,hiscall,hisgrid) + subroutine decode(this,callback,iwave,nutc,ntrperiod,nsubmode,nfqso, & + ntol,ndepth,mycall,hiscall,hisgrid) use timer_module, only: timer use packjt @@ -44,15 +44,23 @@ contains integer dat4(12) logical lapdx,ltext complex, allocatable :: c0(:) !Analytic signal, 6000 S/s - real s3(-64:127,63) - real s3a(-64:127,63) + real, allocatable, save :: s3(:,:) !Symbol spectra + real, allocatable, save :: s3a(:,:) !Symbol spectra for avg messages real a(5) - data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ - save nc1z,nc2z,ng2z,maxaptypez,nsave,s3a + data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/,nsubmodez/-1/ + save nc1z,nc2z,ng2z,maxaptypez,nsave,nsubmodez + mode66=2**nsubmode nfft1=ntrperiod*12000 nfft2=ntrperiod*6000 allocate (c0(0:nfft1-1)) + + if(nsubmode.ne.nsubmodez) then + if(allocated(s3)) deallocate(s3) + if(allocated(s3a)) deallocate(s3a) + allocate(s3(-64:64*mode66+63,63)) + allocate(s3a(-64:64*mode66+63,63)) + endif if(ntrperiod.eq.15) then nsps=1800 @@ -83,7 +91,6 @@ contains call packcall(mycall(1:6),nc1,ltext) call packcall(hiscall(1:6),nc2,ltext) call packgrid(hisgrid(1:4),ng2,ltext) - nSubmode=0 b90=20.0 !8 to 25 is OK; not very critical nFadingModel=1 @@ -116,28 +123,31 @@ contains c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT call timer('sync66 ',0) - call sync66(iwave,ntrperiod*12000,nsps,nfqso,ntol,xdt,f0,snr1) + call sync66(iwave,ntrperiod*12000,mode66,nsps,nfqso,ntol,xdt,f0,snr1) call timer('sync66 ',1) + jpk=(xdt+0.5)*6000 - 384 !### Empirical ### if(ntrperiod.ge.60) jpk=(xdt+1.0)*6000 - 384 !### TBD ### if(jpk.lt.0) jpk=0 a=0. - a(1)=-(f0 + 2.0*baud) !Data tones start 2 bins higher + a(1)=-(f0 + 2.0*mode66*baud) !Data tones start 2*mode66 bins higher call twkfreq(c0,c0,ntrperiod*6000,6000.0,a) xdt=jpk/6000.0 - 0.5 - call spec66(c0(jpk:),nsps/2,s3) + + LL=64*(mode66+2) + NN=63 + call spec66(c0(jpk:),nsps/2,s3,LL,NN) !Compute the synchronized symbol spectra do j=1,63 !Normalize to symbol baseline - call pctile(s3(:,j),192,40,base) + call pctile(s3(:,j),LL,40,base) s3(:,j)=s3(:,j)/base -! write(71,3071)j,maxloc(s3(:,j)) -!3071 format(2i5) enddo + LL2=64*(mode66+1)-1 s3max=20.0 do j=1,63 !Apply AGC to suppress pings - xx=maxval(s3(-64:127,j)) - if(xx.gt.s3max) s3(-64:127,j)=s3(-64:127,j)*s3max/xx + xx=maxval(s3(-64:LL2,j)) + if(xx.gt.s3max) s3(-64:LL2,j)=s3(-64:LL2,j)*s3max/xx enddo ! Call Nico's QRA64 decoder diff --git a/lib/spec66.f90 b/lib/spec66.f90 index 0d381cf78..0d049fddb 100644 --- a/lib/spec66.f90 +++ b/lib/spec66.f90 @@ -1,11 +1,11 @@ -subroutine spec66(c0,nsps,s3) +subroutine spec66(c0,nsps,s3,LL,NN) + +! Compute synchronized symbol spectra. - parameter (LL=3*64) !Frequency channels - parameter (NN=63) !Data symbols complex c0(0:85*nsps-1) !Synchronized complex data at 6000 S/s complex cs(0:nsps-1) !Complex symbol spectrum real s3(LL,NN) !Synchronized symbol spectra - real xbase0(LL),xbase(LL) + real xbase0(LL),xbase(LL) !Work arrays fac=1.0/nsps ja=-nsps diff --git a/lib/sync66.f90 b/lib/sync66.f90 index 0c966ebf3..3cd0188bb 100644 --- a/lib/sync66.f90 +++ b/lib/sync66.f90 @@ -1,4 +1,4 @@ -subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) +subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) parameter (NSTEP=4) !Quarter-symbol steps integer*2 iwave(0:nmax-1) !Raw data @@ -35,7 +35,7 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) endif fac=1/32767.0 - do j=1,jz !Compute symbol spectra at quarter-symbol steps + do j=1,jz !Compute symbol spectra at quarter-symbol steps ia=(j-1)*istep ib=ia+nsps-1 k=-1 @@ -66,9 +66,9 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) sync_sig=0. ia=min(64,nint(ntol/df)) dt4=nsps/(NSTEP*12000.0) !duration of 1/4 symbol - lag2=nint(0.5/dt4) - if(nsps.ge.7680) lag2=nint(1.0/dt4) - lag1=-lag2 +! lag2=nint(0.5/dt4) +! if(nsps.ge.7680) lag2=nint(1.0/dt4) +! lag1=-lag2 jadd=11 if(nsps.ge.3600) jadd=7 @@ -77,7 +77,7 @@ subroutine sync66(iwave,nmax,nsps,nfqso,ntol,xdt,f0,snr1) if(nsps.ge.41472) jadd=1 do i=-ia,ia - x=s1(i0+2+i,:)-s1(i0+i,:) !Do the 2FSK demodulation + x=s1(i0+2*mode66+i,:)-s1(i0+i,:) !Do the 2FSK demodulation ! do lag=lag1,lag2 do lag=-15,15 do k=1,22 From 42626009b57f3a8f5f7be17559d66ea7342e59f1 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 9 Aug 2020 14:21:25 -0400 Subject: [PATCH 041/206] TEMPORARY: Diagnostic routine for the "Save All" missing files problem. --- lib/symspec.f90 | 32 ++++++++++++++++++++++++++++++++ widgets/mainwindow.cpp | 2 ++ 2 files changed, 34 insertions(+) diff --git a/lib/symspec.f90 b/lib/symspec.f90 index a3bed192f..64c88815e 100644 --- a/lib/symspec.f90 +++ b/lib/symspec.f90 @@ -126,3 +126,35 @@ subroutine symspec(shared_data,k,TRperiod,nsps,ingain,bLowSidelobes, & return end subroutine symspec + +subroutine chk_samples(ihsym,k,nstop) + + integer*8 count0,count1,clkfreq + integer itime(8) + real*8 dtime,fsample + character*12 ctime + data count0/-1/,k0/99999999/,maxhsym/0/ + save count0,k0,maxhsym + + if(k.lt.k0 .or. count0.eq.-1) then + call system_clock(count0,clkfreq) + maxhsym=0 + endif + if((mod(ihsym,100).eq.0 .or. ihsym.ge.nstop-100) .and. & + k0.ne.99999999) then + call system_clock(count1,clkfreq) + dtime=dfloat(count1-count0)/dfloat(clkfreq) + if(dtime.lt.28.0) return + if(dtime.gt.1.d-6) fsample=(k-3456)/dtime + call date_and_time(values=itime) + sec=itime(7)+0.001*itime(8) + write(ctime,3000) itime(5)-itime(4)/60,itime(6),sec +3000 format(i2.2,':',i2.2,':',f6.3) + write(33,3033) ctime,dtime,ihsym,nstop,k,fsample +3033 format(a12,f12.6,2i7,i10,f15.3) + flush(33) + endif + k0=k + + return +end subroutine chk_samples diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 678dfce87..9b1bd2eb7 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -178,6 +178,7 @@ extern "C" { void get_ft4msg_(int* idecode, char* line, int len); + void chk_samples_(int* m_ihsym,int* k, int* m_hsymStop); } int volatile itone[NUM_ISCAT_SYMBOLS]; //Audio tones for all Tx symbols @@ -1436,6 +1437,7 @@ void MainWindow::dataSink(qint64 frames) if(m_mode.startsWith("FST4")) npct=ui->sbNB->value(); symspec_(&dec_data,&k,&m_TRperiod,&nsps,&m_inGain,&bLowSidelobes,&nsmo,&m_px,s, &m_df3,&m_ihsym,&m_npts8,&m_pxmax,&npct); + chk_samples_(&m_ihsym,&k,&m_hsymStop); if(m_mode=="WSPR" or m_mode=="FST4W") wspr_downsample_(dec_data.d2,&k); if(m_ihsym <=0) return; if(ui) ui->signal_meter_widget->setValue(m_px,m_pxmax); // Update thermometer From 07f63cdb63da22b7b7de135a1d582b987ec71274 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 9 Aug 2020 15:48:56 -0400 Subject: [PATCH 042/206] Small adjustment to make file names for QRA66-30 modes correct. --- widgets/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 9b1bd2eb7..956fb7e9d 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -3018,7 +3018,7 @@ void MainWindow::decode() //decode() if(m_TRperiod>=60) imin=imin - (imin % (int(m_TRperiod)/60)); dec_data.params.nutc=100*ihr + imin; if(m_TRperiod < 60) { - qint64 ms=1000.0*(2.0-m_TRperiod); + qint64 ms=1000.0*(3.5-m_TRperiod); if(m_mode=="FST4") ms=1000.0*(6.0-m_TRperiod); //Adjust for FT8 early decode: if(m_mode=="FT8" and m_ihsym==m_earlyDecode and !m_diskData) ms+=(m_hsymStop-m_earlyDecode)*288; From b6d14853c43b503aa562a85e344e6b8cbab19eea Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 10 Aug 2020 09:31:44 -0400 Subject: [PATCH 043/206] User Guide edits from Dave, KC3GPM. --- doc/user_guide/en/install-from-source.adoc | 6 +- doc/user_guide/en/install-linux.adoc | 18 +++--- doc/user_guide/en/install-mac.adoc | 8 +-- doc/user_guide/en/introduction.adoc | 10 ++-- doc/user_guide/en/logging.adoc | 24 ++++---- doc/user_guide/en/make-qso.adoc | 8 +-- doc/user_guide/en/measurement_tools.adoc | 66 +++++++++++----------- doc/user_guide/en/protocols.adoc | 21 ++++--- 8 files changed, 84 insertions(+), 77 deletions(-) diff --git a/doc/user_guide/en/install-from-source.adoc b/doc/user_guide/en/install-from-source.adoc index f106aa59b..b70e89c55 100644 --- a/doc/user_guide/en/install-from-source.adoc +++ b/doc/user_guide/en/install-from-source.adoc @@ -1,7 +1,7 @@ -// Status=review +// Status=edited Source code for _WSJT-X_ is available from a public repository at -{devrepo}. To compile the program you will need to install at least the +{devrepo}. To compile the program, at a minimum you must install the following packages: - Git @@ -19,7 +19,7 @@ cd wsjtx git checkout wsjtx-{VERSION} ===== -and for the current development branch, +and for the current development branch: ===== git clone git://git.code.sf.net/p/wsjt/wsjtx diff --git a/doc/user_guide/en/install-linux.adoc b/doc/user_guide/en/install-linux.adoc index b3075d66a..7c198ca84 100644 --- a/doc/user_guide/en/install-linux.adoc +++ b/doc/user_guide/en/install-linux.adoc @@ -1,16 +1,14 @@ -// Status=review +// Status=edited Debian, Ubuntu, and other Debian-based systems including Raspbian: -NOTE: The project team release binary installer packages for Linux -when a new _WSJT-X_ release is announced. These are built to -target one contemporary version of a Linux distribution. Although -these may work on newer Linux versions or even different -distributions, it is unlikely that they will work on older -versions. Check the notes provided with the release for details of the -targeted Linux distributions and versions. If the binary package is -not compatible with your Linux distribution or version you must build -the application from sources. +NOTE: The project team release binary installer packages targeted for +one contemporary version of a Linux distribution. Although these may +work on newer Linux versions or even different distributions, it is +unlikely that they work on older versions. Check the notes provided +with the release for details of the targeted Linux distributions and +versions. If the binary package is not compatible with your Linux +distribution or version, you must build the application from sources. * 32-bit: {debian32} - To install: diff --git a/doc/user_guide/en/install-mac.adoc b/doc/user_guide/en/install-mac.adoc index 26384805f..6595ba1c9 100644 --- a/doc/user_guide/en/install-mac.adoc +++ b/doc/user_guide/en/install-mac.adoc @@ -1,12 +1,12 @@ // These instructions are up-to-date for WSJT-X v2.2 -*OS X 10.12* and later: Download the file {osx} to your desktop, -double-click on it and consult its `ReadMe` file for important +*macOS10.13* and later: Download the file {osx} to your desktop, +double-click it and consult its `ReadMe` file for important installation notes. If you have already installed a previous version, you can retain it by -changing its name in the *Applications* folder (say, from _WSJT-X_ to -_WSJT-X_2.1_). You can then proceed to the installation phase. +changing its name in the *Applications* folder (such as from _WSJT-X_ to +_WSJT-X_2.2_). You can then proceed to the installation phase. Take note also of the following: diff --git a/doc/user_guide/en/introduction.adoc b/doc/user_guide/en/introduction.adoc index a592e5325..f172b5d35 100644 --- a/doc/user_guide/en/introduction.adoc +++ b/doc/user_guide/en/introduction.adoc @@ -4,7 +4,7 @@ _WSJT-X_ is a computer program designed to facilitate basic amateur radio communication using very weak signals. The first four letters in the program name stand for "`**W**eak **S**ignal communication by K1**JT**,`" while the suffix "`-X`" indicates that _WSJT-X_ started as -an e**Xt**ended and e**X**perimental branch of the program _WSJT_, +an extended and experimental branch of the program _WSJT_, first released in 2001. Bill Somerville, G4WJS, and Steve Franke, K9AN, have been major contributors to program development since 2013 and 2015, respectively. @@ -16,7 +16,7 @@ making reliable QSOs under weak-signal conditions. They use nearly identical message structure and source encoding. JT65 and QRA64 were designed for EME ("`moonbounce`") on the VHF/UHF bands and have also proven very effective for worldwide QRP communication on the HF bands. -QRA64 has a some advantages over JT65, including better performance +QRA64 has some advantages over JT65, including better performance for EME on the higher microwave bands. JT9 was originally designed for the LF, MF, and lower HF bands. Its submode JT9A is 2 dB more sensitive than JT65 while using less than 10% of the bandwidth. JT4 @@ -27,7 +27,7 @@ reception, so a minimal QSO takes four to six minutes — two or three transmissions by each station, one sending in odd UTC minutes and the other even. FT8 is operationally similar but four times faster (15-second T/R sequences) and less sensitive by a few dB. FT4 is -faster still (7.5 s T/R sequences) and especially well suited for +faster still (7.5 s T/R sequences) and especially well-suited for radio contesting. On the HF bands, world-wide QSOs are possible with any of these modes using power levels of a few watts (or even milliwatts) and compromise antennas. On VHF bands and higher, QSOs @@ -45,7 +45,7 @@ protocols designed to take advantage of brief signal enhancements from ionized meteor trails, aircraft scatter, and other types of scatter propagation. These modes use timed sequences of 5, 10, 15, or 30 s duration. User messages are transmitted repeatedly at high rate (up -to 250 characters per second, for MSK144) to make good use of the +to 250 characters per second for MSK144) to make good use of the shortest meteor-trail reflections or "`pings`". ISCAT uses free-form messages up to 28 characters long, while MSK144 uses the same structured messages as the slow modes and optionally an abbreviated @@ -80,4 +80,4 @@ be beta releases leading up to the final release of v2.1.0. Release candidates should be used _only_ during a short testing period. They carry an implied obligation to provide feedback to the program development group. Candidate releases should not be used on -the air after a full release with the same number has been made. +the air after a full release with the same number is made. diff --git a/doc/user_guide/en/logging.adoc b/doc/user_guide/en/logging.adoc index 4176a2a40..a3193ba25 100644 --- a/doc/user_guide/en/logging.adoc +++ b/doc/user_guide/en/logging.adoc @@ -1,7 +1,9 @@ +//status: edited + A basic logging facility in _WSJT-X_ saves QSO information to files named `wsjtx.log` (in comma-separated text format) and `wsjtx_log.adi` (in standard ADIF format). These files can be imported directly into -other programs, for example spreadsheets and popular logging programs. +other programs (such as spreadsheets and popular logging programs). As described in the <> and <> sections, different operating systems may place your local log files in different locations. You can always navigate to @@ -12,30 +14,32 @@ applications like {jtalert}, which can log QSOs automatically to other applications including {hrd}, {dxlsuite}, and {log4om}. The program option *Show DXCC entity and worked before status* -(selectable on the *Settings | General* tab) is intended mostly for +(selectable on the *File | Settings | General* tab) is intended mostly for use on non-Windows platforms, where {jtalert} is not available. When -this option is checked _WSJT-X_ appends some additional information to +this option is checked, _WSJT-X_ appends some additional information to all CQ messages displayed in the _Band Activity_ window. The name of the DXCC entity is shown, abbreviated if necessary. Your "`worked before`" status for this callsign (according to log file `wsjtx_log.adi`) is indicated by highlighting colors, if that option -has been selected. +is selected. _WSJT-X_ includes a built-in `cty.dat` file containing DXCC prefix information. Updated files can be downloaded from the {cty_dat} web -site when required. If an updated `cty.dat` is present in the logs -folder and readable, it will be used in preference to the built-in -one. +site when required. If an updated and readable `cty.dat` file is +present in the logs folder, it is used in preference to the +built-in file. The log file `wsjtx_log.adi` is updated whenever you log a QSO from -_WSJT-X_. (Keep in mind that if you erase this file you will lose all +_WSJT-X_. (Keep in mind that if you erase this file, you lose all "`worked before`" information.) You can append or overwrite the `wsjtx_log.adi` file by exporting your QSO history as an ADIF file from another logging program. Turning *Show DXCC entity and worked -before status* off and then on again will cause _WSJT-X_ to re-read +before status* off and then on again causes _WSJT-X_ to re-read the log file. Very large log files may cause _WSJT-X_ to slow down -when searching for calls. If the ADIF log file has been changed +when searching for calls. If the ADIF log file has been changed outside of _WSJT-X_ you can force _WSJT-X_ to reload the file from the *Settings | Colors* tab using the *Rescan ADIF Log* button, see <>. +Additional features are provided for *Contest* and *Fox* logging. +(more to come, here ...) diff --git a/doc/user_guide/en/make-qso.adoc b/doc/user_guide/en/make-qso.adoc index 03f02fd46..725bafe73 100644 --- a/doc/user_guide/en/make-qso.adoc +++ b/doc/user_guide/en/make-qso.adoc @@ -37,7 +37,7 @@ assigns more reliable numbers to relatively strong signals. NOTE: Signals become visible on the waterfall around S/N = –26 dB and audible (to someone with very good hearing) around –15 dB. Thresholds for decodability are around -20 dB for FT8, -23 dB for JT4, –25 dB for -JT65, –27 dB for JT9. +JT65, and –27 dB for JT9. NOTE: Several options are available for circumstances where fast QSOs are desirable. Double-click the *Tx1* control under _Now_ or _Next_ @@ -75,7 +75,7 @@ When calling CQ you may also choose to check the box *Call 1st*. _WSJT-X_ will then respond automatically to the first decoded responder to your CQ. -NOTE: When *Auto-Seq* is enabled the program de-activates *Enable Tx* +NOTE: When *Auto-Seq* is enabled, the program de-activates *Enable Tx* at the end of each QSO. It is not intended that _WSJT-X_ should make fully automated QSOs. @@ -259,7 +259,7 @@ that a second callsign is never permissible in these messages. NOTE: During a transmission your outgoing message is displayed in the first label on the *Status Bar* and shown exactly as another station -will receive it. You can check to see that you are actually +receives it. You can check to see that you are actually transmitting the message you wish to send. QSOs involving *Type 2* compound callsigns might look like either @@ -287,7 +287,7 @@ standard structured messages without callsign prefix or suffix. TIP: If you are using a compound callsign, you may want to experiment with the option *Message generation for type 2 compound -callsign holders* on the *Settings | General* tab, so that messages +callsign holders* on the *File | Settings | General* tab, so that messages will be generated that best suit your needs. === Pre-QSO Checklist diff --git a/doc/user_guide/en/measurement_tools.adoc b/doc/user_guide/en/measurement_tools.adoc index 766939e7c..fe501d650 100644 --- a/doc/user_guide/en/measurement_tools.adoc +++ b/doc/user_guide/en/measurement_tools.adoc @@ -1,6 +1,8 @@ +//Status: edited + === Frequency Calibration -Many _WSJT-X_ capabilities depend on signal-detection bandwidths no +Many _WSJT-X_ capabilities depend on signal-detection bandwidths of no more than a few Hz. Frequency accuracy and stability are therefore unusually important. We provide tools to enable accurate frequency calibration of your radio, as well as precise frequency measurement of @@ -11,11 +13,11 @@ measuring the error in dial frequency for each signal. You will probably find it convenient to define and use a special <> dedicated to frequency calibration. -Then complete the following steps, as appropriate for your system. +Then complete the following steps, as appropriate, for your system. - Switch to FreqCal mode -- In the _Working Frequencies_ box on the *Settings -> Frequencies* +- In the _Working Frequencies_ box on the *File | Settings | Frequencies* tab, delete any default frequencies for *FreqCal* mode that are not relevant for your location. You may want to replace some of them with reliably known frequencies receivable at your location. @@ -29,14 +31,14 @@ of WWV at 2.500, 5.000, 10.000, 15.000, and 20.000 MHz, and CHU at 3.330, 7.850, and 14.670 MHz. Similar shortwave signals are available in other parts of the world. -- In most cases you will want to start by deleting any existing file -`fmt.all` in the directory where your log files are kept. +- In most cases, start by deleting any existing file `fmt.all` in the +directory where your log files are kept. - To cycle automatically through your chosen list of calibration frequencies, check *Execute frequency calibration cycle* on the *Tools* menu. _WSJT-X_ will spend 30 seconds at each frequency. Initially no measurement data is saved to the `fmt.all` -file although it is displayed on screen, this allows you to check your +file although it is displayed on screen; this allows you to check your current calibration parameters. - During the calibration procedure, the radio's USB dial frequency is @@ -61,7 +63,7 @@ the nominal frequency itself (in MHz). For example, the 20 MHz measurement for WWV shown above produced a measured tone offset of 24.6 Hz, displayed in the _WSJT-X_ decoded text window. The resulting calibration constant is 24.6/20=1.23 parts per million. This number -may be entered as *Slope* on the *settings -> Frequencies* tab. +may be entered as *Slope* on the *File | Settings | Frequencies* tab. A more precise calibration can be effected by fitting the intercept and slope of a straight line to the whole sequence of calibration @@ -81,19 +83,19 @@ After running *Execute frequency calibration cycle* at least once with good results, check and edit the file `fmt.all` in the log directory and delete any spurious or outlier measurements. The line-fitting procedure can then be carried out automatically by clicking *Solve for -calibration parameters* on the *Tools* menu. The results will be +calibration parameters* on the *Tools* menu. The results are displayed as in the following screen shot. Estimated uncertainties are included for slope and intercept; `N` is the number of averaged frequency measurements included in the fit, and `StdDev` is the root mean square deviation of averaged measurements from the fitted -straight line. If the solution seems valid you will be offered an -*Apply* button to push that will automatically set the calibration -parameters in *Settings -> Frequencies -> Frequency Calibration*. +straight line. If the solution seems valid, you are offered an +*Apply* button to push that automatically sets the calibration +parameters in *File | Settings | Frequencies | Frequency Calibration*. image::FreqCal_Results.png[align="center",alt="FreqCal_Results"] For a quick visual check of the resulting calibration, stay in -*FreqCal* mode with the *Measure* option cleared. _WSJT-X_ will show +*FreqCal* mode with the *Measure* option cleared. _WSJT-X_ shows the adjusted results directly on the waterfall and the displayed records. @@ -103,8 +105,8 @@ _WSJT-X_ provides a tool that can be used to determine the detailed shape of your receiver's passband. Disconnect your antenna or tune to a quiet frequency with no signals. With _WSJT-X_ running in one of the slow modes, select *Measure reference spectrum* from the *Tools* -menu. Wait for about a minute and then hit the *Stop* button. A file -named `refspec.dat` will appear in your log directory. When you check +menu. Wait for about a minute and then click *Stop*. A file +named `refspec.dat` appears in your log directory. When you check *Ref Spec* on the *Wide Graph*, the recorded reference spectrum will then be used to flatten your overall effective passband. @@ -122,39 +124,39 @@ response* generates an undistorted audio waveform equal to the one generated by the transmitting station. Its Fourier transform is then used as a frequency-dependent phase reference to compare with the phase of the received frame's Fourier coefficients. Phase differences -between the reference spectrum and received spectrum will include +between the reference spectrum and received spectrum include contributions from the originating station's transmit filter, the propagation channel, and filters in the receiver. If the received frame originates from a station known to transmit signals having -little phase distortion (say, a station known to use a properly -adjusted software-defined-transceiver) and if the received signal is +little phase distortion (such as a station known to use a properly +adjusted software-defined transceiver), and if the received signal is relatively free from multipath distortion so that the channel phase is close to linear, the measured phase differences will be representative of the local receiver's phase response. Complete the following steps to generate a phase equalization curve: -- Record a number of wav files that contain decodable signals from -your chosen reference station. Best results will be obtained when the +- Record a number of `wav` files that contain decodable signals from +your chosen reference station. Best results are obtained when the signal-to-noise ratio of the reference signals is 10 dB or greater. - Enter the callsign of the reference station in the DX Call box. - Select *Measure phase response* from the *Tools* menu, and open each -of the wav files in turn. The mode character on decoded text lines -will change from `&` to `^` while _WSJT-X_ is measuring the phase -response, and it will change back to `&` after the measurement is +of the `wav` files in turn. The mode character on decoded text lines +changes from `&` to `^` while _WSJT-X_ is measuring the phase +response, and it changes back to `&` after the measurement is completed. The program needs to average a number of high-SNR frames to accurately estimate the phase, so it may be necessary to process -several wav files. The measurement can be aborted at any time by +several `wav` files. The measurement can be aborted at any time by selecting *Measure phase response* again to toggle the phase measurement off. + -When the measurement is complete _WSJT-X_ will save the measured +When the measurement is complete, _WSJT-X_ saves the measured phase response in the *Log directory*, in a file with suffix -".pcoeff". The filename will contain the callsign of the reference +".pcoeff". The filename contains the callsign of the reference station and a timestamp, for example `K0TPP_170923_112027.pcoeff`. - Select *Equalization tools ...* under the *Tools* menu and click the @@ -165,23 +167,23 @@ the proposed phase equalization curve. It's a good idea to repeat the phase measurement several times, using different wav files for each measurement, to ensure that your measurements are repeatable. -- Once you are satisfied with a fitted curve, push the *Apply* button -to save the proposed response. The red curve will be replaced with a +- Once you are satisfied with a fitted curve, click the *Apply* button +to save the proposed response. The red curve is replaced with a light green curve labeled "Current" to indicate that the phase equalization curve is now being applied to the received data. Another -curve labeled "Group Delay" will appear. The "Group Delay" curve shows +curve labeled "Group Delay" appears. The "Group Delay" curve shows the group delay variation across the passband, in ms. Click the *Discard Measured* button to remove the captured data from the plot, leaving only the applied phase equalization curve and corresponding group delay curve. -- To revert to no phase equalization, push the *Restore Defaults* +- To revert to no phase equalization, click the *Restore Defaults* button followed by the *Apply* button. The three numbers printed at the end of each MSK144 decode line can be used to assess the improvement provided by equalization. These numbers are: `N` = Number of frames averaged, `H` = Number of hard bit errors -corrected, `E` = Size of MSK eye diagram opening. +corrected, and `E` = Size of MSK eye diagram opening. Here is a decode of K0TPP obtained while *Measure phase response* was measuring the phase response: @@ -196,7 +198,7 @@ scale. Here's how the same decode looks after phase equalization: 103900 17 6.5 1493 & WA8CLT K0TPP +07 1 0 1.6 -In this case, equalization has increased the eye opening from 1.2 to +In this case, equalization has increased the eye-opening from 1.2 to 1.6. Larger positive eye openings are associated with reduced likelihood of bit errors and higher likelihood that a frame will be successfully decoded. In this case, the larger eye-opening tells us @@ -206,7 +208,7 @@ equalization curve is going to improve decoding of signals other than those from the reference station, K0TPP. It's a good idea to carry out before and after comparisons using a -large number of saved wav files with signals from many different +large number of saved `wav` files with signals from many different stations, to help decide whether your equalization curve improves decoding for most signals. When doing such comparisons, keep in mind that equalization may cause _WSJT-X_ to successfully decode a frame diff --git a/doc/user_guide/en/protocols.adoc b/doc/user_guide/en/protocols.adoc index d9a7d8ada..e22911266 100644 --- a/doc/user_guide/en/protocols.adoc +++ b/doc/user_guide/en/protocols.adoc @@ -1,3 +1,5 @@ +//status: edited + [[PROTOCOL_OVERVIEW]] === Overview @@ -30,17 +32,17 @@ of 4-digit Maidenhead grid locators on earth is 180×180 = 32,400, which is less than 2^15^ = 32,768; so a grid locator requires 15 bits. Some 6 million of the possible 28-bit values are not needed for -callsigns. A few of these slots have been assigned to special message +callsigns. A few of these slots are assigned to special message components such as `CQ`, `DE`, and `QRZ`. `CQ` may be followed by three digits to indicate a desired callback frequency. (If K1ABC transmits -on a standard calling frequency, say 50.280, and sends `CQ 290 K1ABC +on a standard calling frequency such as 50.280, and sends `CQ 290 K1ABC FN42`, it means that s/he will listen on 50.290 and respond there to any replies.) A numerical signal report of the form `–nn` or `R–nn` can be sent in place of a grid locator. (As originally defined, numerical signal reports `nn` were required to fall between -01 -and -30 dB. Program versions 2.3 and later accommodate reports between --50 and +50 dB.) A country prefix or portable suffix may be -attached to one of the callsigns. When this feature is used the +and -30 dB. Recent program versions 2.3 and later accommodate reports between +-50 and +49 dB.) A country prefix or portable suffix may be +attached to one of the callsigns. When this feature is used, the additional information is sent in place of the grid locator or by encoding additional information into some of the 6 million available slots mentioned above. @@ -147,7 +149,8 @@ following pseudo-random sequence: The synchronizing tone is normally sent in each interval having a "`1`" in the sequence. Modulation is 65-FSK at 11025/4096 = 2.692 baud. Frequency spacing between tones is equal to the keying rate for -JT65A, and 2 and 4 times larger for JT65B and JT65C. For EME QSOs the +JT65A, and 2 and 4 times larger for JT65B and JT65C, respectively. +For EME QSOs the signal report OOO is sometimes used instead of numerical signal reports. It is conveyed by reversing sync and data positions in the transmitted sequence. Shorthand messages for RO, RRR, and 73 dispense @@ -155,7 +158,7 @@ with the sync vector entirely and use time intervals of 16384/11025 = 1.486 s for pairs of alternating tones. The lower frequency is the same as that of the sync tone used in long messages, and the frequency separation is 110250/4096 = 26.92 Hz multiplied by n for JT65A, with n -= 2, 3, 4 used to convey the messages RO, RRR, and 73. += 2, 3, 4 used to convey the messages RO, RRR, and 73, respectively. [[QRA64_PROTOCOL]] ==== QRA64 @@ -225,7 +228,7 @@ the sync bit. [[SLOW_SUMMARY]] ==== Summary -Table 7 provides a brief summary parameters for the slow modes in +Table 7 provides a brief summary of parameters for the slow modes in _WSJT-X_. Parameters K and r specify the constraint length and rate of the convolutional codes; n and k specify the sizes of the (equivalent) block codes; Q is the alphabet size for the @@ -305,7 +308,7 @@ available character set is: Transmissions consist of sequences of 24 symbols: a synchronizing pattern of four symbols at tone numbers 0, 1, 3, and 2, followed by two symbols with tone number corresponding to (message length) and -(message length + 5), and finally 18 symbols conveying the user's +(message length + 5), and, finally, 18 symbols conveying the user's message, sent repeatedly character by character. The message always starts with `@`, the beginning-of-message symbol, which is not displayed to the user. The sync pattern and message-length indicator From 683cd081032b2a5dd3b0f9e8495df538b971b464 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Mon, 17 Aug 2020 14:12:08 -0500 Subject: [PATCH 044/206] Add timer call for bit metric calculation. Improve some comments. Make fort.21 ntype parameter more informative. --- lib/fst4/decode240_101.f90 | 2 +- lib/fst4/decode240_74.f90 | 2 +- lib/fst4/get_fst4_bitmetrics.f90 | 2 +- lib/fst4_decode.f90 | 8 +++++--- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/fst4/decode240_101.f90 b/lib/fst4/decode240_101.f90 index 80e42eeb0..e924f00ec 100644 --- a/lib/fst4/decode240_101.f90 +++ b/lib/fst4/decode240_101.f90 @@ -141,7 +141,7 @@ subroutine decode240_101(llr,Keff,maxosd,norder,apmask,message101,cw,ntype,nhard where(llr .ge. 0) hdec=1 nxor=ieor(hdec,cw) dmin=sum(nxor*abs(llr)) - ntype=2 + ntype=1+nosd return endif enddo diff --git a/lib/fst4/decode240_74.f90 b/lib/fst4/decode240_74.f90 index 3f8a6a952..224a2860d 100644 --- a/lib/fst4/decode240_74.f90 +++ b/lib/fst4/decode240_74.f90 @@ -141,7 +141,7 @@ subroutine decode240_74(llr,Keff,maxosd,norder,apmask,message74,cw,ntype,nharder where(llr .ge. 0) hdec=1 nxor=ieor(hdec,cw) dmin=sum(nxor*abs(llr)) - ntype=2 + ntype=1+nosd return endif enddo diff --git a/lib/fst4/get_fst4_bitmetrics.f90 b/lib/fst4/get_fst4_bitmetrics.f90 index 9cf1e2470..f248171f0 100644 --- a/lib/fst4/get_fst4_bitmetrics.f90 +++ b/lib/fst4/get_fst4_bitmetrics.f90 @@ -84,7 +84,7 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,badsync) endif bitmetrics=0.0 - do nseq=1,nmax !Try coherent sequences of 1, 2, and 4 symbols + do nseq=1,nmax !Try coherent sequences of 1,2,3,4 or 1,2,4,8 symbols if(nseq.eq.1) nsym=1 if(nseq.eq.2) nsym=2 if(nhicoh.eq.0) then diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index e56fa27a8..9a6683fe4 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -395,11 +395,13 @@ contains if(is0.lt.0) cycle cframe=c2(is0:is0+160*nss-1) bitmetrics=0 + call timer('bitmetrc',0) if(hmod.eq.1) then call get_fst4_bitmetrics(cframe,nss,hmod,nblock,nhicoh,bitmetrics,s4,badsync) else call get_fst4_bitmetrics2(cframe,nss,hmod,nblock,bitmetrics,s4,badsync) endif + call timer('bitmetrc',1) if(badsync) cycle hbits=0 @@ -410,7 +412,8 @@ contains ns4=count(hbits(229:244).eq.(/1,1,1,0,0,1,0,0,1,0,1,1,0,0,0,1/)) ns5=count(hbits(305:320).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/)) nsync_qual=ns1+ns2+ns3+ns4+ns5 - if(nsync_qual.lt. 46) cycle !### Value ?? ### + + if(nsync_qual.lt. 46) cycle !### Value ?? ### scalefac=2.83 llra( 1: 60)=bitmetrics( 17: 76, 1) llra( 61:120)=bitmetrics( 93:152, 1) @@ -768,7 +771,7 @@ contains nnw=nint(48000.*nsps*2./fs) allocate (s(nnw)) - s=0. !Compute low-resloution power spectrum + s=0. !Compute low-resolution power spectrum do i=ina,inb ! noise analysis window includes signal analysis window j0=nint(i*df2/df1) do j=j0-ndh,j0+ndh @@ -785,7 +788,6 @@ contains enddo call pctile(s2(ina+hmod*3:inb-hmod*3),inb-ina+1-hmod*6,30,base) s2=s2/base !Normalize wrt noise level - ncand=0 candidates=0 if(ia.lt.3) ia=3 From 07486ee0c7864b485539aee94d495e9f75244ebf Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Wed, 19 Aug 2020 09:20:48 -0500 Subject: [PATCH 045/206] Simplify some code in fst4_decode.f90 - no functional change. --- lib/fst4_decode.f90 | 49 +++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 9a6683fe4..6f3e36105 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -48,7 +48,7 @@ contains complex, allocatable :: c2(:) complex, allocatable :: cframe(:) complex, allocatable :: c_bigfft(:) !Complex waveform - real llr(240),llra(240),llrb(240),llrc(240),llrd(240) + real llr(240),llrs(240,4) real candidates(200,4) real bitmetrics(320,4) real s4(0:3,NN) @@ -415,28 +415,15 @@ contains if(nsync_qual.lt. 46) cycle !### Value ?? ### scalefac=2.83 - llra( 1: 60)=bitmetrics( 17: 76, 1) - llra( 61:120)=bitmetrics( 93:152, 1) - llra(121:180)=bitmetrics(169:228, 1) - llra(181:240)=bitmetrics(245:304, 1) - llra=scalefac*llra - llrb( 1: 60)=bitmetrics( 17: 76, 2) - llrb( 61:120)=bitmetrics( 93:152, 2) - llrb(121:180)=bitmetrics(169:228, 2) - llrb(181:240)=bitmetrics(245:304, 2) - llrb=scalefac*llrb - llrc( 1: 60)=bitmetrics( 17: 76, 3) - llrc( 61:120)=bitmetrics( 93:152, 3) - llrc(121:180)=bitmetrics(169:228, 3) - llrc(181:240)=bitmetrics(245:304, 3) - llrc=scalefac*llrc - llrd( 1: 60)=bitmetrics( 17: 76, 4) - llrd( 61:120)=bitmetrics( 93:152, 4) - llrd(121:180)=bitmetrics(169:228, 4) - llrd(181:240)=bitmetrics(245:304, 4) - llrd=scalefac*llrd + do il=1,4 + llrs( 1: 60,il)=bitmetrics( 17: 76, il) + llrs( 61:120,il)=bitmetrics( 93:152, il) + llrs(121:180,il)=bitmetrics(169:228, il) + llrs(181:240,il)=bitmetrics(245:304, il) + enddo + llrs=scalefac*llrs - apmag=maxval(abs(llra))*1.1 + apmag=maxval(abs(llrs(:,1)))*1.1 ntmax=nblock+nappasses(nQSOProgress) if(lapcqonly) ntmax=nblock+1 if(ndepth.eq.1) ntmax=nblock @@ -448,22 +435,22 @@ contains endif do itry=1,ntmax - if(itry.eq.1) llr=llra - if(itry.eq.2.and.itry.le.nblock) llr=llrb - if(itry.eq.3.and.itry.le.nblock) llr=llrc - if(itry.eq.4.and.itry.le.nblock) llr=llrd + if(itry.eq.1) llr=llrs(:,1) + if(itry.eq.2.and.itry.le.nblock) llr=llrs(:,2) + if(itry.eq.3.and.itry.le.nblock) llr=llrs(:,3) + if(itry.eq.4.and.itry.le.nblock) llr=llrs(:,4) if(itry.le.nblock) then apmask=0 iaptype=0 endif if(itry.gt.nblock) then - llr=llra + llr=llrs(:,1) if(nblock.gt.1) then - if(hmod.eq.1) llr=llrc - if(hmod.eq.2) llr=llra - if(hmod.eq.4) llr=llrb - if(hmod.eq.8) llr=llrc + if(hmod.eq.1) llr=llrs(:,3) + if(hmod.eq.2) llr=llrs(:,1) + if(hmod.eq.4) llr=llrs(:,2) + if(hmod.eq.8) llr=llrs(:,4) endif iaptype=naptypes(nQSOProgress,itry-nblock) if(lapcqonly) iaptype=1 From e28215fce54c7ff50976b40c44109a707fcb8bc1 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Wed, 19 Aug 2020 14:10:28 -0500 Subject: [PATCH 046/206] Reconfigure to optimize decoder for MF/LF (high coherence) channels. --- lib/fst4/get_fst4_bitmetrics.f90 | 2 +- lib/fst4_decode.f90 | 22 +++++++++------------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/fst4/get_fst4_bitmetrics.f90 b/lib/fst4/get_fst4_bitmetrics.f90 index f248171f0..f224854e2 100644 --- a/lib/fst4/get_fst4_bitmetrics.f90 +++ b/lib/fst4/get_fst4_bitmetrics.f90 @@ -105,7 +105,7 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,badsync) csum=csum+cs(graymap(ntone),ks+j)*cterm cterm=cterm*conjg(cp(graymap(ntone))) enddo - s2(i)=abs(csum)**2 + s2(i)=abs(csum) enddo ipt=1+(ks-1)*2 if(nsym.eq.1) ibmax=1 diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 6f3e36105..448e699c3 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -275,12 +275,8 @@ contains fb=min(4800,nfb) endif - if(hmod.eq.1) then - if(ntrperiod.eq.15) minsync=1.15 - if(ntrperiod.gt.15) minsync=1.25 - elseif(hmod.gt.1) then - minsync=1.2 - endif + minsync=1.2 + if(ntrperiod.eq.15) minsync=1.15 ! Get first approximation of candidate frequencies call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb, & @@ -788,13 +784,13 @@ contains iploc=ia+im(1)-1 !Index of CCF peak pval=s2(iploc) !Peak value if(pval.lt.minsync) exit -! do i=-3,+3 !Remove 0.9 of a model CCF at -! k=iploc+2*hmod*i !this frequency from s2() -! if(k.ge.ia .and. k.le.ib) then -! s2(k)=max(0.,s2(k)-0.9*pval*xdb(i)) -! endif -! enddo - s2(max(1,iploc-2*hmod*3):min(nnw,iploc+2*hmod*3))=0.0 + do i=-3,+3 !Remove 0.9 of a model CCF at + k=iploc+2*hmod*i !this frequency from s2() + if(k.ge.ia .and. k.le.ib) then + s2(k)=max(0.,s2(k)-0.9*pval*xdb(i)) + endif + enddo +! s2(max(1,iploc-2*hmod*3):min(nnw,iploc+2*hmod*3))=0.0 ncand=ncand+1 candidates(ncand,1)=df2*iploc !Candidate frequency candidates(ncand,2)=pval !Rough estimate of SNR From 0e0349e87aec6a4e34455456381264bbe53f034a Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Thu, 20 Aug 2020 09:48:32 -0500 Subject: [PATCH 047/206] Streamline fst4_decode. Add timer for downsampling. --- lib/decoder.f90 | 4 +- lib/fst4/get_fst4_bitmetrics.f90 | 19 ++++ lib/fst4_decode.f90 | 162 +++++++++++++------------------ 3 files changed, 88 insertions(+), 97 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 925dc0d43..c339ab523 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -213,7 +213,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) params%nQSOProgress,params%nfqso,params%nfa,params%nfb, & params%nsubmode,ndepth,params%ntr,params%nexp_decode, & params%ntol,params%emedelay, & - logical(params%lapcqonly),mycall,hiscall,params%nfsplit,iwspr) + logical(params%lapcqonly),mycall,hiscall,iwspr) call timer('dec240 ',1) go to 800 endif @@ -227,7 +227,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) params%nQSOProgress,params%nfqso,params%nfa,params%nfb, & params%nsubmode,ndepth,params%ntr,params%nexp_decode, & params%ntol,params%emedelay, & - logical(params%lapcqonly),mycall,hiscall,params%nfsplit,iwspr) + logical(params%lapcqonly),mycall,hiscall,iwspr) call timer('dec240 ',1) go to 800 endif diff --git a/lib/fst4/get_fst4_bitmetrics.f90 b/lib/fst4/get_fst4_bitmetrics.f90 index f224854e2..f34cb9322 100644 --- a/lib/fst4/get_fst4_bitmetrics.f90 +++ b/lib/fst4/get_fst4_bitmetrics.f90 @@ -11,6 +11,7 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,badsync) integer graymap(0:3) integer ip(1) integer hmod + integer hbits(2*NN) logical one(0:65535,0:15) ! 65536 8-symbol sequences, 16 bits logical first logical badsync @@ -122,10 +123,28 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,badsync) enddo enddo + hbits=0 + where(bitmetrics(:,1).ge.0) hbits=1 + ns1=count(hbits( 1: 16).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/)) + ns2=count(hbits( 77: 92).eq.(/1,1,1,0,0,1,0,0,1,0,1,1,0,0,0,1/)) + ns3=count(hbits(153:168).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/)) + ns4=count(hbits(229:244).eq.(/1,1,1,0,0,1,0,0,1,0,1,1,0,0,0,1/)) + ns5=count(hbits(305:320).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/)) + nsync_qual=ns1+ns2+ns3+ns4+ns5 + + if(nsync_qual.lt. 46) then + badsync=.true. + return + endif + call normalizebmet(bitmetrics(:,1),2*NN) call normalizebmet(bitmetrics(:,2),2*NN) call normalizebmet(bitmetrics(:,3),2*NN) call normalizebmet(bitmetrics(:,4),2*NN) + + scalefac=2.83 + bitmetrics=scalefac*bitmetrics + return end subroutine get_fst4_bitmetrics diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 448e699c3..8a116bbbf 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -31,7 +31,7 @@ contains subroutine decode(this,callback,iwave,nutc,nQSOProgress,nfqso, & nfa,nfb,nsubmode,ndepth,ntrperiod,nexp_decode,ntol, & - emedelay,lapcqonly,mycall,hiscall,nfsplit,iwspr) + emedelay,lapcqonly,mycall,hiscall,iwspr) use timer_module, only: timer use packjt77 @@ -252,29 +252,10 @@ contains call four2a(c_bigfft,nfft1,1,-1,0) !r2c ! call blank2(nfa,nfb,nfft1,c_bigfft,iwave) - nhicoh=0 - if(hmod.eq.1) then - if(fMHz.lt.2.0) then - nsyncoh=8 ! Use N=8 for sync - nhicoh=1 ! Use N=1,2,4,8 for symbol estimation - else - nsyncoh=4 ! Use N=4 for sync - nhicoh=0 ! Use N=1,2,3,4 for symbol estimation - endif - else - if(hmod.eq.2) nsyncoh=1 - if(hmod.eq.4) nsyncoh=-2 - if(hmod.eq.8) nsyncoh=-4 - endif - - if( single_decode ) then - fa=max(100,nint(nfqso+1.5*hmod*baud-ntol)) - fb=min(4800,nint(nfqso+1.5*hmod*baud+ntol)) - else - fa=max(100,nfa) - fb=min(4800,nfb) - endif - + nhicoh=1 + nsyncoh=8 + fa=max(100,nint(nfqso+1.5*hmod*baud-ntol)) + fb=min(4800,nint(nfqso+1.5*hmod*baud+ntol)) minsync=1.2 if(ntrperiod.eq.15) minsync=1.15 @@ -296,54 +277,15 @@ contains ! Output array c2 is complex baseband sampled at 12000/ndown Sa/sec. ! The size of the downsampled c2 array is nfft2=nfft1/ndown + call timer('dwnsmpl ',0) call fst4_downsample(c_bigfft,nfft1,ndown,fc0,sigbw,c2) + call timer('dwnsmpl ',1) call timer('sync240 ',0) - fc1=0.0 - if(emedelay.lt.0.1) then ! search offsets from 0 s to 2 s - is0=1.5*nspsec - ishw=1.5*nspsec - else ! search plus or minus 1.5 s centered on emedelay - is0=nint((emedelay+1.0)*nspsec) - ishw=1.5*nspsec - endif - - smax=-1.e30 - do if=-12,12 - fc=fc1 + 0.1*baud*if - do istart=max(1,is0-ishw),is0+ishw,4*hmod - call sync_fst4(c2,istart,fc,hmod,nsyncoh,nfft2,nss, & - ntrperiod,fs2,sync) - if(sync.gt.smax) then - fc2=fc - isbest=istart - smax=sync - endif - enddo - enddo - - fc1=fc2 - is0=isbest - ishw=4*hmod - isst=1*hmod - - smax=0.0 - do if=-7,7 - fc=fc1 + 0.02*baud*if - do istart=max(1,is0-ishw),is0+ishw,isst - call sync_fst4(c2,istart,fc,hmod,nsyncoh,nfft2,nss, & - ntrperiod,fs2,sync) - if(sync.gt.smax) then - fc2=fc - isbest=istart - smax=sync - endif - enddo - enddo - + call fst4_sync_search(c2,nfft2,hmod,fs2,nss,ntrperiod,nsyncoh,emedelay,sbest,fcbest,isbest) call timer('sync240 ',1) - fc_synced = fc0 + fc2 + fc_synced = fc0 + fcbest dt_synced = (isbest-fs2)*dt2 !nominal dt is 1 second so frame starts at sample fs2 candidates(icand,3)=fc_synced candidates(icand,4)=isbest @@ -382,7 +324,11 @@ contains isbest=nint(candidates(icand,4)) xdt=(isbest-nspsec)/fs2 if(ntrperiod.eq.15) xdt=(isbest-real(nspsec)/2.0)/fs2 + + call timer('dwnsmpl ',0) call fst4_downsample(c_bigfft,nfft1,ndown,fc_synced,sigbw,c2) + call timer('dwnsmpl ',1) + do ijitter=0,jittermax if(ijitter.eq.0) ioffset=0 if(ijitter.eq.1) ioffset=1 @@ -392,32 +338,16 @@ contains cframe=c2(is0:is0+160*nss-1) bitmetrics=0 call timer('bitmetrc',0) - if(hmod.eq.1) then - call get_fst4_bitmetrics(cframe,nss,hmod,nblock,nhicoh,bitmetrics,s4,badsync) - else - call get_fst4_bitmetrics2(cframe,nss,hmod,nblock,bitmetrics,s4,badsync) - endif + call get_fst4_bitmetrics(cframe,nss,hmod,nblock,nhicoh,bitmetrics,s4,badsync) call timer('bitmetrc',1) if(badsync) cycle - hbits=0 - where(bitmetrics(:,1).ge.0) hbits=1 - ns1=count(hbits( 1: 16).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/)) - ns2=count(hbits( 77: 92).eq.(/1,1,1,0,0,1,0,0,1,0,1,1,0,0,0,1/)) - ns3=count(hbits(153:168).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/)) - ns4=count(hbits(229:244).eq.(/1,1,1,0,0,1,0,0,1,0,1,1,0,0,0,1/)) - ns5=count(hbits(305:320).eq.(/0,0,0,1,1,0,1,1,0,1,0,0,1,1,1,0/)) - nsync_qual=ns1+ns2+ns3+ns4+ns5 - - if(nsync_qual.lt. 46) cycle !### Value ?? ### - scalefac=2.83 do il=1,4 llrs( 1: 60,il)=bitmetrics( 17: 76, il) llrs( 61:120,il)=bitmetrics( 93:152, il) llrs(121:180,il)=bitmetrics(169:228, il) llrs(181:240,il)=bitmetrics(245:304, il) enddo - llrs=scalefac*llrs apmag=maxval(abs(llrs(:,1)))*1.1 ntmax=nblock+nappasses(nQSOProgress) @@ -440,14 +370,8 @@ contains iaptype=0 endif - if(itry.gt.nblock) then - llr=llrs(:,1) - if(nblock.gt.1) then - if(hmod.eq.1) llr=llrs(:,3) - if(hmod.eq.2) llr=llrs(:,1) - if(hmod.eq.4) llr=llrs(:,2) - if(hmod.eq.8) llr=llrs(:,4) - endif + if(itry.gt.nblock) then ! do ap passes + llr=llrs(:,nblock) ! Use largest blocksize as the basis for AP passes iaptype=naptypes(nQSOProgress,itry-nblock) if(lapcqonly) iaptype=1 if(iaptype.ge.2 .and. apbits(1).gt.1) cycle ! No, or nonstandard, mycall @@ -486,7 +410,7 @@ contains if(iwspr.eq.0) then maxosd=2 Keff=91 - norder=3 + norder=4 call timer('d240_101',0) call decode240_101(llr,Keff,maxosd,norder,apmask,message101, & cw,ntype,nharderrors,dmin) @@ -556,8 +480,8 @@ contains fsig=fc_synced - 1.5*hmod*baud if(ex) then write(21,3021) nutc,icand,itry,nsyncoh,iaptype, & - ijitter,ntype,nsync_qual,nharderrors,dmin, & - sync,xsnr,xdt,fsig,w50,trim(msg) + ijitter,ntype,nsync_qual,nharderrors,dmin, & + sync,xsnr,xdt,fsig,w50,trim(msg) 3021 format(i6.6,6i3,2i4,f6.1,f7.2,f6.1,f6.2,f7.1,f7.3,1x,a) flush(21) endif @@ -799,6 +723,54 @@ contains return end subroutine get_candidates_fst4 + subroutine fst4_sync_search(c2,nfft2,hmod,fs2,nss,ntrperiod,nsyncoh,emedelay,sbest,fcbest,isbest) + complex c2(0:nfft2-1) + integer hmod + nspsec=int(fs2) + baud=fs2/real(nss) + fc1=0.0 + if(emedelay.lt.0.1) then ! search offsets from 0 s to 2 s + is0=1.5*nspsec + ishw=1.5*nspsec + else ! search plus or minus 1.5 s centered on emedelay + is0=nint((emedelay+1.0)*nspsec) + ishw=1.5*nspsec + endif + + sbest=-1.e30 + do if=-12,12 + fc=fc1 + 0.1*baud*if + do istart=max(1,is0-ishw),is0+ishw,4*hmod + call sync_fst4(c2,istart,fc,hmod,nsyncoh,nfft2,nss, & + ntrperiod,fs2,sync) + if(sync.gt.sbest) then + fcbest=fc + isbest=istart + sbest=sync + endif + enddo + enddo + + fc1=fcbest + is0=isbest + ishw=4*hmod + isst=1*hmod + + sbest=0.0 + do if=-7,7 + fc=fc1 + 0.02*baud*if + do istart=max(1,is0-ishw),is0+ishw,isst + call sync_fst4(c2,istart,fc,hmod,nsyncoh,nfft2,nss, & + ntrperiod,fs2,sync) + if(sync.gt.sbest) then + fcbest=fc + isbest=istart + sbest=sync + endif + enddo + enddo + end subroutine fst4_sync_search + subroutine dopspread(itone,iwave,nsps,nmax,ndown,hmod,i0,fc,fmid,w50) ! On "plotspec" special request, compute Doppler spread for a decoded signal From 091d6d0b1a3bf53394538c681d59b68b8a93c953 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Fri, 21 Aug 2020 09:18:59 -0500 Subject: [PATCH 048/206] Tweaks to update the diagnostics that are written to fort.21. --- lib/fst4/decode240_101.f90 | 3 ++- lib/fst4/decode240_74.f90 | 3 ++- lib/fst4/get_fst4_bitmetrics.f90 | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/fst4/decode240_101.f90 b/lib/fst4/decode240_101.f90 index e924f00ec..4271a464c 100644 --- a/lib/fst4/decode240_101.f90 +++ b/lib/fst4/decode240_101.f90 @@ -140,8 +140,9 @@ subroutine decode240_101(llr,Keff,maxosd,norder,apmask,message101,cw,ntype,nhard hdec=0 where(llr .ge. 0) hdec=1 nxor=ieor(hdec,cw) + nharderror=sum(nxor) ! re-calculate nharderror based on input llrs dmin=sum(nxor*abs(llr)) - ntype=1+nosd + ntype=1+i return endif enddo diff --git a/lib/fst4/decode240_74.f90 b/lib/fst4/decode240_74.f90 index 224a2860d..be18f6e09 100644 --- a/lib/fst4/decode240_74.f90 +++ b/lib/fst4/decode240_74.f90 @@ -140,8 +140,9 @@ subroutine decode240_74(llr,Keff,maxosd,norder,apmask,message74,cw,ntype,nharder hdec=0 where(llr .ge. 0) hdec=1 nxor=ieor(hdec,cw) + nharderror=sum(nxor) ! nharderror based on input llrs dmin=sum(nxor*abs(llr)) - ntype=1+nosd + ntype=1+i return endif enddo diff --git a/lib/fst4/get_fst4_bitmetrics.f90 b/lib/fst4/get_fst4_bitmetrics.f90 index f34cb9322..e245db18c 100644 --- a/lib/fst4/get_fst4_bitmetrics.f90 +++ b/lib/fst4/get_fst4_bitmetrics.f90 @@ -1,4 +1,4 @@ -subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,badsync) +subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,nsync_qual,badsync) include 'fst4_params.f90' complex cd(0:NN*nss-1) From e3171d2142740850b85dc88736ff559b0b44d7e4 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Sat, 22 Aug 2020 09:42:34 -0500 Subject: [PATCH 049/206] Fix argument list in call to fet_fst4_bitmetrics.f90 --- lib/fst4_decode.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 8a116bbbf..444553618 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -338,7 +338,8 @@ contains cframe=c2(is0:is0+160*nss-1) bitmetrics=0 call timer('bitmetrc',0) - call get_fst4_bitmetrics(cframe,nss,hmod,nblock,nhicoh,bitmetrics,s4,badsync) + call get_fst4_bitmetrics(cframe,nss,hmod,nblock,nhicoh,bitmetrics, & + s4,nsync_qual,badsync) call timer('bitmetrc',1) if(badsync) cycle From ad0540a02785c8dfe223a7d299e5b400a36ae785 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Mon, 24 Aug 2020 10:17:45 -0500 Subject: [PATCH 050/206] Speed up decoder by eliminating some complex multiples in sequence detection loop. Add timer calls for doppler spread calculation and sequence detection loop. --- lib/fst4/get_fst4_bitmetrics.f90 | 13 ++++++++++--- lib/fst4_decode.f90 | 2 ++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/lib/fst4/get_fst4_bitmetrics.f90 b/lib/fst4/get_fst4_bitmetrics.f90 index e245db18c..69a649a04 100644 --- a/lib/fst4/get_fst4_bitmetrics.f90 +++ b/lib/fst4/get_fst4_bitmetrics.f90 @@ -1,5 +1,6 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,nsync_qual,badsync) + use timer_module, only: timer include 'fst4_params.f90' complex cd(0:NN*nss-1) complex cs(0:3,NN) @@ -84,6 +85,8 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,nsync_qual, return endif + + call timer('seqcorrs',0) bitmetrics=0.0 do nseq=1,nmax !Try coherent sequences of 1,2,3,4 or 1,2,4,8 symbols if(nseq.eq.1) nsym=1 @@ -100,11 +103,14 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,nsync_qual, s2=0 do i=0,nt-1 csum=0 - cterm=1 +! cterm=1 ! hmod.ne.1 + term=1 do j=0,nsym-1 ntone=mod(i/4**(nsym-1-j),4) - csum=csum+cs(graymap(ntone),ks+j)*cterm - cterm=cterm*conjg(cp(graymap(ntone))) + csum=csum+cs(graymap(ntone),ks+j)*term + term=-term +! csum=csum+cs(graymap(ntone),ks+j)*cterm ! hmod.ne.1 +! cterm=cterm*conjg(cp(graymap(ntone))) ! hmod.ne.1 enddo s2(i)=abs(csum) enddo @@ -122,6 +128,7 @@ subroutine get_fst4_bitmetrics(cd,nss,hmod,nmax,nhicoh,bitmetrics,s4,nsync_qual, enddo enddo enddo + call timer('seqcorrs',1) hbits=0 where(bitmetrics(:,1).ge.0) hbits=1 diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index 444553618..efe6a3798 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -455,10 +455,12 @@ contains endif inquire(file='plotspec',exist=ex) fmid=-999.0 + call timer('dopsprd ',0) if(ex) then call dopspread(itone,iwave,nsps,nmax,ndown,hmod, & isbest,fc_synced,fmid,w50) endif + call timer('dopsprd ',1) xsig=0 do i=1,NN xsig=xsig+s4(itone(i),i) From e232c32178e8310e4ed10d6d5c144d1069ba4e85 Mon Sep 17 00:00:00 2001 From: Steven Franke Date: Fri, 28 Aug 2020 09:22:22 -0500 Subject: [PATCH 051/206] Use 3rd order polynomial fit to estimate the noise baseline. The polynomial fit is done over 400 Hz bandwidth for T/R periods longer than 15s, and over approx. 600 Hz (10 times the signal bandwidth) for T/R period of 15s. --- CMakeLists.txt | 1 + lib/fst4/fst4_baseline.f90 | 48 ++++++++++++++++++++++++++++++++++++++ lib/fst4_decode.f90 | 48 +++++++++++++++++++++++--------------- 3 files changed, 78 insertions(+), 19 deletions(-) create mode 100644 lib/fst4/fst4_baseline.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 403774100..8080d98b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -621,6 +621,7 @@ set (wsjt_FSRCS lib/fst4/osd240_101.f90 lib/fst4/osd240_74.f90 lib/fst4/get_crc24.f90 + lib/fst4/fst4_baseline.f90 ) # temporary workaround for a gfortran v7.3 ICE on Fedora 27 64-bit diff --git a/lib/fst4/fst4_baseline.f90 b/lib/fst4/fst4_baseline.f90 new file mode 100644 index 000000000..32776651a --- /dev/null +++ b/lib/fst4/fst4_baseline.f90 @@ -0,0 +1,48 @@ +subroutine fst4_baseline(s,np,ia,ib,npct,sbase) + +! Fit baseline to spectrum (for FST4) +! Input: s(npts) Linear scale in power +! Output: sbase(npts) Baseline + + implicit real*8 (a-h,o-z) + real*4 s(np),sw(np) + real*4 sbase(np) + real*4 base + real*8 x(1000),y(1000),a(5) + data nseg/8/ + + do i=ia,ib + sw(i)=10.0*log10(s(i)) !Convert to dB scale + enddo + + nterms=3 + nlen=(ib-ia+1)/nseg !Length of test segment + i0=(ib-ia+1)/2 !Midpoint + k=0 + do n=1,nseg !Loop over all segments + ja=ia + (n-1)*nlen + jb=ja+nlen-1 + call pctile(sw(ja),nlen,npct,base) !Find lowest npct of points + do i=ja,jb + if(sw(i).le.base) then + if (k.lt.1000) k=k+1 !Save all "lower envelope" points + x(k)=i-i0 + y(k)=sw(i) + endif + enddo + enddo + kz=k + a=0. + call polyfit(x,y,y,kz,nterms,0,a,chisqr) !Fit a low-order polynomial + sbase=0.0 + do i=ia,ib + t=i-i0 + sbase(i)=a(1)+t*(a(2)+t*(a(3))) + 0.2 +! write(51,3051) i,sw(i),sbase(i) +!3051 format(i8,2f12.3) + enddo + + sbase=10**(sbase/10.0) + + return +end subroutine fst4_baseline diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index efe6a3798..d609df115 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -49,7 +49,7 @@ contains complex, allocatable :: cframe(:) complex, allocatable :: c_bigfft(:) !Complex waveform real llr(240),llrs(240,4) - real candidates(200,4) + real candidates(200,5) real bitmetrics(320,4) real s4(0:3,NN) real minsync @@ -254,14 +254,19 @@ contains nhicoh=1 nsyncoh=8 - fa=max(100,nint(nfqso+1.5*hmod*baud-ntol)) - fb=min(4800,nint(nfqso+1.5*hmod*baud+ntol)) - minsync=1.2 + if(iwspr.eq.1) then + fa=1400.0 + fb=1600.0 + else + fa=max(100,nint(nfqso+1.5*hmod*baud-ntol)) + fb=min(4800,nint(nfqso+1.5*hmod*baud+ntol)) + endif + minsync=1.20 if(ntrperiod.eq.15) minsync=1.15 ! Get first approximation of candidate frequencies call get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb, & - minsync,ncand,candidates,base) + minsync,ncand,candidates) ndecodes=0 decodes=' ' @@ -317,7 +322,7 @@ contains enddo ncand=ic xsnr=0. - +!write(*,*) 'ncand ',ncand do icand=1,ncand sync=candidates(icand,2) fc_synced=candidates(icand,3) @@ -465,6 +470,7 @@ contains do i=1,NN xsig=xsig+s4(itone(i),i) enddo + base=candidates(icand,5) arg=600.0*(xsig/base)-1.0 if(arg.gt.0.0) then xsnr=10*log10(arg)-35.5-12.5*log10(nsps/8200.0) @@ -645,14 +651,15 @@ contains end subroutine fst4_downsample subroutine get_candidates_fst4(c_bigfft,nfft1,nsps,hmod,fs,fa,fb, & - minsync,ncand,candidates,base) + minsync,ncand,candidates) complex c_bigfft(0:nfft1/2) !Full length FFT of raw data integer hmod !Modulation index (submode) integer im(1) !For maxloc - real candidates(200,4) !Candidate list + real candidates(200,5) !Candidate list real, allocatable :: s(:) !Low resolution power spectrum real, allocatable :: s2(:) !CCF of s() with 4 tones + real, allocatable :: sbase(:) !noise baseline estimate real xdb(-3:3) !Model 4-tone CCF peaks real minsync data xdb/0.25,0.50,0.75,1.0,0.75,0.50,0.25/ @@ -668,17 +675,17 @@ contains signal_bw=4*(12000.0/nsps)*hmod analysis_bw=min(4800.0,fb)-max(100.0,fa) xnoise_bw=10.0*signal_bw !Is this a good compromise? - if(analysis_bw.gt.xnoise_bw) then - ina=ia - inb=ib - else - fcenter=(fa+fb)/2.0 !If noise_bw > analysis_bw, - fl = max(100.0,fcenter-xnoise_bw/2.)/df2 !we'll search over noise_bw + if(xnoise_bw .lt. 400.0) xnoise_bw=400.0 + if(analysis_bw.gt.xnoise_bw) then !Estimate noise baseline over analysis bw + ina=0.9*ia + inb=min(int(1.1*ib),nfft1/2) + else !Estimate noise baseline over noise bw + fcenter=(fa+fb)/2.0 + fl = max(100.0,fcenter-xnoise_bw/2.)/df2 fh = min(4800.0,fcenter+xnoise_bw/2.)/df2 ina=nint(fl) inb=nint(fh) endif - nnw=nint(48000.*nsps*2./fs) allocate (s(nnw)) s=0. !Compute low-resolution power spectrum @@ -692,12 +699,16 @@ contains ina=max(ina,1+3*hmod) !Don't run off the ends inb=min(inb,nnw-3*hmod) allocate (s2(nnw)) + allocate (sbase(nnw)) s2=0. do i=ina,inb !Compute CCF of s() and 4 tones s2(i)=s(i-hmod*3) + s(i-hmod) +s(i+hmod) +s(i+hmod*3) enddo - call pctile(s2(ina+hmod*3:inb-hmod*3),inb-ina+1-hmod*6,30,base) - s2=s2/base !Normalize wrt noise level + npct=30 + call fst4_baseline(s2,nnw,ina+hmod*3,inb-hmod*3,npct,sbase) + if(any(sbase(ina:inb).le.0.0)) return + s2(ina:inb)=s2(ina:inb)/sbase(ina:inb) !Normalize wrt noise level + ncand=0 candidates=0 if(ia.lt.3) ia=3 @@ -717,12 +728,11 @@ contains s2(k)=max(0.,s2(k)-0.9*pval*xdb(i)) endif enddo -! s2(max(1,iploc-2*hmod*3):min(nnw,iploc+2*hmod*3))=0.0 ncand=ncand+1 candidates(ncand,1)=df2*iploc !Candidate frequency candidates(ncand,2)=pval !Rough estimate of SNR + candidates(ncand,5)=sbase(iploc) enddo - return end subroutine get_candidates_fst4 From 8159478d51da4a7eafdb5d6f2d71536c994dbb66 Mon Sep 17 00:00:00 2001 From: K9AN Date: Fri, 28 Aug 2020 12:25:17 -0500 Subject: [PATCH 052/206] Remove an unused variable from fst4_decode --- lib/fst4_decode.f90 | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/fst4_decode.f90 b/lib/fst4_decode.f90 index d609df115..a3c2e2a98 100644 --- a/lib/fst4_decode.f90 +++ b/lib/fst4_decode.f90 @@ -57,7 +57,6 @@ contains integer itone(NN) integer hmod integer*1 apmask(240),cw(240) - integer*1 hbits(320) integer*1 message101(101),message74(74),message77(77) integer*1 rvec(77) integer apbits(240) From 6ca77f0245f21fa2d5c89812847f5a72f4b3acfa Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Fri, 11 Sep 2020 20:15:21 +0100 Subject: [PATCH 053/206] Restore deleted action --- widgets/mainwindow.ui | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 6aa94e18b..a826b2fa2 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -3293,6 +3293,14 @@ Yellow when too low FST4W + + + true + + + QRA66 + + From 8e69f84bdd3472f74ce7abece09ebe6961672055 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 11 Sep 2020 18:39:24 -0400 Subject: [PATCH 054/206] Remove some obsolete, commented-out code. No real cghanges! --- lib/sync66.f90 | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/lib/sync66.f90 b/lib/sync66.f90 index 3cd0188bb..bbb72c997 100644 --- a/lib/sync66.f90 +++ b/lib/sync66.f90 @@ -66,9 +66,6 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) sync_sig=0. ia=min(64,nint(ntol/df)) dt4=nsps/(NSTEP*12000.0) !duration of 1/4 symbol -! lag2=nint(0.5/dt4) -! if(nsps.ge.7680) lag2=nint(1.0/dt4) -! lag1=-lag2 jadd=11 if(nsps.ge.3600) jadd=7 @@ -78,7 +75,6 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) do i=-ia,ia x=s1(i0+2*mode66+i,:)-s1(i0+i,:) !Do the 2FSK demodulation -! do lag=lag1,lag2 do lag=-15,15 do k=1,22 n=4*NSTEP*(k-1) + 1 @@ -103,16 +99,6 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) xdt=jdt*tsym/4.0 snr1=maxval(sync_sig)/22.0 - -! do i=-64,64 -! write(62,3062) nfqso+i*df,sync_sig(i,jj) -!3062 format(2f12.3) -! enddo - -! do j=-15,15 -! write(63,3063) j,j*dt4,sync_sig(ii,j) -!3063 format(i5,2f12.3) -! enddo return end subroutine sync66 From 2057600f43c7fc5e05e51d646af2c6b4ad7045ae Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 25 Sep 2020 10:55:21 -0400 Subject: [PATCH 055/206] First functioning QRA65 encode and decode. --- lib/genqra64.f90 | 21 +++++---- lib/qra/qra66/qra66sim.f90 | 2 +- lib/qra66_decode.f90 | 11 ++--- lib/spec66.f90 | 15 +++++-- lib/sync66.f90 | 90 ++++++++++++++++++++------------------ 5 files changed, 75 insertions(+), 64 deletions(-) diff --git a/lib/genqra64.f90 b/lib/genqra64.f90 index babe7d692..fb0c19438 100644 --- a/lib/genqra64.f90 +++ b/lib/genqra64.f90 @@ -1,6 +1,6 @@ subroutine genqra64(msg0,ichk,msgsent,itone,itype) -! Encodes a QRA64 message to yield itone(1:84) +! Encodes a QRA64 message to yield itone(1:84) or a QRA65 msg, itone(1:85) use packjt character*22 msg0 @@ -8,15 +8,15 @@ subroutine genqra64(msg0,ichk,msgsent,itone,itype) character*22 msgsent !Message as it will be received integer itone(85) !QRA64 uses only 84 character*3 cok !' ' or 'OOO' - logical old_qra_sync integer dgen(13) integer sent(63) - integer b11(11) !Barker 11 code + integer isync(22) integer icos7(0:6) data icos7/2,5,6,0,4,1,3/ !Defines a 7x7 Costas array - data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 definition + data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ save + print*,'ichk:',ichk if(msg0(1:1).eq.'@') then read(msg0(2:5),*,end=1,err=1) nfreq go to 2 @@ -44,18 +44,17 @@ subroutine genqra64(msg0,ichk,msgsent,itone,itype) if(ichk.eq.1) go to 999 !Return if checking only call qra64_enc(dgen,sent) !Encode using QRA64 - if(ichk.eq.66) then -! Experimental QRA66 (FST66?) mode - j=0 + if(ichk.eq.65) then +! Experimental QRA65 mode + j=1 k=0 do i=1,85 - if(mod(i,4).eq.1) then + if(i.eq.isync(j)) then j=j+1 !Index for next sync symbol - if(j.eq.12) j=1 - itone(i)=b11(j) !Insert a sync symbol + itone(i)=0 !Insert a sync symbol else k=k+1 - itone(i)=sent(k) + 2 + itone(i)=sent(k) + 1 endif enddo else diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra66/qra66sim.f90 index 1171542ad..335a37252 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra66/qra66sim.f90 @@ -65,7 +65,7 @@ program qra66sim mode66=2**(ichar(csubmode) - ichar('A')) print*,csubmode,mode66 - ichk=66 !Flag sent to genqra64 + ichk=65 !Flag sent to genqra64 call genqra64(msg,ichk,msgsent,itone,itype) write(*,1001) itone 1001 format('Channel symbols:'/(20i3)) diff --git a/lib/qra66_decode.f90 b/lib/qra66_decode.f90 index f175fb0ba..f0db7378e 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra66_decode.f90 @@ -115,6 +115,10 @@ contains endif naptype=maxaptype + call timer('sync66 ',0) + call sync66(iwave,ntrperiod*12000,mode66,nsps,nfqso,ntol,xdt,f0,snr1) + call timer('sync66 ',1) + ! Downsample to give complex data at 6000 S/s fac=2.0/nfft1 c0=fac*iwave(1:nfft1) @@ -122,21 +126,18 @@ contains c0(nfft2/2+1:nfft2)=0. !Zero the top half c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT - call timer('sync66 ',0) - call sync66(iwave,ntrperiod*12000,mode66,nsps,nfqso,ntol,xdt,f0,snr1) - call timer('sync66 ',1) jpk=(xdt+0.5)*6000 - 384 !### Empirical ### if(ntrperiod.ge.60) jpk=(xdt+1.0)*6000 - 384 !### TBD ### if(jpk.lt.0) jpk=0 a=0. - a(1)=-(f0 + 2.0*mode66*baud) !Data tones start 2*mode66 bins higher + a(1)=-(f0 + mode66*baud) !Data tones start mode66 bins higher call twkfreq(c0,c0,ntrperiod*6000,6000.0,a) xdt=jpk/6000.0 - 0.5 LL=64*(mode66+2) NN=63 - call spec66(c0(jpk:),nsps/2,s3,LL,NN) !Compute the synchronized symbol spectra + call spec66(c0(jpk:),nsps/2,s3,LL,NN) !Compute synchronized symbol spectra do j=1,63 !Normalize to symbol baseline call pctile(s3(:,j),LL,40,base) diff --git a/lib/spec66.f90 b/lib/spec66.f90 index 0d049fddb..454f1c18d 100644 --- a/lib/spec66.f90 +++ b/lib/spec66.f90 @@ -6,12 +6,19 @@ subroutine spec66(c0,nsps,s3,LL,NN) complex cs(0:nsps-1) !Complex symbol spectrum real s3(LL,NN) !Synchronized symbol spectra real xbase0(LL),xbase(LL) !Work arrays + integer isync(22) !Indices of sync symbols + data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ fac=1.0/nsps - ja=-nsps - do j=1,NN - ja=ja+nsps - if(mod(ja/nsps,4).eq.0) ja=ja+nsps + 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 jb=ja+nsps-1 cs=fac*c0(ja:jb) call four2a(cs,nsps,1,-1,1) !c2c FFT to frequency diff --git a/lib/sync66.f90 b/lib/sync66.f90 index bbb72c997..48ed279b4 100644 --- a/lib/sync66.f90 +++ b/lib/sync66.f90 @@ -1,36 +1,32 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) - parameter (NSTEP=4) !Quarter-symbol steps - integer*2 iwave(0:nmax-1) !Raw data - integer b11(11) !Barker 11 code - integer ijpk(2) !Indices i and j at peak of sync_sig - real, allocatable :: s1(:,:) !Symbol spectra - real, allocatable :: x(:) !Work array; demoduated 2FSK sync signal - real sync(4*85) !sync vector - real sync_sig(-64:64,-15:15) + parameter (NSTEP=4) !Quarter-symbol steps + integer*2 iwave(0:nmax-1) !Raw data + integer isync(22) !Indices of sync symbols + integer ijpk(2) !Indices i and j at peak of ccf + real, allocatable :: s1(:,:) !Symbol spectra, quarter-symbol steps + real sync(85) !sync vector + real ccf(-64:64,-15:15) complex, allocatable :: c0(:) !Complex spectrum of symbol - data b11/1,1,1,0,0,0,1,0,0,1,0/ !Barker 11 code + data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data sync(1)/99.0/ save sync nfft=2*nsps df=12000.0/nfft istep=nsps/NSTEP - iz=5000.0/df !Uppermost frequency bin, at 5000 Hz + iz=5000.0/df !Uppermost frequency bin, at 5000 Hz txt=85.0*nsps/12000.0 - jz=(txt+1.0)*12000.0/istep !Number of quarter-symbol steps + jz=(txt+1.0)*12000.0/istep !Number of quarter-symbol steps if(nsps.ge.7680) jz=(txt+2.0)*12000.0/istep !For TR 60 s and higher + allocate(s1(iz,jz)) - allocate(x(jz)) - allocate(c0(0:nsps)) + allocate(c0(0:nfft-1)) if(sync(1).eq.99.0) then - sync=0. + sync=-22.0/63.0 !Sync OFF do k=1,22 - kk=k - if(kk.gt.11) kk=k-11 - i=4*NSTEP*(k-1) + 1 - sync(i)=2.0*b11(kk) - 1.0 + sync(isync(k))=1.0 !Sync ON enddo endif @@ -45,7 +41,7 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) k=k+1 c0(k)=fac*cmplx(xx,yy) enddo - c0(k+1:nfft/2)=0. + c0(k+1:)=0. call four2a(c0,nfft,1,-1,0) !r2c FFT do i=1,iz s1(i,j)=real(c0(i))**2 + aimag(c0(i))**2 @@ -58,14 +54,18 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) s1max=20.0 ! Apply AGC - do j=1,jz - x(j)=maxval(s1(i0-64:i0+192,j)) - if(x(j).gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/x(j) - enddo +! do j=1,jz +! smax=maxval(s1(i0-64:i0+192,j)) +! if(smax.gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/smax +! enddo - sync_sig=0. +! do i=1,iz +! write(60,3060) i,i*df,sum(s1(i,1:jz)) +!3060 format(i6,f10.3,e12.3) +! enddo + + ccf=0. ia=min(64,nint(ntol/df)) - dt4=nsps/(NSTEP*12000.0) !duration of 1/4 symbol jadd=11 if(nsps.ge.3600) jadd=7 @@ -74,31 +74,35 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) if(nsps.ge.41472) jadd=1 do i=-ia,ia - x=s1(i0+2*mode66+i,:)-s1(i0+i,:) !Do the 2FSK demodulation do lag=-15,15 - do k=1,22 - n=4*NSTEP*(k-1) + 1 + do k=1,85 + n=NSTEP*(k-1) + 1 j=n+lag+jadd - if(j.ge.1 .and. j.le.jz) sync_sig(i,lag)=sync_sig(i,lag) + sync(n)*x(j) + if(j.ge.1 .and. j.le.jz) then + ccf(i,lag)=ccf(i,lag) + sync(k)*s1(i0+i,j) + endif enddo enddo enddo - ijpk=maxloc(sync_sig) - ii=ijpk(1)-65 - jj=ijpk(2)-16 +! do i=-64,64 +! write(61,3061) i,ccf(i,jpk) +!3061 format(i5,e12.3) +! enddo +! do j=-15,15 +! write(62,3061) j,ccf(ipk,j) +! enddo -! Use peakup() here? - f0=nfqso + ii*df - jdt=jj - -! j0=0.5/dt4 -! if(nsps.ge.7680) j0=1.0/dt4 - - tsym=nsps/12000.0 - xdt=jdt*tsym/4.0 - - snr1=maxval(sync_sig)/22.0 + ijpk=maxloc(ccf) + ipk=ijpk(1)-65 + jpk=ijpk(2)-16 + dt4=nsps/(NSTEP*12000.0) !1/4 of symbol duration + if(nsps.ge.7680) j0=1.0/dt4 + f0=nfqso + ipk*df + xdt=jpk*dt4 + snr1=maxval(ccf)/22.0 +! write(*,3100) ipk,jpk,xdt,f0,snr1 +!3100 format(2i5,f7.2,2f10.2) return end subroutine sync66 From 6ebc7002880c4fa0539f138f8b06c72459745213 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 25 Sep 2020 12:21:57 -0400 Subject: [PATCH 056/206] Mostly(?) changed QRA66 to QRA65 on the Fortran side. --- CMakeLists.txt | 15 +++---- lib/decoder.f90 | 32 +++++++------- lib/genqra64.f90 | 1 - .../qra66sim.f90 => qra65/qra65sim.f90} | 17 ++++---- lib/{qra66_decode.f90 => qra65_decode.f90} | 42 +++++++++---------- lib/{spec66.f90 => spec_qra65.f90} | 4 +- lib/{sync66.f90 => sync_qra65.f90} | 11 ++--- 7 files changed, 59 insertions(+), 63 deletions(-) rename lib/qra/{qra66/qra66sim.f90 => qra65/qra65sim.f90} (93%) rename lib/{qra66_decode.f90 => qra65_decode.f90} (85%) rename lib/{spec66.f90 => spec_qra65.f90} (95%) rename lib/{sync66.f90 => sync_qra65.f90} (92%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8080d98b8..a14535141 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -380,7 +380,7 @@ set (wsjt_FSRCS lib/options.f90 lib/packjt.f90 lib/77bit/packjt77.f90 - lib/qra66_decode.f90 + lib/qra65_decode.f90 lib/readwav.f90 lib/timer_C_wrapper.f90 lib/timer_impl.f90 @@ -568,7 +568,7 @@ set (wsjt_FSRCS lib/softsym9w.f90 lib/shell.f90 lib/spec64.f90 - lib/spec66.f90 + lib/spec_qra65.f90 lib/spec9f.f90 lib/stdmsg.f90 lib/subtract65.f90 @@ -580,8 +580,8 @@ set (wsjt_FSRCS lib/symspec65.f90 lib/sync4.f90 lib/sync64.f90 - lib/sync66.f90 lib/sync65.f90 + lib/sync_qra65.f90 lib/ft4/getcandidates4.f90 lib/ft4/get_ft4_bitmetrics.f90 lib/ft8/sync8.f90 @@ -1335,11 +1335,8 @@ target_link_libraries (sumsim wsjt_fort wsjt_cxx) add_executable (qra64sim lib/qra/qra64/qra64sim.f90 wsjtx.rc) target_link_libraries (qra64sim wsjt_fort wsjt_cxx) -add_executable (qra66sim lib/qra/qra66/qra66sim.f90 wsjtx.rc) -target_link_libraries (qra66sim wsjt_fort wsjt_cxx) - -#add_executable (test_sync66 lib/test_sync66.f90 wsjtx.rc) -#target_link_libraries (test_sync66 wsjt_fort wsjt_cxx) +add_executable (qra65sim lib/qra/qra65/qra65sim.f90 wsjtx.rc) +target_link_libraries (qra65sim wsjt_fort wsjt_cxx) add_executable (jt49sim lib/jt49sim.f90 wsjtx.rc) target_link_libraries (jt49sim wsjt_fort wsjt_cxx) @@ -1543,7 +1540,7 @@ install (TARGETS jt9 wsprd fmtave fcal fmeasure if(WSJT_BUILD_UTILS) install (TARGETS ft8code jt65code qra64code qra64sim jt9code jt4code - msk144code fst4sim + msk144code fst4sim qra65sim RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime ) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index a6c84d66b..496729388 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -9,7 +9,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) use ft8_decode use ft4_decode use fst4_decode - use qra66_decode + use qra65_decode include 'jt9com.f90' include 'timer_common.inc' @@ -38,9 +38,9 @@ subroutine multimode_decoder(ss,id2,params,nfsample) integer :: decoded end type counting_fst4_decoder - type, extends(qra66_decoder) :: counting_qra66_decoder + type, extends(qra65_decoder) :: counting_qra65_decoder integer :: decoded - end type counting_qra66_decoder + end type counting_qra65_decoder real ss(184,NSMAX) logical baddata,newdat65,newdat9,single_decode,bVHF,bad0,newdat,ex @@ -59,7 +59,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) type(counting_ft8_decoder) :: my_ft8 type(counting_ft4_decoder) :: my_ft4 type(counting_fst4_decoder) :: my_fst4 - type(counting_qra66_decoder) :: my_qra66 + type(counting_qra65_decoder) :: my_qra65 !cast C character arrays to Fortran character strings datetime=transfer(params%datetime, datetime) @@ -75,7 +75,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) my_ft8%decoded = 0 my_ft4%decoded = 0 my_fst4%decoded = 0 - my_qra66%decoded = 0 + my_qra65%decoded = 0 ! For testing only: return Rx messages stored in a file as decodes inquire(file='rx_messages.txt',exist=ex) @@ -195,12 +195,12 @@ subroutine multimode_decoder(ss,id2,params,nfsample) endif if(params%nmode.eq.66) then -! We're in QRA66 mode - call timer('decqra66',0) - call my_qra66%decode(qra66_decoded,id2,params%nutc,params%ntr, & +! We're in QRA65 mode + call timer('decqra65',0) + call my_qra65%decode(qra65_decoded,id2,params%nutc,params%ntr, & params%nsubmode,params%nfqso,params%ntol,params%ndepth, & mycall,hiscall,hisgrid) - call timer('decqra66',1) + call timer('decqra65',1) go to 800 endif @@ -776,13 +776,13 @@ contains return end subroutine fst4_decoded - subroutine qra66_decoded (this,nutc,sync,nsnr,dt,freq,decoded,irc, & + subroutine qra65_decoded (this,nutc,sync,nsnr,dt,freq,decoded,irc, & qual,ntrperiod,fmid,w50) - use qra66_decode + use qra65_decode implicit none - class(qra66_decoder), intent(inout) :: this + class(qra65_decoder), intent(inout) :: this integer, intent(in) :: nutc real, intent(in) :: sync integer, intent(in) :: nsnr @@ -801,23 +801,23 @@ contains write(*,1001) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg 1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded -1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA66') +1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA65') else write(*,1003) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg 1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded -1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA66') +1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA65') endif call flush(6) call flush(13) select type(this) - type is (counting_qra66_decoder) + type is (counting_qra65_decoder) this%decoded = this%decoded + 1 end select return - end subroutine qra66_decoded + end subroutine qra65_decoded end subroutine multimode_decoder diff --git a/lib/genqra64.f90 b/lib/genqra64.f90 index fb0c19438..8426b8830 100644 --- a/lib/genqra64.f90 +++ b/lib/genqra64.f90 @@ -16,7 +16,6 @@ subroutine genqra64(msg0,ichk,msgsent,itone,itype) data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ save - print*,'ichk:',ichk if(msg0(1:1).eq.'@') then read(msg0(2:5),*,end=1,err=1) nfreq go to 2 diff --git a/lib/qra/qra66/qra66sim.f90 b/lib/qra/qra65/qra65sim.f90 similarity index 93% rename from lib/qra/qra66/qra66sim.f90 rename to lib/qra/qra65/qra65sim.f90 index 335a37252..299c95445 100644 --- a/lib/qra/qra66/qra66sim.f90 +++ b/lib/qra/qra65/qra65sim.f90 @@ -1,6 +1,6 @@ -program qra66sim +program qra65sim -! Generate simulated QRA66 data for testing the decoder. +! Generate simulated QRA65 data for testing the decoder. use wavhdr use packjt @@ -19,13 +19,13 @@ program qra66sim nargs=iargc() if(nargs.ne.8) then - print *, 'Usage: qra66sim "msg" A-E freq fDop DT TRp Nfiles SNR' - print *, 'Example: qra66sim "K1ABC W9XYZ EN37" A 1500 0.2 0.0 15 1 -10' + print *, 'Usage: qra65sim "msg" A-E freq fDop DT TRp Nfiles SNR' + print *, 'Example: qra65sim "K1ABC W9XYZ EN37" A 1500 0.2 0.0 15 1 -10' go to 999 endif call getarg(1,msg) call getarg(2,csubmode) - mode66=2**(ichar(csubmode)-ichar('A')) + mode65=2**(ichar(csubmode)-ichar('A')) call getarg(3,arg) read(arg,*) f0 call getarg(4,arg) @@ -62,8 +62,7 @@ program qra66sim dt=1.d0/fsample !Sample interval (s) twopi=8.d0*atan(1.d0) nsym=85 !Number of channel symbols - mode66=2**(ichar(csubmode) - ichar('A')) - print*,csubmode,mode66 + mode65=2**(ichar(csubmode) - ichar('A')) ichk=65 !Flag sent to genqra64 call genqra64(msg,ichk,msgsent,itone,itype) @@ -108,7 +107,7 @@ program qra66sim isym=i/nsps + 1 if(isym.gt.nsym) exit if(isym.ne.isym0) then - freq=f0 + itone(isym)*baud*mode66 + freq=f0 + itone(isym)*baud*mode65 dphi=twopi*freq*dt isym0=isym endif @@ -176,4 +175,4 @@ program qra66sim ! enddo enddo -999 end program qra66sim +999 end program qra65sim diff --git a/lib/qra66_decode.f90 b/lib/qra65_decode.f90 similarity index 85% rename from lib/qra66_decode.f90 rename to lib/qra65_decode.f90 index f0db7378e..1f4b0a1f2 100644 --- a/lib/qra66_decode.f90 +++ b/lib/qra65_decode.f90 @@ -1,17 +1,17 @@ -module qra66_decode +module qra65_decode - type :: qra66_decoder - procedure(qra66_decode_callback), pointer :: callback + type :: qra65_decoder + procedure(qra65_decode_callback), pointer :: callback contains procedure :: decode - end type qra66_decoder + end type qra65_decoder abstract interface - subroutine qra66_decode_callback (this,nutc,sync,nsnr,dt,freq, & + subroutine qra65_decode_callback (this,nutc,sync,nsnr,dt,freq, & decoded,nap,qual,ntrperiod,fmid,w50) - import qra66_decoder + import qra65_decoder implicit none - class(qra66_decoder), intent(inout) :: this + class(qra65_decoder), intent(inout) :: this integer, intent(in) :: nutc real, intent(in) :: sync integer, intent(in) :: nsnr @@ -23,7 +23,7 @@ module qra66_decode integer, intent(in) :: ntrperiod real, intent(in) :: fmid real, intent(in) :: w50 - end subroutine qra66_decode_callback + end subroutine qra65_decode_callback end interface contains @@ -35,8 +35,8 @@ contains use packjt use, intrinsic :: iso_c_binding parameter (NMAX=300*12000) !### Needs to be 300*12000 ### - class(qra66_decoder), intent(inout) :: this - procedure(qra66_decode_callback) :: callback + class(qra65_decoder), intent(inout) :: this + procedure(qra65_decode_callback) :: callback character(len=12) :: mycall, hiscall character(len=6) :: hisgrid character*37 decoded @@ -50,7 +50,7 @@ contains data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/,nsubmodez/-1/ save nc1z,nc2z,ng2z,maxaptypez,nsave,nsubmodez - mode66=2**nsubmode + mode65=2**nsubmode nfft1=ntrperiod*12000 nfft2=ntrperiod*6000 allocate (c0(0:nfft1-1)) @@ -58,8 +58,8 @@ contains if(nsubmode.ne.nsubmodez) then if(allocated(s3)) deallocate(s3) if(allocated(s3a)) deallocate(s3a) - allocate(s3(-64:64*mode66+63,63)) - allocate(s3a(-64:64*mode66+63,63)) + allocate(s3(-64:64*mode65+63,63)) + allocate(s3a(-64:64*mode65+63,63)) endif if(ntrperiod.eq.15) then @@ -115,9 +115,9 @@ contains endif naptype=maxaptype - call timer('sync66 ',0) - call sync66(iwave,ntrperiod*12000,mode66,nsps,nfqso,ntol,xdt,f0,snr1) - call timer('sync66 ',1) + call timer('sync_q65',0) + call sync_qra65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1) + call timer('sync_q65',1) ! Downsample to give complex data at 6000 S/s fac=2.0/nfft1 @@ -131,20 +131,20 @@ contains if(ntrperiod.ge.60) jpk=(xdt+1.0)*6000 - 384 !### TBD ### if(jpk.lt.0) jpk=0 a=0. - a(1)=-(f0 + mode66*baud) !Data tones start mode66 bins higher + a(1)=-(f0 + mode65*baud) !Data tones start mode65 bins higher call twkfreq(c0,c0,ntrperiod*6000,6000.0,a) xdt=jpk/6000.0 - 0.5 - LL=64*(mode66+2) + LL=64*(mode65+2) NN=63 - call spec66(c0(jpk:),nsps/2,s3,LL,NN) !Compute synchronized symbol spectra + call spec_qra65(c0(jpk:),nsps/2,s3,LL,NN) !Compute synchronized symbol spectra do j=1,63 !Normalize to symbol baseline call pctile(s3(:,j),LL,40,base) s3(:,j)=s3(:,j)/base enddo - LL2=64*(mode66+1)-1 + LL2=64*(mode65+1)-1 s3max=20.0 do j=1,63 !Apply AGC to suppress pings xx=maxval(s3(-64:LL2,j)) @@ -201,4 +201,4 @@ contains return end subroutine decode -end module qra66_decode +end module qra65_decode diff --git a/lib/spec66.f90 b/lib/spec_qra65.f90 similarity index 95% rename from lib/spec66.f90 rename to lib/spec_qra65.f90 index 454f1c18d..9f6af0b38 100644 --- a/lib/spec66.f90 +++ b/lib/spec_qra65.f90 @@ -1,4 +1,4 @@ -subroutine spec66(c0,nsps,s3,LL,NN) +subroutine spec_qra65(c0,nsps,s3,LL,NN) ! Compute synchronized symbol spectra. @@ -46,4 +46,4 @@ subroutine spec66(c0,nsps,s3,LL,NN) enddo return -end subroutine spec66 +end subroutine spec_qra65 diff --git a/lib/sync66.f90 b/lib/sync_qra65.f90 similarity index 92% rename from lib/sync66.f90 rename to lib/sync_qra65.f90 index 48ed279b4..8d3bc1013 100644 --- a/lib/sync66.f90 +++ b/lib/sync_qra65.f90 @@ -1,4 +1,4 @@ -subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) +subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) parameter (NSTEP=4) !Quarter-symbol steps integer*2 iwave(0:nmax-1) !Raw data @@ -7,7 +7,7 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) real, allocatable :: s1(:,:) !Symbol spectra, quarter-symbol steps real sync(85) !sync vector real ccf(-64:64,-15:15) - complex, allocatable :: c0(:) !Complex spectrum of symbol + complex, allocatable :: c0(:) !Complex spectrum of symbol data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data sync(1)/99.0/ save sync @@ -72,6 +72,9 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) if(nsps.ge.7680) jadd=6 if(nsps.ge.16000) jadd=3 if(nsps.ge.41472) jadd=1 + dt4=nsps/(NSTEP*12000.0) !1/4 of symbol duration +! j0=0.5/dt4 +! if(nsps.ge.7680) j0=1.0/dt4 do i=-ia,ia do lag=-15,15 @@ -96,8 +99,6 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) ijpk=maxloc(ccf) ipk=ijpk(1)-65 jpk=ijpk(2)-16 - dt4=nsps/(NSTEP*12000.0) !1/4 of symbol duration - if(nsps.ge.7680) j0=1.0/dt4 f0=nfqso + ipk*df xdt=jpk*dt4 snr1=maxval(ccf)/22.0 @@ -105,4 +106,4 @@ subroutine sync66(iwave,nmax,mode66,nsps,nfqso,ntol,xdt,f0,snr1) !3100 format(2i5,f7.2,2f10.2) return -end subroutine sync66 +end subroutine sync_qra65 From 7fd2f1afe693d44b90e835d957b9fbf8d1f2da13 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 25 Sep 2020 13:20:46 -0400 Subject: [PATCH 057/206] Change QRA66 to QRA65, on the C++ side. --- lib/decoder.f90 | 2 +- widgets/mainwindow.cpp | 52 +++++++++++++++++++++--------------------- widgets/mainwindow.h | 4 ++-- widgets/mainwindow.ui | 6 ++--- widgets/plotter.cpp | 8 +++---- 5 files changed, 36 insertions(+), 36 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 496729388..7a8e12275 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -194,7 +194,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) go to 800 endif - if(params%nmode.eq.66) then + if(params%nmode.eq.66) then !NB: JT65 = 65, QRA65 = 66. ! We're in QRA65 mode call timer('decqra65',0) call my_qra65%decode(qra65_decoded,id2,params%nutc,params%ntr, & diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 49aa52253..c2231eb5e 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -596,7 +596,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionISCAT->setActionGroup(modeGroup); ui->actionMSK144->setActionGroup(modeGroup); ui->actionQRA64->setActionGroup(modeGroup); - ui->actionQRA66->setActionGroup(modeGroup); + ui->actionQRA65->setActionGroup(modeGroup); ui->actionFreqCal->setActionGroup(modeGroup); QActionGroup* saveGroup = new QActionGroup(this); @@ -1366,7 +1366,7 @@ void MainWindow::fixStop() } else if (m_mode=="QRA64"){ m_hsymStop=179; if(m_config.decode_at_52s()) m_hsymStop=186; - } else if (m_mode=="QRA66"){ + } else if (m_mode=="QRA65"){ m_hsymStop=48; if(m_TRperiod==30) m_hsymStop=96; if(m_TRperiod==60) m_hsymStop=196; @@ -2355,7 +2355,7 @@ void MainWindow::setup_status_bar (bool vhf) mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #66ff66}"); } else if ("QRA64" == m_mode) { mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #99ff33}"); - } else if ("QRA66" == m_mode) { + } else if ("QRA65" == m_mode) { mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #99ff33}"); } else if ("MSK144" == m_mode) { mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff6666}"); @@ -2557,7 +2557,7 @@ void MainWindow::on_actionCopyright_Notice_triggered() "notice prominently in your derivative work:\n\n" "\"The algorithms, source code, look-and-feel of WSJT-X and related " "programs, and protocol specifications for the modes FSK441, FST4, FT8, " - "JT4, JT6M, JT9, JT65, JTMS, QRA64, QRA66, ISCAT, MSK144 are Copyright (C) " + "JT4, JT6M, JT9, JT65, JTMS, QRA64, QRA65, ISCAT, MSK144 are Copyright (C) " "2001-2020 by one or more of the following authors: Joseph Taylor, " "K1JT; Bill Somerville, G4WJS; Steven Franke, K9AN; Nico Palermo, " "IV3NWV; Greg Beam, KI7MT; Michael Black, W9MDB; Edson Pereira, PY2SDR; " @@ -3079,8 +3079,8 @@ void MainWindow::decode() //decode() ui->actionEnable_AP_JT65->isChecked (); if(m_mode=="QRA64") dec_data.params.nmode=164; if(m_mode=="QRA64") dec_data.params.ntxmode=164; - if(m_mode=="QRA66") dec_data.params.nmode=66; - if(m_mode=="QRA66") dec_data.params.ntxmode=66; + if(m_mode=="QRA65") dec_data.params.nmode=66; + if(m_mode=="QRA65") dec_data.params.ntxmode=66; if(m_mode=="JT9+JT65") dec_data.params.nmode=9+65; // = 74 if(m_mode=="JT4") { dec_data.params.nmode=4; @@ -3403,7 +3403,7 @@ void MainWindow::readFromStdout() //readFromStdout //Right (Rx Frequency) window bool bDisplayRight=bAvgMsg; int audioFreq=decodedtext.frequencyOffset(); - if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="FST4" or m_mode=="QRA66") { + if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="FST4" or m_mode=="QRA65") { auto const& parts = decodedtext.string().remove("<").remove(">") .split (' ', SkipEmptyParts); if (parts.size() > 6) { @@ -3486,7 +3486,7 @@ void MainWindow::readFromStdout() //readFromStdout //### I think this is where we are preventing Hounds from spotting Fox ### if(m_mode!="FT8" or (SpecOp::HOUND != m_config.special_op_id())) { - if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="QRA64" or m_mode=="QRA66" + if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="QRA64" or m_mode=="QRA65" or m_mode=="JT4" or m_mode=="JT65" or m_mode=="JT9" or m_mode=="FST4") { auto_sequence (decodedtext, 25, 50); } @@ -3696,7 +3696,7 @@ void MainWindow::guiUpdate() if(m_modeTx=="JT9") txDuration=1.0 + 85.0*m_nsps/12000.0; // JT9 if(m_modeTx=="JT65") txDuration=1.0 + 126*4096/11025.0; // JT65 if(m_modeTx=="QRA64") txDuration=1.0 + 84*6912/12000.0; // QRA64 - if(m_modeTx=="QRA66") { // QRA66 + if(m_modeTx=="QRA65") { // QRA65 if(m_TRperiod==15) txDuration=0.5 + 85*1800/12000.0; if(m_TRperiod==30) txDuration=0.5 + 85*3600/12000.0; if(m_TRperiod==60) txDuration=1.0 + 85*7680/12000.0; @@ -3954,9 +3954,9 @@ void MainWindow::guiUpdate() &m_currentMessageType, 22, 22); if(m_modeTx=="QRA64") genqra64_(message, &ichk, msgsent, const_cast (itone), &m_currentMessageType, 22, 22); - if(m_modeTx=="QRA66") { - int ichk66=66; - genqra64_(message, &ichk66, msgsent, const_cast (itone), + if(m_modeTx=="QRA65") { + int ichk65=65; + genqra64_(message, &ichk65, msgsent, const_cast (itone), &m_currentMessageType, 22, 22); } if(m_modeTx=="WSPR") genwspr_(message, msgsent, const_cast (itone), @@ -4672,7 +4672,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie || ("JT9" == m_mode && mode != "@") || ("MSK144" == m_mode && !("&" == mode || "^" == mode)) || ("QRA64" == m_mode && mode.left (1) != ":")) { - return; //Currently we do auto-sequencing only in FT4, FT8, MSK144, FST4, and QRA66 + return; //Currently we do auto-sequencing only in FT4, FT8, MSK144, FST4, and QRA65 } //Skip the rest if no decoded text extracted @@ -4780,7 +4780,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie ui->TxFreqSpinBox->setValue(frequency); } if(m_mode != "JT4" && m_mode != "JT65" && !m_mode.startsWith ("JT9") && - m_mode != "QRA64" && m_mode != "QRA66" && m_mode!="FT8" && + m_mode != "QRA64" && m_mode != "QRA65" && m_mode!="FT8" && m_mode!="FT4" && m_mode!="FST4") { return; } @@ -6324,12 +6324,12 @@ void MainWindow::on_actionQRA64_triggered() statusChanged(); } -void MainWindow::on_actionQRA66_triggered() +void MainWindow::on_actionQRA65_triggered() { on_actionFST4_triggered(); - m_mode="QRA66"; - m_modeTx="QRA66"; - ui->actionQRA66->setChecked(true); + m_mode="QRA65"; + m_modeTx="QRA65"; + ui->actionQRA65->setChecked(true); switch_mode (Modes::QRA64); setup_status_bar (false); m_hsymStop=49; @@ -6392,7 +6392,7 @@ void MainWindow::on_actionMSK144_triggered() if("JT9_JT65"==m_mode) ui->actionJT9_JT65->setChecked(true); if("ISCAT"==m_mode) ui->actionISCAT->setChecked(true); if("QRA64"==m_mode) ui->actionQRA64->setChecked(true); - if("QRA66"==m_mode) ui->actionQRA66->setChecked(true); + if("QRA65"==m_mode) ui->actionQRA65->setChecked(true); if("WSPR"==m_mode) ui->actionWSPR->setChecked(true); if("Echo"==m_mode) ui->actionEcho->setChecked(true); if("FreqCal"==m_mode) ui->actionFreqCal->setChecked(true); @@ -7206,15 +7206,15 @@ void MainWindow::transmit (double snr) true, false, snr, m_TRperiod); } - if (m_modeTx == "QRA66") { + if (m_modeTx == "QRA65") { int nsps=1800; if(m_TRperiod==30) nsps=3600; if(m_TRperiod==60) nsps=7680; if(m_TRperiod==120) nsps=16000; if(m_TRperiod==300) nsps=41472; - int mode66=pow(2.0,double(m_nSubMode)); - toneSpacing=mode66*12000.0/nsps; - Q_EMIT sendMessage (m_mode, NUM_QRA66_SYMBOLS, + int mode65=pow(2.0,double(m_nSubMode)); + toneSpacing=mode65*12000.0/nsps; + Q_EMIT sendMessage (m_mode, NUM_QRA65_SYMBOLS, double(nsps), ui->TxFreqSpinBox->value () - m_XIT, toneSpacing, m_soundOutput, m_config.audio_output_channel (), true, false, snr, m_TRperiod); @@ -7475,9 +7475,9 @@ void::MainWindow::VHF_features_enabled(bool b) void MainWindow::on_sbTR_valueChanged(int value) { // if(!m_bFastMode and n>m_nSubMode) m_MinW=m_nSubMode; - if(m_bFastMode or m_mode=="FreqCal" or m_mode=="FST4" or m_mode=="FST4W" or m_mode=="QRA66") { + if(m_bFastMode or m_mode=="FreqCal" or m_mode=="FST4" or m_mode=="FST4W" or m_mode=="QRA65") { m_TRperiod = value; - if (m_mode == "FST4" or m_mode == "FST4W" or m_mode=="QRA66") { + if (m_mode == "FST4" or m_mode == "FST4W" or m_mode=="QRA65") { if (m_TRperiod < 60) { ui->decodedTextLabel->setText(" UTC dB DT Freq " + tr ("Message")); if (m_mode != "FST4W") { @@ -9157,7 +9157,7 @@ void MainWindow::set_mode (QString const& mode) else if ("JT9+JT65" == mode) on_actionJT9_JT65_triggered (); else if ("JT65" == mode) on_actionJT65_triggered (); else if ("QRA64" == mode) on_actionQRA64_triggered (); - else if ("QRA66" == mode) on_actionQRA66_triggered (); + else if ("QRA65" == mode) on_actionQRA65_triggered (); else if ("FreqCal" == mode) on_actionFreqCal_triggered (); else if ("ISCAT" == mode) on_actionISCAT_triggered (); else if ("MSK144" == mode) on_actionMSK144_triggered (); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 3660cd219..2e931ea3c 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -48,7 +48,7 @@ #define NUM_ISCAT_SYMBOLS 1291 //30*11025/256 #define NUM_MSK144_SYMBOLS 144 //s8 + d48 + s8 + d80 #define NUM_QRA64_SYMBOLS 84 //63 data + 21 sync -#define NUM_QRA66_SYMBOLS 85 //63 data + 22 sync +#define NUM_QRA65_SYMBOLS 85 //63 data + 22 sync #define NUM_FT8_SYMBOLS 79 #define NUM_FT4_SYMBOLS 105 #define NUM_FST4_SYMBOLS 160 //240/2 data + 5*8 sync @@ -300,7 +300,7 @@ private slots: void on_cbCQTx_toggled(bool b); void on_actionMSK144_triggered(); void on_actionQRA64_triggered(); - void on_actionQRA66_triggered(); + void on_actionQRA65_triggered(); void on_actionFreqCal_triggered(); void splash_done (); void on_measure_check_box_stateChanged (int); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index a826b2fa2..33ffd38ca 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -2806,7 +2806,7 @@ Yellow when too low - + @@ -3293,12 +3293,12 @@ Yellow when too low FST4W - + true - QRA66 + QRA65 diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index ea53b7925..3879f0c27 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -472,7 +472,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() if(m_nSubMode==4) bw=16*bw; //E } - if(m_mode=="QRA66") { //QRA66 + if(m_mode=="QRA65") { //QRA65 int h=int(pow(2.0,m_nSubMode)); int nsps=1800; if(m_TRperiod==30) nsps=3600; @@ -513,10 +513,10 @@ void CPlotter::DrawOverlay() //DrawOverlay() int yTxTop=12; int yRxBottom=yTxTop + 2*yh + 4; if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" - or m_mode=="QRA64" or m_mode=="QRA66" or m_mode=="FT8" or m_mode=="FT4" + or m_mode=="QRA64" or m_mode=="QRA65" or m_mode=="FT8" or m_mode=="FT4" or m_mode.startsWith("FST4")) { - if(m_mode=="QRA64" or m_mode=="QRA66" or (m_mode=="JT65" and m_bVHF)) { + if(m_mode=="QRA64" or m_mode=="QRA65" or (m_mode=="JT65" and m_bVHF)) { painter0.setPen(penGreen); x1=XfromFreq(m_rxFreq-m_tol); x2=XfromFreq(m_rxFreq+m_tol); @@ -554,7 +554,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() } if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or - m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="QRA66" or m_mode=="FT8" + m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="QRA65" or m_mode=="FT8" or m_mode=="FT4" or m_mode.startsWith("FST4")) { painter0.setPen(penRed); x1=XfromFreq(m_txFreq); From 443aee5355b20ed7371af6950e451531df03b95a Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 25 Sep 2020 13:31:43 -0400 Subject: [PATCH 058/206] Restore AGC action in sync_qra65(). --- lib/sync_qra65.f90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/sync_qra65.f90 b/lib/sync_qra65.f90 index 8d3bc1013..09681262b 100644 --- a/lib/sync_qra65.f90 +++ b/lib/sync_qra65.f90 @@ -54,10 +54,10 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) s1max=20.0 ! Apply AGC -! do j=1,jz -! smax=maxval(s1(i0-64:i0+192,j)) -! if(smax.gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/smax -! enddo + do j=1,jz + smax=maxval(s1(i0-64:i0+192,j)) + if(smax.gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/smax + enddo ! do i=1,iz ! write(60,3060) i,i*df,sum(s1(i,1:jz)) From acd6253373765587813f7119efd003cb35dc75a7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 25 Sep 2020 15:38:20 -0400 Subject: [PATCH 059/206] A few more fixups for QRA65. Not finished, yet! --- CMakeLists.txt | 3 +++ Modulator/Modulator.cpp | 2 +- displayWidgets.txt | 2 +- lib/sync_qra65.f90 | 1 + lib/{test_qra66.f90 => test_qra65.f90} | 11 +++++------ models/Modes.cpp | 3 ++- models/Modes.hpp | 1 + widgets/mainwindow.cpp | 11 ++++++----- 8 files changed, 20 insertions(+), 14 deletions(-) rename lib/{test_qra66.f90 => test_qra65.f90} (90%) diff --git a/CMakeLists.txt b/CMakeLists.txt index a14535141..712e176ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1338,6 +1338,9 @@ target_link_libraries (qra64sim wsjt_fort wsjt_cxx) add_executable (qra65sim lib/qra/qra65/qra65sim.f90 wsjtx.rc) target_link_libraries (qra65sim wsjt_fort wsjt_cxx) +add_executable (test_qra65 lib/test_qra65.f90 wsjtx.rc) +target_link_libraries (test_qra65 wsjt_fort wsjt_cxx) + add_executable (jt49sim lib/jt49sim.f90 wsjtx.rc) target_link_libraries (jt49sim wsjt_fort wsjt_cxx) diff --git a/Modulator/Modulator.cpp b/Modulator/Modulator.cpp index f391b1ffd..328b5b3ab 100644 --- a/Modulator/Modulator.cpp +++ b/Modulator/Modulator.cpp @@ -70,7 +70,7 @@ void Modulator::start (QString mode, unsigned symbolsLength, double framesPerSym m_bFastMode=fastMode; m_TRperiod=TRperiod; unsigned delay_ms=1000; - if(mode=="FT8" or (mode=="FST4" and m_nsps==720) or mode=="QRA66") delay_ms=500; //FT8, FST4-15, QRA66 + if(mode=="FT8" or (mode=="FST4" and m_nsps==720) or mode=="QRA65") delay_ms=500; //FT8, FST4-15, QRA65 if(mode=="FT4") delay_ms=300; //FT4 // noise generator parameters diff --git a/displayWidgets.txt b/displayWidgets.txt index 912b19f01..23e02480f 100644 --- a/displayWidgets.txt +++ b/displayWidgets.txt @@ -11,7 +11,7 @@ JT9+JT65 1110100000011110000100000000000010 JT65 1110100000001110000100000000000010 JT65/VHF 1111100100001101101011000100000000 QRA64 1111100101101101100000000010000000 -QRA66 1111110101101101000100000011000000 +QRA65 1111110101101101000100000011000000 ISCAT 1001110000000001100000000000000000 MSK144 1011111101000000000100010000000000 WSPR 0000000000000000010100000000000000 diff --git a/lib/sync_qra65.f90 b/lib/sync_qra65.f90 index 09681262b..1a7859cb1 100644 --- a/lib/sync_qra65.f90 +++ b/lib/sync_qra65.f90 @@ -73,6 +73,7 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) if(nsps.ge.16000) jadd=3 if(nsps.ge.41472) jadd=1 dt4=nsps/(NSTEP*12000.0) !1/4 of symbol duration +! print*,'DT range +/-',15*dt4 ! j0=0.5/dt4 ! if(nsps.ge.7680) j0=1.0/dt4 diff --git a/lib/test_qra66.f90 b/lib/test_qra65.f90 similarity index 90% rename from lib/test_qra66.f90 rename to lib/test_qra65.f90 index 8ff97829c..67af7a720 100644 --- a/lib/test_qra66.f90 +++ b/lib/test_qra65.f90 @@ -1,17 +1,16 @@ -program test_qra66 +program test_qra65 character*70 cmd1,cmd2,line character*22 msg character*8 arg integer nretcode(0:11) integer fDop - real fspread logical decok nargs=iargc() if(nargs.ne.7) then - print*,'Usage: test_qra66 "msg" ndepth freq DT fDop nfiles SNR' - print*,'Example: test_qra66 "K1ABC W9XYZ EN37" 3 1500 0.0 5 100 0' + print*,'Usage: test_qra65 "msg" ndepth freq DT fDop nfiles SNR' + print*,'Example: test_qra65 "K1ABC W9XYZ EN37" 3 1500 0.0 5 100 0' print*,' SNR = 0 to loop over all relevant SNRs' go to 999 endif @@ -31,7 +30,7 @@ program test_qra66 ! 1 2 3 4 5 6 ! 1234567890123456789012345678901234567890123456789012345678901234' - cmd1='qra66sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 100 -10 > junk0' + cmd1='qra65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 100 -10 > junk0' cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 1 *.wav > junk' write(cmd1(10:33),'(a)') '"'//msg//'"' @@ -96,7 +95,7 @@ program test_qra66 flush(12) enddo -999 end program test_qra66 +999 end program test_qra65 include 'sec0.f90' diff --git a/models/Modes.cpp b/models/Modes.cpp index 2de1f7c90..deaa2a0f6 100644 --- a/models/Modes.cpp +++ b/models/Modes.cpp @@ -26,7 +26,8 @@ namespace "FT8", "FT4", "FST4", - "FST4W" + "FST4W", + "QRA65" }; std::size_t constexpr mode_names_size = sizeof (mode_names) / sizeof (mode_names[0]); } diff --git a/models/Modes.hpp b/models/Modes.hpp index ac57ba4ad..2f3bf60f7 100644 --- a/models/Modes.hpp +++ b/models/Modes.hpp @@ -52,6 +52,7 @@ public: FT4, FST4, FST4W, + QRA65, MODES_END_SENTINAL_AND_COUNT // this must be last }; Q_ENUM (Mode) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index c2231eb5e..1cd40b1fe 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6330,16 +6330,17 @@ void MainWindow::on_actionQRA65_triggered() m_mode="QRA65"; m_modeTx="QRA65"; ui->actionQRA65->setChecked(true); - switch_mode (Modes::QRA64); - setup_status_bar (false); + switch_mode(Modes::QRA65); + setup_status_bar(true); m_hsymStop=49; ui->sbTR->values ({15, 30, 60, 120, 300}); on_sbTR_valueChanged (ui->sbTR->value()); - m_wideGraph->setMode(m_mode); + ui->sbSubmode->setMaximum(3); + ui->sbSubmode->setValue(m_nSubMode); m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); m_wideGraph->setPeriod(m_TRperiod,6912); + m_wideGraph->setTol(ui->sbFtol->value()); // 0123456789012345678901234567890123 -//displayWidgets(nWidgets("1111100001001100000100000001000000")); displayWidgets(nWidgets("1111110101101101000100000011000000")); statusChanged();} @@ -7523,7 +7524,7 @@ void MainWindow::on_sbTR_FST4W_valueChanged(int value) QChar MainWindow::current_submode () const { QChar submode {0}; - if (m_mode.contains (QRegularExpression {R"(^(JT65|JT9|JT4|ISCAT|QRA64)$)"}) + if (m_mode.contains (QRegularExpression {R"(^(JT65|JT9|JT4|ISCAT|QRA64|QRA65)$)"}) && (m_config.enable_VHF_features () || "JT4" == m_mode || "ISCAT" == m_mode)) { submode = m_nSubMode + 65; From c3d8e4dd73fff65d559e38071d9a04639fb5b60c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 26 Sep 2020 16:49:06 -0400 Subject: [PATCH 060/206] Working on QRA65, including simulator and test program. --- lib/qra/qra65/qra65sim.f90 | 4 +- lib/qra65_decode.f90 | 19 ++++--- lib/sync_qra65.f90 | 27 +++++----- lib/test_qra65.f90 | 101 ++++++++++++++++++++++++++----------- widgets/mainwindow.cpp | 11 +++- 5 files changed, 105 insertions(+), 57 deletions(-) diff --git a/lib/qra/qra65/qra65sim.f90 b/lib/qra/qra65/qra65sim.f90 index 299c95445..e91324d27 100644 --- a/lib/qra/qra65/qra65sim.f90 +++ b/lib/qra/qra65/qra65sim.f90 @@ -96,8 +96,8 @@ program qra65sim bandwidth_ratio=2500.0/6000.0 sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snrdb) if(snrdb.gt.90.0) sig=1.0 - write(*,1020) ifile,ntrperiod,f0,csubmode,xsnr,xdt,fspread,msgsent -1020 format(i4,i6,f7.1,2x,a1,2x,f5.1,f6.2,f6.1,1x,a22) + write(*,1020) ifile,ntrperiod,f0,csubmode,snrdb,xdt,fspread,msgsent +1020 format(i4,i6,f7.1,2x,a1,2x,f5.1,f6.2,f6.1,2x,a22) phi=0.d0 dphi=0.d0 k=(xdt+0.5)*12000 !Start audio at t=xdt+0.5 s (TR=15 and 30 s) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index 1f4b0a1f2..0f04565f7 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -78,7 +78,7 @@ contains baud=12000.0/nsps df1=12000.0/nfft1 -! do i=1,NMAX +! do i=1,12000*ntrperiod ! write(61,3061) i/12000.0,iwave(i)/32767.0 !3061 format(2f12.6) ! enddo @@ -120,24 +120,27 @@ contains call timer('sync_q65',1) ! Downsample to give complex data at 6000 S/s + call timer('down_q65',0) fac=2.0/nfft1 c0=fac*iwave(1:nfft1) call four2a(c0,nfft1,1,-1,1) !Forward c2c FFT c0(nfft2/2+1:nfft2)=0. !Zero the top half c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT - - jpk=(xdt+0.5)*6000 - 384 !### Empirical ### - if(ntrperiod.ge.60) jpk=(xdt+1.0)*6000 - 384 !### TBD ### - if(jpk.lt.0) jpk=0 a=0. a(1)=-(f0 + mode65*baud) !Data tones start mode65 bins higher call twkfreq(c0,c0,ntrperiod*6000,6000.0,a) + call timer('down_q65',1) + + jpk=(xdt+0.5)*6000 - 384 !### Empirical ### + if(ntrperiod.ge.60) jpk=(xdt+1.0)*6000 - 384 !### TBD ??? ### + if(jpk.lt.0) jpk=0 xdt=jpk/6000.0 - 0.5 - LL=64*(mode65+2) NN=63 - call spec_qra65(c0(jpk:),nsps/2,s3,LL,NN) !Compute synchronized symbol spectra + call timer('spec_q65',0) + call spec_qra65(c0(jpk:),nsps/2,s3,LL,NN) !Compute synced symbol spectra + call timer('spec_q65',1) do j=1,63 !Normalize to symbol baseline call pctile(s3(:,j),LL,40,base) @@ -188,7 +191,7 @@ contains irc,qual,ntrperiod,fmid,w50) else snr2=0. - nsnr=-25 + nsnr=-25 !### TEMPORARY? ### call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) diff --git a/lib/sync_qra65.f90 b/lib/sync_qra65.f90 index 1a7859cb1..21c155415 100644 --- a/lib/sync_qra65.f90 +++ b/lib/sync_qra65.f90 @@ -6,7 +6,7 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) integer ijpk(2) !Indices i and j at peak of ccf real, allocatable :: s1(:,:) !Symbol spectra, quarter-symbol steps real sync(85) !sync vector - real ccf(-64:64,-15:15) + real ccf(-64:64,-26:107) complex, allocatable :: c0(:) !Complex spectrum of symbol data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data sync(1)/99.0/ @@ -64,24 +64,20 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) !3060 format(i6,f10.3,e12.3) ! enddo + dt4=nsps/(NSTEP*12000.0) !1/4 of symbol duration + j0=0.5/dt4 + if(nsps.ge.7680) j0=1.0/dt4 + ccf=0. ia=min(64,nint(ntol/df)) + lag1=-1.0/dt4 + lag2=4.0/dt4 + 0.9999 - jadd=11 - if(nsps.ge.3600) jadd=7 - if(nsps.ge.7680) jadd=6 - if(nsps.ge.16000) jadd=3 - if(nsps.ge.41472) jadd=1 - dt4=nsps/(NSTEP*12000.0) !1/4 of symbol duration -! print*,'DT range +/-',15*dt4 -! j0=0.5/dt4 -! if(nsps.ge.7680) j0=1.0/dt4 - do i=-ia,ia - do lag=-15,15 + do lag=lag1,lag2 do k=1,85 n=NSTEP*(k-1) + 1 - j=n+lag+jadd + j=n+lag+j0 if(j.ge.1 .and. j.le.jz) then ccf(i,lag)=ccf(i,lag) + sync(k)*s1(i0+i,j) endif @@ -93,13 +89,14 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) ! write(61,3061) i,ccf(i,jpk) !3061 format(i5,e12.3) ! enddo -! do j=-15,15 +! do j=lag1,lag2 ! write(62,3061) j,ccf(ipk,j) ! enddo ijpk=maxloc(ccf) ipk=ijpk(1)-65 - jpk=ijpk(2)-16 +! jpk=ijpk(2)-16 + jpk=ijpk(2)-27 f0=nfqso + ipk*df xdt=jpk*dt4 snr1=maxval(ccf)/22.0 diff --git a/lib/test_qra65.f90 b/lib/test_qra65.f90 index 67af7a720..2ebe08264 100644 --- a/lib/test_qra65.f90 +++ b/lib/test_qra65.f90 @@ -1,16 +1,15 @@ program test_qra65 - character*70 cmd1,cmd2,line + character*71 cmd1,cmd2,line character*22 msg character*8 arg integer nretcode(0:11) - integer fDop logical decok nargs=iargc() - if(nargs.ne.7) then - print*,'Usage: test_qra65 "msg" ndepth freq DT fDop nfiles SNR' - print*,'Example: test_qra65 "K1ABC W9XYZ EN37" 3 1500 0.0 5 100 0' + if(nargs.ne.8) then + print*,'Usage: test_qra65 "msg" ndepth freq DT fDop TRp nfiles SNR' + print*,'Example: test_qra65 "K1ABC W9XYZ EN37" 3 1500 0.0 5.0 60 100 -20' print*,' SNR = 0 to loop over all relevant SNRs' go to 999 endif @@ -24,32 +23,61 @@ program test_qra65 call getarg(5,arg) read(arg,*) fDop call getarg(6,arg) - read(arg,*) nfiles + read(arg,*) ntrperiod call getarg(7,arg) + read(arg,*) nfiles + call getarg(8,arg) read(arg,*) nsnr -! 1 2 3 4 5 6 -! 1234567890123456789012345678901234567890123456789012345678901234' - cmd1='qra65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 100 -10 > junk0' - cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 1 *.wav > junk' - - write(cmd1(10:33),'(a)') '"'//msg//'"' - write(cmd1(37:40),'(i4)') nf0 - write(cmd1(41:45),'(i5)') fDop - write(cmd1(46:50),'(f5.2)') dt - write(cmd1(51:55),'(i5)') nfiles - write(cmd2(32:32),'(i1)') ndepth - call system('rm -f *.wav') - - write(*,1000) (j,j=0,11) - write(12,1000) (j,j=0,11) -1000 format(/'SNR d Dop Sync Dec1 DecN Bad',i5,11i4,' tdec'/83('-')) - ia=-12 - ib=-30 + if(ntrperiod.eq.15) then + nsps=1800 + i50=-21 + else if(ntrperiod.eq.30) then + nsps=3600 + i50=-24 + else if(ntrperiod.eq.60) then + nsps=7680 + i50=-28 + else if(ntrperiod.eq.120) then + nsps=16000 + i50=-31 + else if(ntrperiod.eq.300) then + nsps=41472 + i50=-35 + else + stop 'Invalid TR period' + endif + ia=i50 + 8 + ib=i50 - 5 if(nsnr.ne.0) then ia=nsnr ib=nsnr endif + + baud=12000.0/nsps + tsym=1.0/baud + +! 1 2 3 4 5 6 7 +! 12345678901234567890123456789012345678901234567890123456789012345678901' + cmd1='qra65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 -10 > junk0' + cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 1 *.wav > junk' + + write(cmd1(10:33),'(a)') '"'//msg//'"' + write(cmd1(37:40),'(i4)') nf0 + write(cmd1(41:45),'(f5.1)') fDop + write(cmd1(46:50),'(f5.2)') dt + write(cmd1(51:54),'(i4)') ntrperiod + write(cmd1(55:59),'(i5)') nfiles + write(cmd2(11:13),'(i3)') ntrperiod + write(cmd2(33:33),'(i1)') ndepth + call system('rm -f *.wav') + + write(*,1000) (j,j=0,11) + write(12,1000) (j,j=0,11) +1000 format(/'SNR d Dop Sync Dec1 DecN Bad',i6,11i4,' tdec dtavg dtrms'/97('-')) + + dterr=3.0*tsym/4.0 + nferr=max(1,nint(0.5*baud)) do nsnr=ia,ib,-1 nsync=0 @@ -57,7 +85,9 @@ program test_qra65 nfalse=0 nretcode=0 navg=0 - write(cmd1(57:59),'(i3)') nsnr + sumxdt=0. + sqxdt=0. + write(cmd1(61:63),'(i3)') nsnr call system(cmd1) call sec0(0,tdec) call system(cmd2) @@ -65,10 +95,11 @@ program test_qra65 open(10,file='junk',status='unknown') n=0 do iline=1,9999 - read(10,'(a70)',end=10) line + read(10,'(a71)',end=10) line if(len(trim(line)).lt.60) cycle read(line(11:20),*) xdt,nf - if(abs(xdt-dt).lt.0.15 .and. abs(nf-nf0).lt.4) nsync=nsync+1 +! if(ntrperiod.eq.60) xdt=xdt-0.5 !### TEMPORARY ### + if(abs(xdt-dt).le.dterr .and. abs(nf-nf0).le.nferr) nsync=nsync+1 read(line(60:),*) irc,iavg if(irc.lt.0) cycle decok=index(line,'W9XYZ').gt.0 @@ -76,6 +107,8 @@ program test_qra65 i=irc if(i.le.11) then ndecodes=ndecodes + 1 + sumxdt=sumxdt + xdt + sqxdt=sqxdt + xdt*xdt navg=navg + 1 else i=mod(i,10) @@ -88,9 +121,17 @@ program test_qra65 endif enddo 10 close(10) - write(*,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode,tdec/nfiles - write(12,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode,tdec/nfiles -1100 format(i3,i2,i3,3i5,i4,i6,11i4,f6.2) + xdt_avg=0. + xdt_rms=0. + if(ndecodes.ge.2) then + xdt_avg=sumxdt/ndecodes + xdt_rms=sqxdt/(ndecodes-1) - xdt_avg*xdt_avg + endif + write(*,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode, & + tdec/nfiles,xdt_avg,xdt_rms + write(12,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode, & + tdec/nfiles,xdt_avg,xdt_rms +1100 format(i3,i2,f5.1,3i5,i4,i6,11i4,3f6.2) flush(6) flush(12) enddo diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 1cd40b1fe..df2117292 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6326,23 +6326,30 @@ void MainWindow::on_actionQRA64_triggered() void MainWindow::on_actionQRA65_triggered() { - on_actionFST4_triggered(); +// on_actionFST4_triggered(); m_mode="QRA65"; m_modeTx="QRA65"; ui->actionQRA65->setChecked(true); switch_mode(Modes::QRA65); setup_status_bar(true); + m_nsps=6912; //For symspec only + m_FFTSize = m_nsps / 2; + Q_EMIT FFTSize(m_FFTSize); m_hsymStop=49; ui->sbTR->values ({15, 30, 60, 120, 300}); on_sbTR_valueChanged (ui->sbTR->value()); ui->sbSubmode->setMaximum(3); ui->sbSubmode->setValue(m_nSubMode); m_wideGraph->setMode(m_mode); + m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); m_wideGraph->setPeriod(m_TRperiod,6912); m_wideGraph->setTol(ui->sbFtol->value()); + m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); + m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); // 0123456789012345678901234567890123 displayWidgets(nWidgets("1111110101101101000100000011000000")); - statusChanged();} + statusChanged(); +} void MainWindow::on_actionISCAT_triggered() { From 5d1fb28d2b64cb761065c2339be947e3165a9664 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 3 Oct 2020 08:25:17 -0400 Subject: [PATCH 061/206] Working on test_qra6[45].f90. --- CMakeLists.txt | 3 + lib/test_qra64.f90 | 134 +++++++++++++++++++++++++++++++++++++++++++++ lib/test_qra65.f90 | 26 +++++---- 3 files changed, 152 insertions(+), 11 deletions(-) create mode 100644 lib/test_qra64.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 712e176ad..95a8cfb57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1338,6 +1338,9 @@ target_link_libraries (qra64sim wsjt_fort wsjt_cxx) add_executable (qra65sim lib/qra/qra65/qra65sim.f90 wsjtx.rc) target_link_libraries (qra65sim wsjt_fort wsjt_cxx) +add_executable (test_qra64 lib/test_qra64.f90 wsjtx.rc) +target_link_libraries (test_qra64 wsjt_fort wsjt_cxx) + add_executable (test_qra65 lib/test_qra65.f90 wsjtx.rc) target_link_libraries (test_qra65 wsjt_fort wsjt_cxx) diff --git a/lib/test_qra64.f90 b/lib/test_qra64.f90 new file mode 100644 index 000000000..751a9e9a4 --- /dev/null +++ b/lib/test_qra64.f90 @@ -0,0 +1,134 @@ +program test_qra64 + + character*71 cmd1,cmd2,line + character*22 msg + character*8 arg + character*1 csubmode + integer nretcode(0:11) + logical decok + + nargs=iargc() + if(nargs.ne.9) then + print*,'Usage: test_qra64 "msg" A-D depth freq DT fDop TRp nfiles SNR' + print*,'Example: test_qra64 "K1ABC W9XYZ EN37" A 3 1000 0.0 5.0 60 100 -20' + print*,' SNR = 0 to loop over all relevant SNRs' + go to 999 + endif + call getarg(1,msg) + call getarg(2,csubmode) + call getarg(3,arg) + read(arg,*) ndepth + call getarg(4,arg) + read(arg,*) nf0 + call getarg(5,arg) + read(arg,*) dt + call getarg(6,arg) + read(arg,*) fDop + call getarg(7,arg) + read(arg,*) ntrperiod + call getarg(8,arg) + read(arg,*) nfiles + call getarg(9,arg) + read(arg,*) nsnr + + nsps=7680 + i50=-28 + ia=-20 + ib=-33 + if(nsnr.ne.0) then + ia=nsnr + ib=nsnr + endif + + baud=12000.0/nsps + tsym=1.0/baud + +! 1 2 3 4 5 6 7 +! 12345678901234567890123456789012345678901234567890123456789012345678901' + cmd1='qra64sim "K1ABC W9XYZ EN37 " A 1 0.2 0.00 100 -20 > junk0' + + cmd2='jt9 -q -L 300 -H 3000 -f 1000 -d 3 -b A *.wav > junk' +! jt9 -q -L 300 -H 3000 -f 1000 -d 3 -b A *.w1000 unk + + write(cmd1(10:33),'(a)') '"'//msg//'"' + cmd1(35:35)=csubmode + write(cmd1(40:43),'(f4.1)') fDop + write(cmd1(44:48),'(f5.2)') dt + write(cmd1(49:53),'(i5)') nfiles + + write(cmd2(26:29),'(i4)') nf0 + write(cmd2(34:34),'(i1)') ndepth + cmd2(39:39)=csubmode + + call system('rm -f *.wav') + + write(*,1000) (j,j=0,11) + write(12,1000) (j,j=0,11) +1000 format(/'SNR d Dop Sync Dec1 DecN Bad',i6,11i4,' tdec dtavg dtrms'/97('-')) + + dterr=tsym/4.0 + nferr=max(1,nint(0.5*baud)) + + do nsnr=ia,ib,-1 + nsync=0 + ndecodes=0 + nfalse=0 + nretcode=0 + navg=0 + sumxdt=0. + sqxdt=0. + write(cmd1(55:57),'(i3)') nsnr + call system(cmd1) + call sec0(0,tdec) + call system(cmd2) + call sec0(1,tdec) + open(10,file='junk',status='unknown') + n=0 + do iline=1,9999 + read(10,'(a71)',end=10) line + if(index(line,' Date: Sat, 3 Oct 2020 11:02:18 -0400 Subject: [PATCH 062/206] Tweak test_qra64.f90 --- lib/test_qra64.f90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/test_qra64.f90 b/lib/test_qra64.f90 index 751a9e9a4..c16abde2f 100644 --- a/lib/test_qra64.f90 +++ b/lib/test_qra64.f90 @@ -33,7 +33,7 @@ program test_qra64 nsps=7680 i50=-28 - ia=-20 + ia=-24 ib=-33 if(nsnr.ne.0) then ia=nsnr @@ -48,7 +48,6 @@ program test_qra64 cmd1='qra64sim "K1ABC W9XYZ EN37 " A 1 0.2 0.00 100 -20 > junk0' cmd2='jt9 -q -L 300 -H 3000 -f 1000 -d 3 -b A *.wav > junk' -! jt9 -q -L 300 -H 3000 -f 1000 -d 3 -b A *.w1000 unk write(cmd1(10:33),'(a)') '"'//msg//'"' cmd1(35:35)=csubmode From 95ec019da3bca7add7b5cb1f18a75797c2290aa4 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 4 Oct 2020 12:29:18 -0400 Subject: [PATCH 063/206] Improvements to test_qra64.# Please enter the commit message for your changes. Lines starting --- lib/test_qra64.f90 | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/lib/test_qra64.f90 b/lib/test_qra64.f90 index c16abde2f..f816244a3 100644 --- a/lib/test_qra64.f90 +++ b/lib/test_qra64.f90 @@ -33,7 +33,7 @@ program test_qra64 nsps=7680 i50=-28 - ia=-24 + ia=-20 ib=-33 if(nsnr.ne.0) then ia=nsnr @@ -63,19 +63,17 @@ program test_qra64 write(*,1000) (j,j=0,11) write(12,1000) (j,j=0,11) -1000 format(/'SNR d Dop Sync Dec1 DecN Bad',i6,11i4,' tdec dtavg dtrms'/97('-')) +1000 format(/'SNR d Dop Sync Dec Bad',i6,11i4,' tdec'/80('-')) dterr=tsym/4.0 - nferr=max(1,nint(0.5*baud)) + nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) + ndecodes0=nfiles do nsnr=ia,ib,-1 nsync=0 ndecodes=0 nfalse=0 nretcode=0 - navg=0 - sumxdt=0. - sqxdt=0. write(cmd1(55:57),'(i3)') nsnr call system(cmd1) call sec0(0,tdec) @@ -89,17 +87,15 @@ program test_qra64 read(line(11:20),*) xdt,nf irc=-1 if(line(23:23).ne.' ') read(line(45:46),*) irc -! write(71,3071) dt,xdt,abs(xdt-dt),dterr,nf0,nf,abs(nf-nf0),nferr,irc -!3071 format(4f6.2,4i5,i8) - if(abs(xdt-dt).le.dterr .and. abs(nf-nf0).le.nferr) nsync=nsync+1 - if(irc.lt.0) cycle decok=index(line,'W9XYZ').gt.0 + if((abs(xdt-dt).le.dterr .and. abs(nf-nf0).le.nferr) .or. decok) then + nsync=nsync+1 + endif + if(irc.lt.0) cycle if(decok) then i=irc if(i.le.11) then ndecodes=ndecodes + 1 - sumxdt=sumxdt + xdt - sqxdt=sqxdt + xdt*xdt navg=navg + 1 else i=mod(i,10) @@ -110,22 +106,24 @@ program test_qra64 nfalse=nfalse + 1 print*,'False: ',line endif - enddo + enddo ! iline 10 close(10) - xdt_avg=0. - xdt_rms=0. - if(ndecodes.ge.2) then - xdt_avg=sumxdt/ndecodes - xdt_rms=sqxdt/(ndecodes-1) - xdt_avg*xdt_avg + write(*,1100) nsnr,ndepth,fDop,nsync,ndecodes,nfalse,nretcode, & + tdec/nfiles + write(12,1100) nsnr,ndepth,fDop,nsync,ndecodes,nfalse,nretcode, & + tdec/nfiles +1100 format(i3,i2,f5.1,2i5,i4,i6,11i4,f6.2) + if(ndecodes.lt.nfiles/2 .and. ndecodes0.ge.nfiles/2) then + snr_thresh=nsnr + float(nfiles/2 - ndecodes)/(ndecodes0-ndecodes) + write(13,1200) ndepth,fdop,csubmode,snr_thresh +1200 format(i1,f6.1,2x,a1,f7.1) + flush(13) endif - write(*,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode, & - tdec/nfiles,xdt_avg,xdt_rms - write(12,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode, & - tdec/nfiles,xdt_avg,xdt_rms -1100 format(i3,i2,f5.1,3i5,i4,i6,11i4,3f6.2) flush(6) flush(12) - enddo + if(ndecodes.eq.0) exit !Bail out if no decodes at this SNR + ndecodes0=ndecodes + enddo ! nsnr 999 end program test_qra64 From 20fb18c8ae1af9ed085efc9bb5824aaf03cab332 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 4 Oct 2020 15:22:45 -0400 Subject: [PATCH 064/206] Minor code cleanup. --- lib/sync64.f90 | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/sync64.f90 b/lib/sync64.f90 index d927af9c9..f6d438e32 100644 --- a/lib/sync64.f90 +++ b/lib/sync64.f90 @@ -5,14 +5,14 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & parameter (NMAX=60*12000) !Max size of raw data at 12000 Hz parameter (NSPS=3456) !Samples per symbol at 6000 Hz - parameter (NSPC=7*NSPS) !Samples per Costas array + parameter (NSPC=7*NSPS) !Samples per Costas waveform real s1(0:NSPC-1) !Power spectrum of Costas 1 real s2(0:NSPC-1) !Power spectrum of Costas 2 real s3(0:NSPC-1) !Power spectrum of Costas 3 real s0(0:NSPC-1) !Sum of s1+s2+s3 real s0a(0:NSPC-1) !Best synchromized spectrum (saved) real s0b(0:NSPC-1) !tmp - real a(5) + real a(5) !Parameters of Lorentzian fit integer icos7(0:6) !Costas 7x7 tones integer ipk0(1) complex cc(0:NSPC-1) !Costas waveform @@ -25,11 +25,12 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & save if(mode64.ne.mode64z) then +! Submode has changed, recompute the complex Costas waveform twopi=8.0*atan(1.0) dfgen=mode64*12000.0/6912.0 k=-1 phi=0. - do j=0,6 !Compute complex Costas waveform + do j=0,6 dphi=twopi*10.0*icos7(j)*dfgen/6000.0 do i=1,NSPS phi=phi + dphi @@ -42,7 +43,6 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & endif nfft3=NSPC - nh3=nfft3/2 df3=6000.0/nfft3 fa=max(nf1,nfqso-ntol) @@ -61,7 +61,7 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & smaxall=0. jpk=0 ja=0 - jb=(5.0+emedelay)*6000 + jb=(5.0+emedelay)*6000 !Bigger range than necessary? jstep=100 ipk=0 kpk=0 @@ -69,7 +69,7 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & if(mod(nadd,2).eq.0) nadd=nadd+1 !Make nadd odd nskip=max(49,nadd) - do j1=ja,jb,jstep + do j1=ja,jb,jstep !Loop over DT call timer('sync64_1',0) j2=j1 + 39*NSPS j3=j1 + 77*NSPS @@ -95,7 +95,7 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & s0(ia:ib)=s1(ia:ib) + s2(ia:ib) + s3(ia:ib) s0(:ia-1)=0. s0(ib+1:)=0. - if(nadd.ge.3) then + if(nadd.ge.3) then !Smooth the spectrum do ii=1,3 s0b(ia:ib)=s0(ia:ib) call smo(s0b(ia:ib),iz,s0(ia:ib),nadd) @@ -114,7 +114,7 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & f0=ip*df3 endif call timer('sync64_2',1) - enddo + enddo ! j1 (DT loop) s0a=s0a+2.0 ! write(17) ia,ib,s0a(ia:ib) !Save data for red curve @@ -141,7 +141,6 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & rewind 17 write(17,1110) 0.0,0.0 rewind 17 -! rewind 76 do i=2,iz-2*nskip-1,3 x=i z=(x-a(3))/(0.5*a(4)) @@ -155,11 +154,9 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & ss=(s0a(j-1)+s0a(j)+s0a(j+1))/3.0 if(ss.gt.slimit) write(17,1110) freq,ss 1110 format(3f10.3) -! write(76,1110) freq,ss,yfit enddo flush(17) close(17) -! flush(76) return end subroutine sync64 From 333fac1fae7778064113697c57a5bc7c6c5b8219 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 4 Oct 2020 15:32:08 -0400 Subject: [PATCH 065/206] Code cleanup. --- lib/lorentzian.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/lorentzian.f90 b/lib/lorentzian.f90 index cd2257a75..f3f4e14ef 100644 --- a/lib/lorentzian.f90 +++ b/lib/lorentzian.f90 @@ -1,7 +1,7 @@ subroutine lorentzian(y,npts,a) ! Input: y(npts); assume x(i)=i, i=1,npts -! Output: a(5) +! Output: a(1:5) ! a(1) = baseline ! a(2) = amplitude ! a(3) = x0 From df034cf9b51ca622edbec81d12615fd72aec445b Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 4 Oct 2020 16:10:44 -0400 Subject: [PATCH 066/206] Don't set TxFreq and RxFreq defaults on QRA64 startup. --- widgets/mainwindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index df2117292..2def05a2d 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6316,8 +6316,8 @@ void MainWindow::on_actionQRA64_triggered() ui->sbSubmode->setValue(m_nSubMode); ui->actionInclude_averaging->setVisible (false); ui->actionInclude_correlation->setVisible (false); - ui->RxFreqSpinBox->setValue(1000); - ui->TxFreqSpinBox->setValue(1000); +// ui->RxFreqSpinBox->setValue(1000); +// ui->TxFreqSpinBox->setValue(1000); QString fname {QDir::toNativeSeparators(m_config.temp_dir ().absoluteFilePath ("red.dat"))}; m_wideGraph->setRedFile(fname); displayWidgets(nWidgets("1111100100101101100000000010000000")); From c17acdb4474e45b958755c3ec9d54ac355740074 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 5 Oct 2020 09:48:44 -0400 Subject: [PATCH 067/206] Activate Fast and Normal decode options for QRA64. --- widgets/mainwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 2def05a2d..60b3bf1ae 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6320,7 +6320,8 @@ void MainWindow::on_actionQRA64_triggered() // ui->TxFreqSpinBox->setValue(1000); QString fname {QDir::toNativeSeparators(m_config.temp_dir ().absoluteFilePath ("red.dat"))}; m_wideGraph->setRedFile(fname); - displayWidgets(nWidgets("1111100100101101100000000010000000")); +// 0123456789012345678901234567890123 + displayWidgets(nWidgets("1111100100101101100100000010000000")); statusChanged(); } From f38f355395886f03286e0f9ffc6b6a8b40649e6e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 5 Oct 2020 09:50:55 -0400 Subject: [PATCH 068/206] Many tweaks to QRA64 decoder to optimize processing of 6m ionoscatter signals. --- lib/qra64a.f90 | 69 +++++++++++++++++++++++++++---------------- lib/sync64.f90 | 14 +++++---- widgets/mainwindow.ui | 2 +- 3 files changed, 53 insertions(+), 32 deletions(-) diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index 5d314f2b4..12198ad44 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -12,7 +12,7 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & logical ltext complex c00(0:720000) !Complex spectrum of dd() complex c0(0:720000) !Complex data for dd() - real a(3) + real a(3) !twkfreq params f,f1,f2 real dd(NMAX) !Raw data sampled at 12000 Hz real s3(LN) !Symbol spectra real s3a(LN) !Symbol spectra @@ -62,39 +62,49 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & npts2=npts/2 call timer('sync64 ',0) - call sync64(c00,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk0,sync, & - sync2,width) + 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.ge.0 .and. (sync-7.0).lt.minsync) go to 900 -! if((sync-3.4).lt.float(minsync) .or.width.gt.340.0) go to 900 - a=0. - a(1)=-f0 - call twkfreq(c00,c0,npts2,6000.0,a) + if(mode64.eq.1 .and. minsync.ne.-1 .and. (sync-7.0).lt.minsync) go to 900 irc=-99 s3lim=20. - itz=11 - if(mode64.eq.4) itz=9 - if(mode64.eq.2) itz=7 - if(mode64.eq.1) itz=5 - + ibwmax=11 + if(mode64.le.4) ibwmax=9 + ibwmin=0 + idtmax=5 + if(minsync.eq.-2) then + ibwmin=ibwmax + idtmax=3 + endif LL=64*(mode64+2) NN=63 napmin=99 - do itry0=1,5 - idt=itry0/2 - if(mod(itry0,2).eq.0) idt=-idt + ncall=0 + + do idf0=1,11 + idf=idf0/2 + if(mod(idf0,2).eq.0) idf=-idf + + a=0. + a(1)=-(f0+0.868*idf) + call twkfreq(c00,c0,npts2,6000.0,a) + + do idt0=1,idtmax + idt=idt0/2 + if(mod(idt0,2).eq.0) idt=-idt jpk=jpk0 + 750*idt call spec64(c0,jpk,s3a,LL,NN) call pctile(s3a,LL*NN,40,base) s3a=s3a/base where(s3a(1:LL*NN)>s3lim) s3a(1:LL*NN)=s3lim - do iter=itz,0,-2 - b90=1.728**iter + do ibw=ibwmax,ibwmin,-2 + b90=1.728**ibw if(b90.gt.230.0) cycle if(b90.lt.0.15*width) exit s3(1:LL*NN)=s3a(1:LL*NN) + ncall=ncall+1 call timer('qra64_de',0) call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & nFadingModel,dat4,snr2,irc) @@ -109,21 +119,27 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & napmin=nap(iirc) irckeep=irc dtxkeep=jpk/6000.0 - 1.0 - itry0keep=itry0 - iterkeep=iter + f0keep=-a(1) + idfkeep=idf + idtkeep=idt + ibwkeep=ibw endif enddo - if(irc.eq.0) exit - enddo + if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 + if(irc.eq.0) go to 100 + enddo ! idt (DT loop) + enddo ! idf (f0 loop) - if(napmin.ne.99) then +100 if(napmin.ne.99) then dat4=dat4x b90=b90x snr2=snr2x irc=irckeep dtx=dtxkeep - itry0=itry0keep - iter=iterkeep + f0=f0keep + idt=idtkeep + idf=idfkeep + ibw=ibwkeep endif 10 decoded=' ' @@ -140,6 +156,9 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & else snr2=0. endif + nfreq=nint(f0) + write(71,3071) idf,idt,ncall,irc,nsnr,dtx,nfreq,decoded +3071 format(5i5,f7.2,i6,2x,a22) 900 if(irc.lt.0) then sy=max(1.0,sync) diff --git a/lib/sync64.f90 b/lib/sync64.f90 index f6d438e32..e95814303 100644 --- a/lib/sync64.f90 +++ b/lib/sync64.f90 @@ -1,5 +1,5 @@ -subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & - sync2,width) +subroutine sync64(c0,nf1,nf2,nfqso,ntol,minsync,mode64,emedelay,dtx,f0, & + jpk,sync,sync2,width) use timer_module, only: timer @@ -61,11 +61,13 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & smaxall=0. jpk=0 ja=0 - jb=(5.0+emedelay)*6000 !Bigger range than necessary? +! jb=(5.0+emedelay)*6000 !Bigger range than necessary? + jb=(2.0+emedelay)*6000 !Bigger range than necessary? jstep=100 ipk=0 kpk=0 nadd=10*mode64 + if(minsync.eq.-2) nadd=10 !### if(mod(nadd,2).eq.0) nadd=nadd+1 !Make nadd odd nskip=max(49,nadd) @@ -96,7 +98,9 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & s0(:ia-1)=0. s0(ib+1:)=0. if(nadd.ge.3) then !Smooth the spectrum - do ii=1,3 + iiz=3 + if(minsync.eq.-2) iiz=1 + do ii=1,iiz !### Was ii=1,3 s0b(ia:ib)=s0(ia:ib) call smo(s0b(ia:ib),iz,s0(ia:ib),nadd) enddo @@ -117,8 +121,6 @@ subroutine sync64(c0,nf1,nf2,nfqso,ntol,mode64,emedelay,dtx,f0,jpk,sync, & enddo ! j1 (DT loop) s0a=s0a+2.0 -! write(17) ia,ib,s0a(ia:ib) !Save data for red curve -! close(17) nskip=50 call lorentzian(s0a(ia+nskip:ib-nskip),iz-2*nskip,a) diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 33ffd38ca..f65b50480 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -799,7 +799,7 @@ QPushButton[state="ok"] { Sync - -1 + -2 10 From 69f7cea5e65270bf9f6efdc26868a4561ebea233 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 6 Oct 2020 10:29:03 -0400 Subject: [PATCH 069/206] Formatting adjustments to qra64a.f90; updates to test_qra6[45].f90. --- lib/qra64a.f90 | 84 +++++++++++++++++++++++----------------------- lib/test_qra64.f90 | 2 -- lib/test_qra65.f90 | 41 +++++++++++----------- 3 files changed, 64 insertions(+), 63 deletions(-) diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index 12198ad44..f880b6ab0 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -84,50 +84,50 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & ncall=0 do idf0=1,11 - idf=idf0/2 - if(mod(idf0,2).eq.0) idf=-idf + idf=idf0/2 + if(mod(idf0,2).eq.0) idf=-idf - a=0. - a(1)=-(f0+0.868*idf) - call twkfreq(c00,c0,npts2,6000.0,a) + a=0. + a(1)=-(f0+0.868*idf) + call twkfreq(c00,c0,npts2,6000.0,a) - do idt0=1,idtmax - idt=idt0/2 - if(mod(idt0,2).eq.0) idt=-idt - jpk=jpk0 + 750*idt - call spec64(c0,jpk,s3a,LL,NN) - call pctile(s3a,LL*NN,40,base) - s3a=s3a/base - where(s3a(1:LL*NN)>s3lim) s3a(1:LL*NN)=s3lim - do ibw=ibwmax,ibwmin,-2 - b90=1.728**ibw - if(b90.gt.230.0) cycle - if(b90.lt.0.15*width) exit - s3(1:LL*NN)=s3a(1:LL*NN) - ncall=ncall+1 - call timer('qra64_de',0) - call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & - nFadingModel,dat4,snr2,irc) - call timer('qra64_de',1) - if(irc.eq.0) go to 10 - if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) - iirc=max(0,min(irc,11)) - if(irc.gt.0 .and. nap(iirc).lt.napmin) then - dat4x=dat4 - b90x=b90 - snr2x=snr2 - napmin=nap(iirc) - irckeep=irc - dtxkeep=jpk/6000.0 - 1.0 - f0keep=-a(1) - idfkeep=idf - idtkeep=idt - ibwkeep=ibw - endif - enddo - if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 - if(irc.eq.0) go to 100 - enddo ! idt (DT loop) + do idt0=1,idtmax + idt=idt0/2 + if(mod(idt0,2).eq.0) idt=-idt + jpk=jpk0 + 750*idt + call spec64(c0,jpk,s3a,LL,NN) + call pctile(s3a,LL*NN,40,base) + s3a=s3a/base + where(s3a(1:LL*NN)>s3lim) s3a(1:LL*NN)=s3lim + do ibw=ibwmax,ibwmin,-2 + b90=1.728**ibw + if(b90.gt.230.0) cycle + if(b90.lt.0.15*width) exit + s3(1:LL*NN)=s3a(1:LL*NN) + ncall=ncall+1 + call timer('qra64_de',0) + call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & + nFadingModel,dat4,snr2,irc) + call timer('qra64_de',1) + if(irc.eq.0) go to 10 + if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) + iirc=max(0,min(irc,11)) + if(irc.gt.0 .and. nap(iirc).lt.napmin) then + dat4x=dat4 + b90x=b90 + snr2x=snr2 + napmin=nap(iirc) + irckeep=irc + dtxkeep=jpk/6000.0 - 1.0 + f0keep=-a(1) + idfkeep=idf + idtkeep=idt + ibwkeep=ibw + endif + enddo ! ibw (b90 loop) + if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 + if(irc.eq.0) go to 100 + enddo ! idt (DT loop) enddo ! idf (f0 loop) 100 if(napmin.ne.99) then diff --git a/lib/test_qra64.f90 b/lib/test_qra64.f90 index f816244a3..760c87452 100644 --- a/lib/test_qra64.f90 +++ b/lib/test_qra64.f90 @@ -96,10 +96,8 @@ program test_qra64 i=irc if(i.le.11) then ndecodes=ndecodes + 1 - navg=navg + 1 else i=mod(i,10) - navg=navg + 1 endif nretcode(i)=nretcode(i) + 1 else diff --git a/lib/test_qra65.f90 b/lib/test_qra65.f90 index 30e2c0d9f..76056cef8 100644 --- a/lib/test_qra65.f90 +++ b/lib/test_qra65.f90 @@ -80,8 +80,9 @@ program test_qra65 write(12,1000) (j,j=0,11) 1000 format(/'SNR d Dop Sync Dec1 DecN Bad',i6,11i4,' tdec dtavg dtrms'/97('-')) - dterr=3.0*tsym/4.0 - nferr=max(1,nint(0.5*baud)) + dterr=tsym/4.0 + nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) + ndecodes0=nfiles do nsnr=ia,ib,-1 nsync=0 @@ -89,8 +90,6 @@ program test_qra65 nfalse=0 nretcode=0 navg=0 - sumxdt=0. - sqxdt=0. write(cmd1(61:63),'(i3)') nsnr call system(cmd1) call sec0(0,tdec) @@ -100,19 +99,20 @@ program test_qra65 n=0 do iline=1,9999 read(10,'(a71)',end=10) line - if(len(trim(line)).lt.60) cycle + if(index(line,' Date: Tue, 6 Oct 2020 10:45:30 -0400 Subject: [PATCH 070/206] Add tentative 6m frequencies for QRA64 and QRA65. --- models/FrequencyList.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp index ec3c185ff..07b4d5a49 100644 --- a/models/FrequencyList.cpp +++ b/models/FrequencyList.cpp @@ -262,6 +262,8 @@ namespace {28180000, Modes::FT4, IARURegions::ALL}, {50200000, Modes::Echo, IARURegions::ALL}, + {50270000, Modes::QRA64, IARURegions::ALL}, + {50270000, Modes::QRA65, IARURegions::ALL}, {50276000, Modes::JT65, IARURegions::R2}, {50276000, Modes::JT65, IARURegions::R3}, {50380000, Modes::MSK144, IARURegions::R1}, From db1a24f1d4ccdec5cd7da89bf8fe52e6af99c334 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 6 Oct 2020 11:07:08 -0400 Subject: [PATCH 071/206] Update WideGraph parameters when entering QRA64 mode. --- widgets/mainwindow.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 60b3bf1ae..ed47afbfb 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6320,6 +6320,13 @@ void MainWindow::on_actionQRA64_triggered() // ui->TxFreqSpinBox->setValue(1000); QString fname {QDir::toNativeSeparators(m_config.temp_dir ().absoluteFilePath ("red.dat"))}; m_wideGraph->setRedFile(fname); + m_wideGraph->setMode(m_mode); + m_wideGraph->setModeTx(m_modeTx); + m_wideGraph->setPeriod(m_TRperiod,6912); + m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); + m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); + m_wideGraph->setTol(ui->sbFtol->value()); + switch_mode (Modes::FST4); // 0123456789012345678901234567890123 displayWidgets(nWidgets("1111100100101101100100000010000000")); statusChanged(); From 6e75a62811c75a00d607426f6169ad559b791bb0 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Tue, 6 Oct 2020 18:38:18 +0100 Subject: [PATCH 072/206] Correct mode switching for QRA64 and QRA65 --- widgets/mainwindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index ed47afbfb..ff9be4ec4 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6326,7 +6326,7 @@ void MainWindow::on_actionQRA64_triggered() m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); m_wideGraph->setTol(ui->sbFtol->value()); - switch_mode (Modes::FST4); + switch_mode (Modes::QRA64); // 0123456789012345678901234567890123 displayWidgets(nWidgets("1111100100101101100100000010000000")); statusChanged(); @@ -6354,6 +6354,7 @@ void MainWindow::on_actionQRA65_triggered() m_wideGraph->setTol(ui->sbFtol->value()); m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); + switch_mode (Modes::QRA65); // 0123456789012345678901234567890123 displayWidgets(nWidgets("1111110101101101000100000011000000")); statusChanged(); From bb8e6ea64ae36641da3426cb1c4afea7bf86a7ba Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Tue, 6 Oct 2020 19:55:43 +0100 Subject: [PATCH 073/206] Missed merge from develop branch conflict resolved --- widgets/mainwindow.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index b30b2043b..d211cbc1a 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -3046,27 +3046,6 @@ void MainWindow::decode() //decode() dec_data.params.nutc=dec_data.params.nutc/100; } if(dec_data.params.nagain==0 && dec_data.params.newdat==1 && (!m_diskData)) { -<<<<<<< HEAD - qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - int imin=ms/60000; - int ihr=imin/60; - imin=imin % 60; - if(m_TRperiod>=60) imin=imin - (imin % (int(m_TRperiod)/60)); - dec_data.params.nutc=100*ihr + imin; - if(m_TRperiod < 60) { - qint64 ms=1000.0*(3.5-m_TRperiod); - if(m_mode=="FST4") ms=1000.0*(6.0-m_TRperiod); - //Adjust for FT8 early decode: - if(m_mode=="FT8" and m_ihsym==m_earlyDecode and !m_diskData) ms+=(m_hsymStop-m_earlyDecode)*288; - if(m_mode=="FT8" and m_ihsym==m_earlyDecode2 and !m_diskData) ms+=(m_hsymStop-m_earlyDecode2)*288; - QDateTime t=QDateTime::currentDateTimeUtc().addMSecs(ms); - ihr=t.toString("hh").toInt(); - imin=t.toString("mm").toInt(); - int isec=t.toString("ss").toInt(); - isec=isec - fmod(double(isec),m_TRperiod); - dec_data.params.nutc=10000*ihr + 100*imin + isec; - } -======= auto t_start = qt_truncate_date_time_to (QDateTime::currentDateTimeUtc (), m_TRperiod * 1.e3); auto t = t_start.time (); dec_data.params.nutc = t.hour () * 100 + t.minute (); @@ -3074,7 +3053,6 @@ void MainWindow::decode() //decode() { dec_data.params.nutc = dec_data.params.nutc * 100 + t.second (); } ->>>>>>> develop } if(m_nPick==1 and !m_diskData) { From 5e23f88f7e9a0a793ec9c7b93ed732a4c374d5c2 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 7 Oct 2020 16:04:00 -0400 Subject: [PATCH 074/206] Save a working temporary state for QRA64/QRA65 decoders. --- CMakeLists.txt | 1 + lib/qra64a.f90 | 88 +++----------------------------------- lib/qra_loops.f90 | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+), 82 deletions(-) create mode 100644 lib/qra_loops.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index d179f6da7..4d1246489 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -552,6 +552,7 @@ set (wsjt_FSRCS lib/prog_args.f90 lib/ps4.f90 lib/qra64a.f90 + lib/qra_loops.f90 lib/refspectrum.f90 lib/savec2.f90 lib/sec0.f90 diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index f880b6ab0..953a4789b 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -10,16 +10,10 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & character*6 mycall,hiscall,hisgrid_6 character*4 hisgrid logical ltext - complex c00(0:720000) !Complex spectrum of dd() - complex c0(0:720000) !Complex data for dd() - real a(3) !twkfreq params f,f1,f2 + complex c00(0:720000) !Analytic signal for dd() real dd(NMAX) !Raw data sampled at 12000 Hz real s3(LN) !Symbol spectra - real s3a(LN) !Symbol spectra integer dat4(12) !Decoded message (as 12 integers) - integer dat4x(12) - integer nap(0:11) - data nap/0,2,3,2,3,4,2,3,6,4,6,6/ data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ save @@ -59,7 +53,6 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & naptype=maxaptype call ana64(dd,npts,c00) - npts2=npts/2 call timer('sync64 ',0) call sync64(c00,nf1,nf2,nfqso,ntol,minsync,mode64,emedelay,dtx,f0, & @@ -68,81 +61,12 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & nfreq=nint(f0) if(mode64.eq.1 .and. minsync.ne.-1 .and. (sync-7.0).lt.minsync) go to 900 - irc=-99 - s3lim=20. - ibwmax=11 - if(mode64.le.4) ibwmax=9 - ibwmin=0 - idtmax=5 - if(minsync.eq.-2) then - ibwmin=ibwmax - idtmax=3 - endif - LL=64*(mode64+2) - NN=63 - napmin=99 - ncall=0 - - do idf0=1,11 - idf=idf0/2 - if(mod(idf0,2).eq.0) idf=-idf + call timer('qraloops',0) + call qra_loops(c00,npts/2,64,mode64,nsubmode,nFadingModel,minsync, & + ndepth,nc1,nc2,ng2,naptype,jpk0,dtx,f0,width,snr2,s3,irc,dat4) + call timer('qraloops',1) - a=0. - a(1)=-(f0+0.868*idf) - call twkfreq(c00,c0,npts2,6000.0,a) - - do idt0=1,idtmax - idt=idt0/2 - if(mod(idt0,2).eq.0) idt=-idt - jpk=jpk0 + 750*idt - call spec64(c0,jpk,s3a,LL,NN) - call pctile(s3a,LL*NN,40,base) - s3a=s3a/base - where(s3a(1:LL*NN)>s3lim) s3a(1:LL*NN)=s3lim - do ibw=ibwmax,ibwmin,-2 - b90=1.728**ibw - if(b90.gt.230.0) cycle - if(b90.lt.0.15*width) exit - s3(1:LL*NN)=s3a(1:LL*NN) - ncall=ncall+1 - call timer('qra64_de',0) - call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & - nFadingModel,dat4,snr2,irc) - call timer('qra64_de',1) - if(irc.eq.0) go to 10 - if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) - iirc=max(0,min(irc,11)) - if(irc.gt.0 .and. nap(iirc).lt.napmin) then - dat4x=dat4 - b90x=b90 - snr2x=snr2 - napmin=nap(iirc) - irckeep=irc - dtxkeep=jpk/6000.0 - 1.0 - f0keep=-a(1) - idfkeep=idf - idtkeep=idt - ibwkeep=ibw - endif - enddo ! ibw (b90 loop) - if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 - if(irc.eq.0) go to 100 - enddo ! idt (DT loop) - enddo ! idf (f0 loop) - -100 if(napmin.ne.99) then - dat4=dat4x - b90=b90x - snr2=snr2x - irc=irckeep - dtx=dtxkeep - f0=f0keep - idt=idtkeep - idf=idfkeep - ibw=ibwkeep - endif -10 decoded=' ' - + decoded=' ' if(irc.ge.0) then call unpackmsg(dat4,decoded) !Unpack the user message call fmtmsg(decoded,iz) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 new file mode 100644 index 000000000..e82b708dd --- /dev/null +++ b/lib/qra_loops.f90 @@ -0,0 +1,105 @@ +subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & + ndepth,nc1,nc2,ng2,naptype,jpk0,dtx,f0,width,snr2,s3,irc,dat4) + + use timer_module, only: timer + parameter (LN=1152*63) + complex c00(0:720000) !Analytic representation of dd(), 6000 Hz + complex c0(0:720000) !Ditto, with freq shift + real a(3) !twkfreq params f,f1,f2 + real s3(LN),s3a(LN) !Symbol spectra + integer dat4(12),dat4x(12) !Decoded message (as 12 integers) + integer nap(0:11) !AP return codes + data nap/0,2,3,2,3,4,2,3,6,4,6,6/ +! save + + irc=-99 + s3lim=20. + ibwmax=11 + if(mode64.le.4) ibwmax=9 + ibwmin=0 + idtmax=5 + if(minsync.eq.-2) then + ibwmin=ibwmax + idtmax=3 + endif + LL=64*(mode64+2) + NN=63 + napmin=99 + ncall=0 + + do idf0=1,11 + idf=idf0/2 + if(mod(idf0,2).eq.0) idf=-idf + a=0. + a(1)=-(f0+0.868*idf) + call twkfreq(c00,c0,npts2,6000.0,a) + do idt0=1,idtmax + idt=idt0/2 + if(mod(idt0,2).eq.0) idt=-idt + jpk=jpk0 + 750*idt + if(mode.eq.64) then + call spec64(c0,jpk,s3a,LL,NN) + else + if(jpk.lt.0) jpk=0 + call timer('spec_q65',0) + call spec_qra65(c0(jpk:),nsps2,s3,LL,NN) !Get synced symbol spectra + call timer('spec_q65',1) +! do j=1,63 !Normalize to symbol baseline +! call pctile(s3(:,j),LL,40,base) +! s3(:,j)=s3(:,j)/base +! enddo +! LL2=64*(mode65+1)-1 +! s3max=20.0 +! do j=1,63 !Apply AGC to suppress pings +! xx=maxval(s3(-64:LL2,j)) +! if(xx.gt.s3max) s3(-64:LL2,j)=s3(-64:LL2,j)*s3max/xx +! enddo + endif + call pctile(s3a,LL*NN,40,base) + s3a=s3a/base + where(s3a(1:LL*NN)>s3lim) s3a(1:LL*NN)=s3lim + do ibw=ibwmax,ibwmin,-2 + b90=1.728**ibw + if(b90.gt.230.0) cycle + if(b90.lt.0.15*width) exit + s3(1:LL*NN)=s3a(1:LL*NN) + ncall=ncall+1 + call timer('qra64_de',0) + call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & + nFadingModel,dat4,snr2,irc) + call timer('qra64_de',1) + if(irc.eq.0) go to 200 + if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) + iirc=max(0,min(irc,11)) + if(irc.gt.0 .and. nap(iirc).lt.napmin) then + dat4x=dat4 + b90x=b90 + snr2x=snr2 + napmin=nap(iirc) + irckeep=irc + dtxkeep=jpk/6000.0 - 1.0 + f0keep=-a(1) + idfkeep=idf + idtkeep=idt + ibwkeep=ibw + endif + enddo ! ibw (b90 loop) + if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 + if(irc.eq.0) go to 100 + enddo ! idt (DT loop) + enddo ! idf (f0 loop) + +100 if(napmin.ne.99) then + dat4=dat4x + b90=b90x + snr2=snr2x + irc=irckeep + dtx=dtxkeep + f0=f0keep + idt=idtkeep + idf=idfkeep + ibw=ibwkeep + endif + +200 return +end subroutine qra_loops From c5502cda05fcb37c67ad9886725f182087447021 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 8 Oct 2020 16:48:11 -0400 Subject: [PATCH 075/206] QRA65 now decodes using qra_loops() -- the same inner loops as QRA64. Very effective! --- CMakeLists.txt | 5 +- lib/ana64.f90 | 5 +- lib/qra64a.f90 | 2 - lib/qra65_decode.f90 | 139 +++++++++++++++---------------------------- lib/qra_loops.f90 | 31 +++------- lib/spec64.f90 | 67 ++++++++++++++++----- 6 files changed, 112 insertions(+), 137 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d1246489..8ff8f0ebf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -570,7 +570,6 @@ set (wsjt_FSRCS lib/softsym9w.f90 lib/shell.f90 lib/spec64.f90 - lib/spec_qra65.f90 lib/spec9f.f90 lib/stdmsg.f90 lib/subtract65.f90 @@ -1317,7 +1316,7 @@ if (${OPENMP_FOUND} OR APPLE) endif (APPLE) if (WIN32) set_target_properties (jt9 PROPERTIES - LINK_FLAGS -Wl,--stack,16777216 + LINK_FLAGS -Wl,--stack,28000000 ) endif () target_link_libraries (jt9 wsjt_fort_omp wsjt_cxx fort_qt) @@ -1454,7 +1453,7 @@ else () ) if (WIN32) set_target_properties (wsjtx PROPERTIES - LINK_FLAGS -Wl,--stack,16777216 + LINK_FLAGS -Wl,--stack,28000000 ) endif () endif () diff --git a/lib/ana64.f90 b/lib/ana64.f90 index 5681ee176..faebb84e5 100644 --- a/lib/ana64.f90 +++ b/lib/ana64.f90 @@ -3,13 +3,12 @@ subroutine ana64(dd,npts,c0) use timer_module, only: timer parameter (NMAX=60*12000) !Max size of raw data at 12000 Hz - parameter (NSPS=3456) !Samples per symbol at 6000 Hz - parameter (NSPC=7*NSPS) !Samples per Costas array real dd(NMAX) !Raw data complex c0(0:720000) !Complex spectrum of dd() save - nfft1=672000 +! nfft1=672000 + nfft1=720000 nfft2=nfft1/2 df1=12000.0/nfft1 fac=2.0/nfft1 diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index 953a4789b..e5da55afd 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -81,8 +81,6 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & snr2=0. endif nfreq=nint(f0) - write(71,3071) idf,idt,ncall,irc,nsnr,dtx,nfreq,decoded -3071 format(5i5,f7.2,i6,2x,a22) 900 if(irc.lt.0) then sy=max(1.0,sync) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index 0f04565f7..d377a6d11 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -41,18 +41,20 @@ contains character(len=6) :: hisgrid character*37 decoded integer*2 iwave(NMAX) !Raw data + real dd(NMAX) !Raw data integer dat4(12) logical lapdx,ltext + complex, allocatable :: c00(:) !Analytic signal, 6000 S/s complex, allocatable :: c0(:) !Analytic signal, 6000 S/s real, allocatable, save :: s3(:,:) !Symbol spectra real, allocatable, save :: s3a(:,:) !Symbol spectra for avg messages - real a(5) data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/,nsubmodez/-1/ save nc1z,nc2z,ng2z,maxaptypez,nsave,nsubmodez mode65=2**nsubmode nfft1=ntrperiod*12000 nfft2=ntrperiod*6000 + allocate (c00(0:nfft1-1)) allocate (c0(0:nfft1-1)) if(nsubmode.ne.nsubmodez) then @@ -74,106 +76,61 @@ contains nsps=41472 else stop 'Invalid TR period' - endif - baud=12000.0/nsps - df1=12000.0/nfft1 - -! do i=1,12000*ntrperiod -! write(61,3061) i/12000.0,iwave(i)/32767.0 -!3061 format(2f12.6) -! enddo - - this%callback => callback - - if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning + 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 ! Prime the QRA decoder for possible use of AP - 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 + 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 ! AP control could be done differently, but this works well: - maxaptype=0 - if(ndepth.eq.2) maxaptype=3 - if(ndepth.eq.3) maxaptype=5 + maxaptype=0 + if(ndepth.eq.2) maxaptype=3 + if(ndepth.eq.3) maxaptype=5 - 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(s3,nc1,nc2,ng2,naptype,1,nSubmode,b90, & - nFadingModel,dat4,snr2,irc) - enddo - nc1z=nc1 - nc2z=nc2 - ng2z=ng2 - maxaptypez=maxaptype - s3a=0. - nsave=0 - endif - naptype=maxaptype + 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(s3,nc1,nc2,ng2,naptype,1,nSubmode,b90, & + nFadingModel,dat4,snr2,irc) + enddo + nc1z=nc1 + nc2z=nc2 + ng2z=ng2 + maxaptypez=maxaptype + s3a=0. + nsave=0 + endif + naptype=maxaptype - call timer('sync_q65',0) - call sync_qra65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1) - call timer('sync_q65',1) + call timer('sync_q65',0) + call sync_qra65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1) + call timer('sync_q65',1) -! Downsample to give complex data at 6000 S/s - call timer('down_q65',0) - fac=2.0/nfft1 - c0=fac*iwave(1:nfft1) - call four2a(c0,nfft1,1,-1,1) !Forward c2c FFT - c0(nfft2/2+1:nfft2)=0. !Zero the top half - c0(0)=0.5*c0(0) - call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT - a=0. - a(1)=-(f0 + mode65*baud) !Data tones start mode65 bins higher - call twkfreq(c0,c0,ntrperiod*6000,6000.0,a) - call timer('down_q65',1) + jpk0=(xdt+1.0)*6000 !### + if(jpk0.lt.0) jpk0=0 - jpk=(xdt+0.5)*6000 - 384 !### Empirical ### - if(ntrperiod.ge.60) jpk=(xdt+1.0)*6000 - 384 !### TBD ??? ### - if(jpk.lt.0) jpk=0 - xdt=jpk/6000.0 - 0.5 - LL=64*(mode65+2) - NN=63 - call timer('spec_q65',0) - call spec_qra65(c0(jpk:),nsps/2,s3,LL,NN) !Compute synced symbol spectra - call timer('spec_q65',1) + fac=1.0/32767.0 + dd=fac*iwave +! npts=648000 + minsync=-2 + nmode=65 - do j=1,63 !Normalize to symbol baseline - call pctile(s3(:,j),LL,40,base) - s3(:,j)=s3(:,j)/base - enddo + call ana64(dd,npts,c00) - LL2=64*(mode65+1)-1 - s3max=20.0 - do j=1,63 !Apply AGC to suppress pings - xx=maxval(s3(-64:LL2,j)) - if(xx.gt.s3max) s3(-64:LL2,j)=s3(-64:LL2,j)*s3max/xx - enddo - -! Call Nico's QRA64 decoder - call timer('qra64_de',0) - call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & - nFadingModel,dat4,snr2,irc) - call timer('qra64_de',1) - - if(irc.lt.0) then -! No luck so far. Try for an average decode. - call timer('qra64_av',0) - s3a=s3a+s3 - nsave=nsave+1 - if(nsave.ge.2) then - call qra64_dec(s3a,nc1,nc2,ng2,naptype,0,nSubmode,b90, & - nFadingModel,dat4,snr2,irc) - if(irc.ge.0) irc=100*nsave + irc - endif - call timer('qra64_av',1) - endif - snr2=snr2 + db(6912.0/nsps) - if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) + call timer('qraloops',0) + call qra_loops(c00,npts/2,nmode,mode65,nsubmode,nFadingModel,minsync, & + ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,s3,irc,dat4) + if(nmode.eq.65) xdt=xdt+0.4 !### Empirical WHY ??? ### + call timer('qraloops',1) decoded=' ' if(irc.ge.0) then diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index e82b708dd..0ea261047 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -1,5 +1,5 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & - ndepth,nc1,nc2,ng2,naptype,jpk0,dtx,f0,width,snr2,s3,irc,dat4) + ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,s3,irc,dat4) use timer_module, only: timer parameter (LN=1152*63) @@ -10,7 +10,6 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & integer dat4(12),dat4x(12) !Decoded message (as 12 integers) integer nap(0:11) !AP return codes data nap/0,2,3,2,3,4,2,3,6,4,6,6/ -! save irc=-99 s3lim=20. @@ -26,6 +25,8 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & NN=63 napmin=99 ncall=0 + nsps=3456 !QRA64 + if(mode.eq.65) nsps=3840 !QRA65 do idf0=1,11 idf=idf0/2 @@ -36,25 +37,9 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & do idt0=1,idtmax idt=idt0/2 if(mod(idt0,2).eq.0) idt=-idt - jpk=jpk0 + 750*idt - if(mode.eq.64) then - call spec64(c0,jpk,s3a,LL,NN) - else - if(jpk.lt.0) jpk=0 - call timer('spec_q65',0) - call spec_qra65(c0(jpk:),nsps2,s3,LL,NN) !Get synced symbol spectra - call timer('spec_q65',1) -! do j=1,63 !Normalize to symbol baseline -! call pctile(s3(:,j),LL,40,base) -! s3(:,j)=s3(:,j)/base -! enddo -! LL2=64*(mode65+1)-1 -! s3max=20.0 -! do j=1,63 !Apply AGC to suppress pings -! xx=maxval(s3(-64:LL2,j)) -! if(xx.gt.s3max) s3(-64:LL2,j)=s3(-64:LL2,j)*s3max/xx -! enddo - endif + jpk=jpk0 + 750*idt + if(jpk.lt.0) jpk=0 + call spec64(c0,nsps,mode,jpk,s3a,LL,NN) call pctile(s3a,LL*NN,40,base) s3a=s3a/base where(s3a(1:LL*NN)>s3lim) s3a(1:LL*NN)=s3lim @@ -77,7 +62,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & snr2x=snr2 napmin=nap(iirc) irckeep=irc - dtxkeep=jpk/6000.0 - 1.0 + xdtkeep=jpk/6000.0 - 1.0 f0keep=-a(1) idfkeep=idf idtkeep=idt @@ -94,7 +79,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & b90=b90x snr2=snr2x irc=irckeep - dtx=dtxkeep + xdt=xdtkeep f0=f0keep idt=idtkeep idf=idfkeep diff --git a/lib/spec64.f90 b/lib/spec64.f90 index 3404243c4..377e8dfcf 100644 --- a/lib/spec64.f90 +++ b/lib/spec64.f90 @@ -1,26 +1,50 @@ -subroutine spec64(c0,jpk,s3,LL,NN) +subroutine spec64(c0,nsps,mode,jpk,s3,LL,NN) - parameter (NSPS=3456) !Samples per symbol at 6000 Hz + parameter (MAXFFT=3840) complex c0(0:360000) !Complex spectrum of dd() - complex cs(0:NSPS-1) !Complex symbol spectrum + complex cs(0:MAXFFT-1) !Complex symbol spectrum real s3(LL,NN) !Synchronized symbol spectra real xbase0(LL),xbase(LL) + integer isync(22) !Indices of sync symbols + 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 fac=1.0/nfft - 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)=fac*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 + + 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)=fac*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 enddo - 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)=fac*c0(ja:jb) + call four2a(cs,nsps,1,-1,1) !c2c FFT to frequency + do ii=1,LL + i=ii-65 + if(i.lt.0) i=i+nsps + s3(ii,j)=real(cs(i))**2 + aimag(cs(i))**2 + enddo + enddo + endif df=6000.0/nfft do i=1,LL @@ -38,5 +62,18 @@ subroutine spec64(c0,jpk,s3,LL,NN) s3(i,1:NN)=s3(i,1:NN)/(xbase(i)+0.001) !Apply frequency equalization enddo +! print*,'a',LL,NN,jpk +! df=6000.0/nfft +! do i=1,LL +! write(71,3071) i,i-65,i*df,(s3(i,j),j=1,4) +!3071 format(2i8,f10.3,4e12.3) +! enddo +! +! do j=1,NN +! write(72,3072) j,maxloc(s3(1:LL,j)),maxloc(s3(1:LL,j))-65 +!3072 format(3i8) +! enddo +! if(nfft.ne.-999) stop + return end subroutine spec64 From 8612398b020447be8a77b5d1d05653189fd122c9 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 9 Oct 2020 10:44:25 -0400 Subject: [PATCH 076/206] Minor tweaks to test_qra65. --- lib/test_qra65.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/test_qra65.f90 b/lib/test_qra65.f90 index 76056cef8..4a9881d9f 100644 --- a/lib/test_qra65.f90 +++ b/lib/test_qra65.f90 @@ -78,7 +78,7 @@ program test_qra65 write(*,1000) (j,j=0,11) write(12,1000) (j,j=0,11) -1000 format(/'SNR d Dop Sync Dec1 DecN Bad',i6,11i4,' tdec dtavg dtrms'/97('-')) +1000 format(/'SNR d Dop Sync Dec1 DecN Bad',i6,11i4,' tdec'/85('-')) dterr=tsym/4.0 nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) @@ -140,6 +140,7 @@ program test_qra65 endif flush(6) flush(12) + if(ndecodes.eq.0) exit !Bail out if no decodes at this SNR ndecodes0=ndecodes enddo ! nsnr From a4ba64a5fabeef7ccac0c00db11c61d8bf4bd467 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 9 Oct 2020 13:16:25 -0400 Subject: [PATCH 077/206] Code cleanup and documentation. --- lib/qra65_decode.f90 | 26 +++++++++++++++-------- lib/sync_qra65.f90 | 49 ++++++++++++++++++++------------------------ 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index d377a6d11..13ee12e1d 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -31,22 +31,32 @@ contains subroutine decode(this,callback,iwave,nutc,ntrperiod,nsubmode,nfqso, & ntol,ndepth,mycall,hiscall,hisgrid) +! Decodes QRA65 signals +! 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 + use timer_module, only: timer use packjt use, intrinsic :: iso_c_binding - parameter (NMAX=300*12000) !### Needs to be 300*12000 ### + parameter (NMAX=300*12000) !Max TRperiod is 300 s class(qra65_decoder), intent(inout) :: this procedure(qra65_decode_callback) :: callback - character(len=12) :: mycall, hiscall + character(len=12) :: mycall, hiscall !Used for AP decoding character(len=6) :: hisgrid - character*37 decoded + character*37 decoded !Decoded message integer*2 iwave(NMAX) !Raw data real dd(NMAX) !Raw data - integer dat4(12) - logical lapdx,ltext - complex, allocatable :: c00(:) !Analytic signal, 6000 S/s - complex, allocatable :: c0(:) !Analytic signal, 6000 S/s - real, allocatable, save :: s3(:,:) !Symbol spectra + 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 + real, allocatable, save :: s3(:,:) !Synchronized symbol spectra real, allocatable, save :: s3a(:,:) !Symbol spectra for avg messages data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/,nsubmodez/-1/ save nc1z,nc2z,ng2z,maxaptypez,nsave,nsubmodez diff --git a/lib/sync_qra65.f90 b/lib/sync_qra65.f90 index 21c155415..c93aed626 100644 --- a/lib/sync_qra65.f90 +++ b/lib/sync_qra65.f90 @@ -1,19 +1,29 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) +! Look for the sync vector in a QRA65 signal. +! Input: iwave(0:nmax-1) Raw data +! mode65 Tone spacing 1 2 4 8 16 (A-E) +! nsps Samples per symbol at 12000 Sa/s +! nfqso Target frequency (Hz) +! ntol Search range around nfqso (Hz) +! Output: xdt Time offset from nominal (s) +! f0 Frequency of sync tone +! snr1 Relative SNR of sync signal + parameter (NSTEP=4) !Quarter-symbol steps integer*2 iwave(0:nmax-1) !Raw data integer isync(22) !Indices of sync symbols integer ijpk(2) !Indices i and j at peak of ccf real, allocatable :: s1(:,:) !Symbol spectra, quarter-symbol steps real sync(85) !sync vector - real ccf(-64:64,-26:107) + real ccf(-64:64,-26:107) !CCF(freq,time) complex, allocatable :: c0(:) !Complex spectrum of symbol data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data sync(1)/99.0/ save sync nfft=2*nsps - df=12000.0/nfft + df=12000.0/nfft !Freq resolution = 0.5*baud istep=nsps/NSTEP iz=5000.0/df !Uppermost frequency bin, at 5000 Hz txt=85.0*nsps/12000.0 @@ -23,10 +33,10 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) allocate(s1(iz,jz)) allocate(c0(0:nfft-1)) - if(sync(1).eq.99.0) then - sync=-22.0/63.0 !Sync OFF + if(sync(1).eq.99.0) then !Generate the sync vector + sync=-22.0/63.0 !Sync tone OFF do k=1,22 - sync(isync(k))=1.0 !Sync ON + sync(isync(k))=1.0 !Sync tone ON enddo endif @@ -46,27 +56,23 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) do i=1,iz s1(i,j)=real(c0(i))**2 + aimag(c0(i))**2 enddo +! For large Doppler spreads, should we smooth the spectra here? enddo - i0=nint(nfqso/df) + i0=nint(nfqso/df) !Target QSO frequency call pctile(s1(i0-64:i0+192,1:jz),129*jz,40,base) - s1=s1/base - s1max=20.0 + s1=s1/base !Maybe should subtract 1.0 here? -! Apply AGC +! Apply fast AGC + s1max=20.0 !Empirical choice do j=1,jz smax=maxval(s1(i0-64:i0+192,j)) if(smax.gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/smax enddo -! do i=1,iz -! write(60,3060) i,i*df,sum(s1(i,1:jz)) -!3060 format(i6,f10.3,e12.3) -! enddo - - dt4=nsps/(NSTEP*12000.0) !1/4 of symbol duration + dt4=nsps/(NSTEP*12000.0) !1/4 of symbol duration j0=0.5/dt4 - if(nsps.ge.7680) j0=1.0/dt4 + if(nsps.ge.7680) j0=1.0/dt4 !Nominal index for start of signal ccf=0. ia=min(64,nint(ntol/df)) @@ -85,23 +91,12 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) enddo enddo -! do i=-64,64 -! write(61,3061) i,ccf(i,jpk) -!3061 format(i5,e12.3) -! enddo -! do j=lag1,lag2 -! write(62,3061) j,ccf(ipk,j) -! enddo - ijpk=maxloc(ccf) ipk=ijpk(1)-65 -! jpk=ijpk(2)-16 jpk=ijpk(2)-27 f0=nfqso + ipk*df xdt=jpk*dt4 snr1=maxval(ccf)/22.0 -! write(*,3100) ipk,jpk,xdt,f0,snr1 -!3100 format(2i5,f7.2,2f10.2) return end subroutine sync_qra65 From 538b0b91ab55463c90dcc8eb115b405f997e7e43 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 9 Oct 2020 14:12:34 -0400 Subject: [PATCH 078/206] Move s3, s3a arrays into qra_loops. --- lib/qra65_decode.f90 | 104 +++++++++++++++++++------------------------ lib/qra_loops.f90 | 2 +- 2 files changed, 46 insertions(+), 60 deletions(-) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index 13ee12e1d..7778844bf 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -56,10 +56,8 @@ contains logical ltext complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s - real, allocatable, save :: s3(:,:) !Synchronized symbol spectra - real, allocatable, save :: s3a(:,:) !Symbol spectra for avg messages data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/,nsubmodez/-1/ - save nc1z,nc2z,ng2z,maxaptypez,nsave,nsubmodez + save nc1z,nc2z,ng2z,maxaptypez,nsubmodez mode65=2**nsubmode nfft1=ntrperiod*12000 @@ -67,13 +65,6 @@ contains allocate (c00(0:nfft1-1)) allocate (c0(0:nfft1-1)) - if(nsubmode.ne.nsubmodez) then - if(allocated(s3)) deallocate(s3) - if(allocated(s3a)) deallocate(s3a) - allocate(s3(-64:64*mode65+63,63)) - allocate(s3a(-64:64*mode65+63,63)) - endif - if(ntrperiod.eq.15) then nsps=1800 else if(ntrperiod.eq.30) then @@ -85,67 +76,62 @@ contains else if(ntrperiod.eq.300) then nsps=41472 else - 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 + 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 ! Prime the QRA decoder for possible use of AP - 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 + 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 ! AP control could be done differently, but this works well: - maxaptype=0 - if(ndepth.eq.2) maxaptype=3 - if(ndepth.eq.3) maxaptype=5 + maxaptype=0 + if(ndepth.eq.2) maxaptype=3 + if(ndepth.eq.3) maxaptype=5 - 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(s3,nc1,nc2,ng2,naptype,1,nSubmode,b90, & - nFadingModel,dat4,snr2,irc) - enddo - nc1z=nc1 - nc2z=nc2 - ng2z=ng2 - maxaptypez=maxaptype - s3a=0. - nsave=0 - endif - naptype=maxaptype + 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) - call sync_qra65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1) - call timer('sync_q65',1) + call timer('sync_q65',0) + call sync_qra65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1) + call timer('sync_q65',1) - jpk0=(xdt+1.0)*6000 !### - if(jpk0.lt.0) jpk0=0 + jpk0=(xdt+1.0)*6000 !### + if(jpk0.lt.0) jpk0=0 - fac=1.0/32767.0 - dd=fac*iwave -! npts=648000 - minsync=-2 - nmode=65 + fac=1.0/32767.0 + dd=fac*iwave + minsync=-2 + nmode=65 - call ana64(dd,npts,c00) - - call timer('qraloops',0) - call qra_loops(c00,npts/2,nmode,mode65,nsubmode,nFadingModel,minsync, & - ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,s3,irc,dat4) - if(nmode.eq.65) xdt=xdt+0.4 !### Empirical WHY ??? ### - call timer('qraloops',1) + call ana64(dd,npts,c00) + call timer('qraloops',0) + call qra_loops(c00,npts/2,nmode,mode65,nsubmode,nFadingModel,minsync, & + ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) + call timer('qraloops',1) + xdt=xdt+0.4 !### Empirical -- WHY ??? ### + snr2=snr2 + db(6912.0/nsps) decoded=' ' if(irc.ge.0) then - nsave=0 - s3a=0. call unpackmsg(dat4,decoded) !Unpack the user message call fmtmsg(decoded,iz) if(index(decoded,"000AAA ").ge.1) then diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 0ea261047..4aa6c7b17 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -1,5 +1,5 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & - ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,s3,irc,dat4) + ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) use timer_module, only: timer parameter (LN=1152*63) From e82da4484cf608965aac7dbfc0d7ba8d5df7a84e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 9 Oct 2020 15:29:16 -0400 Subject: [PATCH 079/206] Code cleanup. --- lib/qra64a.f90 | 5 ++--- lib/qra_loops.f90 | 11 +++++------ 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index e5da55afd..b062928e1 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -12,7 +12,6 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & logical ltext complex c00(0:720000) !Analytic signal for dd() real dd(NMAX) !Raw data sampled at 12000 Hz - real s3(LN) !Symbol spectra integer dat4(12) !Decoded message (as 12 integers) data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/ save @@ -42,7 +41,7 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & maxaptype.ne.maxaptypez) then do naptype=0,maxaptype if(naptype.eq.2 .and. maxaptype.eq.4) cycle - call qra64_dec(s3,nc1,nc2,ng2,naptype,1,nSubmode,b90, & + call qra64_dec(s3dummy,nc1,nc2,ng2,naptype,1,nSubmode,b90, & nFadingModel,dat4,snr2,irc) enddo nc1z=nc1 @@ -63,7 +62,7 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & call timer('qraloops',0) call qra_loops(c00,npts/2,64,mode64,nsubmode,nFadingModel,minsync, & - ndepth,nc1,nc2,ng2,naptype,jpk0,dtx,f0,width,snr2,s3,irc,dat4) + ndepth,nc1,nc2,ng2,naptype,jpk0,dtx,f0,width,snr2,irc,dat4) call timer('qraloops',1) decoded=' ' diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 4aa6c7b17..445c7c93f 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -26,7 +26,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & napmin=99 ncall=0 nsps=3456 !QRA64 - if(mode.eq.65) nsps=3840 !QRA65 + if(mode.eq.65) nsps=3840 !QRA65 ### Is 3840 too big? ### do idf0=1,11 idf=idf0/2 @@ -39,15 +39,14 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & if(mod(idt0,2).eq.0) idt=-idt jpk=jpk0 + 750*idt if(jpk.lt.0) jpk=0 - call spec64(c0,nsps,mode,jpk,s3a,LL,NN) - call pctile(s3a,LL*NN,40,base) - s3a=s3a/base - where(s3a(1:LL*NN)>s3lim) s3a(1:LL*NN)=s3lim + call spec64(c0,nsps,mode,jpk,s3,LL,NN) + call pctile(s3,LL*NN,40,base) + s3=s3/base + where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim do ibw=ibwmax,ibwmin,-2 b90=1.728**ibw if(b90.gt.230.0) cycle if(b90.lt.0.15*width) exit - s3(1:LL*NN)=s3a(1:LL*NN) ncall=ncall+1 call timer('qra64_de',0) call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & From d5ce2def09abbe61aac4e678ba75cd059bfbd0fb Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 9 Oct 2020 17:04:06 -0400 Subject: [PATCH 080/206] Code cleanup. --- lib/qra_loops.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 445c7c93f..d59bbe05f 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -6,7 +6,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & complex c00(0:720000) !Analytic representation of dd(), 6000 Hz complex c0(0:720000) !Ditto, with freq shift real a(3) !twkfreq params f,f1,f2 - real s3(LN),s3a(LN) !Symbol spectra + real s3(LN) !Symbol spectra integer dat4(12),dat4x(12) !Decoded message (as 12 integers) integer nap(0:11) !AP return codes data nap/0,2,3,2,3,4,2,3,6,4,6,6/ From ad70cdeb8a1e8409de694058111e18ab0476137d Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 13 Oct 2020 13:49:09 -0400 Subject: [PATCH 081/206] More work on sync tests, etc., of QRA6[45]. --- lib/qra/qra64/qra64sim.f90 | 41 +++++++++++++++++++++++++++++++----- lib/qra/qra65/qra65sim.f90 | 42 +++++++++++++++++++++++++++++-------- lib/qra65_decode.f90 | 5 +++-- lib/qra_loops.f90 | 7 +++++-- lib/sync_qra65.f90 | 43 +++++++++++++++++++------------------- 5 files changed, 99 insertions(+), 39 deletions(-) diff --git a/lib/qra/qra64/qra64sim.f90 b/lib/qra/qra64/qra64sim.f90 index 278c1797d..2360ef7da 100644 --- a/lib/qra/qra64/qra64sim.f90 +++ b/lib/qra/qra64/qra64sim.f90 @@ -14,14 +14,18 @@ program qra64sim complex cdat(NMAX) !Generated complex waveform complex cspread(0:NFFT-1) !Complex amplitude for Rayleigh fading complex z + complex c00(0:720000) !Analytic signal for dat() real*8 f0,dt,twopi,phi,dphi,baud,fsample,freq - character msg*22,fname*11,csubmode*1,arg*12 + character msg*22,fname*11,csubmode*1,arg*12,cd*1 character msgsent*22 + logical lsync + data lsync/.false./ nargs=iargc() - if(nargs.ne. 7) then - print *, 'Usage: qra64sim "msg" A-E Nsigs fDop DT Nfiles SNR' - print *, 'Example qra64sim "K1ABC W9XYZ EN37" A 10 0.2 0.0 1 0' + if(nargs.ne.8) then + print*,'Usage: qra64sim "msg" A-E Nsigs fDop DT Nfiles Sync SNR' + print*,'Example qra64sim "K1ABC W9XYZ EN37" A 10 0.2 0.0 1 T -26' + print*,'Sync = T to include sync test.' go to 999 endif call getarg(1,msg) @@ -36,8 +40,10 @@ program qra64sim call getarg(6,arg) read(arg,*) nfiles call getarg(7,arg) + if(arg(1:1).eq.'T' .or. arg(1:1).eq.'1') lsync=.true. + call getarg(8,arg) read(arg,*) snrdb - + if(mode64.ge.8) nsigs=1 rms=100. fsample=12000.d0 !Sample rate (Hz) @@ -54,6 +60,7 @@ program qra64sim write(*,1000) 1000 format('File Sig Freq A-E S/N DT Dop Message'/60('-')) + nsync=0 do ifile=1,nfiles !Loop over requested number of files write(fname,1002) ifile !Output filename 1002 format('000000_',i4.4) @@ -165,6 +172,30 @@ program qra64sim if(snrdb.lt.90.0) iwave(1:npts)=nint(rms*dat(1:npts)) write(10) h,iwave(1:npts) !Save the .wav file close(10) + + if(lsync) then + cd=' ' + if(ifile.eq.nfiles) cd='d' + nf1=200 + nf2=3000 + nfqso=nint(f0) + ntol=100 + minsync=0 + emedelay=0.0 + call ana64(dat,npts,c00) + call sync64(c00,nf1,nf2,nfqso,ntol,minsync,mode64,emedelay,xdt2,f02, & + jpk0,sync,sync2,width) + terr=1.01/(8.0*baud) + ferr=1.01*mode64*baud + if(abs(xdt2-xdt).lt.terr .and. abs(f02-f0).lt.ferr) nsync=nsync+1 + open(40,file='sync64.out',status='unknown',position='append') + write(40,1030) ifile,64,csubmode,snrdb,fspread,xdt2-xdt,f02-f0, & + width,sync,sync2,nsync,cd +1030 format(i4,i3,1x,a1,2f7.1,f7.2,4f8.1,i5,1x,a1) + close(40) + endif enddo + if(lsync) write(*,1040) snrdb,nfiles,nsync +1040 format('SNR:',f6.1,' nfiles:',i5,' nsynced:',i5) 999 end program qra64sim diff --git a/lib/qra/qra65/qra65sim.f90 b/lib/qra/qra65/qra65sim.f90 index e91324d27..62ec63f57 100644 --- a/lib/qra/qra65/qra65sim.f90 +++ b/lib/qra/qra65/qra65sim.f90 @@ -14,13 +14,16 @@ program qra65sim complex cspread(0:NMAX-1) !Complex amplitude for Rayleigh fading complex z real*8 f0,dt,twopi,phi,dphi,baud,fsample,freq - character msg*22,fname*17,csubmode*1,arg*12 + character msg*22,fname*17,csubmode*1,arg*12,cd*1 character msgsent*22 - + logical lsync + data lsync/.false./ + nargs=iargc() - if(nargs.ne.8) then - print *, 'Usage: qra65sim "msg" A-E freq fDop DT TRp Nfiles SNR' - print *, 'Example: qra65sim "K1ABC W9XYZ EN37" A 1500 0.2 0.0 15 1 -10' + if(nargs.ne.9) then + print *, 'Usage: qra65sim "msg" A-E freq fDop DT TRp Nfiles Sync SNR' + print *, 'Example: qra65sim "K1ABC W9XYZ EN37" A 1500 0.0 0.0 60 1 T -26' + print*,'Sync = T to include sync test.' go to 999 endif call getarg(1,msg) @@ -37,8 +40,15 @@ program qra65sim call getarg(7,arg) read(arg,*) nfiles call getarg(8,arg) + if(arg(1:1).eq.'T' .or. arg(1:1).eq.'1') lsync=.true. + call getarg(9,arg) read(arg,*) snrdb + if(nfiles.lt.0) then + nfiles=-nfiles + lsync=.true. + endif + if(ntrperiod.eq.15) then nsps=1800 else if(ntrperiod.eq.30) then @@ -75,6 +85,7 @@ program qra65sim write(*,1000) 1000 format('File TR Freq Mode S/N DT Dop Message'/60('-')) + nsync=0 do ifile=1,nfiles !Loop over requested number of files if(ntrperiod.lt.60) then write(fname,1002) ifile !Output filename @@ -169,10 +180,23 @@ program qra65sim write(10) h,iwave(1:npts) !Save the .wav file close(10) -! do i=1,NMAX -! write(15,3020) i/12000.0,iwave(i) -!3020 format(f10.6,i8) -! enddo + if(lsync) then + cd=' ' + if(ifile.eq.nfiles) cd='d' + nfqso=nint(f0) + ntol=100 + call sync_qra65(iwave,npts,mode65,nsps,nfqso,ntol,xdt2,f02,snr2) + terr=1.01/(8.0*baud) + ferr=1.01*mode65*baud + if(abs(xdt2-xdt).lt.terr .and. abs(f02-f0).lt.ferr) nsync=nsync+1 + open(40,file='sync65.out',status='unknown',position='append') + write(40,1030) ifile,65,csubmode,snrdb,fspread,xdt2-xdt,f02-f0, & + snr2,nsync,cd +1030 format(i4,i3,1x,a1,2f7.1,f7.2,2f8.1,i5,1x,a1) + close(40) + endif enddo + if(lsync) write(*,1040) snrdb,nfiles,nsync +1040 format('SNR:',f6.1,' nfiles:',i5,' nsynced:',i5) 999 end program qra65sim diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index 7778844bf..c5ab8521c 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -93,8 +93,9 @@ contains ! AP control could be done differently, but this works well: maxaptype=0 - if(ndepth.eq.2) maxaptype=3 - if(ndepth.eq.3) maxaptype=5 +! if(ndepth.eq.2) maxaptype=3 +! if(ndepth.eq.3) maxaptype=5 + if(ndepth.ge.2) maxaptype=5 !### if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & maxaptype.ne.maxaptypez) then diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index d59bbe05f..59b9458b1 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -69,7 +69,6 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & endif enddo ! ibw (b90 loop) if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 - if(irc.eq.0) go to 100 enddo ! idt (DT loop) enddo ! idf (f0 loop) @@ -85,5 +84,9 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & ibw=ibwkeep endif -200 return +200 continue + write(53,3053) idt,idf,ibw,irc,b90,xdt,f0,snr2 +3053 format(4i5,f7.1,f7.2,2f7.1) + + return end subroutine qra_loops diff --git a/lib/sync_qra65.f90 b/lib/sync_qra65.f90 index c93aed626..b18aa8870 100644 --- a/lib/sync_qra65.f90 +++ b/lib/sync_qra65.f90 @@ -1,6 +1,8 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) -! Look for the sync vector in a QRA65 signal. +! Detect and align with the QRA65 sync vector, returning time and frequency +! offsets and SNR estimate. + ! Input: iwave(0:nmax-1) Raw data ! mode65 Tone spacing 1 2 4 8 16 (A-E) ! nsps Samples per symbol at 12000 Sa/s @@ -10,7 +12,7 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) ! f0 Frequency of sync tone ! snr1 Relative SNR of sync signal - parameter (NSTEP=4) !Quarter-symbol steps + parameter (NSTEP=8) !Step size nsps/NSTEP integer*2 iwave(0:nmax-1) !Raw data integer isync(22) !Indices of sync symbols integer ijpk(2) !Indices i and j at peak of ccf @@ -28,7 +30,7 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) iz=5000.0/df !Uppermost frequency bin, at 5000 Hz txt=85.0*nsps/12000.0 jz=(txt+1.0)*12000.0/istep !Number of quarter-symbol steps - if(nsps.ge.7680) jz=(txt+2.0)*12000.0/istep !For TR 60 s and higher + if(nsps.ge.6912) jz=(txt+2.0)*12000.0/istep !For TR 60 s and higher allocate(s1(iz,jz)) allocate(c0(0:nfft-1)) @@ -41,11 +43,11 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) endif fac=1/32767.0 - do j=1,jz !Compute symbol spectra at quarter-symbol steps + do j=1,jz !Compute symbol spectra at step size ia=(j-1)*istep ib=ia+nsps-1 k=-1 - do i=ia,ib,2 + do i=ia,ib,2 !Load iwave data into complex array c0, for r2c FFT xx=iwave(i) yy=iwave(i+1) k=k+1 @@ -57,11 +59,12 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) s1(i,j)=real(c0(i))**2 + aimag(c0(i))**2 enddo ! For large Doppler spreads, should we smooth the spectra here? + call smo121(s1(1:iz,j),iz) enddo i0=nint(nfqso/df) !Target QSO frequency call pctile(s1(i0-64:i0+192,1:jz),129*jz,40,base) - s1=s1/base !Maybe should subtract 1.0 here? + s1=s1/base - 1.0 ! Apply fast AGC s1max=20.0 !Empirical choice @@ -70,24 +73,22 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) if(smax.gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/smax enddo - dt4=nsps/(NSTEP*12000.0) !1/4 of symbol duration - j0=0.5/dt4 - if(nsps.ge.7680) j0=1.0/dt4 !Nominal index for start of signal + dtstep=nsps/(NSTEP*12000.0) !Step size in seconds + j0=0.5/dtstep + if(nsps.ge.6192) j0=1.0/dtstep !Nominal index for start of signal ccf=0. ia=min(64,nint(ntol/df)) - lag1=-1.0/dt4 - lag2=4.0/dt4 + 0.9999 + lag1=-1.0/dtstep + lag2=4.0/dtstep + 0.9999 - do i=-ia,ia - 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 - ccf(i,lag)=ccf(i,lag) + sync(k)*s1(i0+i,j) - endif - enddo + 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 + ccf(-ia:ia,lag)=ccf(-ia:ia,lag) + sync(k)*s1(i0-ia:i0+ia,j) + endif enddo enddo @@ -95,7 +96,7 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) ipk=ijpk(1)-65 jpk=ijpk(2)-27 f0=nfqso + ipk*df - xdt=jpk*dt4 + xdt=jpk*dtstep snr1=maxval(ccf)/22.0 return From 4bf5f23c544068c477ae217696db4e45186fea74 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 14 Oct 2020 11:49:27 -0400 Subject: [PATCH 082/206] Update QRA test programs. --- lib/qra64a.f90 | 16 ++++++++++++++++ lib/qra65_decode.f90 | 3 ++- lib/test_qra64.f90 | 4 ++-- lib/test_qra65.f90 | 8 ++++---- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index b062928e1..a8c532266 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -37,6 +37,7 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & nFadingModel=1 maxaptype=4 if(iand(ndepth,64).ne.0) maxaptype=5 + call qra_params(ndepth,maxaptype,minsync) if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & maxaptype.ne.maxaptypez) then do naptype=0,maxaptype @@ -93,3 +94,18 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & return end subroutine qra64a + +subroutine qra_params(ndepth,maxaptype,minsync) + +! If file qra_params is present in CWD, read decoding params from it. + + logical ex + inquire(file='qra_params',exist=ex) + if(ex) then + open(29,file='qra_params',status='old') + read(29,*) ndepth,maxaptype,minsync + close(29) + endif + + return +end subroutine qra_params diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index c5ab8521c..b9b9c1a7b 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -96,6 +96,8 @@ contains ! if(ndepth.eq.2) maxaptype=3 ! if(ndepth.eq.3) maxaptype=5 if(ndepth.ge.2) maxaptype=5 !### + minsync=-2 + call qra_params(ndepth,maxaptype,minsync) if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & maxaptype.ne.maxaptypez) then @@ -120,7 +122,6 @@ contains fac=1.0/32767.0 dd=fac*iwave - minsync=-2 nmode=65 call ana64(dd,npts,c00) diff --git a/lib/test_qra64.f90 b/lib/test_qra64.f90 index 760c87452..24f54c2d6 100644 --- a/lib/test_qra64.f90 +++ b/lib/test_qra64.f90 @@ -45,7 +45,7 @@ program test_qra64 ! 1 2 3 4 5 6 7 ! 12345678901234567890123456789012345678901234567890123456789012345678901' - cmd1='qra64sim "K1ABC W9XYZ EN37 " A 1 0.2 0.00 100 -20 > junk0' + cmd1='qra64sim "K1ABC W9XYZ EN37 " A 1 0.2 0.00 100 F -20 > junk0' cmd2='jt9 -q -L 300 -H 3000 -f 1000 -d 3 -b A *.wav > junk' @@ -74,7 +74,7 @@ program test_qra64 ndecodes=0 nfalse=0 nretcode=0 - write(cmd1(55:57),'(i3)') nsnr + write(cmd1(57:59),'(i3)') nsnr call system(cmd1) call sec0(0,tdec) call system(cmd2) diff --git a/lib/test_qra65.f90 b/lib/test_qra65.f90 index 4a9881d9f..21cc5caab 100644 --- a/lib/test_qra65.f90 +++ b/lib/test_qra65.f90 @@ -1,6 +1,6 @@ program test_qra65 - character*71 cmd1,cmd2,line + character*73 cmd1,cmd2,line character*22 msg character*8 arg character*1 csubmode @@ -60,8 +60,8 @@ program test_qra65 tsym=1.0/baud ! 1 2 3 4 5 6 7 -! 12345678901234567890123456789012345678901234567890123456789012345678901' - cmd1='qra65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 -10 > junk0' +! 1234567890123456789012345678901234567890123456789012345678901234567890123' + cmd1='qra65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 F -10 > junk0' cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A *.wav > junk' write(cmd1(10:33),'(a)') '"'//msg//'"' @@ -90,7 +90,7 @@ program test_qra65 nfalse=0 nretcode=0 navg=0 - write(cmd1(61:63),'(i3)') nsnr + write(cmd1(63:65),'(i3)') nsnr call system(cmd1) call sec0(0,tdec) call system(cmd2) From 2aa999ba44bcce36eff3a4ddeb4ab4d1bca326e7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 16 Oct 2020 14:44:13 -0400 Subject: [PATCH 083/206] Improved version of qra_params() subroutine, for testing. --- lib/qra64a.f90 | 35 +++++++++++++++++++++++++---------- lib/qra65_decode.f90 | 6 +++--- lib/qra_loops.f90 | 11 ++++------- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index a8c532266..0691cea78 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -37,7 +37,7 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & nFadingModel=1 maxaptype=4 if(iand(ndepth,64).ne.0) maxaptype=5 - call qra_params(ndepth,maxaptype,minsync) + call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & maxaptype.ne.maxaptypez) then do naptype=0,maxaptype @@ -62,7 +62,7 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & if(mode64.eq.1 .and. minsync.ne.-1 .and. (sync-7.0).lt.minsync) go to 900 call timer('qraloops',0) - call qra_loops(c00,npts/2,64,mode64,nsubmode,nFadingModel,minsync, & + call qra_loops(c00,npts/2,64,mode64,nsubmode,nFadingModel, & ndepth,nc1,nc2,ng2,naptype,jpk0,dtx,f0,width,snr2,irc,dat4) call timer('qraloops',1) @@ -95,17 +95,32 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & return end subroutine qra64a -subroutine qra_params(ndepth,maxaptype,minsync) +subroutine qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) ! If file qra_params is present in CWD, read decoding params from it. - - logical ex - inquire(file='qra_params',exist=ex) - if(ex) then - open(29,file='qra_params',status='old') - read(29,*) ndepth,maxaptype,minsync - close(29) + + integer iparam(6) + logical first,ex + data iparam/3,5,11,5,9,9/ !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 + write(*,'(6i4)') iparam + first=.false. endif + ndepth=iparam(1) + maxaptype=iparam(2) + idf0max=iparam(3) + idt0max=iparam(4) + ibwmin=iparam(5) + ibwmax=iparam(6) return end subroutine qra_params diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index b9b9c1a7b..afde90c9d 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -97,7 +97,7 @@ contains ! if(ndepth.eq.3) maxaptype=5 if(ndepth.ge.2) maxaptype=5 !### minsync=-2 - call qra_params(ndepth,maxaptype,minsync) + call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & maxaptype.ne.maxaptypez) then @@ -127,7 +127,7 @@ contains call ana64(dd,npts,c00) call timer('qraloops',0) - call qra_loops(c00,npts/2,nmode,mode65,nsubmode,nFadingModel,minsync, & + call qra_loops(c00,npts/2,nmode,mode65,nsubmode,nFadingModel, & ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) call timer('qraloops',1) xdt=xdt+0.4 !### Empirical -- WHY ??? ### @@ -146,7 +146,7 @@ contains irc,qual,ntrperiod,fmid,w50) else snr2=0. - nsnr=-25 + nsnr=-30 !### TEMPORARY? ### call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 59b9458b1..92908a2bc 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -1,4 +1,4 @@ -subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & +subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) use timer_module, only: timer @@ -15,12 +15,9 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel,minsync, & s3lim=20. ibwmax=11 if(mode64.le.4) ibwmax=9 - ibwmin=0 - idtmax=5 - if(minsync.eq.-2) then - ibwmin=ibwmax - idtmax=3 - endif + ibwmin=ibwmax + idtmax=3 + call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) LL=64*(mode64+2) NN=63 napmin=99 From 8542af30f9a8109b56798e93f4219d233b28d340 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 16 Oct 2020 18:42:31 -0400 Subject: [PATCH 084/206] Default ibwmin set to 0 in qra_params(). --- lib/qra64a.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index 0691cea78..ae810d044 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -101,7 +101,7 @@ subroutine qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) integer iparam(6) logical first,ex - data iparam/3,5,11,5,9,9/ !Default values + data iparam/3,5,11,5,0,9/ !Default values data first/.true./ save first,iparam From 3f68f075e80d204d5b3a602301ab38c0f0928176 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 17 Oct 2020 11:19:15 -0400 Subject: [PATCH 085/206] Tweak some QRA65 decoding ideas. --- lib/qra64a.f90 | 6 +++--- lib/qra65_decode.f90 | 2 +- lib/qra_loops.f90 | 32 ++++++++++++++++++++------------ lib/test_qra65.f90 | 2 +- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index ae810d044..dd678ce3e 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -37,7 +37,7 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & nFadingModel=1 maxaptype=4 if(iand(ndepth,64).ne.0) maxaptype=5 - call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) + call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax) if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & maxaptype.ne.maxaptypez) then do naptype=0,maxaptype @@ -101,7 +101,8 @@ subroutine qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) integer iparam(6) logical first,ex - data iparam/3,5,11,5,0,9/ !Default values +! data iparam/3,5,11,5,0,9/ !Maximum effort + data iparam/3,5,3,3,7,9/ !Default values data first/.true./ save first,iparam @@ -112,7 +113,6 @@ subroutine qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) read(29,*) iparam close(29) endif - write(*,'(6i4)') iparam first=.false. endif ndepth=iparam(1) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index afde90c9d..d79275f53 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -97,7 +97,7 @@ contains ! if(ndepth.eq.3) maxaptype=5 if(ndepth.ge.2) maxaptype=5 !### minsync=-2 - call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) + call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax) if(nc1.ne.nc1z .or. nc2.ne.nc2z .or. ng2.ne.ng2z .or. & maxaptype.ne.maxaptypez) then diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 92908a2bc..e366ed27d 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -1,8 +1,10 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) + use packjt use timer_module, only: timer parameter (LN=1152*63) + character*37 decoded complex c00(0:720000) !Analytic representation of dd(), 6000 Hz complex c0(0:720000) !Ditto, with freq shift real a(3) !twkfreq params f,f1,f2 @@ -17,7 +19,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & if(mode64.le.4) ibwmax=9 ibwmin=ibwmax idtmax=3 - call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) + call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax) LL=64*(mode64+2) NN=63 napmin=99 @@ -25,16 +27,16 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & nsps=3456 !QRA64 if(mode.eq.65) nsps=3840 !QRA65 ### Is 3840 too big? ### - do idf0=1,11 - idf=idf0/2 - if(mod(idf0,2).eq.0) idf=-idf + do idf=1,idfmax + ndf=idfn/2 + if(mod(idf,2).eq.0) ndf=-ndf a=0. - a(1)=-(f0+0.868*idf) + a(1)=-(f0+0.868*ndf) call twkfreq(c00,c0,npts2,6000.0,a) - do idt0=1,idtmax - idt=idt0/2 - if(mod(idt0,2).eq.0) idt=-idt - jpk=jpk0 + 750*idt + do idt=1,idtmax + ndt=idt/2 + if(mod(idt,2).eq.0) ndt=-ndt + jpk=jpk0 + 750*ndt if(jpk.lt.0) jpk=0 call spec64(c0,nsps,mode,jpk,s3,LL,NN) call pctile(s3,LL*NN,40,base) @@ -82,8 +84,14 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & endif 200 continue - write(53,3053) idt,idf,ibw,irc,b90,xdt,f0,snr2 -3053 format(4i5,f7.1,f7.2,2f7.1) - +!### For tests only: + if(irc.ge.0) then + open(53,file='fort.53',status='unknown',position='append') + call unpackmsg(dat4,decoded) !Unpack the user message + write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,irc,decoded(1:22) +3053 format(3i5,f7.1,f7.2,2f7.1,i5,2x,a22) + close(53) + endif +!### return end subroutine qra_loops diff --git a/lib/test_qra65.f90 b/lib/test_qra65.f90 index 21cc5caab..5b881d6ba 100644 --- a/lib/test_qra65.f90 +++ b/lib/test_qra65.f90 @@ -102,7 +102,7 @@ program test_qra65 if(index(line,' Date: Sat, 17 Oct 2020 13:16:46 -0400 Subject: [PATCH 086/206] Allocate some big arrays on the heap. --- CMakeLists.txt | 2 +- lib/qra65_decode.f90 | 3 ++- lib/spec_qra65.f90 | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c88b61e10..05cf0ae6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1382,7 +1382,7 @@ if (${OPENMP_FOUND} OR APPLE) endif (APPLE) if (WIN32) set_target_properties (jt9 PROPERTIES - LINK_FLAGS -Wl,--stack,28000000 + LINK_FLAGS -Wl,--stack,16777216 ) endif () target_link_libraries (jt9 wsjt_fort_omp wsjt_cxx fort_qt) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index d79275f53..beb174527 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -51,7 +51,7 @@ contains character(len=6) :: hisgrid character*37 decoded !Decoded message integer*2 iwave(NMAX) !Raw data - real dd(NMAX) !Raw data + real, allocatable :: dd(:) !Raw data integer dat4(12) !Decoded message as 12 6-bit integers logical ltext complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s @@ -62,6 +62,7 @@ contains mode65=2**nsubmode nfft1=ntrperiod*12000 nfft2=ntrperiod*6000 + allocate(dd(NMAX)) allocate (c00(0:nfft1-1)) allocate (c0(0:nfft1-1)) diff --git a/lib/spec_qra65.f90 b/lib/spec_qra65.f90 index 9f6af0b38..15e8fd092 100644 --- a/lib/spec_qra65.f90 +++ b/lib/spec_qra65.f90 @@ -3,12 +3,13 @@ subroutine spec_qra65(c0,nsps,s3,LL,NN) ! Compute synchronized symbol spectra. complex c0(0:85*nsps-1) !Synchronized complex data at 6000 S/s - complex cs(0:nsps-1) !Complex symbol spectrum + complex, allocatable :: cs(:) !Complex symbol spectrum real s3(LL,NN) !Synchronized symbol spectra real xbase0(LL),xbase(LL) !Work arrays integer isync(22) !Indices of sync symbols data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ + allocate(cs(0:nsps-1)) fac=1.0/nsps j=0 n=1 From 3187be38489816092c76cb5819479a41dba8c417 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 19 Oct 2020 11:29:48 -0400 Subject: [PATCH 087/206] Improved qra_loops(). --- lib/qra_loops.f90 | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index e366ed27d..73eeb20f7 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -26,6 +26,9 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & ncall=0 nsps=3456 !QRA64 if(mode.eq.65) nsps=3840 !QRA65 ### Is 3840 too big? ### + maxdist=5 + if(ndepth.eq.2) maxdist=10 + if(ndepth.eq.3) maxdist=30 do idf=1,idfmax ndf=idfn/2 @@ -36,13 +39,15 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & do idt=1,idtmax ndt=idt/2 if(mod(idt,2).eq.0) ndt=-ndt - jpk=jpk0 + 750*ndt + jpk=jpk0 + 240*ndt !240/6000 = 0.04 s = tsym/32 if(jpk.lt.0) jpk=0 call spec64(c0,nsps,mode,jpk,s3,LL,NN) call pctile(s3,LL*NN,40,base) s3=s3/base where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim do ibw=ibwmax,ibwmin,-2 + ndist=ndf**2 + ndt**2 + ((ibwmax-ibw)/2)**2 + if(ndist.gt.maxdist) cycle b90=1.728**ibw if(b90.gt.230.0) cycle if(b90.lt.0.15*width) exit @@ -65,9 +70,11 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & idfkeep=idf idtkeep=idt ibwkeep=ibw + ndistx=ndist + go to 100 !### endif enddo ! ibw (b90 loop) - if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 +!### if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 enddo ! idt (DT loop) enddo ! idf (f0 loop) @@ -81,6 +88,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & idt=idtkeep idf=idfkeep ibw=ibwkeep + ndist=ndistx endif 200 continue @@ -88,8 +96,8 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & if(irc.ge.0) then open(53,file='fort.53',status='unknown',position='append') call unpackmsg(dat4,decoded) !Unpack the user message - write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,irc,decoded(1:22) -3053 format(3i5,f7.1,f7.2,2f7.1,i5,2x,a22) + write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,ndist,irc,decoded(1:22) +3053 format(3i5,f7.1,f7.2,2f7.1,2i5,2x,a22) close(53) endif !### From df69562a9fc1cb7e75354684f8f24feff68e91ce Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 19 Oct 2020 15:24:32 -0400 Subject: [PATCH 088/206] More tweaks to QRA65 decoder. --- lib/qra65_decode.f90 | 32 +++++++++++++++----------------- lib/qra_loops.f90 | 9 ++++++--- lib/sync_qra65.f90 | 17 ++++++++++++++++- 3 files changed, 37 insertions(+), 21 deletions(-) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index beb174527..e7ff43626 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -118,21 +118,20 @@ contains call sync_qra65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1) call timer('sync_q65',1) - jpk0=(xdt+1.0)*6000 !### - 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) - call qra_loops(c00,npts/2,nmode,mode65,nsubmode,nFadingModel, & - ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) - call timer('qraloops',1) - xdt=xdt+0.4 !### Empirical -- WHY ??? ### - snr2=snr2 + db(6912.0/nsps) + irc=-1 + if(snr1.ge.2.7) then + jpk0=(xdt+1.0)*6000 !### + 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) + call qra_loops(c00,npts/2,nmode,mode65,nsubmode,nFadingModel, & + ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) + call timer('qraloops',1) + snr2=snr2 + db(6912.0/nsps) + endif decoded=' ' if(irc.ge.0) then call unpackmsg(dat4,decoded) !Unpack the user message @@ -146,8 +145,7 @@ contains call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) else - snr2=0. - nsnr=-30 + nsnr=db(snr1) - 32.0 !### TEMPORARY? ### call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 73eeb20f7..f2d1e30e5 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -31,17 +31,19 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & if(ndepth.eq.3) maxdist=30 do idf=1,idfmax - ndf=idfn/2 + ndf=idf/2 if(mod(idf,2).eq.0) ndf=-ndf a=0. - a(1)=-(f0+0.868*ndf) + a(1)=-(f0+0.4*ndf) call twkfreq(c00,c0,npts2,6000.0,a) do idt=1,idtmax ndt=idt/2 if(mod(idt,2).eq.0) ndt=-ndt jpk=jpk0 + 240*ndt !240/6000 = 0.04 s = tsym/32 if(jpk.lt.0) jpk=0 + call timer('spec64 ',0) call spec64(c0,nsps,mode,jpk,s3,LL,NN) + call timer('spec64 ',1) call pctile(s3,LL*NN,40,base) s3=s3/base where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim @@ -91,7 +93,8 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & ndist=ndistx endif -200 continue +200 if(mode.eq.65) xdt=xdt+0.4 !### Empirical -- WHY ??? ### + !### For tests only: if(irc.ge.0) then open(53,file='fort.53',status='unknown',position='append') diff --git a/lib/sync_qra65.f90 b/lib/sync_qra65.f90 index b18aa8870..401efcc3c 100644 --- a/lib/sync_qra65.f90 +++ b/lib/sync_qra65.f90 @@ -97,7 +97,22 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) jpk=ijpk(2)-27 f0=nfqso + ipk*df xdt=jpk*dtstep - snr1=maxval(ccf)/22.0 + sq=0. + nsq=0 + do j=lag1,lag2 + if(abs(j-jpk).gt.6) then + sq=sq + ccf(ipk,j)**2 + nsq=nsq+1 + endif + enddo + rms=sqrt(sq/nsq) + snr1=ccf(ipk,jpk)/rms + +! do j=lag1,lag2 +! write(55,3055) j,j*dtstep,ccf(ipk,j)/rms +!3055 format(i5,f8.3,f10.3) +! enddo + return end subroutine sync_qra65 From 35d85744264eec87335c7ca894cc663089c64b5e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 19 Oct 2020 17:27:11 -0400 Subject: [PATCH 089/206] Basic message averaging implemented for QRA65. --- lib/qra_loops.f90 | 131 +++++++++++++++++++++++++++------------------- 1 file changed, 77 insertions(+), 54 deletions(-) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index f2d1e30e5..797367c76 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -9,9 +9,12 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & complex c0(0:720000) !Ditto, with freq shift real a(3) !twkfreq params f,f1,f2 real s3(LN) !Symbol spectra + real s3a(LN) !Saved symbol spectra + real s3avg(LN) !Averaged symbol spectra integer dat4(12),dat4x(12) !Decoded message (as 12 integers) integer nap(0:11) !AP return codes - data nap/0,2,3,2,3,4,2,3,6,4,6,6/ + data nap/0,2,3,2,3,4,2,3,6,4,6,6/,nsave/0/ + save nsave,s3avg irc=-99 s3lim=20. @@ -30,56 +33,72 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & if(ndepth.eq.2) maxdist=10 if(ndepth.eq.3) maxdist=30 - do idf=1,idfmax - ndf=idf/2 - if(mod(idf,2).eq.0) ndf=-ndf - a=0. - a(1)=-(f0+0.4*ndf) - call twkfreq(c00,c0,npts2,6000.0,a) - do idt=1,idtmax - ndt=idt/2 - if(mod(idt,2).eq.0) ndt=-ndt - jpk=jpk0 + 240*ndt !240/6000 = 0.04 s = tsym/32 - if(jpk.lt.0) jpk=0 - call timer('spec64 ',0) - call spec64(c0,nsps,mode,jpk,s3,LL,NN) - call timer('spec64 ',1) - call pctile(s3,LL*NN,40,base) - s3=s3/base - where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim - do ibw=ibwmax,ibwmin,-2 - ndist=ndf**2 + ndt**2 + ((ibwmax-ibw)/2)**2 - if(ndist.gt.maxdist) cycle - b90=1.728**ibw - if(b90.gt.230.0) cycle - if(b90.lt.0.15*width) exit - ncall=ncall+1 - call timer('qra64_de',0) - call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & - nFadingModel,dat4,snr2,irc) - call timer('qra64_de',1) - if(irc.eq.0) go to 200 - if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) - iirc=max(0,min(irc,11)) - if(irc.gt.0 .and. nap(iirc).lt.napmin) then - dat4x=dat4 - b90x=b90 - snr2x=snr2 - napmin=nap(iirc) - irckeep=irc - xdtkeep=jpk/6000.0 - 1.0 - f0keep=-a(1) - idfkeep=idf - idtkeep=idt - ibwkeep=ibw - ndistx=ndist - go to 100 !### + do iavg=0,1 + if(iavg.eq.1) then + idfmax=1 + idtmax=1 + endif + do idf=1,idfmax + ndf=idf/2 + if(mod(idf,2).eq.0) ndf=-ndf + a=0. + a(1)=-(f0+0.4*ndf) + call twkfreq(c00,c0,npts2,6000.0,a) + do idt=1,idtmax + ndt=idt/2 + if(iavg.eq.0) then + if(mod(idt,2).eq.0) ndt=-ndt + jpk=jpk0 + 240*ndt !240/6000 = 0.04 s = tsym/32 + if(jpk.lt.0) jpk=0 + call timer('spec64 ',0) + call spec64(c0,nsps,mode,jpk,s3,LL,NN) + call timer('spec64 ',1) + call pctile(s3,LL*NN,40,base) + s3=s3/base + where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim + if(iavg.eq.0 .and. idf.eq.1 .and. idt.eq.1) s3a(1:LL*NN)=s3(1:LL*NN) + else + s3(1:LL*NN)=s3avg(1:LL*NN) endif - enddo ! ibw (b90 loop) -!### if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 - enddo ! idt (DT loop) - enddo ! idf (f0 loop) - + do ibw=ibwmax,ibwmin,-2 + ndist=ndf**2 + ndt**2 + ((ibwmax-ibw)/2)**2 + if(ndist.gt.maxdist) cycle + b90=1.728**ibw + if(b90.gt.230.0) cycle + if(b90.lt.0.15*width) exit + ncall=ncall+1 + call timer('qra64_de',0) + call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & + nFadingModel,dat4,snr2,irc) + call timer('qra64_de',1) + if(irc.eq.0) go to 200 + if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) + iirc=max(0,min(irc,11)) + if(irc.gt.0 .and. nap(iirc).lt.napmin) then + dat4x=dat4 + b90x=b90 + snr2x=snr2 + napmin=nap(iirc) + irckeep=irc + xdtkeep=jpk/6000.0 - 1.0 + f0keep=-a(1) + idfkeep=idf + idtkeep=idt + ibwkeep=ibw + ndistx=ndist + go to 100 !### + endif + enddo ! ibw (b90 loop) + !### if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 + enddo ! idt (DT loop) + enddo ! idf (f0 loop) + if(iavg.eq.0 .and. abs(jpk0-4320).le.1300) then + s3avg(1:LL*NN)=s3avg(1:LL*NN)+s3a(1:LL*NN) + nsave=nsave+1 + endif + if(iavg.eq.0 .and. nsave.lt.2) exit + enddo ! iavg + 100 if(napmin.ne.99) then dat4=dat4x b90=b90x @@ -95,14 +114,18 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & 200 if(mode.eq.65) xdt=xdt+0.4 !### Empirical -- WHY ??? ### -!### For tests only: if(irc.ge.0) then + navg=nsave + if(iavg.eq.0) navg=0 + !### For tests only: open(53,file='fort.53',status='unknown',position='append') call unpackmsg(dat4,decoded) !Unpack the user message - write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,ndist,irc,decoded(1:22) -3053 format(3i5,f7.1,f7.2,2f7.1,2i5,2x,a22) + write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,ndist,irc,navg,decoded(1:22) +3053 format(3i5,f7.1,f7.2,2f7.1,3i4,2x,a22) close(53) + !### + nsave=0 + s3avg=0. endif -!### return end subroutine qra_loops From ef3b158d431a2c6652637b625fd4962d06095061 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 19 Oct 2020 18:35:50 -0400 Subject: [PATCH 090/206] QRA65 message averaging assumes a fixed DT close to zero. --- lib/qra_loops.f90 | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 797367c76..3c9c2f1c3 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -9,7 +9,6 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & complex c0(0:720000) !Ditto, with freq shift real a(3) !twkfreq params f,f1,f2 real s3(LN) !Symbol spectra - real s3a(LN) !Saved symbol spectra real s3avg(LN) !Averaged symbol spectra integer dat4(12),dat4x(12) !Decoded message (as 12 integers) integer nap(0:11) !AP return codes @@ -56,7 +55,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & call pctile(s3,LL*NN,40,base) s3=s3/base where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim - if(iavg.eq.0 .and. idf.eq.1 .and. idt.eq.1) s3a(1:LL*NN)=s3(1:LL*NN) +! if(iavg.eq.0 .and. idf.eq.1 .and. idt.eq.1) s3a(1:LL*NN)=s3(1:LL*NN) else s3(1:LL*NN)=s3avg(1:LL*NN) endif @@ -92,8 +91,18 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & !### if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 enddo ! idt (DT loop) enddo ! idf (f0 loop) - if(iavg.eq.0 .and. abs(jpk0-4320).le.1300) then - s3avg(1:LL*NN)=s3avg(1:LL*NN)+s3a(1:LL*NN) +! if(iavg.eq.0 .and. abs(jpk0-4320).le.1300) then + if(iavg.eq.0) then + a=0. + a(1)=-f0 + call twkfreq(c00,c0,npts2,6000.0,a) +! jpk=4320 + jpk=4080 + call spec64(c0,nsps,mode,jpk,s3,LL,NN) + call pctile(s3,LL*NN,40,base) + s3=s3/base + where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim + s3avg(1:LL*NN)=s3avg(1:LL*NN)+s3(1:LL*NN) nsave=nsave+1 endif if(iavg.eq.0 .and. nsave.lt.2) exit From a17a5193241c26c7c0137a0454c58bfb48557594 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 19 Oct 2020 18:49:52 -0400 Subject: [PATCH 091/206] Send QRA65 navg to the callback routine. --- lib/qra_loops.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 3c9c2f1c3..0679e4d88 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -135,6 +135,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & !### nsave=0 s3avg=0. + irc=irc + 100*navg endif return end subroutine qra_loops From 7fe18a0a8ccfd1362817c17d5653acce211692a9 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 19 Oct 2020 18:56:54 -0400 Subject: [PATCH 092/206] Reset the default values in qra_params.f90. --- lib/qra64a.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index dd678ce3e..1a9728a8f 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -101,8 +101,8 @@ subroutine qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) integer iparam(6) logical first,ex -! data iparam/3,5,11,5,0,9/ !Maximum effort - data iparam/3,5,3,3,7,9/ !Default values +! data iparam/3,5,3,11,0,9/ !Maximum effort + data iparam/2,5,3,11,3,9/ !Default values data first/.true./ save first,iparam From 0ce65566117ee0f44bdf31ce58fa7e86486993d7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 20 Oct 2020 22:05:43 -0400 Subject: [PATCH 093/206] Slight reduction in snr1 limit after sync_qra65(). --- lib/qra65_decode.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index e7ff43626..ea021e4cb 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -119,7 +119,7 @@ contains call timer('sync_q65',1) irc=-1 - if(snr1.ge.2.7) then + if(snr1.ge.2.5) then jpk0=(xdt+1.0)*6000 !### if(jpk0.lt.0) jpk0=0 fac=1.0/32767.0 From b68ccee2fae3952f6184abc432b77d6c4feb29d6 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 22 Oct 2020 14:05:20 -0400 Subject: [PATCH 094/206] Correct a flaw in assigning bin numbers for in sync64(), fixing QRA65 submodes B C D E. --- lib/qra_loops.f90 | 4 ++-- lib/spec64.f90 | 15 +++++++++------ lib/sync_qra65.f90 | 11 +++++++++-- widgets/mainwindow.cpp | 2 +- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 0679e4d88..d6e2072f1 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -50,7 +50,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & jpk=jpk0 + 240*ndt !240/6000 = 0.04 s = tsym/32 if(jpk.lt.0) jpk=0 call timer('spec64 ',0) - call spec64(c0,nsps,mode,jpk,s3,LL,NN) + call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) call timer('spec64 ',1) call pctile(s3,LL*NN,40,base) s3=s3/base @@ -98,7 +98,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & call twkfreq(c00,c0,npts2,6000.0,a) ! jpk=4320 jpk=4080 - call spec64(c0,nsps,mode,jpk,s3,LL,NN) + call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) call pctile(s3,LL*NN,40,base) s3=s3/base where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim diff --git a/lib/spec64.f90 b/lib/spec64.f90 index 377e8dfcf..b6cc10c34 100644 --- a/lib/spec64.f90 +++ b/lib/spec64.f90 @@ -1,10 +1,11 @@ -subroutine spec64(c0,nsps,mode,jpk,s3,LL,NN) +subroutine spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) parameter (MAXFFT=3840) complex c0(0:360000) !Complex spectrum of dd() complex cs(0:MAXFFT-1) !Complex symbol spectrum real s3(LL,NN) !Synchronized symbol spectra real xbase0(LL),xbase(LL) +! integer ipk1(1) integer isync(22) !Indices of sync symbols data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ @@ -39,7 +40,7 @@ subroutine spec64(c0,nsps,mode,jpk,s3,LL,NN) cs(0:nfft-1)=fac*c0(ja:jb) call four2a(cs,nsps,1,-1,1) !c2c FFT to frequency do ii=1,LL - i=ii-65 + i=ii-65+mode64 !mode64 = 1 2 4 8 16 for QRA65 A B C D E if(i.lt.0) i=i+nsps s3(ii,j)=real(cs(i))**2 + aimag(cs(i))**2 enddo @@ -62,16 +63,18 @@ subroutine spec64(c0,nsps,mode,jpk,s3,LL,NN) s3(i,1:NN)=s3(i,1:NN)/(xbase(i)+0.001) !Apply frequency equalization enddo -! print*,'a',LL,NN,jpk +! print*,'a',LL,NN,jpk,mode,mode64 ! df=6000.0/nfft ! do i=1,LL ! write(71,3071) i,i-65,i*df,(s3(i,j),j=1,4) !3071 format(2i8,f10.3,4e12.3) ! enddo -! + ! do j=1,NN -! write(72,3072) j,maxloc(s3(1:LL,j)),maxloc(s3(1:LL,j))-65 -!3072 format(3i8) +! ipk1=maxloc(s3(1:LL,j)) +! m=ipk1(1)-65 +! write(72,3072) j,m,m/2,m/4,m/8 +!3072 format(5i8) ! enddo ! if(nfft.ne.-999) stop diff --git a/lib/sync_qra65.f90 b/lib/sync_qra65.f90 index 401efcc3c..c58241dbc 100644 --- a/lib/sync_qra65.f90 +++ b/lib/sync_qra65.f90 @@ -107,12 +107,19 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) endif enddo rms=sqrt(sq/nsq) - snr1=ccf(ipk,jpk)/rms + smax=ccf(ipk,jpk) + snr1=smax/rms ! do j=lag1,lag2 ! write(55,3055) j,j*dtstep,ccf(ipk,j)/rms !3055 format(i5,f8.3,f10.3) ! enddo - + +! ncall=ncall+1 +! do i=-ia,ia +! write(56,3056) ncall,i*df,ncall+0.3*ccf(i,0)/rms +!3056 format(i6,f7.2,f10.3) +! enddo + return end subroutine sync_qra65 diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index d211cbc1a..cd0152889 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6403,7 +6403,7 @@ void MainWindow::on_actionQRA65_triggered() m_hsymStop=49; ui->sbTR->values ({15, 30, 60, 120, 300}); on_sbTR_valueChanged (ui->sbTR->value()); - ui->sbSubmode->setMaximum(3); + ui->sbSubmode->setMaximum(4); ui->sbSubmode->setValue(m_nSubMode); m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); From 687d60019eef8151bd2fbb03bc49918d1317e4c6 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 22 Oct 2020 15:56:20 -0400 Subject: [PATCH 095/206] Working toward functionality for sequence lengths other than 60 s. --- lib/ana64.f90 | 11 ++++------- lib/qra64a.f90 | 3 ++- lib/qra65_decode.f90 | 2 +- lib/qra_loops.f90 | 6 ++---- lib/sync_qra65.f90 | 11 +++++------ 5 files changed, 14 insertions(+), 19 deletions(-) diff --git a/lib/ana64.f90 b/lib/ana64.f90 index faebb84e5..1f3b54820 100644 --- a/lib/ana64.f90 +++ b/lib/ana64.f90 @@ -2,20 +2,17 @@ subroutine ana64(dd,npts,c0) use timer_module, only: timer - parameter (NMAX=60*12000) !Max size of raw data at 12000 Hz - real dd(NMAX) !Raw data - complex c0(0:720000) !Complex spectrum of dd() + real dd(npts) !Raw data at 12000 Hz + complex c0(0:npts-1) !Complex data at 6000 Hz save -! nfft1=672000 - nfft1=720000 + nfft1=npts nfft2=nfft1/2 df1=12000.0/nfft1 fac=2.0/nfft1 c0(0:npts-1)=fac*dd(1:npts) - c0(npts:nfft1)=0. call four2a(c0,nfft1,1,-1,1) !Forward c2c FFT - c0(nfft2/2+1:nfft2)=0. + c0(nfft2/2+1:nfft2-1)=0. c0(0)=0.5*c0(0) call four2a(c0,nfft2,1,1,1) !Inverse c2c FFT; c0 is analytic sig diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index 1a9728a8f..45e44d8cf 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -61,8 +61,9 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & 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,64,mode64,nsubmode,nFadingModel, & + 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) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index ea021e4cb..4762e8419 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -127,7 +127,7 @@ contains nmode=65 call ana64(dd,npts,c00) call timer('qraloops',0) - call qra_loops(c00,npts/2,nmode,mode65,nsubmode,nFadingModel, & + call qra_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) call timer('qraloops',1) snr2=snr2 + db(6912.0/nsps) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index d6e2072f1..21dbc863d 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -1,4 +1,4 @@ -subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & +subroutine qra_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) use packjt @@ -26,8 +26,6 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & NN=63 napmin=99 ncall=0 - nsps=3456 !QRA64 - if(mode.eq.65) nsps=3840 !QRA65 ### Is 3840 too big? ### maxdist=5 if(ndepth.eq.2) maxdist=10 if(ndepth.eq.3) maxdist=30 @@ -121,7 +119,7 @@ subroutine qra_loops(c00,npts2,mode,mode64,nsubmode,nFadingModel, & ndist=ndistx endif -200 if(mode.eq.65) xdt=xdt+0.4 !### Empirical -- WHY ??? ### +200 if(mode.eq.65 .and. nsps.eq.7680/2) xdt=xdt+0.4 !### Empirical -- WHY ??? ### if(irc.ge.0) then navg=nsave diff --git a/lib/sync_qra65.f90 b/lib/sync_qra65.f90 index c58241dbc..3b608f20a 100644 --- a/lib/sync_qra65.f90 +++ b/lib/sync_qra65.f90 @@ -18,7 +18,7 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) integer ijpk(2) !Indices i and j at peak of ccf real, allocatable :: s1(:,:) !Symbol spectra, quarter-symbol steps real sync(85) !sync vector - real ccf(-64:64,-26:107) !CCF(freq,time) + real ccf(-64:64,-53:214) !CCF(freq,time) complex, allocatable :: c0(:) !Complex spectrum of symbol data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data sync(1)/99.0/ @@ -94,10 +94,10 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) ijpk=maxloc(ccf) ipk=ijpk(1)-65 - jpk=ijpk(2)-27 + jpk=ijpk(2)-54 f0=nfqso + ipk*df xdt=jpk*dtstep - + sq=0. nsq=0 do j=lag1,lag2 @@ -115,10 +115,9 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) !3055 format(i5,f8.3,f10.3) ! enddo -! ncall=ncall+1 ! do i=-ia,ia -! write(56,3056) ncall,i*df,ncall+0.3*ccf(i,0)/rms -!3056 format(i6,f7.2,f10.3) +! write(56,3056) i*df,ccf(i,0)/rms +!3056 format(2f10.3) ! enddo return From 37e5489080e57f33a5aa78075f3d38f1535ac9dd Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 22 Oct 2020 19:07:21 -0400 Subject: [PATCH 096/206] QRA65 submodes A-E now basically OK for 15, 30, 60, 120 s sequences; 300 s is NG. --- lib/qra65_decode.f90 | 3 ++- lib/spec64.f90 | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/qra65_decode.f90 b/lib/qra65_decode.f90 index 4762e8419..6c6cf29ae 100644 --- a/lib/qra65_decode.f90 +++ b/lib/qra65_decode.f90 @@ -120,7 +120,8 @@ contains irc=-1 if(snr1.ge.2.5) then - jpk0=(xdt+1.0)*6000 !### + jpk0=(xdt+1.0)*6000 !### + if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### if(jpk0.lt.0) jpk0=0 fac=1.0/32767.0 dd=fac*iwave diff --git a/lib/spec64.f90 b/lib/spec64.f90 index b6cc10c34..9a62434ee 100644 --- a/lib/spec64.f90 +++ b/lib/spec64.f90 @@ -1,7 +1,8 @@ subroutine spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) - parameter (MAXFFT=3840) - complex c0(0:360000) !Complex spectrum of dd() + parameter (MAXFFT=20736) +!### Fix this: + complex c0(0:1800000-1) !Complex spectrum of dd() complex cs(0:MAXFFT-1) !Complex symbol spectrum real s3(LL,NN) !Synchronized symbol spectra real xbase0(LL),xbase(LL) @@ -76,7 +77,6 @@ subroutine spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) ! write(72,3072) j,m,m/2,m/4,m/8 !3072 format(5i8) ! enddo -! if(nfft.ne.-999) stop return end subroutine spec64 From 90fb84e43ed144de741922ac398e483797272baf Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 22 Oct 2020 19:20:56 -0400 Subject: [PATCH 097/206] All QRA65 submodes and sequence lengths 15 - 300 s are now basically functional. --- lib/qra_loops.f90 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index 21dbc863d..a835ed5e9 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -5,8 +5,8 @@ subroutine qra_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & use timer_module, only: timer parameter (LN=1152*63) character*37 decoded - complex c00(0:720000) !Analytic representation of dd(), 6000 Hz - complex c0(0:720000) !Ditto, with freq shift + complex c00(0:npts2-1) !Analytic representation of dd(), 6000 Hz + complex ,allocatable :: c0(:) !Ditto, with freq shift real a(3) !twkfreq params f,f1,f2 real s3(LN) !Symbol spectra real s3avg(LN) !Averaged symbol spectra @@ -15,6 +15,7 @@ subroutine qra_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & data nap/0,2,3,2,3,4,2,3,6,4,6,6/,nsave/0/ save nsave,s3avg + allocate(c0(0:npts2-1)) irc=-99 s3lim=20. ibwmax=11 From 9b452e8f993f20932dbef8b81ade6071ceacd332 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 25 Oct 2020 13:58:18 -0400 Subject: [PATCH 098/206] Change mode name QRA65 to Q65 everywhere, supposedly. --- CMakeLists.txt | 14 ++--- Modulator/Modulator.cpp | 3 +- lib/decoder.f90 | 42 +++++++-------- lib/{qra65_decode.f90 => q65_decode.f90} | 28 +++++----- lib/q65params.f90 | 20 ++++++++ lib/qra/qra65/{qra65sim.f90 => q65sim.f90} | 12 ++--- lib/qra64a.f90 | 13 ++--- lib/qra_loops.f90 | 10 ++-- lib/spec64.f90 | 2 +- lib/{sync_qra65.f90 => sync_q65.f90} | 6 +-- lib/{test_qra65.f90 => test_q65.f90} | 60 ++++++++++++---------- models/FrequencyList.cpp | 2 +- models/Modes.cpp | 2 +- models/Modes.hpp | 2 +- widgets/mainwindow.cpp | 50 +++++++++--------- widgets/mainwindow.h | 4 +- widgets/mainwindow.ui | 6 +-- widgets/plotter.cpp | 8 +-- 18 files changed, 154 insertions(+), 130 deletions(-) rename lib/{qra65_decode.f90 => q65_decode.f90} (89%) create mode 100644 lib/q65params.f90 rename lib/qra/qra65/{qra65sim.f90 => q65sim.f90} (94%) rename lib/{sync_qra65.f90 => sync_q65.f90} (95%) rename lib/{test_qra65.f90 => test_q65.f90} (66%) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05cf0ae6a..1ac4ad4f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -324,7 +324,7 @@ set (wsjt_FSRCS lib/options.f90 lib/packjt.f90 lib/77bit/packjt77.f90 - lib/qra65_decode.f90 + lib/q65_decode.f90 lib/readwav.f90 lib/timer_C_wrapper.f90 lib/timer_impl.f90 @@ -525,7 +525,7 @@ set (wsjt_FSRCS lib/sync4.f90 lib/sync64.f90 lib/sync65.f90 - lib/sync_qra65.f90 + lib/sync_q65.f90 lib/ft4/getcandidates4.f90 lib/ft4/get_ft4_bitmetrics.f90 lib/ft8/sync8.f90 @@ -1114,14 +1114,14 @@ target_link_libraries (sumsim wsjt_fort wsjt_cxx) add_executable (qra64sim lib/qra/qra64/qra64sim.f90) target_link_libraries (qra64sim wsjt_fort wsjt_cxx) -add_executable (qra65sim lib/qra/qra65/qra65sim.f90) -target_link_libraries (qra65sim wsjt_fort wsjt_cxx) +add_executable (q65sim lib/qra/qra65/q65sim.f90) +target_link_libraries (q65sim wsjt_fort wsjt_cxx) add_executable (test_qra64 lib/test_qra64.f90) target_link_libraries (test_qra64 wsjt_fort wsjt_cxx) -add_executable (test_qra65 lib/test_qra65.f90) -target_link_libraries (test_qra65 wsjt_fort wsjt_cxx) +add_executable (test_q65 lib/test_q65.f90) +target_link_libraries (test_q65 wsjt_fort wsjt_cxx) add_executable (jt49sim lib/jt49sim.f90) target_link_libraries (jt49sim wsjt_fort wsjt_cxx) @@ -1545,7 +1545,7 @@ install (TARGETS jt9 wsprd fmtave fcal fmeasure if(WSJT_BUILD_UTILS) install (TARGETS ft8code jt65code qra64code qra64sim jt9code jt4code - msk144code fst4sim qra65sim + msk144code fst4sim q65sim RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT runtime ) diff --git a/Modulator/Modulator.cpp b/Modulator/Modulator.cpp index df096131b..32645bec2 100644 --- a/Modulator/Modulator.cpp +++ b/Modulator/Modulator.cpp @@ -70,7 +70,8 @@ void Modulator::start (QString mode, unsigned symbolsLength, double framesPerSym m_bFastMode=fastMode; m_TRperiod=TRperiod; unsigned delay_ms=1000; - if(mode=="FT8" or (mode=="FST4" and m_nsps==720) or mode=="QRA65") delay_ms=500; //FT8, FST4-15, QRA65 + if(mode=="FT8" or (mode=="FST4" and m_nsps==720)) delay_ms=500; //FT8, FST4-15 + if(mode=="Q65" and m_nsps<=3600) delay_ms=500; //Q65-15 and Q65-30 if(mode=="FT4") delay_ms=300; //FT4 // noise generator parameters diff --git a/lib/decoder.f90 b/lib/decoder.f90 index f70d07108..911352277 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -9,7 +9,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) use ft8_decode use ft4_decode use fst4_decode - use qra65_decode + use q65_decode include 'jt9com.f90' include 'timer_common.inc' @@ -38,9 +38,9 @@ subroutine multimode_decoder(ss,id2,params,nfsample) integer :: decoded end type counting_fst4_decoder - type, extends(qra65_decoder) :: counting_qra65_decoder + type, extends(q65_decoder) :: counting_q65_decoder integer :: decoded - end type counting_qra65_decoder + end type counting_q65_decoder real ss(184,NSMAX) logical baddata,newdat65,newdat9,single_decode,bVHF,bad0,newdat,ex @@ -59,7 +59,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) type(counting_ft8_decoder) :: my_ft8 type(counting_ft4_decoder) :: my_ft4 type(counting_fst4_decoder) :: my_fst4 - type(counting_qra65_decoder) :: my_qra65 + type(counting_q65_decoder) :: my_q65 rms=sqrt(dot_product(float(id2(1:180000)), & float(id2(1:180000)))/180000.0) @@ -79,7 +79,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) my_ft8%decoded = 0 my_ft4%decoded = 0 my_fst4%decoded = 0 - my_qra65%decoded = 0 + my_q65%decoded = 0 ! For testing only: return Rx messages stored in a file as decodes inquire(file='rx_messages.txt',exist=ex) @@ -198,13 +198,13 @@ subroutine multimode_decoder(ss,id2,params,nfsample) go to 800 endif - if(params%nmode.eq.66) then !NB: JT65 = 65, QRA65 = 66. -! We're in QRA65 mode - call timer('decqra65',0) - call my_qra65%decode(qra65_decoded,id2,params%nutc,params%ntr, & + if(params%nmode.eq.66) then !NB: JT65 = 65, Q65 = 66. +! We're in Q65 mode + call timer('dec_q65 ',0) + call my_q65%decode(q65_decoded,id2,params%nutc,params%ntr, & params%nsubmode,params%nfqso,params%ntol,params%ndepth, & mycall,hiscall,hisgrid) - call timer('decqra65',1) + call timer('dec_q65 ',1) go to 800 endif @@ -213,13 +213,13 @@ subroutine multimode_decoder(ss,id2,params,nfsample) ndepth=iand(params%ndepth,3) iwspr=0 params%nsubmode=0 - call timer('dec240 ',0) + call timer('dec_fst4',0) call my_fst4%decode(fst4_decoded,id2,params%nutc, & params%nQSOProgress,params%nfa,params%nfb, & params%nfqso,ndepth,params%ntr,params%nexp_decode, & params%ntol,params%emedelay,logical(params%nagain), & logical(params%lapcqonly),mycall,hiscall,iwspr) - call timer('dec240 ',1) + call timer('dec_fst4',1) go to 800 endif @@ -227,13 +227,13 @@ subroutine multimode_decoder(ss,id2,params,nfsample) ! We're in FST4W mode ndepth=iand(params%ndepth,3) iwspr=1 - call timer('dec240 ',0) + call timer('dec_fst4',0) call my_fst4%decode(fst4_decoded,id2,params%nutc, & params%nQSOProgress,params%nfa,params%nfb, & params%nfqso,ndepth,params%ntr,params%nexp_decode, & params%ntol,params%emedelay,logical(params%nagain), & logical(params%lapcqonly),mycall,hiscall,iwspr) - call timer('dec240 ',1) + call timer('dec_fst4',1) go to 800 endif @@ -776,13 +776,13 @@ contains return end subroutine fst4_decoded - subroutine qra65_decoded (this,nutc,sync,nsnr,dt,freq,decoded,irc, & + subroutine q65_decoded (this,nutc,sync,nsnr,dt,freq,decoded,irc, & qual,ntrperiod,fmid,w50) - use qra65_decode + use q65_decode implicit none - class(qra65_decoder), intent(inout) :: this + class(q65_decoder), intent(inout) :: this integer, intent(in) :: nutc real, intent(in) :: sync integer, intent(in) :: nsnr @@ -801,23 +801,23 @@ contains write(*,1001) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg 1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded -1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA65') +1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') else write(*,1003) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg 1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded -1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' QRA65') +1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') endif call flush(6) call flush(13) select type(this) - type is (counting_qra65_decoder) + type is (counting_q65_decoder) this%decoded = this%decoded + 1 end select return - end subroutine qra65_decoded + end subroutine q65_decoded end subroutine multimode_decoder diff --git a/lib/qra65_decode.f90 b/lib/q65_decode.f90 similarity index 89% rename from lib/qra65_decode.f90 rename to lib/q65_decode.f90 index 6c6cf29ae..8b522ce2e 100644 --- a/lib/qra65_decode.f90 +++ b/lib/q65_decode.f90 @@ -1,17 +1,17 @@ -module qra65_decode +module q65_decode - type :: qra65_decoder - procedure(qra65_decode_callback), pointer :: callback + type :: q65_decoder + procedure(q65_decode_callback), pointer :: callback contains procedure :: decode - end type qra65_decoder + end type q65_decoder abstract interface - subroutine qra65_decode_callback (this,nutc,sync,nsnr,dt,freq, & + subroutine q65_decode_callback (this,nutc,sync,nsnr,dt,freq, & decoded,nap,qual,ntrperiod,fmid,w50) - import qra65_decoder + import q65_decoder implicit none - class(qra65_decoder), intent(inout) :: this + class(q65_decoder), intent(inout) :: this integer, intent(in) :: nutc real, intent(in) :: sync integer, intent(in) :: nsnr @@ -23,7 +23,7 @@ module qra65_decode integer, intent(in) :: ntrperiod real, intent(in) :: fmid real, intent(in) :: w50 - end subroutine qra65_decode_callback + end subroutine q65_decode_callback end interface contains @@ -31,7 +31,7 @@ contains subroutine decode(this,callback,iwave,nutc,ntrperiod,nsubmode,nfqso, & ntol,ndepth,mycall,hiscall,hisgrid) -! Decodes QRA65 signals +! Decodes Q65 signals ! Input: iwave Raw data, i*2 ! nutc UTC for time-tagging the decode ! ntrperiod T/R sequence length (s) @@ -45,8 +45,8 @@ contains use packjt use, intrinsic :: iso_c_binding parameter (NMAX=300*12000) !Max TRperiod is 300 s - class(qra65_decoder), intent(inout) :: this - procedure(qra65_decode_callback) :: callback + class(q65_decoder), intent(inout) :: this + procedure(q65_decode_callback) :: callback character(len=12) :: mycall, hiscall !Used for AP decoding character(len=6) :: hisgrid character*37 decoded !Decoded message @@ -98,7 +98,7 @@ contains ! if(ndepth.eq.3) maxaptype=5 if(ndepth.ge.2) maxaptype=5 !### minsync=-2 - call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax) + 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 @@ -115,7 +115,7 @@ contains naptype=maxaptype call timer('sync_q65',0) - call sync_qra65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1) + call sync_q65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1) call timer('sync_q65',1) irc=-1 @@ -159,4 +159,4 @@ contains return end subroutine decode -end module qra65_decode +end module q65_decode diff --git a/lib/q65params.f90 b/lib/q65params.f90 new file mode 100644 index 000000000..c519cc94e --- /dev/null +++ b/lib/q65params.f90 @@ -0,0 +1,20 @@ +program q65params + + integer ntrp(5) + integer nsps(5) + data ntrp/15,30,60,120,300/ + data nsps/1800,3600,7200,15680,40960/ + + write(*,1000) +1000 format('T/R tsym baud BW TxT SNR'/39('-')) + do i=1,5 + baud=12000.0/nsps(i) + bw=65.0*baud + tsym=1.0/baud + txt=85.0*tsym + snr=-27.0 + 10.0*log10(7200.0/nsps(i)) + write(*,1010) ntrp(i),tsym,baud,bw,txt,snr +1010 format(i3,2f7.3,3f7.1) + enddo + +end program q65params diff --git a/lib/qra/qra65/qra65sim.f90 b/lib/qra/qra65/q65sim.f90 similarity index 94% rename from lib/qra/qra65/qra65sim.f90 rename to lib/qra/qra65/q65sim.f90 index 62ec63f57..03696a0ae 100644 --- a/lib/qra/qra65/qra65sim.f90 +++ b/lib/qra/qra65/q65sim.f90 @@ -1,6 +1,6 @@ -program qra65sim +program q65sim -! Generate simulated QRA65 data for testing the decoder. +! Generate simulated Q65 data for testing the decoder. use wavhdr use packjt @@ -21,8 +21,8 @@ program qra65sim nargs=iargc() if(nargs.ne.9) then - print *, 'Usage: qra65sim "msg" A-E freq fDop DT TRp Nfiles Sync SNR' - print *, 'Example: qra65sim "K1ABC W9XYZ EN37" A 1500 0.0 0.0 60 1 T -26' + print *, 'Usage: q65sim "msg" A-E freq fDop DT TRp Nfiles Sync SNR' + print *, 'Example: q65sim "K1ABC W9XYZ EN37" A 1500 0.0 0.0 60 1 T -26' print*,'Sync = T to include sync test.' go to 999 endif @@ -185,7 +185,7 @@ program qra65sim if(ifile.eq.nfiles) cd='d' nfqso=nint(f0) ntol=100 - call sync_qra65(iwave,npts,mode65,nsps,nfqso,ntol,xdt2,f02,snr2) + call sync_q65(iwave,npts,mode65,nsps,nfqso,ntol,xdt2,f02,snr2) terr=1.01/(8.0*baud) ferr=1.01*mode65*baud if(abs(xdt2-xdt).lt.terr .and. abs(f02-f0).lt.ferr) nsync=nsync+1 @@ -199,4 +199,4 @@ program qra65sim if(lsync) write(*,1040) snrdb,nfiles,nsync 1040 format('SNR:',f6.1,' nfiles:',i5,' nsynced:',i5) -999 end program qra65sim +999 end program q65sim diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index 45e44d8cf..c0d501fd7 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -37,7 +37,7 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & nFadingModel=1 maxaptype=4 if(iand(ndepth,64).ne.0) maxaptype=5 - call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax) + 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 @@ -96,14 +96,14 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & return end subroutine qra64a -subroutine qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) +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(6) + integer iparam(7) logical first,ex -! data iparam/3,5,3,11,0,9/ !Maximum effort - data iparam/2,5,3,11,3,9/ !Default values +! data iparam/3,5,3,11,0,9,30/ !Maximum effort + data iparam/2,5,3,11,3,9,10/ !Default values data first/.true./ save first,iparam @@ -122,6 +122,7 @@ subroutine qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax) idt0max=iparam(4) ibwmin=iparam(5) ibwmax=iparam(6) - + maxdist=iparam(7) + return end subroutine qra_params diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index a835ed5e9..c2155aeba 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -22,14 +22,11 @@ subroutine qra_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & if(mode64.le.4) ibwmax=9 ibwmin=ibwmax idtmax=3 - call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax) + call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist) LL=64*(mode64+2) NN=63 napmin=99 ncall=0 - maxdist=5 - if(ndepth.eq.2) maxdist=10 - if(ndepth.eq.3) maxdist=30 do iavg=0,1 if(iavg.eq.1) then @@ -95,8 +92,9 @@ subroutine qra_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & a=0. a(1)=-f0 call twkfreq(c00,c0,npts2,6000.0,a) -! jpk=4320 - jpk=4080 + jpk=3000 !### These definitions need work ### +! if(nsps.ge.3600) jpk=4080 !### + if(nsps.ge.3600) jpk=6000 !### call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) call pctile(s3,LL*NN,40,base) s3=s3/base diff --git a/lib/spec64.f90 b/lib/spec64.f90 index 9a62434ee..0bf30e679 100644 --- a/lib/spec64.f90 +++ b/lib/spec64.f90 @@ -41,7 +41,7 @@ subroutine spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) cs(0:nfft-1)=fac*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 QRA65 A B C D E + 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 diff --git a/lib/sync_qra65.f90 b/lib/sync_q65.f90 similarity index 95% rename from lib/sync_qra65.f90 rename to lib/sync_q65.f90 index 3b608f20a..8df6da47f 100644 --- a/lib/sync_qra65.f90 +++ b/lib/sync_q65.f90 @@ -1,6 +1,6 @@ -subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) +subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) -! Detect and align with the QRA65 sync vector, returning time and frequency +! Detect and align with the Q65 sync vector, returning time and frequency ! offsets and SNR estimate. ! Input: iwave(0:nmax-1) Raw data @@ -121,4 +121,4 @@ subroutine sync_qra65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) ! enddo return -end subroutine sync_qra65 +end subroutine sync_q65 diff --git a/lib/test_qra65.f90 b/lib/test_q65.f90 similarity index 66% rename from lib/test_qra65.f90 rename to lib/test_q65.f90 index 5b881d6ba..c56fa0bab 100644 --- a/lib/test_qra65.f90 +++ b/lib/test_q65.f90 @@ -1,4 +1,4 @@ -program test_qra65 +program test_q65 character*73 cmd1,cmd2,line character*22 msg @@ -9,8 +9,8 @@ program test_qra65 nargs=iargc() if(nargs.ne.9) then - print*,'Usage: test_qra65 "msg" A-D depth freq DT fDop TRp nfiles SNR' - print*,'Example: test_qra65 "K1ABC W9XYZ EN37" A 3 1500 0.0 5.0 60 100 -20' + print*,'Usage: test_q65 "msg" A-D depth freq DT fDop TRp nfiles SNR' + print*,'Example: test_q65 "K1ABC W9XYZ EN37" A 3 1500 0.0 5.0 60 100 -20' print*,' SNR = 0 to loop over all relevant SNRs' go to 999 endif @@ -61,7 +61,7 @@ program test_qra65 ! 1 2 3 4 5 6 7 ! 1234567890123456789012345678901234567890123456789012345678901234567890123' - cmd1='qra65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 F -10 > junk0' + cmd1='q65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 F -10 > junk0' cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A *.wav > junk' write(cmd1(10:33),'(a)') '"'//msg//'"' @@ -71,25 +71,32 @@ program test_qra65 write(cmd1(46:50),'(f5.2)') dt write(cmd1(51:54),'(i4)') ntrperiod write(cmd1(55:59),'(i5)') nfiles + write(cmd2(11:13),'(i3)') ntrperiod write(cmd2(33:33),'(i1)') ndepth cmd2(38:38)=csubmode call system('rm -f *.wav') - write(*,1000) (j,j=0,11) - write(12,1000) (j,j=0,11) -1000 format(/'SNR d Dop Sync Dec1 DecN Bad',i6,11i4,' tdec'/85('-')) + call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist) + write(*,1000) ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist + write(12,1000) ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist +1000 format(/'Depth:',i2,' AP:',i2,' df:',i3,' dt:',i3,' bw1:',i3,' bw2:',i3, & + ' dist:',i3) + + write(*,1010) (j,j=0,11) + write(12,1010) (j,j=0,11) +1010 format('SNR d Dop Sync DecN Dec1 Bad',i6,11i4,' tdec'/85('-')) dterr=tsym/4.0 nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) - ndecodes0=nfiles + ndec10=nfiles do nsnr=ia,ib,-1 nsync=0 - ndecodes=0 + ndec1=0 nfalse=0 nretcode=0 - navg=0 + ndecn=0 write(cmd1(63:65),'(i3)') nsnr call system(cmd1) call sec0(0,tdec) @@ -107,18 +114,15 @@ program test_qra65 nsync=nsync+1 endif irc=-1 - if(line(23:23).ne.' ') read(line(60:),*) irc,iavg + iavg=0 + i0=23 + if(ntrperiod.le.30) i0=25 + if(line(i0:i0).ne.' ') read(line(60:),*) irc,iavg if(irc.lt.0) cycle if(decok) then - i=irc - if(i.le.11) then - ndecodes=ndecodes + 1 - navg=navg + 1 - else - i=mod(i,10) - navg=navg + 1 - endif - nretcode(i)=nretcode(i) + 1 + ndecn=ndecn + 1 + if(iavg.le.1) ndec1=ndec1 + 1 + nretcode(irc)=nretcode(irc) + 1 else nfalse=nfalse + 1 print*,'False: ',line @@ -127,24 +131,24 @@ program test_qra65 10 close(10) xdt_avg=0. xdt_rms=0. - write(*,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode, & + write(*,1100) nsnr,ndepth,fDop,nsync,ndecn,ndec1,nfalse,nretcode, & tdec/nfiles - write(12,1100) nsnr,ndepth,fDop,nsync,ndecodes,navg,nfalse,nretcode, & + write(12,1100) nsnr,ndepth,fDop,nsync,ndecn,ndec1,nfalse,nretcode, & tdec/nfiles 1100 format(i3,i2,f5.1,3i5,i4,i6,11i4,f6.2) - if(ndecodes.lt.nfiles/2 .and. ndecodes0.ge.nfiles/2) then - snr_thresh=nsnr + float(nfiles/2 - ndecodes)/(ndecodes0-ndecodes) + if(ndec1.lt.nfiles/2 .and. ndec10.ge.nfiles/2) then + snr_thresh=nsnr + float(nfiles/2 - ndec1)/(ndec10-ndec1) write(13,1200) ndepth,fdop,csubmode,snr_thresh 1200 format(i1,f6.1,2x,a1,f7.1) flush(13) endif flush(6) flush(12) - if(ndecodes.eq.0) exit !Bail out if no decodes at this SNR - ndecodes0=ndecodes + if(ndec1.eq.0 .and. ndecn.eq.0) exit !Bail out if no decodes at this SNR + ndec10=ndec1 enddo ! nsnr -999 end program test_qra65 +999 end program test_q65 - include 'sec0.f90' +include 'sec0.f90' diff --git a/models/FrequencyList.cpp b/models/FrequencyList.cpp index bb2d1738f..2662e24ff 100644 --- a/models/FrequencyList.cpp +++ b/models/FrequencyList.cpp @@ -263,7 +263,7 @@ namespace {50200000, Modes::Echo, IARURegions::ALL}, {50270000, Modes::QRA64, IARURegions::ALL}, - {50270000, Modes::QRA65, IARURegions::ALL}, + {50270000, Modes::Q65, IARURegions::ALL}, {50276000, Modes::JT65, IARURegions::R2}, {50276000, Modes::JT65, IARURegions::R3}, {50380000, Modes::MSK144, IARURegions::R1}, diff --git a/models/Modes.cpp b/models/Modes.cpp index deaa2a0f6..0d3c544d4 100644 --- a/models/Modes.cpp +++ b/models/Modes.cpp @@ -27,7 +27,7 @@ namespace "FT4", "FST4", "FST4W", - "QRA65" + "Q65" }; std::size_t constexpr mode_names_size = sizeof (mode_names) / sizeof (mode_names[0]); } diff --git a/models/Modes.hpp b/models/Modes.hpp index 2f3bf60f7..132ca8657 100644 --- a/models/Modes.hpp +++ b/models/Modes.hpp @@ -52,7 +52,7 @@ public: FT4, FST4, FST4W, - QRA65, + Q65, MODES_END_SENTINAL_AND_COUNT // this must be last }; Q_ENUM (Mode) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index cd0152889..f835e9f31 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -602,7 +602,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionISCAT->setActionGroup(modeGroup); ui->actionMSK144->setActionGroup(modeGroup); ui->actionQRA64->setActionGroup(modeGroup); - ui->actionQRA65->setActionGroup(modeGroup); + ui->actionQ65->setActionGroup(modeGroup); ui->actionFreqCal->setActionGroup(modeGroup); QActionGroup* saveGroup = new QActionGroup(this); @@ -1382,7 +1382,7 @@ void MainWindow::fixStop() } else if (m_mode=="QRA64"){ m_hsymStop=179; if(m_config.decode_at_52s()) m_hsymStop=186; - } else if (m_mode=="QRA65"){ + } else if (m_mode=="Q65"){ m_hsymStop=48; if(m_TRperiod==30) m_hsymStop=96; if(m_TRperiod==60) m_hsymStop=196; @@ -2379,7 +2379,7 @@ void MainWindow::setup_status_bar (bool vhf) mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #66ff66}"); } else if ("QRA64" == m_mode) { mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #99ff33}"); - } else if ("QRA65" == m_mode) { + } else if ("Q65" == m_mode) { mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #99ff33}"); } else if ("MSK144" == m_mode) { mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff6666}"); @@ -2581,7 +2581,7 @@ void MainWindow::on_actionCopyright_Notice_triggered() "notice prominently in your derivative work:\n\n" "\"The algorithms, source code, look-and-feel of WSJT-X and related " "programs, and protocol specifications for the modes FSK441, FST4, FT8, " - "JT4, JT6M, JT9, JT65, JTMS, QRA64, QRA65, ISCAT, MSK144 are Copyright (C) " + "JT4, JT6M, JT9, JT65, JTMS, QRA64, Q65, ISCAT, MSK144 are Copyright (C) " "2001-2020 by one or more of the following authors: Joseph Taylor, " "K1JT; Bill Somerville, G4WJS; Steven Franke, K9AN; Nico Palermo, " "IV3NWV; Greg Beam, KI7MT; Michael Black, W9MDB; Edson Pereira, PY2SDR; " @@ -3110,8 +3110,8 @@ void MainWindow::decode() //decode() ui->actionEnable_AP_JT65->isChecked (); if(m_mode=="QRA64") dec_data.params.nmode=164; if(m_mode=="QRA64") dec_data.params.ntxmode=164; - if(m_mode=="QRA65") dec_data.params.nmode=66; - if(m_mode=="QRA65") dec_data.params.ntxmode=66; + if(m_mode=="Q65") dec_data.params.nmode=66; + if(m_mode=="Q65") dec_data.params.ntxmode=66; if(m_mode=="JT9+JT65") dec_data.params.nmode=9+65; // = 74 if(m_mode=="JT4") { dec_data.params.nmode=4; @@ -3434,7 +3434,7 @@ void MainWindow::readFromStdout() //readFromStdout //Right (Rx Frequency) window bool bDisplayRight=bAvgMsg; int audioFreq=decodedtext.frequencyOffset(); - if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="FST4" or m_mode=="QRA65") { + if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="FST4" or m_mode=="Q65") { auto const& parts = decodedtext.string().remove("<").remove(">") .split (' ', SkipEmptyParts); if (parts.size() > 6) { @@ -3517,7 +3517,7 @@ void MainWindow::readFromStdout() //readFromStdout //### I think this is where we are preventing Hounds from spotting Fox ### if(m_mode!="FT8" or (SpecOp::HOUND != m_config.special_op_id())) { - if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="QRA64" or m_mode=="QRA65" + if(m_mode=="FT8" or m_mode=="FT4" or m_mode=="QRA64" or m_mode=="Q65" or m_mode=="JT4" or m_mode=="JT65" or m_mode=="JT9" or m_mode=="FST4") { auto_sequence (decodedtext, 25, 50); } @@ -3727,7 +3727,7 @@ void MainWindow::guiUpdate() if(m_modeTx=="JT9") txDuration=1.0 + 85.0*m_nsps/12000.0; // JT9 if(m_modeTx=="JT65") txDuration=1.0 + 126*4096/11025.0; // JT65 if(m_modeTx=="QRA64") txDuration=1.0 + 84*6912/12000.0; // QRA64 - if(m_modeTx=="QRA65") { // QRA65 + if(m_modeTx=="Q65") { // Q65 if(m_TRperiod==15) txDuration=0.5 + 85*1800/12000.0; if(m_TRperiod==30) txDuration=0.5 + 85*3600/12000.0; if(m_TRperiod==60) txDuration=1.0 + 85*7680/12000.0; @@ -3985,7 +3985,7 @@ void MainWindow::guiUpdate() &m_currentMessageType, 22, 22); if(m_modeTx=="QRA64") genqra64_(message, &ichk, msgsent, const_cast (itone), &m_currentMessageType, 22, 22); - if(m_modeTx=="QRA65") { + if(m_modeTx=="Q65") { int ichk65=65; genqra64_(message, &ichk65, msgsent, const_cast (itone), &m_currentMessageType, 22, 22); @@ -4703,7 +4703,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie || ("JT9" == m_mode && mode != "@") || ("MSK144" == m_mode && !("&" == mode || "^" == mode)) || ("QRA64" == m_mode && mode.left (1) != ":")) { - return; //Currently we do auto-sequencing only in FT4, FT8, MSK144, FST4, and QRA65 + return; //Currently we do auto-sequencing only in FT4, FT8, MSK144, FST4, and Q65 } //Skip the rest if no decoded text extracted @@ -4811,7 +4811,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie ui->TxFreqSpinBox->setValue(frequency); } if(m_mode != "JT4" && m_mode != "JT65" && !m_mode.startsWith ("JT9") && - m_mode != "QRA64" && m_mode != "QRA65" && m_mode!="FT8" && + m_mode != "QRA64" && m_mode != "Q65" && m_mode!="FT8" && m_mode!="FT4" && m_mode!="FST4") { return; } @@ -6389,13 +6389,13 @@ void MainWindow::on_actionQRA64_triggered() statusChanged(); } -void MainWindow::on_actionQRA65_triggered() +void MainWindow::on_actionQ65_triggered() { // on_actionFST4_triggered(); - m_mode="QRA65"; - m_modeTx="QRA65"; - ui->actionQRA65->setChecked(true); - switch_mode(Modes::QRA65); + m_mode="Q65"; + m_modeTx="Q65"; + ui->actionQ65->setChecked(true); + switch_mode(Modes::Q65); setup_status_bar(true); m_nsps=6912; //For symspec only m_FFTSize = m_nsps / 2; @@ -6411,7 +6411,7 @@ void MainWindow::on_actionQRA65_triggered() m_wideGraph->setTol(ui->sbFtol->value()); m_wideGraph->setRxFreq(ui->RxFreqSpinBox->value()); m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); - switch_mode (Modes::QRA65); + switch_mode (Modes::Q65); // 012345678901234567890123456789012345 displayWidgets(nWidgets("111111010110110100010000001100000000")); statusChanged(); @@ -6464,7 +6464,7 @@ void MainWindow::on_actionMSK144_triggered() if("JT9_JT65"==m_mode) ui->actionJT9_JT65->setChecked(true); if("ISCAT"==m_mode) ui->actionISCAT->setChecked(true); if("QRA64"==m_mode) ui->actionQRA64->setChecked(true); - if("QRA65"==m_mode) ui->actionQRA65->setChecked(true); + if("Q65"==m_mode) ui->actionQ65->setChecked(true); if("WSPR"==m_mode) ui->actionWSPR->setChecked(true); if("Echo"==m_mode) ui->actionEcho->setChecked(true); if("FreqCal"==m_mode) ui->actionFreqCal->setChecked(true); @@ -7312,7 +7312,7 @@ void MainWindow::transmit (double snr) true, false, snr, m_TRperiod); } - if (m_modeTx == "QRA65") { + if (m_modeTx == "Q65") { int nsps=1800; if(m_TRperiod==30) nsps=3600; if(m_TRperiod==60) nsps=7680; @@ -7320,7 +7320,7 @@ void MainWindow::transmit (double snr) if(m_TRperiod==300) nsps=41472; int mode65=pow(2.0,double(m_nSubMode)); toneSpacing=mode65*12000.0/nsps; - Q_EMIT sendMessage (m_mode, NUM_QRA65_SYMBOLS, + Q_EMIT sendMessage (m_mode, NUM_Q65_SYMBOLS, double(nsps), ui->TxFreqSpinBox->value () - m_XIT, toneSpacing, m_soundOutput, m_config.audio_output_channel (), true, false, snr, m_TRperiod); @@ -7581,9 +7581,9 @@ void::MainWindow::VHF_features_enabled(bool b) void MainWindow::on_sbTR_valueChanged(int value) { // if(!m_bFastMode and n>m_nSubMode) m_MinW=m_nSubMode; - if(m_bFastMode or m_mode=="FreqCal" or m_mode=="FST4" or m_mode=="FST4W" or m_mode=="QRA65") { + if(m_bFastMode or m_mode=="FreqCal" or m_mode=="FST4" or m_mode=="FST4W" or m_mode=="Q65") { m_TRperiod = value; - if (m_mode == "FST4" || m_mode == "FST4W" || m_mode=="QRA65") + if (m_mode == "FST4" || m_mode == "FST4W" || m_mode=="Q65") { if (m_TRperiod < 60) { @@ -7627,7 +7627,7 @@ void MainWindow::on_sbTR_FST4W_valueChanged(int value) QChar MainWindow::current_submode () const { QChar submode {0}; - if (m_mode.contains (QRegularExpression {R"(^(JT65|JT9|JT4|ISCAT|QRA64|QRA65)$)"}) + if (m_mode.contains (QRegularExpression {R"(^(JT65|JT9|JT4|ISCAT|QRA64|Q65)$)"}) && (m_config.enable_VHF_features () || "JT4" == m_mode || "ISCAT" == m_mode)) { submode = m_nSubMode + 65; @@ -9256,7 +9256,7 @@ void MainWindow::set_mode (QString const& mode) else if ("JT9+JT65" == mode) on_actionJT9_JT65_triggered (); else if ("JT65" == mode) on_actionJT65_triggered (); else if ("QRA64" == mode) on_actionQRA64_triggered (); - else if ("QRA65" == mode) on_actionQRA65_triggered (); + else if ("Q65" == mode) on_actionQ65_triggered (); else if ("FreqCal" == mode) on_actionFreqCal_triggered (); else if ("ISCAT" == mode) on_actionISCAT_triggered (); else if ("MSK144" == mode) on_actionMSK144_triggered (); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 3a111e0c4..4066af831 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -48,7 +48,7 @@ #define NUM_ISCAT_SYMBOLS 1291 //30*11025/256 #define NUM_MSK144_SYMBOLS 144 //s8 + d48 + s8 + d80 #define NUM_QRA64_SYMBOLS 84 //63 data + 21 sync -#define NUM_QRA65_SYMBOLS 85 //63 data + 22 sync +#define NUM_Q65_SYMBOLS 85 //63 data + 22 sync #define NUM_FT8_SYMBOLS 79 #define NUM_FT4_SYMBOLS 105 #define NUM_FST4_SYMBOLS 160 //240/2 data + 5*8 sync @@ -301,7 +301,7 @@ private slots: void on_cbCQTx_toggled(bool b); void on_actionMSK144_triggered(); void on_actionQRA64_triggered(); - void on_actionQRA65_triggered(); + void on_actionQ65_triggered(); void on_actionFreqCal_triggered(); void splash_done (); void on_measure_check_box_stateChanged (int); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 0b7adff9b..ff7986403 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -2895,7 +2895,7 @@ list. The list can be maintained in Settings (F2). - + @@ -3383,12 +3383,12 @@ list. The list can be maintained in Settings (F2). FST4W - + true - QRA65 + Q65 diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index 44ee92291..888ae8619 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -471,7 +471,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() if(m_nSubMode==4) bw=16*bw; //E } - if(m_mode=="QRA65") { //QRA65 + if(m_mode=="Q65") { //Q65 int h=int(pow(2.0,m_nSubMode)); int nsps=1800; if(m_TRperiod==30) nsps=3600; @@ -512,7 +512,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() int yTxTop=12; int yRxBottom=yTxTop + 2*yh + 4; if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" - or m_mode=="QRA64" or m_mode=="QRA65" or m_mode=="FT8" or m_mode=="FT4" + or m_mode=="QRA64" or m_mode=="Q65" or m_mode=="FT8" or m_mode=="FT4" or m_mode.startsWith("FST4")) { if(m_mode=="FST4" and !m_bSingleDecode) { @@ -524,7 +524,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() painter0.drawLine(x2,25,x2-5,20); } - if(m_mode=="QRA64" or m_mode=="QRA65" or (m_mode=="JT65" and m_bVHF)) { + if(m_mode=="QRA64" or m_mode=="Q65" or (m_mode=="JT65" and m_bVHF)) { painter0.setPen(penGreen); x1=XfromFreq(m_rxFreq-m_tol); x2=XfromFreq(m_rxFreq+m_tol); @@ -562,7 +562,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() } if(m_mode=="JT9" or m_mode=="JT65" or m_mode=="JT9+JT65" or - m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="QRA65" or m_mode=="FT8" + m_mode.mid(0,4)=="WSPR" or m_mode=="QRA64" or m_mode=="Q65" or m_mode=="FT8" or m_mode=="FT4" or m_mode.startsWith("FST4")) { painter0.setPen(penRed); x1=XfromFreq(m_txFreq); From 7a22e6a2e1a219a5d2ff908f9fd1366c170bbaac Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 25 Oct 2020 14:10:38 -0400 Subject: [PATCH 099/206] Change the Q65 value of nsps from 7680 to 7200. --- lib/q65_decode.f90 | 2 +- lib/qra/qra65/q65sim.f90 | 2 +- lib/qra_loops.f90 | 2 +- lib/test_q65.f90 | 2 +- lib/test_qra64.f90 | 2 +- widgets/mainwindow.cpp | 4 ++-- widgets/plotter.cpp | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 8b522ce2e..d1f874649 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -71,7 +71,7 @@ contains else if(ntrperiod.eq.30) then nsps=3600 else if(ntrperiod.eq.60) then - nsps=7680 + nsps=7200 else if(ntrperiod.eq.120) then nsps=16000 else if(ntrperiod.eq.300) then diff --git a/lib/qra/qra65/q65sim.f90 b/lib/qra/qra65/q65sim.f90 index 03696a0ae..8841b92cd 100644 --- a/lib/qra/qra65/q65sim.f90 +++ b/lib/qra/qra65/q65sim.f90 @@ -54,7 +54,7 @@ program q65sim else if(ntrperiod.eq.30) then nsps=3600 else if(ntrperiod.eq.60) then - nsps=7680 + nsps=7200 else if(ntrperiod.eq.120) then nsps=16000 else if(ntrperiod.eq.300) then diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index c2155aeba..de58263de 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -118,7 +118,7 @@ subroutine qra_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ndist=ndistx endif -200 if(mode.eq.65 .and. nsps.eq.7680/2) xdt=xdt+0.4 !### Empirical -- WHY ??? ### +200 if(mode.eq.65 .and. nsps.eq.7200/2) xdt=xdt+0.4 !### Empirical -- WHY ??? ### if(irc.ge.0) then navg=nsave diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index c56fa0bab..ead15b013 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -38,7 +38,7 @@ program test_q65 nsps=3600 i50=-24 else if(ntrperiod.eq.60) then - nsps=7680 + nsps=7200 i50=-28 else if(ntrperiod.eq.120) then nsps=16000 diff --git a/lib/test_qra64.f90 b/lib/test_qra64.f90 index 24f54c2d6..632dbdf66 100644 --- a/lib/test_qra64.f90 +++ b/lib/test_qra64.f90 @@ -31,7 +31,7 @@ program test_qra64 call getarg(9,arg) read(arg,*) nsnr - nsps=7680 + nsps=6192 i50=-28 ia=-20 ib=-33 diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index f835e9f31..231e9efa9 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -3730,7 +3730,7 @@ void MainWindow::guiUpdate() if(m_modeTx=="Q65") { // Q65 if(m_TRperiod==15) txDuration=0.5 + 85*1800/12000.0; if(m_TRperiod==30) txDuration=0.5 + 85*3600/12000.0; - if(m_TRperiod==60) txDuration=1.0 + 85*7680/12000.0; + if(m_TRperiod==60) txDuration=1.0 + 85*7200/12000.0; if(m_TRperiod==120) txDuration=1.0 + 85*16000/12000.0; if(m_TRperiod==300) txDuration=1.0 + 85*41472/12000.0; } @@ -7315,7 +7315,7 @@ void MainWindow::transmit (double snr) if (m_modeTx == "Q65") { int nsps=1800; if(m_TRperiod==30) nsps=3600; - if(m_TRperiod==60) nsps=7680; + if(m_TRperiod==60) nsps=7200; if(m_TRperiod==120) nsps=16000; if(m_TRperiod==300) nsps=41472; int mode65=pow(2.0,double(m_nSubMode)); diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index 888ae8619..b813978b5 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -475,7 +475,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() int h=int(pow(2.0,m_nSubMode)); int nsps=1800; if(m_TRperiod==30) nsps=3600; - if(m_TRperiod==60) nsps=7680; + if(m_TRperiod==60) nsps=7200; if(m_TRperiod==120) nsps=16000; if(m_TRperiod==300) nsps=41472; float baud=12000.0/nsps; From ef2c63af29e06ecc533a03c3bba062c8005276c5 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 25 Oct 2020 15:44:52 -0400 Subject: [PATCH 100/206] Enable some changes for Q65 submodes F, G, H. (They won't decode without additions to the core Q65 decoder.) --- lib/pctile.f90 | 2 +- lib/qra_loops.f90 | 3 +-- lib/spec64.f90 | 4 ++-- widgets/mainwindow.cpp | 3 ++- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/pctile.f90 b/lib/pctile.f90 index 7a039b05a..3bf2ffcf8 100644 --- a/lib/pctile.f90 +++ b/lib/pctile.f90 @@ -1,6 +1,6 @@ subroutine pctile(x,npts,npct,xpct) - parameter (NMAX=128*1024) + parameter (NMAX=256*1024) real*4 x(npts) real*4 tmp(NMAX) diff --git a/lib/qra_loops.f90 b/lib/qra_loops.f90 index de58263de..cebd7036a 100644 --- a/lib/qra_loops.f90 +++ b/lib/qra_loops.f90 @@ -3,7 +3,7 @@ subroutine qra_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & use packjt use timer_module, only: timer - parameter (LN=1152*63) + parameter (LN=2176*63) !LN=LL*NN; LL = 64*(mode64+2) character*37 decoded complex c00(0:npts2-1) !Analytic representation of dd(), 6000 Hz complex ,allocatable :: c0(:) !Ditto, with freq shift @@ -51,7 +51,6 @@ subroutine qra_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & call pctile(s3,LL*NN,40,base) s3=s3/base where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim -! if(iavg.eq.0 .and. idf.eq.1 .and. idt.eq.1) s3a(1:LL*NN)=s3(1:LL*NN) else s3(1:LL*NN)=s3avg(1:LL*NN) endif diff --git a/lib/spec64.f90 b/lib/spec64.f90 index 0bf30e679..fe518d747 100644 --- a/lib/spec64.f90 +++ b/lib/spec64.f90 @@ -74,8 +74,8 @@ subroutine spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) ! do j=1,NN ! ipk1=maxloc(s3(1:LL,j)) ! m=ipk1(1)-65 -! write(72,3072) j,m,m/2,m/4,m/8 -!3072 format(5i8) +! write(72,3072) j,m,m/2,m/4,m/8,m/16,m/32,m/64 +!3072 format(8i7) ! enddo return diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 231e9efa9..dbb950df7 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6403,7 +6403,8 @@ void MainWindow::on_actionQ65_triggered() m_hsymStop=49; ui->sbTR->values ({15, 30, 60, 120, 300}); on_sbTR_valueChanged (ui->sbTR->value()); - ui->sbSubmode->setMaximum(4); +//### ui->sbSubmode->setMaximum(4); + ui->sbSubmode->setMaximum(7); ui->sbSubmode->setValue(m_nSubMode); m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); From 1f06fd65fc33bbecc618cfd7ae7bc3ecd6b055f6 Mon Sep 17 00:00:00 2001 From: Nico Palermo/IV3NWV Date: Mon, 26 Oct 2020 01:10:53 +0100 Subject: [PATCH 101/206] Initial q65 distrib --- lib/qra/q65/Makefile.Win | 33 + lib/qra/q65/build.sh | 2 + lib/qra/q65/ebnovalues.txt | 17 + lib/qra/q65/fadengauss.c | 302 ++++++ lib/qra/q65/fadenlorentz.c | 304 ++++++ lib/qra/q65/normrnd.c | 82 ++ lib/qra/q65/normrnd.h | 51 + lib/qra/q65/npfwht.c | 216 +++++ lib/qra/q65/npfwht.h | 45 + lib/qra/q65/pdmath.c | 385 ++++++++ lib/qra/q65/pdmath.h | 85 ++ lib/qra/q65/q65.c | 795 +++++++++++++++ lib/qra/q65/q65.h | 103 ++ lib/qra/q65/q65.sln | 20 + lib/qra/q65/q65.vcproj | 255 +++++ lib/qra/q65/q65test.c | 910 ++++++++++++++++++ lib/qra/q65/qra15_65_64_irr_e23.c | 557 +++++++++++ lib/qra/q65/qra15_65_64_irr_e23.h | 41 + lib/qra/q65/qra65.c | 795 +++++++++++++++ lib/qra/q65/qra65.h | 101 ++ lib/qra/q65/qracodes.c | 474 +++++++++ lib/qra/q65/qracodes.h | 80 ++ .../q65/wer-ff-qra15_65_64_irr_e23-ap00.txt | 19 + 23 files changed, 5672 insertions(+) create mode 100644 lib/qra/q65/Makefile.Win create mode 100644 lib/qra/q65/build.sh create mode 100644 lib/qra/q65/ebnovalues.txt create mode 100644 lib/qra/q65/fadengauss.c create mode 100644 lib/qra/q65/fadenlorentz.c create mode 100644 lib/qra/q65/normrnd.c create mode 100644 lib/qra/q65/normrnd.h create mode 100644 lib/qra/q65/npfwht.c create mode 100644 lib/qra/q65/npfwht.h create mode 100644 lib/qra/q65/pdmath.c create mode 100644 lib/qra/q65/pdmath.h create mode 100644 lib/qra/q65/q65.c create mode 100644 lib/qra/q65/q65.h create mode 100644 lib/qra/q65/q65.sln create mode 100644 lib/qra/q65/q65.vcproj create mode 100644 lib/qra/q65/q65test.c create mode 100644 lib/qra/q65/qra15_65_64_irr_e23.c create mode 100644 lib/qra/q65/qra15_65_64_irr_e23.h create mode 100644 lib/qra/q65/qra65.c create mode 100644 lib/qra/q65/qra65.h create mode 100644 lib/qra/q65/qracodes.c create mode 100644 lib/qra/q65/qracodes.h create mode 100644 lib/qra/q65/wer-ff-qra15_65_64_irr_e23-ap00.txt diff --git a/lib/qra/q65/Makefile.Win b/lib/qra/q65/Makefile.Win new file mode 100644 index 000000000..cedf2ef17 --- /dev/null +++ b/lib/qra/q65/Makefile.Win @@ -0,0 +1,33 @@ +CC = gcc +CFLAGS = -O2 -Wall -I. -D_WIN32 + +# Default rules +%.o: %.c + ${CC} ${CFLAGS} -c $< +%.o: %.f + ${FC} ${FFLAGS} -c $< +%.o: %.F + ${FC} ${FFLAGS} -c $< +%.o: %.f90 + ${FC} ${FFLAGS} -c $< +%.o: %.F90 + ${FC} ${FFLAGS} -c $< + +all: libq65.a q65.exe + +OBJS1 = normrnd.o npfwht.o pdmath.o qra15_65_64_irr_e23.o \ + q65.o + +libq65.a: $(OBJS1) + ar cr libq65.a $(OBJS1) + ranlib libq65.a + +OBJS2 = q65test.o + +q65.exe: $(OBJS2) + ${CC} -o q65.exe $(OBJS2) libq65.a -lm + +.PHONY : clean + +clean: + $(RM) *.o libq65.a q65.exe diff --git a/lib/qra/q65/build.sh b/lib/qra/q65/build.sh new file mode 100644 index 000000000..3d7d76f1d --- /dev/null +++ b/lib/qra/q65/build.sh @@ -0,0 +1,2 @@ +gcc -Wall -march=native -pthread -O3 *.c -lpthread -lm -o q65 + diff --git a/lib/qra/q65/ebnovalues.txt b/lib/qra/q65/ebnovalues.txt new file mode 100644 index 000000000..06a3f585e --- /dev/null +++ b/lib/qra/q65/ebnovalues.txt @@ -0,0 +1,17 @@ +# Eb/No Values to be used during the Q65 codec simulation +# Each line of this file indicates the Eb/No value to be simulated (in dB) +# and the number of errors that should be detected by the decoder +# +# Be careful that the simulation takes a long time to complete +# if the number of errors is large for the specified Eb/No +# (this is particularly true if AP decoding is used) +# +-30 100 +0.5 1000 +1.0 1000 +1.5 1000 +2.0 1000 +2.5 1000 +3.0 1000 +3.5 1000 +4.0 1000 \ No newline at end of file diff --git a/lib/qra/q65/fadengauss.c b/lib/qra/q65/fadengauss.c new file mode 100644 index 000000000..f6ca27253 --- /dev/null +++ b/lib/qra/q65/fadengauss.c @@ -0,0 +1,302 @@ +// Gaussian energy fading tables for QRA64 +static const int glen_tab_gauss[64] = { + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 6, + 6, 6, 7, 7, 8, 8, 9, 10, + 10, 11, 12, 13, 14, 15, 17, 18, + 19, 21, 23, 25, 27, 29, 32, 34, + 37, 41, 44, 48, 52, 57, 62, 65 +}; +static const float ggauss1[2] = { +0.0296f, 0.9101f +}; +static const float ggauss2[2] = { +0.0350f, 0.8954f +}; +static const float ggauss3[2] = { +0.0411f, 0.8787f +}; +static const float ggauss4[2] = { +0.0483f, 0.8598f +}; +static const float ggauss5[2] = { +0.0566f, 0.8387f +}; +static const float ggauss6[2] = { +0.0660f, 0.8154f +}; +static const float ggauss7[2] = { +0.0767f, 0.7898f +}; +static const float ggauss8[2] = { +0.0886f, 0.7621f +}; +static const float ggauss9[2] = { +0.1017f, 0.7325f +}; +static const float ggauss10[2] = { +0.1159f, 0.7012f +}; +static const float ggauss11[2] = { +0.1310f, 0.6687f +}; +static const float ggauss12[2] = { +0.1465f, 0.6352f +}; +static const float ggauss13[2] = { +0.1621f, 0.6013f +}; +static const float ggauss14[2] = { +0.1771f, 0.5674f +}; +static const float ggauss15[2] = { +0.1911f, 0.5339f +}; +static const float ggauss16[2] = { +0.2034f, 0.5010f +}; +static const float ggauss17[3] = { +0.0299f, 0.2135f, 0.4690f +}; +static const float ggauss18[3] = { +0.0369f, 0.2212f, 0.4383f +}; +static const float ggauss19[3] = { +0.0454f, 0.2263f, 0.4088f +}; +static const float ggauss20[3] = { +0.0552f, 0.2286f, 0.3806f +}; +static const float ggauss21[3] = { +0.0658f, 0.2284f, 0.3539f +}; +static const float ggauss22[3] = { +0.0766f, 0.2258f, 0.3287f +}; +static const float ggauss23[3] = { +0.0869f, 0.2212f, 0.3049f +}; +static const float ggauss24[3] = { +0.0962f, 0.2148f, 0.2826f +}; +static const float ggauss25[4] = { +0.0351f, 0.1041f, 0.2071f, 0.2616f +}; +static const float ggauss26[4] = { +0.0429f, 0.1102f, 0.1984f, 0.2420f +}; +static const float ggauss27[4] = { +0.0508f, 0.1145f, 0.1890f, 0.2237f +}; +static const float ggauss28[4] = { +0.0582f, 0.1169f, 0.1791f, 0.2067f +}; +static const float ggauss29[5] = { +0.0289f, 0.0648f, 0.1176f, 0.1689f, 0.1908f +}; +static const float ggauss30[5] = { +0.0351f, 0.0703f, 0.1168f, 0.1588f, 0.1760f +}; +static const float ggauss31[5] = { +0.0411f, 0.0745f, 0.1146f, 0.1488f, 0.1623f +}; +static const float ggauss32[6] = { +0.0246f, 0.0466f, 0.0773f, 0.1115f, 0.1390f, 0.1497f +}; +static const float ggauss33[6] = { +0.0297f, 0.0512f, 0.0788f, 0.1075f, 0.1295f, 0.1379f +}; +static const float ggauss34[6] = { +0.0345f, 0.0549f, 0.0791f, 0.1029f, 0.1205f, 0.1270f +}; +static const float ggauss35[7] = { +0.0240f, 0.0387f, 0.0575f, 0.0784f, 0.0979f, 0.1118f, 0.1169f +}; +static const float ggauss36[7] = { +0.0281f, 0.0422f, 0.0590f, 0.0767f, 0.0926f, 0.1037f, 0.1076f +}; +static const float ggauss37[8] = { +0.0212f, 0.0318f, 0.0449f, 0.0596f, 0.0744f, 0.0872f, 0.0960f, 0.0991f +}; +static const float ggauss38[8] = { +0.0247f, 0.0348f, 0.0467f, 0.0593f, 0.0716f, 0.0819f, 0.0887f, 0.0911f +}; +static const float ggauss39[9] = { +0.0199f, 0.0278f, 0.0372f, 0.0476f, 0.0584f, 0.0684f, 0.0766f, 0.0819f, +0.0838f +}; +static const float ggauss40[10] = { +0.0166f, 0.0228f, 0.0303f, 0.0388f, 0.0478f, 0.0568f, 0.0649f, 0.0714f, +0.0756f, 0.0771f +}; +static const float ggauss41[10] = { +0.0193f, 0.0254f, 0.0322f, 0.0397f, 0.0474f, 0.0548f, 0.0613f, 0.0664f, +0.0697f, 0.0709f +}; +static const float ggauss42[11] = { +0.0168f, 0.0217f, 0.0273f, 0.0335f, 0.0399f, 0.0464f, 0.0524f, 0.0576f, +0.0617f, 0.0643f, 0.0651f +}; +static const float ggauss43[12] = { +0.0151f, 0.0191f, 0.0237f, 0.0288f, 0.0342f, 0.0396f, 0.0449f, 0.0498f, +0.0540f, 0.0572f, 0.0592f, 0.0599f +}; +static const float ggauss44[13] = { +0.0138f, 0.0171f, 0.0210f, 0.0252f, 0.0297f, 0.0343f, 0.0388f, 0.0432f, +0.0471f, 0.0504f, 0.0529f, 0.0545f, 0.0550f +}; +static const float ggauss45[14] = { +0.0128f, 0.0157f, 0.0189f, 0.0224f, 0.0261f, 0.0300f, 0.0339f, 0.0377f, +0.0412f, 0.0444f, 0.0470f, 0.0489f, 0.0501f, 0.0505f +}; +static const float ggauss46[15] = { +0.0121f, 0.0146f, 0.0173f, 0.0202f, 0.0234f, 0.0266f, 0.0299f, 0.0332f, +0.0363f, 0.0391f, 0.0416f, 0.0437f, 0.0452f, 0.0461f, 0.0464f +}; +static const float ggauss47[17] = { +0.0097f, 0.0116f, 0.0138f, 0.0161f, 0.0186f, 0.0212f, 0.0239f, 0.0267f, +0.0294f, 0.0321f, 0.0346f, 0.0369f, 0.0389f, 0.0405f, 0.0417f, 0.0424f, +0.0427f +}; +static const float ggauss48[18] = { +0.0096f, 0.0113f, 0.0131f, 0.0151f, 0.0172f, 0.0194f, 0.0217f, 0.0241f, +0.0264f, 0.0287f, 0.0308f, 0.0329f, 0.0347f, 0.0362f, 0.0375f, 0.0384f, +0.0390f, 0.0392f +}; +static const float ggauss49[19] = { +0.0095f, 0.0110f, 0.0126f, 0.0143f, 0.0161f, 0.0180f, 0.0199f, 0.0219f, +0.0239f, 0.0258f, 0.0277f, 0.0294f, 0.0310f, 0.0325f, 0.0337f, 0.0347f, +0.0354f, 0.0358f, 0.0360f +}; +static const float ggauss50[21] = { +0.0083f, 0.0095f, 0.0108f, 0.0122f, 0.0136f, 0.0152f, 0.0168f, 0.0184f, +0.0201f, 0.0217f, 0.0234f, 0.0250f, 0.0265f, 0.0279f, 0.0292f, 0.0303f, +0.0313f, 0.0320f, 0.0326f, 0.0329f, 0.0330f +}; +static const float ggauss51[23] = { +0.0074f, 0.0084f, 0.0095f, 0.0106f, 0.0118f, 0.0131f, 0.0144f, 0.0157f, +0.0171f, 0.0185f, 0.0199f, 0.0213f, 0.0227f, 0.0240f, 0.0252f, 0.0263f, +0.0273f, 0.0282f, 0.0290f, 0.0296f, 0.0300f, 0.0303f, 0.0303f +}; +static const float ggauss52[25] = { +0.0068f, 0.0076f, 0.0085f, 0.0094f, 0.0104f, 0.0115f, 0.0126f, 0.0137f, +0.0149f, 0.0160f, 0.0172f, 0.0184f, 0.0196f, 0.0207f, 0.0218f, 0.0228f, +0.0238f, 0.0247f, 0.0255f, 0.0262f, 0.0268f, 0.0273f, 0.0276f, 0.0278f, +0.0279f +}; +static const float ggauss53[27] = { +0.0063f, 0.0070f, 0.0078f, 0.0086f, 0.0094f, 0.0103f, 0.0112f, 0.0121f, +0.0131f, 0.0141f, 0.0151f, 0.0161f, 0.0170f, 0.0180f, 0.0190f, 0.0199f, +0.0208f, 0.0216f, 0.0224f, 0.0231f, 0.0237f, 0.0243f, 0.0247f, 0.0251f, +0.0254f, 0.0255f, 0.0256f +}; +static const float ggauss54[29] = { +0.0060f, 0.0066f, 0.0072f, 0.0079f, 0.0086f, 0.0093f, 0.0101f, 0.0109f, +0.0117f, 0.0125f, 0.0133f, 0.0142f, 0.0150f, 0.0159f, 0.0167f, 0.0175f, +0.0183f, 0.0190f, 0.0197f, 0.0204f, 0.0210f, 0.0216f, 0.0221f, 0.0225f, +0.0228f, 0.0231f, 0.0233f, 0.0234f, 0.0235f +}; +static const float ggauss55[32] = { +0.0053f, 0.0058f, 0.0063f, 0.0068f, 0.0074f, 0.0080f, 0.0086f, 0.0093f, +0.0099f, 0.0106f, 0.0113f, 0.0120f, 0.0127f, 0.0134f, 0.0141f, 0.0148f, +0.0155f, 0.0162f, 0.0168f, 0.0174f, 0.0180f, 0.0186f, 0.0191f, 0.0196f, +0.0201f, 0.0204f, 0.0208f, 0.0211f, 0.0213f, 0.0214f, 0.0215f, 0.0216f +}; +static const float ggauss56[34] = { +0.0052f, 0.0056f, 0.0060f, 0.0065f, 0.0070f, 0.0075f, 0.0080f, 0.0086f, +0.0091f, 0.0097f, 0.0103f, 0.0109f, 0.0115f, 0.0121f, 0.0127f, 0.0133f, +0.0138f, 0.0144f, 0.0150f, 0.0155f, 0.0161f, 0.0166f, 0.0170f, 0.0175f, +0.0179f, 0.0183f, 0.0186f, 0.0189f, 0.0192f, 0.0194f, 0.0196f, 0.0197f, +0.0198f, 0.0198f +}; +static const float ggauss57[37] = { +0.0047f, 0.0051f, 0.0055f, 0.0058f, 0.0063f, 0.0067f, 0.0071f, 0.0076f, +0.0080f, 0.0085f, 0.0090f, 0.0095f, 0.0100f, 0.0105f, 0.0110f, 0.0115f, +0.0120f, 0.0125f, 0.0130f, 0.0134f, 0.0139f, 0.0144f, 0.0148f, 0.0152f, +0.0156f, 0.0160f, 0.0164f, 0.0167f, 0.0170f, 0.0173f, 0.0175f, 0.0177f, +0.0179f, 0.0180f, 0.0181f, 0.0181f, 0.0182f +}; +static const float ggauss58[41] = { +0.0041f, 0.0044f, 0.0047f, 0.0050f, 0.0054f, 0.0057f, 0.0060f, 0.0064f, +0.0068f, 0.0072f, 0.0076f, 0.0080f, 0.0084f, 0.0088f, 0.0092f, 0.0096f, +0.0101f, 0.0105f, 0.0109f, 0.0113f, 0.0117f, 0.0121f, 0.0125f, 0.0129f, +0.0133f, 0.0137f, 0.0140f, 0.0144f, 0.0147f, 0.0150f, 0.0153f, 0.0155f, +0.0158f, 0.0160f, 0.0162f, 0.0163f, 0.0164f, 0.0165f, 0.0166f, 0.0167f, +0.0167f +}; +static const float ggauss59[44] = { +0.0039f, 0.0042f, 0.0044f, 0.0047f, 0.0050f, 0.0053f, 0.0056f, 0.0059f, +0.0062f, 0.0065f, 0.0068f, 0.0072f, 0.0075f, 0.0079f, 0.0082f, 0.0086f, +0.0089f, 0.0093f, 0.0096f, 0.0100f, 0.0104f, 0.0107f, 0.0110f, 0.0114f, +0.0117f, 0.0120f, 0.0124f, 0.0127f, 0.0130f, 0.0132f, 0.0135f, 0.0138f, +0.0140f, 0.0142f, 0.0144f, 0.0146f, 0.0148f, 0.0149f, 0.0150f, 0.0151f, +0.0152f, 0.0153f, 0.0153f, 0.0153f +}; +static const float ggauss60[48] = { +0.0036f, 0.0038f, 0.0040f, 0.0042f, 0.0044f, 0.0047f, 0.0049f, 0.0052f, +0.0055f, 0.0057f, 0.0060f, 0.0063f, 0.0066f, 0.0068f, 0.0071f, 0.0074f, +0.0077f, 0.0080f, 0.0083f, 0.0086f, 0.0089f, 0.0092f, 0.0095f, 0.0098f, +0.0101f, 0.0104f, 0.0107f, 0.0109f, 0.0112f, 0.0115f, 0.0117f, 0.0120f, +0.0122f, 0.0124f, 0.0126f, 0.0128f, 0.0130f, 0.0132f, 0.0134f, 0.0135f, +0.0136f, 0.0137f, 0.0138f, 0.0139f, 0.0140f, 0.0140f, 0.0140f, 0.0140f +}; +static const float ggauss61[52] = { +0.0033f, 0.0035f, 0.0037f, 0.0039f, 0.0041f, 0.0043f, 0.0045f, 0.0047f, +0.0049f, 0.0051f, 0.0053f, 0.0056f, 0.0058f, 0.0060f, 0.0063f, 0.0065f, +0.0068f, 0.0070f, 0.0073f, 0.0075f, 0.0078f, 0.0080f, 0.0083f, 0.0085f, +0.0088f, 0.0090f, 0.0093f, 0.0095f, 0.0098f, 0.0100f, 0.0102f, 0.0105f, +0.0107f, 0.0109f, 0.0111f, 0.0113f, 0.0115f, 0.0116f, 0.0118f, 0.0120f, +0.0121f, 0.0122f, 0.0124f, 0.0125f, 0.0126f, 0.0126f, 0.0127f, 0.0128f, +0.0128f, 0.0129f, 0.0129f, 0.0129f +}; +static const float ggauss62[57] = { +0.0030f, 0.0031f, 0.0033f, 0.0034f, 0.0036f, 0.0038f, 0.0039f, 0.0041f, +0.0043f, 0.0045f, 0.0047f, 0.0048f, 0.0050f, 0.0052f, 0.0054f, 0.0056f, +0.0058f, 0.0060f, 0.0063f, 0.0065f, 0.0067f, 0.0069f, 0.0071f, 0.0073f, +0.0075f, 0.0077f, 0.0080f, 0.0082f, 0.0084f, 0.0086f, 0.0088f, 0.0090f, +0.0092f, 0.0094f, 0.0096f, 0.0097f, 0.0099f, 0.0101f, 0.0103f, 0.0104f, +0.0106f, 0.0107f, 0.0108f, 0.0110f, 0.0111f, 0.0112f, 0.0113f, 0.0114f, +0.0115f, 0.0116f, 0.0116f, 0.0117f, 0.0117f, 0.0118f, 0.0118f, 0.0118f, +0.0118f +}; +static const float ggauss63[62] = { +0.0027f, 0.0029f, 0.0030f, 0.0031f, 0.0032f, 0.0034f, 0.0035f, 0.0037f, +0.0038f, 0.0040f, 0.0041f, 0.0043f, 0.0045f, 0.0046f, 0.0048f, 0.0049f, +0.0051f, 0.0053f, 0.0055f, 0.0056f, 0.0058f, 0.0060f, 0.0062f, 0.0063f, +0.0065f, 0.0067f, 0.0069f, 0.0071f, 0.0072f, 0.0074f, 0.0076f, 0.0078f, +0.0079f, 0.0081f, 0.0083f, 0.0084f, 0.0086f, 0.0088f, 0.0089f, 0.0091f, +0.0092f, 0.0094f, 0.0095f, 0.0096f, 0.0098f, 0.0099f, 0.0100f, 0.0101f, +0.0102f, 0.0103f, 0.0104f, 0.0105f, 0.0105f, 0.0106f, 0.0107f, 0.0107f, +0.0108f, 0.0108f, 0.0108f, 0.0108f, 0.0109f, 0.0109f +}; +static const float ggauss64[65] = { +0.0028f, 0.0029f, 0.0030f, 0.0031f, 0.0032f, 0.0034f, 0.0035f, 0.0036f, +0.0037f, 0.0039f, 0.0040f, 0.0041f, 0.0043f, 0.0044f, 0.0046f, 0.0047f, +0.0048f, 0.0050f, 0.0051f, 0.0053f, 0.0054f, 0.0056f, 0.0057f, 0.0059f, +0.0060f, 0.0062f, 0.0063f, 0.0065f, 0.0066f, 0.0068f, 0.0069f, 0.0071f, +0.0072f, 0.0074f, 0.0075f, 0.0077f, 0.0078f, 0.0079f, 0.0081f, 0.0082f, +0.0083f, 0.0084f, 0.0086f, 0.0087f, 0.0088f, 0.0089f, 0.0090f, 0.0091f, +0.0092f, 0.0093f, 0.0094f, 0.0094f, 0.0095f, 0.0096f, 0.0097f, 0.0097f, +0.0098f, 0.0098f, 0.0099f, 0.0099f, 0.0099f, 0.0099f, 0.0100f, 0.0100f, +0.0100f +}; +static const float *gptr_tab_gauss[64] = { +ggauss1, ggauss2, ggauss3, ggauss4, +ggauss5, ggauss6, ggauss7, ggauss8, +ggauss9, ggauss10, ggauss11, ggauss12, +ggauss13, ggauss14, ggauss15, ggauss16, +ggauss17, ggauss18, ggauss19, ggauss20, +ggauss21, ggauss22, ggauss23, ggauss24, +ggauss25, ggauss26, ggauss27, ggauss28, +ggauss29, ggauss30, ggauss31, ggauss32, +ggauss33, ggauss34, ggauss35, ggauss36, +ggauss37, ggauss38, ggauss39, ggauss40, +ggauss41, ggauss42, ggauss43, ggauss44, +ggauss45, ggauss46, ggauss47, ggauss48, +ggauss49, ggauss50, ggauss51, ggauss52, +ggauss53, ggauss54, ggauss55, ggauss56, +ggauss57, ggauss58, ggauss59, ggauss60, +ggauss61, ggauss62, ggauss63, ggauss64 +}; diff --git a/lib/qra/q65/fadenlorentz.c b/lib/qra/q65/fadenlorentz.c new file mode 100644 index 000000000..22329f65e --- /dev/null +++ b/lib/qra/q65/fadenlorentz.c @@ -0,0 +1,304 @@ +// Lorentz energy fading tables for QRA64 +static const int glen_tab_lorentz[64] = { + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 3, 4, 4, 4, + 4, 4, 5, 5, 5, 5, 6, 6, + 7, 7, 7, 8, 8, 9, 10, 10, + 11, 12, 13, 14, 15, 16, 17, 19, + 20, 22, 23, 25, 27, 30, 32, 35, + 38, 41, 45, 49, 53, 57, 62, 65 +}; +static const float glorentz1[2] = { +0.0214f, 0.9107f +}; +static const float glorentz2[2] = { +0.0244f, 0.9030f +}; +static const float glorentz3[2] = { +0.0280f, 0.8950f +}; +static const float glorentz4[2] = { +0.0314f, 0.8865f +}; +static const float glorentz5[2] = { +0.0349f, 0.8773f +}; +static const float glorentz6[2] = { +0.0388f, 0.8675f +}; +static const float glorentz7[2] = { +0.0426f, 0.8571f +}; +static const float glorentz8[2] = { +0.0463f, 0.8459f +}; +static const float glorentz9[2] = { +0.0500f, 0.8339f +}; +static const float glorentz10[2] = { +0.0538f, 0.8210f +}; +static const float glorentz11[2] = { +0.0579f, 0.8074f +}; +static const float glorentz12[2] = { +0.0622f, 0.7930f +}; +static const float glorentz13[2] = { +0.0668f, 0.7777f +}; +static const float glorentz14[2] = { +0.0715f, 0.7616f +}; +static const float glorentz15[3] = { +0.0196f, 0.0765f, 0.7445f +}; +static const float glorentz16[3] = { +0.0210f, 0.0816f, 0.7267f +}; +static const float glorentz17[3] = { +0.0226f, 0.0870f, 0.7080f +}; +static const float glorentz18[3] = { +0.0242f, 0.0925f, 0.6885f +}; +static const float glorentz19[3] = { +0.0259f, 0.0981f, 0.6682f +}; +static const float glorentz20[3] = { +0.0277f, 0.1039f, 0.6472f +}; +static const float glorentz21[3] = { +0.0296f, 0.1097f, 0.6255f +}; +static const float glorentz22[4] = { +0.0143f, 0.0316f, 0.1155f, 0.6031f +}; +static const float glorentz23[4] = { +0.0153f, 0.0337f, 0.1213f, 0.5803f +}; +static const float glorentz24[4] = { +0.0163f, 0.0358f, 0.1270f, 0.5570f +}; +static const float glorentz25[4] = { +0.0174f, 0.0381f, 0.1325f, 0.5333f +}; +static const float glorentz26[4] = { +0.0186f, 0.0405f, 0.1378f, 0.5095f +}; +static const float glorentz27[5] = { +0.0113f, 0.0198f, 0.0429f, 0.1428f, 0.4855f +}; +static const float glorentz28[5] = { +0.0120f, 0.0211f, 0.0455f, 0.1473f, 0.4615f +}; +static const float glorentz29[5] = { +0.0129f, 0.0225f, 0.0481f, 0.1514f, 0.4376f +}; +static const float glorentz30[5] = { +0.0137f, 0.0239f, 0.0508f, 0.1549f, 0.4140f +}; +static const float glorentz31[6] = { +0.0095f, 0.0147f, 0.0254f, 0.0536f, 0.1578f, 0.3907f +}; +static const float glorentz32[6] = { +0.0101f, 0.0156f, 0.0270f, 0.0564f, 0.1600f, 0.3680f +}; +static const float glorentz33[7] = { +0.0076f, 0.0109f, 0.0167f, 0.0287f, 0.0592f, 0.1614f, 0.3458f +}; +static const float glorentz34[7] = { +0.0081f, 0.0116f, 0.0178f, 0.0305f, 0.0621f, 0.1620f, 0.3243f +}; +static const float glorentz35[7] = { +0.0087f, 0.0124f, 0.0190f, 0.0324f, 0.0649f, 0.1618f, 0.3035f +}; +static const float glorentz36[8] = { +0.0069f, 0.0093f, 0.0133f, 0.0203f, 0.0343f, 0.0676f, 0.1607f, 0.2836f +}; +static const float glorentz37[8] = { +0.0074f, 0.0100f, 0.0142f, 0.0216f, 0.0362f, 0.0702f, 0.1588f, 0.2645f +}; +static const float glorentz38[9] = { +0.0061f, 0.0080f, 0.0107f, 0.0152f, 0.0230f, 0.0382f, 0.0726f, 0.1561f, +0.2464f +}; +static const float glorentz39[10] = { +0.0052f, 0.0066f, 0.0086f, 0.0115f, 0.0162f, 0.0244f, 0.0402f, 0.0747f, +0.1526f, 0.2291f +}; +static const float glorentz40[10] = { +0.0056f, 0.0071f, 0.0092f, 0.0123f, 0.0173f, 0.0259f, 0.0422f, 0.0766f, +0.1484f, 0.2128f +}; +static const float glorentz41[11] = { +0.0049f, 0.0061f, 0.0076f, 0.0098f, 0.0132f, 0.0184f, 0.0274f, 0.0441f, +0.0780f, 0.1437f, 0.1975f +}; +static const float glorentz42[12] = { +0.0044f, 0.0053f, 0.0065f, 0.0082f, 0.0106f, 0.0141f, 0.0196f, 0.0290f, +0.0460f, 0.0791f, 0.1384f, 0.1831f +}; +static const float glorentz43[13] = { +0.0040f, 0.0048f, 0.0057f, 0.0070f, 0.0088f, 0.0113f, 0.0150f, 0.0209f, +0.0305f, 0.0477f, 0.0797f, 0.1327f, 0.1695f +}; +static const float glorentz44[14] = { +0.0037f, 0.0043f, 0.0051f, 0.0062f, 0.0075f, 0.0094f, 0.0121f, 0.0160f, +0.0221f, 0.0321f, 0.0493f, 0.0799f, 0.1267f, 0.1568f +}; +static const float glorentz45[15] = { +0.0035f, 0.0040f, 0.0047f, 0.0055f, 0.0066f, 0.0081f, 0.0101f, 0.0129f, +0.0171f, 0.0234f, 0.0335f, 0.0506f, 0.0795f, 0.1204f, 0.1450f +}; +static const float glorentz46[16] = { +0.0033f, 0.0037f, 0.0043f, 0.0050f, 0.0059f, 0.0071f, 0.0087f, 0.0108f, +0.0138f, 0.0181f, 0.0246f, 0.0349f, 0.0517f, 0.0786f, 0.1141f, 0.1340f +}; +static const float glorentz47[17] = { +0.0031f, 0.0035f, 0.0040f, 0.0046f, 0.0054f, 0.0064f, 0.0077f, 0.0093f, +0.0116f, 0.0147f, 0.0192f, 0.0259f, 0.0362f, 0.0525f, 0.0773f, 0.1076f, +0.1237f +}; +static const float glorentz48[19] = { +0.0027f, 0.0030f, 0.0034f, 0.0038f, 0.0043f, 0.0050f, 0.0058f, 0.0069f, +0.0082f, 0.0100f, 0.0123f, 0.0156f, 0.0203f, 0.0271f, 0.0374f, 0.0530f, +0.0755f, 0.1013f, 0.1141f +}; +static const float glorentz49[20] = { +0.0026f, 0.0029f, 0.0032f, 0.0036f, 0.0041f, 0.0047f, 0.0054f, 0.0063f, +0.0074f, 0.0088f, 0.0107f, 0.0131f, 0.0165f, 0.0213f, 0.0282f, 0.0383f, +0.0531f, 0.0734f, 0.0950f, 0.1053f +}; +static const float glorentz50[22] = { +0.0023f, 0.0025f, 0.0028f, 0.0031f, 0.0035f, 0.0039f, 0.0044f, 0.0050f, +0.0058f, 0.0067f, 0.0079f, 0.0094f, 0.0114f, 0.0139f, 0.0175f, 0.0223f, +0.0292f, 0.0391f, 0.0529f, 0.0709f, 0.0889f, 0.0971f +}; +static const float glorentz51[23] = { +0.0023f, 0.0025f, 0.0027f, 0.0030f, 0.0034f, 0.0037f, 0.0042f, 0.0048f, +0.0054f, 0.0062f, 0.0072f, 0.0085f, 0.0100f, 0.0121f, 0.0148f, 0.0184f, +0.0233f, 0.0301f, 0.0396f, 0.0524f, 0.0681f, 0.0829f, 0.0894f +}; +static const float glorentz52[25] = { +0.0021f, 0.0023f, 0.0025f, 0.0027f, 0.0030f, 0.0033f, 0.0036f, 0.0040f, +0.0045f, 0.0051f, 0.0058f, 0.0067f, 0.0077f, 0.0090f, 0.0107f, 0.0128f, +0.0156f, 0.0192f, 0.0242f, 0.0308f, 0.0398f, 0.0515f, 0.0650f, 0.0772f, +0.0824f +}; +static const float glorentz53[27] = { +0.0019f, 0.0021f, 0.0022f, 0.0024f, 0.0027f, 0.0029f, 0.0032f, 0.0035f, +0.0039f, 0.0044f, 0.0049f, 0.0055f, 0.0062f, 0.0072f, 0.0083f, 0.0096f, +0.0113f, 0.0135f, 0.0164f, 0.0201f, 0.0249f, 0.0314f, 0.0398f, 0.0502f, +0.0619f, 0.0718f, 0.0759f +}; +static const float glorentz54[30] = { +0.0017f, 0.0018f, 0.0019f, 0.0021f, 0.0022f, 0.0024f, 0.0026f, 0.0029f, +0.0031f, 0.0034f, 0.0038f, 0.0042f, 0.0047f, 0.0052f, 0.0059f, 0.0067f, +0.0076f, 0.0088f, 0.0102f, 0.0120f, 0.0143f, 0.0171f, 0.0208f, 0.0256f, +0.0317f, 0.0395f, 0.0488f, 0.0586f, 0.0666f, 0.0698f +}; +static const float glorentz55[32] = { +0.0016f, 0.0017f, 0.0018f, 0.0019f, 0.0021f, 0.0022f, 0.0024f, 0.0026f, +0.0028f, 0.0031f, 0.0034f, 0.0037f, 0.0041f, 0.0045f, 0.0050f, 0.0056f, +0.0063f, 0.0071f, 0.0081f, 0.0094f, 0.0108f, 0.0127f, 0.0149f, 0.0178f, +0.0214f, 0.0261f, 0.0318f, 0.0389f, 0.0470f, 0.0553f, 0.0618f, 0.0643f +}; +static const float glorentz56[35] = { +0.0014f, 0.0015f, 0.0016f, 0.0017f, 0.0018f, 0.0020f, 0.0021f, 0.0023f, +0.0024f, 0.0026f, 0.0028f, 0.0031f, 0.0033f, 0.0036f, 0.0040f, 0.0044f, +0.0049f, 0.0054f, 0.0060f, 0.0067f, 0.0076f, 0.0087f, 0.0099f, 0.0114f, +0.0133f, 0.0156f, 0.0184f, 0.0220f, 0.0264f, 0.0318f, 0.0381f, 0.0451f, +0.0520f, 0.0572f, 0.0591f +}; +static const float glorentz57[38] = { +0.0013f, 0.0014f, 0.0015f, 0.0016f, 0.0017f, 0.0018f, 0.0019f, 0.0020f, +0.0021f, 0.0023f, 0.0024f, 0.0026f, 0.0028f, 0.0031f, 0.0033f, 0.0036f, +0.0039f, 0.0043f, 0.0047f, 0.0052f, 0.0058f, 0.0064f, 0.0072f, 0.0081f, +0.0092f, 0.0104f, 0.0120f, 0.0139f, 0.0162f, 0.0190f, 0.0224f, 0.0265f, +0.0315f, 0.0371f, 0.0431f, 0.0487f, 0.0529f, 0.0544f +}; +static const float glorentz58[41] = { +0.0012f, 0.0013f, 0.0014f, 0.0014f, 0.0015f, 0.0016f, 0.0017f, 0.0018f, +0.0019f, 0.0020f, 0.0022f, 0.0023f, 0.0025f, 0.0026f, 0.0028f, 0.0030f, +0.0033f, 0.0036f, 0.0039f, 0.0042f, 0.0046f, 0.0050f, 0.0056f, 0.0061f, +0.0068f, 0.0076f, 0.0086f, 0.0097f, 0.0110f, 0.0125f, 0.0144f, 0.0167f, +0.0194f, 0.0226f, 0.0265f, 0.0309f, 0.0359f, 0.0409f, 0.0455f, 0.0488f, +0.0500f +}; +static const float glorentz59[45] = { +0.0011f, 0.0012f, 0.0012f, 0.0013f, 0.0013f, 0.0014f, 0.0015f, 0.0016f, +0.0016f, 0.0017f, 0.0018f, 0.0019f, 0.0021f, 0.0022f, 0.0023f, 0.0025f, +0.0026f, 0.0028f, 0.0030f, 0.0033f, 0.0035f, 0.0038f, 0.0041f, 0.0045f, +0.0049f, 0.0054f, 0.0059f, 0.0065f, 0.0072f, 0.0081f, 0.0090f, 0.0102f, +0.0115f, 0.0130f, 0.0149f, 0.0171f, 0.0197f, 0.0227f, 0.0263f, 0.0302f, +0.0345f, 0.0387f, 0.0425f, 0.0451f, 0.0460f +}; +static const float glorentz60[49] = { +0.0010f, 0.0011f, 0.0011f, 0.0012f, 0.0012f, 0.0013f, 0.0013f, 0.0014f, +0.0014f, 0.0015f, 0.0016f, 0.0017f, 0.0018f, 0.0019f, 0.0020f, 0.0021f, +0.0022f, 0.0024f, 0.0025f, 0.0027f, 0.0028f, 0.0030f, 0.0033f, 0.0035f, +0.0038f, 0.0041f, 0.0044f, 0.0048f, 0.0052f, 0.0057f, 0.0063f, 0.0069f, +0.0077f, 0.0085f, 0.0095f, 0.0106f, 0.0119f, 0.0135f, 0.0153f, 0.0174f, +0.0199f, 0.0227f, 0.0259f, 0.0293f, 0.0330f, 0.0365f, 0.0395f, 0.0415f, +0.0423f +}; +static const float glorentz61[53] = { +0.0009f, 0.0010f, 0.0010f, 0.0011f, 0.0011f, 0.0011f, 0.0012f, 0.0012f, +0.0013f, 0.0014f, 0.0014f, 0.0015f, 0.0016f, 0.0016f, 0.0017f, 0.0018f, +0.0019f, 0.0020f, 0.0021f, 0.0023f, 0.0024f, 0.0025f, 0.0027f, 0.0029f, +0.0031f, 0.0033f, 0.0035f, 0.0038f, 0.0041f, 0.0044f, 0.0047f, 0.0051f, +0.0056f, 0.0061f, 0.0067f, 0.0073f, 0.0081f, 0.0089f, 0.0099f, 0.0110f, +0.0124f, 0.0139f, 0.0156f, 0.0176f, 0.0199f, 0.0225f, 0.0253f, 0.0283f, +0.0314f, 0.0343f, 0.0367f, 0.0383f, 0.0389f +}; +static const float glorentz62[57] = { +0.0009f, 0.0009f, 0.0009f, 0.0010f, 0.0010f, 0.0011f, 0.0011f, 0.0011f, +0.0012f, 0.0012f, 0.0013f, 0.0013f, 0.0014f, 0.0015f, 0.0015f, 0.0016f, +0.0017f, 0.0018f, 0.0019f, 0.0020f, 0.0021f, 0.0022f, 0.0023f, 0.0024f, +0.0026f, 0.0027f, 0.0029f, 0.0031f, 0.0033f, 0.0035f, 0.0038f, 0.0040f, +0.0043f, 0.0047f, 0.0050f, 0.0055f, 0.0059f, 0.0064f, 0.0070f, 0.0077f, +0.0085f, 0.0093f, 0.0103f, 0.0114f, 0.0127f, 0.0142f, 0.0158f, 0.0177f, +0.0198f, 0.0221f, 0.0246f, 0.0272f, 0.0297f, 0.0321f, 0.0340f, 0.0353f, +0.0357f +}; +static const float glorentz63[62] = { +0.0008f, 0.0008f, 0.0009f, 0.0009f, 0.0009f, 0.0010f, 0.0010f, 0.0010f, +0.0011f, 0.0011f, 0.0011f, 0.0012f, 0.0012f, 0.0013f, 0.0013f, 0.0014f, +0.0015f, 0.0015f, 0.0016f, 0.0017f, 0.0017f, 0.0018f, 0.0019f, 0.0020f, +0.0021f, 0.0022f, 0.0023f, 0.0025f, 0.0026f, 0.0028f, 0.0029f, 0.0031f, +0.0033f, 0.0035f, 0.0038f, 0.0040f, 0.0043f, 0.0046f, 0.0050f, 0.0053f, +0.0058f, 0.0062f, 0.0068f, 0.0074f, 0.0081f, 0.0088f, 0.0097f, 0.0106f, +0.0117f, 0.0130f, 0.0144f, 0.0159f, 0.0176f, 0.0195f, 0.0216f, 0.0237f, +0.0259f, 0.0280f, 0.0299f, 0.0315f, 0.0325f, 0.0328f +}; +static const float glorentz64[65] = { +0.0008f, 0.0008f, 0.0008f, 0.0009f, 0.0009f, 0.0009f, 0.0010f, 0.0010f, +0.0010f, 0.0011f, 0.0011f, 0.0012f, 0.0012f, 0.0012f, 0.0013f, 0.0013f, +0.0014f, 0.0014f, 0.0015f, 0.0016f, 0.0016f, 0.0017f, 0.0018f, 0.0019f, +0.0020f, 0.0021f, 0.0022f, 0.0023f, 0.0024f, 0.0025f, 0.0027f, 0.0028f, +0.0030f, 0.0031f, 0.0033f, 0.0035f, 0.0038f, 0.0040f, 0.0043f, 0.0046f, +0.0049f, 0.0052f, 0.0056f, 0.0061f, 0.0066f, 0.0071f, 0.0077f, 0.0084f, +0.0091f, 0.0100f, 0.0109f, 0.0120f, 0.0132f, 0.0145f, 0.0159f, 0.0175f, +0.0192f, 0.0209f, 0.0228f, 0.0246f, 0.0264f, 0.0279f, 0.0291f, 0.0299f, +0.0301f +}; +static const float *gptr_tab_lorentz[64] = { +glorentz1, glorentz2, glorentz3, glorentz4, +glorentz5, glorentz6, glorentz7, glorentz8, +glorentz9, glorentz10, glorentz11, glorentz12, +glorentz13, glorentz14, glorentz15, glorentz16, +glorentz17, glorentz18, glorentz19, glorentz20, +glorentz21, glorentz22, glorentz23, glorentz24, +glorentz25, glorentz26, glorentz27, glorentz28, +glorentz29, glorentz30, glorentz31, glorentz32, +glorentz33, glorentz34, glorentz35, glorentz36, +glorentz37, glorentz38, glorentz39, glorentz40, +glorentz41, glorentz42, glorentz43, glorentz44, +glorentz45, glorentz46, glorentz47, glorentz48, +glorentz49, glorentz50, glorentz51, glorentz52, +glorentz53, glorentz54, glorentz55, glorentz56, +glorentz57, glorentz58, glorentz59, glorentz60, +glorentz61, glorentz62, glorentz63, glorentz64 +}; diff --git a/lib/qra/q65/normrnd.c b/lib/qra/q65/normrnd.c new file mode 100644 index 000000000..90abfa425 --- /dev/null +++ b/lib/qra/q65/normrnd.c @@ -0,0 +1,82 @@ +// normrnd.c +// functions to generate gaussian distributed numbers +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// +// Credits to Andrea Montefusco - IW0HDV for his help on adapting the sources +// to OSs other than MS Windows +// +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + + +#include "normrnd.h" + +#if _WIN32 // note the underscore: without it, it's not msdn official! + // Windows (x64 and x86) + #include // required only for GetTickCount(...) + #define K_RAND_MAX UINT_MAX +#elif _SVID_SOURCE || _XOPEN_SOURCE || __unix__ || (defined (__APPLE__) && defined(__MACH__)) /* POSIX or Unix or Apple */ + #include + #define rand_s(x) (*x)=(unsigned int)lrand48() // returns unsigned integers in the range 0..0x7FFFFFFF + #define K_RAND_MAX 0x7FFFFFFF // that's the max number + // generated by lrand48 +#else + #error "No good quality PRNG found" +#endif + + +// use MS rand_s(...) function +void normrnd_s(float *dst, int nitems, float mean, float stdev) +{ + unsigned int r; + float phi=0, u=0; + int set = 0; + + while (nitems--) + if (set==1) { + *dst++ = (float)sin(phi)*u*stdev+mean; + set = 0; + } + else { + rand_s((unsigned int*)&r); phi = (M_2PI/(1.0f+K_RAND_MAX))*r; + rand_s((unsigned int*)&r); u = (float)sqrt(-2.0f* log( (1.0f/(1.0f+K_RAND_MAX))*(1.0f+r) ) ); + *dst++ = (float)cos(phi)*u*stdev+mean; + set=1; + } +} + +/* NOT USED +// use MS rand() function +void normrnd(float *dst, int nitems, float mean, float stdev) +{ + float phi=0, u=0; + int set = 0; + + while (nitems--) + if (set==1) { + *dst++ = (float)sin(phi)*u*stdev+mean; + set = 0; + } + else { + phi = (M_2PI/(1.0f+RAND_MAX))*rand(); + u = (float)sqrt(-2.0f* log( (1.0f/(1.0f+RAND_MAX))*(1.0f+rand()) ) ); + *dst++ = (float)cos(phi)*u*stdev+mean; + set=1; + } +} +*/ diff --git a/lib/qra/q65/normrnd.h b/lib/qra/q65/normrnd.h new file mode 100644 index 000000000..dd4b65bbe --- /dev/null +++ b/lib/qra/q65/normrnd.h @@ -0,0 +1,51 @@ +// normrnd.h +// Functions to generate gaussian distributed numbers +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#ifndef _normrnd_h_ +#define _normrnd_h_ + +#define _CRT_RAND_S +#include + +#define _USE_MATH_DEFINES +#include +#define M_2PI (2.0f*(float)M_PI) + +#ifdef __cplusplus +extern "C" { +#endif + +void normrnd_s(float *dst, int nitems, float mean, float stdev); +// generate a random array of numbers with a gaussian distribution of given mean and stdev +// use MS rand_s(...) function + +/* not used +void normrnd(float *dst, int nitems, float mean, float stdev); +// generate a random array of numbers with a gaussian distribution of given mean and stdev +// use MS rand() function +*/ + +#ifdef __cplusplus +} +#endif + +#endif // _normrnd_h_ + diff --git a/lib/qra/q65/npfwht.c b/lib/qra/q65/npfwht.c new file mode 100644 index 000000000..5732ce913 --- /dev/null +++ b/lib/qra/q65/npfwht.c @@ -0,0 +1,216 @@ +// npfwht.c +// Basic implementation of the Fast Walsh-Hadamard Transforms +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (repeat and accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#include "npfwht.h" + +#define WHBFY(dst,src,base,offs,dist) { dst[base+offs]=src[base+offs]+src[base+offs+dist]; dst[base+offs+dist]=src[base+offs]-src[base+offs+dist]; } + +typedef void (*pnp_fwht)(float*,float*); + +static void np_fwht2(float *dst, float *src); + +static void np_fwht1(float *dst, float *src); +static void np_fwht2(float *dst, float *src); +static void np_fwht4(float *dst, float *src); +static void np_fwht8(float *dst, float *src); +static void np_fwht16(float *dst, float *src); +static void np_fwht32(float *dst, float *src); +static void np_fwht64(float *dst, float *src); + +static pnp_fwht np_fwht_tab[7] = { + np_fwht1, + np_fwht2, + np_fwht4, + np_fwht8, + np_fwht16, + np_fwht32, + np_fwht64 +}; + +void np_fwht(int nlogdim, float *dst, float *src) +{ + np_fwht_tab[nlogdim](dst,src); +} + +static void np_fwht1(float *dst, float *src) +{ + dst[0] = src[0]; +} + + +static void np_fwht2(float *dst, float *src) +{ + float t[2]; + + WHBFY(t,src,0,0,1); + dst[0]= t[0]; + dst[1]= t[1]; +} + +static void np_fwht4(float *dst, float *src) +{ + float t[4]; + + // group 1 + WHBFY(t,src,0,0,2); WHBFY(t,src,0,1,2); + // group 2 + WHBFY(dst,t,0,0,1); WHBFY(dst,t,2,0,1); +}; + + +static void np_fwht8(float *dst, float *src) +{ + float t[16]; + float *t1=t, *t2=t+8; + + // group 1 + WHBFY(t1,src,0,0,4); WHBFY(t1,src,0,1,4); WHBFY(t1,src,0,2,4); WHBFY(t1,src,0,3,4); + // group 2 + WHBFY(t2,t1,0,0,2); WHBFY(t2,t1,0,1,2); WHBFY(t2,t1,4,0,2); WHBFY(t2,t1,4,1,2); + // group 3 + WHBFY(dst,t2,0,0,1); WHBFY(dst,t2,2,0,1); WHBFY(dst,t2,4,0,1); WHBFY(dst,t2,6,0,1); +}; + + +static void np_fwht16(float *dst, float *src) +{ + float t[32]; + float *t1=t, *t2=t+16; + + // group 1 + WHBFY(t1,src,0,0,8); WHBFY(t1,src,0,1,8); WHBFY(t1,src,0,2,8); WHBFY(t1,src,0,3,8); + WHBFY(t1,src,0,4,8); WHBFY(t1,src,0,5,8); WHBFY(t1,src,0,6,8); WHBFY(t1,src,0,7,8); + // group 2 + WHBFY(t2,t1,0,0,4); WHBFY(t2,t1,0,1,4); WHBFY(t2,t1,0,2,4); WHBFY(t2,t1,0,3,4); + WHBFY(t2,t1,8,0,4); WHBFY(t2,t1,8,1,4); WHBFY(t2,t1,8,2,4); WHBFY(t2,t1,8,3,4); + // group 3 + WHBFY(t1,t2,0,0,2); WHBFY(t1,t2,0,1,2); WHBFY(t1,t2,4,0,2); WHBFY(t1,t2,4,1,2); + WHBFY(t1,t2,8,0,2); WHBFY(t1,t2,8,1,2); WHBFY(t1,t2,12,0,2); WHBFY(t1,t2,12,1,2); + // group 4 + WHBFY(dst,t1,0,0,1); WHBFY(dst,t1,2,0,1); WHBFY(dst,t1,4,0,1); WHBFY(dst,t1,6,0,1); + WHBFY(dst,t1,8,0,1); WHBFY(dst,t1,10,0,1); WHBFY(dst,t1,12,0,1); WHBFY(dst,t1,14,0,1); + +} + +static void np_fwht32(float *dst, float *src) +{ + float t[64]; + float *t1=t, *t2=t+32; + + // group 1 + WHBFY(t1,src,0,0,16); WHBFY(t1,src,0,1,16); WHBFY(t1,src,0,2,16); WHBFY(t1,src,0,3,16); + WHBFY(t1,src,0,4,16); WHBFY(t1,src,0,5,16); WHBFY(t1,src,0,6,16); WHBFY(t1,src,0,7,16); + WHBFY(t1,src,0,8,16); WHBFY(t1,src,0,9,16); WHBFY(t1,src,0,10,16); WHBFY(t1,src,0,11,16); + WHBFY(t1,src,0,12,16); WHBFY(t1,src,0,13,16); WHBFY(t1,src,0,14,16); WHBFY(t1,src,0,15,16); + + // group 2 + WHBFY(t2,t1,0,0,8); WHBFY(t2,t1,0,1,8); WHBFY(t2,t1,0,2,8); WHBFY(t2,t1,0,3,8); + WHBFY(t2,t1,0,4,8); WHBFY(t2,t1,0,5,8); WHBFY(t2,t1,0,6,8); WHBFY(t2,t1,0,7,8); + WHBFY(t2,t1,16,0,8); WHBFY(t2,t1,16,1,8); WHBFY(t2,t1,16,2,8); WHBFY(t2,t1,16,3,8); + WHBFY(t2,t1,16,4,8); WHBFY(t2,t1,16,5,8); WHBFY(t2,t1,16,6,8); WHBFY(t2,t1,16,7,8); + + // group 3 + WHBFY(t1,t2,0,0,4); WHBFY(t1,t2,0,1,4); WHBFY(t1,t2,0,2,4); WHBFY(t1,t2,0,3,4); + WHBFY(t1,t2,8,0,4); WHBFY(t1,t2,8,1,4); WHBFY(t1,t2,8,2,4); WHBFY(t1,t2,8,3,4); + WHBFY(t1,t2,16,0,4); WHBFY(t1,t2,16,1,4); WHBFY(t1,t2,16,2,4); WHBFY(t1,t2,16,3,4); + WHBFY(t1,t2,24,0,4); WHBFY(t1,t2,24,1,4); WHBFY(t1,t2,24,2,4); WHBFY(t1,t2,24,3,4); + + // group 4 + WHBFY(t2,t1,0,0,2); WHBFY(t2,t1,0,1,2); WHBFY(t2,t1,4,0,2); WHBFY(t2,t1,4,1,2); + WHBFY(t2,t1,8,0,2); WHBFY(t2,t1,8,1,2); WHBFY(t2,t1,12,0,2); WHBFY(t2,t1,12,1,2); + WHBFY(t2,t1,16,0,2); WHBFY(t2,t1,16,1,2); WHBFY(t2,t1,20,0,2); WHBFY(t2,t1,20,1,2); + WHBFY(t2,t1,24,0,2); WHBFY(t2,t1,24,1,2); WHBFY(t2,t1,28,0,2); WHBFY(t2,t1,28,1,2); + + // group 5 + WHBFY(dst,t2,0,0,1); WHBFY(dst,t2,2,0,1); WHBFY(dst,t2,4,0,1); WHBFY(dst,t2,6,0,1); + WHBFY(dst,t2,8,0,1); WHBFY(dst,t2,10,0,1); WHBFY(dst,t2,12,0,1); WHBFY(dst,t2,14,0,1); + WHBFY(dst,t2,16,0,1); WHBFY(dst,t2,18,0,1); WHBFY(dst,t2,20,0,1); WHBFY(dst,t2,22,0,1); + WHBFY(dst,t2,24,0,1); WHBFY(dst,t2,26,0,1); WHBFY(dst,t2,28,0,1); WHBFY(dst,t2,30,0,1); + +} + +static void np_fwht64(float *dst, float *src) +{ + float t[128]; + float *t1=t, *t2=t+64; + + + // group 1 + WHBFY(t1,src,0,0,32); WHBFY(t1,src,0,1,32); WHBFY(t1,src,0,2,32); WHBFY(t1,src,0,3,32); + WHBFY(t1,src,0,4,32); WHBFY(t1,src,0,5,32); WHBFY(t1,src,0,6,32); WHBFY(t1,src,0,7,32); + WHBFY(t1,src,0,8,32); WHBFY(t1,src,0,9,32); WHBFY(t1,src,0,10,32); WHBFY(t1,src,0,11,32); + WHBFY(t1,src,0,12,32); WHBFY(t1,src,0,13,32); WHBFY(t1,src,0,14,32); WHBFY(t1,src,0,15,32); + WHBFY(t1,src,0,16,32); WHBFY(t1,src,0,17,32); WHBFY(t1,src,0,18,32); WHBFY(t1,src,0,19,32); + WHBFY(t1,src,0,20,32); WHBFY(t1,src,0,21,32); WHBFY(t1,src,0,22,32); WHBFY(t1,src,0,23,32); + WHBFY(t1,src,0,24,32); WHBFY(t1,src,0,25,32); WHBFY(t1,src,0,26,32); WHBFY(t1,src,0,27,32); + WHBFY(t1,src,0,28,32); WHBFY(t1,src,0,29,32); WHBFY(t1,src,0,30,32); WHBFY(t1,src,0,31,32); + + // group 2 + WHBFY(t2,t1,0,0,16); WHBFY(t2,t1,0,1,16); WHBFY(t2,t1,0,2,16); WHBFY(t2,t1,0,3,16); + WHBFY(t2,t1,0,4,16); WHBFY(t2,t1,0,5,16); WHBFY(t2,t1,0,6,16); WHBFY(t2,t1,0,7,16); + WHBFY(t2,t1,0,8,16); WHBFY(t2,t1,0,9,16); WHBFY(t2,t1,0,10,16); WHBFY(t2,t1,0,11,16); + WHBFY(t2,t1,0,12,16); WHBFY(t2,t1,0,13,16); WHBFY(t2,t1,0,14,16); WHBFY(t2,t1,0,15,16); + + WHBFY(t2,t1,32,0,16); WHBFY(t2,t1,32,1,16); WHBFY(t2,t1,32,2,16); WHBFY(t2,t1,32,3,16); + WHBFY(t2,t1,32,4,16); WHBFY(t2,t1,32,5,16); WHBFY(t2,t1,32,6,16); WHBFY(t2,t1,32,7,16); + WHBFY(t2,t1,32,8,16); WHBFY(t2,t1,32,9,16); WHBFY(t2,t1,32,10,16); WHBFY(t2,t1,32,11,16); + WHBFY(t2,t1,32,12,16); WHBFY(t2,t1,32,13,16); WHBFY(t2,t1,32,14,16); WHBFY(t2,t1,32,15,16); + + // group 3 + WHBFY(t1,t2,0,0,8); WHBFY(t1,t2,0,1,8); WHBFY(t1,t2,0,2,8); WHBFY(t1,t2,0,3,8); + WHBFY(t1,t2,0,4,8); WHBFY(t1,t2,0,5,8); WHBFY(t1,t2,0,6,8); WHBFY(t1,t2,0,7,8); + WHBFY(t1,t2,16,0,8); WHBFY(t1,t2,16,1,8); WHBFY(t1,t2,16,2,8); WHBFY(t1,t2,16,3,8); + WHBFY(t1,t2,16,4,8); WHBFY(t1,t2,16,5,8); WHBFY(t1,t2,16,6,8); WHBFY(t1,t2,16,7,8); + WHBFY(t1,t2,32,0,8); WHBFY(t1,t2,32,1,8); WHBFY(t1,t2,32,2,8); WHBFY(t1,t2,32,3,8); + WHBFY(t1,t2,32,4,8); WHBFY(t1,t2,32,5,8); WHBFY(t1,t2,32,6,8); WHBFY(t1,t2,32,7,8); + WHBFY(t1,t2,48,0,8); WHBFY(t1,t2,48,1,8); WHBFY(t1,t2,48,2,8); WHBFY(t1,t2,48,3,8); + WHBFY(t1,t2,48,4,8); WHBFY(t1,t2,48,5,8); WHBFY(t1,t2,48,6,8); WHBFY(t1,t2,48,7,8); + + // group 4 + WHBFY(t2,t1,0,0,4); WHBFY(t2,t1,0,1,4); WHBFY(t2,t1,0,2,4); WHBFY(t2,t1,0,3,4); + WHBFY(t2,t1,8,0,4); WHBFY(t2,t1,8,1,4); WHBFY(t2,t1,8,2,4); WHBFY(t2,t1,8,3,4); + WHBFY(t2,t1,16,0,4); WHBFY(t2,t1,16,1,4); WHBFY(t2,t1,16,2,4); WHBFY(t2,t1,16,3,4); + WHBFY(t2,t1,24,0,4); WHBFY(t2,t1,24,1,4); WHBFY(t2,t1,24,2,4); WHBFY(t2,t1,24,3,4); + WHBFY(t2,t1,32,0,4); WHBFY(t2,t1,32,1,4); WHBFY(t2,t1,32,2,4); WHBFY(t2,t1,32,3,4); + WHBFY(t2,t1,40,0,4); WHBFY(t2,t1,40,1,4); WHBFY(t2,t1,40,2,4); WHBFY(t2,t1,40,3,4); + WHBFY(t2,t1,48,0,4); WHBFY(t2,t1,48,1,4); WHBFY(t2,t1,48,2,4); WHBFY(t2,t1,48,3,4); + WHBFY(t2,t1,56,0,4); WHBFY(t2,t1,56,1,4); WHBFY(t2,t1,56,2,4); WHBFY(t2,t1,56,3,4); + + // group 5 + WHBFY(t1,t2,0,0,2); WHBFY(t1,t2,0,1,2); WHBFY(t1,t2,4,0,2); WHBFY(t1,t2,4,1,2); + WHBFY(t1,t2,8,0,2); WHBFY(t1,t2,8,1,2); WHBFY(t1,t2,12,0,2); WHBFY(t1,t2,12,1,2); + WHBFY(t1,t2,16,0,2); WHBFY(t1,t2,16,1,2); WHBFY(t1,t2,20,0,2); WHBFY(t1,t2,20,1,2); + WHBFY(t1,t2,24,0,2); WHBFY(t1,t2,24,1,2); WHBFY(t1,t2,28,0,2); WHBFY(t1,t2,28,1,2); + WHBFY(t1,t2,32,0,2); WHBFY(t1,t2,32,1,2); WHBFY(t1,t2,36,0,2); WHBFY(t1,t2,36,1,2); + WHBFY(t1,t2,40,0,2); WHBFY(t1,t2,40,1,2); WHBFY(t1,t2,44,0,2); WHBFY(t1,t2,44,1,2); + WHBFY(t1,t2,48,0,2); WHBFY(t1,t2,48,1,2); WHBFY(t1,t2,52,0,2); WHBFY(t1,t2,52,1,2); + WHBFY(t1,t2,56,0,2); WHBFY(t1,t2,56,1,2); WHBFY(t1,t2,60,0,2); WHBFY(t1,t2,60,1,2); + + // group 6 + WHBFY(dst,t1,0,0,1); WHBFY(dst,t1,2,0,1); WHBFY(dst,t1,4,0,1); WHBFY(dst,t1,6,0,1); + WHBFY(dst,t1,8,0,1); WHBFY(dst,t1,10,0,1); WHBFY(dst,t1,12,0,1); WHBFY(dst,t1,14,0,1); + WHBFY(dst,t1,16,0,1); WHBFY(dst,t1,18,0,1); WHBFY(dst,t1,20,0,1); WHBFY(dst,t1,22,0,1); + WHBFY(dst,t1,24,0,1); WHBFY(dst,t1,26,0,1); WHBFY(dst,t1,28,0,1); WHBFY(dst,t1,30,0,1); + WHBFY(dst,t1,32,0,1); WHBFY(dst,t1,34,0,1); WHBFY(dst,t1,36,0,1); WHBFY(dst,t1,38,0,1); + WHBFY(dst,t1,40,0,1); WHBFY(dst,t1,42,0,1); WHBFY(dst,t1,44,0,1); WHBFY(dst,t1,46,0,1); + WHBFY(dst,t1,48,0,1); WHBFY(dst,t1,50,0,1); WHBFY(dst,t1,52,0,1); WHBFY(dst,t1,54,0,1); + WHBFY(dst,t1,56,0,1); WHBFY(dst,t1,58,0,1); WHBFY(dst,t1,60,0,1); WHBFY(dst,t1,62,0,1); +} \ No newline at end of file diff --git a/lib/qra/q65/npfwht.h b/lib/qra/q65/npfwht.h new file mode 100644 index 000000000..9452e2077 --- /dev/null +++ b/lib/qra/q65/npfwht.h @@ -0,0 +1,45 @@ +// np_fwht.h +// Basic implementation of the Fast Walsh-Hadamard Transforms +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (repeat and accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#ifndef _npfwht_h_ +#define _npfwht_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +void np_fwht(int nlogdim, float *dst, float *src); +// Compute the Walsh-Hadamard transform of the given data up to a +// 64-dimensional transform +// +// Input parameters: +// nlogdim: log2 of the transform size. Must be in the range [0..6] +// src : pointer to the input data buffer. +// dst : pointer to the output data buffer. +// +// src and dst must point to preallocated data buffers of size 2^nlogdim*sizeof(float) +// src and dst buffers can overlap + +#ifdef __cplusplus +} +#endif + +#endif // _npfwht_ diff --git a/lib/qra/q65/pdmath.c b/lib/qra/q65/pdmath.c new file mode 100644 index 000000000..47ecab917 --- /dev/null +++ b/lib/qra/q65/pdmath.c @@ -0,0 +1,385 @@ +// pdmath.c +// Elementary math on probability distributions +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#include "pdmath.h" + +typedef const float *ppd_uniform; +typedef void (*ppd_imul)(float*,const float*); +typedef float (*ppd_norm)(float*); + +// define vector size in function of its logarithm in base 2 +static const int pd_log2dim[7] = { + 1,2,4,8,16,32,64 +}; + +// define uniform distributions of given size +static const float pd_uniform1[1] = { + 1. +}; +static const float pd_uniform2[2] = { + 1./2., 1./2. +}; +static const float pd_uniform4[4] = { + 1./4., 1./4.,1./4., 1./4. +}; +static const float pd_uniform8[8] = { + 1./8., 1./8.,1./8., 1./8.,1./8., 1./8.,1./8., 1./8. +}; +static const float pd_uniform16[16] = { + 1./16., 1./16., 1./16., 1./16.,1./16., 1./16.,1./16., 1./16., + 1./16., 1./16., 1./16., 1./16.,1./16., 1./16.,1./16., 1./16. +}; +static const float pd_uniform32[32] = { + 1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32., + 1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32., + 1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32., + 1./32., 1./32., 1./32., 1./32.,1./32., 1./32.,1./32., 1./32. +}; +static const float pd_uniform64[64] = { + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64., + 1./64., 1./64., 1./64., 1./64.,1./64., 1./64.,1./64., 1./64. + +}; + +static const ppd_uniform pd_uniform_tab[7] = { + pd_uniform1, + pd_uniform2, + pd_uniform4, + pd_uniform8, + pd_uniform16, + pd_uniform32, + pd_uniform64 +}; + +// returns a pointer to the uniform distribution of the given logsize +const float *pd_uniform(int nlogdim) +{ + return pd_uniform_tab[nlogdim]; +} + +// in-place multiplication functions +// compute dst = dst*src for any element of the distrib + +static void pd_imul1(float *dst, const float *src) +{ + dst[0] *= src[0]; +} + +static void pd_imul2(float *dst, const float *src) +{ + dst[0] *= src[0]; dst[1] *= src[1]; +} +static void pd_imul4(float *dst, const float *src) +{ + dst[0] *= src[0]; dst[1] *= src[1]; + dst[2] *= src[2]; dst[3] *= src[3]; +} +static void pd_imul8(float *dst, const float *src) +{ + dst[0] *= src[0]; dst[1] *= src[1]; dst[2] *= src[2]; dst[3] *= src[3]; + dst[4] *= src[4]; dst[5] *= src[5]; dst[6] *= src[6]; dst[7] *= src[7]; +} +static void pd_imul16(float *dst, const float *src) +{ + dst[0] *= src[0]; dst[1] *= src[1]; dst[2] *= src[2]; dst[3] *= src[3]; + dst[4] *= src[4]; dst[5] *= src[5]; dst[6] *= src[6]; dst[7] *= src[7]; + dst[8] *= src[8]; dst[9] *= src[9]; dst[10]*= src[10]; dst[11]*= src[11]; + dst[12]*= src[12]; dst[13]*= src[13]; dst[14]*= src[14]; dst[15]*= src[15]; +} +static void pd_imul32(float *dst, const float *src) +{ + pd_imul16(dst,src); + pd_imul16(dst+16,src+16); +} +static void pd_imul64(float *dst, const float *src) +{ + pd_imul16(dst, src); + pd_imul16(dst+16, src+16); + pd_imul16(dst+32, src+32); + pd_imul16(dst+48, src+48); +} + +static const ppd_imul pd_imul_tab[7] = { + pd_imul1, + pd_imul2, + pd_imul4, + pd_imul8, + pd_imul16, + pd_imul32, + pd_imul64 +}; + +// in place multiplication +// compute dst = dst*src for any element of the distrib give their log2 size +// arguments must be pointers to array of floats of the given size +void pd_imul(float *dst, const float *src, int nlogdim) +{ + pd_imul_tab[nlogdim](dst,src); +} + +static float pd_norm1(float *ppd) +{ + float t = ppd[0]; + ppd[0] = 1.f; + return t; +} + +static float pd_norm2(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; + + if (t<=0) { + pd_init(ppd,pd_uniform(1),pd_log2dim[1]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; + return to; + +} + +static float pd_norm4(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + + if (t<=0) { + pd_init(ppd,pd_uniform(2),pd_log2dim[2]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + return to; +} + +static float pd_norm8(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7]; + + if (t<=0) { + pd_init(ppd,pd_uniform(3),pd_log2dim[3]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t; + return to; +} +static float pd_norm16(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7]; + t +=ppd[8]; t +=ppd[9]; t +=ppd[10]; t +=ppd[11]; + t +=ppd[12]; t +=ppd[13]; t +=ppd[14]; t +=ppd[15]; + + if (t<=0) { + pd_init(ppd,pd_uniform(4),pd_log2dim[4]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t; + ppd[8] *=t; ppd[9] *=t; ppd[10] *=t; ppd[11] *=t; + ppd[12] *=t; ppd[13] *=t; ppd[14] *=t; ppd[15] *=t; + + return to; +} +static float pd_norm32(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7]; + t +=ppd[8]; t +=ppd[9]; t +=ppd[10]; t +=ppd[11]; + t +=ppd[12]; t +=ppd[13]; t +=ppd[14]; t +=ppd[15]; + t +=ppd[16]; t +=ppd[17]; t +=ppd[18]; t +=ppd[19]; + t +=ppd[20]; t +=ppd[21]; t +=ppd[22]; t +=ppd[23]; + t +=ppd[24]; t +=ppd[25]; t +=ppd[26]; t +=ppd[27]; + t +=ppd[28]; t +=ppd[29]; t +=ppd[30]; t +=ppd[31]; + + if (t<=0) { + pd_init(ppd,pd_uniform(5),pd_log2dim[5]); + return t; + } + + to = t; + t = 1.f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t; + ppd[8] *=t; ppd[9] *=t; ppd[10] *=t; ppd[11] *=t; + ppd[12] *=t; ppd[13] *=t; ppd[14] *=t; ppd[15] *=t; + ppd[16] *=t; ppd[17] *=t; ppd[18] *=t; ppd[19] *=t; + ppd[20] *=t; ppd[21] *=t; ppd[22] *=t; ppd[23] *=t; + ppd[24] *=t; ppd[25] *=t; ppd[26] *=t; ppd[27] *=t; + ppd[28] *=t; ppd[29] *=t; ppd[30] *=t; ppd[31] *=t; + + return to; +} + +static float pd_norm64(float *ppd) +{ + float t,to; + + t =ppd[0]; t +=ppd[1]; t +=ppd[2]; t +=ppd[3]; + t +=ppd[4]; t +=ppd[5]; t +=ppd[6]; t +=ppd[7]; + t +=ppd[8]; t +=ppd[9]; t +=ppd[10]; t +=ppd[11]; + t +=ppd[12]; t +=ppd[13]; t +=ppd[14]; t +=ppd[15]; + t +=ppd[16]; t +=ppd[17]; t +=ppd[18]; t +=ppd[19]; + t +=ppd[20]; t +=ppd[21]; t +=ppd[22]; t +=ppd[23]; + t +=ppd[24]; t +=ppd[25]; t +=ppd[26]; t +=ppd[27]; + t +=ppd[28]; t +=ppd[29]; t +=ppd[30]; t +=ppd[31]; + + t +=ppd[32]; t +=ppd[33]; t +=ppd[34]; t +=ppd[35]; + t +=ppd[36]; t +=ppd[37]; t +=ppd[38]; t +=ppd[39]; + t +=ppd[40]; t +=ppd[41]; t +=ppd[42]; t +=ppd[43]; + t +=ppd[44]; t +=ppd[45]; t +=ppd[46]; t +=ppd[47]; + t +=ppd[48]; t +=ppd[49]; t +=ppd[50]; t +=ppd[51]; + t +=ppd[52]; t +=ppd[53]; t +=ppd[54]; t +=ppd[55]; + t +=ppd[56]; t +=ppd[57]; t +=ppd[58]; t +=ppd[59]; + t +=ppd[60]; t +=ppd[61]; t +=ppd[62]; t +=ppd[63]; + + if (t<=0) { + pd_init(ppd,pd_uniform(6),pd_log2dim[6]); + return t; + } + + to = t; + t = 1.0f/t; + ppd[0] *=t; ppd[1] *=t; ppd[2] *=t; ppd[3] *=t; + ppd[4] *=t; ppd[5] *=t; ppd[6] *=t; ppd[7] *=t; + ppd[8] *=t; ppd[9] *=t; ppd[10] *=t; ppd[11] *=t; + ppd[12] *=t; ppd[13] *=t; ppd[14] *=t; ppd[15] *=t; + ppd[16] *=t; ppd[17] *=t; ppd[18] *=t; ppd[19] *=t; + ppd[20] *=t; ppd[21] *=t; ppd[22] *=t; ppd[23] *=t; + ppd[24] *=t; ppd[25] *=t; ppd[26] *=t; ppd[27] *=t; + ppd[28] *=t; ppd[29] *=t; ppd[30] *=t; ppd[31] *=t; + + ppd[32] *=t; ppd[33] *=t; ppd[34] *=t; ppd[35] *=t; + ppd[36] *=t; ppd[37] *=t; ppd[38] *=t; ppd[39] *=t; + ppd[40] *=t; ppd[41] *=t; ppd[42] *=t; ppd[43] *=t; + ppd[44] *=t; ppd[45] *=t; ppd[46] *=t; ppd[47] *=t; + ppd[48] *=t; ppd[49] *=t; ppd[50] *=t; ppd[51] *=t; + ppd[52] *=t; ppd[53] *=t; ppd[54] *=t; ppd[55] *=t; + ppd[56] *=t; ppd[57] *=t; ppd[58] *=t; ppd[59] *=t; + ppd[60] *=t; ppd[61] *=t; ppd[62] *=t; ppd[63] *=t; + + return to; +} + + +static const ppd_norm pd_norm_tab[7] = { + pd_norm1, + pd_norm2, + pd_norm4, + pd_norm8, + pd_norm16, + pd_norm32, + pd_norm64 +}; + +float pd_norm(float *pd, int nlogdim) +{ + return pd_norm_tab[nlogdim](pd); +} + +void pd_memset(float *dst, const float *src, int ndim, int nitems) +{ + int size = PD_SIZE(ndim); + while(nitems--) { + memcpy(dst,src,size); + dst +=ndim; + } +} + +void pd_fwdperm(float *dst, float *src, const int *perm, int ndim) +{ + // TODO: non-loop implementation + while (ndim--) + dst[ndim] = src[perm[ndim]]; +} + +void pd_bwdperm(float *dst, float *src, const int *perm, int ndim) +{ + // TODO: non-loop implementation + while (ndim--) + dst[perm[ndim]] = src[ndim]; +} + +float pd_max(float *src, int ndim) +{ + // TODO: faster implementation + + float cmax=0; // we assume that prob distributions are always positive + float cval; + + while (ndim--) { + cval = src[ndim]; + if (cval>=cmax) { + cmax = cval; + } + } + + return cmax; +} + +int pd_argmax(float *pmax, float *src, int ndim) +{ + // TODO: faster implementation + + float cmax=0; // we assume that prob distributions are always positive + float cval; + int idxmax=-1; // indicates that all pd elements are <0 + + while (ndim--) { + cval = src[ndim]; + if (cval>=cmax) { + cmax = cval; + idxmax = ndim; + } + } + + if (pmax) + *pmax = cmax; + + return idxmax; +} diff --git a/lib/qra/q65/pdmath.h b/lib/qra/q65/pdmath.h new file mode 100644 index 000000000..bbd1210c4 --- /dev/null +++ b/lib/qra/q65/pdmath.h @@ -0,0 +1,85 @@ +// pdmath.h +// Elementary math on probability distributions +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (repeat and accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + + +#ifndef _pdmath_h_ +#define _pdmath_h_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define PD_NDIM(nlogdim) ((1<<(nlogdim)) +#define PD_SIZE(ndim) ((ndim)*sizeof(float)) +#define PD_ROWADDR(fp,ndim,idx) (fp+((ndim)*(idx))) + +const float *pd_uniform(int nlogdim); +// Returns a pointer to a (constant) uniform distribution of the given log2 size + +#define pd_init(dst,src,ndim) memcpy(dst,src,PD_SIZE(ndim)) +// Distribution copy + +void pd_memset(float *dst, const float *src, int ndim, int nitems); +// Copy the distribution pointed by src to the array of distributions dst +// src is a pointer to the input distribution (a vector of size ndim) +// dst is a pointer to a linear array of distributions (a vector of size ndim*nitems) + +void pd_imul(float *dst, const float *src, int nlogdim); +// In place multiplication +// Compute dst = dst*src for any element of the distrib give their log2 size +// src and dst arguments must be pointers to array of floats of the given size + +float pd_norm(float *pd, int nlogdim); +// In place normalizazion +// Normalizes the input vector so that the sum of its components are one +// pd must be a pointer to an array of floats of the given size. +// If the norm of the input vector is non-positive the vector components +// are replaced with a uniform distribution +// Returns the norm of the distribution prior to the normalization + +void pd_fwdperm(float *dst, float *src, const int *perm, int ndim); +// Forward permutation of a distribution +// Computes dst[k] = src[perm[k]] for every element in the distribution +// perm must be a pointer to an array of integers of length ndim + +void pd_bwdperm(float *dst, float *src, const int *perm, int ndim); +// Backward permutation of a distribution +// Computes dst[perm[k]] = src[k] for every element in the distribution +// perm must be a pointer to an array of integers of length ndim + +float pd_max(float *src, int ndim); +// Return the maximum of the elements of the given distribution +// Assumes that the input vector is a probability distribution and that each element in the +// distribution is non negative + +int pd_argmax(float *pmax, float *src, int ndim); +// Return the index of the maximum element of the given distribution +// The maximum is stored in the variable pointed by pmax if pmax is not null +// Same note of pd_max applies. +// Return -1 if all the elements in the distribution are negative + +#ifdef __cplusplus +} +#endif + +#endif // _pdmath_h_ diff --git a/lib/qra/q65/q65.c b/lib/qra/q65/q65.c new file mode 100644 index 000000000..856d8d7a7 --- /dev/null +++ b/lib/qra/q65/q65.c @@ -0,0 +1,795 @@ +// q65.c +// q65 modes encoding/decoding functions +// +// (c) 2020 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#include +#include +#include + +#include "q65.h" +#include "pdmath.h" + + +static int _q65_crc6(int *x, int sz); +static void _q65_crc12(int *y, int *x, int sz); + + +int q65_init(q65_codec_ds *pCodec, const qracode *pqracode) +{ + // Eb/No value for which we optimize the decoder metric (AWGN/Rayleigh cases) + const float EbNodBMetric = 2.8f; + const float EbNoMetric = (float)pow(10,EbNodBMetric/10); + + float R; // code effective rate (after puncturing) + int nm; // bits per symbol + + if (!pCodec) + return -1; // why do you called me? + + if (!pqracode) + return -2; // invalid qra code + + if (pqracode->M!=64) + return -3; // q65 supports only codes over GF(64) + + pCodec->pQraCode = pqracode; + + // allocate buffers used by encoding/decoding functions + pCodec->x = (int*)malloc(pqracode->K*sizeof(int)); + pCodec->y = (int*)malloc(pqracode->N*sizeof(int)); + pCodec->qra_v2cmsg = (float*)malloc(pqracode->NMSG*pqracode->M*sizeof(float)); + pCodec->qra_c2vmsg = (float*)malloc(pqracode->NMSG*pqracode->M*sizeof(float)); + pCodec->ix = (float*)malloc(pqracode->N*pqracode->M*sizeof(float)); + pCodec->ex = (float*)malloc(pqracode->N*pqracode->M*sizeof(float)); + + if (pCodec->x== NULL || + pCodec->y== NULL || + pCodec->qra_v2cmsg== NULL || + pCodec->qra_c2vmsg== NULL || + pCodec->ix== NULL || + pCodec->ex== NULL) { + q65_free(pCodec); + return -4; // out of memory + } + + // compute and store the AWGN/Rayleigh Es/No ratio for which we optimize + // the decoder metric + nm = _q65_get_bits_per_symbol(pqracode); + R = _q65_get_code_rate(pqracode); + pCodec->decoderEsNoMetric = 1.0f*nm*R*EbNoMetric; + + return 1; +} + +void q65_free(q65_codec_ds *pCodec) +{ + if (!pCodec) + return; + + // free internal buffers + if (pCodec->x!=NULL) + free(pCodec->x); + + if (pCodec->y!=NULL) + free(pCodec->y); + + if (pCodec->qra_v2cmsg!=NULL) + free(pCodec->qra_v2cmsg); + + if (pCodec->qra_c2vmsg!=NULL) + free(pCodec->qra_c2vmsg); + + if (pCodec->ix!=NULL) + free(pCodec->ix); + + if (pCodec->ex!=NULL) + free(pCodec->ex); + + pCodec->pQraCode = NULL; + pCodec->x = NULL; + pCodec->y = NULL; + pCodec->qra_v2cmsg = NULL; + pCodec->qra_c2vmsg = NULL; + pCodec->qra_v2cmsg = NULL; + pCodec->ix = NULL; + pCodec->ex = NULL; + + return; +} + +int q65_encode(const q65_codec_ds *pCodec, int *pOutputCodeword, const int *pInputMsg) +{ + const qracode *pQraCode; + int *px; + int *py; + int nK; + int nN; + + if (!pCodec) + return -1; // which codec? + + pQraCode = pCodec->pQraCode; + px = pCodec->x; + py = pCodec->y; + nK = _q65_get_message_length(pQraCode); + nN = _q65_get_codeword_length(pQraCode); + + // copy the information symbols into the internal buffer + memcpy(px,pInputMsg,nK*sizeof(int)); + + // compute and append the appropriate CRC if required + switch (pQraCode->type) { + case QRATYPE_NORMAL: + break; + case QRATYPE_CRC: + case QRATYPE_CRCPUNCTURED: + px[nK] = _q65_crc6(px,nK); + break; + case QRATYPE_CRCPUNCTURED2: + _q65_crc12(px+nK,px,nK); + break; + default: + return -2; // code type not supported + } + + // encode with the given qra code + qra_encode(pQraCode,py,px); + + // puncture the CRC symbols as required + // and copy the result to the destination buffer + switch (pQraCode->type) { + case QRATYPE_NORMAL: + case QRATYPE_CRC: + // no puncturing + memcpy(pOutputCodeword,py,nN*sizeof(int)); + break; + case QRATYPE_CRCPUNCTURED: + // strip the single CRC symbol from the encoded codeword + memcpy(pOutputCodeword,py,nK*sizeof(int)); // copy the systematic symbols + memcpy(pOutputCodeword+nK,py+nK+1,(nN-nK)*sizeof(int)); // copy the check symbols skipping the CRC symbol + break; + case QRATYPE_CRCPUNCTURED2: + // strip the 2 CRC symbols from the encoded codeword + memcpy(pOutputCodeword,py,nK*sizeof(int)); // copy the systematic symbols + memcpy(pOutputCodeword+nK,py+nK+2,(nN-nK)*sizeof(int)); // copy the check symbols skipping the two CRC symbols + break; + default: + return -2; // code type unsupported + } + + return 1; // ok +} + +int q65_intrinsics(q65_codec_ds *pCodec, float *pIntrinsics, const float *pInputEnergies) +{ + // compute observations intrinsics probabilities + // for the AWGN/Rayleigh channels + + // NOTE: + // A true Rayleigh channel metric would require that the channel gains were known + // for each symbol in the codeword. Such gains cannot be estimated reliably when + // the Es/No ratio is small. Therefore we compute intrinsic probabilities assuming + // that, on average, these channel gains are unitary. + // In general it is even difficult to estimate the Es/No ratio for the AWGN channel + // Therefore we always compute the intrinsic probabilities assuming that the Es/No + // ratio is known and equal to the constant decoderEsNoMetric. This assumption will + // generate the true intrinsic probabilities only when the actual Eb/No ratio is + // equal to this constant. As in all the other cases the probabilities are evaluated + // with a wrong scaling constant we can expect that the decoder performance at different + // Es/No will be worse. Anyway, since the EsNoMetric constant has been chosen so that the + // decoder error rate is about 50%, we obtain almost optimal error rates down to + // any useful Es/No ratio. + + const qracode *pQraCode; + int nN, nBits; + float EsNoMetric; + + if (pCodec==NULL) + return -1; // which codec? + + pQraCode = pCodec->pQraCode; + nN = _q65_get_codeword_length(pQraCode); + nBits = pQraCode->m; + + EsNoMetric = pCodec->decoderEsNoMetric; + qra_mfskbesselmetric(pIntrinsics,pInputEnergies,nBits,nN,EsNoMetric); + + return 1; // success +} + +int q65_esnodb(const q65_codec_ds *pCodec, float *pEsNodB, const int *ydec, const float *pInputEnergies) +{ + // compute average Es/No for the AWGN/Rayleigh channel cases + + int k,j; + float sigplusnoise=0; + float noise=0; + int nN, nM; + const float *pIn = pInputEnergies; + const int *py = ydec; + float EsNodB; + + nN = q65_get_codeword_length(pCodec); + nM = q65_get_alphabet_size(pCodec); + + for (k=0;k4) + return Q65_DECODE_INVPARAMS; // invalid submode + + // As the symbol duration in q65 is longer than in QRA64 the fading tables continue + // to be valid if the B90 parameter is scaled by the actual symbol rate + // Compute index to most appropriate weighting function coefficients + hidx = (int)(logf(B90*TS_Q65/TS_QRA64)/logf(1.09f) - 0.499f); + +// if (hidx<0 || hidx > 64) +// // index of weighting function out of range +// // B90 out of range +// return q65_DECODE_INVPARAMS; + + // Unlike in QRA64 we accept any B90, anyway limiting it to + // the extreme cases (0.9 to 210 Hz approx.) + if (hidx<0) + hidx = 0; + else + if (hidx > 64) + hidx=64; + + // select the appropriate weighting fading coefficients array + if (fadingModel==0) { // gaussian fading model + // point to gaussian energy weighting taps + hlen = glen_tab_gauss[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = gptr_tab_gauss[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else if (fadingModel==1) { + // point to lorentzian energy weighting taps + hlen = glen_tab_lorentz[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = gptr_tab_lorentz[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else + return Q65_DECODE_INVPARAMS; // invalid fading model + + // compute (euristically) the optimal decoder metric accordingly the given spread amount + // We assume that the decoder 50% decoding threshold is: + // Es/No(dB) = Es/No(AWGN)(dB) + 8*log(B90)/log(240)(dB) + // that's to say, at the maximum Doppler spread bandwidth (240 Hz for QRA64) + // there's a ~8 dB Es/No degradation over the AWGN case + fTemp = 8.0f*logf(B90)/logf(240.0f); // assumed Es/No degradation for the given fading bandwidth + EsNoMetric = pCodec->decoderEsNoMetric*powf(10.0f,fTemp/10.0f); + + nM = q65_get_alphabet_size(pCodec); + nN = q65_get_codeword_length(pCodec); + nBinsPerTone = 1<ffNoiseVar = fNoiseVar; + pCodec->ffEsNoMetric = EsNoMetric; + pCodec->nBinsPerTone = nBinsPerTone; + pCodec->nBinsPerSymbol = nBinsPerSymbol; + pCodec->nWeights = hlen; + weight = pCodec->ffWeight; + + // compute the fast fading weights accordingly to the Es/No ratio + // for which we compute the exact intrinsics probabilities + for (k=0;kmaxlogp) // keep track of the max + maxlogp = fTemp; + pCurIx[k]=fTemp; + + pCurBin += nBinsPerTone; // next tone + } + + // exponentiate and accumulate the normalization constant + sumix = 0.0f; + for (k=0;knBinsPerTone; + nBinsPerSymbol = pCodec->nBinsPerSymbol; + nWeights = pCodec->nWeights; + ffNoiseVar = pCodec->ffNoiseVar; + ffEsNoMetric = pCodec->ffEsNoMetric; + nTotWeights = 2*nWeights-1; + + // compute symbols energy (noise included) summing the + // energies pertaining to the decoded symbols in the codeword + + EsPlusWNo = 0.0f; + pCurSym = pInputEnergies + nM; // point to first central bin of first symbol tone + for (n=0;npQraCode; + ix = pCodec->ix; + ex = pCodec->ex; + + nK = _q65_get_message_length(pQraCode); + nN = _q65_get_codeword_length(pQraCode); + nM = pQraCode->M; + nBits = pQraCode->m; + + px = pCodec->x; + py = pCodec->y; + + // Depuncture intrinsics observations as required by the code type + switch (pQraCode->type) { + case QRATYPE_CRCPUNCTURED: + memcpy(ix,pIntrinsics,nK*nM*sizeof(float)); // information symbols + pd_init(PD_ROWADDR(ix,nM,nK),pd_uniform(nBits),nM); // crc + memcpy(ix+(nK+1)*nM,pIntrinsics+nK*nM,(nN-nK)*nM*sizeof(float)); // parity checks + break; + case QRATYPE_CRCPUNCTURED2: + memcpy(ix,pIntrinsics,nK*nM*sizeof(float)); // information symbols + pd_init(PD_ROWADDR(ix,nM,nK),pd_uniform(nBits),nM); // crc + pd_init(PD_ROWADDR(ix,nM,nK+1),pd_uniform(nBits),nM); // crc + memcpy(ix+(nK+2)*nM,pIntrinsics+nK*nM,(nN-nK)*nM*sizeof(float)); // parity checks + break; + case QRATYPE_NORMAL: + case QRATYPE_CRC: + default: + // no puncturing + memcpy(ix,pIntrinsics,nN*nM*sizeof(float)); // as they are + } + + // mask the intrinsics with the available a priori knowledge + if (pAPMask!=NULL) + _q65_mask(pQraCode,ix,pAPMask,pAPSymbols); + + + // Compute the extrinsic symbols probabilities with the message-passing algorithm + // Stop if the extrinsics information does not converges to unity + // within the given number of iterations + rc = qra_extrinsic( pQraCode, + ex, + ix, + 100, + pCodec->qra_v2cmsg, + pCodec->qra_c2vmsg); + + if (rc<0) + // failed to converge to a solution + return Q65_DECODE_FAILED; + + // decode the information symbols (punctured information symbols included) + qra_mapdecode(pQraCode,px,ex,ix); + + // verify CRC match + + switch (pQraCode->type) { + case QRATYPE_CRC: + case QRATYPE_CRCPUNCTURED: + crc6=_q65_crc6(px,nK); // compute crc-6 + if (crc6!=px[nK]) + return Q65_DECODE_CRCMISMATCH; // crc doesn't match + break; + case QRATYPE_CRCPUNCTURED2: + _q65_crc12(crc12, px,nK); // compute crc-12 + if (crc12[0]!=px[nK] || + crc12[1]!=px[nK+1]) + return Q65_DECODE_CRCMISMATCH; // crc doesn't match + break; + case QRATYPE_NORMAL: + default: + // nothing to check + break; + } + + // copy the decoded msg to the user buffer (excluding punctured symbols) + if (pDecodedMsg) + memcpy(pDecodedMsg,px,nK*sizeof(int)); + + if (pDecodedCodeword==NULL) // user is not interested in it + return rc; // return the number of iterations required to decode + + // crc matches therefore we can reconstruct the transmitted codeword + // reencoding the information available in px... + + qra_encode(pQraCode, py, px); + + // ...and strip the punctured symbols from the codeword + switch (pQraCode->type) { + case QRATYPE_CRCPUNCTURED: + memcpy(pDecodedCodeword,py,nK*sizeof(int)); + memcpy(pDecodedCodeword+nK,py+nK+1,(nN-nK)*sizeof(int)); // puncture crc-6 symbol + break; + case QRATYPE_CRCPUNCTURED2: + memcpy(pDecodedCodeword,py,nK*sizeof(int)); + memcpy(pDecodedCodeword+nK,py+nK+2,(nN-nK)*sizeof(int)); // puncture crc-12 symbols + break; + case QRATYPE_CRC: + case QRATYPE_NORMAL: + default: + memcpy(pDecodedCodeword,py,nN*sizeof(int)); // no puncturing + } + + return rc; // return the number of iterations required to decode + +} + + + + +// helper functions ------------------------------------------------------------- + +int _q65_get_message_length(const qracode *pCode) +{ + // return the actual information message length (in symbols) + // excluding any punctured symbol + + int nMsgLength; + + switch (pCode->type) { + case QRATYPE_NORMAL: + nMsgLength = pCode->K; + break; + case QRATYPE_CRC: + case QRATYPE_CRCPUNCTURED: + // one information symbol of the underlying qra code is reserved for CRC + nMsgLength = pCode->K-1; + break; + case QRATYPE_CRCPUNCTURED2: + // two code information symbols are reserved for CRC + nMsgLength = pCode->K-2; + break; + default: + nMsgLength = -1; + } + + return nMsgLength; +} + +int _q65_get_codeword_length(const qracode *pCode) +{ + // return the actual codeword length (in symbols) + // excluding any punctured symbol + + int nCwLength; + + switch (pCode->type) { + case QRATYPE_NORMAL: + case QRATYPE_CRC: + // no puncturing + nCwLength = pCode->N; + break; + case QRATYPE_CRCPUNCTURED: + // the CRC symbol is punctured + nCwLength = pCode->N-1; + break; + case QRATYPE_CRCPUNCTURED2: + // the two CRC symbols are punctured + nCwLength = pCode->N-2; + break; + default: + nCwLength = -1; + } + + return nCwLength; +} + +float _q65_get_code_rate(const qracode *pCode) +{ + return 1.0f*_q65_get_message_length(pCode)/_q65_get_codeword_length(pCode); +} + +int _q65_get_alphabet_size(const qracode *pCode) +{ + return pCode->M; +} +int _q65_get_bits_per_symbol(const qracode *pCode) +{ + return pCode->m; +} +static void _q65_mask(const qracode *pcode, float *ix, const int *mask, const int *x) +{ + // mask intrinsic information ix with available a priori knowledge + + int k,kk, smask; + const int nM=pcode->M; + const int nm=pcode->m; + int nK; + + // Exclude from masking the symbols which have been punctured. + // nK is the length of the mask and x arrays, which do + // not include any punctured symbol + nK = _q65_get_message_length(pcode); + + // for each symbol set to zero the probability + // of the values which are not allowed by + // the a priori information + + for (k=0;k>1) ^ CRC6_GEN_POL; + else + sr = (sr>>1); + t>>=1; + } + } + + return sr; +} + +static void _q65_crc12(int *y, int *x, int sz) +{ + int k,j,t,sr = 0; + for (k=0;k>1) ^ CRC12_GEN_POL; + else + sr = (sr>>1); + t>>=1; + } + } + + y[0] = sr&0x3F; + y[1] = (sr>>6); +} + + diff --git a/lib/qra/q65/q65.h b/lib/qra/q65/q65.h new file mode 100644 index 000000000..04b5d8365 --- /dev/null +++ b/lib/qra/q65/q65.h @@ -0,0 +1,103 @@ +// q65.h +// Q65 modes encoding/decoding functions +// +// (c) 2020 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#ifndef _q65_h +#define _q65_h + +#include "qracodes.h" + +// Error codes returned by q65_decode(...) +#define Q65_DECODE_INVPARAMS -1 +#define Q65_DECODE_FAILED -2 +#define Q65_DECODE_CRCMISMATCH -3 + +// maximum number of weights for the fast-fading metric evaluation +#define Q65_FASTFADING_MAXWEIGTHS 65 + +typedef struct { + const qracode *pQraCode; // qra code to be used by the codec + float decoderEsNoMetric; // value for which we optimize the decoder metric + int *x; // codec input + int *y; // codec output + float *qra_v2cmsg; // decoder v->c messages + float *qra_c2vmsg; // decoder c->v messages + float *ix; // decoder intrinsic information + float *ex; // decoder extrinsic information + // variables used to compute the intrinsics in the fast-fading case + int nBinsPerTone; + int nBinsPerSymbol; + float ffNoiseVar; + float ffEsNoMetric; + int nWeights; + float ffWeight[Q65_FASTFADING_MAXWEIGTHS]; +} q65_codec_ds; + +int q65_init(q65_codec_ds *pCodec, const qracode *pQraCode); +void q65_free(q65_codec_ds *pCodec); + +int q65_encode(const q65_codec_ds *pCodec, int *pOutputCodeword, const int *pInputMsg); + +int q65_intrinsics(q65_codec_ds *pCodec, float *pIntrinsics, const float *pInputEnergies); + +int q65_intrinsics_fastfading(q65_codec_ds *pCodec, + float *pIntrinsics, // intrinsic symbol probabilities output + const float *pInputEnergies, // received energies input + const int submode, // submode idx (0=A ... 4=E) + const float B90, // spread bandwidth (90% fractional energy) + const int fadingModel); // 0=Gaussian 1=Lorentzian fade model + + +int q65_decode(q65_codec_ds *pCodec, + int* pDecodedCodeword, + int *pDecodedMsg, + const float *pIntrinsics, + const int *pAPMask, + const int *pAPSymbols); + +int q65_esnodb(const q65_codec_ds *pCodec, + float *pEsNodB, + const int *ydec, + const float *pInputEnergies); + +int q65_esnodb_fastfading( + const q65_codec_ds *pCodec, + float *pEsNodB, + const int *ydec, + const float *pInputEnergies); + + +// helper functions +#define q65_get_message_length(pCodec) _q65_get_message_length((pCodec)->pQraCode) +#define q65_get_codeword_length(pCodec) _q65_get_codeword_length((pCodec)->pQraCode) +#define q65_get_code_rate(pCodec) _q65_get_code_rate((pCodec)->pQraCode) +#define q65_get_alphabet_size(pCodec) _q65_get_alphabet_size((pCodec)->pQraCode) +#define q65_get_bits_per_symbol(pCodec) _q65_get_bits_per_symbol((pCodec)->pQraCode) + + +// internally used but made public for the above defines +int _q65_get_message_length(const qracode *pCode); +int _q65_get_codeword_length(const qracode *pCode); +float _q65_get_code_rate(const qracode *pCode); +void _q65_mask(const qracode *pcode, float *ix, const int *mask, const int *x); +int _q65_get_alphabet_size(const qracode *pCode); +int _q65_get_bits_per_symbol(const qracode *pCode); + +#endif // _qra65_h \ No newline at end of file diff --git a/lib/qra/q65/q65.sln b/lib/qra/q65/q65.sln new file mode 100644 index 000000000..1ac03a6ae --- /dev/null +++ b/lib/qra/q65/q65.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "q65", "q65.vcproj", "{933A58F6-199B-4723-ACFE-3013E6DD9D0A}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {933A58F6-199B-4723-ACFE-3013E6DD9D0A}.Debug|Win32.ActiveCfg = Debug|Win32 + {933A58F6-199B-4723-ACFE-3013E6DD9D0A}.Debug|Win32.Build.0 = Debug|Win32 + {933A58F6-199B-4723-ACFE-3013E6DD9D0A}.Release|Win32.ActiveCfg = Release|Win32 + {933A58F6-199B-4723-ACFE-3013E6DD9D0A}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/lib/qra/q65/q65.vcproj b/lib/qra/q65/q65.vcproj new file mode 100644 index 000000000..36b3235e1 --- /dev/null +++ b/lib/qra/q65/q65.vcproj @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/qra/q65/q65test.c b/lib/qra/q65/q65test.c new file mode 100644 index 000000000..e90792803 --- /dev/null +++ b/lib/qra/q65/q65test.c @@ -0,0 +1,910 @@ +// q65test.c +// Word Error Rate test example for the Q65 mode +// Multi-threaded simulator version + +// (c) 2020 - Nico Palermo, IV3NWV +// +// +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// Dependencies: +// q65test.c - this file +// normrnd.c/.h - random gaussian number generator +// npfwht.c/.h - Fast Walsh-Hadamard Transforms +// pdmath.c/.h - Elementary math on probability distributions +// qra15_65_64_irr_e23.c/.h - Tables for the QRA(15,65) irregular RA code used by Q65 +// qracodes.c/.h - QRA codes encoding/decoding functions +// fadengauss.c - fading coefficients tables for gaussian shaped fast fading channels +// fadenlorenz.c - fading coefficients tables for lorenzian shaped fast fading channels +// +// ------------------------------------------------------------------------------- +// +// This is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . +// +// ------------------------------------------------------------------------------ + +// OS dependent defines and includes -------------------------------------------- + +#if _WIN32 // note the underscore: without it, it's not msdn official! + // Windows (x64 and x86) + #define _CRT_SECURE_NO_WARNINGS // we don't need warnings for sprintf/fopen function usage + #include // required only for GetTickCount(...) + #include // _beginthread +#endif + +#if defined(__linux__) + +// remove unwanted macros +#define __cdecl + +// implements Windows API +#include + + unsigned int GetTickCount(void) { + struct timespec ts; + unsigned int theTick = 0U; + clock_gettime( CLOCK_REALTIME, &ts ); + theTick = ts.tv_nsec / 1000000; + theTick += ts.tv_sec * 1000; + return theTick; +} + +// Convert Windows millisecond sleep +// +// VOID WINAPI Sleep(_In_ DWORD dwMilliseconds); +// +// to Posix usleep (in microseconds) +// +// int usleep(useconds_t usec); +// +#include +#define Sleep(x) usleep(x*1000) + +#endif + +#if defined(__linux__) || ( defined(__MINGW32__) || defined (__MIGW64__) ) +#include +#endif + +#if __APPLE__ +#endif + +#include +#include + +#include "qracodes.h" // basic qra encoding/decoding functions +#include "normrnd.h" // gaussian numbers generator +#include "pdmath.h" // operations on probability distributions + +#include "qra15_65_64_irr_e23.h" // QRA code used by Q65 +#include "q65.h" + +#define Q65_TS 0.640f // Q65 symbol time interval in seconds +#define Q65_REFBW 2500.0f // reference bandwidth in Hz for SNR estimates + +// ----------------------------------------------------------------------------------- + +#define NTHREADS_MAX 160 // if you have some big enterprise hardware + +// channel types +#define CHANNEL_AWGN 0 +#define CHANNEL_RAYLEIGH 1 +#define CHANNEL_FASTFADING 2 + +// amount of a-priori information provided to the decoder +#define AP_NONE 0 +#define AP_MYCALL 1 +#define AP_HISCALL 2 +#define AP_BOTHCALL 3 +#define AP_FULL 4 +#define AP_LAST AP_FULL + +const char ap_str[AP_LAST+1][16] = { + "None", + "32 bit", + "32 bit", + "62 bit", + "78 bit", +}; +const char fnameout_sfx[AP_LAST+1][64] = { + "-ap00.txt", + "-ap32m.txt", + "-ap32h.txt", + "-ap62.txt", + "-ap78.txt" +}; + +const char fnameout_pfx[3][64] = { + "wer-awgn-", + "wer-rayl-", + "wer-ff-" +}; + +// AP masks are computed assuming that the source message has been packed in 13 symbols s[0]..[s12] +// in a little indian format, that's to say: + +// s[0] = {src5 src4 src3 src2 src1 src0} +// s[1] = {src11 src10 src9 src8 src7 src6} +// ... +// s[12]= {src78 src77 src76 src75 src74 src73} +// +// where srcj is the j-th bit of the source message. +// +// It is also assumed that the source message is as indicated by the protocol specification of wsjt-x +// structured messages. src78 should be always set to a value known by the decoder (and masked as an AP bit) +// With this convention the field i3 of the structured message is mapped to bits src77 src76 src75, +// that's to say to the 3rd,4th and 5th bit of s[12]. +// Therefore, if i3 is known in advance, since src78 is always known, +// the AP mask for s[12] is 0x3C (4 most significant bits of s[12] are known) + +const int ap_masks_q65[AP_LAST+1][13] = { +// AP0 Mask +{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +// Mask first(c28 r1) .... i3 src78 (AP32my MyCall ? ? StdMsg) +{ 0x3F, 0x3F, 0x3F, 0x3F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C}, +// Mask second(c28 r1) .... i3 src78 (AP32his ? HisCall ? StdMsg) +{ 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x3F, 0x3F, 0x3F, 0x0F, 0x00, 0x00, 0x3C}, +// Mask (c28 r1 c28 r1) ... i3 src78 (AP62 MyCall HisCall ? StdMsg) +{ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x0F, 0x00, 0x00, 0x3C}, +// Mask All (c28 r1 c28 r1 R g15 StdMsg src78) (AP78) +{ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F}, +}; + +int verbose = 0; + +void printword(char *msg, int *x, int size) +{ + int k; + printf("\n%s ",msg); + for (k=0;kchannel_type; + + rc = q65_init(&codec,pdata->pcode); + + if (rc<0) { + printf("error in qra65_init\n"); + goto term_thread; + } + + nK = q65_get_message_length(&codec); + nN = q65_get_codeword_length(&codec); + nM = q65_get_alphabet_size(&codec); + nm = q65_get_bits_per_symbol(&codec); + R = q65_get_code_rate(&codec); + + nSamples = nN*nM; + + x = (int*)malloc(nK*sizeof(int)); + xdec = (int*)malloc(nK*sizeof(int)); + y = (int*)malloc(nN*sizeof(int)); + ydec = (int*)malloc(nN*sizeof(int)); + rsquared = (float*)malloc(nSamples*sizeof(float)); + pIntrinsics = (float*)malloc(nSamples*sizeof(float)); + + // sets the AP mask to be used for this simulation + if (pdata->ap_index==AP_NONE) + apMask = NULL; // we simply avoid masking if ap-index specifies no AP + else + apMask = ap_masks_q65[pdata->ap_index]; + + // Channel simulation variables -------------------- + rp = (float*)malloc(nSamples*sizeof(float)); + rq = (float*)malloc(nSamples*sizeof(float)); + chp = (float*)malloc(nN*sizeof(float)); + chq = (float*)malloc(nN*sizeof(float)); + + EbNo = (float)powf(10,pdata->EbNodB/10); + EsNo = 1.0f*nm*R*EbNo; + Es = EsNo*No; + A = (float)sqrt(Es); + + // Generate a (meaningless) test message + for (k=0;kstop==0) { + + // Channel simulation -------------------------------------------- + // Generate AWGN noise + normrnd_s(rp,nSamples,0,sigma); + normrnd_s(rq,nSamples,0,sigma); + + if (channel_type == CHANNEL_AWGN) + // add symbol amplitudes + for (k=0;k0 && verbose==1) { + float EbNodBestimated; + float SNRdBestimated; + q65_esnodb(&codec, &EsNodBestimated, ydec,rsquared); + EbNodBestimated = EsNodBestimated -10.0f*log10f(R*nm); + SNRdBestimated = EsNodBestimated -10.0f*log10f(Q65_TS*Q65_REFBW); + printf("\nEstimated Eb/No=%5.1fdB SNR2500=%5.1fdB", + EbNodBestimated, + SNRdBestimated); + } + + nt = nt+1; + pdata->nt=nt; + pdata->nerrs=nerrs; + pdata->ncrcwrong = ncrcwrong; + } + +term_thread: + + free(x); + free(xdec); + free(y); + free(ydec); + free(rsquared); + free(pIntrinsics); + + free(rp); + free(rq); + free(chp); + free(chq); + + q65_free(&codec); + + // signal the calling thread we are quitting + pdata->done=1; + #if _WIN32 + _endthread(); + #endif +} + +void wer_test_thread_ff(wer_test_ds *pdata) +{ + // We don't do a realistic simulation of the fading-channel here + // If required give a look to the simulator used in the QRA64 mode. + // For the purpose of testing the formal correctness of the Q65 decoder + // fast-fadind routines here we simulate the channel as a Rayleigh channel + // with no frequency spread but use the q65....-fastfading routines + // to check that they produce correct results also in this case. + + const int submode = 2; // Assume that we are using the Q65C tone spacing + const float B90 = 4.0f; // Configure the Q65 fast-fading decoder for a the given freq. spread + const int fadingModel = 1; // Assume a lorenzian frequency spread + + int nt = 0; // transmitted codewords + int nerrs = 0; // total number of errors + int ncrcwrong = 0; // number of decodes with wrong crc + + q65_codec_ds codec; + + int rc, k; + int nK, nN, nM, nm, nSamples; + int *x, *y, *xdec, *ydec; + const int *apMask; + float R; + float *rsquared, *pIntrinsics; + float EsNodBestimated; + + int nBinsPerTone, nBinsPerSymbol; + + + // for channel simulation + const float No = 1.0f; // noise spectral density + const float sigma = sqrtf(No/2.0f); // std dev of I/Q noise components + const float sigmach = sqrtf(1/2.0f); // std dev of I/Q channel gains (Rayleigh channel) + float EbNo, EsNo, Es, A; + float *rp, *rq, *chp, *chq; + int channel_type = pdata->channel_type; + + rc = q65_init(&codec,pdata->pcode); + + if (rc<0) { + printf("error in q65_init\n"); + goto term_thread; + } + + nK = q65_get_message_length(&codec); + nN = q65_get_codeword_length(&codec); + nM = q65_get_alphabet_size(&codec); + nm = q65_get_bits_per_symbol(&codec); + R = q65_get_code_rate(&codec); + + + nBinsPerTone = 1<ap_index==AP_NONE) + apMask = NULL; // we simply avoid masking if ap-index specifies no AP + else + apMask = ap_masks_q65[pdata->ap_index]; + + + x = (int*)malloc(nK*sizeof(int)); + xdec = (int*)malloc(nK*sizeof(int)); + y = (int*)malloc(nN*sizeof(int)); + ydec = (int*)malloc(nN*sizeof(int)); + rsquared = (float*)malloc(nSamples*sizeof(float)); + pIntrinsics = (float*)malloc(nN*nM*sizeof(float)); + + // Channel simulation variables -------------------- + rp = (float*)malloc(nSamples*sizeof(float)); + rq = (float*)malloc(nSamples*sizeof(float)); + chp = (float*)malloc(nN*sizeof(float)); + chq = (float*)malloc(nN*sizeof(float)); + + EbNo = (float)powf(10,pdata->EbNodB/10); + EsNo = 1.0f*nm*R*EbNo; + Es = EsNo*No; + A = (float)sqrt(Es); + // ------------------------------------------------- + + // generate a test message + for (k=0;kstop==0) { + + // Channel simulation -------------------------------------------- + // generate AWGN noise + normrnd_s(rp,nSamples,0,sigma); + normrnd_s(rq,nSamples,0,sigma); + + + // Generate Rayleigh distributed symbol amplitudes + normrnd_s(chp,nN,0,sigmach); + normrnd_s(chq,nN,0,sigmach); + // Don't simulate a really frequency spreaded signal. + // Just place the tones in the appropriate central bins + // ot the received signal + for (k=0;k0 && verbose==1) { + float EbNodBestimated; + float SNRdBestimated; + // use the fastfading version + q65_esnodb_fastfading(&codec, &EsNodBestimated, ydec,rsquared); + EbNodBestimated = EsNodBestimated -10.0f*log10f(R*nm); + SNRdBestimated = EsNodBestimated -10.0f*log10f(Q65_TS*Q65_REFBW); + printf("\nEstimated Eb/No=%5.1fdB SNR2500=%5.1fdB", + EbNodBestimated, + SNRdBestimated); + } + + nt = nt+1; + pdata->nt=nt; + pdata->nerrs=nerrs; + pdata->ncrcwrong = ncrcwrong; + } + +term_thread: + + free(x); + free(xdec); + free(y); + free(ydec); + free(rsquared); + free(pIntrinsics); + + free(rp); + free(rq); + free(chp); + free(chq); + + q65_free(&codec); + + // signal the calling thread we are quitting + pdata->done=1; + #if _WIN32 + _endthread(); + #endif +} + + +#if defined(__linux__) || ( defined(__MINGW32__) || defined (__MIGW64__) ) + +void *wer_test_pthread_awgnrayl(void *p) +{ + wer_test_thread_awgnrayl((wer_test_ds *)p); + return 0; +} + +void *wer_test_pthread_ff(void *p) +{ + wer_test_thread_ff((wer_test_ds *)p); + return 0; +} + +#endif + + +int wer_test_proc(const qracode *pcode, int nthreads, int chtype, int ap_index, float *EbNodB, int *nerrstgt, int nitems) +{ + int k,j,nt,nerrs,nerrsu,ncrcwrong,nd; + int cini,cend; + char fnameout[128]; + FILE *fout; + wer_test_ds wt[NTHREADS_MAX]; + float pe,peu,avgt; + + if (nthreads>NTHREADS_MAX) { + printf("Error: nthreads should be <=%d\n",NTHREADS_MAX); + return -1; + } + + sprintf(fnameout,"%s%s%s", + fnameout_pfx[chtype], + pcode->name, + fnameout_sfx[ap_index]); + + fout = fopen(fnameout,"w"); + fprintf(fout,"#Code Name: %s\n",pcode->name); + fprintf(fout,"#ChannelType (0=AWGN,1=Rayleigh,2=Fast-Fading)\n#Eb/No (dB)\n#Transmitted Codewords\n#Errors\n#CRC Errors\n#Undetected\n#Avg dec. time (ms)\n#WER\n#UER\n"); + + printf("\nTesting the code %s\nSimulation data will be saved to %s\n", + pcode->name, + fnameout); + fflush (stdout); + + // init fixed thread parameters and preallocate buffers + for (j=0;j=nerrstgt[k]) { + for (j=0;j] [-t] [-c] [-a] [-f[-h]\n"); + printf("Options: \n"); + printf(" -q: code to simulate. 0=qra_15_65_64_irr_e23 (default)\n"); + printf(" -t : number of threads to be used for the simulation [1..24]\n"); + printf(" (default=8)\n"); + printf(" -c : channel_type. 0=AWGN 1=Rayleigh 2=Fast-Fading\n"); + printf(" (default=AWGN)\n"); + printf(" -a : amount of a-priori information provided to decoder. \n"); + printf(" 0= No a-priori (default)\n"); + printf(" 1= 32 bit (Mycall)\n"); + printf(" 2= 32 bit (Hiscall)\n"); + printf(" 3= 62 bit (Bothcalls\n"); + printf(" 4= 78 bit (full AP)\n"); + printf(" -v : verbose (output SNRs of decoded messages\n"); + + printf(" -f : name of the file containing the Eb/No values to be simulated\n"); + printf(" (default=ebnovalues.txt)\n"); + printf(" This file should contain lines in this format:\n"); + printf(" # Eb/No(dB) Target Errors\n"); + printf(" 0.1 5000\n"); + printf(" 0.6 5000\n"); + printf(" 1.1 1000\n"); + printf(" 1.6 1000\n"); + printf(" ...\n"); + printf(" (lines beginning with a # are treated as comments\n\n"); +} + +#define SIM_POINTS_MAX 20 + +int main(int argc, char* argv[]) +{ + + float EbNodB[SIM_POINTS_MAX]; + int nerrstgt[SIM_POINTS_MAX]; + FILE *fin; + + char fnamein[128]= "ebnovalues.txt"; + char buf[128]; + + int nitems = 0; + int code_idx = 0; + int nthreads = 8; + int ch_type = CHANNEL_AWGN; + int ap_index = AP_NONE; + + // parse command line + while(--argc) { + argv++; + if (strncmp(*argv,"-h",2)==0) { + syntax(); + return 0; + } + else + if (strncmp(*argv,"-q",2)==0) { + code_idx = (int)atoi((*argv)+2); + if (code_idx>7) { + printf("Invalid code index\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-t",2)==0) { + nthreads = (int)atoi((*argv)+2); + +// printf("nthreads = %d\n",nthreads); + + if (nthreads>NTHREADS_MAX) { + printf("Invalid number of threads\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-c",2)==0) { + ch_type = (int)atoi((*argv)+2); + if (ch_type>CHANNEL_FASTFADING) { + printf("Invalid channel type\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-a",2)==0) { + ap_index = (int)atoi((*argv)+2); + if (ap_index>AP_LAST) { + printf("Invalid a-priori information index\n"); + syntax(); + return -1; + } + } + else + if (strncmp(*argv,"-f",2)==0) { + strncpy(fnamein,(*argv)+2,127); + } + else + if (strncmp(*argv,"-h",2)==0) { + syntax(); + return -1; + } + else + if (strncmp(*argv,"-v",2)==0) + verbose = TRUE; + else { + printf("Invalid option\n"); + syntax(); + return -1; + } + } + + // parse points to be simulated from the input file + fin = fopen(fnamein,"r"); + if (!fin) { + printf("Can't open file: %s\n",fnamein); + syntax(); + return -1; + } + + while (fgets(buf,128,fin)!=0) + if (*buf=='#' || *buf=='\n' ) + continue; + else + if (nitems==SIM_POINTS_MAX) + break; + else + if (sscanf(buf,"%f %u",&EbNodB[nitems],&nerrstgt[nitems])!=2) { + printf("Invalid input file format\n"); + syntax(); + return -1; + } + else + nitems++; + + fclose(fin); + + if (nitems==0) { + printf("No Eb/No point specified in file %s\n",fnamein); + syntax(); + return -1; + } + + printf("\nQ65 Word Error Rate Simulator\n"); + printf("(c) 2016-2020, Nico Palermo - IV3NWV\n\n"); + + printf("Nthreads = %d\n",nthreads); + switch(ch_type) { + case CHANNEL_AWGN: + printf("Channel = AWGN\n"); + break; + case CHANNEL_RAYLEIGH: + printf("Channel = Rayleigh\n"); + break; + case CHANNEL_FASTFADING: + printf("Channel = Fast Fading\n"); + break; + } + printf("Codename = %s\n",codetotest[code_idx]->name); + printf("A-priori = %s\n",ap_str[ap_index]); + printf("Eb/No input file = %s\n\n",fnamein); + + wer_test_proc(codetotest[code_idx], nthreads, ch_type, ap_index, EbNodB, nerrstgt, nitems); + + printf("\n\n\n"); + return 0; +} + diff --git a/lib/qra/q65/qra15_65_64_irr_e23.c b/lib/qra/q65/qra15_65_64_irr_e23.c new file mode 100644 index 000000000..d56e057fd --- /dev/null +++ b/lib/qra/q65/qra15_65_64_irr_e23.c @@ -0,0 +1,557 @@ +// qra15_65_64_irr_e23.c +// Encoding/Decoding tables for Q-ary RA code (15,65) over GF(64) +// Code Name: qra15_65_64_irr_e23 +// (15,65) RA Code over GF(64) + +// (c) 2020 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy + +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#include "qra15_65_64_irr_e23.h" + +// File generated by npiwnarsavehc.m + +#define qra_K 15 // number of information symbols +#define qra_N 65 // codeword length in symbols +#define qra_m 6 // bits/symbol +#define qra_M 64 // Symbol alphabet cardinality +#define qra_a 1 // grouping factor +#define qra_NC 50 // number of check symbols (N-K) + +// Defines used by the message passing decoder -------- + +#define qra_V 65 // number of variables in the code graph (N) +#define qra_C 116 // number of factors in the code graph (N +(N-K)+1) +#define qra_NMSG 216 // number of msgs in the code graph +#define qra_MAXVDEG 5 // maximum variable degree +#define qra_MAXCDEG 3 // maximum factor degree +#define qra_R 0.23077f // code rate (K/N) +#define CODE_NAME "qra15_65_64_irr_e23" // code name + +// table of the systematic symbols indexes in the accumulator chain +static const int qra_acc_input_idx[qra_NC+1] = { + 13, 1, 3, 4, 8, 12, 9, 14, 10, 5, + 0, 7, 1, 11, 8, 9, 12, 6, 3, 10, + 7, 5, 2, 13, 12, 4, 8, 0, 1, 11, + 2, 9, 14, 5, 6, 13, 7, 12, 11, 2, + 9, 0, 10, 4, 7, 14, 8, 11, 3, 6, + 10 +}; + +// table of the systematic symbols weight logarithms over GF(M) +static const int qra_acc_input_wlog[qra_NC+1] = { + 0, 14, 0, 0, 13, 37, 0, 27, 56, 62, + 29, 0, 52, 34, 62, 4, 3, 22, 25, 0, + 22, 0, 20, 10, 0, 43, 53, 60, 0, 0, + 0, 62, 0, 5, 0, 61, 36, 31, 61, 59, + 10, 0, 29, 39, 25, 18, 0, 14, 11, 50, + 17 +}; + +// table of the logarithms of the elements of GF(M) (log(0) never used) +static const int qra_log[qra_M] = { + -1, 0, 1, 6, 2, 12, 7, 26, 3, 32, + 13, 35, 8, 48, 27, 18, 4, 24, 33, 16, + 14, 52, 36, 54, 9, 45, 49, 38, 28, 41, + 19, 56, 5, 62, 25, 11, 34, 31, 17, 47, + 15, 23, 53, 51, 37, 44, 55, 40, 10, 61, + 46, 30, 50, 22, 39, 43, 29, 60, 42, 21, + 20, 59, 57, 58 +}; + +// table of GF(M) elements given their logarithm +static const int qra_exp[qra_M-1] = { + 1, 2, 4, 8, 16, 32, 3, 6, 12, 24, + 48, 35, 5, 10, 20, 40, 19, 38, 15, 30, + 60, 59, 53, 41, 17, 34, 7, 14, 28, 56, + 51, 37, 9, 18, 36, 11, 22, 44, 27, 54, + 47, 29, 58, 55, 45, 25, 50, 39, 13, 26, + 52, 43, 21, 42, 23, 46, 31, 62, 63, 61, + 57, 49, 33 +}; + +// table of the messages weight logarithms over GF(M) +static const int qra_msgw[qra_NMSG] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 14, 0, 0, 13, + 37, 0, 27, 56, 62, 29, 0, 52, 34, 62, + 4, 3, 22, 25, 0, 22, 0, 20, 10, 0, + 43, 53, 60, 0, 0, 0, 62, 0, 5, 0, + 61, 36, 31, 61, 59, 10, 0, 29, 39, 25, + 18, 0, 14, 11, 50, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0 +}; + +// table of the degrees of the variable nodes +static const int qra_vdeg[qra_V] = { + 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, + 5, 5, 5, 4, 4, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3 +}; + +// table of the degrees of the factor nodes +static const int qra_cdeg[qra_C] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 2 +}; + +// table (uncompressed) of the v->c message indexes (-1=unused entry) +static const int qra_v2cmidx[qra_V*qra_MAXVDEG] = { + 0, 75, 92, 106, -1, + 1, 66, 77, 93, -1, + 2, 87, 95, 104, -1, + 3, 67, 83, 113, -1, + 4, 68, 90, 108, -1, + 5, 74, 86, 98, -1, + 6, 82, 99, 114, -1, + 7, 76, 85, 101, 109, + 8, 69, 79, 91, 111, + 9, 71, 80, 96, 105, + 10, 73, 84, 107, 115, + 11, 78, 94, 103, 112, + 12, 70, 81, 89, 102, + 13, 65, 88, 100, -1, + 14, 72, 97, 110, -1, + 15, 116, 117, -1, -1, + 16, 118, 119, -1, -1, + 17, 120, 121, -1, -1, + 18, 122, 123, -1, -1, + 19, 124, 125, -1, -1, + 20, 126, 127, -1, -1, + 21, 128, 129, -1, -1, + 22, 130, 131, -1, -1, + 23, 132, 133, -1, -1, + 24, 134, 135, -1, -1, + 25, 136, 137, -1, -1, + 26, 138, 139, -1, -1, + 27, 140, 141, -1, -1, + 28, 142, 143, -1, -1, + 29, 144, 145, -1, -1, + 30, 146, 147, -1, -1, + 31, 148, 149, -1, -1, + 32, 150, 151, -1, -1, + 33, 152, 153, -1, -1, + 34, 154, 155, -1, -1, + 35, 156, 157, -1, -1, + 36, 158, 159, -1, -1, + 37, 160, 161, -1, -1, + 38, 162, 163, -1, -1, + 39, 164, 165, -1, -1, + 40, 166, 167, -1, -1, + 41, 168, 169, -1, -1, + 42, 170, 171, -1, -1, + 43, 172, 173, -1, -1, + 44, 174, 175, -1, -1, + 45, 176, 177, -1, -1, + 46, 178, 179, -1, -1, + 47, 180, 181, -1, -1, + 48, 182, 183, -1, -1, + 49, 184, 185, -1, -1, + 50, 186, 187, -1, -1, + 51, 188, 189, -1, -1, + 52, 190, 191, -1, -1, + 53, 192, 193, -1, -1, + 54, 194, 195, -1, -1, + 55, 196, 197, -1, -1, + 56, 198, 199, -1, -1, + 57, 200, 201, -1, -1, + 58, 202, 203, -1, -1, + 59, 204, 205, -1, -1, + 60, 206, 207, -1, -1, + 61, 208, 209, -1, -1, + 62, 210, 211, -1, -1, + 63, 212, 213, -1, -1, + 64, 214, 215, -1, -1 +}; + +// table (uncompressed) of the c->v message indexes (-1=unused entry) +static const int qra_c2vmidx[qra_C*qra_MAXCDEG] = { + 0, -1, -1, 1, -1, -1, 2, -1, -1, 3, -1, -1, + 4, -1, -1, 5, -1, -1, 6, -1, -1, 7, -1, -1, + 8, -1, -1, 9, -1, -1, 10, -1, -1, 11, -1, -1, + 12, -1, -1, 13, -1, -1, 14, -1, -1, 15, -1, -1, + 16, -1, -1, 17, -1, -1, 18, -1, -1, 19, -1, -1, + 20, -1, -1, 21, -1, -1, 22, -1, -1, 23, -1, -1, + 24, -1, -1, 25, -1, -1, 26, -1, -1, 27, -1, -1, + 28, -1, -1, 29, -1, -1, 30, -1, -1, 31, -1, -1, + 32, -1, -1, 33, -1, -1, 34, -1, -1, 35, -1, -1, + 36, -1, -1, 37, -1, -1, 38, -1, -1, 39, -1, -1, + 40, -1, -1, 41, -1, -1, 42, -1, -1, 43, -1, -1, + 44, -1, -1, 45, -1, -1, 46, -1, -1, 47, -1, -1, + 48, -1, -1, 49, -1, -1, 50, -1, -1, 51, -1, -1, + 52, -1, -1, 53, -1, -1, 54, -1, -1, 55, -1, -1, + 56, -1, -1, 57, -1, -1, 58, -1, -1, 59, -1, -1, + 60, -1, -1, 61, -1, -1, 62, -1, -1, 63, -1, -1, + 64, -1, -1, 65, 116, -1, 66, 117, 118, 67, 119, 120, + 68, 121, 122, 69, 123, 124, 70, 125, 126, 71, 127, 128, + 72, 129, 130, 73, 131, 132, 74, 133, 134, 75, 135, 136, + 76, 137, 138, 77, 139, 140, 78, 141, 142, 79, 143, 144, + 80, 145, 146, 81, 147, 148, 82, 149, 150, 83, 151, 152, + 84, 153, 154, 85, 155, 156, 86, 157, 158, 87, 159, 160, + 88, 161, 162, 89, 163, 164, 90, 165, 166, 91, 167, 168, + 92, 169, 170, 93, 171, 172, 94, 173, 174, 95, 175, 176, + 96, 177, 178, 97, 179, 180, 98, 181, 182, 99, 183, 184, +100, 185, 186, 101, 187, 188, 102, 189, 190, 103, 191, 192, +104, 193, 194, 105, 195, 196, 106, 197, 198, 107, 199, 200, +108, 201, 202, 109, 203, 204, 110, 205, 206, 111, 207, 208, +112, 209, 210, 113, 211, 212, 114, 213, 214, 115, 215, -1 +}; + +// permutation matrix to compute Prob(x*alfa^logw) +static const int qra_pmat[qra_M*qra_M] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 33, 1, 32, 2, 35, 3, 34, 4, 37, 5, 36, 6, 39, 7, 38, + 8, 41, 9, 40, 10, 43, 11, 42, 12, 45, 13, 44, 14, 47, 15, 46, + 16, 49, 17, 48, 18, 51, 19, 50, 20, 53, 21, 52, 22, 55, 23, 54, + 24, 57, 25, 56, 26, 59, 27, 58, 28, 61, 29, 60, 30, 63, 31, 62, + 0, 49, 33, 16, 1, 48, 32, 17, 2, 51, 35, 18, 3, 50, 34, 19, + 4, 53, 37, 20, 5, 52, 36, 21, 6, 55, 39, 22, 7, 54, 38, 23, + 8, 57, 41, 24, 9, 56, 40, 25, 10, 59, 43, 26, 11, 58, 42, 27, + 12, 61, 45, 28, 13, 60, 44, 29, 14, 63, 47, 30, 15, 62, 46, 31, + 0, 57, 49, 8, 33, 24, 16, 41, 1, 56, 48, 9, 32, 25, 17, 40, + 2, 59, 51, 10, 35, 26, 18, 43, 3, 58, 50, 11, 34, 27, 19, 42, + 4, 61, 53, 12, 37, 28, 20, 45, 5, 60, 52, 13, 36, 29, 21, 44, + 6, 63, 55, 14, 39, 30, 22, 47, 7, 62, 54, 15, 38, 31, 23, 46, + 0, 61, 57, 4, 49, 12, 8, 53, 33, 28, 24, 37, 16, 45, 41, 20, + 1, 60, 56, 5, 48, 13, 9, 52, 32, 29, 25, 36, 17, 44, 40, 21, + 2, 63, 59, 6, 51, 14, 10, 55, 35, 30, 26, 39, 18, 47, 43, 22, + 3, 62, 58, 7, 50, 15, 11, 54, 34, 31, 27, 38, 19, 46, 42, 23, + 0, 63, 61, 2, 57, 6, 4, 59, 49, 14, 12, 51, 8, 55, 53, 10, + 33, 30, 28, 35, 24, 39, 37, 26, 16, 47, 45, 18, 41, 22, 20, 43, + 1, 62, 60, 3, 56, 7, 5, 58, 48, 15, 13, 50, 9, 54, 52, 11, + 32, 31, 29, 34, 25, 38, 36, 27, 17, 46, 44, 19, 40, 23, 21, 42, + 0, 62, 63, 1, 61, 3, 2, 60, 57, 7, 6, 56, 4, 58, 59, 5, + 49, 15, 14, 48, 12, 50, 51, 13, 8, 54, 55, 9, 53, 11, 10, 52, + 33, 31, 30, 32, 28, 34, 35, 29, 24, 38, 39, 25, 37, 27, 26, 36, + 16, 46, 47, 17, 45, 19, 18, 44, 41, 23, 22, 40, 20, 42, 43, 21, + 0, 31, 62, 33, 63, 32, 1, 30, 61, 34, 3, 28, 2, 29, 60, 35, + 57, 38, 7, 24, 6, 25, 56, 39, 4, 27, 58, 37, 59, 36, 5, 26, + 49, 46, 15, 16, 14, 17, 48, 47, 12, 19, 50, 45, 51, 44, 13, 18, + 8, 23, 54, 41, 55, 40, 9, 22, 53, 42, 11, 20, 10, 21, 52, 43, + 0, 46, 31, 49, 62, 16, 33, 15, 63, 17, 32, 14, 1, 47, 30, 48, + 61, 19, 34, 12, 3, 45, 28, 50, 2, 44, 29, 51, 60, 18, 35, 13, + 57, 23, 38, 8, 7, 41, 24, 54, 6, 40, 25, 55, 56, 22, 39, 9, + 4, 42, 27, 53, 58, 20, 37, 11, 59, 21, 36, 10, 5, 43, 26, 52, + 0, 23, 46, 57, 31, 8, 49, 38, 62, 41, 16, 7, 33, 54, 15, 24, + 63, 40, 17, 6, 32, 55, 14, 25, 1, 22, 47, 56, 30, 9, 48, 39, + 61, 42, 19, 4, 34, 53, 12, 27, 3, 20, 45, 58, 28, 11, 50, 37, + 2, 21, 44, 59, 29, 10, 51, 36, 60, 43, 18, 5, 35, 52, 13, 26, + 0, 42, 23, 61, 46, 4, 57, 19, 31, 53, 8, 34, 49, 27, 38, 12, + 62, 20, 41, 3, 16, 58, 7, 45, 33, 11, 54, 28, 15, 37, 24, 50, + 63, 21, 40, 2, 17, 59, 6, 44, 32, 10, 55, 29, 14, 36, 25, 51, + 1, 43, 22, 60, 47, 5, 56, 18, 30, 52, 9, 35, 48, 26, 39, 13, + 0, 21, 42, 63, 23, 2, 61, 40, 46, 59, 4, 17, 57, 44, 19, 6, + 31, 10, 53, 32, 8, 29, 34, 55, 49, 36, 27, 14, 38, 51, 12, 25, + 62, 43, 20, 1, 41, 60, 3, 22, 16, 5, 58, 47, 7, 18, 45, 56, + 33, 52, 11, 30, 54, 35, 28, 9, 15, 26, 37, 48, 24, 13, 50, 39, + 0, 43, 21, 62, 42, 1, 63, 20, 23, 60, 2, 41, 61, 22, 40, 3, + 46, 5, 59, 16, 4, 47, 17, 58, 57, 18, 44, 7, 19, 56, 6, 45, + 31, 52, 10, 33, 53, 30, 32, 11, 8, 35, 29, 54, 34, 9, 55, 28, + 49, 26, 36, 15, 27, 48, 14, 37, 38, 13, 51, 24, 12, 39, 25, 50, + 0, 52, 43, 31, 21, 33, 62, 10, 42, 30, 1, 53, 63, 11, 20, 32, + 23, 35, 60, 8, 2, 54, 41, 29, 61, 9, 22, 34, 40, 28, 3, 55, + 46, 26, 5, 49, 59, 15, 16, 36, 4, 48, 47, 27, 17, 37, 58, 14, + 57, 13, 18, 38, 44, 24, 7, 51, 19, 39, 56, 12, 6, 50, 45, 25, + 0, 26, 52, 46, 43, 49, 31, 5, 21, 15, 33, 59, 62, 36, 10, 16, + 42, 48, 30, 4, 1, 27, 53, 47, 63, 37, 11, 17, 20, 14, 32, 58, + 23, 13, 35, 57, 60, 38, 8, 18, 2, 24, 54, 44, 41, 51, 29, 7, + 61, 39, 9, 19, 22, 12, 34, 56, 40, 50, 28, 6, 3, 25, 55, 45, + 0, 13, 26, 23, 52, 57, 46, 35, 43, 38, 49, 60, 31, 18, 5, 8, + 21, 24, 15, 2, 33, 44, 59, 54, 62, 51, 36, 41, 10, 7, 16, 29, + 42, 39, 48, 61, 30, 19, 4, 9, 1, 12, 27, 22, 53, 56, 47, 34, + 63, 50, 37, 40, 11, 6, 17, 28, 20, 25, 14, 3, 32, 45, 58, 55, + 0, 39, 13, 42, 26, 61, 23, 48, 52, 19, 57, 30, 46, 9, 35, 4, + 43, 12, 38, 1, 49, 22, 60, 27, 31, 56, 18, 53, 5, 34, 8, 47, + 21, 50, 24, 63, 15, 40, 2, 37, 33, 6, 44, 11, 59, 28, 54, 17, + 62, 25, 51, 20, 36, 3, 41, 14, 10, 45, 7, 32, 16, 55, 29, 58, + 0, 50, 39, 21, 13, 63, 42, 24, 26, 40, 61, 15, 23, 37, 48, 2, + 52, 6, 19, 33, 57, 11, 30, 44, 46, 28, 9, 59, 35, 17, 4, 54, + 43, 25, 12, 62, 38, 20, 1, 51, 49, 3, 22, 36, 60, 14, 27, 41, + 31, 45, 56, 10, 18, 32, 53, 7, 5, 55, 34, 16, 8, 58, 47, 29, + 0, 25, 50, 43, 39, 62, 21, 12, 13, 20, 63, 38, 42, 51, 24, 1, + 26, 3, 40, 49, 61, 36, 15, 22, 23, 14, 37, 60, 48, 41, 2, 27, + 52, 45, 6, 31, 19, 10, 33, 56, 57, 32, 11, 18, 30, 7, 44, 53, + 46, 55, 28, 5, 9, 16, 59, 34, 35, 58, 17, 8, 4, 29, 54, 47, + 0, 45, 25, 52, 50, 31, 43, 6, 39, 10, 62, 19, 21, 56, 12, 33, + 13, 32, 20, 57, 63, 18, 38, 11, 42, 7, 51, 30, 24, 53, 1, 44, + 26, 55, 3, 46, 40, 5, 49, 28, 61, 16, 36, 9, 15, 34, 22, 59, + 23, 58, 14, 35, 37, 8, 60, 17, 48, 29, 41, 4, 2, 47, 27, 54, + 0, 55, 45, 26, 25, 46, 52, 3, 50, 5, 31, 40, 43, 28, 6, 49, + 39, 16, 10, 61, 62, 9, 19, 36, 21, 34, 56, 15, 12, 59, 33, 22, + 13, 58, 32, 23, 20, 35, 57, 14, 63, 8, 18, 37, 38, 17, 11, 60, + 42, 29, 7, 48, 51, 4, 30, 41, 24, 47, 53, 2, 1, 54, 44, 27, + 0, 58, 55, 13, 45, 23, 26, 32, 25, 35, 46, 20, 52, 14, 3, 57, + 50, 8, 5, 63, 31, 37, 40, 18, 43, 17, 28, 38, 6, 60, 49, 11, + 39, 29, 16, 42, 10, 48, 61, 7, 62, 4, 9, 51, 19, 41, 36, 30, + 21, 47, 34, 24, 56, 2, 15, 53, 12, 54, 59, 1, 33, 27, 22, 44, + 0, 29, 58, 39, 55, 42, 13, 16, 45, 48, 23, 10, 26, 7, 32, 61, + 25, 4, 35, 62, 46, 51, 20, 9, 52, 41, 14, 19, 3, 30, 57, 36, + 50, 47, 8, 21, 5, 24, 63, 34, 31, 2, 37, 56, 40, 53, 18, 15, + 43, 54, 17, 12, 28, 1, 38, 59, 6, 27, 60, 33, 49, 44, 11, 22, + 0, 47, 29, 50, 58, 21, 39, 8, 55, 24, 42, 5, 13, 34, 16, 63, + 45, 2, 48, 31, 23, 56, 10, 37, 26, 53, 7, 40, 32, 15, 61, 18, + 25, 54, 4, 43, 35, 12, 62, 17, 46, 1, 51, 28, 20, 59, 9, 38, + 52, 27, 41, 6, 14, 33, 19, 60, 3, 44, 30, 49, 57, 22, 36, 11, + 0, 54, 47, 25, 29, 43, 50, 4, 58, 12, 21, 35, 39, 17, 8, 62, + 55, 1, 24, 46, 42, 28, 5, 51, 13, 59, 34, 20, 16, 38, 63, 9, + 45, 27, 2, 52, 48, 6, 31, 41, 23, 33, 56, 14, 10, 60, 37, 19, + 26, 44, 53, 3, 7, 49, 40, 30, 32, 22, 15, 57, 61, 11, 18, 36, + 0, 27, 54, 45, 47, 52, 25, 2, 29, 6, 43, 48, 50, 41, 4, 31, + 58, 33, 12, 23, 21, 14, 35, 56, 39, 60, 17, 10, 8, 19, 62, 37, + 55, 44, 1, 26, 24, 3, 46, 53, 42, 49, 28, 7, 5, 30, 51, 40, + 13, 22, 59, 32, 34, 57, 20, 15, 16, 11, 38, 61, 63, 36, 9, 18, + 0, 44, 27, 55, 54, 26, 45, 1, 47, 3, 52, 24, 25, 53, 2, 46, + 29, 49, 6, 42, 43, 7, 48, 28, 50, 30, 41, 5, 4, 40, 31, 51, + 58, 22, 33, 13, 12, 32, 23, 59, 21, 57, 14, 34, 35, 15, 56, 20, + 39, 11, 60, 16, 17, 61, 10, 38, 8, 36, 19, 63, 62, 18, 37, 9, + 0, 22, 44, 58, 27, 13, 55, 33, 54, 32, 26, 12, 45, 59, 1, 23, + 47, 57, 3, 21, 52, 34, 24, 14, 25, 15, 53, 35, 2, 20, 46, 56, + 29, 11, 49, 39, 6, 16, 42, 60, 43, 61, 7, 17, 48, 38, 28, 10, + 50, 36, 30, 8, 41, 63, 5, 19, 4, 18, 40, 62, 31, 9, 51, 37, + 0, 11, 22, 29, 44, 39, 58, 49, 27, 16, 13, 6, 55, 60, 33, 42, + 54, 61, 32, 43, 26, 17, 12, 7, 45, 38, 59, 48, 1, 10, 23, 28, + 47, 36, 57, 50, 3, 8, 21, 30, 52, 63, 34, 41, 24, 19, 14, 5, + 25, 18, 15, 4, 53, 62, 35, 40, 2, 9, 20, 31, 46, 37, 56, 51, + 0, 36, 11, 47, 22, 50, 29, 57, 44, 8, 39, 3, 58, 30, 49, 21, + 27, 63, 16, 52, 13, 41, 6, 34, 55, 19, 60, 24, 33, 5, 42, 14, + 54, 18, 61, 25, 32, 4, 43, 15, 26, 62, 17, 53, 12, 40, 7, 35, + 45, 9, 38, 2, 59, 31, 48, 20, 1, 37, 10, 46, 23, 51, 28, 56, + 0, 18, 36, 54, 11, 25, 47, 61, 22, 4, 50, 32, 29, 15, 57, 43, + 44, 62, 8, 26, 39, 53, 3, 17, 58, 40, 30, 12, 49, 35, 21, 7, + 27, 9, 63, 45, 16, 2, 52, 38, 13, 31, 41, 59, 6, 20, 34, 48, + 55, 37, 19, 1, 60, 46, 24, 10, 33, 51, 5, 23, 42, 56, 14, 28, + 0, 9, 18, 27, 36, 45, 54, 63, 11, 2, 25, 16, 47, 38, 61, 52, + 22, 31, 4, 13, 50, 59, 32, 41, 29, 20, 15, 6, 57, 48, 43, 34, + 44, 37, 62, 55, 8, 1, 26, 19, 39, 46, 53, 60, 3, 10, 17, 24, + 58, 51, 40, 33, 30, 23, 12, 5, 49, 56, 35, 42, 21, 28, 7, 14, + 0, 37, 9, 44, 18, 55, 27, 62, 36, 1, 45, 8, 54, 19, 63, 26, + 11, 46, 2, 39, 25, 60, 16, 53, 47, 10, 38, 3, 61, 24, 52, 17, + 22, 51, 31, 58, 4, 33, 13, 40, 50, 23, 59, 30, 32, 5, 41, 12, + 29, 56, 20, 49, 15, 42, 6, 35, 57, 28, 48, 21, 43, 14, 34, 7, + 0, 51, 37, 22, 9, 58, 44, 31, 18, 33, 55, 4, 27, 40, 62, 13, + 36, 23, 1, 50, 45, 30, 8, 59, 54, 5, 19, 32, 63, 12, 26, 41, + 11, 56, 46, 29, 2, 49, 39, 20, 25, 42, 60, 15, 16, 35, 53, 6, + 47, 28, 10, 57, 38, 21, 3, 48, 61, 14, 24, 43, 52, 7, 17, 34, + 0, 56, 51, 11, 37, 29, 22, 46, 9, 49, 58, 2, 44, 20, 31, 39, + 18, 42, 33, 25, 55, 15, 4, 60, 27, 35, 40, 16, 62, 6, 13, 53, + 36, 28, 23, 47, 1, 57, 50, 10, 45, 21, 30, 38, 8, 48, 59, 3, + 54, 14, 5, 61, 19, 43, 32, 24, 63, 7, 12, 52, 26, 34, 41, 17, + 0, 28, 56, 36, 51, 47, 11, 23, 37, 57, 29, 1, 22, 10, 46, 50, + 9, 21, 49, 45, 58, 38, 2, 30, 44, 48, 20, 8, 31, 3, 39, 59, + 18, 14, 42, 54, 33, 61, 25, 5, 55, 43, 15, 19, 4, 24, 60, 32, + 27, 7, 35, 63, 40, 52, 16, 12, 62, 34, 6, 26, 13, 17, 53, 41, + 0, 14, 28, 18, 56, 54, 36, 42, 51, 61, 47, 33, 11, 5, 23, 25, + 37, 43, 57, 55, 29, 19, 1, 15, 22, 24, 10, 4, 46, 32, 50, 60, + 9, 7, 21, 27, 49, 63, 45, 35, 58, 52, 38, 40, 2, 12, 30, 16, + 44, 34, 48, 62, 20, 26, 8, 6, 31, 17, 3, 13, 39, 41, 59, 53, + 0, 7, 14, 9, 28, 27, 18, 21, 56, 63, 54, 49, 36, 35, 42, 45, + 51, 52, 61, 58, 47, 40, 33, 38, 11, 12, 5, 2, 23, 16, 25, 30, + 37, 34, 43, 44, 57, 62, 55, 48, 29, 26, 19, 20, 1, 6, 15, 8, + 22, 17, 24, 31, 10, 13, 4, 3, 46, 41, 32, 39, 50, 53, 60, 59, + 0, 34, 7, 37, 14, 44, 9, 43, 28, 62, 27, 57, 18, 48, 21, 55, + 56, 26, 63, 29, 54, 20, 49, 19, 36, 6, 35, 1, 42, 8, 45, 15, + 51, 17, 52, 22, 61, 31, 58, 24, 47, 13, 40, 10, 33, 3, 38, 4, + 11, 41, 12, 46, 5, 39, 2, 32, 23, 53, 16, 50, 25, 59, 30, 60, + 0, 17, 34, 51, 7, 22, 37, 52, 14, 31, 44, 61, 9, 24, 43, 58, + 28, 13, 62, 47, 27, 10, 57, 40, 18, 3, 48, 33, 21, 4, 55, 38, + 56, 41, 26, 11, 63, 46, 29, 12, 54, 39, 20, 5, 49, 32, 19, 2, + 36, 53, 6, 23, 35, 50, 1, 16, 42, 59, 8, 25, 45, 60, 15, 30, + 0, 41, 17, 56, 34, 11, 51, 26, 7, 46, 22, 63, 37, 12, 52, 29, + 14, 39, 31, 54, 44, 5, 61, 20, 9, 32, 24, 49, 43, 2, 58, 19, + 28, 53, 13, 36, 62, 23, 47, 6, 27, 50, 10, 35, 57, 16, 40, 1, + 18, 59, 3, 42, 48, 25, 33, 8, 21, 60, 4, 45, 55, 30, 38, 15, + 0, 53, 41, 28, 17, 36, 56, 13, 34, 23, 11, 62, 51, 6, 26, 47, + 7, 50, 46, 27, 22, 35, 63, 10, 37, 16, 12, 57, 52, 1, 29, 40, + 14, 59, 39, 18, 31, 42, 54, 3, 44, 25, 5, 48, 61, 8, 20, 33, + 9, 60, 32, 21, 24, 45, 49, 4, 43, 30, 2, 55, 58, 15, 19, 38, + 0, 59, 53, 14, 41, 18, 28, 39, 17, 42, 36, 31, 56, 3, 13, 54, + 34, 25, 23, 44, 11, 48, 62, 5, 51, 8, 6, 61, 26, 33, 47, 20, + 7, 60, 50, 9, 46, 21, 27, 32, 22, 45, 35, 24, 63, 4, 10, 49, + 37, 30, 16, 43, 12, 55, 57, 2, 52, 15, 1, 58, 29, 38, 40, 19, + 0, 60, 59, 7, 53, 9, 14, 50, 41, 21, 18, 46, 28, 32, 39, 27, + 17, 45, 42, 22, 36, 24, 31, 35, 56, 4, 3, 63, 13, 49, 54, 10, + 34, 30, 25, 37, 23, 43, 44, 16, 11, 55, 48, 12, 62, 2, 5, 57, + 51, 15, 8, 52, 6, 58, 61, 1, 26, 38, 33, 29, 47, 19, 20, 40, + 0, 30, 60, 34, 59, 37, 7, 25, 53, 43, 9, 23, 14, 16, 50, 44, + 41, 55, 21, 11, 18, 12, 46, 48, 28, 2, 32, 62, 39, 57, 27, 5, + 17, 15, 45, 51, 42, 52, 22, 8, 36, 58, 24, 6, 31, 1, 35, 61, + 56, 38, 4, 26, 3, 29, 63, 33, 13, 19, 49, 47, 54, 40, 10, 20, + 0, 15, 30, 17, 60, 51, 34, 45, 59, 52, 37, 42, 7, 8, 25, 22, + 53, 58, 43, 36, 9, 6, 23, 24, 14, 1, 16, 31, 50, 61, 44, 35, + 41, 38, 55, 56, 21, 26, 11, 4, 18, 29, 12, 3, 46, 33, 48, 63, + 28, 19, 2, 13, 32, 47, 62, 49, 39, 40, 57, 54, 27, 20, 5, 10, + 0, 38, 15, 41, 30, 56, 17, 55, 60, 26, 51, 21, 34, 4, 45, 11, + 59, 29, 52, 18, 37, 3, 42, 12, 7, 33, 8, 46, 25, 63, 22, 48, + 53, 19, 58, 28, 43, 13, 36, 2, 9, 47, 6, 32, 23, 49, 24, 62, + 14, 40, 1, 39, 16, 54, 31, 57, 50, 20, 61, 27, 44, 10, 35, 5, + 0, 19, 38, 53, 15, 28, 41, 58, 30, 13, 56, 43, 17, 2, 55, 36, + 60, 47, 26, 9, 51, 32, 21, 6, 34, 49, 4, 23, 45, 62, 11, 24, + 59, 40, 29, 14, 52, 39, 18, 1, 37, 54, 3, 16, 42, 57, 12, 31, + 7, 20, 33, 50, 8, 27, 46, 61, 25, 10, 63, 44, 22, 5, 48, 35, + 0, 40, 19, 59, 38, 14, 53, 29, 15, 39, 28, 52, 41, 1, 58, 18, + 30, 54, 13, 37, 56, 16, 43, 3, 17, 57, 2, 42, 55, 31, 36, 12, + 60, 20, 47, 7, 26, 50, 9, 33, 51, 27, 32, 8, 21, 61, 6, 46, + 34, 10, 49, 25, 4, 44, 23, 63, 45, 5, 62, 22, 11, 35, 24, 48, + 0, 20, 40, 60, 19, 7, 59, 47, 38, 50, 14, 26, 53, 33, 29, 9, + 15, 27, 39, 51, 28, 8, 52, 32, 41, 61, 1, 21, 58, 46, 18, 6, + 30, 10, 54, 34, 13, 25, 37, 49, 56, 44, 16, 4, 43, 63, 3, 23, + 17, 5, 57, 45, 2, 22, 42, 62, 55, 35, 31, 11, 36, 48, 12, 24, + 0, 10, 20, 30, 40, 34, 60, 54, 19, 25, 7, 13, 59, 49, 47, 37, + 38, 44, 50, 56, 14, 4, 26, 16, 53, 63, 33, 43, 29, 23, 9, 3, + 15, 5, 27, 17, 39, 45, 51, 57, 28, 22, 8, 2, 52, 62, 32, 42, + 41, 35, 61, 55, 1, 11, 21, 31, 58, 48, 46, 36, 18, 24, 6, 12, + 0, 5, 10, 15, 20, 17, 30, 27, 40, 45, 34, 39, 60, 57, 54, 51, + 19, 22, 25, 28, 7, 2, 13, 8, 59, 62, 49, 52, 47, 42, 37, 32, + 38, 35, 44, 41, 50, 55, 56, 61, 14, 11, 4, 1, 26, 31, 16, 21, + 53, 48, 63, 58, 33, 36, 43, 46, 29, 24, 23, 18, 9, 12, 3, 6, + 0, 35, 5, 38, 10, 41, 15, 44, 20, 55, 17, 50, 30, 61, 27, 56, + 40, 11, 45, 14, 34, 1, 39, 4, 60, 31, 57, 26, 54, 21, 51, 16, + 19, 48, 22, 53, 25, 58, 28, 63, 7, 36, 2, 33, 13, 46, 8, 43, + 59, 24, 62, 29, 49, 18, 52, 23, 47, 12, 42, 9, 37, 6, 32, 3, + 0, 48, 35, 19, 5, 53, 38, 22, 10, 58, 41, 25, 15, 63, 44, 28, + 20, 36, 55, 7, 17, 33, 50, 2, 30, 46, 61, 13, 27, 43, 56, 8, + 40, 24, 11, 59, 45, 29, 14, 62, 34, 18, 1, 49, 39, 23, 4, 52, + 60, 12, 31, 47, 57, 9, 26, 42, 54, 6, 21, 37, 51, 3, 16, 32, + 0, 24, 48, 40, 35, 59, 19, 11, 5, 29, 53, 45, 38, 62, 22, 14, + 10, 18, 58, 34, 41, 49, 25, 1, 15, 23, 63, 39, 44, 52, 28, 4, + 20, 12, 36, 60, 55, 47, 7, 31, 17, 9, 33, 57, 50, 42, 2, 26, + 30, 6, 46, 54, 61, 37, 13, 21, 27, 3, 43, 51, 56, 32, 8, 16, + 0, 12, 24, 20, 48, 60, 40, 36, 35, 47, 59, 55, 19, 31, 11, 7, + 5, 9, 29, 17, 53, 57, 45, 33, 38, 42, 62, 50, 22, 26, 14, 2, + 10, 6, 18, 30, 58, 54, 34, 46, 41, 37, 49, 61, 25, 21, 1, 13, + 15, 3, 23, 27, 63, 51, 39, 43, 44, 32, 52, 56, 28, 16, 4, 8, + 0, 6, 12, 10, 24, 30, 20, 18, 48, 54, 60, 58, 40, 46, 36, 34, + 35, 37, 47, 41, 59, 61, 55, 49, 19, 21, 31, 25, 11, 13, 7, 1, + 5, 3, 9, 15, 29, 27, 17, 23, 53, 51, 57, 63, 45, 43, 33, 39, + 38, 32, 42, 44, 62, 56, 50, 52, 22, 16, 26, 28, 14, 8, 2, 4, + 0, 3, 6, 5, 12, 15, 10, 9, 24, 27, 30, 29, 20, 23, 18, 17, + 48, 51, 54, 53, 60, 63, 58, 57, 40, 43, 46, 45, 36, 39, 34, 33, + 35, 32, 37, 38, 47, 44, 41, 42, 59, 56, 61, 62, 55, 52, 49, 50, + 19, 16, 21, 22, 31, 28, 25, 26, 11, 8, 13, 14, 7, 4, 1, 2, + 0, 32, 3, 35, 6, 38, 5, 37, 12, 44, 15, 47, 10, 42, 9, 41, + 24, 56, 27, 59, 30, 62, 29, 61, 20, 52, 23, 55, 18, 50, 17, 49, + 48, 16, 51, 19, 54, 22, 53, 21, 60, 28, 63, 31, 58, 26, 57, 25, + 40, 8, 43, 11, 46, 14, 45, 13, 36, 4, 39, 7, 34, 2, 33, 1, + 0, 16, 32, 48, 3, 19, 35, 51, 6, 22, 38, 54, 5, 21, 37, 53, + 12, 28, 44, 60, 15, 31, 47, 63, 10, 26, 42, 58, 9, 25, 41, 57, + 24, 8, 56, 40, 27, 11, 59, 43, 30, 14, 62, 46, 29, 13, 61, 45, + 20, 4, 52, 36, 23, 7, 55, 39, 18, 2, 50, 34, 17, 1, 49, 33, + 0, 8, 16, 24, 32, 40, 48, 56, 3, 11, 19, 27, 35, 43, 51, 59, + 6, 14, 22, 30, 38, 46, 54, 62, 5, 13, 21, 29, 37, 45, 53, 61, + 12, 4, 28, 20, 44, 36, 60, 52, 15, 7, 31, 23, 47, 39, 63, 55, + 10, 2, 26, 18, 42, 34, 58, 50, 9, 1, 25, 17, 41, 33, 57, 49, + 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, + 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63, + 6, 2, 14, 10, 22, 18, 30, 26, 38, 34, 46, 42, 54, 50, 62, 58, + 5, 1, 13, 9, 21, 17, 29, 25, 37, 33, 45, 41, 53, 49, 61, 57, + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, + 3, 1, 7, 5, 11, 9, 15, 13, 19, 17, 23, 21, 27, 25, 31, 29, + 35, 33, 39, 37, 43, 41, 47, 45, 51, 49, 55, 53, 59, 57, 63, 61 +}; + +// SO array +static const int SO[qra_N-qra_K+1] = { + 14, 2, 4, 5, 9, 13, 10, 15, 11, 6, 1, 8, 2, 12, 9, 10, + 13, 7, 4, 11, 8, 6, 3, 14, 13, 5, 9, 1, 2, 12, 3, 10, + 15, 6, 7, 14, 8, 13, 12, 3, 10, 1, 11, 5, 8, 15, 9, 12, + 4, 7, 11 +}; + +// LOGWO array +static const int LOGWO[qra_N-qra_K+1] = { + 0, 14, 0, 0, 13, 37, 0, 27, 56, 62, 29, 0, 52, 34, 62, 4, + 3, 22, 25, 0, 22, 0, 20, 10, 0, 43, 53, 60, 0, 0, 0, 62, + 0, 5, 0, 61, 36, 31, 61, 59, 10, 0, 29, 39, 25, 18, 0, 14, + 11, 50, 17 +}; + +// repfact array +static const int repfact[qra_K] = { + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 3, 3 +}; + +const qracode qra15_65_64_irr_e23 = { + qra_K, + qra_N, + qra_m, + qra_M, + qra_a, + qra_NC, + qra_V, + qra_C, + qra_NMSG, + qra_MAXVDEG, + qra_MAXCDEG, + QRATYPE_CRCPUNCTURED2, + qra_R, + CODE_NAME, + qra_acc_input_idx, + qra_acc_input_wlog, + qra_log, + qra_exp, + qra_msgw, + qra_vdeg, + qra_cdeg, + qra_v2cmidx, + qra_c2vmidx, + qra_pmat +}; +#undef qra_K +#undef qra_N +#undef qra_m +#undef qra_M +#undef qra_a +#undef qra_NC +#undef qra_V +#undef qra_C +#undef qra_NMSG +#undef qra_MAXVDEG +#undef qra_MAXCDEG +#undef qra_R +#undef CODE_NAME diff --git a/lib/qra/q65/qra15_65_64_irr_e23.h b/lib/qra/q65/qra15_65_64_irr_e23.h new file mode 100644 index 000000000..4e4f601c4 --- /dev/null +++ b/lib/qra/q65/qra15_65_64_irr_e23.h @@ -0,0 +1,41 @@ +// qra15_65_64_irr_e23.h +// Code tables and defines for Q-ary RA code (15,65) over GF(64) +// Code Name: qra15_65_64_irr_e23 +// (15,65) RA Code over GF(64) + +// (c) 2020 - Nico Palermo - IV3NWV - Microtelecom Srl, Italy + +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#ifndef _qra15_65_64_irr_e23_h +#define _qra15_65_64_irr_e23_h + +// File generated by npiwnarsavehc.m + +#include "qracodes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern const qracode qra15_65_64_irr_e23; + +#ifdef __cplusplus +} +#endif + +#endif // _qra15_65_64_irr_e23_h diff --git a/lib/qra/q65/qra65.c b/lib/qra/q65/qra65.c new file mode 100644 index 000000000..efb3e94a0 --- /dev/null +++ b/lib/qra/q65/qra65.c @@ -0,0 +1,795 @@ +// qra65.c +// QRA65 modes encoding/decoding functions +// +// (c) 2020 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#include +#include +#include + +#include "qra65.h" +#include "pdmath.h" + + +static int _qra65_crc6(int *x, int sz); +static void _qra65_crc12(int *y, int *x, int sz); + + +int qra65_init(qra65_codec_ds *pCodec, const qracode *pqracode) +{ + // Eb/No value for which we optimize the decoder metric (AWGN/Rayleigh cases) + const float EbNodBMetric = 2.8f; + const float EbNoMetric = (float)pow(10,EbNodBMetric/10); + + float R; // code effective rate (after puncturing) + int nm; // bits per symbol + + if (!pCodec) + return -1; // why do you called me? + + if (!pqracode) + return -2; // invalid qra code + + if (pqracode->M!=64) + return -3; // QRA65 supports only codes over GF(64) + + pCodec->pQraCode = pqracode; + + // allocate buffers used by encoding/decoding functions + pCodec->x = (int*)malloc(pqracode->K*sizeof(int)); + pCodec->y = (int*)malloc(pqracode->N*sizeof(int)); + pCodec->qra_v2cmsg = (float*)malloc(pqracode->NMSG*pqracode->M*sizeof(float)); + pCodec->qra_c2vmsg = (float*)malloc(pqracode->NMSG*pqracode->M*sizeof(float)); + pCodec->ix = (float*)malloc(pqracode->N*pqracode->M*sizeof(float)); + pCodec->ex = (float*)malloc(pqracode->N*pqracode->M*sizeof(float)); + + if (pCodec->x== NULL || + pCodec->y== NULL || + pCodec->qra_v2cmsg== NULL || + pCodec->qra_c2vmsg== NULL || + pCodec->ix== NULL || + pCodec->ex== NULL) { + qra65_free(pCodec); + return -4; // out of memory + } + + // compute and store the AWGN/Rayleigh Es/No ratio for which we optimize + // the decoder metric + nm = _qra65_get_bits_per_symbol(pqracode); + R = _qra65_get_code_rate(pqracode); + pCodec->decoderEsNoMetric = 1.0f*nm*R*EbNoMetric; + + return 1; +} + +void qra65_free(qra65_codec_ds *pCodec) +{ + if (!pCodec) + return; + + // free internal buffers + if (pCodec->x!=NULL) + free(pCodec->x); + + if (pCodec->y!=NULL) + free(pCodec->y); + + if (pCodec->qra_v2cmsg!=NULL) + free(pCodec->qra_v2cmsg); + + if (pCodec->qra_c2vmsg!=NULL) + free(pCodec->qra_c2vmsg); + + if (pCodec->ix!=NULL) + free(pCodec->ix); + + if (pCodec->ex!=NULL) + free(pCodec->ex); + + pCodec->pQraCode = NULL; + pCodec->x = NULL; + pCodec->y = NULL; + pCodec->qra_v2cmsg = NULL; + pCodec->qra_c2vmsg = NULL; + pCodec->qra_v2cmsg = NULL; + pCodec->ix = NULL; + pCodec->ex = NULL; + + return; +} + +int qra65_encode(const qra65_codec_ds *pCodec, int *pOutputCodeword, const int *pInputMsg) +{ + const qracode *pQraCode; + int *px; + int *py; + int nK; + int nN; + + if (!pCodec) + return -1; // which codec? + + pQraCode = pCodec->pQraCode; + px = pCodec->x; + py = pCodec->y; + nK = _qra65_get_message_length(pQraCode); + nN = _qra65_get_codeword_length(pQraCode); + + // copy the information symbols into the internal buffer + memcpy(px,pInputMsg,nK*sizeof(int)); + + // compute and append the appropriate CRC if required + switch (pQraCode->type) { + case QRATYPE_NORMAL: + break; + case QRATYPE_CRC: + case QRATYPE_CRCPUNCTURED: + px[nK] = _qra65_crc6(px,nK); + break; + case QRATYPE_CRCPUNCTURED2: + _qra65_crc12(px+nK,px,nK); + break; + default: + return -2; // code type not supported + } + + // encode with the given qra code + qra_encode(pQraCode,py,px); + + // puncture the CRC symbols as required + // and copy the result to the destination buffer + switch (pQraCode->type) { + case QRATYPE_NORMAL: + case QRATYPE_CRC: + // no puncturing + memcpy(pOutputCodeword,py,nN*sizeof(int)); + break; + case QRATYPE_CRCPUNCTURED: + // strip the single CRC symbol from the encoded codeword + memcpy(pOutputCodeword,py,nK*sizeof(int)); // copy the systematic symbols + memcpy(pOutputCodeword+nK,py+nK+1,(nN-nK)*sizeof(int)); // copy the check symbols skipping the CRC symbol + break; + case QRATYPE_CRCPUNCTURED2: + // strip the 2 CRC symbols from the encoded codeword + memcpy(pOutputCodeword,py,nK*sizeof(int)); // copy the systematic symbols + memcpy(pOutputCodeword+nK,py+nK+2,(nN-nK)*sizeof(int)); // copy the check symbols skipping the two CRC symbols + break; + default: + return -2; // code type unsupported + } + + return 1; // ok +} + +int qra65_intrinsics(qra65_codec_ds *pCodec, float *pIntrinsics, const float *pInputEnergies) +{ + // compute observations intrinsics probabilities + // for the AWGN/Rayleigh channels + + // NOTE: + // A true Rayleigh channel metric would require that the channel gains were known + // for each symbol in the codeword. Such gains cannot be estimated reliably when + // the Es/No ratio is small. Therefore we compute intrinsic probabilities assuming + // that, on average, these channel gains are unitary. + // In general it is even difficult to estimate the Es/No ratio for the AWGN channel + // Therefore we always compute the intrinsic probabilities assuming that the Es/No + // ratio is known and equal to the constant decoderEsNoMetric. This assumption will + // generate the true intrinsic probabilities only when the actual Eb/No ratio is + // equal to this constant. As in all the other cases the probabilities are evaluated + // with a wrong scaling constant we can expect that the decoder performance at different + // Es/No will be worse. Anyway, since the EsNoMetric constant has been chosen so that the + // decoder error rate is about 50%, we obtain almost optimal error rates down to + // any useful Es/No ratio. + + const qracode *pQraCode; + int nN, nBits; + float EsNoMetric; + + if (pCodec==NULL) + return -1; // which codec? + + pQraCode = pCodec->pQraCode; + nN = _qra65_get_codeword_length(pQraCode); + nBits = pQraCode->m; + + EsNoMetric = pCodec->decoderEsNoMetric; + qra_mfskbesselmetric(pIntrinsics,pInputEnergies,nBits,nN,EsNoMetric); + + return 1; // success +} + +int qra65_esnodb(const qra65_codec_ds *pCodec, float *pEsNodB, const int *ydec, const float *pInputEnergies) +{ + // compute average Es/No for the AWGN/Rayleigh channel cases + + int k,j; + float sigplusnoise=0; + float noise=0; + int nN, nM; + const float *pIn = pInputEnergies; + const int *py = ydec; + float EsNodB; + + nN = qra65_get_codeword_length(pCodec); + nM = qra65_get_alphabet_size(pCodec); + + for (k=0;k4) + return QRA65_DECODE_INVPARAMS; // invalid submode + + // As the symbol duration in QRA65 is longer than in QRA64 the fading tables continue + // to be valid if the B90 parameter is scaled by the actual symbol rate + // Compute index to most appropriate weighting function coefficients + hidx = (int)(logf(B90*TS_QRA65/TS_QRA64)/logf(1.09f) - 0.499f); + +// if (hidx<0 || hidx > 64) +// // index of weighting function out of range +// // B90 out of range +// return QRA65_DECODE_INVPARAMS; + + // Unlike in QRA64 we accept any B90, anyway limiting it to + // the extreme cases (0.9 to 210 Hz approx.) + if (hidx<0) + hidx = 0; + else + if (hidx > 64) + hidx=64; + + // select the appropriate weighting fading coefficients array + if (fadingModel==0) { // gaussian fading model + // point to gaussian energy weighting taps + hlen = glen_tab_gauss[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = gptr_tab_gauss[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else if (fadingModel==1) { + // point to lorentzian energy weighting taps + hlen = glen_tab_lorentz[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) + hptr = gptr_tab_lorentz[hidx]; // pointer to the first (L+1)/2 coefficients of w fun + } + else + return QRA65_DECODE_INVPARAMS; // invalid fading model + + // compute (euristically) the optimal decoder metric accordingly the given spread amount + // We assume that the decoder 50% decoding threshold is: + // Es/No(dB) = Es/No(AWGN)(dB) + 8*log(B90)/log(240)(dB) + // that's to say, at the maximum Doppler spread bandwidth (240 Hz for QRA64) + // there's a ~8 dB Es/No degradation over the AWGN case + fTemp = 8.0f*logf(B90)/logf(240.0f); // assumed Es/No degradation for the given fading bandwidth + EsNoMetric = pCodec->decoderEsNoMetric*powf(10.0f,fTemp/10.0f); + + nM = qra65_get_alphabet_size(pCodec); + nN = qra65_get_codeword_length(pCodec); + nBinsPerTone = 1<ffNoiseVar = fNoiseVar; + pCodec->ffEsNoMetric = EsNoMetric; + pCodec->nBinsPerTone = nBinsPerTone; + pCodec->nBinsPerSymbol = nBinsPerSymbol; + pCodec->nWeights = hlen; + weight = pCodec->ffWeight; + + // compute the fast fading weights accordingly to the Es/No ratio + // for which we compute the exact intrinsics probabilities + for (k=0;kmaxlogp) // keep track of the max + maxlogp = fTemp; + pCurIx[k]=fTemp; + + pCurBin += nBinsPerTone; // next tone + } + + // exponentiate and accumulate the normalization constant + sumix = 0.0f; + for (k=0;knBinsPerTone; + nBinsPerSymbol = pCodec->nBinsPerSymbol; + nWeights = pCodec->nWeights; + ffNoiseVar = pCodec->ffNoiseVar; + ffEsNoMetric = pCodec->ffEsNoMetric; + nTotWeights = 2*nWeights-1; + + // compute symbols energy (noise included) summing the + // energies pertaining to the decoded symbols in the codeword + + EsPlusWNo = 0.0f; + pCurSym = pInputEnergies + nM; // point to first central bin of first symbol tone + for (n=0;npQraCode; + ix = pCodec->ix; + ex = pCodec->ex; + + nK = _qra65_get_message_length(pQraCode); + nN = _qra65_get_codeword_length(pQraCode); + nM = pQraCode->M; + nBits = pQraCode->m; + + px = pCodec->x; + py = pCodec->y; + + // Depuncture intrinsics observations as required by the code type + switch (pQraCode->type) { + case QRATYPE_CRCPUNCTURED: + memcpy(ix,pIntrinsics,nK*nM*sizeof(float)); // information symbols + pd_init(PD_ROWADDR(ix,nM,nK),pd_uniform(nBits),nM); // crc + memcpy(ix+(nK+1)*nM,pIntrinsics+nK*nM,(nN-nK)*nM*sizeof(float)); // parity checks + break; + case QRATYPE_CRCPUNCTURED2: + memcpy(ix,pIntrinsics,nK*nM*sizeof(float)); // information symbols + pd_init(PD_ROWADDR(ix,nM,nK),pd_uniform(nBits),nM); // crc + pd_init(PD_ROWADDR(ix,nM,nK+1),pd_uniform(nBits),nM); // crc + memcpy(ix+(nK+2)*nM,pIntrinsics+nK*nM,(nN-nK)*nM*sizeof(float)); // parity checks + break; + case QRATYPE_NORMAL: + case QRATYPE_CRC: + default: + // no puncturing + memcpy(ix,pIntrinsics,nN*nM*sizeof(float)); // as they are + } + + // mask the intrinsics with the available a priori knowledge + if (pAPMask!=NULL) + _qra65_mask(pQraCode,ix,pAPMask,pAPSymbols); + + + // Compute the extrinsic symbols probabilities with the message-passing algorithm + // Stop if the extrinsics information does not converges to unity + // within the given number of iterations + rc = qra_extrinsic( pQraCode, + ex, + ix, + 100, + pCodec->qra_v2cmsg, + pCodec->qra_c2vmsg); + + if (rc<0) + // failed to converge to a solution + return QRA65_DECODE_FAILED; + + // decode the information symbols (punctured information symbols included) + qra_mapdecode(pQraCode,px,ex,ix); + + // verify CRC match + + switch (pQraCode->type) { + case QRATYPE_CRC: + case QRATYPE_CRCPUNCTURED: + crc6=_qra65_crc6(px,nK); // compute crc-6 + if (crc6!=px[nK]) + return QRA65_DECODE_CRCMISMATCH; // crc doesn't match + break; + case QRATYPE_CRCPUNCTURED2: + _qra65_crc12(crc12, px,nK); // compute crc-12 + if (crc12[0]!=px[nK] || + crc12[1]!=px[nK+1]) + return QRA65_DECODE_CRCMISMATCH; // crc doesn't match + break; + case QRATYPE_NORMAL: + default: + // nothing to check + break; + } + + // copy the decoded msg to the user buffer (excluding punctured symbols) + if (pDecodedMsg) + memcpy(pDecodedMsg,px,nK*sizeof(int)); + + if (pDecodedCodeword==NULL) // user is not interested in it + return rc; // return the number of iterations required to decode + + // crc matches therefore we can reconstruct the transmitted codeword + // reencoding the information available in px... + + qra_encode(pQraCode, py, px); + + // ...and strip the punctured symbols from the codeword + switch (pQraCode->type) { + case QRATYPE_CRCPUNCTURED: + memcpy(pDecodedCodeword,py,nK*sizeof(int)); + memcpy(pDecodedCodeword+nK,py+nK+1,(nN-nK)*sizeof(int)); // puncture crc-6 symbol + break; + case QRATYPE_CRCPUNCTURED2: + memcpy(pDecodedCodeword,py,nK*sizeof(int)); + memcpy(pDecodedCodeword+nK,py+nK+2,(nN-nK)*sizeof(int)); // puncture crc-12 symbols + break; + case QRATYPE_CRC: + case QRATYPE_NORMAL: + default: + memcpy(pDecodedCodeword,py,nN*sizeof(int)); // no puncturing + } + + return rc; // return the number of iterations required to decode + +} + + + + +// helper functions ------------------------------------------------------------- + +int _qra65_get_message_length(const qracode *pCode) +{ + // return the actual information message length (in symbols) + // excluding any punctured symbol + + int nMsgLength; + + switch (pCode->type) { + case QRATYPE_NORMAL: + nMsgLength = pCode->K; + break; + case QRATYPE_CRC: + case QRATYPE_CRCPUNCTURED: + // one information symbol of the underlying qra code is reserved for CRC + nMsgLength = pCode->K-1; + break; + case QRATYPE_CRCPUNCTURED2: + // two code information symbols are reserved for CRC + nMsgLength = pCode->K-2; + break; + default: + nMsgLength = -1; + } + + return nMsgLength; +} + +int _qra65_get_codeword_length(const qracode *pCode) +{ + // return the actual codeword length (in symbols) + // excluding any punctured symbol + + int nCwLength; + + switch (pCode->type) { + case QRATYPE_NORMAL: + case QRATYPE_CRC: + // no puncturing + nCwLength = pCode->N; + break; + case QRATYPE_CRCPUNCTURED: + // the CRC symbol is punctured + nCwLength = pCode->N-1; + break; + case QRATYPE_CRCPUNCTURED2: + // the two CRC symbols are punctured + nCwLength = pCode->N-2; + break; + default: + nCwLength = -1; + } + + return nCwLength; +} + +float _qra65_get_code_rate(const qracode *pCode) +{ + return 1.0f*_qra65_get_message_length(pCode)/_qra65_get_codeword_length(pCode); +} + +int _qra65_get_alphabet_size(const qracode *pCode) +{ + return pCode->M; +} +int _qra65_get_bits_per_symbol(const qracode *pCode) +{ + return pCode->m; +} +static void _qra65_mask(const qracode *pcode, float *ix, const int *mask, const int *x) +{ + // mask intrinsic information ix with available a priori knowledge + + int k,kk, smask; + const int nM=pcode->M; + const int nm=pcode->m; + int nK; + + // Exclude from masking the symbols which have been punctured. + // nK is the length of the mask and x arrays, which do + // not include any punctured symbol + nK = _qra65_get_message_length(pcode); + + // for each symbol set to zero the probability + // of the values which are not allowed by + // the a priori information + + for (k=0;k>1) ^ CRC6_GEN_POL; + else + sr = (sr>>1); + t>>=1; + } + } + + return sr; +} + +static void _qra65_crc12(int *y, int *x, int sz) +{ + int k,j,t,sr = 0; + for (k=0;k>1) ^ CRC12_GEN_POL; + else + sr = (sr>>1); + t>>=1; + } + } + + y[0] = sr&0x3F; + y[1] = (sr>>6); +} + + diff --git a/lib/qra/q65/qra65.h b/lib/qra/q65/qra65.h new file mode 100644 index 000000000..ffa383279 --- /dev/null +++ b/lib/qra/q65/qra65.h @@ -0,0 +1,101 @@ +// qra65.h +// QRA65 modes encoding/decoding functions +// +// (c) 2020 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#ifndef _qra65_h +#define _qra65_h + +#include "qracodes.h" + +// Error codes returned by qra65_decode(...) +#define QRA65_DECODE_INVPARAMS -1 +#define QRA65_DECODE_FAILED -2 +#define QRA65_DECODE_CRCMISMATCH -3 + +// maximum number of weights for the fast-fading metric evaluation +#define QRA65_FASTFADING_MAXWEIGTHS 65 + +typedef struct { + const qracode *pQraCode; // qra code to be used by the codec + float decoderEsNoMetric; // value for which we optimize the decoder metric + int *x; // codec input + int *y; // codec output + float *qra_v2cmsg; // decoder v->c messages + float *qra_c2vmsg; // decoder c->v messages + float *ix; // decoder intrinsic information + float *ex; // decoder extrinsic information + // variables used to compute the intrinsics in the fast-fading case + int nBinsPerTone; + int nBinsPerSymbol; + float ffNoiseVar; + float ffEsNoMetric; + int nWeights; + float ffWeight[QRA65_FASTFADING_MAXWEIGTHS]; +} qra65_codec_ds; + +int qra65_init(qra65_codec_ds *pCodec, const qracode *pQraCode); +void qra65_free(qra65_codec_ds *pCodec); + +int qra65_encode(const qra65_codec_ds *pCodec, int *pOutputCodeword, const int *pInputMsg); + +int qra65_intrinsics(qra65_codec_ds *pCodec, float *pIntrinsics, const float *pInputEnergies); + +int qra65_intrinsics_fastfading(qra65_codec_ds *pCodec, + float *pIntrinsics, // intrinsic symbol probabilities output + const float *pInputEnergies, // received energies input + const int submode, // submode idx (0=A ... 4=E) + const float B90, // spread bandwidth (90% fractional energy) + const int fadingModel); // 0=Gaussian 1=Lorentzian fade model + + +int qra65_decode(qra65_codec_ds *pCodec, + int* pDecodedCodeword, + int *pDecodedMsg, + const float *pIntrinsics, + const int *pAPMask, + const int *pAPSymbols); + +int qra65_esnodb(const qra65_codec_ds *pCodec, + float *pEsNodB, + const int *ydec, + const float *pInputEnergies); + +int qra65_esnodb_fastfading( + const qra65_codec_ds *pCodec, + float *pEsNodB, + const int *ydec, + const float *pInputEnergies); + + +#define qra65_get_message_length(pCodec) _qra65_get_message_length((pCodec)->pQraCode) +#define qra65_get_codeword_length(pCodec) _qra65_get_codeword_length((pCodec)->pQraCode) +#define qra65_get_code_rate(pCodec) _qra65_get_code_rate((pCodec)->pQraCode) +#define qra65_get_alphabet_size(pCodec) _qra65_get_alphabet_size((pCodec)->pQraCode) +#define qra65_get_bits_per_symbol(pCodec) _qra65_get_bits_per_symbol((pCodec)->pQraCode) + +// internally used but made publicly available for the defines above +int _qra65_get_message_length(const qracode *pCode); +int _qra65_get_codeword_length(const qracode *pCode); +float _qra65_get_code_rate(const qracode *pCode); +void _qra65_mask(const qracode *pcode, float *ix, const int *mask, const int *x); +int _qra65_get_alphabet_size(const qracode *pCode); +int _qra65_get_bits_per_symbol(const qracode *pCode); + +#endif // _qra65_h \ No newline at end of file diff --git a/lib/qra/q65/qracodes.c b/lib/qra/q65/qracodes.c new file mode 100644 index 000000000..748a9c9cd --- /dev/null +++ b/lib/qra/q65/qracodes.c @@ -0,0 +1,474 @@ +// qracodes.c +// Q-ary RA codes encoding/decoding functions +// +// (c) 2016 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy +// ------------------------------------------------------------------------------ +// This file is part of the qracodes project, a Forward Error Control +// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. +// +// qracodes is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// qracodes is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with qracodes source distribution. +// If not, see . + +#include +#include + +#include "npfwht.h" +#include "pdmath.h" + +#include "qracodes.h" + +int qra_encode(const qracode *pcode, int *y, const int *x) +{ + int k,j,kk,jj; + int t, chk = 0; + + const int K = pcode->K; + const int M = pcode->M; + const int NC= pcode->NC; + const int a = pcode->a; + const int *acc_input_idx = pcode->acc_input_idx; + const int *acc_input_wlog = pcode->acc_input_wlog; + const int *gflog = pcode->gflog; + const int *gfexp = pcode->gfexp; + + // copy the systematic symbols to destination + memcpy(y,x,K*sizeof(int)); + + y = y+K; // point to check symbols + + // compute the code check symbols as a weighted accumulation of a permutated + // sequence of the (repeated) systematic input symbols: + // chk(k+1) = x(idx(k))*alfa^(logw(k)) + chk(k) + // (all operations performed over GF(M)) + + if (a==1) { // grouping factor = 1 + for (k=0;k 1 + for (k=0;k80.f) // avoid floating point exp() overflows + v=80.f; + + src[nitems] = (float)exp(v); + } +} + + +float qra_mfskbesselmetric(float *pix, const float *rsq, const int m, const int N, float EsNoMetric) +{ + // Computes the codeword symbols intrinsic probabilities + // given the square of the received input amplitudes. + + // The input vector rqs must be a linear array of size M*N, where M=2^m, + // containing the squared amplitudes (rp*rp+rq*rq) of the input samples + + // First symbol amplitudes should be stored in the first M positions, + // second symbol amplitudes stored at positions [M ... 2*M-1], and so on. + + // Output vector is the intrinsic symbol metric (the probability distribution) + // assuming that symbols are transmitted using a M-FSK modulation + // and incoherent demodulation. + + // As the input Es/No is generally unknown (as it cannot be exstimated accurately + // when the codeword length is few tens symbols) but an exact metric requires it + // we simply fix it to a predefined EsNoMetric value so that the metric is what + // expected at that specific value. + // The metric computed in this way is optimal only at this predefined Es/No value, + // nevertheless it is usually better than a generic parameter-free metric which + // makes no assumptions on the input Es/No. + + // returns the estimated noise standard deviation + + int k; + float rsum = 0.f; + float sigmaest, cmetric; + + const int M = 1<M; + const int qra_m = pcode->m; + const int qra_V = pcode->V; + const int qra_MAXVDEG = pcode->MAXVDEG; + const int *qra_vdeg = pcode->vdeg; + const int qra_C = pcode->C; + const int qra_MAXCDEG = pcode->MAXCDEG; + const int *qra_cdeg = pcode->cdeg; + const int *qra_v2cmidx = pcode->v2cmidx; + const int *qra_c2vmidx = pcode->c2vmidx; + const int *qra_pmat = pcode->gfpmat; + const int *qra_msgw = pcode->msgw; + +// float msgout[qra_M]; // buffer to store temporary results + float msgout[QRACODE_MAX_M]; // we use a fixed size in order to avoid mallocs + + float totex; // total extrinsic information + int nit; // current iteration + int nv; // current variable + int nc; // current check + int k,kk; // loop indexes + + int ndeg; // current node degree + int msgbase; // current offset in the table of msg indexes + int imsg; // current message index + int wmsg; // current message weight + + int rc = -1; // rc>=0 extrinsic converged to 1 at iteration rc (rc=0..maxiter-1) + // rc=-1 no convergence in the given number of iterations + // rc=-2 error in the code tables (code checks degrees must be >1) + // rc=-3 M is larger than QRACODE_MAX_M + + + + if (qra_M>QRACODE_MAX_M) + return -3; + + // message initialization ------------------------------------------------------- + + // init c->v variable intrinsic msgs + pd_init(C2VMSG(0),pix,qra_M*qra_V); + + // init the v->c messages directed to code factors (k=1..ndeg) with the intrinsic info + for (nv=0;nvc + for (k=1;kv step ----------------------------------------------------- + // Computes messages from code checks to code variables. + // As the first qra_V checks are associated with intrinsic information + // (the code tables have been constructed in this way) + // we need to do this step only for code checks in the range [qra_V..qra_C) + + // The convolutions of probability distributions over the alphabet of a finite field GF(qra_M) + // are performed with a fast convolution algorithm over the given field. + // + // I.e. given the code check x1+x2+x3 = 0 (with x1,x2,x3 in GF(2^m)) + // and given Prob(x2) and Prob(x3), we have that: + // Prob(x1=X1) = Prob((x2+x3)=X1) = sum((Prob(x2=X2)*Prob(x3=(X1+X2))) for all the X2s in the field + // This translates to Prob(x1) = IWHT(WHT(Prob(x2))*WHT(Prob(x3))) + // where WHT and IWHT are the direct and inverse Walsh-Hadamard transforms of the argument. + // Note that the WHT and the IWHF differs only by a multiplicative coefficent and since in this step + // we don't need that the output distribution is normalized we use the relationship + // Prob(x1) =(proportional to) WH(WH(Prob(x2))*WH(Prob(x3))) + + // In general given the check code x1+x2+x3+..+xm = 0 + // the output distribution of a variable given the distributions of the other m-1 variables + // is the inverse WHT of the product of the WHTs of the distribution of the other m-1 variables + // The complexity of this algorithm scales with M*log2(M) instead of the M^2 complexity of + // the brute force approach (M=size of the alphabet) + + for (nc=qra_V;nc1) + return -2; // bad code tables + + msgbase = nc*qra_MAXCDEG; // base to msg index row for the current node + + // transforms inputs in the Walsh-Hadamard "frequency" domain + // v->c -> fwht(v->c) + for (k=0;kv = prod(fwht(v->c)) + // TODO: we assume that checks degrees are not larger than three but + // if they are larger the products can be computed more efficiently + for (kk=0;kkc steps when multipling + // small fp numbers + msgout[0]+=1E-7f; // TODO: define the bias accordingly to the field size + + np_fwht(qra_m,msgout,msgout); + + // inverse weight and output + imsg = qra_c2vmidx[msgbase+k]; // current output msg index + wmsg = qra_msgw[imsg]; // current msg weight + + if (wmsg==0) + pd_init(C2VMSG(imsg),msgout,qra_M); + else + // output p(alfa^(-w)*x) + pd_bwdperm(C2VMSG(imsg),msgout, MSGPERM(wmsg), qra_M); + + } // for (k=0;kc step ----------------------------------------------------- + for (nv=0;nvc msg = prod(c->v) + // TODO: factor factors to reduce the number of computations for high degree nodes + for (kk=0;kkc are null + // normalize output to a probability distribution + if (pd_norm(msgout,qra_m)<=0) { + // dump msgin; + printf("warning: v->c pd with invalid norm. nit=%d nv=%d k=%d\n",nit,nv,k); + for (kk=0;kk(1.*(qra_V)-0.01)) { + // the total maximum extrinsic information of each symbol in the codeword + // is very close to one. This means that we have reached the (1,1) point in the + // code EXIT chart(s) and we have successfully decoded the input. + rc = nit; + break; // remove the break to evaluate the decoder speed performance as a function of the max iterations number) + } + + } // for (nit=0;nitM; + const int qra_m = pcode->m; + const int qra_K = pcode->K; + + int k; + + for (k=0;k. + +#ifndef _qracodes_h_ +#define _qracodes_h_ + +// type of codes +#define QRATYPE_NORMAL 0x00 // normal code +#define QRATYPE_CRC 0x01 // code with crc - last information symbol is a CRC-6 +#define QRATYPE_CRCPUNCTURED 0x02 // the CRC-6 symbol is punctured (not sent along the channel) +#define QRATYPE_CRCPUNCTURED2 0x03 // code with CRC-12. The two crc symbols are punctured + + +typedef struct { + // code parameters + const int K; // number of information symbols + const int N; // codeword length in symbols + const int m; // bits/symbol + const int M; // Symbol alphabet cardinality (2^m) + const int a; // code grouping factor + const int NC; // number of check symbols (N-K) + const int V; // number of variables in the code graph (N) + const int C; // number of factors in the code graph (N +(N-K)+1) + const int NMSG; // number of msgs in the code graph + const int MAXVDEG; // maximum variable degree + const int MAXCDEG; // maximum factor degree + const int type; // see QRATYPE_xx defines + const float R; // code rate (K/N) + const char name[64]; // code name + // tables used by the encoder + const int *acc_input_idx; + const int *acc_input_wlog; + const int *gflog; + const int *gfexp; + // tables used by the decoder ------------------------- + const int *msgw; + const int *vdeg; + const int *cdeg; + const int *v2cmidx; + const int *c2vmidx; + const int *gfpmat; +} qracode; +// Uncomment the header file of the code which needs to be tested + +//#include "qra12_63_64_irr_b.h" // irregular code (12,63) over GF(64) +//#include "qra13_64_64_irr_e.h" // irregular code with good performance and best UER protection at AP56 +//#include "qra13_64_64_reg_a.h" // regular code with good UER but perf. inferior to that of code qra12_63_64_irr_b + +#ifdef __cplusplus +extern "C" { +#endif + +int qra_encode(const qracode *pcode, int *y, const int *x); +float qra_mfskbesselmetric(float *pix, const float *rsq, const int m, const int N, float EsNoMetric); +int qra_extrinsic(const qracode *pcode, float *pex, const float *pix, int maxiter,float *qra_v2cmsg,float *qra_c2vmsg); +void qra_mapdecode(const qracode *pcode, int *xdec, float *pex, const float *pix); + +#ifdef __cplusplus +} +#endif + +#endif // _qracodes_h_ diff --git a/lib/qra/q65/wer-ff-qra15_65_64_irr_e23-ap00.txt b/lib/qra/q65/wer-ff-qra15_65_64_irr_e23-ap00.txt new file mode 100644 index 000000000..b087ad9fb --- /dev/null +++ b/lib/qra/q65/wer-ff-qra15_65_64_irr_e23-ap00.txt @@ -0,0 +1,19 @@ +#Code Name: qra15_65_64_irr_e23 +#ChannelType (0=AWGN,1=Rayleigh,2=Fast-Fading) +#Eb/No (dB) +#Transmitted Codewords +#Errors +#CRC Errors +#Undetected +#Avg dec. time (ms) +#WER +#UER +2 -30.00 106 106 0 0 4.87 1.00e+000 0.00e+000 +2 0.50 1006 1006 0 0 4.91 1.00e+000 0.00e+000 +2 1.00 1007 1006 0 0 4.98 9.99e-001 0.00e+000 +2 1.50 1009 1007 0 0 4.97 9.98e-001 0.00e+000 +2 2.00 1017 1007 1 0 4.84 9.90e-001 2.40e-007 +2 2.50 1047 1006 1 0 4.79 9.61e-001 2.33e-007 +2 3.00 1148 1006 3 0 4.61 8.76e-001 6.38e-007 +2 3.50 1338 1006 6 0 4.43 7.52e-001 1.10e-006 +2 4.00 1902 1006 7 0 3.94 5.29e-001 8.99e-007 From 676d3578f167601d0e21ca3927eedb31880e36a4 Mon Sep 17 00:00:00 2001 From: Nico Palermo/IV3NWV Date: Mon, 26 Oct 2020 02:20:44 +0100 Subject: [PATCH 102/206] removed unused qra65 files --- lib/qra/q65/qra65.c | 795 -------------------------------------------- lib/qra/q65/qra65.h | 101 ------ 2 files changed, 896 deletions(-) delete mode 100644 lib/qra/q65/qra65.c delete mode 100644 lib/qra/q65/qra65.h diff --git a/lib/qra/q65/qra65.c b/lib/qra/q65/qra65.c deleted file mode 100644 index efb3e94a0..000000000 --- a/lib/qra/q65/qra65.c +++ /dev/null @@ -1,795 +0,0 @@ -// qra65.c -// QRA65 modes encoding/decoding functions -// -// (c) 2020 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy -// ------------------------------------------------------------------------------ -// This file is part of the qracodes project, a Forward Error Control -// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. -// -// qracodes is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// qracodes is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with qracodes source distribution. -// If not, see . - -#include -#include -#include - -#include "qra65.h" -#include "pdmath.h" - - -static int _qra65_crc6(int *x, int sz); -static void _qra65_crc12(int *y, int *x, int sz); - - -int qra65_init(qra65_codec_ds *pCodec, const qracode *pqracode) -{ - // Eb/No value for which we optimize the decoder metric (AWGN/Rayleigh cases) - const float EbNodBMetric = 2.8f; - const float EbNoMetric = (float)pow(10,EbNodBMetric/10); - - float R; // code effective rate (after puncturing) - int nm; // bits per symbol - - if (!pCodec) - return -1; // why do you called me? - - if (!pqracode) - return -2; // invalid qra code - - if (pqracode->M!=64) - return -3; // QRA65 supports only codes over GF(64) - - pCodec->pQraCode = pqracode; - - // allocate buffers used by encoding/decoding functions - pCodec->x = (int*)malloc(pqracode->K*sizeof(int)); - pCodec->y = (int*)malloc(pqracode->N*sizeof(int)); - pCodec->qra_v2cmsg = (float*)malloc(pqracode->NMSG*pqracode->M*sizeof(float)); - pCodec->qra_c2vmsg = (float*)malloc(pqracode->NMSG*pqracode->M*sizeof(float)); - pCodec->ix = (float*)malloc(pqracode->N*pqracode->M*sizeof(float)); - pCodec->ex = (float*)malloc(pqracode->N*pqracode->M*sizeof(float)); - - if (pCodec->x== NULL || - pCodec->y== NULL || - pCodec->qra_v2cmsg== NULL || - pCodec->qra_c2vmsg== NULL || - pCodec->ix== NULL || - pCodec->ex== NULL) { - qra65_free(pCodec); - return -4; // out of memory - } - - // compute and store the AWGN/Rayleigh Es/No ratio for which we optimize - // the decoder metric - nm = _qra65_get_bits_per_symbol(pqracode); - R = _qra65_get_code_rate(pqracode); - pCodec->decoderEsNoMetric = 1.0f*nm*R*EbNoMetric; - - return 1; -} - -void qra65_free(qra65_codec_ds *pCodec) -{ - if (!pCodec) - return; - - // free internal buffers - if (pCodec->x!=NULL) - free(pCodec->x); - - if (pCodec->y!=NULL) - free(pCodec->y); - - if (pCodec->qra_v2cmsg!=NULL) - free(pCodec->qra_v2cmsg); - - if (pCodec->qra_c2vmsg!=NULL) - free(pCodec->qra_c2vmsg); - - if (pCodec->ix!=NULL) - free(pCodec->ix); - - if (pCodec->ex!=NULL) - free(pCodec->ex); - - pCodec->pQraCode = NULL; - pCodec->x = NULL; - pCodec->y = NULL; - pCodec->qra_v2cmsg = NULL; - pCodec->qra_c2vmsg = NULL; - pCodec->qra_v2cmsg = NULL; - pCodec->ix = NULL; - pCodec->ex = NULL; - - return; -} - -int qra65_encode(const qra65_codec_ds *pCodec, int *pOutputCodeword, const int *pInputMsg) -{ - const qracode *pQraCode; - int *px; - int *py; - int nK; - int nN; - - if (!pCodec) - return -1; // which codec? - - pQraCode = pCodec->pQraCode; - px = pCodec->x; - py = pCodec->y; - nK = _qra65_get_message_length(pQraCode); - nN = _qra65_get_codeword_length(pQraCode); - - // copy the information symbols into the internal buffer - memcpy(px,pInputMsg,nK*sizeof(int)); - - // compute and append the appropriate CRC if required - switch (pQraCode->type) { - case QRATYPE_NORMAL: - break; - case QRATYPE_CRC: - case QRATYPE_CRCPUNCTURED: - px[nK] = _qra65_crc6(px,nK); - break; - case QRATYPE_CRCPUNCTURED2: - _qra65_crc12(px+nK,px,nK); - break; - default: - return -2; // code type not supported - } - - // encode with the given qra code - qra_encode(pQraCode,py,px); - - // puncture the CRC symbols as required - // and copy the result to the destination buffer - switch (pQraCode->type) { - case QRATYPE_NORMAL: - case QRATYPE_CRC: - // no puncturing - memcpy(pOutputCodeword,py,nN*sizeof(int)); - break; - case QRATYPE_CRCPUNCTURED: - // strip the single CRC symbol from the encoded codeword - memcpy(pOutputCodeword,py,nK*sizeof(int)); // copy the systematic symbols - memcpy(pOutputCodeword+nK,py+nK+1,(nN-nK)*sizeof(int)); // copy the check symbols skipping the CRC symbol - break; - case QRATYPE_CRCPUNCTURED2: - // strip the 2 CRC symbols from the encoded codeword - memcpy(pOutputCodeword,py,nK*sizeof(int)); // copy the systematic symbols - memcpy(pOutputCodeword+nK,py+nK+2,(nN-nK)*sizeof(int)); // copy the check symbols skipping the two CRC symbols - break; - default: - return -2; // code type unsupported - } - - return 1; // ok -} - -int qra65_intrinsics(qra65_codec_ds *pCodec, float *pIntrinsics, const float *pInputEnergies) -{ - // compute observations intrinsics probabilities - // for the AWGN/Rayleigh channels - - // NOTE: - // A true Rayleigh channel metric would require that the channel gains were known - // for each symbol in the codeword. Such gains cannot be estimated reliably when - // the Es/No ratio is small. Therefore we compute intrinsic probabilities assuming - // that, on average, these channel gains are unitary. - // In general it is even difficult to estimate the Es/No ratio for the AWGN channel - // Therefore we always compute the intrinsic probabilities assuming that the Es/No - // ratio is known and equal to the constant decoderEsNoMetric. This assumption will - // generate the true intrinsic probabilities only when the actual Eb/No ratio is - // equal to this constant. As in all the other cases the probabilities are evaluated - // with a wrong scaling constant we can expect that the decoder performance at different - // Es/No will be worse. Anyway, since the EsNoMetric constant has been chosen so that the - // decoder error rate is about 50%, we obtain almost optimal error rates down to - // any useful Es/No ratio. - - const qracode *pQraCode; - int nN, nBits; - float EsNoMetric; - - if (pCodec==NULL) - return -1; // which codec? - - pQraCode = pCodec->pQraCode; - nN = _qra65_get_codeword_length(pQraCode); - nBits = pQraCode->m; - - EsNoMetric = pCodec->decoderEsNoMetric; - qra_mfskbesselmetric(pIntrinsics,pInputEnergies,nBits,nN,EsNoMetric); - - return 1; // success -} - -int qra65_esnodb(const qra65_codec_ds *pCodec, float *pEsNodB, const int *ydec, const float *pInputEnergies) -{ - // compute average Es/No for the AWGN/Rayleigh channel cases - - int k,j; - float sigplusnoise=0; - float noise=0; - int nN, nM; - const float *pIn = pInputEnergies; - const int *py = ydec; - float EsNodB; - - nN = qra65_get_codeword_length(pCodec); - nM = qra65_get_alphabet_size(pCodec); - - for (k=0;k4) - return QRA65_DECODE_INVPARAMS; // invalid submode - - // As the symbol duration in QRA65 is longer than in QRA64 the fading tables continue - // to be valid if the B90 parameter is scaled by the actual symbol rate - // Compute index to most appropriate weighting function coefficients - hidx = (int)(logf(B90*TS_QRA65/TS_QRA64)/logf(1.09f) - 0.499f); - -// if (hidx<0 || hidx > 64) -// // index of weighting function out of range -// // B90 out of range -// return QRA65_DECODE_INVPARAMS; - - // Unlike in QRA64 we accept any B90, anyway limiting it to - // the extreme cases (0.9 to 210 Hz approx.) - if (hidx<0) - hidx = 0; - else - if (hidx > 64) - hidx=64; - - // select the appropriate weighting fading coefficients array - if (fadingModel==0) { // gaussian fading model - // point to gaussian energy weighting taps - hlen = glen_tab_gauss[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) - hptr = gptr_tab_gauss[hidx]; // pointer to the first (L+1)/2 coefficients of w fun - } - else if (fadingModel==1) { - // point to lorentzian energy weighting taps - hlen = glen_tab_lorentz[hidx]; // hlen = (L+1)/2 (where L=(odd) number of taps of w fun) - hptr = gptr_tab_lorentz[hidx]; // pointer to the first (L+1)/2 coefficients of w fun - } - else - return QRA65_DECODE_INVPARAMS; // invalid fading model - - // compute (euristically) the optimal decoder metric accordingly the given spread amount - // We assume that the decoder 50% decoding threshold is: - // Es/No(dB) = Es/No(AWGN)(dB) + 8*log(B90)/log(240)(dB) - // that's to say, at the maximum Doppler spread bandwidth (240 Hz for QRA64) - // there's a ~8 dB Es/No degradation over the AWGN case - fTemp = 8.0f*logf(B90)/logf(240.0f); // assumed Es/No degradation for the given fading bandwidth - EsNoMetric = pCodec->decoderEsNoMetric*powf(10.0f,fTemp/10.0f); - - nM = qra65_get_alphabet_size(pCodec); - nN = qra65_get_codeword_length(pCodec); - nBinsPerTone = 1<ffNoiseVar = fNoiseVar; - pCodec->ffEsNoMetric = EsNoMetric; - pCodec->nBinsPerTone = nBinsPerTone; - pCodec->nBinsPerSymbol = nBinsPerSymbol; - pCodec->nWeights = hlen; - weight = pCodec->ffWeight; - - // compute the fast fading weights accordingly to the Es/No ratio - // for which we compute the exact intrinsics probabilities - for (k=0;kmaxlogp) // keep track of the max - maxlogp = fTemp; - pCurIx[k]=fTemp; - - pCurBin += nBinsPerTone; // next tone - } - - // exponentiate and accumulate the normalization constant - sumix = 0.0f; - for (k=0;knBinsPerTone; - nBinsPerSymbol = pCodec->nBinsPerSymbol; - nWeights = pCodec->nWeights; - ffNoiseVar = pCodec->ffNoiseVar; - ffEsNoMetric = pCodec->ffEsNoMetric; - nTotWeights = 2*nWeights-1; - - // compute symbols energy (noise included) summing the - // energies pertaining to the decoded symbols in the codeword - - EsPlusWNo = 0.0f; - pCurSym = pInputEnergies + nM; // point to first central bin of first symbol tone - for (n=0;npQraCode; - ix = pCodec->ix; - ex = pCodec->ex; - - nK = _qra65_get_message_length(pQraCode); - nN = _qra65_get_codeword_length(pQraCode); - nM = pQraCode->M; - nBits = pQraCode->m; - - px = pCodec->x; - py = pCodec->y; - - // Depuncture intrinsics observations as required by the code type - switch (pQraCode->type) { - case QRATYPE_CRCPUNCTURED: - memcpy(ix,pIntrinsics,nK*nM*sizeof(float)); // information symbols - pd_init(PD_ROWADDR(ix,nM,nK),pd_uniform(nBits),nM); // crc - memcpy(ix+(nK+1)*nM,pIntrinsics+nK*nM,(nN-nK)*nM*sizeof(float)); // parity checks - break; - case QRATYPE_CRCPUNCTURED2: - memcpy(ix,pIntrinsics,nK*nM*sizeof(float)); // information symbols - pd_init(PD_ROWADDR(ix,nM,nK),pd_uniform(nBits),nM); // crc - pd_init(PD_ROWADDR(ix,nM,nK+1),pd_uniform(nBits),nM); // crc - memcpy(ix+(nK+2)*nM,pIntrinsics+nK*nM,(nN-nK)*nM*sizeof(float)); // parity checks - break; - case QRATYPE_NORMAL: - case QRATYPE_CRC: - default: - // no puncturing - memcpy(ix,pIntrinsics,nN*nM*sizeof(float)); // as they are - } - - // mask the intrinsics with the available a priori knowledge - if (pAPMask!=NULL) - _qra65_mask(pQraCode,ix,pAPMask,pAPSymbols); - - - // Compute the extrinsic symbols probabilities with the message-passing algorithm - // Stop if the extrinsics information does not converges to unity - // within the given number of iterations - rc = qra_extrinsic( pQraCode, - ex, - ix, - 100, - pCodec->qra_v2cmsg, - pCodec->qra_c2vmsg); - - if (rc<0) - // failed to converge to a solution - return QRA65_DECODE_FAILED; - - // decode the information symbols (punctured information symbols included) - qra_mapdecode(pQraCode,px,ex,ix); - - // verify CRC match - - switch (pQraCode->type) { - case QRATYPE_CRC: - case QRATYPE_CRCPUNCTURED: - crc6=_qra65_crc6(px,nK); // compute crc-6 - if (crc6!=px[nK]) - return QRA65_DECODE_CRCMISMATCH; // crc doesn't match - break; - case QRATYPE_CRCPUNCTURED2: - _qra65_crc12(crc12, px,nK); // compute crc-12 - if (crc12[0]!=px[nK] || - crc12[1]!=px[nK+1]) - return QRA65_DECODE_CRCMISMATCH; // crc doesn't match - break; - case QRATYPE_NORMAL: - default: - // nothing to check - break; - } - - // copy the decoded msg to the user buffer (excluding punctured symbols) - if (pDecodedMsg) - memcpy(pDecodedMsg,px,nK*sizeof(int)); - - if (pDecodedCodeword==NULL) // user is not interested in it - return rc; // return the number of iterations required to decode - - // crc matches therefore we can reconstruct the transmitted codeword - // reencoding the information available in px... - - qra_encode(pQraCode, py, px); - - // ...and strip the punctured symbols from the codeword - switch (pQraCode->type) { - case QRATYPE_CRCPUNCTURED: - memcpy(pDecodedCodeword,py,nK*sizeof(int)); - memcpy(pDecodedCodeword+nK,py+nK+1,(nN-nK)*sizeof(int)); // puncture crc-6 symbol - break; - case QRATYPE_CRCPUNCTURED2: - memcpy(pDecodedCodeword,py,nK*sizeof(int)); - memcpy(pDecodedCodeword+nK,py+nK+2,(nN-nK)*sizeof(int)); // puncture crc-12 symbols - break; - case QRATYPE_CRC: - case QRATYPE_NORMAL: - default: - memcpy(pDecodedCodeword,py,nN*sizeof(int)); // no puncturing - } - - return rc; // return the number of iterations required to decode - -} - - - - -// helper functions ------------------------------------------------------------- - -int _qra65_get_message_length(const qracode *pCode) -{ - // return the actual information message length (in symbols) - // excluding any punctured symbol - - int nMsgLength; - - switch (pCode->type) { - case QRATYPE_NORMAL: - nMsgLength = pCode->K; - break; - case QRATYPE_CRC: - case QRATYPE_CRCPUNCTURED: - // one information symbol of the underlying qra code is reserved for CRC - nMsgLength = pCode->K-1; - break; - case QRATYPE_CRCPUNCTURED2: - // two code information symbols are reserved for CRC - nMsgLength = pCode->K-2; - break; - default: - nMsgLength = -1; - } - - return nMsgLength; -} - -int _qra65_get_codeword_length(const qracode *pCode) -{ - // return the actual codeword length (in symbols) - // excluding any punctured symbol - - int nCwLength; - - switch (pCode->type) { - case QRATYPE_NORMAL: - case QRATYPE_CRC: - // no puncturing - nCwLength = pCode->N; - break; - case QRATYPE_CRCPUNCTURED: - // the CRC symbol is punctured - nCwLength = pCode->N-1; - break; - case QRATYPE_CRCPUNCTURED2: - // the two CRC symbols are punctured - nCwLength = pCode->N-2; - break; - default: - nCwLength = -1; - } - - return nCwLength; -} - -float _qra65_get_code_rate(const qracode *pCode) -{ - return 1.0f*_qra65_get_message_length(pCode)/_qra65_get_codeword_length(pCode); -} - -int _qra65_get_alphabet_size(const qracode *pCode) -{ - return pCode->M; -} -int _qra65_get_bits_per_symbol(const qracode *pCode) -{ - return pCode->m; -} -static void _qra65_mask(const qracode *pcode, float *ix, const int *mask, const int *x) -{ - // mask intrinsic information ix with available a priori knowledge - - int k,kk, smask; - const int nM=pcode->M; - const int nm=pcode->m; - int nK; - - // Exclude from masking the symbols which have been punctured. - // nK is the length of the mask and x arrays, which do - // not include any punctured symbol - nK = _qra65_get_message_length(pcode); - - // for each symbol set to zero the probability - // of the values which are not allowed by - // the a priori information - - for (k=0;k>1) ^ CRC6_GEN_POL; - else - sr = (sr>>1); - t>>=1; - } - } - - return sr; -} - -static void _qra65_crc12(int *y, int *x, int sz) -{ - int k,j,t,sr = 0; - for (k=0;k>1) ^ CRC12_GEN_POL; - else - sr = (sr>>1); - t>>=1; - } - } - - y[0] = sr&0x3F; - y[1] = (sr>>6); -} - - diff --git a/lib/qra/q65/qra65.h b/lib/qra/q65/qra65.h deleted file mode 100644 index ffa383279..000000000 --- a/lib/qra/q65/qra65.h +++ /dev/null @@ -1,101 +0,0 @@ -// qra65.h -// QRA65 modes encoding/decoding functions -// -// (c) 2020 - Nico Palermo, IV3NWV - Microtelecom Srl, Italy -// ------------------------------------------------------------------------------ -// This file is part of the qracodes project, a Forward Error Control -// encoding/decoding package based on Q-ary RA (Repeat and Accumulate) LDPC codes. -// -// qracodes is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// qracodes is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with qracodes source distribution. -// If not, see . - -#ifndef _qra65_h -#define _qra65_h - -#include "qracodes.h" - -// Error codes returned by qra65_decode(...) -#define QRA65_DECODE_INVPARAMS -1 -#define QRA65_DECODE_FAILED -2 -#define QRA65_DECODE_CRCMISMATCH -3 - -// maximum number of weights for the fast-fading metric evaluation -#define QRA65_FASTFADING_MAXWEIGTHS 65 - -typedef struct { - const qracode *pQraCode; // qra code to be used by the codec - float decoderEsNoMetric; // value for which we optimize the decoder metric - int *x; // codec input - int *y; // codec output - float *qra_v2cmsg; // decoder v->c messages - float *qra_c2vmsg; // decoder c->v messages - float *ix; // decoder intrinsic information - float *ex; // decoder extrinsic information - // variables used to compute the intrinsics in the fast-fading case - int nBinsPerTone; - int nBinsPerSymbol; - float ffNoiseVar; - float ffEsNoMetric; - int nWeights; - float ffWeight[QRA65_FASTFADING_MAXWEIGTHS]; -} qra65_codec_ds; - -int qra65_init(qra65_codec_ds *pCodec, const qracode *pQraCode); -void qra65_free(qra65_codec_ds *pCodec); - -int qra65_encode(const qra65_codec_ds *pCodec, int *pOutputCodeword, const int *pInputMsg); - -int qra65_intrinsics(qra65_codec_ds *pCodec, float *pIntrinsics, const float *pInputEnergies); - -int qra65_intrinsics_fastfading(qra65_codec_ds *pCodec, - float *pIntrinsics, // intrinsic symbol probabilities output - const float *pInputEnergies, // received energies input - const int submode, // submode idx (0=A ... 4=E) - const float B90, // spread bandwidth (90% fractional energy) - const int fadingModel); // 0=Gaussian 1=Lorentzian fade model - - -int qra65_decode(qra65_codec_ds *pCodec, - int* pDecodedCodeword, - int *pDecodedMsg, - const float *pIntrinsics, - const int *pAPMask, - const int *pAPSymbols); - -int qra65_esnodb(const qra65_codec_ds *pCodec, - float *pEsNodB, - const int *ydec, - const float *pInputEnergies); - -int qra65_esnodb_fastfading( - const qra65_codec_ds *pCodec, - float *pEsNodB, - const int *ydec, - const float *pInputEnergies); - - -#define qra65_get_message_length(pCodec) _qra65_get_message_length((pCodec)->pQraCode) -#define qra65_get_codeword_length(pCodec) _qra65_get_codeword_length((pCodec)->pQraCode) -#define qra65_get_code_rate(pCodec) _qra65_get_code_rate((pCodec)->pQraCode) -#define qra65_get_alphabet_size(pCodec) _qra65_get_alphabet_size((pCodec)->pQraCode) -#define qra65_get_bits_per_symbol(pCodec) _qra65_get_bits_per_symbol((pCodec)->pQraCode) - -// internally used but made publicly available for the defines above -int _qra65_get_message_length(const qracode *pCode); -int _qra65_get_codeword_length(const qracode *pCode); -float _qra65_get_code_rate(const qracode *pCode); -void _qra65_mask(const qracode *pcode, float *ix, const int *mask, const int *x); -int _qra65_get_alphabet_size(const qracode *pCode); -int _qra65_get_bits_per_symbol(const qracode *pCode); - -#endif // _qra65_h \ No newline at end of file From 5d352d3068a302d0df4e9187f658e99e2f0aeb46 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 25 Oct 2020 21:29:44 -0400 Subject: [PATCH 103/206] Declare _q65_mask() as static when first declared, in q65.h. Add qracodes.o to Makefile.Win. --- lib/qra/q65/Makefile.Win | 2 +- lib/qra/q65/q65.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/qra/q65/Makefile.Win b/lib/qra/q65/Makefile.Win index cedf2ef17..99b34d726 100644 --- a/lib/qra/q65/Makefile.Win +++ b/lib/qra/q65/Makefile.Win @@ -16,7 +16,7 @@ CFLAGS = -O2 -Wall -I. -D_WIN32 all: libq65.a q65.exe OBJS1 = normrnd.o npfwht.o pdmath.o qra15_65_64_irr_e23.o \ - q65.o + q65.o qracodes.o libq65.a: $(OBJS1) ar cr libq65.a $(OBJS1) diff --git a/lib/qra/q65/q65.h b/lib/qra/q65/q65.h index 04b5d8365..d36cb608f 100644 --- a/lib/qra/q65/q65.h +++ b/lib/qra/q65/q65.h @@ -96,8 +96,8 @@ int q65_esnodb_fastfading( int _q65_get_message_length(const qracode *pCode); int _q65_get_codeword_length(const qracode *pCode); float _q65_get_code_rate(const qracode *pCode); -void _q65_mask(const qracode *pcode, float *ix, const int *mask, const int *x); +static void _q65_mask(const qracode *pcode, float *ix, const int *mask, const int *x); int _q65_get_alphabet_size(const qracode *pCode); int _q65_get_bits_per_symbol(const qracode *pCode); -#endif // _qra65_h \ No newline at end of file +#endif // _qra65_h From cc5e0c7f2c7c8a49b0fd6a35fa0045523c904a28 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 26 Oct 2020 16:54:05 -0400 Subject: [PATCH 104/206] Add a Fortran program to test calls to Nico's Q65 codec. --- CMakeLists.txt | 6 +++ lib/qra/q65/Makefile.Win | 9 +++- lib/qra/q65/q65_ftn_test.f90 | 50 ++++++++++++++++++++ lib/qra/q65/q65_subs.c | 90 ++++++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 lib/qra/q65/q65_ftn_test.f90 create mode 100644 lib/qra/q65/q65_subs.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ac4ad4f8..4af7e5dcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -587,6 +587,9 @@ set (qra_CSRCS lib/qra/qracodes/qra13_64_64_irr_e.c lib/qra/qracodes/qracodes.c lib/qra/qracodes/normrnd.c + lib/qra/q65/qra15_65_64_irr_e23.c + lib/qra/q65/q65.c + lib/qra/q65/q65_subs.c ) set (wsjt_CSRCS @@ -1123,6 +1126,9 @@ target_link_libraries (test_qra64 wsjt_fort wsjt_cxx) add_executable (test_q65 lib/test_q65.f90) target_link_libraries (test_q65 wsjt_fort wsjt_cxx) +add_executable (q65_ftn_test lib/qra/q65/q65_ftn_test.f90) +target_link_libraries (q65_ftn_test wsjt_fort wsjt_cxx) + add_executable (jt49sim lib/jt49sim.f90) target_link_libraries (jt49sim wsjt_fort wsjt_cxx) diff --git a/lib/qra/q65/Makefile.Win b/lib/qra/q65/Makefile.Win index 99b34d726..8f2214d99 100644 --- a/lib/qra/q65/Makefile.Win +++ b/lib/qra/q65/Makefile.Win @@ -1,5 +1,7 @@ CC = gcc CFLAGS = -O2 -Wall -I. -D_WIN32 +FC = gfortran +FFLAGS = -Wall -fbounds-check # Default rules %.o: %.c @@ -13,7 +15,7 @@ CFLAGS = -O2 -Wall -I. -D_WIN32 %.o: %.F90 ${FC} ${FFLAGS} -c $< -all: libq65.a q65.exe +all: libq65.a q65.exe q65_ftn_test.exe OBJS1 = normrnd.o npfwht.o pdmath.o qra15_65_64_irr_e23.o \ q65.o qracodes.o @@ -27,6 +29,11 @@ OBJS2 = q65test.o q65.exe: $(OBJS2) ${CC} -o q65.exe $(OBJS2) libq65.a -lm +OBJS3 = q65_ftn_test.o q65_subs.o + +q65_ftn_test.exe: $(OBJS3) + ${FC} -o q65_ftn_test.exe $(OBJS3) libq65.a -lm + .PHONY : clean clean: diff --git a/lib/qra/q65/q65_ftn_test.f90 b/lib/qra/q65/q65_ftn_test.f90 new file mode 100644 index 000000000..6291950a2 --- /dev/null +++ b/lib/qra/q65/q65_ftn_test.f90 @@ -0,0 +1,50 @@ +program q65_ftn_test + + use packjt77 + parameter (LL=64,NN=63) + integer x(13) !User's 78-bit message as 13 six-bit integers + integer y(63) !Q65 codeword for x + integer xdec(13) !Decoded message + integer APmask(13) + integer APsymbols(13) + real s3(0:LL-1,NN) + real s3prob(0:LL-1,NN) + character*37 msg0,msg,msgsent + character*77 c77 + logical unpk77_success + + narg=iargc() + if(narg.ne.1) then + print*,'Usage: q65_ftn_test "message"' + print*,'Example: q65_ftn_test "K1ABC W9XYZ EN37"' + go to 999 + endif + call getarg(1,msg0) + call pack77(msg0,i3,n3,c77) + call unpack77(c77,0,msgsent,unpk77_success) !Unpack to get msgsent + read(c77,1000) x +1000 format(12b6.6,b5.5) + + call q65_enc(x,y) + + write(*,1010) x,msg0 +1010 format('User message:'/13i3,2x,a) + write(*,1020) y +1020 format(/'Generated codeword:'/(20i3)) + + s3=0. + s3prob=0. + do j=1,NN + s3(y(j),j)=1.0 + enddo + APmask=0 + APsymbols=0 + + call q65_dec(s3,APmask,APsymbols,s3prob,snr2500,xdec,irc) + + write(c77,1000) xdec + call unpack77(c77,0,msg,unpk77_success) !Unpack to get msgsent + write(*,1100) xdec,trim(msg) +1100 format(/'Decoded message:'/13i3,2x,a) + +999 end program q65_ftn_test diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c new file mode 100644 index 000000000..97889871f --- /dev/null +++ b/lib/qra/q65/q65_subs.c @@ -0,0 +1,90 @@ +// q65_subs.c + +/* Fortran interface for Q65 codec + + To encode a Q65 message: + + integer x(13) !Message payload, 78 bits as 13 six-bit integers + integer y(63) !Codeword, 63 six-bit integers + call q65_enc(imsg,icodeword) + + To decode a Q65 message: + + parameter (LL=64,NN=63) + real s3(LL,NN) !Received energies + real s3prob(LL,NN) !Symbol-value probabilities + integer APmask(13) + integer APsymbols(13) + real snr2500 + integer xdec(13) !Decoded 78-bit message as 13 six-bit integers + integer irc !Return code from q65_decode() + + call q65_dec(s3,APmask,APsymbols,s3prob,snr2500,xdec,irc) +*/ + +#include "qra15_65_64_irr_e23.h" // QRA code used by Q65 +#include "q65.h" +#include +#include + +static q65_codec_ds codec; + +void q65_enc_(int x[], int y[]) +{ + + static int first=1; + if (first) { + // Set the QRA code, allocate memory, and initialize + int rc = q65_init(&codec,&qra15_65_64_irr_e23); + if (rc<0) { + printf("error in q65_init()\n"); + exit(0); + } + first=0; + } + // Encode message x[13], producing codeword y[63] + q65_encode(&codec,y,x); +} + +void q65_dec_(float s3[], int APmask[], int APsymbols[], float s3prob[], + float* snr2500, int xdec[], int* rc0) +{ + +/* Input: s3[LL,NN] Received energies + * APmask[13] AP information to be used in decoding + * APsymbols[13] Available AP informtion + * Output: s3prob[LL,NN] Symbol-value intrinsic probabilities + * snr2500 SNR_2500 of decoded signal, or lower limit + * xdec[13] Decoded 78-bit message as 13 six-bit integers + * rc0 Return code from q65_decode() + */ + + int rc; + int ydec[63]; + float esnodb; + + // rc = q65_intrinsics_fastfding(&codec,s3prob,s3,submode,B90,fadingModel); + rc = q65_intrinsics(&codec,s3prob,s3); + if(rc<0) { + printf("error in q65_intrinsics()\n"); + exit(0); + } + + rc = q65_decode(&codec,ydec,xdec,s3prob,APmask,APsymbols); + *rc0=rc; + if(rc<0) { + printf("Error in q65_decode(), rc = %d\n",rc); + // rc = -1: Invalid params + // rc = -2: Decode failed + // rc = -3: CRC mismatch + return; + } + + // rc = q65_esnodb_fastfading(&codec,&esnodb,ydec,s3); + rc = q65_esnodb(&codec,&esnodb,ydec,s3); + if(rc<0) { + printf("error in q65_esnodb_fastfading()\n"); + exit(0); + } + *snr2500 = esnodb - 31.0; +} From 0d8734de47af5547b01d97ced551ebb7b423c707 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 26 Oct 2020 19:25:16 -0400 Subject: [PATCH 105/206] Update some path names for QRA64/Q65 files. --- CMakeLists.txt | 8 ++++---- lib/qra/q65/q65_ftn_test.f90 | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4af7e5dcb..da53e1be8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -581,12 +581,12 @@ set_source_files_properties (${ka9q_CSRCS} PROPERTIES COMPILE_FLAGS -Wno-sign-co set (qra_CSRCS lib/qra/qra64/qra64.c lib/qra/qra64/qra64_subs.c - lib/qra/qracodes/npfwht.c - lib/qra/qracodes/pdmath.c lib/qra/qracodes/qra12_63_64_irr_b.c lib/qra/qracodes/qra13_64_64_irr_e.c - lib/qra/qracodes/qracodes.c - lib/qra/qracodes/normrnd.c + lib/qra/q65/npfwht.c + lib/qra/q65/pdmath.c + lib/qra/q65/qracodes.c + lib/qra/q65/normrnd.c lib/qra/q65/qra15_65_64_irr_e23.c lib/qra/q65/q65.c lib/qra/q65/q65_subs.c diff --git a/lib/qra/q65/q65_ftn_test.f90 b/lib/qra/q65/q65_ftn_test.f90 index 6291950a2..6ff17ddf6 100644 --- a/lib/qra/q65/q65_ftn_test.f90 +++ b/lib/qra/q65/q65_ftn_test.f90 @@ -25,7 +25,7 @@ program q65_ftn_test read(c77,1000) x 1000 format(12b6.6,b5.5) - call q65_enc(x,y) + call q65_enc(x,y) !Encode message, x(1:13) ==> y(1:63) write(*,1010) x,msg0 1010 format('User message:'/13i3,2x,a) From a473cee2ea4ecc21680b8f7e3e1d14740e766f18 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 26 Oct 2020 19:42:03 -0400 Subject: [PATCH 106/206] Move q65sim.f90 to the q65 directory. --- CMakeLists.txt | 2 +- lib/qra/{qra65 => q65}/q65sim.f90 | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename lib/qra/{qra65 => q65}/q65sim.f90 (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt index da53e1be8..41eec794b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1117,7 +1117,7 @@ target_link_libraries (sumsim wsjt_fort wsjt_cxx) add_executable (qra64sim lib/qra/qra64/qra64sim.f90) target_link_libraries (qra64sim wsjt_fort wsjt_cxx) -add_executable (q65sim lib/qra/qra65/q65sim.f90) +add_executable (q65sim lib/qra/q65/q65sim.f90) target_link_libraries (q65sim wsjt_fort wsjt_cxx) add_executable (test_qra64 lib/test_qra64.f90) diff --git a/lib/qra/qra65/q65sim.f90 b/lib/qra/q65/q65sim.f90 similarity index 100% rename from lib/qra/qra65/q65sim.f90 rename to lib/qra/q65/q65sim.f90 From 079177579fc4503e84b8e7c6f67a1aa8b00cc310 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 12:01:41 -0400 Subject: [PATCH 107/206] Add genq65.f90 to Fortran sources. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 41eec794b..8e8e993bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -424,6 +424,7 @@ set (wsjt_FSRCS lib/gen9.f90 lib/geniscat.f90 lib/ft8/genft8.f90 + lib/qra/q65/genq65.f90 lib/genmsk_128_90.f90 lib/genmsk40.f90 lib/ft4/ft4code.f90 From ccdaf49e3a19f543f7beff0a1ee140962567d1fe Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 12:02:49 -0400 Subject: [PATCH 108/206] Must initialize Q65 codec is decode is called before encode. --- lib/qra/q65/q65_subs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c index 97889871f..c7cb0d8c4 100644 --- a/lib/qra/q65/q65_subs.c +++ b/lib/qra/q65/q65_subs.c @@ -62,7 +62,17 @@ void q65_dec_(float s3[], int APmask[], int APsymbols[], float s3prob[], int rc; int ydec[63]; float esnodb; + static int first=1; + if (first) { + // Set the QRA code, allocate memory, and initialize + int rc = q65_init(&codec,&qra15_65_64_irr_e23); + if (rc<0) { + printf("error in q65_init()\n"); + exit(0); + } + first=0; + } // rc = q65_intrinsics_fastfding(&codec,s3prob,s3,submode,B90,fadingModel); rc = q65_intrinsics(&codec,s3prob,s3); if(rc<0) { From 5a2f9e4f3fd585a0881e0da6be7d4a88591a9960 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 12:04:15 -0400 Subject: [PATCH 109/206] Updte q65sim to use the new Q65 code. --- lib/qra/q65/q65sim.f90 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/qra/q65/q65sim.f90 b/lib/qra/q65/q65sim.f90 index 8841b92cd..24dce31e6 100644 --- a/lib/qra/q65/q65sim.f90 +++ b/lib/qra/q65/q65sim.f90 @@ -14,8 +14,8 @@ program q65sim complex cspread(0:NMAX-1) !Complex amplitude for Rayleigh fading complex z real*8 f0,dt,twopi,phi,dphi,baud,fsample,freq - character msg*22,fname*17,csubmode*1,arg*12,cd*1 - character msgsent*22 + character msg*37,fname*17,csubmode*1,arg*12,cd*1 + character msgsent*37 logical lsync data lsync/.false./ @@ -74,8 +74,8 @@ program q65sim nsym=85 !Number of channel symbols mode65=2**(ichar(csubmode) - ichar('A')) - ichk=65 !Flag sent to genqra64 - call genqra64(msg,ichk,msgsent,itone,itype) + ichk=0 + call genq65(msg,ichk,msgsent,itone,i3,n3) write(*,1001) itone 1001 format('Channel symbols:'/(20i3)) @@ -107,8 +107,8 @@ program q65sim bandwidth_ratio=2500.0/6000.0 sig=sqrt(2*bandwidth_ratio)*10.0**(0.05*snrdb) if(snrdb.gt.90.0) sig=1.0 - write(*,1020) ifile,ntrperiod,f0,csubmode,snrdb,xdt,fspread,msgsent -1020 format(i4,i6,f7.1,2x,a1,2x,f5.1,f6.2,f6.1,2x,a22) + write(*,1020) ifile,ntrperiod,f0,csubmode,snrdb,xdt,fspread,trim(msgsent) +1020 format(i4,i6,f7.1,2x,a1,2x,f5.1,f6.2,f6.1,2x,a) phi=0.d0 dphi=0.d0 k=(xdt+0.5)*12000 !Start audio at t=xdt+0.5 s (TR=15 and 30 s) From 2dad27f1ad679b2b3861c9161f2c4da865082b95 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 13:08:07 -0400 Subject: [PATCH 110/206] First decodes of Q65 from within wsjtx. --- CMakeLists.txt | 1 + lib/q65_decode.f90 | 52 ++++++----- lib/qra/q65/q65_loops.f90 | 175 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 207 insertions(+), 21 deletions(-) create mode 100644 lib/qra/q65/q65_loops.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 8e8e993bf..c001db3f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -497,6 +497,7 @@ set (wsjt_FSRCS lib/ps4.f90 lib/qra64a.f90 lib/qra_loops.f90 + lib/qra/q65/q65_loops.f90 lib/refspectrum.f90 lib/savec2.f90 lib/sec0.f90 diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index d1f874649..3daf8c4c3 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -42,7 +42,7 @@ contains ! Output: sent to the callback routine for display to user use timer_module, only: timer - use packjt + use packjt77 use, intrinsic :: iso_c_binding parameter (NMAX=300*12000) !Max TRperiod is 300 s class(q65_decoder), intent(inout) :: this @@ -50,10 +50,13 @@ contains character(len=12) :: mycall, hiscall !Used for AP decoding character(len=6) :: hisgrid character*37 decoded !Decoded message + character*77 c77 integer*2 iwave(NMAX) !Raw data real, allocatable :: dd(:) !Raw data integer dat4(12) !Decoded message as 12 6-bit integers + integer dat4a(13) logical ltext + logical unpk77_success complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/,nsubmodez/-1/ @@ -86,9 +89,9 @@ contains if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning ! Prime the QRA decoder for possible use of AP - call packcall(mycall(1:6),nc1,ltext) - call packcall(hiscall(1:6),nc2,ltext) - call packgrid(hisgrid(1:4),ng2,ltext) +! 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 @@ -100,18 +103,18 @@ contains minsync=-2 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 +! 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) @@ -127,16 +130,23 @@ contains dd=fac*iwave nmode=65 call ana64(dd,npts,c00) - call timer('qraloops',0) - call qra_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & + call timer('q65loops',0) + call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) - call timer('qraloops',1) + call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) endif decoded=' ' if(irc.ge.0) then - call unpackmsg(dat4,decoded) !Unpack the user message - call fmtmsg(decoded,iz) + dat4a(1:12)=dat4 + dat4a(13)=9 + write(74,3074) dat4a,1 +3074 format(13i3,i6) + write(c77,1000) dat4a +1000 format(12b6.6,b5.5) + call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent +! 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=' ' diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 new file mode 100644 index 000000000..c0dbf59c1 --- /dev/null +++ b/lib/qra/q65/q65_loops.f90 @@ -0,0 +1,175 @@ +subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & + ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) + + use packjt77 + use timer_module, only: timer + parameter (LN=2176*63) !LN=LL*NN; LL = 64*(mode64+2) + character*37 decoded + character*77 c77 + complex c00(0:npts2-1) !Analytic representation of dd(), 6000 Hz + complex ,allocatable :: c0(:) !Ditto, with freq shift + real a(3) !twkfreq params f,f1,f2 + real s3(LN) !Symbol spectra + real s3avg(LN) !Averaged symbol spectra + real s3prob(LN) !Symbol-value probabilities + real s3tmp(4032) + logical unpk77_success + integer APmask(13) + integer APsymbols(13) + integer dat4(13),dat4x(13) !Decoded message (as 13 six-bit integers) + integer nap(0:11) !AP return codes + data nap/0,2,3,2,3,4,2,3,6,4,6,6/,nsave/0/ + save nsave,s3avg + + allocate(c0(0:npts2-1)) + irc=-99 + s3lim=20. + ibwmax=11 + if(mode64.le.4) ibwmax=9 + ibwmin=ibwmax + idtmax=3 + call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist) + LL=64*(mode64+2) + NN=63 + napmin=99 + ncall=0 + + do iavg=0,1 + if(iavg.eq.1) then + idfmax=1 + idtmax=1 + endif + do idf=1,idfmax + ndf=idf/2 + if(mod(idf,2).eq.0) ndf=-ndf + a=0. + a(1)=-(f0+0.4*ndf) + call twkfreq(c00,c0,npts2,6000.0,a) + do idt=1,idtmax + ndt=idt/2 + if(iavg.eq.0) then + if(mod(idt,2).eq.0) ndt=-ndt + jpk=jpk0 + 240*ndt !240/6000 = 0.04 s = tsym/32 + if(jpk.lt.0) jpk=0 + call timer('spec64 ',0) + call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) + call timer('spec64 ',1) + call pctile(s3,LL*NN,40,base) + s3=s3/base + where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim + else + s3(1:LL*NN)=s3avg(1:LL*NN) + endif + do ibw=ibwmax,ibwmin,-2 + ndist=ndf**2 + ndt**2 + ((ibwmax-ibw)/2)**2 + if(ndist.gt.maxdist) cycle + b90=1.728**ibw + if(b90.gt.230.0) cycle + if(b90.lt.0.15*width) exit + ncall=ncall+1 + call timer('qra64_de',0) +!### +! call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & +! nFadingModel,dat4,snr2,irc) + APmask=0 + APsymbols=0 + call s3fix(s3,s3tmp) + call q65_dec(s3tmp,APmask,APsymbols,s3prob,snr2,dat4,irc) + write(74,3074) dat4,0 +3074 format(13i3,i6) +!### + call timer('qra64_de',1) + if(irc.eq.0) go to 200 +! if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) + iirc=max(0,min(irc,11)) + if(irc.gt.0 .and. nap(iirc).lt.napmin) then + dat4x=dat4 + b90x=b90 + snr2x=snr2 + napmin=nap(iirc) + irckeep=irc + xdtkeep=jpk/6000.0 - 1.0 + f0keep=-a(1) + idfkeep=idf + idtkeep=idt + ibwkeep=ibw + ndistx=ndist + go to 100 !### + endif + enddo ! ibw (b90 loop) + !### if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 + enddo ! idt (DT loop) + enddo ! idf (f0 loop) +! if(iavg.eq.0 .and. abs(jpk0-4320).le.1300) then + if(iavg.eq.0) then + a=0. + a(1)=-f0 + call twkfreq(c00,c0,npts2,6000.0,a) + jpk=3000 !### These definitions need work ### +! if(nsps.ge.3600) jpk=4080 !### + if(nsps.ge.3600) jpk=6000 !### + call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) + call pctile(s3,LL*NN,40,base) + s3=s3/base + where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim + s3avg(1:LL*NN)=s3avg(1:LL*NN)+s3(1:LL*NN) + nsave=nsave+1 + endif + if(iavg.eq.0 .and. nsave.lt.2) exit + enddo ! iavg + +100 if(napmin.ne.99) then + dat4=dat4x + b90=b90x + snr2=snr2x + irc=irckeep + xdt=xdtkeep + f0=f0keep + idt=idtkeep + idf=idfkeep + ibw=ibwkeep + ndist=ndistx + endif + +200 if(mode.eq.65 .and. nsps.eq.7200/2) xdt=xdt+0.4 !### Empirical -- WHY ??? ### + + if(irc.ge.0) then + navg=nsave + if(iavg.eq.0) navg=0 + !### For tests only: + open(53,file='fort.53',status='unknown',position='append') + write(c77,1200) dat4 +1200 format(12b6.6,b5.5) + call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent +! call unpackmsg(dat4,decoded) !Unpack the user message + write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,ndist,irc,navg,decoded(1:22) +3053 format(3i5,f7.1,f7.2,2f7.1,3i4,2x,a22) + close(53) + !### + nsave=0 + s3avg=0. + irc=irc + 100*navg + endif + return +end subroutine q65_loops + +subroutine s3fix(s3,s3tmp) + real s3(0:191,63) + real s3tmp(0:63,63) + integer ipk1(1) + integer y(63) + + do j=1,63 + s3tmp(0:63,j)=s3(64:127,j) +! s3tmp(y(j),j)=1.0 + ipk1=maxloc(s3(0:191,j)) + m=ipk1(1)-65 + ipk1=maxloc(s3tmp(0:63,j)) + mtmp=ipk1(1)-1 + write(72,3072) j,y(j),m,m-y(j),mtmp,mtmp-y(j) +3072 format(6i7) + enddo + write(70) s3tmp + + return +end subroutine s3fix From 4d739a31ca9f4b8a5075ede6458f5a1bc754c4b4 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 13:22:02 -0400 Subject: [PATCH 111/206] Minor cleanup of Q65 decoder sequence. Much more needed! --- lib/q65_decode.f90 | 16 ++-------------- lib/qra/q65/q65_loops.f90 | 4 +--- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 3daf8c4c3..062952c84 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -53,8 +53,7 @@ contains character*77 c77 integer*2 iwave(NMAX) !Raw data real, allocatable :: dd(:) !Raw data - integer dat4(12) !Decoded message as 12 6-bit integers - integer dat4a(13) + integer dat4(13) !Decoded message as 12 6-bit integers logical ltext logical unpk77_success complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s @@ -138,20 +137,9 @@ contains endif decoded=' ' if(irc.ge.0) then - dat4a(1:12)=dat4 - dat4a(13)=9 - write(74,3074) dat4a,1 -3074 format(13i3,i6) - write(c77,1000) dat4a + write(c77,1000) dat4 1000 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent -! 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) call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index c0dbf59c1..d49af9632 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -65,7 +65,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & if(ndist.gt.maxdist) cycle b90=1.728**ibw if(b90.gt.230.0) cycle - if(b90.lt.0.15*width) exit +! if(b90.lt.0.15*width) exit ncall=ncall+1 call timer('qra64_de',0) !### @@ -75,8 +75,6 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & APsymbols=0 call s3fix(s3,s3tmp) call q65_dec(s3tmp,APmask,APsymbols,s3prob,snr2,dat4,irc) - write(74,3074) dat4,0 -3074 format(13i3,i6) !### call timer('qra64_de',1) if(irc.eq.0) go to 200 From 5d904927a0fc262e4a83589a12c1816f31d16b1c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 13:56:25 -0400 Subject: [PATCH 112/206] Decode Q65 using the Lorentzian fast fading model. --- lib/q65_decode.f90 | 21 +-------------------- lib/qra/q65/q65_loops.f90 | 30 ++---------------------------- lib/qra/q65/q65_subs.c | 10 +++++++--- 3 files changed, 10 insertions(+), 51 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 062952c84..d8c51816a 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -54,7 +54,6 @@ contains integer*2 iwave(NMAX) !Raw data real, allocatable :: dd(:) !Raw data integer dat4(13) !Decoded message as 12 6-bit integers - logical ltext logical unpk77_success complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s @@ -86,11 +85,6 @@ contains df1=12000.0/nfft1 this%callback => callback if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning - -! Prime the QRA decoder for possible use of AP -! 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 @@ -101,19 +95,6 @@ contains if(ndepth.ge.2) maxaptype=5 !### minsync=-2 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 timer('sync_q65',0) @@ -131,7 +112,7 @@ contains call ana64(dd,npts,c00) call timer('q65loops',0) call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & - ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) + ndepth,jpk0,xdt,f0,width,snr2,irc,dat4) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) endif diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index d49af9632..ea116fd9a 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,5 +1,5 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & - ndepth,nc1,nc2,ng2,naptype,jpk0,xdt,f0,width,snr2,irc,dat4) + ndepth,jpk0,xdt,f0,width,snr2,irc,dat4) use packjt77 use timer_module, only: timer @@ -68,14 +68,9 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ! if(b90.lt.0.15*width) exit ncall=ncall+1 call timer('qra64_de',0) -!### -! call qra64_dec(s3,nc1,nc2,ng2,naptype,0,nSubmode,b90, & -! nFadingModel,dat4,snr2,irc) APmask=0 APsymbols=0 - call s3fix(s3,s3tmp) - call q65_dec(s3tmp,APmask,APsymbols,s3prob,snr2,dat4,irc) -!### + call q65_dec(s3,APmask,APsymbols,nsubmode,b90,nFadingModel,s3prob,snr2,dat4,irc) call timer('qra64_de',1) if(irc.eq.0) go to 200 ! if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) @@ -150,24 +145,3 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & endif return end subroutine q65_loops - -subroutine s3fix(s3,s3tmp) - real s3(0:191,63) - real s3tmp(0:63,63) - integer ipk1(1) - integer y(63) - - do j=1,63 - s3tmp(0:63,j)=s3(64:127,j) -! s3tmp(y(j),j)=1.0 - ipk1=maxloc(s3(0:191,j)) - m=ipk1(1)-65 - ipk1=maxloc(s3tmp(0:63,j)) - mtmp=ipk1(1)-1 - write(72,3072) j,y(j),m,m-y(j),mtmp,mtmp-y(j) -3072 format(6i7) - enddo - write(70) s3tmp - - return -end subroutine s3fix diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c index c7cb0d8c4..dfb2a50f1 100644 --- a/lib/qra/q65/q65_subs.c +++ b/lib/qra/q65/q65_subs.c @@ -46,13 +46,17 @@ void q65_enc_(int x[], int y[]) q65_encode(&codec,y,x); } -void q65_dec_(float s3[], int APmask[], int APsymbols[], float s3prob[], +void q65_dec_(float s3[], int APmask[], int APsymbols[], int* submode, + float* B90, int* fadingModel, float s3prob[], float* snr2500, int xdec[], int* rc0) { /* Input: s3[LL,NN] Received energies * APmask[13] AP information to be used in decoding * APsymbols[13] Available AP informtion + * submode 0=A, 4=E + * B90 Spread bandwidth, 90% fractional energy + * fadingModel 0=Gaussian, 1=Lorentzian * Output: s3prob[LL,NN] Symbol-value intrinsic probabilities * snr2500 SNR_2500 of decoded signal, or lower limit * xdec[13] Decoded 78-bit message as 13 six-bit integers @@ -73,8 +77,8 @@ void q65_dec_(float s3[], int APmask[], int APsymbols[], float s3prob[], } first=0; } - // rc = q65_intrinsics_fastfding(&codec,s3prob,s3,submode,B90,fadingModel); - rc = q65_intrinsics(&codec,s3prob,s3); + rc = q65_intrinsics_fastfading(&codec,s3prob,s3,*submode,*B90,*fadingModel); + // rc = q65_intrinsics(&codec,s3prob,s3); if(rc<0) { printf("error in q65_intrinsics()\n"); exit(0); From a41325d596a339763dda6f7ea664beaa6725d12a Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 15:45:34 -0400 Subject: [PATCH 113/206] Use fast fading model in q65_ftn_test. --- lib/qra/q65/q65_ftn_test.f90 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/qra/q65/q65_ftn_test.f90 b/lib/qra/q65/q65_ftn_test.f90 index 6ff17ddf6..607d0f5ba 100644 --- a/lib/qra/q65/q65_ftn_test.f90 +++ b/lib/qra/q65/q65_ftn_test.f90 @@ -1,7 +1,7 @@ program q65_ftn_test use packjt77 - parameter (LL=64,NN=63) + parameter (LL=192,NN=63) integer x(13) !User's 78-bit message as 13 six-bit integers integer y(63) !Q65 codeword for x integer xdec(13) !Decoded message @@ -35,13 +35,14 @@ program q65_ftn_test s3=0. s3prob=0. do j=1,NN - s3(y(j),j)=1.0 + s3(y(j)+64,j)=1.0 enddo APmask=0 APsymbols=0 - - call q65_dec(s3,APmask,APsymbols,s3prob,snr2500,xdec,irc) - + nsubmode=0 + b90=1.0 + nFadingModel=1 + call q65_dec(s3,APmask,APsymbols,nsubmode,b90,nFadingModel,s3prob,snr2500,xdec,irc) write(c77,1000) xdec call unpack77(c77,0,msg,unpk77_success) !Unpack to get msgsent write(*,1100) xdec,trim(msg) From 9643e8a75332111c2c0e7a6d84109fcbb83c7875 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 15:51:32 -0400 Subject: [PATCH 114/206] Code cleanup. --- lib/qra/q65/q65_loops.f90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index ea116fd9a..b2498e982 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -71,9 +71,12 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & APmask=0 APsymbols=0 call q65_dec(s3,APmask,APsymbols,nsubmode,b90,nFadingModel,s3prob,snr2,dat4,irc) + ! irc > 0 ==> number of iterations required to decode + ! -1 = invalid params + ! -2 = decode failed + ! -3 = CRC mismatch call timer('qra64_de',1) - if(irc.eq.0) go to 200 -! if(irc.gt.0) call badmsg(irc,dat4,nc1,nc2,ng2) + if(irc.ge.0) go to 200 iirc=max(0,min(irc,11)) if(irc.gt.0 .and. nap(iirc).lt.napmin) then dat4x=dat4 From c6424100a20942ab4c671805a7ad0dbe4a3c8602 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 15:52:26 -0400 Subject: [PATCH 115/206] Code cleanup. --- lib/qra/q65/q65_subs.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c index dfb2a50f1..6908c7c8a 100644 --- a/lib/qra/q65/q65_subs.c +++ b/lib/qra/q65/q65_subs.c @@ -67,7 +67,7 @@ void q65_dec_(float s3[], int APmask[], int APsymbols[], int* submode, int ydec[63]; float esnodb; static int first=1; - + if (first) { // Set the QRA code, allocate memory, and initialize int rc = q65_init(&codec,&qra15_65_64_irr_e23); @@ -78,7 +78,6 @@ void q65_dec_(float s3[], int APmask[], int APsymbols[], int* submode, first=0; } rc = q65_intrinsics_fastfading(&codec,s3prob,s3,*submode,*B90,*fadingModel); - // rc = q65_intrinsics(&codec,s3prob,s3); if(rc<0) { printf("error in q65_intrinsics()\n"); exit(0); @@ -86,13 +85,11 @@ void q65_dec_(float s3[], int APmask[], int APsymbols[], int* submode, rc = q65_decode(&codec,ydec,xdec,s3prob,APmask,APsymbols); *rc0=rc; - if(rc<0) { - printf("Error in q65_decode(), rc = %d\n",rc); - // rc = -1: Invalid params - // rc = -2: Decode failed - // rc = -3: CRC mismatch - return; - } + // rc = -1: Invalid params + // rc = -2: Decode failed + // rc = -3: CRC mismatch + *snr2500 = -31.0; + if(rc<0) return; // rc = q65_esnodb_fastfading(&codec,&esnodb,ydec,s3); rc = q65_esnodb(&codec,&esnodb,ydec,s3); From bbad483aaf5eb0a921b2e84ea059cb17409142ef Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 15:52:57 -0400 Subject: [PATCH 116/206] Code cleanup in q65sim.f90. --- lib/qra/q65/q65sim.f90 | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/lib/qra/q65/q65sim.f90 b/lib/qra/q65/q65sim.f90 index 24dce31e6..762c9ef87 100644 --- a/lib/qra/q65/q65sim.f90 +++ b/lib/qra/q65/q65sim.f90 @@ -7,7 +7,8 @@ program q65sim parameter (NMAX=300*12000) !Total samples in .wav file type(hdr) h !Header for .wav file integer*2 iwave(NMAX) !Generated waveform - integer*4 itone(85) !Channel symbols (values 0-65) + integer itone(85) !Channel symbols (values 0-65) + integer y(63) !Codeword real*4 xnoise(NMAX) !Generated random noise real*4 dat(NMAX) !Generated real data complex cdat(NMAX) !Generated complex waveform @@ -76,23 +77,35 @@ program q65sim ichk=0 call genq65(msg,ichk,msgsent,itone,i3,n3) - write(*,1001) itone -1001 format('Channel symbols:'/(20i3)) + + j=0 + do i=1,85 + if(itone(i).gt.0) then + j=j+1 + y(j)=itone(i)-1 + endif + enddo + write(*,1001) y(1:13) +1001 format('Generated message:'/13i3) + write(*,1002) y +1002 format(/'Codeword:'/(20i3)) + write(*,1003) itone +1003 format(/'Channel symbols:'/(20i3)) baud=12000.d0/nsps !Keying rate (6.67 baud fot 15-s sequences) h=default_header(12000,npts) - write(*,1000) -1000 format('File TR Freq Mode S/N DT Dop Message'/60('-')) + write(*,1004) +1004 format('File TR Freq Mode S/N DT Dop Message'/60('-')) nsync=0 do ifile=1,nfiles !Loop over requested number of files if(ntrperiod.lt.60) then - write(fname,1002) ifile !Output filename -1002 format('000000_',i6.6,'.wav') + write(fname,1005) ifile !Output filename +1005 format('000000_',i6.6,'.wav') else - write(fname,1104) ifile -1104 format('000000_',i4.4,'.wav') + write(fname,1106) ifile +1106 format('000000_',i4.4,'.wav') endif open(10,file=trim(fname),access='stream',status='unknown') From 494a8fc9a7448af4bb6a347f05d55d01e6f3c9de Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 16:08:50 -0400 Subject: [PATCH 117/206] More cleanup: Q65 SNRs, reported irc values. --- lib/q65_decode.f90 | 3 ++- lib/qra/q65/q65_subs.c | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index d8c51816a..2c238b824 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -118,6 +118,7 @@ contains endif decoded=' ' if(irc.ge.0) then + irc=0 !### TEMPORARY ??? ### write(c77,1000) dat4 1000 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent @@ -125,7 +126,7 @@ contains call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) else - nsnr=db(snr1) - 32.0 + nsnr=db(snr1) - 35.0 !### TEMPORARY? ### call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c index 6908c7c8a..f589f7faa 100644 --- a/lib/qra/q65/q65_subs.c +++ b/lib/qra/q65/q65_subs.c @@ -91,8 +91,7 @@ void q65_dec_(float s3[], int APmask[], int APsymbols[], int* submode, *snr2500 = -31.0; if(rc<0) return; - // rc = q65_esnodb_fastfading(&codec,&esnodb,ydec,s3); - rc = q65_esnodb(&codec,&esnodb,ydec,s3); + rc = q65_esnodb_fastfading(&codec,&esnodb,ydec,s3); if(rc<0) { printf("error in q65_esnodb_fastfading()\n"); exit(0); From fca76a5730832c81f719e7ce315b6620efdfaf88 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 27 Oct 2020 16:28:25 -0400 Subject: [PATCH 118/206] Report Q65 average decodes to the callback routine so test_q65 can distinguish them. --- lib/q65_decode.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 2c238b824..ec96ad4ec 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -118,7 +118,7 @@ contains endif decoded=' ' if(irc.ge.0) then - irc=0 !### TEMPORARY ??? ### + irc=(irc/100) * 100 !### TEMPORARY ??? ### write(c77,1000) dat4 1000 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent From 347fb063820653f170ef1a78f08ae106b41504d7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 28 Oct 2020 09:28:50 -0400 Subject: [PATCH 119/206] Separate calls to q65_intrinsics_ff() and q65_dec(). --- lib/qra/q65/q65_loops.f90 | 3 ++- lib/qra/q65/q65_subs.c | 30 ++++++++++++++++++++---------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index b2498e982..15e640ffd 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -68,9 +68,10 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ! if(b90.lt.0.15*width) exit ncall=ncall+1 call timer('qra64_de',0) + call q65_intrinsics_ff(s3,nsubmode,b90,nFadingModel,s3prob) APmask=0 APsymbols=0 - call q65_dec(s3,APmask,APsymbols,nsubmode,b90,nFadingModel,s3prob,snr2,dat4,irc) + call q65_dec(s3,s3prob,APmask,APsymbols,snr2,dat4,irc) ! irc > 0 ==> number of iterations required to decode ! -1 = invalid params ! -2 = decode failed diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c index f589f7faa..ffd4c0385 100644 --- a/lib/qra/q65/q65_subs.c +++ b/lib/qra/q65/q65_subs.c @@ -46,26 +46,18 @@ void q65_enc_(int x[], int y[]) q65_encode(&codec,y,x); } -void q65_dec_(float s3[], int APmask[], int APsymbols[], int* submode, - float* B90, int* fadingModel, float s3prob[], - float* snr2500, int xdec[], int* rc0) +void q65_intrinsics_ff_(float s3[], int* submode, float* B90, + int* fadingModel, float s3prob[]) { /* Input: s3[LL,NN] Received energies - * APmask[13] AP information to be used in decoding - * APsymbols[13] Available AP informtion * submode 0=A, 4=E * B90 Spread bandwidth, 90% fractional energy * fadingModel 0=Gaussian, 1=Lorentzian * Output: s3prob[LL,NN] Symbol-value intrinsic probabilities - * snr2500 SNR_2500 of decoded signal, or lower limit - * xdec[13] Decoded 78-bit message as 13 six-bit integers - * rc0 Return code from q65_decode() */ int rc; - int ydec[63]; - float esnodb; static int first=1; if (first) { @@ -82,6 +74,24 @@ void q65_dec_(float s3[], int APmask[], int APsymbols[], int* submode, printf("error in q65_intrinsics()\n"); exit(0); } +} + +void q65_dec_(float s3[], float s3prob[], int APmask[], int APsymbols[], + float* snr2500, int xdec[], int* rc0) +{ + +/* Input: s3prob[LL,NN] Symbol-value intrinsic probabilities + * APmask[13] AP information to be used in decoding + * APsymbols[13] Available AP informtion + * Output: + * snr2500 SNR_2500 of decoded signal, or lower limit + * xdec[13] Decoded 78-bit message as 13 six-bit integers + * rc0 Return code from q65_decode() + */ + + int rc; + int ydec[63]; + float esnodb; rc = q65_decode(&codec,ydec,xdec,s3prob,APmask,APsymbols); *rc0=rc; From b6071d29da18a54ef5c2149c074a627ec5eaa0d2 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 28 Oct 2020 12:04:10 -0400 Subject: [PATCH 120/206] Code cleanup. --- lib/qra/q65/q65_loops.f90 | 47 +++++++-------------------------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 15e640ffd..0bb0b27d4 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -77,34 +77,17 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ! -2 = decode failed ! -3 = CRC mismatch call timer('qra64_de',1) - if(irc.ge.0) go to 200 - iirc=max(0,min(irc,11)) - if(irc.gt.0 .and. nap(iirc).lt.napmin) then - dat4x=dat4 - b90x=b90 - snr2x=snr2 - napmin=nap(iirc) - irckeep=irc - xdtkeep=jpk/6000.0 - 1.0 - f0keep=-a(1) - idfkeep=idf - idtkeep=idt - ibwkeep=ibw - ndistx=ndist - go to 100 !### - endif + if(irc.ge.0) go to 100 enddo ! ibw (b90 loop) - !### if(iand(ndepth,3).lt.3 .and. irc.ge.0) go to 100 enddo ! idt (DT loop) enddo ! idf (f0 loop) -! if(iavg.eq.0 .and. abs(jpk0-4320).le.1300) then if(iavg.eq.0) then a=0. a(1)=-f0 call twkfreq(c00,c0,npts2,6000.0,a) - jpk=3000 !### These definitions need work ### -! if(nsps.ge.3600) jpk=4080 !### - if(nsps.ge.3600) jpk=6000 !### + jpk=3000 !### These definitions need work ### +! if(nsps.ge.3600) jpk=4080 !### + if(nsps.ge.3600) jpk=6000 !### call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) call pctile(s3,LL*NN,40,base) s3=s3/base @@ -113,32 +96,18 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & nsave=nsave+1 endif if(iavg.eq.0 .and. nsave.lt.2) exit - enddo ! iavg - -100 if(napmin.ne.99) then - dat4=dat4x - b90=b90x - snr2=snr2x - irc=irckeep - xdt=xdtkeep - f0=f0keep - idt=idtkeep - idf=idfkeep - ibw=ibwkeep - ndist=ndistx - endif + enddo ! iavg -200 if(mode.eq.65 .and. nsps.eq.7200/2) xdt=xdt+0.4 !### Empirical -- WHY ??? ### +100 if(mode.eq.65 .and. nsps.eq.7200/2) xdt=xdt+0.4 !### Empirical -- WHY ??? ### if(irc.ge.0) then navg=nsave if(iavg.eq.0) navg=0 !### For tests only: open(53,file='fort.53',status='unknown',position='append') - write(c77,1200) dat4 -1200 format(12b6.6,b5.5) + write(c77,1100) dat4 +1100 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent -! call unpackmsg(dat4,decoded) !Unpack the user message write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,ndist,irc,navg,decoded(1:22) 3053 format(3i5,f7.1,f7.2,2f7.1,3i4,2x,a22) close(53) From 20b6d65c61f7d79486048526127df35aa0fa7ede Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 28 Oct 2020 12:04:43 -0400 Subject: [PATCH 121/206] Allow WSJT-X to generate the new Q65 code. Loopback Q65 QSOs now work. --- widgets/mainwindow.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index dbb950df7..a771d8a7b 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -132,6 +132,9 @@ extern "C" { void genqra64_(char* msg, int* ichk, char* msgsent, int itone[], int* itext, fortran_charlen_t, fortran_charlen_t); + void genq65_(char* msg, int* ichk, char* msgsent, int itone[], + int* i3, int* n3, fortran_charlen_t, fortran_charlen_t); + void genwspr_(char* msg, char* msgsent, int itone[], fortran_charlen_t, fortran_charlen_t); void geniscat_(char* msg, char* msgsent, int itone[], fortran_charlen_t, fortran_charlen_t); @@ -3986,9 +3989,9 @@ void MainWindow::guiUpdate() if(m_modeTx=="QRA64") genqra64_(message, &ichk, msgsent, const_cast (itone), &m_currentMessageType, 22, 22); if(m_modeTx=="Q65") { - int ichk65=65; - genqra64_(message, &ichk65, msgsent, const_cast (itone), - &m_currentMessageType, 22, 22); + int i3=-1; + int n3=-1; + genq65_(message,&ichk,msgsent,const_cast(itone),&i3,&n3,37,37); } if(m_modeTx=="WSPR") genwspr_(message, msgsent, const_cast (itone), 22, 22); From 7786101dcf2c86c89e051baaf84e9bbcdc41a0d8 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 28 Oct 2020 13:38:06 -0400 Subject: [PATCH 122/206] Add a missing file. --- lib/qra/q65/genq65.f90 | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 lib/qra/q65/genq65.f90 diff --git a/lib/qra/q65/genq65.f90 b/lib/qra/q65/genq65.f90 new file mode 100644 index 000000000..21c96bfaf --- /dev/null +++ b/lib/qra/q65/genq65.f90 @@ -0,0 +1,48 @@ +subroutine genq65(msg0,ichk,msgsent,itone,i3,n3) + +! Encodes a Q65 message to yield itone(1:85) + + use packjt77 + character*37 msg0 !Message to be generated + character*37 msgsent !Message as it will be received + character*77 c77 + logical unpk77_success + integer itone(85) !QRA64 uses only 84 + integer dgen(13) + integer sent(63) + integer isync(22) + data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ + save + + if(msg0(1:1).eq.'@') then + read(msg0(2:5),*,end=1,err=1) nfreq + go to 2 +1 nfreq=1000 +2 itone(1)=nfreq + write(msgsent,1000) nfreq +1000 format(i5,' Hz') + goto 999 + endif + i3=-1 + n3=-1 + call pack77(msg0,i3,n3,c77) + call unpack77(c77,0,msgsent,unpk77_success) !Unpack to get msgsent + read(c77,1001) dgen +1001 format(12b6.6,b5.5) + if(ichk.eq.1) go to 999 !Return if checking only + call q65_enc(dgen,sent) !Encode message, dgen(1:13) ==> sent(1:63) + + j=1 + k=0 + do i=1,85 + if(i.eq.isync(j)) then + j=j+1 !Index for next sync symbol + itone(i)=0 !Insert sync symbol at tone 0 + else + k=k+1 + itone(i)=sent(k) + 1 !Q65 symbol=0 is transmitted at tone 1, etc. + endif + enddo + +999 return +end subroutine genq65 From e2978abcf5d74a9332c24c79f4e41cc6586501f0 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 29 Oct 2020 10:33:54 -0400 Subject: [PATCH 123/206] Pass ncontest and lapcqonly to the Q65 decoder. --- lib/decoder.f90 | 2 +- lib/q65_decode.f90 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 911352277..4c3b58c84 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -203,7 +203,7 @@ subroutine multimode_decoder(ss,id2,params,nfsample) call timer('dec_q65 ',0) call my_q65%decode(q65_decoded,id2,params%nutc,params%ntr, & params%nsubmode,params%nfqso,params%ntol,params%ndepth, & - mycall,hiscall,hisgrid) + mycall,hiscall,hisgrid,ncontest,logical(params%lapcqonly)) call timer('dec_q65 ',1) go to 800 endif diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index ec96ad4ec..bcd280b71 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -29,7 +29,7 @@ module q65_decode contains subroutine decode(this,callback,iwave,nutc,ntrperiod,nsubmode,nfqso, & - ntol,ndepth,mycall,hiscall,hisgrid) + ntol,ndepth,mycall,hiscall,hisgrid,ncontest,lapcqonly) ! Decodes Q65 signals ! Input: iwave Raw data, i*2 @@ -54,7 +54,7 @@ contains integer*2 iwave(NMAX) !Raw data real, allocatable :: dd(:) !Raw data integer dat4(13) !Decoded message as 12 6-bit integers - logical unpk77_success + logical lapcqonly,unpk77_success complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/,nsubmodez/-1/ From 1c30b9722857157e6a9bb24f9f82f12bedc91861 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 29 Oct 2020 10:53:30 -0400 Subject: [PATCH 124/206] More adjustments for adding AP decoding to Q65. --- lib/decoder.f90 | 5 +++-- lib/q65_decode.f90 | 5 ++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 4c3b58c84..49dca917b 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -202,8 +202,9 @@ subroutine multimode_decoder(ss,id2,params,nfsample) ! We're in Q65 mode call timer('dec_q65 ',0) call my_q65%decode(q65_decoded,id2,params%nutc,params%ntr, & - params%nsubmode,params%nfqso,params%ntol,params%ndepth, & - mycall,hiscall,hisgrid,ncontest,logical(params%lapcqonly)) + params%nsubmode,params%nfqso,params%ntol,params%ndepth, & + mycall,hiscall,hisgrid,params%nQSOProgress,ncontest, & + logical(params%lapcqonly)) call timer('dec_q65 ',1) go to 800 endif diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index bcd280b71..1a973dd7c 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -29,7 +29,7 @@ module q65_decode contains subroutine decode(this,callback,iwave,nutc,ntrperiod,nsubmode,nfqso, & - ntol,ndepth,mycall,hiscall,hisgrid,ncontest,lapcqonly) + ntol,ndepth,mycall,hiscall,hisgrid,nQSOprogress,ncontest,lapcqonly) ! Decodes Q65 signals ! Input: iwave Raw data, i*2 @@ -83,9 +83,8 @@ contains npts=ntrperiod*12000 baud=12000.0/nsps df1=12000.0/nfft1 - this%callback => callback + this%callback => callback if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning - b90=20.0 !8 to 25 is OK; not very critical nFadingModel=1 ! AP control could be done differently, but this works well: From f974751e42482f6a5d0deecb27bb6c31273e5636 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 30 Oct 2020 11:07:44 -0400 Subject: [PATCH 125/206] Q65 AP decoding is now (sort of?) working. Problem with i3 field, and maybe other problems... --- CMakeLists.txt | 1 + lib/q65_decode.f90 | 73 +++++++++++++---- lib/qra/q65/q65_ap.f90 | 164 ++++++++++++++++++++++++++++++++++++++ lib/qra/q65/q65_loops.f90 | 11 +-- 4 files changed, 227 insertions(+), 22 deletions(-) create mode 100644 lib/qra/q65/q65_ap.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index c001db3f4..4235643cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -497,6 +497,7 @@ set (wsjt_FSRCS lib/ps4.f90 lib/qra64a.f90 lib/qra_loops.f90 + lib/qra/q65/q65_ap.f90 lib/qra/q65/q65_loops.f90 lib/refspectrum.f90 lib/savec2.f90 diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 1a973dd7c..583d50ebd 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -51,9 +51,13 @@ contains character(len=6) :: hisgrid character*37 decoded !Decoded message character*77 c77 + character*78 c78 integer*2 iwave(NMAX) !Raw data real, allocatable :: dd(:) !Raw data integer dat4(13) !Decoded message as 12 6-bit integers + integer apsym0(58),aph10(10) + integer apmask1(78),apsymbols1(78) + integer apmask(13),apsymbols(13) logical lapcqonly,unpk77_success complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s @@ -101,40 +105,75 @@ contains call timer('sync_q65',1) irc=-1 - if(snr1.ge.2.5) then - jpk0=(xdt+1.0)*6000 !### - if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### - if(jpk0.lt.0) jpk0=0 - fac=1.0/32767.0 - dd=fac*iwave - nmode=65 - call ana64(dd,npts,c00) + if(snr1.lt.2.5) go to 100 + jpk0=(xdt+1.0)*6000 !### + if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### + if(jpk0.lt.0) jpk0=0 + fac=1.0/32767.0 + dd=fac*iwave + nmode=65 + call ana64(dd,npts,c00) + + call ft8apset(mycall,hiscall,ncontest,apsym0,aph10) + where(apsym0.eq.-1) apsym0=0 + + npasses=2 + if(nQSOprogress.eq.3 .or.nQSOprogress.eq.4) npasses=4 + if(nQSOprogress.eq.5) npasses=3 + if(lapcqonly) npasses=1 + do ipass=0,npasses +! print*,'A',nQSOprogress,ipass,npasses + apmask=0 + apsymbols=0 + if(ipass.ge.1) then + call q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,apsym0,apmask1, & + apsymbols1) + write(c78,1050) apmask1 +1050 format(78i1) + c78(75:78)=' ' + read(c78,1060) apmask +1060 format(13b6.6) + write(c78,1050) apsymbols1 + read(c78,1060) apsymbols + +! write(72,3060) 'A',ipass,apmask,apmask +!3060 format(a1,i1,1x,13b6.6/3x,13i6) +! write(72,3060) 'B',ipass,apsymbols,apsymbols + endif + call timer('q65loops',0) call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & - ndepth,jpk0,xdt,f0,width,snr2,irc,dat4) + ndepth,jpk0,xdt,f0,width,ipass,apmask,apsymbols,snr2,irc,dat4) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) - endif - decoded=' ' + if(irc.ge.0) exit + enddo + +100 decoded=' ' if(irc.ge.0) then - irc=(irc/100) * 100 !### TEMPORARY ??? ### +!### +! irc=(irc/100) * 100 !### TEMPORARY ??? ### + navg=irc/100 + irc=ipass +!### write(c77,1000) dat4 1000 format(12b6.6,b5.5) + +! write(72,3080) 'C',ipass,c77,'0' +!3080 format(a1,i1,1x,a77,a1) +! write(72,3060) 'C',ipass,dat4,dat4 + call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent nsnr=nint(snr2) call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) else + ! Report sync, even if no decode. nsnr=db(snr1) - 35.0 -!### TEMPORARY? ### call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) -!### endif -! write(61,3061) nutc,irc,xdt,f0,snr1,snr2,trim(decoded) -!3061 format(i6.6,i4,4f10.2,2x,a) - return end subroutine decode diff --git a/lib/qra/q65/q65_ap.f90 b/lib/qra/q65/q65_ap.f90 new file mode 100644 index 000000000..1c9fe1517 --- /dev/null +++ b/lib/qra/q65/q65_ap.f90 @@ -0,0 +1,164 @@ +subroutine q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,apsym0,apmask,apsymbols) + + integer apsym0(58),aph10(10) + integer apmask(78),apsymbols(78) + integer naptypes(0:5,4) ! (nQSOProgress, ipass) maximum of 4 passes for now + integer mcqru(29),mcqfd(29),mcqtest(29),mcqww(29) + integer mcq(29),mrrr(19),m73(19),mrr73(19) + logical lapcqonly,first + data mcq/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0/ + data mcqru/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,0,0,1,1,0,0/ + data mcqfd/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0,1,0/ + data mcqtest/0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,0,1,0,1,1,1,1,1,1,0,0,1,0/ + data mcqww/0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,1,1,0,1,1,1,1,0/ + data mrrr/0,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,1/ + data m73/0,1,1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,0,1/ + data mrr73/0,1,1,1,1,1,1,0,0,1,1,1,0,1,0,1,0,0,1/ + data ncontest0/99/ + data first/.true./ + save naptypes,ncontest0 + +! nQSOprogress +! 0 CALLING +! 1 REPLYING +! 2 REPORT +! 3 ROGER_REPORT +! 4 ROGERS +! 5 SIGNOFF + + if(first.or.(ncontest.ne.ncontest0)) then +! iaptype +!------------------------ +! 1 CQ ??? ??? (29+4=33 ap bits) +! 2 MyCall ??? ??? (29+4=33 ap bits) +! 3 MyCall DxCall ??? (58+4=62 ap bits) +! 4 MyCall DxCall RRR (78 ap bits) +! 5 MyCall DxCall 73 (78 ap bits) +! 6 MyCall DxCall RR73 (78 ap bits) + + naptypes(0,1:4)=(/1,2,0,0/) ! Tx6 selected (CQ) + naptypes(1,1:4)=(/2,3,0,0/) ! Tx1 + naptypes(2,1:4)=(/2,3,0,0/) ! Tx2 + naptypes(3,1:4)=(/3,4,5,6/) ! Tx3 + naptypes(4,1:4)=(/3,4,5,6/) ! Tx4 + naptypes(5,1:4)=(/3,1,2,0/) ! Tx5 + first=.false. + ncontest0=ncontest + endif + + apsymbols=0 + iaptype=naptypes(nQSOProgress,ipass) + if(lapcqonly) iaptype=1 + +! ncontest=0 : NONE +! 1 : NA_VHF +! 2 : EU_VHF +! 3 : FIELD DAY +! 4 : RTTY +! 5 : WW_DIGI +! 6 : FOX +! 7 : HOUND + +! Conditions that cause us to bail out of AP decoding +! if(ncontest.le.5 .and. iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) goto 900 +! if(ncontest.eq.6) goto 900 !No AP for Foxes +! if(ncontest.eq.7.and.f1.gt.950.0) goto 900 !Hounds use AP only below 950 Hz + if(ncontest.ge.6) goto 900 + if(iaptype.ge.2 .and. apsym0(1).gt.1) goto 900 !No, or nonstandard, mycall + if(ncontest.eq.7 .and. iaptype.ge.2 .and. aph10(1).gt.1) goto 900 + if(iaptype.ge.3 .and. apsym0(30).gt.1) goto 900 !No, or nonstandard, dxcall + + if(iaptype.eq.1) then ! CQ or CQ RU or CQ TEST or CQ FD + apmask=0 + apmask(1:29)=1 + if(ncontest.eq.0) apsymbols(1:29)=mcq + if(ncontest.eq.1) apsymbols(1:29)=mcqtest + if(ncontest.eq.2) apsymbols(1:29)=mcqtest + if(ncontest.eq.3) apsymbols(1:29)=mcqfd + if(ncontest.eq.4) apsymbols(1:29)=mcqru + if(ncontest.eq.5) apsymbols(1:29)=mcqww + if(ncontest.eq.7) apsymbols(1:29)=mcq + apmask(75:78)=1 + apsymbols(75:78)=(/0,0,1,0/) + endif + + if(iaptype.eq.2) then ! MyCall,???,??? + apmask=0 + if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.5) then + apmask(1:29)=1 + apsymbols(1:29)=apsym0(1:29) + apmask(75:78)=1 + apsymbols(75:78)=(/0,0,1,0/) + else if(ncontest.eq.2) then + apmask(1:28)=1 + apsymbols(1:28)=apsym0(1:28) + apmask(72:74)=1 + apsymbols(72)=0 + apsymbols(73)=(+1) + apsymbols(74)=0 + apmask(75:78)=1 + apsymbols(75:78)=0 + else if(ncontest.eq.3) then + apmask(1:28)=1 + apsymbols(1:28)=apsym0(1:28) + apmask(75:78)=1 + apsymbols(75:78)=0 + else if(ncontest.eq.4) then + apmask(2:29)=1 + apsymbols(2:29)=apsym0(1:28) + apmask(75:78)=1 + apsymbols(75:78)=(/0,0,1,0/) + else if(ncontest.eq.7) then ! ??? RR73; MyCall ??? + apmask(29:56)=1 + apsymbols(29:56)=apsym0(1:28) + apmask(57:66)=1 + apsymbols(57:66)=aph10(1:10) + apmask(72:78)=1 + apsymbols(72:74)=(/0,0,1/) + apsymbols(75:78)=0 + endif + endif + + if(iaptype.eq.3) then ! MyCall,DxCall,??? + apmask=0 + if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.2.or.ncontest.eq.5.or.ncontest.eq.7) then + apmask(1:58)=1 + apsymbols(1:58)=apsym0 + apmask(75:78)=1 + apsymbols(75:78)=(/0,0,1,0/) + else if(ncontest.eq.3) then ! Field Day + apmask(1:56)=1 + apsymbols(1:28)=apsym0(1:28) + apsymbols(29:56)=apsym0(30:57) + apmask(72:78)=1 + apsymbols(75:78)=0 + else if(ncontest.eq.4) then + apmask(2:57)=1 + apsymbols(2:29)=apsym0(1:28) + apsymbols(30:57)=apsym0(30:57) + apmask(75:78)=1 + apsymbols(75:78)=(/0,0,1,0/) + endif + endif + + if(iaptype.eq.5.and.ncontest.eq.7) goto 900 !Hound + if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then + apmask=0 + if(ncontest.le.5 .or. (ncontest.eq.7.and.iaptype.eq.6)) then + apmask(1:78)=1 ! mycall, hiscall, RRR|73|RR73 + apsymbols(1:58)=apsym0 + if(iaptype.eq.4) apsymbols(59:77)=mrrr + if(iaptype.eq.5) apsymbols(59:77)=m73 + if(iaptype.eq.6) apsymbols(59:77)=mrr73 + else if(ncontest.eq.7.and.iaptype.eq.4) then ! Hound listens for MyCall RR73;... + apmask(1:28)=1 + apsymbols(1:28)=apsym0(1:28) + apmask(57:66)=1 + apsymbols(57:66)=aph10(1:10) + apmask(72:78)=1 + apsymbols(72:78)=(/0,0,1,0,0,0,0/) + endif + endif + +900 return +end subroutine q65_ap diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 0bb0b27d4..b468b00ce 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,5 +1,5 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & - ndepth,jpk0,xdt,f0,width,snr2,irc,dat4) + ndepth,jpk0,xdt,f0,width,ipass,APmask,APsymbols,snr2,irc,dat4) use packjt77 use timer_module, only: timer @@ -69,8 +69,8 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ncall=ncall+1 call timer('qra64_de',0) call q65_intrinsics_ff(s3,nsubmode,b90,nFadingModel,s3prob) - APmask=0 - APsymbols=0 +! APmask=0 +! APsymbols=0 call q65_dec(s3,s3prob,APmask,APsymbols,snr2,dat4,irc) ! irc > 0 ==> number of iterations required to decode ! -1 = invalid params @@ -108,8 +108,9 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & write(c77,1100) dat4 1100 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent - write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,ndist,irc,navg,decoded(1:22) -3053 format(3i5,f7.1,f7.2,2f7.1,3i4,2x,a22) + write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,ndist,irc,ipass,navg, & + trim(decoded) +3053 format(3i5,f7.1,f7.2,2f7.1,4i4,2x,a) close(53) !### nsave=0 From 306c0c863354aa210e0d6b4997c1030a2503b509 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 30 Oct 2020 12:02:15 -0400 Subject: [PATCH 126/206] Limit the Q65 DT search rnge to +/- 1 s for TR=15, 30 s. --- lib/q65_decode.f90 | 1 - lib/qra/q65/q65_loops.f90 | 2 -- lib/sync_q65.f90 | 12 +++++++----- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 583d50ebd..029d399d9 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -140,7 +140,6 @@ contains !3060 format(a1,i1,1x,13b6.6/3x,13i6) ! write(72,3060) 'B',ipass,apsymbols,apsymbols endif - call timer('q65loops',0) call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & ndepth,jpk0,xdt,f0,width,ipass,apmask,apsymbols,snr2,irc,dat4) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index b468b00ce..8fef412d4 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -69,8 +69,6 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ncall=ncall+1 call timer('qra64_de',0) call q65_intrinsics_ff(s3,nsubmode,b90,nFadingModel,s3prob) -! APmask=0 -! APsymbols=0 call q65_dec(s3,s3prob,APmask,APsymbols,snr2,dat4,irc) ! irc > 0 ==> number of iterations required to decode ! -1 = invalid params diff --git a/lib/sync_q65.f90 b/lib/sync_q65.f90 index 8df6da47f..c52cca12f 100644 --- a/lib/sync_q65.f90 +++ b/lib/sync_q65.f90 @@ -74,13 +74,15 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) enddo dtstep=nsps/(NSTEP*12000.0) !Step size in seconds - j0=0.5/dtstep - if(nsps.ge.6192) j0=1.0/dtstep !Nominal index for start of signal - - ccf=0. ia=min(64,nint(ntol/df)) lag1=-1.0/dtstep - lag2=4.0/dtstep + 0.9999 + lag2=1.0/dtstep + 0.9999 + j0=0.5/dtstep + if(nsps.ge.6192) then + j0=1.0/dtstep !Nominal index for start of signal + lag2=4.0/dtstep + 0.9999 !Include EME delays + endif + ccf=0. do lag=lag1,lag2 do k=1,85 From b3f0aec4075fc0ff995b63256971b017fa255ced Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 30 Oct 2020 14:52:58 -0400 Subject: [PATCH 127/206] Q65: compute snr from esnodb, using actual symbol rate. --- lib/qra/q65/q65_loops.f90 | 7 ++++--- lib/qra/q65/q65_subs.c | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 8fef412d4..f476ce0fc 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -69,7 +69,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ncall=ncall+1 call timer('qra64_de',0) call q65_intrinsics_ff(s3,nsubmode,b90,nFadingModel,s3prob) - call q65_dec(s3,s3prob,APmask,APsymbols,snr2,dat4,irc) + call q65_dec(s3,s3prob,APmask,APsymbols,esnodb,dat4,irc) ! irc > 0 ==> number of iterations required to decode ! -1 = invalid params ! -2 = decode failed @@ -84,8 +84,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & a(1)=-f0 call twkfreq(c00,c0,npts2,6000.0,a) jpk=3000 !### These definitions need work ### -! if(nsps.ge.3600) jpk=4080 !### - if(nsps.ge.3600) jpk=6000 !### + if(nsps.ge.3600) jpk=6000 !### TR >= 60 s call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) call pctile(s3,LL*NN,40,base) s3=s3/base @@ -100,6 +99,8 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & if(irc.ge.0) then navg=nsave + baud=6000.0/nsps + snr2=esnodb - db(2500.0/baud) if(iavg.eq.0) navg=0 !### For tests only: open(53,file='fort.53',status='unknown',position='append') diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c index ffd4c0385..b36adc540 100644 --- a/lib/qra/q65/q65_subs.c +++ b/lib/qra/q65/q65_subs.c @@ -77,14 +77,14 @@ void q65_intrinsics_ff_(float s3[], int* submode, float* B90, } void q65_dec_(float s3[], float s3prob[], int APmask[], int APsymbols[], - float* snr2500, int xdec[], int* rc0) + float* esnodb0, int xdec[], int* rc0) { /* Input: s3prob[LL,NN] Symbol-value intrinsic probabilities * APmask[13] AP information to be used in decoding * APsymbols[13] Available AP informtion * Output: - * snr2500 SNR_2500 of decoded signal, or lower limit + * esnodb0 Estimated Es/No in dB * xdec[13] Decoded 78-bit message as 13 six-bit integers * rc0 Return code from q65_decode() */ @@ -98,7 +98,7 @@ void q65_dec_(float s3[], float s3prob[], int APmask[], int APsymbols[], // rc = -1: Invalid params // rc = -2: Decode failed // rc = -3: CRC mismatch - *snr2500 = -31.0; + *esnodb0 = 0.0; //Default Es/No for a failed decode if(rc<0) return; rc = q65_esnodb_fastfading(&codec,&esnodb,ydec,s3); @@ -106,5 +106,5 @@ void q65_dec_(float s3[], float s3prob[], int APmask[], int APsymbols[], printf("error in q65_esnodb_fastfading()\n"); exit(0); } - *snr2500 = esnodb - 31.0; + *esnodb0 = esnodb; } From abbb2777934a38d49bb912ddd71e58b788bdf2b0 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 31 Oct 2020 11:15:03 -0400 Subject: [PATCH 128/206] Fix the issue with using AP for the "i3" bit and 78th bit. --- lib/q65_decode.f90 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 029d399d9..664e63100 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -130,12 +130,11 @@ contains apsymbols1) write(c78,1050) apmask1 1050 format(78i1) - c78(75:78)=' ' read(c78,1060) apmask 1060 format(13b6.6) write(c78,1050) apsymbols1 read(c78,1060) apsymbols - + apsymbols(13)=apsymbols(13)/2 !Fixup for c77-->c78 ! write(72,3060) 'A',ipass,apmask,apmask !3060 format(a1,i1,1x,13b6.6/3x,13i6) ! write(72,3060) 'B',ipass,apsymbols,apsymbols From 1768971931698a5bf3a57f022cd914a3b2282e6c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 31 Oct 2020 11:33:01 -0400 Subject: [PATCH 129/206] Add timer calls for two of Nico's routines. --- lib/qra/q65/q65_loops.f90 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index f476ce0fc..41f468595 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -67,14 +67,17 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & if(b90.gt.230.0) cycle ! if(b90.lt.0.15*width) exit ncall=ncall+1 - call timer('qra64_de',0) + call timer('q65_intr',0) call q65_intrinsics_ff(s3,nsubmode,b90,nFadingModel,s3prob) + call timer('q65_intr',1) + + call timer('q65_dec ',0) call q65_dec(s3,s3prob,APmask,APsymbols,esnodb,dat4,irc) + call timer('q65_dec ',1) ! irc > 0 ==> number of iterations required to decode ! -1 = invalid params ! -2 = decode failed ! -3 = CRC mismatch - call timer('qra64_de',1) if(irc.ge.0) go to 100 enddo ! ibw (b90 loop) enddo ! idt (DT loop) From fa92799bdad103a524059ae5ad7d1b5a049f362d Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 2 Nov 2020 15:59:10 -0500 Subject: [PATCH 130/206] OPtimize the --- lib/q65_decode.f90 | 28 +++++----------------------- lib/qra/q65/q65_loops.f90 | 32 ++++++++++++++++---------------- lib/qra64a.f90 | 2 +- lib/sync_q65.f90 | 12 ++++++++++-- 4 files changed, 32 insertions(+), 42 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 664e63100..0e3b4f47a 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -61,8 +61,6 @@ contains logical lapcqonly,unpk77_success complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s - data nc1z/-1/,nc2z/-1/,ng2z/-1/,maxaptypez/-1/,nsubmodez/-1/ - save nc1z,nc2z,ng2z,maxaptypez,nsubmodez mode65=2**nsubmode nfft1=ntrperiod*12000 @@ -90,23 +88,16 @@ contains this%callback => callback if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning nFadingModel=1 - -! AP control could be done differently, but this works well: - maxaptype=0 -! if(ndepth.eq.2) maxaptype=3 -! if(ndepth.eq.3) maxaptype=5 - if(ndepth.ge.2) maxaptype=5 !### - minsync=-2 call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist) - naptype=maxaptype call timer('sync_q65',0) - call sync_q65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0,snr1) + call sync_q65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0, & + snr1,width) call timer('sync_q65',1) irc=-1 if(snr1.lt.2.5) go to 100 - jpk0=(xdt+1.0)*6000 !### + jpk0=(xdt+1.0)*6000 !### Is this OK? if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### if(jpk0.lt.0) jpk0=0 fac=1.0/32767.0 @@ -122,7 +113,6 @@ contains if(nQSOprogress.eq.5) npasses=3 if(lapcqonly) npasses=1 do ipass=0,npasses -! print*,'A',nQSOprogress,ipass,npasses apmask=0 apsymbols=0 if(ipass.ge.1) then @@ -135,9 +125,6 @@ contains write(c78,1050) apsymbols1 read(c78,1060) apsymbols apsymbols(13)=apsymbols(13)/2 !Fixup for c77-->c78 -! write(72,3060) 'A',ipass,apmask,apmask -!3060 format(a1,i1,1x,13b6.6/3x,13i6) -! write(72,3060) 'B',ipass,apsymbols,apsymbols endif call timer('q65loops',0) call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & @@ -149,24 +136,19 @@ contains 100 decoded=' ' if(irc.ge.0) then -!### -! irc=(irc/100) * 100 !### TEMPORARY ??? ### +!### navg=irc/100 irc=ipass !### write(c77,1000) dat4 1000 format(12b6.6,b5.5) -! write(72,3080) 'C',ipass,c77,'0' -!3080 format(a1,i1,1x,a77,a1) -! write(72,3060) 'C',ipass,dat4,dat4 - call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent nsnr=nint(snr2) call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) else - ! Report sync, even if no decode. +! Report sync, even if no decode. nsnr=db(snr1) - 35.0 call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & irc,qual,ntrperiod,fmid,w50) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 41f468595..d36ca395f 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -21,6 +21,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & data nap/0,2,3,2,3,4,2,3,6,4,6,6/,nsave/0/ save nsave,s3avg + ircbest=9999 allocate(c0(0:npts2-1)) irc=-99 s3lim=20. @@ -32,7 +33,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & LL=64*(mode64+2) NN=63 napmin=99 - ncall=0 + baud=6000.0/nsps do iavg=0,1 if(iavg.eq.1) then @@ -43,13 +44,13 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ndf=idf/2 if(mod(idf,2).eq.0) ndf=-ndf a=0. - a(1)=-(f0+0.4*ndf) + a(1)=-(f0+0.5*baud*ndf) call twkfreq(c00,c0,npts2,6000.0,a) do idt=1,idtmax ndt=idt/2 if(iavg.eq.0) then if(mod(idt,2).eq.0) ndt=-ndt - jpk=jpk0 + 240*ndt !240/6000 = 0.04 s = tsym/32 + jpk=jpk0 + nsps*ndt/16 !tsym/16 if(jpk.lt.0) jpk=0 call timer('spec64 ',0) call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) @@ -60,13 +61,14 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & else s3(1:LL*NN)=s3avg(1:LL*NN) endif - do ibw=ibwmax,ibwmin,-2 - ndist=ndf**2 + ndt**2 + ((ibwmax-ibw)/2)**2 + do ibw=ibwmin,ibwmax + nbw=ibw + ndist=ndf**2 + ndt**2 + ((nbw-2))**2 if(ndist.gt.maxdist) cycle - b90=1.728**ibw +! b90=1.728**ibw + b90=3.0**nbw if(b90.gt.230.0) cycle ! if(b90.lt.0.15*width) exit - ncall=ncall+1 call timer('q65_intr',0) call q65_intrinsics_ff(s3,nsubmode,b90,nFadingModel,s3prob) call timer('q65_intr',1) @@ -74,11 +76,11 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & call timer('q65_dec ',0) call q65_dec(s3,s3prob,APmask,APsymbols,esnodb,dat4,irc) call timer('q65_dec ',1) + if(irc.ge.0) go to 100 ! irc > 0 ==> number of iterations required to decode ! -1 = invalid params ! -2 = decode failed ! -3 = CRC mismatch - if(irc.ge.0) go to 100 enddo ! ibw (b90 loop) enddo ! idt (DT loop) enddo ! idf (f0 loop) @@ -86,7 +88,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & a=0. a(1)=-f0 call twkfreq(c00,c0,npts2,6000.0,a) - jpk=3000 !### These definitions need work ### + jpk=3000 !### Are these definitions OK? if(nsps.ge.3600) jpk=6000 !### TR >= 60 s call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) call pctile(s3,LL*NN,40,base) @@ -98,26 +100,24 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & if(iavg.eq.0 .and. nsave.lt.2) exit enddo ! iavg -100 if(mode.eq.65 .and. nsps.eq.7200/2) xdt=xdt+0.4 !### Empirical -- WHY ??? ### - - if(irc.ge.0) then +100 if(irc.ge.0) then navg=nsave - baud=6000.0/nsps snr2=esnodb - db(2500.0/baud) if(iavg.eq.0) navg=0 - !### For tests only: +!### For tests only: open(53,file='fort.53',status='unknown',position='append') write(c77,1100) dat4 1100 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent - write(53,3053) idf,idt,ibw,b90,xdt,f0,snr2,ndist,irc,ipass,navg, & + write(53,3053) ndf,ndt,nbw,b90,xdt,f0,snr2,ndist,irc,ipass,navg, & trim(decoded) 3053 format(3i5,f7.1,f7.2,2f7.1,4i4,2x,a) close(53) - !### +!### nsave=0 s3avg=0. irc=irc + 100*navg endif + return end subroutine q65_loops diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index c0d501fd7..fb56390e5 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -22,7 +22,7 @@ subroutine qra64a(dd,npts,nf1,nf2,nfqso,ntol,mode64,minsync,ndepth, & nft=99 if(nfqso.lt.nf1 .or. nfqso.gt.nf2) go to 900 - mycall=mycall_12(1:6) !### May need fixing ### + mycall=mycall_12(1:6) !### May need fixing? ### hiscall=hiscall_12(1:6) hisgrid=hisgrid_6(1:4) call packcall(mycall,nc1,ltext) diff --git a/lib/sync_q65.f90 b/lib/sync_q65.f90 index c52cca12f..2abe79184 100644 --- a/lib/sync_q65.f90 +++ b/lib/sync_q65.f90 @@ -1,4 +1,4 @@ -subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) +subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) ! Detect and align with the Q65 sync vector, returning time and frequency ! offsets and SNR estimate. @@ -118,9 +118,17 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1) ! enddo ! do i=-ia,ia -! write(56,3056) i*df,ccf(i,0)/rms +! write(56,3056) i*df,ccf(i,jpk)/rms !3056 format(2f10.3) ! enddo +! flush(56) + + acf0=dot_product(ccf(-ia:ia,jpk),ccf(-ia:ia,jpk)) + do i=1,ia + acf=dot_product(ccf(-ia:ia,jpk),ccf(-ia+i:ia+i,jpk)) + if(acf.le.0.5*acf0) exit + enddo + width=i*1.414*df return end subroutine sync_q65 From 1b541082fdd1238917b91571b1841b30f13d5683 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 2 Nov 2020 16:04:46 -0500 Subject: [PATCH 131/206] Optimize the Q65 inner loops. Also more code cleanup. --- lib/qra64a.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/qra64a.f90 b/lib/qra64a.f90 index fb56390e5..d4189827d 100644 --- a/lib/qra64a.f90 +++ b/lib/qra64a.f90 @@ -102,8 +102,8 @@ subroutine qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist) integer iparam(7) logical first,ex -! data iparam/3,5,3,11,0,9,30/ !Maximum effort - data iparam/2,5,3,11,3,9,10/ !Default values +! 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 From 2c51c97b14eedb4cc8e90b0200df9f8ed81817e4 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 3 Nov 2020 10:36:19 -0500 Subject: [PATCH 132/206] Increase the Q65 minimum snr1 from 2.5 to 2.8. --- lib/q65_decode.f90 | 4 ++-- lib/qra/q65/q65_loops.f90 | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 0e3b4f47a..ae878679e 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -96,7 +96,7 @@ contains call timer('sync_q65',1) irc=-1 - if(snr1.lt.2.5) go to 100 + if(snr1.lt.2.8) go to 100 jpk0=(xdt+1.0)*6000 !### Is this OK? if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### if(jpk0.lt.0) jpk0=0 @@ -128,7 +128,7 @@ contains endif call timer('q65loops',0) call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & - ndepth,jpk0,xdt,f0,width,ipass,apmask,apsymbols,snr2,irc,dat4) + ndepth,jpk0,xdt,f0,width,ipass,apmask,apsymbols,snr1,snr2,irc,dat4) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) if(irc.ge.0) exit diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index d36ca395f..01fc56054 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,5 +1,5 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & - ndepth,jpk0,xdt,f0,width,ipass,APmask,APsymbols,snr2,irc,dat4) + ndepth,jpk0,xdt,f0,width,ipass,APmask,APsymbols,snr1,snr2,irc,dat4) use packjt77 use timer_module, only: timer @@ -105,14 +105,13 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & snr2=esnodb - db(2500.0/baud) if(iavg.eq.0) navg=0 !### For tests only: - open(53,file='fort.53',status='unknown',position='append') + open(53,file='fort.53',status='unknown') write(c77,1100) dat4 1100 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent write(53,3053) ndf,ndt,nbw,b90,xdt,f0,snr2,ndist,irc,ipass,navg, & - trim(decoded) -3053 format(3i5,f7.1,f7.2,2f7.1,4i4,2x,a) - close(53) + snr1,trim(decoded) +3053 format(3i4,f6.1,f6.2,f7.1,f6.1,4i4,f7.2,1x,a) !### nsave=0 s3avg=0. From a01ebab363467ca9a562d42cbc19166a77c933dd Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 3 Nov 2020 11:31:21 -0500 Subject: [PATCH 133/206] Improve sync_q65() for larger values of FTol. --- lib/sync_q65.f90 | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/lib/sync_q65.f90 b/lib/sync_q65.f90 index 2abe79184..68cb5d919 100644 --- a/lib/sync_q65.f90 +++ b/lib/sync_q65.f90 @@ -15,10 +15,10 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) parameter (NSTEP=8) !Step size nsps/NSTEP integer*2 iwave(0:nmax-1) !Raw data integer isync(22) !Indices of sync symbols - integer ijpk(2) !Indices i and j at peak of ccf real, allocatable :: s1(:,:) !Symbol spectra, quarter-symbol steps + real, allocatable :: ccf(:,:) !CCF(freq,lag) + real, allocatable :: ccf1(:) !CCF(freq) at best lag real sync(85) !sync vector - real ccf(-64:64,-53:214) !CCF(freq,time) complex, allocatable :: c0(:) !Complex spectrum of symbol data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data sync(1)/99.0/ @@ -31,9 +31,12 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) txt=85.0*nsps/12000.0 jz=(txt+1.0)*12000.0/istep !Number of quarter-symbol steps if(nsps.ge.6912) jz=(txt+2.0)*12000.0/istep !For TR 60 s and higher + ia=ntol/df allocate(s1(iz,jz)) allocate(c0(0:nfft-1)) + allocate(ccf(-ia:ia,-53:214)) + allocate(ccf1(-ia:ia)) if(sync(1).eq.99.0) then !Generate the sync vector sync=-22.0/63.0 !Sync tone OFF @@ -74,7 +77,7 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) enddo dtstep=nsps/(NSTEP*12000.0) !Step size in seconds - ia=min(64,nint(ntol/df)) + ia=ntol/df lag1=-1.0/dtstep lag2=1.0/dtstep + 0.9999 j0=0.5/dtstep @@ -94,9 +97,19 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) enddo enddo - ijpk=maxloc(ccf) - ipk=ijpk(1)-65 - jpk=ijpk(2)-54 + ic=ntol/df + ccfmax=0. + ipk=0 + jpk=0 + do i=-ic,ic + do j=lag1,lag2 + if(ccf(i,j).gt.ccfmax) then + ipk=i + jpk=j + ccfmax=ccf(i,j) + endif + enddo + enddo f0=nfqso + ipk*df xdt=jpk*dtstep @@ -123,9 +136,10 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) ! enddo ! flush(56) - acf0=dot_product(ccf(-ia:ia,jpk),ccf(-ia:ia,jpk)) + ccf1=ccf(-ia:ia,jpk) + acf0=dot_product(ccf1,ccf1) do i=1,ia - acf=dot_product(ccf(-ia:ia,jpk),ccf(-ia+i:ia+i,jpk)) + acf=dot_product(ccf1,cshift(ccf1,i)) if(acf.le.0.5*acf0) exit enddo width=i*1.414*df From 6d8958bce6f2f80485a64452eb4ac0b0e07a7d3b Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 3 Nov 2020 15:49:11 -0500 Subject: [PATCH 134/206] Code cleanup. --- lib/qra/q65/q65_loops.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 01fc56054..eacd99549 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -12,11 +12,10 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & real s3(LN) !Symbol spectra real s3avg(LN) !Averaged symbol spectra real s3prob(LN) !Symbol-value probabilities - real s3tmp(4032) logical unpk77_success integer APmask(13) integer APsymbols(13) - integer dat4(13),dat4x(13) !Decoded message (as 13 six-bit integers) + integer dat4(13) !Decoded message (as 13 six-bit integers) integer nap(0:11) !AP return codes data nap/0,2,3,2,3,4,2,3,6,4,6,6/,nsave/0/ save nsave,s3avg @@ -105,13 +104,14 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & snr2=esnodb - db(2500.0/baud) if(iavg.eq.0) navg=0 !### For tests only: - open(53,file='fort.53',status='unknown') + open(53,file='fort.53',status='unknown',position='append') write(c77,1100) dat4 1100 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent write(53,3053) ndf,ndt,nbw,b90,xdt,f0,snr2,ndist,irc,ipass,navg, & snr1,trim(decoded) 3053 format(3i4,f6.1,f6.2,f7.1,f6.1,4i4,f7.2,1x,a) + close(53) !### nsave=0 s3avg=0. From 860b0ce21e4529b34a4d994c417fa06de697ce97 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 3 Nov 2020 15:49:24 -0500 Subject: [PATCH 135/206] Include TRperiod in the Q65 status bar label. --- widgets/mainwindow.cpp | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index a771d8a7b..7476ab9e3 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -2360,14 +2360,13 @@ void MainWindow::createStatusBar() //createStatusBar void MainWindow::setup_status_bar (bool vhf) { auto submode = current_submode (); - if (vhf && submode != QChar::Null) - { - mode_label.setText (m_mode + " " + submode); - } - else - { - mode_label.setText (m_mode); - } + if (vhf && submode != QChar::Null) { + QString t{m_mode + " " + submode}; + if(m_mode=="Q65") t=m_mode + "-" + QString::number(m_TRperiod) + submode; + mode_label.setText (t); + } else { + mode_label.setText (m_mode); + } if ("ISCAT" == m_mode) { mode_label.setStyleSheet ("QLabel{color: #000000; background-color: #ff9933}"); } else if ("JT9" == m_mode) { @@ -7620,6 +7619,7 @@ void MainWindow::on_sbTR_valueChanged(int value) if(m_transmitting) { on_stopTxButton_clicked(); } + on_sbSubmode_valueChanged(ui->sbSubmode->value()); statusUpdate (); } @@ -7644,14 +7644,13 @@ void MainWindow::on_sbSubmode_valueChanged(int n) m_nSubMode=n; m_wideGraph->setSubMode(m_nSubMode); auto submode = current_submode (); - if (submode != QChar::Null) - { - mode_label.setText (m_mode + " " + submode); - } - else - { - mode_label.setText (m_mode); - } + if (submode != QChar::Null) { + QString t{m_mode + " " + submode}; + if(m_mode=="Q65") t=m_mode + "-" + QString::number(m_TRperiod) + submode; + mode_label.setText (t); + } else { + mode_label.setText (m_mode); + } if(m_mode=="ISCAT") { if(m_nSubMode==0) ui->TxFreqSpinBox->setValue(1012); if(m_nSubMode==1) ui->TxFreqSpinBox->setValue(560); From 145ddb88210b66523ff49b207fabdb7e4788eb21 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 3 Nov 2020 17:17:21 -0500 Subject: [PATCH 136/206] Correct the false-decode test in test_q65. --- lib/test_q65.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index ead15b013..1191069a6 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -109,7 +109,7 @@ program test_q65 if(index(line,' Date: Tue, 10 Nov 2020 10:14:41 -0500 Subject: [PATCH 137/206] Reactivate Q65 message averaging, and fix the reporting of those decodes. --- lib/q65_decode.f90 | 3 +-- lib/qra/q65/q65_loops.f90 | 7 ++++--- lib/sumsim.f90 | 5 +++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index ae878679e..94ca0fff4 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -138,11 +138,10 @@ contains if(irc.ge.0) then !### navg=irc/100 - irc=ipass + irc=100*navg + ipass !### write(c77,1000) dat4 1000 format(12b6.6,b5.5) - call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent nsnr=nint(snr2) call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index eacd99549..0460fb621 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -47,7 +47,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & call twkfreq(c00,c0,npts2,6000.0,a) do idt=1,idtmax ndt=idt/2 - if(iavg.eq.0) then + if(ipass.eq.0 .and. iavg.eq.0) then if(mod(idt,2).eq.0) ndt=-ndt jpk=jpk0 + nsps*ndt/16 !tsym/16 if(jpk.lt.0) jpk=0 @@ -57,7 +57,8 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & call pctile(s3,LL*NN,40,base) s3=s3/base where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim - else + endif + if(iavg.eq.1) then s3(1:LL*NN)=s3avg(1:LL*NN) endif do ibw=ibwmin,ibwmax @@ -83,7 +84,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & enddo ! ibw (b90 loop) enddo ! idt (DT loop) enddo ! idf (f0 loop) - if(iavg.eq.0) then + if(ipass.eq.0 .and. iavg.eq.0) then a=0. a(1)=-f0 call twkfreq(c00,c0,npts2,6000.0,a) diff --git a/lib/sumsim.f90 b/lib/sumsim.f90 index e05f8d4d0..dba801470 100644 --- a/lib/sumsim.f90 +++ b/lib/sumsim.f90 @@ -24,14 +24,15 @@ program sumsim nfsample=h%nsamrate read(10) iwave(1:npts) n=len(trim(fname)) - wave(1:npts)=wave(1:npts)+iwave(1:npts) + wave(1:npts)=wave(1:npts) + iwave(1:npts) rms=sqrt(dot_product(wave(1:npts),wave(1:npts))/npts) write(*,1000) ifile,npts,float(npts)/nfsample,rms,fname(n-14:n) 1000 format(i3,i8,f6.1,f10.3,2x,a15) close(10) enddo - fac=1.0/sqrt(float(nargs)) +! fac=1.0/sqrt(float(nargs)) + fac=1.0/nargs iwave(1:npts)=nint(fac*wave(1:npts)) open(12,file='000000_0000.wav',access='stream',status='unknown') From 3068f0c61fc93765a272125737d6dc3428c5190a Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 11 Nov 2020 11:14:02 -0500 Subject: [PATCH 138/206] Use genwave() to create Q65 audio signal. Send "include averaging" flag to Q65 decoder. --- CMakeLists.txt | 1 + displayWidgets.txt | 2 +- lib/genwave.f90 | 52 +++++++++++++++++++++++++++++++++++++++ lib/q65_decode.f90 | 2 +- lib/qra/q65/q65_loops.f90 | 6 +++-- widgets/mainwindow.cpp | 30 ++++++++++++++++------ 6 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 lib/genwave.f90 diff --git a/CMakeLists.txt b/CMakeLists.txt index 4235643cd..d4f630f47 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -423,6 +423,7 @@ set (wsjt_FSRCS lib/gen65.f90 lib/gen9.f90 lib/geniscat.f90 + lib/genwave.f90 lib/ft8/genft8.f90 lib/qra/q65/genq65.f90 lib/genmsk_128_90.f90 diff --git a/displayWidgets.txt b/displayWidgets.txt index e23cc5e5d..2f176ae00 100644 --- a/displayWidgets.txt +++ b/displayWidgets.txt @@ -11,7 +11,7 @@ JT9+JT65 111010000001111000010000000000001000 JT65 111010000000111000010000000000001000 JT65/VHF 111110010000110110101100010000000000 QRA64 111110010110110110000000001000000000 -QRA65 111111010110110100010000001100000000 +Q65 111111010110110100011000001100000000 ISCAT 100111000000000110000000000000000000 MSK144 101111110100000000010001000000000000 WSPR 000000000000000001010000000000000000 diff --git a/lib/genwave.f90 b/lib/genwave.f90 new file mode 100644 index 000000000..7db4cc7de --- /dev/null +++ b/lib/genwave.f90 @@ -0,0 +1,52 @@ +subroutine genwave(itone,nsym,nsps,nwave,fsample,hmod,f0,icmplx,cwave,wave) + + real wave(nwave) + complex cwave(nwave) + integer hmod + integer itone(nsym) + logical ex + real*8 dt,phi,dphi,twopi,freq,baud + + dt=1.d0/fsample + twopi=8.d0*atan(1.d0) + baud=fsample/nsps + +! Calculate the audio waveform + phi=0.d0 + if(icmplx.le.0) wave=0. + if(icmplx.eq.1) cwave=0. + k=0 + do j=1,nsym + freq=f0 + itone(j)*hmod*baud + dphi=twopi*freq*dt + do i=1,nsps + k=k+1 + if(icmplx.eq.1) then + cwave(k)=cmplx(cos(phi),sin(phi)) + else + wave(k)=sin(phi) + endif + phi=phi+dphi + if(phi.gt.twopi) phi=phi-twopi + enddo + enddo + +!### TEMPORARY code to allow transmitting both A and B submodes + inquire(file='Q65_Tx2',exist=ex) + if(ex) then + k=0 + do j=1,nsym + freq=f0 + itone(j)*2.d0*hmod*baud + 500.d0 + dphi=twopi*freq*dt + do i=1,nsps + k=k+1 + wave(k)=0.5*(wave(k)+sin(phi)) + phi=phi+dphi + if(phi.gt.twopi) phi=phi-twopi + enddo + enddo + endif +!### + + return +end subroutine genwave diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 94ca0fff4..6566924e2 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -38,7 +38,7 @@ contains ! nsubmode Tone-spacing indicator, 0-4 for A-E ! nfqso Target signal frequency (Hz) ! ntol Search range around nfqso (Hz) -! ndepth Optional decoding level (???) +! ndepth Optional decoding level ! Output: sent to the callback routine for display to user use timer_module, only: timer diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 0460fb621..e72b38dbb 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -33,8 +33,10 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & NN=63 napmin=99 baud=6000.0/nsps - - do iavg=0,1 + + maxavg=0 + if(iand(ndepth,16).ne.0) maxavg=1 + do iavg=0,maxavg if(iavg.eq.1) then idfmax=1 idtmax=1 diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 7476ab9e3..9c76fbe51 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -117,6 +117,9 @@ extern "C" { void gen_fst4wave_(int itone[], int* nsym, int* nsps, int* nwave, float* fsample, int* hmod, float* f0, int* icmplx, float xjunk[], float wave[]); + void genwave_(int itone[], int* nsym, int* nsps, int* nwave, float* fsample, + int* hmod, float* f0, int* icmplx, float xjunk[], float wave[]); + void gen4_(char* msg, int* ichk, char* msgsent, int itone[], int* itext, fortran_charlen_t, fortran_charlen_t); @@ -3991,6 +3994,20 @@ void MainWindow::guiUpdate() int i3=-1; int n3=-1; genq65_(message,&ichk,msgsent,const_cast(itone),&i3,&n3,37,37); + int nsps=1800; + if(m_TRperiod==30) nsps=3600; + if(m_TRperiod==60) nsps=7200; + if(m_TRperiod==120) nsps=16000; + if(m_TRperiod==300) nsps=41472; + int nsps4=4*nsps; //48000 Hz sampling + int nsym=85; + float fsample=48000.0; + int nwave=(nsym+2)*nsps4; + int icmplx=0; + int hmod=1; + float f0=ui->TxFreqSpinBox->value()-m_XIT; + genwave_(const_cast(itone),&nsym,&nsps4,&nwave, + &fsample,&hmod,&f0,&icmplx,foxcom_.wave,foxcom_.wave); } if(m_modeTx=="WSPR") genwspr_(message, msgsent, const_cast (itone), 22, 22); @@ -6416,7 +6433,7 @@ void MainWindow::on_actionQ65_triggered() m_wideGraph->setTxFreq(ui->TxFreqSpinBox->value()); switch_mode (Modes::Q65); // 012345678901234567890123456789012345 - displayWidgets(nWidgets("111111010110110100010000001100000000")); + displayWidgets(nWidgets("111111010110110100011000000100000000")); statusChanged(); } @@ -6770,8 +6787,6 @@ void MainWindow::on_actionInclude_averaging_toggled (bool checked) m_ndepth ^= (-checked ^ m_ndepth) & 0x00000010; } - - void MainWindow::on_actionInclude_correlation_toggled (bool checked) { m_ndepth ^= (-checked ^ m_ndepth) & 0x00000020; @@ -7321,8 +7336,9 @@ void MainWindow::transmit (double snr) if(m_TRperiod==60) nsps=7200; if(m_TRperiod==120) nsps=16000; if(m_TRperiod==300) nsps=41472; - int mode65=pow(2.0,double(m_nSubMode)); - toneSpacing=mode65*12000.0/nsps; +// int mode65=pow(2.0,double(m_nSubMode)); +// toneSpacing=mode65*12000.0/nsps; + toneSpacing=-4.0; Q_EMIT sendMessage (m_mode, NUM_Q65_SYMBOLS, double(nsps), ui->TxFreqSpinBox->value () - m_XIT, toneSpacing, m_soundOutput, m_config.audio_output_channel (), @@ -7563,13 +7579,13 @@ void MainWindow::on_sbFtol_valueChanged(int value) void::MainWindow::VHF_features_enabled(bool b) { - if(m_mode!="JT4" and m_mode!="JT65") b=false; + if(m_mode!="JT4" and m_mode!="JT65" and m_mode!="Q65") b=false; if(b and (ui->actionInclude_averaging->isChecked() or ui->actionInclude_correlation->isChecked())) { ui->actionDeepestDecode->setChecked (true); } ui->actionInclude_averaging->setVisible (b); - ui->actionInclude_correlation->setVisible (b); + ui->actionInclude_correlation->setVisible (b && m_mode!="Q65"); ui->actionMessage_averaging->setEnabled(b); ui->actionEnable_AP_DXcall->setVisible (m_mode=="QRA64"); ui->actionEnable_AP_JT65->setVisible (b && m_mode=="JT65"); From 5fe6a539b6eef3b40cd680b5a3317f77a520e9a1 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 11 Nov 2020 15:06:24 -0500 Subject: [PATCH 139/206] Fix an error in defining dat4(13) in Q65 mode. Not backward compatible! Also fix AP and message averaging for Q65. --- lib/q65_decode.f90 | 29 ++++++++++++++++++++--------- lib/qra/q65/genq65.f90 | 1 + lib/qra/q65/q65_ap.f90 | 3 ++- lib/qra/q65/q65_loops.f90 | 25 +++++++++++++++---------- lib/qra/q65/q65sim.f90 | 4 ++-- 5 files changed, 40 insertions(+), 22 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 6566924e2..9e4bf38d8 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -88,8 +88,7 @@ contains this%callback => callback if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning nFadingModel=1 - call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist) - +! call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist) call timer('sync_q65',0) call sync_q65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0, & snr1,width) @@ -112,35 +111,47 @@ contains if(nQSOprogress.eq.3 .or.nQSOprogress.eq.4) npasses=4 if(nQSOprogress.eq.5) npasses=3 if(lapcqonly) npasses=1 + iaptype=0 do ipass=0,npasses +! write(54,3000) nQSOprogress,ipass +!3000 format(i1,i2) apmask=0 apsymbols=0 if(ipass.ge.1) then - call q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,apsym0,apmask1, & - apsymbols1) + 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 - apsymbols(13)=apsymbols(13)/2 !Fixup for c77-->c78 +! write(54,3001) iaptype,c78 +!3001 format('a',i2,1x,a78) endif +! write(54,3002) apmask,apsymbols +!3002 format('b ',13b6.6/4x,13b6.6) call timer('q65loops',0) call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & - ndepth,jpk0,xdt,f0,width,ipass,apmask,apsymbols,snr1,snr2,irc,dat4) + ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols,snr1,snr2, & + irc,dat4) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) - if(irc.ge.0) exit + if(irc.ge.0) then +! write(54,3003) dat4,dat4 +!3003 format('c ',13b6.6,13i3) + exit + endif enddo 100 decoded=' ' if(irc.ge.0) then !### navg=irc/100 - irc=100*navg + ipass +! irc=100*navg + ipass + irc=100*navg + iaptype !### - write(c77,1000) dat4 + 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 nsnr=nint(snr2) diff --git a/lib/qra/q65/genq65.f90 b/lib/qra/q65/genq65.f90 index 21c96bfaf..300cbf070 100644 --- a/lib/qra/q65/genq65.f90 +++ b/lib/qra/q65/genq65.f90 @@ -29,6 +29,7 @@ subroutine genq65(msg0,ichk,msgsent,itone,i3,n3) call unpack77(c77,0,msgsent,unpk77_success) !Unpack to get msgsent read(c77,1001) dgen 1001 format(12b6.6,b5.5) + dgen(13)=2*dgen(13) !Convert 77-bit to 78-bit payload if(ichk.eq.1) go to 999 !Return if checking only call q65_enc(dgen,sent) !Encode message, dgen(1:13) ==> sent(1:63) diff --git a/lib/qra/q65/q65_ap.f90 b/lib/qra/q65/q65_ap.f90 index 1c9fe1517..f0cfd72a2 100644 --- a/lib/qra/q65/q65_ap.f90 +++ b/lib/qra/q65/q65_ap.f90 @@ -1,4 +1,5 @@ -subroutine q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,apsym0,apmask,apsymbols) +subroutine q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,iaptype, & + apsym0,apmask,apsymbols) integer apsym0(58),aph10(10) integer apmask(78),apsymbols(78) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index e72b38dbb..e10f0a624 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,5 +1,5 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & - ndepth,jpk0,xdt,f0,width,ipass,APmask,APsymbols,snr1,snr2,irc,dat4) + ndepth,jpk0,xdt,f0,width,iaptype,APmask,APsymbols,snr1,snr2,irc,dat4) use packjt77 use timer_module, only: timer @@ -24,11 +24,16 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & allocate(c0(0:npts2-1)) irc=-99 s3lim=20. - ibwmax=11 - if(mode64.le.4) ibwmax=9 - ibwmin=ibwmax - idtmax=3 - call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist) +! ibwmax=11 +! if(mode64.le.4) ibwmax=9 +! ibwmin=ibwmax +! idtmax=3 +! call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist) + idfmax=5 + idtmax=5 + ibwmin=1 + ibwmax=2 + maxdist=15 LL=64*(mode64+2) NN=63 napmin=99 @@ -49,7 +54,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & call twkfreq(c00,c0,npts2,6000.0,a) do idt=1,idtmax ndt=idt/2 - if(ipass.eq.0 .and. iavg.eq.0) then + if(iaptype.eq.0 .and. iavg.eq.0) then if(mod(idt,2).eq.0) ndt=-ndt jpk=jpk0 + nsps*ndt/16 !tsym/16 if(jpk.lt.0) jpk=0 @@ -86,7 +91,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & enddo ! ibw (b90 loop) enddo ! idt (DT loop) enddo ! idf (f0 loop) - if(ipass.eq.0 .and. iavg.eq.0) then + if(iaptype.eq.0 .and. iavg.eq.0) then a=0. a(1)=-f0 call twkfreq(c00,c0,npts2,6000.0,a) @@ -108,10 +113,10 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & if(iavg.eq.0) navg=0 !### For tests only: open(53,file='fort.53',status='unknown',position='append') - write(c77,1100) dat4 + write(c77,1100) dat4(1:12),dat4(13)/2 1100 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent - write(53,3053) ndf,ndt,nbw,b90,xdt,f0,snr2,ndist,irc,ipass,navg, & + write(53,3053) ndf,ndt,nbw,b90,xdt,f0,snr2,ndist,irc,iaptype,navg, & snr1,trim(decoded) 3053 format(3i4,f6.1,f6.2,f7.1,f6.1,4i4,f7.2,1x,a) close(53) diff --git a/lib/qra/q65/q65sim.f90 b/lib/qra/q65/q65sim.f90 index 762c9ef87..f99ab4f1d 100644 --- a/lib/qra/q65/q65sim.f90 +++ b/lib/qra/q65/q65sim.f90 @@ -85,8 +85,8 @@ program q65sim y(j)=itone(i)-1 endif enddo - write(*,1001) y(1:13) -1001 format('Generated message:'/13i3) + write(*,1001) y(1:13),y(1:13) +1001 format('Generated message'/'6-bit: ',13i3/'binary: ',13b6.6) write(*,1002) y 1002 format(/'Codeword:'/(20i3)) write(*,1003) itone From 8703b669835fcd9d7a791114a35ddb82742cf821 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Wed, 11 Nov 2020 15:20:35 -0500 Subject: [PATCH 140/206] Update test_q65.f90. --- lib/test_q65.f90 | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 1191069a6..50f378064 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -4,7 +4,7 @@ program test_q65 character*22 msg character*8 arg character*1 csubmode - integer nretcode(0:11) + integer naptype(0:6) logical decok nargs=iargc() @@ -77,15 +77,15 @@ program test_q65 cmd2(38:38)=csubmode call system('rm -f *.wav') - call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist) - write(*,1000) ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist - write(12,1000) ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist -1000 format(/'Depth:',i2,' AP:',i2,' df:',i3,' dt:',i3,' bw1:',i3,' bw2:',i3, & - ' dist:',i3) +! call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist) +! write(*,1000) ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist +! write(12,1000) ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist +!1000 format(/'Depth:',i2,' AP:',i2,' df:',i3,' dt:',i3,' bw1:',i3,' bw2:',i3, & +! ' dist:',i3) - write(*,1010) (j,j=0,11) - write(12,1010) (j,j=0,11) -1010 format('SNR d Dop Sync DecN Dec1 Bad',i6,11i4,' tdec'/85('-')) + write(*,1010) (j,j=0,6) + write(12,1010) (j,j=0,6) +1010 format('SNR nd Dop Sync DecN Dec1 Bad',i6,6i4,' tdec'/66('-')) dterr=tsym/4.0 nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) @@ -95,7 +95,7 @@ program test_q65 nsync=0 ndec1=0 nfalse=0 - nretcode=0 + naptype=0 ndecn=0 write(cmd1(63:65),'(i3)') nsnr call system(cmd1) @@ -108,7 +108,6 @@ program test_q65 read(10,'(a71)',end=10) line if(index(line,' Date: Fri, 13 Nov 2020 13:39:32 -0500 Subject: [PATCH 141/206] Restore submode on program restart. --- widgets/mainwindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 9c76fbe51..cf1e2a03e 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -983,7 +983,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, set_mode (m_mode); if(m_mode=="Echo") monitor(false); //Don't auto-start Monitor in Echo mode. - ui->sbSubmode->setValue (vhf ? m_nSubMode : 0); //Submodes require VHF features if(m_mode=="ISCAT" and !vhf) mode_label.setText("ISCAT A"); if(m_mode=="MSK144") { @@ -1238,6 +1237,7 @@ void MainWindow::readSettings() ui->sbF_Low->setValue(m_settings->value("FST4_FLow",600).toInt()); ui->sbF_High->setValue(m_settings->value("FST4_FHigh",1400).toInt()); m_nSubMode=m_settings->value("SubMode",0).toInt(); + ui->sbSubmode->setValue(m_nSubMode); ui->sbFtol->setValue (m_settings->value("Ftol", 50).toInt()); ui->sbFST4W_FTol->setValue(m_settings->value("FST4W_FTol",100).toInt()); m_minSync=m_settings->value("MinSync",0).toInt(); @@ -6424,7 +6424,8 @@ void MainWindow::on_actionQ65_triggered() on_sbTR_valueChanged (ui->sbTR->value()); //### ui->sbSubmode->setMaximum(4); ui->sbSubmode->setMaximum(7); - ui->sbSubmode->setValue(m_nSubMode); m_wideGraph->setMode(m_mode); + ui->sbSubmode->setValue(m_nSubMode); + m_wideGraph->setMode(m_mode); m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); m_wideGraph->setPeriod(m_TRperiod,6912); From 91862e61e605d4e38d8e4c3c5704dbeaf1bd9d03 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 13 Nov 2020 13:40:16 -0500 Subject: [PATCH 142/206] Display Q65 values of DT and f0 from the actual decode, not just values from sync_q65. --- lib/q65_decode.f90 | 14 +++++--------- lib/qra/q65/q65_loops.f90 | 7 ++++++- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 9e4bf38d8..d2a1e468e 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -133,15 +133,11 @@ contains !3002 format('b ',13b6.6/4x,13b6.6) call timer('q65loops',0) call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & - ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols,snr1,snr2, & - irc,dat4) + ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols,snr1,xdt1,f1, & + snr2,irc,dat4) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) - if(irc.ge.0) then -! write(54,3003) dat4,dat4 -!3003 format('c ',13b6.6,13i3) - exit - endif + if(irc.ge.0) exit enddo 100 decoded=' ' @@ -155,12 +151,12 @@ contains 1000 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent nsnr=nint(snr2) - call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & + call this%callback(nutc,sync,nsnr,xdt1,f1,decoded, & irc,qual,ntrperiod,fmid,w50) else ! Report sync, even if no decode. nsnr=db(snr1) - 35.0 - call this%callback(nutc,sync,nsnr,xdt,f0,decoded, & + call this%callback(nutc,sync,nsnr,xdt1,f1,decoded, & irc,qual,ntrperiod,fmid,w50) endif diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index e10f0a624..ebcbc7c94 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,5 +1,6 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & - ndepth,jpk0,xdt,f0,width,iaptype,APmask,APsymbols,snr1,snr2,irc,dat4) + ndepth,jpk0,xdt0,f0,width,iaptype,APmask,APsymbols,snr1,xdt1,f1, & + snr2,irc,dat4) use packjt77 use timer_module, only: timer @@ -38,6 +39,8 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & NN=63 napmin=99 baud=6000.0/nsps + xdt1=xdt0 + f1=f0 maxavg=0 if(iand(ndepth,16).ne.0) maxavg=1 @@ -111,6 +114,8 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & navg=nsave snr2=esnodb - db(2500.0/baud) if(iavg.eq.0) navg=0 + xdt1=xdt0 + nsps*ndt/(16.0*6000.0) + f1=f0 + 0.5*baud*ndf !### For tests only: open(53,file='fort.53',status='unknown',position='append') write(c77,1100) dat4(1:12),dat4(13)/2 From dc3d567ce8399f36e1b4adc061405515b8ee7958 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 13 Nov 2020 13:45:14 -0500 Subject: [PATCH 143/206] Correct the diagnostic output to fort.53. --- lib/qra/q65/q65_loops.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index ebcbc7c94..d870c21b7 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -121,7 +121,7 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & write(c77,1100) dat4(1:12),dat4(13)/2 1100 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent - write(53,3053) ndf,ndt,nbw,b90,xdt,f0,snr2,ndist,irc,iaptype,navg, & + write(53,3053) ndf,ndt,nbw,b90,xdt1,f1,snr2,ndist,irc,iaptype,navg, & snr1,trim(decoded) 3053 format(3i4,f6.1,f6.2,f7.1,f6.1,4i4,f7.2,1x,a) close(53) From 4903b38220652cc9257bb057d0814ee87deb8e8c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 15 Nov 2020 11:58:36 -0500 Subject: [PATCH 144/206] When jt9 is run from command line, set Q65 default FTol = 10. --- lib/jt9.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/jt9.f90 b/lib/jt9.f90 index 2139c66aa..e9abd6480 100644 --- a/lib/jt9.f90 +++ b/lib/jt9.f90 @@ -51,7 +51,7 @@ program jt9 option ('fft-threads', .true., 'm', & 'Number of threads to process large FFTs, default THREADS=1', & 'THREADS'), & - option ('qra66', .false., '3', 'QRA66 mode', ''), & + option ('q65', .false., '3', 'Q65 mode', ''), & option ('jt4', .false., '4', 'JT4 mode', ''), & option ('ft4', .false., '5', 'FT4 mode', ''), & option ('jt65', .false.,'6', 'JT65 mode', ''), & @@ -263,6 +263,7 @@ program jt9 shared_data%params%nfsplit=fsplit shared_data%params%nfb=fhigh shared_data%params%ntol=20 + if(mode.eq.66) shared_data%params%ntol=10 shared_data%params%kin=64800 if(mode.eq.240) shared_data%params%kin=720000 !### 60 s periods ### shared_data%params%nzhsym=nhsym From 24ed64e5ccd09808c0990c0185bafb38b4e10958 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 15 Nov 2020 12:21:08 -0500 Subject: [PATCH 145/206] Add UTC and reformat diagnostic output to fort.53. --- lib/q65_decode.f90 | 24 ++++++++++++++++++------ lib/qra/q65/q65_loops.f90 | 11 +++++++---- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index d2a1e468e..40aef5f8b 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -63,9 +63,10 @@ contains complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s mode65=2**nsubmode + npts=ntrperiod*12000 nfft1=ntrperiod*12000 nfft2=ntrperiod*6000 - allocate(dd(NMAX)) + allocate(dd(npts)) allocate (c00(0:nfft1-1)) allocate (c0(0:nfft1-1)) @@ -82,7 +83,6 @@ contains else stop 'Invalid TR period' endif - npts=ntrperiod*12000 baud=12000.0/nsps df1=12000.0/nfft1 this%callback => callback @@ -100,7 +100,19 @@ contains if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### if(jpk0.lt.0) jpk0=0 fac=1.0/32767.0 - dd=fac*iwave + dd=fac*iwave(1:npts) +!### +! Optionslly write noise level to LU 56 +! sq=dot_product(dd,dd)/npts +! m=nutc +! if(ntrperiod.ge.60) m=100*m +! ihr=m/10000 +! imin=mod(m/100,100) +! isec=mod(m,100) +! hours=ihr + imin/60.0 + isec/3600.0 +! write(56,3056) m,hours,db(sq)+90.3 +!3056 format(i6.6,f10.6,f10.3) +!### nmode=65 call ana64(dd,npts,c00) @@ -132,9 +144,9 @@ contains ! write(54,3002) apmask,apsymbols !3002 format('b ',13b6.6/4x,13b6.6) call timer('q65loops',0) - call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode,nFadingModel, & - ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols,snr1,xdt1,f1, & - snr2,irc,dat4) + call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & + nFadingModel,ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols, & + snr1,xdt1,f1,snr2,irc,dat4) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) if(irc.ge.0) exit diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index d870c21b7..06d8fcd04 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,4 +1,4 @@ -subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & +subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ndepth,jpk0,xdt0,f0,width,iaptype,APmask,APsymbols,snr1,xdt1,f1, & snr2,irc,dat4) @@ -121,9 +121,12 @@ subroutine q65_loops(c00,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & write(c77,1100) dat4(1:12),dat4(13)/2 1100 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent - write(53,3053) ndf,ndt,nbw,b90,xdt1,f1,snr2,ndist,irc,iaptype,navg, & - snr1,trim(decoded) -3053 format(3i4,f6.1,f6.2,f7.1,f6.1,4i4,f7.2,1x,a) + if(nsps.lt.3600) write(53,3001) nutc,ndf,ndt,nbw,ndist,irc, & + iaptype,navg,snr1,xdt1,f1,snr2,trim(decoded) +3001 format(i6.6,7i4,f7.1,f7.2,2f7.1,1x,a) + if(nsps.ge.3600) write(53,3002) nutc,ndf,ndt,nbw,ndist,irc, & + iaptype,navg,snr1,xdt1,f1,snr2,trim(decoded) +3002 format(i4.4,2x,7i4,f7.1,f7.2,2f7.1,1x,a) close(53) !### nsave=0 From df2daf60bda6ee68df9114666a10ed0a235782fc Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 16 Nov 2020 10:06:10 -0500 Subject: [PATCH 146/206] Remove JT9+JT65 mode. Remove labNextCall. Tighten up central array of GUI controls. --- widgets/mainwindow.cpp | 102 +-------------- widgets/mainwindow.h | 2 - widgets/mainwindow.ui | 286 ++++++++++++++++++----------------------- 3 files changed, 127 insertions(+), 263 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index cf1e2a03e..c1904af58 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -601,7 +601,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionFT8->setActionGroup(modeGroup); ui->actionJT9->setActionGroup(modeGroup); ui->actionJT65->setActionGroup(modeGroup); - ui->actionJT9_JT65->setActionGroup(modeGroup); ui->actionJT4->setActionGroup(modeGroup); ui->actionWSPR->setActionGroup(modeGroup); ui->actionEcho->setActionGroup(modeGroup); @@ -860,9 +859,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_msg[0][0]=0; ui->labDXped->setVisible(false); ui->labDXped->setStyleSheet("QLabel {background-color: red; color: white;}"); - ui->labNextCall->setText(""); - ui->labNextCall->setVisible(false); - ui->labNextCall->setToolTip(""); //### Possibly temporary ? ### char const * const power[] = {"1 mW","2 mW","5 mW","10 mW","20 mW","50 mW","100 mW","200 mW","500 mW", "1 W","2 W","5 W","10 W","20 W","50 W","100 W","200 W","500 W","1 kW"}; @@ -1225,8 +1221,6 @@ void MainWindow::readSettings() m_settings->beginGroup("Common"); m_mode=m_settings->value("Mode","JT9").toString(); m_modeTx=m_settings->value("ModeTx","JT9").toString(); - if(m_modeTx.mid(0,3)=="JT9") ui->pbTxMode->setText("Tx JT9 @"); - if(m_modeTx=="JT65") ui->pbTxMode->setText("Tx JT65 #"); ui->actionNone->setChecked(m_settings->value("SaveNone",true).toBool()); ui->actionSave_decoded->setChecked(m_settings->value("SaveDecoded",false).toBool()); ui->actionSave_all->setChecked(m_settings->value("SaveAll",false).toBool()); @@ -2121,8 +2115,6 @@ void MainWindow::keyPressEvent (QKeyEvent * e) return; case Qt::Key_Escape: m_nextCall=""; - ui->labNextCall->setStyleSheet(""); - ui->labNextCall->setText(""); on_stopTxButton_clicked(); abortQSO(); return; @@ -3469,11 +3461,6 @@ void MainWindow::readFromStdout() //readFromStdout ui->decodedTextBrowser2->displayDecodedText(decodedtext0,m_baseCall,m_mode,m_config.DXCC(), m_logBook,m_currentBand,m_config.ppfx()); } - if(m_mode!="JT4") { - bool b65=decodedtext.isJT65(); - if(b65 and m_modeTx!="JT65") on_pbTxMode_clicked(); - if(!b65 and m_modeTx=="JT65") on_pbTxMode_clicked(); - } m_QSOText = decodedtext.string ().trimmed (); } @@ -4384,8 +4371,6 @@ void MainWindow::useNextCall() { ui->dxCallEntry->setText(m_nextCall); m_nextCall=""; - ui->labNextCall->setStyleSheet(""); - ui->labNextCall->setText(""); if(m_nextGrid.contains(grid_regexp)) { ui->dxGridEntry->setText(m_nextGrid); m_ntx=2; @@ -4796,11 +4781,9 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie if (message.isJT9()) { m_modeTx="JT9"; - ui->pbTxMode->setText("Tx JT9 @"); m_wideGraph->setModeTx(m_modeTx); } else if (message.isJT65()) { m_modeTx="JT65"; - ui->pbTxMode->setText("Tx JT65 #"); m_wideGraph->setModeTx(m_modeTx); } } else if ((message.isJT9 () and m_modeTx != "JT9" and m_mode != "JT4") or @@ -5032,17 +5015,6 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } } else { // nothing for us -// if(message_words.size () > 3 // enough fields for a normal message -// && SpecOp::RTTY == m_config.special_op_id() -// && (message_words.at(1).contains(m_baseCall) || "DE" == message_words.at(1)) -// && (!message_words.at(2).contains(qso_partner_base_call) and !bEU_VHF_w2)) { -//// Queue up the next QSO partner -// m_nextCall=message_words.at(2); -// m_nextGrid=message_words.at(3); -// m_nextRpt=message.report(); -// ui->labNextCall->setText("Next: " + m_nextCall); -// ui->labNextCall->setStyleSheet("QLabel {color: #000000; background-color: #66ff66}"); -// } return; } } @@ -5908,7 +5880,7 @@ void MainWindow::displayWidgets(qint64 n) if(i==8) ui->cbFast9->setVisible(b); if(i==9) ui->cbAutoSeq->setVisible(b); if(i==10) ui->cbTx6->setVisible(b); - if(i==11) ui->pbTxMode->setVisible(b); +// if(i==11) ui->pbTxMode->setVisible(b); if(i==12) ui->pbR2T->setVisible(b); if(i==13) ui->pbT2R->setVisible(b); if(i==14) ui->cbHoldTxFreq->setVisible(b); @@ -5929,7 +5901,7 @@ void MainWindow::displayWidgets(qint64 n) if(i==25) ui->actionEnable_AP_JT65->setVisible (b); if(i==26) ui->actionEnable_AP_DXcall->setVisible (b); if(i==27) ui->cbFirst->setVisible(b); - if(i==28) ui->labNextCall->setVisible(b); +// if(i==28) ui->labNextCall->setVisible(b); if(i==29) ui->measure_check_box->setVisible(b); if(i==30) ui->labDXped->setVisible(b); if(i==31) ui->cbRxAll->setVisible(b); @@ -6279,58 +6251,14 @@ void MainWindow::on_actionJT9_triggered() statusChanged(); } -void MainWindow::on_actionJT9_JT65_triggered() -{ - m_mode="JT9+JT65"; - WSPR_config(false); - switch_mode (Modes::JT65); - if(m_modeTx != "JT65") { - ui->pbTxMode->setText("Tx JT9 @"); - m_modeTx="JT9"; - } - m_nSubMode=0; //Dual-mode always means JT9 and JT65A - m_TRperiod=60.0; - m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe - m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe - m_nsps=6912; - m_FFTSize = m_nsps / 2; - Q_EMIT FFTSize (m_FFTSize); - m_hsymStop=174; - if(m_config.decode_at_52s()) m_hsymStop=183; - m_toneSpacing=0.0; - setup_status_bar (false); - ui->actionJT9_JT65->setChecked(true); - VHF_features_enabled(false); - m_wideGraph->setPeriod(m_TRperiod,m_nsps); - m_wideGraph->setMode(m_mode); - m_wideGraph->setModeTx(m_modeTx); - m_bFastMode=false; - m_bFast9=false; - ui->sbSubmode->setValue(0); - ui->lh_decodes_title_label->setText(tr ("Band Activity")); - ui->rh_decodes_title_label->setText(tr ("Rx Frequency")); - ui->lh_decodes_headings_label->setText("UTC dB DT Freq " + tr ("Message")); - ui->rh_decodes_headings_label->setText("UTC dB DT Freq " + tr ("Message")); - displayWidgets(nWidgets("111010000001111000010000000000001000")); - fast_config(false); - statusChanged(); -} - void MainWindow::on_actionJT65_triggered() { - if(m_mode=="JT4" or m_mode=="WSPR" or m_mode=="FST4W") { -// If coming from JT4, WSPR, or FST4W mode, pretend temporarily that we're coming -// from JT9 and click the pbTxMode button - m_modeTx="JT9"; - on_pbTxMode_clicked(); - } on_actionJT9_triggered(); m_mode="JT65"; m_modeTx="JT65"; bool bVHF=m_config.enable_VHF_features(); WSPR_config(false); switch_mode (Modes::JT65); - if(m_modeTx!="JT65") on_pbTxMode_clicked(); m_TRperiod=60.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe @@ -6482,7 +6410,6 @@ void MainWindow::on_actionMSK144_triggered() if("JT4"==m_mode) ui->actionJT4->setChecked(true); if("JT9"==m_mode) ui->actionJT9->setChecked(true); if("JT65"==m_mode) ui->actionJT65->setChecked(true); - if("JT9_JT65"==m_mode) ui->actionJT9_JT65->setChecked(true); if("ISCAT"==m_mode) ui->actionISCAT->setChecked(true); if("QRA64"==m_mode) ui->actionQRA64->setChecked(true); if("Q65"==m_mode) ui->actionQ65->setChecked(true); @@ -7067,21 +6994,6 @@ void MainWindow::on_readFreq_clicked() } } -void MainWindow::on_pbTxMode_clicked() -{ - if(m_mode=="JT9+JT65") { - if(m_modeTx=="JT9") { - m_modeTx="JT65"; - ui->pbTxMode->setText("Tx JT65 #"); - } else { - m_modeTx="JT9"; - ui->pbTxMode->setText("Tx JT9 @"); - } - m_wideGraph->setModeTx(m_modeTx); - statusChanged(); - } -} - void MainWindow::setXIT(int n, Frequency base) { if (m_transmitting && !m_config.tx_QSY_allowed ()) return; @@ -7560,15 +7472,6 @@ void MainWindow::transmitDisplay (bool transmitting) // the following are always disallowed in transmit ui->menuMode->setEnabled (!transmitting); - //ui->bandComboBox->setEnabled (!transmitting); - if (!transmitting) { - if (m_mode == "JT9+JT65") { - // allow mode switch in Rx when in dual mode - ui->pbTxMode->setEnabled (true); - } - } else { - ui->pbTxMode->setEnabled (false); - } } } @@ -9273,7 +9176,6 @@ void MainWindow::set_mode (QString const& mode) else if ("FT8" == mode) on_actionFT8_triggered (); else if ("JT4" == mode) on_actionJT4_triggered (); else if ("JT9" == mode) on_actionJT9_triggered (); - else if ("JT9+JT65" == mode) on_actionJT9_JT65_triggered (); else if ("JT65" == mode) on_actionJT65_triggered (); else if ("QRA64" == mode) on_actionQRA64_triggered (); else if ("Q65" == mode) on_actionQ65_triggered (); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 4066af831..98532ece7 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -203,7 +203,6 @@ private slots: void on_logQSOButton_clicked(); void on_actionJT9_triggered(); void on_actionJT65_triggered(); - void on_actionJT9_JT65_triggered(); void on_actionJT4_triggered(); void on_actionFT4_triggered(); void on_actionFT8_triggered(); @@ -241,7 +240,6 @@ private slots: void on_bandComboBox_editTextChanged (QString const& text); void on_bandComboBox_activated (int index); void on_readFreq_clicked(); - void on_pbTxMode_clicked(); void on_RxFreqSpinBox_valueChanged(int n); void on_outAttenuation_valueChanged (int); void rigOpen (); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index ff7986403..73e06ef21 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 805 - 589 + 637 @@ -590,7 +590,7 @@ - + @@ -1219,25 +1219,6 @@ Yellow when too low - - - - true - - - - 0 - 0 - - - - Toggle Tx mode - - - Tx JT9 @ - - - @@ -1263,53 +1244,6 @@ Yellow when too low - - - - <html><head/><body><p>Submode determines tone spacing; A is narrowest.</p></body></html> - - - Submode determines tone spacing; A is narrowest. - - - Qt::AlignCenter - - - Submode - - - 0 - - - 7 - - - - - - - Qt::AlignCenter - - - - - - F High - - - 100 - - - 5000 - - - 100 - - - 1400 - - - @@ -1379,44 +1313,6 @@ Yellow when too low - - - - Qt::AlignCenter - - - F Low - - - 100 - - - 5000 - - - 100 - - - 600 - - - - - - - <html><head/><body><p>Double-click on another caller to queue that call for your next QSO.</p></body></html> - - - Double-click on another caller to queue that call for your next QSO. - - - Next Call - - - Qt::AlignCenter - - - @@ -1523,60 +1419,6 @@ Not available to nonstandard callsign holders. - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - Tx# - - - 1 - - - 4095 - - - - - - - <html><head/><body><p>Check to keep Tx frequency fixed when double-clicking on decoded text.</p></body></html> - - - Check to keep Tx frequency fixed when double-clicking on decoded text. - - - Hold Tx Freq - - - - - - - <html><head/><body><p>Synchronizing threshold. Lower numbers accept weaker sync signals.</p></body></html> - - - Synchronizing threshold. Lower numbers accept weaker sync signals. - - - Qt::AlignCenter - - - Sync - - - -2 - - - 10 - - - 1 - - - @@ -1704,6 +1546,129 @@ When not checked you can view the calibration results. + + + + <html><head/><body><p>Check to keep Tx frequency fixed when double-clicking on decoded text.</p></body></html> + + + Check to keep Tx frequency fixed when double-clicking on decoded text. + + + Hold Tx Freq + + + + + + + Qt::AlignCenter + + + F Low + + + 100 + + + 5000 + + + 100 + + + 600 + + + + + + + Qt::AlignCenter + + + + + + F High + + + 100 + + + 5000 + + + 100 + + + 1400 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Tx# + + + 1 + + + 4095 + + + + + + + <html><head/><body><p>Submode determines tone spacing; A is narrowest.</p></body></html> + + + Submode determines tone spacing; A is narrowest. + + + Qt::AlignCenter + + + Submode + + + 0 + + + 7 + + + + + + + <html><head/><body><p>Synchronizing threshold. Lower numbers accept weaker sync signals.</p></body></html> + + + Synchronizing threshold. Lower numbers accept weaker sync signals. + + + Qt::AlignCenter + + + Sync + + + -2 + + + 10 + + + 1 + + + @@ -2892,7 +2857,6 @@ list. The list can be maintained in Settings (F2). - From bbcc9419b451949527d20802a128e5c5e1e2a926 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 16 Nov 2020 10:37:09 -0500 Subject: [PATCH 147/206] Set a mainwindow minimum height. --- widgets/mainwindow.ui | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 73e06ef21..05b739f70 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 805 - 637 + 584 @@ -16,6 +16,12 @@ 0 + + + 0 + 584 + + WSJT-X by K1JT @@ -155,7 +161,7 @@ - + 0 10 From 7f772ecc533ab313f24ec7fdf1b03995d055ade3 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 16 Nov 2020 11:49:01 -0500 Subject: [PATCH 148/206] Don't set a global minimum height: SWL mode wants much less. --- widgets/mainwindow.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 05b739f70..78f296c50 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -19,7 +19,7 @@ 0 - 584 + 0 From 0755e52993f482ebb57d29c7ab9d7b700663eb5d Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 16 Nov 2020 13:49:31 -0500 Subject: [PATCH 149/206] Another reformatting of output to fort.53. --- lib/qra/q65/q65_loops.f90 | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 06d8fcd04..a3d62e765 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -121,12 +121,15 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & write(c77,1100) dat4(1:12),dat4(13)/2 1100 format(12b6.6,b5.5) call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent - if(nsps.lt.3600) write(53,3001) nutc,ndf,ndt,nbw,ndist,irc, & - iaptype,navg,snr1,xdt1,f1,snr2,trim(decoded) -3001 format(i6.6,7i4,f7.1,f7.2,2f7.1,1x,a) - if(nsps.ge.3600) write(53,3002) nutc,ndf,ndt,nbw,ndist,irc, & - iaptype,navg,snr1,xdt1,f1,snr2,trim(decoded) -3002 format(i4.4,2x,7i4,f7.1,f7.2,2f7.1,1x,a) + m=nutc + if(nsps.ge.3600) m=100*m + ihr=m/10000 + imin=mod(m/100,100) + isec=mod(m,100) + hours=ihr + imin/60.0 + isec/3600.0 + write(53,3053) m,hours,ndf,ndt,nbw,ndist,irc,iaptype,navg,snr1, & + xdt1,f1,snr2,trim(decoded) +3053 format(i6.6,f8.4,4i3,i4,2i3,f6.1,f6.2,f7.1,f6.1,1x,a) close(53) !### nsave=0 From eeed375baf46b8f647a7328d5f95bef7aa1bcece Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 16 Nov 2020 16:28:37 -0500 Subject: [PATCH 150/206] Tell user to go back it he selects F+H in a mode other than FT8. --- widgets/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index c1904af58..bb29d3da2 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -1888,7 +1888,7 @@ void MainWindow::on_actionSettings_triggered() //Setup Dialog if((m_config.special_op_id()==SpecOp::FOX or m_config.special_op_id()==SpecOp::HOUND) and m_mode!="FT8") { MessageBox::information_message (this, - "Fox-and-Hound operation is available only in FT8 mode."); + "Fox-and-Hound operation is available only in FT8 mode.\nGo back and change your selection."); } } } From e71bc50bbf8a5d8a1fb1a20b4af75690540b5493 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 16 Nov 2020 16:29:52 -0500 Subject: [PATCH 151/206] Set irc to -9, DT and f0 to 0 if sync amplitude it too small. --- lib/q65_decode.f90 | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 40aef5f8b..9f49868ca 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -94,7 +94,7 @@ contains snr1,width) call timer('sync_q65',1) - irc=-1 + irc=-9 if(snr1.lt.2.8) go to 100 jpk0=(xdt+1.0)*6000 !### Is this OK? if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### @@ -125,8 +125,6 @@ contains if(lapcqonly) npasses=1 iaptype=0 do ipass=0,npasses -! write(54,3000) nQSOprogress,ipass -!3000 format(i1,i2) apmask=0 apsymbols=0 if(ipass.ge.1) then @@ -138,11 +136,7 @@ contains 1060 format(13b6.6) write(c78,1050) apsymbols1 read(c78,1060) apsymbols -! write(54,3001) iaptype,c78 -!3001 format('a',i2,1x,a78) endif -! write(54,3002) apmask,apsymbols -!3002 format('b ',13b6.6/4x,13b6.6) call timer('q65loops',0) call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & nFadingModel,ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols, & From abe06e5dbbeee886d220a3b747d866531596cb01 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 17 Nov 2020 10:46:20 -0500 Subject: [PATCH 152/206] Access Q65 Quick-Start Guide from Help menu. --- widgets/mainwindow.cpp | 7 ++++++- widgets/mainwindow.h | 3 ++- widgets/mainwindow.ui | 10 ++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index bb29d3da2..32048bc9e 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -2491,11 +2491,16 @@ void MainWindow::on_actionFT8_DXpedition_Mode_User_Guide_triggered() QDesktopServices::openUrl (QUrl {"http://physics.princeton.edu/pulsar/k1jt/FT8_DXpedition_Mode.pdf"}); } -void MainWindow::on_actionQuick_Start_Guide_triggered() +void MainWindow::on_actionQSG_FST4_triggered() { QDesktopServices::openUrl (QUrl {"https://physics.princeton.edu/pulsar/k1jt/FST4_Quick_Start.pdf"}); } +void MainWindow::on_actionQSG_Q65_triggered() +{ + QDesktopServices::openUrl (QUrl {"https://physics.princeton.edu/pulsar/k1jt/Q65_Quick_Start.pdf"}); +} + void MainWindow::on_actionOnline_User_Guide_triggered() //Display manual { #if defined (CMAKE_BUILD) diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 98532ece7..4ab9a4102 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -151,7 +151,8 @@ private slots: void on_stopButton_clicked(); void on_actionRelease_Notes_triggered (); void on_actionFT8_DXpedition_Mode_User_Guide_triggered(); - void on_actionQuick_Start_Guide_triggered(); + void on_actionQSG_FST4_triggered(); + void on_actionQSG_Q65_triggered(); void on_actionOnline_User_Guide_triggered(); void on_actionLocal_User_Guide_triggered(); void on_actionWide_Waterfall_triggered(); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 78f296c50..51dc92757 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -2843,7 +2843,8 @@ list. The list can be maintained in Settings (F2). - + + @@ -3314,7 +3315,7 @@ list. The list can be maintained in Settings (F2). Export Cabrillo log ... - + Quick-Start Guide to FST4 and FST4W @@ -3372,6 +3373,11 @@ list. The list can be maintained in Settings (F2). Hide lower panel controls to maximize deocde windows + + + Quick-Start Guide to Q65 + + From d3ed0be31895cb4a6f9c8cdbb04fe6dffd57d30e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 17 Nov 2020 10:47:07 -0500 Subject: [PATCH 153/206] Allow 2-digit input of ndepth in test_q65. --- lib/test_q65.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 50f378064..3fb39d026 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -62,7 +62,7 @@ program test_q65 ! 1 2 3 4 5 6 7 ! 1234567890123456789012345678901234567890123456789012345678901234567890123' cmd1='q65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 F -10 > junk0' - cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A *.wav > junk' + cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A *.wav > junk' write(cmd1(10:33),'(a)') '"'//msg//'"' cmd1(35:35)=csubmode @@ -73,8 +73,8 @@ program test_q65 write(cmd1(55:59),'(i5)') nfiles write(cmd2(11:13),'(i3)') ntrperiod - write(cmd2(33:33),'(i1)') ndepth - cmd2(38:38)=csubmode + write(cmd2(33:34),'(i2)') ndepth + cmd2(39:39)=csubmode call system('rm -f *.wav') ! call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist) From 2dcd8504e8109c3dad388838d241136bfb97812b Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 17 Nov 2020 15:09:03 -0500 Subject: [PATCH 154/206] Updates to test_q65: allow command-line input of QSOprogress. --- lib/test_q65.f90 | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 3fb39d026..fc6841ae7 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -8,10 +8,11 @@ program test_q65 logical decok nargs=iargc() - if(nargs.ne.9) then - print*,'Usage: test_q65 "msg" A-D depth freq DT fDop TRp nfiles SNR' - print*,'Example: test_q65 "K1ABC W9XYZ EN37" A 3 1500 0.0 5.0 60 100 -20' - print*,' SNR = 0 to loop over all relevant SNRs' + if(nargs.ne.10) then + print*,'Usage: test_q65 "msg" A-D depth freq DT fDop TRp Q nfiles SNR' + print*,'Example: test_q65 "K1ABC W9XYZ EN37" A 3 1500 0.0 5.0 60 3 100 -20' + print*,'Use SNR = 0 to loop over all relevant SNRs' + print*,'Use MyCall=K1ABC, HisCall=W9XYZ, HisGrid="EN37" for AP decodes' go to 999 endif call getarg(1,msg) @@ -27,8 +28,10 @@ program test_q65 call getarg(7,arg) read(arg,*) ntrperiod call getarg(8,arg) - read(arg,*) nfiles + read(arg,*) nQSOprogress call getarg(9,arg) + read(arg,*) nfiles + call getarg(10,arg) read(arg,*) nsnr if(ntrperiod.eq.15) then @@ -62,7 +65,7 @@ program test_q65 ! 1 2 3 4 5 6 7 ! 1234567890123456789012345678901234567890123456789012345678901234567890123' cmd1='q65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 F -10 > junk0' - cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A *.wav > junk' + cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A -Q 3 *.wav > junk' write(cmd1(10:33),'(a)') '"'//msg//'"' cmd1(35:35)=csubmode @@ -74,6 +77,7 @@ program test_q65 write(cmd2(11:13),'(i3)') ntrperiod write(cmd2(33:34),'(i2)') ndepth + write(cmd2(44:44),'(i1)') nQSOprogress cmd2(39:39)=csubmode call system('rm -f *.wav') @@ -85,7 +89,7 @@ program test_q65 write(*,1010) (j,j=0,6) write(12,1010) (j,j=0,6) -1010 format('SNR nd Dop Sync DecN Dec1 Bad',i6,6i4,' tdec'/66('-')) +1010 format('SNR d Dop Sync DecN Dec1 Bad',i6,6i4,' tdec'/66('-')) dterr=tsym/4.0 nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) From d26acd048c438f7af4b20f38eb75b76661547875 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 17 Nov 2020 15:31:33 -0500 Subject: [PATCH 155/206] Minor tweak to test_q65. --- lib/test_q65.f90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index fc6841ae7..a6b0e8eaa 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -13,6 +13,8 @@ program test_q65 print*,'Example: test_q65 "K1ABC W9XYZ EN37" A 3 1500 0.0 5.0 60 3 100 -20' print*,'Use SNR = 0 to loop over all relevant SNRs' print*,'Use MyCall=K1ABC, HisCall=W9XYZ, HisGrid="EN37" for AP decodes' + print*,'Option Q sets QSOprogress (0-5) for AP decoding.' + print*,'Add 16 to requested depth to enable message averaging.' go to 999 endif call getarg(1,msg) From 44343d87f6ebc5d024e98d4a9a084ccf6a1bb5e2 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 19 Nov 2020 13:45:16 -0500 Subject: [PATCH 156/206] Allow input of fractional SNR to test_q65. --- lib/test_q65.f90 | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index a6b0e8eaa..5871b0579 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -1,6 +1,6 @@ program test_q65 - character*73 cmd1,cmd2,line + character*75 cmd1,cmd2,line character*22 msg character*8 arg character*1 csubmode @@ -34,7 +34,7 @@ program test_q65 call getarg(9,arg) read(arg,*) nfiles call getarg(10,arg) - read(arg,*) nsnr + read(arg,*) snr if(ntrperiod.eq.15) then nsps=1800 @@ -56,17 +56,17 @@ program test_q65 endif ia=i50 + 8 ib=i50 - 5 - if(nsnr.ne.0) then - ia=nsnr - ib=nsnr + if(snr.ne.0.0) then + ia=99 + ib=99 endif baud=12000.0/nsps tsym=1.0/baud ! 1 2 3 4 5 6 7 -! 1234567890123456789012345678901234567890123456789012345678901234567890123' - cmd1='q65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 F -10 > junk0' +! 123456789012345678901234567890123456789012345678901234567890123456789012345' + cmd1='q65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 F -10.0 > junk0' cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A -Q 3 *.wav > junk' write(cmd1(10:33),'(a)') '"'//msg//'"' @@ -91,19 +91,21 @@ program test_q65 write(*,1010) (j,j=0,6) write(12,1010) (j,j=0,6) -1010 format('SNR d Dop Sync DecN Dec1 Bad',i6,6i4,' tdec'/66('-')) +1010 format(' SNR d Dop Sync DecN Dec1 Bad',i6,6i4,' tdec'/68('-')) dterr=tsym/4.0 nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) ndec10=nfiles do nsnr=ia,ib,-1 + snr1=nsnr + if(ia.eq.99) snr1=snr nsync=0 ndec1=0 nfalse=0 naptype=0 ndecn=0 - write(cmd1(63:65),'(i3)') nsnr + write(cmd1(63:67),'(f5.1)') snr1 call system(cmd1) call sec0(0,tdec) call system(cmd2) @@ -136,13 +138,13 @@ program test_q65 10 close(10) xdt_avg=0. xdt_rms=0. - write(*,1100) nsnr,ndepth,fDop,nsync,ndecn,ndec1,nfalse,naptype, & + write(*,1100) snr1,ndepth,fDop,nsync,ndecn,ndec1,nfalse,naptype, & tdec/nfiles - write(12,1100) nsnr,ndepth,fDop,nsync,ndecn,ndec1,nfalse,naptype, & + write(12,1100) snr1,ndepth,fDop,nsync,ndecn,ndec1,nfalse,naptype, & tdec/nfiles -1100 format(i3,i3,f5.1,3i5,i4,i6,6i4,f6.2) +1100 format(f5.1,i3,f5.1,3i5,i4,i6,6i4,f6.2) if(ndec1.lt.nfiles/2 .and. ndec10.ge.nfiles/2) then - snr_thresh=nsnr + float(nfiles/2 - ndec1)/(ndec10-ndec1) + snr_thresh=snr1 + float(nfiles/2 - ndec1)/(ndec10-ndec1) write(13,1200) ndepth,fdop,csubmode,snr_thresh 1200 format(i3,f6.1,2x,a1,f7.1) flush(13) From 0bcb2f0d11df7e3eb4cd7135823bc43a512c6577 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 19 Nov 2020 13:50:59 -0500 Subject: [PATCH 157/206] Adjust SNR limits in test_q65. --- lib/test_q65.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 5871b0579..395e5a5d2 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -54,8 +54,8 @@ program test_q65 else stop 'Invalid TR period' endif - ia=i50 + 8 - ib=i50 - 5 + ia=i50 + 5 + ib=i50 - 10 if(snr.ne.0.0) then ia=99 ib=99 From 13d0b20661895f90131e94172997078c25aa127e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 19 Nov 2020 15:25:28 -0500 Subject: [PATCH 158/206] Change the unmasked bits for iaptype 4, 5, 6. Tweak the SNR limits in test_q65. --- lib/qra/q65/q65_ap.f90 | 5 +++-- lib/test_q65.f90 | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/qra/q65/q65_ap.f90 b/lib/qra/q65/q65_ap.f90 index f0cfd72a2..c30314b1a 100644 --- a/lib/qra/q65/q65_ap.f90 +++ b/lib/qra/q65/q65_ap.f90 @@ -146,11 +146,12 @@ subroutine q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,iaptype, & if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then apmask=0 if(ncontest.le.5 .or. (ncontest.eq.7.and.iaptype.eq.6)) then - apmask(1:78)=1 ! mycall, hiscall, RRR|73|RR73 + apmask(1:78)=1 !MyCall, HisCall, RRR|73|RR73 + apmask(59:63)=0 !Reduce the rate of false decodes apsymbols(1:58)=apsym0 if(iaptype.eq.4) apsymbols(59:77)=mrrr if(iaptype.eq.5) apsymbols(59:77)=m73 - if(iaptype.eq.6) apsymbols(59:77)=mrr73 + if(iaptype.eq.6) apsymbols(59:77)=mrr73 else if(ncontest.eq.7.and.iaptype.eq.4) then ! Hound listens for MyCall RR73;... apmask(1:28)=1 apsymbols(1:28)=apsym0(1:28) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 395e5a5d2..66caca99a 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -54,7 +54,7 @@ program test_q65 else stop 'Invalid TR period' endif - ia=i50 + 5 + ia=i50 + 7 ib=i50 - 10 if(snr.ne.0.0) then ia=99 @@ -145,9 +145,11 @@ program test_q65 1100 format(f5.1,i3,f5.1,3i5,i4,i6,6i4,f6.2) if(ndec1.lt.nfiles/2 .and. ndec10.ge.nfiles/2) then snr_thresh=snr1 + float(nfiles/2 - ndec1)/(ndec10-ndec1) - write(13,1200) ndepth,fdop,csubmode,snr_thresh -1200 format(i3,f6.1,2x,a1,f7.1) - flush(13) + open(13,file='snr_thresh.out',status='unknown',position='append') + write(13,1200) ntrperiod,csubmode,ndepth,nQSOprogress,nfiles, & + fdop,snr_thresh,trim(msg) +1200 format(i3,a1,2i3,i5,2f7.1,2x,a) + close(13) endif flush(6) flush(12) From 3662a76de7ca70db55240562da1eda5729ce5488 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 19 Nov 2020 15:41:15 -0500 Subject: [PATCH 159/206] More Q65 test program tweaks. --- lib/qra/q65/q65_ap.f90 | 2 +- lib/test_q65.f90 | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/qra/q65/q65_ap.f90 b/lib/qra/q65/q65_ap.f90 index c30314b1a..b335153c3 100644 --- a/lib/qra/q65/q65_ap.f90 +++ b/lib/qra/q65/q65_ap.f90 @@ -147,7 +147,7 @@ subroutine q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,iaptype, & apmask=0 if(ncontest.le.5 .or. (ncontest.eq.7.and.iaptype.eq.6)) then apmask(1:78)=1 !MyCall, HisCall, RRR|73|RR73 - apmask(59:63)=0 !Reduce the rate of false decodes + apmask(59:66)=0 !Reduce the rate of false decodes apsymbols(1:58)=apsym0 if(iaptype.eq.4) apsymbols(59:77)=mrrr if(iaptype.eq.5) apsymbols(59:77)=m73 diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 66caca99a..4aa452458 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -91,7 +91,7 @@ program test_q65 write(*,1010) (j,j=0,6) write(12,1010) (j,j=0,6) -1010 format(' SNR d Dop Sync DecN Dec1 Bad',i6,6i4,' tdec'/68('-')) +1010 format(' SNR Mode d Dop Sync DecN Dec1 Bad',i6,6i4,' tdec'/73('-')) dterr=tsym/4.0 nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) @@ -138,11 +138,11 @@ program test_q65 10 close(10) xdt_avg=0. xdt_rms=0. - write(*,1100) snr1,ndepth,fDop,nsync,ndecn,ndec1,nfalse,naptype, & - tdec/nfiles - write(12,1100) snr1,ndepth,fDop,nsync,ndecn,ndec1,nfalse,naptype, & - tdec/nfiles -1100 format(f5.1,i3,f5.1,3i5,i4,i6,6i4,f6.2) + write(*,1100) snr1,ntrperiod,csubmode,ndepth,fDop,nsync,ndecn, & + ndec1,nfalse,naptype,tdec/nfiles + write(12,1100) snr1,ntrperiod,csubmode,ndepth,fDop,nsync,ndecn, & + ndec1,nfalse,naptype,tdec/nfiles +1100 format(f5.1,i4,a1,i3,f5.1,3i5,i4,i6,6i4,f6.2) if(ndec1.lt.nfiles/2 .and. ndec10.ge.nfiles/2) then snr_thresh=snr1 + float(nfiles/2 - ndec1)/(ndec10-ndec1) open(13,file='snr_thresh.out',status='unknown',position='append') From 09815826e2358b4a8f5843b9717f377622b9a971 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 20 Nov 2020 15:16:23 -0500 Subject: [PATCH 160/206] For Q65 with QSOprogress=3, reduce npasses to 2 (iaptype=3, 4 only); reduce APmast from 78 to 75 bits. --- lib/q65_decode.f90 | 1 - lib/qra/q65/q65_ap.f90 | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 9f49868ca..347621026 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -120,7 +120,6 @@ contains where(apsym0.eq.-1) apsym0=0 npasses=2 - if(nQSOprogress.eq.3 .or.nQSOprogress.eq.4) npasses=4 if(nQSOprogress.eq.5) npasses=3 if(lapcqonly) npasses=1 iaptype=0 diff --git a/lib/qra/q65/q65_ap.f90 b/lib/qra/q65/q65_ap.f90 index b335153c3..6c56cd2f5 100644 --- a/lib/qra/q65/q65_ap.f90 +++ b/lib/qra/q65/q65_ap.f90 @@ -147,7 +147,7 @@ subroutine q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,iaptype, & apmask=0 if(ncontest.le.5 .or. (ncontest.eq.7.and.iaptype.eq.6)) then apmask(1:78)=1 !MyCall, HisCall, RRR|73|RR73 - apmask(59:66)=0 !Reduce the rate of false decodes + apmask(72:74)=0 !Check for , RRR, RR73, 73 apsymbols(1:58)=apsym0 if(iaptype.eq.4) apsymbols(59:77)=mrrr if(iaptype.eq.5) apsymbols(59:77)=m73 From 7ff3d598c80af84011212ac9feb79e1b146f5a5e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 20 Nov 2020 15:40:25 -0500 Subject: [PATCH 161/206] Use g15 = 32403 rather than 32373 for the "RR73" message fragment in Q65. --- lib/qra/q65/genq65.f90 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/qra/q65/genq65.f90 b/lib/qra/q65/genq65.f90 index 300cbf070..4c555748a 100644 --- a/lib/qra/q65/genq65.f90 +++ b/lib/qra/q65/genq65.f90 @@ -26,6 +26,8 @@ subroutine genq65(msg0,ichk,msgsent,itone,i3,n3) i3=-1 n3=-1 call pack77(msg0,i3,n3,c77) + read(c77(60:74),'(b15)') ng15 + if(ng15.eq.32373) c77(60:74)='111111010010011' !Message is RR73 call unpack77(c77,0,msgsent,unpk77_success) !Unpack to get msgsent read(c77,1001) dgen 1001 format(12b6.6,b5.5) From d9cb87054057d3fcc7b6761134c5bf7b5a177aa6 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 20 Nov 2020 17:07:11 -0500 Subject: [PATCH 162/206] Adjust Q65 jitter-loop ranges according to ndepth. --- lib/qra/q65/q65_loops.f90 | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index a3d62e765..8ca0b322c 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -25,16 +25,20 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & allocate(c0(0:npts2-1)) irc=-99 s3lim=20. -! ibwmax=11 -! if(mode64.le.4) ibwmax=9 -! ibwmin=ibwmax -! idtmax=3 -! call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist) - idfmax=5 - idtmax=5 + + idfmax=3 + idtmax=3 ibwmin=1 ibwmax=2 maxdist=15 + if(ndepth.ge.2) then + idfmax=5 + idtmax=5 + maxdist=25 + endif + if(ndepth.eq.3) then + ibwmax=5 + endif LL=64*(mode64+2) NN=63 napmin=99 From 6da4be174c49d4b7344d3ec6e9de5e28f42a2598 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 21 Nov 2020 09:39:37 -0500 Subject: [PATCH 163/206] We now have only 4 levels of AP decoding. Modify test_q65 accordingly. --- lib/test_q65.f90 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 4aa452458..0c71d64a5 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -4,7 +4,7 @@ program test_q65 character*22 msg character*8 arg character*1 csubmode - integer naptype(0:6) + integer naptype(0:4) logical decok nargs=iargc() @@ -89,9 +89,9 @@ program test_q65 !1000 format(/'Depth:',i2,' AP:',i2,' df:',i3,' dt:',i3,' bw1:',i3,' bw2:',i3, & ! ' dist:',i3) - write(*,1010) (j,j=0,6) - write(12,1010) (j,j=0,6) -1010 format(' SNR Mode d Dop Sync DecN Dec1 Bad',i6,6i4,' tdec'/73('-')) + write(*,1010) (j,j=0,4) + write(12,1010) (j,j=0,4) +1010 format(' SNR Mode d Dop Sync DecN Dec1 Bad',5i5,' tdec'/70('-')) dterr=tsym/4.0 nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) @@ -142,7 +142,7 @@ program test_q65 ndec1,nfalse,naptype,tdec/nfiles write(12,1100) snr1,ntrperiod,csubmode,ndepth,fDop,nsync,ndecn, & ndec1,nfalse,naptype,tdec/nfiles -1100 format(f5.1,i4,a1,i3,f5.1,3i5,i4,i6,6i4,f6.2) +1100 format(f5.1,i4,1x,a1,i3,f5.1,3i5,i4,i6,4i5,f6.2) if(ndec1.lt.nfiles/2 .and. ndec10.ge.nfiles/2) then snr_thresh=snr1 + float(nfiles/2 - ndec1)/(ndec10-ndec1) open(13,file='snr_thresh.out',status='unknown',position='append') From 8e4ed9b3bea6abc12465c138c39c28e36c4268b2 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 21 Nov 2020 10:12:46 -0500 Subject: [PATCH 164/206] Fix a bug in jt65_decode: crash when Rx Freq is set too close to upper freq limit on waterfall. --- lib/jt65_decode.f90 | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/jt65_decode.f90 b/lib/jt65_decode.f90 index 5242b6efe..bfb78b254 100644 --- a/lib/jt65_decode.f90 +++ b/lib/jt65_decode.f90 @@ -179,6 +179,7 @@ contains ia=max(1,nint((nfa-100)/df)) ib=min(NSZ,nint((nfb+100)/df)) nz=ib-ia+1 + if(nz.lt.50) go to 900 call lorentzian(savg(ia),nz,a) baseline=a(1) amp=a(2) From 4bd7fcb4a10eb9eaa736b86993be7f7ac89c8397 Mon Sep 17 00:00:00 2001 From: Nico Palermo/IV3NWV Date: Sat, 21 Nov 2020 17:00:15 +0100 Subject: [PATCH 165/206] added likelihood check for better false rejection - added function q65_decode_fullaplist for full-ap decoding of a list of codewords --- lib/qra/q65/q65.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++- lib/qra/q65/q65.h | 18 ++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) diff --git a/lib/qra/q65/q65.c b/lib/qra/q65/q65.c index 856d8d7a7..03b5219f5 100644 --- a/lib/qra/q65/q65.c +++ b/lib/qra/q65/q65.c @@ -26,6 +26,12 @@ #include "q65.h" #include "pdmath.h" +// Minimum codeword loglikelihood for decoding +#define Q65_LLH_THRESHOLD -260.0f + +// This value produce the same WER performance in decode_fullaplist +// #define Q65_LLH_THRESHOLD -262.0f + static int _q65_crc6(int *x, int sz); static void _q65_crc12(int *y, int *x, int sz); @@ -608,8 +614,13 @@ int q65_decode(q65_codec_ds *pCodec, int* pDecodedCodeword, int *pDecodedMsg, co if (pDecodedMsg) memcpy(pDecodedMsg,px,nK*sizeof(int)); - if (pDecodedCodeword==NULL) // user is not interested in it +#ifndef Q65_CHECKLLH + if (pDecodedCodeword==NULL) // user is not interested in the decoded codeword return rc; // return the number of iterations required to decode +#else + if (pDecodedCodeword==NULL) // we must have a buffer + return Q65_DECODE_INVPARAMS; // return error +#endif // crc matches therefore we can reconstruct the transmitted codeword // reencoding the information available in px... @@ -632,11 +643,83 @@ int q65_decode(q65_codec_ds *pCodec, int* pDecodedCodeword, int *pDecodedMsg, co memcpy(pDecodedCodeword,py,nN*sizeof(int)); // no puncturing } +#ifdef Q65_CHECKLLH + if (q65_check_llh(NULL,pDecodedCodeword, nN, nM, pIntrinsics)==0) // llh less than threshold + return Q65_DECODE_LLHLOW; +#endif + return rc; // return the number of iterations required to decode } +// Compute and verify the loglikelihood of the decoded codeword +int q65_check_llh(float *llh, const int* ydec, const int nN, const int nM, const float *pIntrin) +{ + int k; + float t = 0; + + for (k=0;k=Q65_LLH_THRESHOLD); +} + +// Full AP decoding from a list of codewords +int q65_decode_fullaplist(q65_codec_ds *codec, + int *ydec, + int *xdec, + const float *pIntrinsics, + const int *pCodewords, + const int nCodewords) +{ + int k; + int nK, nN, nM; + + float llh; + float maxllh = Q65_LLH_THRESHOLD-1; // set to a value less than the threshold + int maxcw = -1; // index of the most likely codeword + const int *pCw; + + if (nCodewords<1 || nCodewords>Q65_FULLAPLIST_SIZE) + return Q65_DECODE_INVPARAMS; // invalid list length + + nK = q65_get_message_length(codec); + nN = q65_get_codeword_length(codec); + nM = q65_get_alphabet_size(codec); + + // compute codewords log likelihoods and find max + pCw = pCodewords; // start from the first codeword + for (k=0;kmaxllh) { + maxllh = llh; + maxcw = k; + } + // point to next codeword + pCw+=nN; + } + + if (maxcw<0) // no llh larger than threshold found + return Q65_DECODE_FAILED; + + pCw = pCodewords+nN*maxcw; + memcpy(ydec,pCw,nN*sizeof(int)); + memcpy(xdec,pCw,nK*sizeof(int)); + + return maxcw; // index to the decoded message (>=0) + +} + + + // helper functions ------------------------------------------------------------- diff --git a/lib/qra/q65/q65.h b/lib/qra/q65/q65.h index d36cb608f..bd80a934c 100644 --- a/lib/qra/q65/q65.h +++ b/lib/qra/q65/q65.h @@ -28,10 +28,18 @@ #define Q65_DECODE_INVPARAMS -1 #define Q65_DECODE_FAILED -2 #define Q65_DECODE_CRCMISMATCH -3 +#define Q65_DECODE_LLHLOW -4 +#define Q65_DECODE_UNDETERR -5 + +// Verify loglikelihood after successful decoding +#define Q65_CHECKLLH +// Max codeword list size in q65_decode_fullaplist +#define Q65_FULLAPLIST_SIZE 64 // maximum number of weights for the fast-fading metric evaluation #define Q65_FASTFADING_MAXWEIGTHS 65 + typedef struct { const qracode *pQraCode; // qra code to be used by the codec float decoderEsNoMetric; // value for which we optimize the decoder metric @@ -72,6 +80,13 @@ int q65_decode(q65_codec_ds *pCodec, const int *pAPMask, const int *pAPSymbols); +int q65_decode_fullaplist(q65_codec_ds *codec, + int *ydec, + int *xdec, + const float *pIntrinsics, + const int *pCodewords, + const int nCodewords); + int q65_esnodb(const q65_codec_ds *pCodec, float *pEsNodB, const int *ydec, @@ -100,4 +115,7 @@ static void _q65_mask(const qracode *pcode, float *ix, const int *mask, const in int _q65_get_alphabet_size(const qracode *pCode); int _q65_get_bits_per_symbol(const qracode *pCode); +// internally used but made public for threshold optimization +int q65_check_llh(float *llh, const int* ydec, const int nN, const int nM, const float *pIntrin); + #endif // _qra65_h From b2833fd6f08cf29b167e049d8518f92754b008b3 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 21 Nov 2020 11:34:17 -0500 Subject: [PATCH 166/206] Fix the use of ndepth for setting jitter-loop limits. --- lib/qra/q65/q65_loops.f90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 8ca0b322c..1e1576556 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -30,13 +30,13 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & idtmax=3 ibwmin=1 ibwmax=2 - maxdist=15 - if(ndepth.ge.2) then + maxdist=5 + if(iand(ndepth,3).ge.2) then idfmax=5 idtmax=5 - maxdist=25 + maxdist=15 endif - if(ndepth.eq.3) then + if(iand(ndepth,3).eq.3) then ibwmax=5 endif LL=64*(mode64+2) From 9c51e93f067cf77db598c78df4ae89e99fca31d1 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 22 Nov 2020 13:58:29 -0500 Subject: [PATCH 167/206] Implement Nico's "deep likelihood" to replace iaptype=4 and 75-bit APmask. --- lib/q65_decode.f90 | 14 ++++++++++++-- lib/qra/q65/q65_ap.f90 | 4 ++-- lib/qra/q65/q65_loops.f90 | 18 ++++++++++++------ lib/qra/q65/q65_subs.c | 39 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 63 insertions(+), 12 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 347621026..4269a3cc8 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -58,6 +58,8 @@ contains integer apsym0(58),aph10(10) integer apmask1(78),apsymbols1(78) integer apmask(13),apsymbols(13) + integer dgen(13) + integer codewords(63,64) logical lapcqonly,unpk77_success complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s @@ -88,7 +90,6 @@ contains this%callback => callback if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning nFadingModel=1 -! call qra_params(ndepth,maxaptype,idfmax,idtmax,ibwmin,ibwmax,maxdist) call timer('sync_q65',0) call sync_q65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0, & snr1,width) @@ -135,17 +136,26 @@ contains 1060 format(13b6.6) write(c78,1050) apsymbols1 read(c78,1060) apsymbols + 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 endif call timer('q65loops',0) call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & nFadingModel,ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols, & - snr1,xdt1,f1,snr2,irc,dat4) + codewords,snr1,xdt1,f1,snr2,irc,dat4) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) if(irc.ge.0) exit enddo 100 decoded=' ' +! if(irc.lt.0 .and.iaptype.eq.4) print*,'AAA',irc,iaptype if(irc.ge.0) then !### navg=irc/100 diff --git a/lib/qra/q65/q65_ap.f90 b/lib/qra/q65/q65_ap.f90 index 6c56cd2f5..32e26a4ed 100644 --- a/lib/qra/q65/q65_ap.f90 +++ b/lib/qra/q65/q65_ap.f90 @@ -149,8 +149,8 @@ subroutine q65_ap(nQSOprogress,ipass,ncontest,lapcqonly,iaptype, & apmask(1:78)=1 !MyCall, HisCall, RRR|73|RR73 apmask(72:74)=0 !Check for , RRR, RR73, 73 apsymbols(1:58)=apsym0 - if(iaptype.eq.4) apsymbols(59:77)=mrrr - if(iaptype.eq.5) apsymbols(59:77)=m73 + if(iaptype.eq.4) apsymbols(59:77)=mrrr + if(iaptype.eq.5) apsymbols(59:77)=m73 if(iaptype.eq.6) apsymbols(59:77)=mrr73 else if(ncontest.eq.7.and.iaptype.eq.4) then ! Hound listens for MyCall RR73;... apmask(1:28)=1 diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 1e1576556..5f680f18a 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,6 +1,6 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & - ndepth,jpk0,xdt0,f0,width,iaptype,APmask,APsymbols,snr1,xdt1,f1, & - snr2,irc,dat4) + ndepth,jpk0,xdt0,f0,width,iaptype,APmask,APsymbols,codewords,snr1, & + xdt1,f1,snr2,irc,dat4) use packjt77 use timer_module, only: timer @@ -16,6 +16,7 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & logical unpk77_success integer APmask(13) integer APsymbols(13) + integer codewords(63,64) integer dat4(13) !Decoded message (as 13 six-bit integers) integer nap(0:11) !AP return codes data nap/0,2,3,2,3,4,2,3,6,4,6,6/,nsave/0/ @@ -86,10 +87,15 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & call timer('q65_intr',0) call q65_intrinsics_ff(s3,nsubmode,b90,nFadingModel,s3prob) call timer('q65_intr',1) - - call timer('q65_dec ',0) - call q65_dec(s3,s3prob,APmask,APsymbols,esnodb,dat4,irc) - call timer('q65_dec ',1) + if(iaptype.eq.4) then + call timer('q65_apli',0) + call q65_dec_fullaplist(s3,s3prob,codewords,3,esnodb,dat4,irc) + call timer('q65_apli',1) + else + call timer('q65_dec ',0) + call q65_dec(s3,s3prob,APmask,APsymbols,esnodb,dat4,irc) + call timer('q65_dec ',1) + endif if(irc.ge.0) go to 100 ! irc > 0 ==> number of iterations required to decode ! -1 = invalid params diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c index b36adc540..688ef899a 100644 --- a/lib/qra/q65/q65_subs.c +++ b/lib/qra/q65/q65_subs.c @@ -80,11 +80,12 @@ void q65_dec_(float s3[], float s3prob[], int APmask[], int APsymbols[], float* esnodb0, int xdec[], int* rc0) { -/* Input: s3prob[LL,NN] Symbol-value intrinsic probabilities +/* Input: s3[LL,NN] Symbol spectra + * s3prob[LL,NN] Symbol-value intrinsic probabilities * APmask[13] AP information to be used in decoding * APsymbols[13] Available AP informtion * Output: - * esnodb0 Estimated Es/No in dB + * esnodb0 Estimated Es/No (dB) * xdec[13] Decoded 78-bit message as 13 six-bit integers * rc0 Return code from q65_decode() */ @@ -108,3 +109,37 @@ void q65_dec_(float s3[], float s3prob[], int APmask[], int APsymbols[], } *esnodb0 = esnodb; } + +void q65_dec_fullaplist_(float s3[], float s3prob[], int codewords[], + int* ncw, float* esnodb0, int xdec[], int* rc0) +{ +/* Input: s3[LL,NN] Symbol spectra + * s3prob[LL,NN] Symbol-value intrinsic probabilities + * codewords[63,ncw] Full codewords to search for + * ncw Number of codewords + * Output: + * esnodb0 Estimated Es/No (dB) + * xdec[13] Decoded 78-bit message as 13 six-bit integers + * rc0 Return code from q65_decode() + */ + + int rc; + int ydec[63]; + float esnodb; + + rc = q65_decode_fullaplist(&codec,ydec,xdec,s3prob,codewords,*ncw); + *rc0=rc; + + // rc = -1: Invalid params + // rc = -2: Decode failed + // rc = -3: CRC mismatch + *esnodb0 = 0.0; //Default Es/No for a failed decode + if(rc<0) return; + + rc = q65_esnodb_fastfading(&codec,&esnodb,ydec,s3); + if(rc<0) { + printf("error in q65_esnodb_fastfading()\n"); + exit(0); + } + *esnodb0 = esnodb; +} From 6fa9f76a7575449a1960c9b24dfee74ff95620f5 Mon Sep 17 00:00:00 2001 From: Nico Palermo/IV3NWV Date: Mon, 23 Nov 2020 06:03:59 +0100 Subject: [PATCH 168/206] Interface to q65_intrinsics_fastfading changed to support B90Ts instead of B90 and then supporting correctly modes with any T/R interval --- lib/q65_decode.f90 | 6 +++++- lib/qra/q65/q65.c | 24 ++++++++++++------------ lib/qra/q65/q65.h | 2 +- lib/qra/q65/q65_loops.f90 | 5 +++-- lib/qra/q65/q65_subs.c | 4 ++-- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 347621026..76b8faec9 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -137,9 +137,13 @@ contains read(c78,1060) apsymbols endif call timer('q65loops',0) +! call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & +! nFadingModel,ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols, & +! snr1,xdt1,f1,snr2,irc,dat4) +! baud rate required to compute B90TS later call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & nFadingModel,ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols, & - snr1,xdt1,f1,snr2,irc,dat4) + snr1,xdt1,f1,snr2,irc,dat4,baud) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) if(irc.ge.0) exit diff --git a/lib/qra/q65/q65.c b/lib/qra/q65/q65.c index 03b5219f5..c91571ba6 100644 --- a/lib/qra/q65/q65.c +++ b/lib/qra/q65/q65.c @@ -277,9 +277,9 @@ int q65_esnodb(const q65_codec_ds *pCodec, float *pEsNodB, const int *ydec, cons // Symbol time interval in seconds #define TS_QRA64 0.576 -#define TS_Q65 0.640 +// #define TS_Q65 0.640 // T/R = 60 s // The tables are computed assuming that the bin spacing is that of QRA64, that's to say -// 1/Ts = 12000/6912 Hz, but in q65 Ts is longer (0.640 s) and the table index +// 1/Ts = 12000/6912 Hz, but in Q65 Ts depends on the T/R interval and the table index // corresponding to a given B90 must be scaled appropriately. // See below. @@ -287,7 +287,7 @@ int q65_intrinsics_fastfading(q65_codec_ds *pCodec, float *pIntrinsics, // intrinsic symbol probabilities output const float *pInputEnergies, // received energies input const int submode, // submode idx (0=A ... 4=E) - const float B90, // spread bandwidth (90% fractional energy) + const float B90Ts, // spread bandwidth (90% fractional energy) const int fadingModel) // 0=Gaussian 1=Lorentzian fade model { int n, k, j; @@ -295,26 +295,26 @@ int q65_intrinsics_fastfading(q65_codec_ds *pCodec, int hidx, hlen, hhsz, hlast; const float *hptr; float fTemp, fNoiseVar, sumix, maxlogp; - float EsNoMetric; + float EsNoMetric,B90; float *weight; const float *pCurSym, *pCurBin; float *pCurIx; +// printf("pcodec=%08x submode=%d fadingmodel=%d B90Ts=%f\n",pcodec, submode,fadingModel, B90Ts); + if (pCodec==NULL) return Q65_DECODE_INVPARAMS; // invalid pCodec pointer + if (submode<0 || submode>4) return Q65_DECODE_INVPARAMS; // invalid submode - // As the symbol duration in q65 is longer than in QRA64 the fading tables continue - // to be valid if the B90 parameter is scaled by the actual symbol rate + // As the symbol duration in q65 is different than in QRA64, + // the fading tables continue to be valid if the B90Ts parameter + // is properly scaled to the QRA64 symbol interval // Compute index to most appropriate weighting function coefficients - hidx = (int)(logf(B90*TS_Q65/TS_QRA64)/logf(1.09f) - 0.499f); - -// if (hidx<0 || hidx > 64) -// // index of weighting function out of range -// // B90 out of range -// return q65_DECODE_INVPARAMS; + B90 = B90Ts/TS_QRA64; + hidx = (int)(logf(B90)/logf(1.09f) - 0.499f); // Unlike in QRA64 we accept any B90, anyway limiting it to // the extreme cases (0.9 to 210 Hz approx.) diff --git a/lib/qra/q65/q65.h b/lib/qra/q65/q65.h index bd80a934c..2e764a32b 100644 --- a/lib/qra/q65/q65.h +++ b/lib/qra/q65/q65.h @@ -69,7 +69,7 @@ int q65_intrinsics_fastfading(q65_codec_ds *pCodec, float *pIntrinsics, // intrinsic symbol probabilities output const float *pInputEnergies, // received energies input const int submode, // submode idx (0=A ... 4=E) - const float B90, // spread bandwidth (90% fractional energy) + const float B90Ts, // normalized spread bandwidth (90% fractional energy) const int fadingModel); // 0=Gaussian 1=Lorentzian fade model diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 1e1576556..1a976e26b 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,6 +1,6 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & ndepth,jpk0,xdt0,f0,width,iaptype,APmask,APsymbols,snr1,xdt1,f1, & - snr2,irc,dat4) + snr2,irc,dat4,baud) use packjt77 use timer_module, only: timer @@ -84,7 +84,8 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & if(b90.gt.230.0) cycle ! if(b90.lt.0.15*width) exit call timer('q65_intr',0) - call q65_intrinsics_ff(s3,nsubmode,b90,nFadingModel,s3prob) + b90ts = b90/baud + call q65_intrinsics_ff(s3,nsubmode,b90ts,nFadingModel,s3prob) call timer('q65_intr',1) call timer('q65_dec ',0) diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c index b36adc540..9d765c86b 100644 --- a/lib/qra/q65/q65_subs.c +++ b/lib/qra/q65/q65_subs.c @@ -46,7 +46,7 @@ void q65_enc_(int x[], int y[]) q65_encode(&codec,y,x); } -void q65_intrinsics_ff_(float s3[], int* submode, float* B90, +void q65_intrinsics_ff_(float s3[], int* submode, float* B90Ts, int* fadingModel, float s3prob[]) { @@ -69,7 +69,7 @@ void q65_intrinsics_ff_(float s3[], int* submode, float* B90, } first=0; } - rc = q65_intrinsics_fastfading(&codec,s3prob,s3,*submode,*B90,*fadingModel); + rc = q65_intrinsics_fastfading(&codec,s3prob,s3,*submode,*B90Ts,*fadingModel); if(rc<0) { printf("error in q65_intrinsics()\n"); exit(0); From cbfb6dd25029a410bfea204cca17c152f45c0ead Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 23 Nov 2020 14:30:36 -0500 Subject: [PATCH 169/206] Implement full-message sync possibility when QSOprogress > 0. --- lib/q65_decode.f90 | 4 ++-- lib/qra/q65/q65_loops.f90 | 19 +++++++++++----- lib/sync_q65.f90 | 47 +++++++++++++++++++++++++++------------ 3 files changed, 48 insertions(+), 22 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 86d9264ab..9fffe9530 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -91,8 +91,8 @@ contains if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning nFadingModel=1 call timer('sync_q65',0) - call sync_q65(iwave,ntrperiod*12000,mode65,nsps,nfqso,ntol,xdt,f0, & - snr1,width) + call sync_q65(iwave,ntrperiod*12000,mode65,nQSOprogress,nsps,nfqso, & + ntol,xdt,f0,snr1,width) call timer('sync_q65',1) irc=-9 diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 72eade730..e1eac4e0e 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,10 +1,10 @@ -subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & +subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & ndepth,jpk0,xdt0,f0,width,iaptype,APmask,APsymbols,codewords,snr1, & xdt1,f1,snr2,irc,dat4) use packjt77 use timer_module, only: timer - parameter (LN=2176*63) !LN=LL*NN; LL = 64*(mode64+2) + parameter (LN=2176*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63 character*37 decoded character*77 c77 complex c00(0:npts2-1) !Analytic representation of dd(), 6000 Hz @@ -17,9 +17,15 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & integer APmask(13) integer APsymbols(13) integer codewords(63,64) +! integer cw4(63) integer dat4(13) !Decoded message (as 13 six-bit integers) integer nap(0:11) !AP return codes data nap/0,2,3,2,3,4,2,3,6,4,6,6/,nsave/0/ +! data cw4/0, 0, 0, 0, 8, 4,60,35,17,48,33,25,34,43,43,43,35,15,46,30, & +! 54,24,26,26,57,57,42, 3,23,11,49,49,16, 2, 6, 6,55,21,39,51, & +! 51,51,42,42,50,25,31,35,57,30, 1,54,54,10,10,22,44,58,57,40, & +! 21,21,19/ + save nsave,s3avg ircbest=9999 @@ -40,7 +46,7 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & if(iand(ndepth,3).eq.3) then ibwmax=5 endif - LL=64*(mode64+2) + LL=64*(mode_q65+2) NN=63 napmin=99 baud=6000.0/nsps @@ -67,7 +73,7 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & jpk=jpk0 + nsps*ndt/16 !tsym/16 if(jpk.lt.0) jpk=0 call timer('spec64 ',0) - call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) + call spec64(c0,nsps,mode,mode_q65,jpk,s3,LL,NN) call timer('spec64 ',1) call pctile(s3,LL*NN,40,base) s3=s3/base @@ -85,10 +91,11 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & if(b90.gt.230.0) cycle ! if(b90.lt.0.15*width) exit call timer('q65_intr',0) - b90ts = b90/baud + b90ts = b90/baud call q65_intrinsics_ff(s3,nsubmode,b90ts,nFadingModel,s3prob) call timer('q65_intr',1) if(iaptype.eq.4) then +! codewords(1:63,4)=cw4 call timer('q65_apli',0) call q65_dec_fullaplist(s3,s3prob,codewords,3,esnodb,dat4,irc) call timer('q65_apli',1) @@ -111,7 +118,7 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode64,nsubmode,nFadingModel, & call twkfreq(c00,c0,npts2,6000.0,a) jpk=3000 !### Are these definitions OK? if(nsps.ge.3600) jpk=6000 !### TR >= 60 s - call spec64(c0,nsps,mode,mode64,jpk,s3,LL,NN) + call spec64(c0,nsps,mode,mode_q65,jpk,s3,LL,NN) call pctile(s3,LL*NN,40,base) s3=s3/base where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim diff --git a/lib/sync_q65.f90 b/lib/sync_q65.f90 index 1839aab0a..c802c27b0 100644 --- a/lib/sync_q65.f90 +++ b/lib/sync_q65.f90 @@ -1,4 +1,5 @@ -subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) +subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & + xdt,f0,snr1,width) ! Detect and align with the Q65 sync vector, returning time and frequency ! offsets and SNR estimate. @@ -13,6 +14,7 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) ! snr1 Relative SNR of sync signal parameter (NSTEP=8) !Step size nsps/NSTEP + parameter (LN=2176*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63 character*37 msg,msgsent integer*2 iwave(0:nmax-1) !Raw data integer isync(22) !Indices of sync symbols @@ -20,7 +22,9 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) real, allocatable :: s1(:,:) !Symbol spectra, quarter-symbol steps real, allocatable :: ccf(:,:) !CCF(freq,lag) real, allocatable :: ccf1(:) !CCF(freq) at best lag - real sync(85) !sync vector + real sync(85) !sync vector + real s3(LN) !Symbol spectra + real s3prob(LN) !Symbol-value probabilities complex, allocatable :: c0(:) !Complex spectrum of symbol data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data sync(1)/99.0/ @@ -147,14 +151,15 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) width=i*1.414*df !### Experimental: - nQSOprogress=3 if(nQSOprogress.lt.1) go to 900 ! "Deep Likelihood" decode attempt - do imsg=1,3 + snr1a_best=0. + do imsg=1,4 ccf=0. msg='K1ABC W9XYZ RRR' if(imsg.eq.2) msg='K1ABC W9XYZ RR73' if(imsg.eq.3) msg='K1ABC W9XYZ 73' + if(imsg.eq.4) msg='CQ K9AN EN50' call genq65(msg,0,msgsent,itone,i3,n3) do lag=lag1,lag2 @@ -196,19 +201,33 @@ subroutine sync_q65(iwave,nmax,mode65,nsps,nfqso,ntol,xdt,f0,snr1,width) rms=sqrt(sq/nsq) smax=ccf(ipk,jpk) snr1a=smax/rms - write(57,3001) imsg,xdt,xdta,f0,f0a,snr1,snr1a -3001 format(i1,6f8.2) + if(snr1a.gt.snr1a_best) then + snr1a_best=snr1a + imsg_best=imsg + xdta_best=xdta + f0a_best=f0a + endif +! write(57,3001) imsg,xdt,xdta,f0,f0a,snr1,snr1a +!3001 format(i1,6f8.2) - do j=lag1,lag2 - write(55,3055) j,j*dtstep,ccf(ipk,j)/rms -3055 format(i5,f8.3,f10.3) - enddo +! do j=lag1,lag2 +! write(55,3055) j,j*dtstep,ccf(ipk,j)/rms +!3055 format(i5,f8.3,f10.3) +! enddo - do i=-ia,ia - write(56,3056) i*df,ccf(i,jpk)/rms -3056 format(2f10.3) - enddo +! do i=-ia,ia +! write(56,3056) i*df,ccf(i,jpk)/rms +!3056 format(2f10.3) +! enddo enddo + if(snr1a_best.gt.2.0) then + xdt=xdta_best + f0=f0a_best + snr1=1.4*snr1a_best + endif + +! write(58,3006) xdta_best,f0a_best,snr1a_best,imsg_best +!3006 format(3f8.2,i3) 900 return end subroutine sync_q65 From f0a1694816934fd1d17aac0bd40cf7d3940c787e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 28 Nov 2020 10:12:12 -0500 Subject: [PATCH 170/206] Minor code cleanup. --- lib/sync_q65.f90 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/sync_q65.f90 b/lib/sync_q65.f90 index c802c27b0..5b8847e3e 100644 --- a/lib/sync_q65.f90 +++ b/lib/sync_q65.f90 @@ -19,12 +19,10 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & integer*2 iwave(0:nmax-1) !Raw data integer isync(22) !Indices of sync symbols integer itone(85) - real, allocatable :: s1(:,:) !Symbol spectra, quarter-symbol steps + real, allocatable :: s1(:,:) !Symbol spectra, 1/8-symbol steps real, allocatable :: ccf(:,:) !CCF(freq,lag) real, allocatable :: ccf1(:) !CCF(freq) at best lag real sync(85) !sync vector - real s3(LN) !Symbol spectra - real s3prob(LN) !Symbol-value probabilities complex, allocatable :: c0(:) !Complex spectrum of symbol data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data sync(1)/99.0/ From 64516e6abbd21ccbd1698daf04693e5ec9432cf2 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 29 Nov 2020 10:00:33 -0500 Subject: [PATCH 171/206] Still testing various parts of the Q65 decoding chain. --- lib/q65_decode.f90 | 16 ---------------- lib/qra/q65/q65_loops.f90 | 39 ++++++++++++++++++++++----------------- lib/sync_q65.f90 | 8 ++++---- 3 files changed, 26 insertions(+), 37 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 9fffe9530..304ca45b4 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -102,18 +102,6 @@ contains if(jpk0.lt.0) jpk0=0 fac=1.0/32767.0 dd=fac*iwave(1:npts) -!### -! Optionslly write noise level to LU 56 -! sq=dot_product(dd,dd)/npts -! m=nutc -! if(ntrperiod.ge.60) m=100*m -! ihr=m/10000 -! imin=mod(m/100,100) -! isec=mod(m,100) -! hours=ihr + imin/60.0 + isec/3600.0 -! write(56,3056) m,hours,db(sq)+90.3 -!3056 format(i6.6,f10.6,f10.3) -!### nmode=65 call ana64(dd,npts,c00) @@ -146,10 +134,6 @@ contains endif endif call timer('q65loops',0) -! call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & -! nFadingModel,ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols, & -! snr1,xdt1,f1,snr2,irc,dat4) -! baud rate required to compute B90TS later call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & nFadingModel,ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols, & codewords,snr1,xdt1,f1,snr2,irc,dat4) diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index e1eac4e0e..bb1033771 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -4,7 +4,8 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & use packjt77 use timer_module, only: timer - parameter (LN=2176*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63 + parameter (NN=63) + parameter (LN=1152*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63 character*37 decoded character*77 c77 complex c00(0:npts2-1) !Analytic representation of dd(), 6000 Hz @@ -12,19 +13,19 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & real a(3) !twkfreq params f,f1,f2 real s3(LN) !Symbol spectra real s3avg(LN) !Averaged symbol spectra - real s3prob(LN) !Symbol-value probabilities + real s3prob(64*NN) !Symbol-value probabilities logical unpk77_success integer APmask(13) integer APsymbols(13) integer codewords(63,64) -! integer cw4(63) + integer cw4(63) integer dat4(13) !Decoded message (as 13 six-bit integers) integer nap(0:11) !AP return codes data nap/0,2,3,2,3,4,2,3,6,4,6,6/,nsave/0/ -! data cw4/0, 0, 0, 0, 8, 4,60,35,17,48,33,25,34,43,43,43,35,15,46,30, & -! 54,24,26,26,57,57,42, 3,23,11,49,49,16, 2, 6, 6,55,21,39,51, & -! 51,51,42,42,50,25,31,35,57,30, 1,54,54,10,10,22,44,58,57,40, & -! 21,21,19/ + data cw4/0, 0, 0, 0, 8, 4,60,35,17,48,33,25,34,43,43,43,35,15,46,30, & + 54,24,26,26,57,57,42, 3,23,11,49,49,16, 2, 6, 6,55,21,39,51, & + 51,51,42,42,50,25,31,35,57,30, 1,54,54,10,10,22,44,58,57,40, & + 21,21,19/ save nsave,s3avg @@ -47,12 +48,11 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & ibwmax=5 endif LL=64*(mode_q65+2) - NN=63 napmin=99 baud=6000.0/nsps xdt1=xdt0 f1=f0 - + maxavg=0 if(iand(ndepth,16).ne.0) maxavg=1 do iavg=0,maxavg @@ -79,8 +79,10 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & s3=s3/base where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim endif - if(iavg.eq.1) then + kavg=0 + if(iavg.eq.1 .and. nsave.ge.2) then s3(1:LL*NN)=s3avg(1:LL*NN) + kavg=nsave endif do ibw=ibwmin,ibwmax nbw=ibw @@ -91,19 +93,22 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & if(b90.gt.230.0) cycle ! if(b90.lt.0.15*width) exit call timer('q65_intr',0) - b90ts = b90/baud + b90ts = b90/baud call q65_intrinsics_ff(s3,nsubmode,b90ts,nFadingModel,s3prob) call timer('q65_intr',1) if(iaptype.eq.4) then -! codewords(1:63,4)=cw4 + codewords(1:63,4)=cw4 call timer('q65_apli',0) - call q65_dec_fullaplist(s3,s3prob,codewords,3,esnodb,dat4,irc) + call q65_dec_fullaplist(s3,s3prob,codewords,4,esnodb,dat4,irc) call timer('q65_apli',1) else call timer('q65_dec ',0) call q65_dec(s3,s3prob,APmask,APsymbols,esnodb,dat4,irc) call timer('q65_dec ',1) endif +! write(71,3071) 100*nutc,0.0,ndf,ndt,nbw,ndist,irc,iaptype, & +! kavg,nsave +!3071 format(i6.6,f8.4,8i5) if(irc.ge.0) go to 100 ! irc > 0 ==> number of iterations required to decode ! -1 = invalid params @@ -122,16 +127,16 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & call pctile(s3,LL*NN,40,base) s3=s3/base where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim - s3avg(1:LL*NN)=s3avg(1:LL*NN)+s3(1:LL*NN) + s3avg(1:LL*NN)=s3avg(1:LL*NN) + s3(1:LL*NN) nsave=nsave+1 endif if(iavg.eq.0 .and. nsave.lt.2) exit enddo ! iavg -100 if(irc.ge.0) then +100 if(irc.ge.0) then navg=nsave snr2=esnodb - db(2500.0/baud) - if(iavg.eq.0) navg=0 + if(kavg.eq.0) navg=0 xdt1=xdt0 + nsps*ndt/(16.0*6000.0) f1=f0 + 0.5*baud*ndf !### For tests only: @@ -145,7 +150,7 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & imin=mod(m/100,100) isec=mod(m,100) hours=ihr + imin/60.0 + isec/3600.0 - write(53,3053) m,hours,ndf,ndt,nbw,ndist,irc,iaptype,navg,snr1, & + write(53,3053) m,hours,ndf,ndt,nbw,ndist,irc,iaptype,kavg,snr1, & xdt1,f1,snr2,trim(decoded) 3053 format(i6.6,f8.4,4i3,i4,2i3,f6.1,f6.2,f7.1,f6.1,1x,a) close(53) diff --git a/lib/sync_q65.f90 b/lib/sync_q65.f90 index 5b8847e3e..201d2a080 100644 --- a/lib/sync_q65.f90 +++ b/lib/sync_q65.f90 @@ -28,7 +28,7 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & data sync(1)/99.0/ save sync - nfft=2*nsps + nfft=nsps df=12000.0/nfft !Freq resolution = 0.5*baud istep=nsps/NSTEP iz=5000.0/df !Uppermost frequency bin, at 5000 Hz @@ -165,7 +165,7 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & j=j0 + NSTEP*(k-1) + 1 + lag if(j.ge.1 .and. j.le.jz) then do i=-ia,ia - ii=i0+2*itone(k)+i + ii=i0+itone(k)+i ccf(i,lag)=ccf(i,lag) + s1(ii,j) enddo endif @@ -207,7 +207,7 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & endif ! write(57,3001) imsg,xdt,xdta,f0,f0a,snr1,snr1a !3001 format(i1,6f8.2) - + ! do j=lag1,lag2 ! write(55,3055) j,j*dtstep,ccf(ipk,j)/rms !3055 format(i5,f8.3,f10.3) @@ -223,7 +223,7 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & f0=f0a_best snr1=1.4*snr1a_best endif - + ! write(58,3006) xdta_best,f0a_best,snr1a_best,imsg_best !3006 format(3f8.2,i3) From 9ff6f5b4d3c2359e7ca1bfee80facc3492599873 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 30 Nov 2020 09:52:47 -0500 Subject: [PATCH 172/206] Temporary save, much work in progress. --- CMakeLists.txt | 2 +- lib/q65_decode.f90 | 19 ++++- lib/{sync_q65.f90 => q65_sync.f90} | 129 ++++++++++++++--------------- lib/qra/q65/q65.c | 3 +- lib/qra/q65/q65.h | 2 +- lib/qra/q65/q65_loops.f90 | 34 ++++---- lib/qra/q65/q65_subs.c | 3 +- lib/qra/q65/q65sim.f90 | 30 +++---- 8 files changed, 114 insertions(+), 108 deletions(-) rename lib/{sync_q65.f90 => q65_sync.f90} (74%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d4f630f47..b910350da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -496,6 +496,7 @@ set (wsjt_FSRCS lib/polyfit.f90 lib/prog_args.f90 lib/ps4.f90 + lib/q65_sync.f90 lib/qra64a.f90 lib/qra_loops.f90 lib/qra/q65/q65_ap.f90 @@ -529,7 +530,6 @@ set (wsjt_FSRCS lib/sync4.f90 lib/sync64.f90 lib/sync65.f90 - lib/sync_q65.f90 lib/ft4/getcandidates4.f90 lib/ft4/get_ft4_bitmetrics.f90 lib/ft8/sync8.f90 diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 304ca45b4..819aba0d1 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -90,11 +90,22 @@ contains this%callback => callback if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning nFadingModel=1 + dgen=0 + call q65_enc(dgen,codewords) !Initialize Q65 +! nQSOprogress=3 !### + dat4=0 call timer('sync_q65',0) - call sync_q65(iwave,ntrperiod*12000,mode65,nQSOprogress,nsps,nfqso, & - ntol,xdt,f0,snr1,width) + call q65_sync(iwave,ntrperiod*12000,mode65,nQSOprogress,nsps,nfqso, & + ntol,xdt,f0,snr1,dat4,snr2,irc) call timer('sync_q65',1) - + write(55,3055) nutc,xdt,f0,snr1,snr2,irc +3055 format(i4.4,4f9.2,i5) + if(irc.ge.0) then + xdt1=xdt + f1=f0 + go to 100 + endif + irc=-9 if(snr1.lt.2.8) go to 100 jpk0=(xdt+1.0)*6000 !### Is this OK? @@ -135,7 +146,7 @@ contains endif call timer('q65loops',0) call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & - nFadingModel,ndepth,jpk0,xdt,f0,width,iaptype,apmask,apsymbols, & + nFadingModel,ndepth,jpk0,xdt,f0,iaptype,apmask,apsymbols, & codewords,snr1,xdt1,f1,snr2,irc,dat4) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) diff --git a/lib/sync_q65.f90 b/lib/q65_sync.f90 similarity index 74% rename from lib/sync_q65.f90 rename to lib/q65_sync.f90 index 201d2a080..d81cbd5f8 100644 --- a/lib/sync_q65.f90 +++ b/lib/q65_sync.f90 @@ -1,11 +1,11 @@ -subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & - xdt,f0,snr1,width) +subroutine q65_sync(iwave,nmax,mode_q65,nQSOprogress,nsps,nfqso,ntol, & + xdt,f0,snr1,dat4,snr2,irc) ! Detect and align with the Q65 sync vector, returning time and frequency ! offsets and SNR estimate. ! Input: iwave(0:nmax-1) Raw data -! mode65 Tone spacing 1 2 4 8 16 (A-E) +! mode_q65 Tone spacing 1 2 4 8 16 (A-E) ! nsps Samples per symbol at 12000 Sa/s ! nfqso Target frequency (Hz) ! ntol Search range around nfqso (Hz) @@ -19,17 +19,23 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & integer*2 iwave(0:nmax-1) !Raw data integer isync(22) !Indices of sync symbols integer itone(85) + integer codewords(63,64) + integer dat4(13) + integer ijpk(2) 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 s3prob(0:63,63) !Symbol-value probabilities real sync(85) !sync vector complex, allocatable :: c0(:) !Complex spectrum of symbol data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ data sync(1)/99.0/ save sync + LL=64*(2+mode_q65) nfft=nsps - df=12000.0/nfft !Freq resolution = 0.5*baud + df=12000.0/nfft !Freq resolution = baud istep=nsps/NSTEP iz=5000.0/df !Uppermost frequency bin, at 5000 Hz txt=85.0*nsps/12000.0 @@ -38,6 +44,7 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & ia=ntol/df allocate(s1(iz,jz)) + allocate(s3(-64:LL-65,63)) allocate(c0(0:nfft-1)) allocate(ccf(-ia:ia,-53:214)) allocate(ccf1(-ia:ia)) @@ -66,12 +73,13 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & s1(i,j)=real(c0(i))**2 + aimag(c0(i))**2 enddo ! For large Doppler spreads, should we smooth the spectra here? - call smo121(s1(1:iz,j),iz) +! call smo121(s1(1:iz,j),iz) enddo i0=nint(nfqso/df) !Target QSO frequency call pctile(s1(i0-64:i0+192,1:jz),129*jz,40,base) - s1=s1/base - 1.0 +! s1=s1/base - 1.0 + s1=s1/base ! Apply fast AGC s1max=20.0 !Empirical choice @@ -101,19 +109,9 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & enddo enddo - ic=ntol/df - ccfmax=0. - ipk=0 - jpk=0 - do i=-ic,ic - do j=lag1,lag2 - if(ccf(i,j).gt.ccfmax) then - ipk=i - jpk=j - ccfmax=ccf(i,j) - endif - enddo - enddo + ijpk=maxloc(ccf) + ipk=ijpk(1)-ia-1 + jpk=ijpk(2)-53-1 f0=nfqso + ipk*df xdt=jpk*dtstep @@ -129,28 +127,10 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & smax=ccf(ipk,jpk) snr1=smax/rms -! do j=lag1,lag2 -! write(55,3055) j,j*dtstep,ccf(ipk,j)/rms -!3055 format(i5,f8.3,f10.3) -! enddo +!###################################################################### +! Experimental: Try early list decoding via "Deep Likelihood". -! do i=-ia,ia -! write(56,3056) i*df,ccf(i,jpk)/rms -!3056 format(2f10.3) -! enddo -! flush(56) - - ccf1=ccf(-ia:ia,jpk) - acf0=dot_product(ccf1,ccf1) - do i=1,ia - acf=dot_product(ccf1,cshift(ccf1,i)) - if(acf.le.0.5*acf0) exit - enddo - width=i*1.414*df - -!### Experimental: if(nQSOprogress.lt.1) go to 900 -! "Deep Likelihood" decode attempt snr1a_best=0. do imsg=1,4 ccf=0. @@ -159,7 +139,14 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & if(imsg.eq.3) msg='K1ABC W9XYZ 73' if(imsg.eq.4) msg='CQ K9AN EN50' call genq65(msg,0,msgsent,itone,i3,n3) + j=0 + do k=1,85 + if(sync(k)>0.) cycle + j=j+1 + codewords(j,imsg)=itone(k) - 1 + enddo +! Compute 2D ccf using all 85 symbols in the list message do lag=lag1,lag2 do k=1,85 j=j0 + NSTEP*(k-1) + 1 + lag @@ -172,22 +159,12 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & enddo enddo - ic=ntol/df - ccfmax=0. - ipk=0 - jpk=0 - do i=-ic,ic - do j=lag1,lag2 - if(ccf(i,j).gt.ccfmax) then - ipk=i - jpk=j - ccfmax=ccf(i,j) - endif - enddo - enddo + ijpk=maxloc(ccf) + ipk=ijpk(1)-ia-1 + jpk=ijpk(2)-53-1 f0a=nfqso + ipk*df xdta=jpk*dtstep - + sq=0. nsq=0 do j=lag1,lag2 @@ -205,27 +182,43 @@ subroutine sync_q65(iwave,nmax,mode65,nQSOprogress,nsps,nfqso,ntol, & xdta_best=xdta f0a_best=f0a endif -! write(57,3001) imsg,xdt,xdta,f0,f0a,snr1,snr1a -!3001 format(i1,6f8.2) + enddo ! imsg -! do j=lag1,lag2 -! write(55,3055) j,j*dtstep,ccf(ipk,j)/rms -!3055 format(i5,f8.3,f10.3) -! enddo - -! do i=-ia,ia -! write(56,3056) i*df,ccf(i,jpk)/rms -!3056 format(2f10.3) -! enddo - enddo if(snr1a_best.gt.2.0) then xdt=xdta_best f0=f0a_best snr1=1.4*snr1a_best endif -! write(58,3006) xdta_best,f0a_best,snr1a_best,imsg_best -!3006 format(3f8.2,i3) + ia=i0+ipk-63 + ib=ia+LL-1 + j=j0+jpk-5 + n=0 + do k=1,85 + j=j+8 + if(sync(k).gt.0.0) then + cycle + endif + n=n+1 + s3(-64:LL-65,n)=s1(ia:ib,j) + enddo + + nsubmode=0 + nFadingModel=1 + baud=12000.0/nsps + dat4=0 + irc=-2 + do ibw=0,10 + b90=1.72**ibw + call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) + call q65_dec_fullaplist(s3,s3prob,codewords,4,esnodb,dat4,plog,irc) + if(irc.ge.0) then + xdt=xdta_best + f0=f0a_best + snr2=esnodb - db(2500.0/baud) + exit + endif + enddo 900 return -end subroutine sync_q65 +end subroutine q65_sync diff --git a/lib/qra/q65/q65.c b/lib/qra/q65/q65.c index c91571ba6..c92335007 100644 --- a/lib/qra/q65/q65.c +++ b/lib/qra/q65/q65.c @@ -703,10 +703,11 @@ int q65_decode_fullaplist(q65_codec_ds *codec, maxllh = llh; maxcw = k; } + // printf("BBB %d %f\n",k,llh); // point to next codeword pCw+=nN; } - + q65_llh=maxllh; if (maxcw<0) // no llh larger than threshold found return Q65_DECODE_FAILED; diff --git a/lib/qra/q65/q65.h b/lib/qra/q65/q65.h index 2e764a32b..f48c40da9 100644 --- a/lib/qra/q65/q65.h +++ b/lib/qra/q65/q65.h @@ -39,7 +39,7 @@ // maximum number of weights for the fast-fading metric evaluation #define Q65_FASTFADING_MAXWEIGTHS 65 - +float q65_llh; typedef struct { const qracode *pQraCode; // qra code to be used by the codec float decoderEsNoMetric; // value for which we optimize the decoder metric diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index bb1033771..5c48f85a1 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,5 +1,5 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & - ndepth,jpk0,xdt0,f0,width,iaptype,APmask,APsymbols,codewords,snr1, & + ndepth,jpk0,xdt0,f0,iaptype,APmask,APsymbols,codewords,snr1, & xdt1,f1,snr2,irc,dat4) use packjt77 @@ -91,7 +91,6 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & ! b90=1.728**ibw b90=3.0**nbw if(b90.gt.230.0) cycle -! if(b90.lt.0.15*width) exit call timer('q65_intr',0) b90ts = b90/baud call q65_intrinsics_ff(s3,nsubmode,b90ts,nFadingModel,s3prob) @@ -99,7 +98,8 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & if(iaptype.eq.4) then codewords(1:63,4)=cw4 call timer('q65_apli',0) - call q65_dec_fullaplist(s3,s3prob,codewords,4,esnodb,dat4,irc) + call q65_dec_fullaplist(s3,s3prob,codewords,4,esnodb, & + dat4,plog,irc) call timer('q65_apli',1) else call timer('q65_dec ',0) @@ -140,20 +140,20 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & xdt1=xdt0 + nsps*ndt/(16.0*6000.0) f1=f0 + 0.5*baud*ndf !### For tests only: - open(53,file='fort.53',status='unknown',position='append') - write(c77,1100) dat4(1:12),dat4(13)/2 -1100 format(12b6.6,b5.5) - call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent - m=nutc - if(nsps.ge.3600) m=100*m - ihr=m/10000 - imin=mod(m/100,100) - isec=mod(m,100) - hours=ihr + imin/60.0 + isec/3600.0 - write(53,3053) m,hours,ndf,ndt,nbw,ndist,irc,iaptype,kavg,snr1, & - xdt1,f1,snr2,trim(decoded) -3053 format(i6.6,f8.4,4i3,i4,2i3,f6.1,f6.2,f7.1,f6.1,1x,a) - close(53) +! open(53,file='fort.53',status='unknown',position='append') +! write(c77,1100) dat4(1:12),dat4(13)/2 +!1100 format(12b6.6,b5.5) +! call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent +! m=nutc +! if(nsps.ge.3600) m=100*m +! ihr=m/10000 +! imin=mod(m/100,100) +! isec=mod(m,100) +! hours=ihr + imin/60.0 + isec/3600.0 +! write(53,3053) m,hours,ndf,ndt,nbw,ndist,irc,iaptype,kavg,snr1, & +! xdt1,f1,snr2,trim(decoded) +!3053 format(i6.6,f8.4,4i3,i4,2i3,f6.1,f6.2,f7.1,f6.1,1x,a) +! close(53) !### nsave=0 s3avg=0. diff --git a/lib/qra/q65/q65_subs.c b/lib/qra/q65/q65_subs.c index 9f29da01c..e55fe927d 100644 --- a/lib/qra/q65/q65_subs.c +++ b/lib/qra/q65/q65_subs.c @@ -111,7 +111,7 @@ void q65_dec_(float s3[], float s3prob[], int APmask[], int APsymbols[], } void q65_dec_fullaplist_(float s3[], float s3prob[], int codewords[], - int* ncw, float* esnodb0, int xdec[], int* rc0) + int* ncw, float* esnodb0, int xdec[], float* plog, int* rc0) { /* Input: s3[LL,NN] Symbol spectra * s3prob[LL,NN] Symbol-value intrinsic probabilities @@ -128,6 +128,7 @@ void q65_dec_fullaplist_(float s3[], float s3prob[], int codewords[], float esnodb; rc = q65_decode_fullaplist(&codec,ydec,xdec,s3prob,codewords,*ncw); + *plog=q65_llh; *rc0=rc; // rc = -1: Invalid params diff --git a/lib/qra/q65/q65sim.f90 b/lib/qra/q65/q65sim.f90 index f99ab4f1d..241d0adb8 100644 --- a/lib/qra/q65/q65sim.f90 +++ b/lib/qra/q65/q65sim.f90 @@ -193,21 +193,21 @@ program q65sim write(10) h,iwave(1:npts) !Save the .wav file close(10) - if(lsync) then - cd=' ' - if(ifile.eq.nfiles) cd='d' - nfqso=nint(f0) - ntol=100 - call sync_q65(iwave,npts,mode65,nsps,nfqso,ntol,xdt2,f02,snr2) - terr=1.01/(8.0*baud) - ferr=1.01*mode65*baud - if(abs(xdt2-xdt).lt.terr .and. abs(f02-f0).lt.ferr) nsync=nsync+1 - open(40,file='sync65.out',status='unknown',position='append') - write(40,1030) ifile,65,csubmode,snrdb,fspread,xdt2-xdt,f02-f0, & - snr2,nsync,cd -1030 format(i4,i3,1x,a1,2f7.1,f7.2,2f8.1,i5,1x,a1) - close(40) - endif +! if(lsync) then +! cd=' ' +! if(ifile.eq.nfiles) cd='d' +! nfqso=nint(f0) +! ntol=100 +! call q65_sync(iwave,npts,mode65,nsps,nfqso,ntol,xdt2,f02,snr2) +! terr=1.01/(8.0*baud) +! ferr=1.01*mode65*baud +! if(abs(xdt2-xdt).lt.terr .and. abs(f02-f0).lt.ferr) nsync=nsync+1 +! open(40,file='sync65.out',status='unknown',position='append') +! write(40,1030) ifile,65,csubmode,snrdb,fspread,xdt2-xdt,f02-f0, & +! snr2,nsync,cd +!1030 format(i4,i3,1x,a1,2f7.1,f7.2,2f8.1,i5,1x,a1) +! close(40) +! endif enddo if(lsync) write(*,1040) snrdb,nfiles,nsync 1040 format('SNR:',f6.1,' nfiles:',i5,' nsynced:',i5) From afc4f2fb5477ddf7c0e2d7248ecc9e955a0a0d07 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 30 Nov 2020 10:45:52 -0500 Subject: [PATCH 173/206] Reorganize things in q65_sync. --- lib/q65_sync.f90 | 109 +++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 64 deletions(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index d81cbd5f8..d47997d9a 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -97,41 +97,13 @@ subroutine q65_sync(iwave,nmax,mode_q65,nQSOprogress,nsps,nfqso,ntol, & j0=1.0/dtstep !Nominal index for start of signal lag2=4.0/dtstep + 0.9999 !Include EME delays endif - 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 - ccf(-ia:ia,lag)=ccf(-ia:ia,lag) + sync(k)*s1(i0-ia:i0+ia,j) - endif - enddo - enddo - - ijpk=maxloc(ccf) - ipk=ijpk(1)-ia-1 - jpk=ijpk(2)-53-1 - f0=nfqso + ipk*df - xdt=jpk*dtstep - - sq=0. - nsq=0 - do j=lag1,lag2 - if(abs(j-jpk).gt.6) then - sq=sq + ccf(ipk,j)**2 - nsq=nsq+1 - endif - enddo - rms=sqrt(sq/nsq) - smax=ccf(ipk,jpk) - snr1=smax/rms !###################################################################### -! Experimental: Try early list decoding via "Deep Likelihood". +! Try list decoding via "Deep Likelihood". - if(nQSOprogress.lt.1) go to 900 - snr1a_best=0. + ipk=0 + jpk=0 + ccf_best=0. do imsg=1,4 ccf=0. msg='K1ABC W9XYZ RRR' @@ -158,38 +130,17 @@ subroutine q65_sync(iwave,nmax,mode_q65,nQSOprogress,nsps,nfqso,ntol, & endif enddo enddo - - ijpk=maxloc(ccf) - ipk=ijpk(1)-ia-1 - jpk=ijpk(2)-53-1 - f0a=nfqso + ipk*df - xdta=jpk*dtstep - - sq=0. - nsq=0 - do j=lag1,lag2 - if(abs(j-jpk).gt.6) then - sq=sq + ccf(ipk,j)**2 - nsq=nsq+1 - endif - enddo - rms=sqrt(sq/nsq) - smax=ccf(ipk,jpk) - snr1a=smax/rms - if(snr1a.gt.snr1a_best) then - snr1a_best=snr1a - imsg_best=imsg - xdta_best=xdta - f0a_best=f0a + ccfmax=maxval(ccf) + if(ccfmax.gt.ccf_best) then + ccf_best=ccfmax + ijpk=maxloc(ccf) + ipk=ijpk(1)-ia-1 + jpk=ijpk(2)-53-1 + f0=nfqso + ipk*df + xdt=jpk*dtstep endif enddo ! imsg - if(snr1a_best.gt.2.0) then - xdt=xdta_best - f0=f0a_best - snr1=1.4*snr1a_best - endif - ia=i0+ipk-63 ib=ia+LL-1 j=j0+jpk-5 @@ -213,12 +164,42 @@ subroutine q65_sync(iwave,nmax,mode_q65,nQSOprogress,nsps,nfqso,ntol, & call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) call q65_dec_fullaplist(s3,s3prob,codewords,4,esnodb,dat4,plog,irc) if(irc.ge.0) then - xdt=xdta_best - f0=f0a_best snr2=esnodb - db(2500.0/baud) - exit + go to 900 endif enddo +!###################################################################### +! Establish xdt, f0, and snr1 using sync symbols (and perhaps some AP symbols) + ccf=0. + irc=-2 + dat4=0 + ia=ntol/df + 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 + ccf(-ia:ia,lag)=ccf(-ia:ia,lag) + sync(k)*s1(i0-ia:i0+ia,j) + endif + enddo + enddo + ijpk=maxloc(ccf) + ipk=ijpk(1)-ia-1 + jpk=ijpk(2)-53-1 + f0=nfqso + ipk*df + xdt=jpk*dtstep + sq=0. + nsq=0 + do j=lag1,lag2 + if(abs(j-jpk).gt.6) then + sq=sq + ccf(ipk,j)**2 + nsq=nsq+1 + endif + enddo + rms=sqrt(sq/nsq) + smax=ccf(ipk,jpk) + snr1=smax/rms + 900 return end subroutine q65_sync From 8285fd28a8ed64d4be10bd3cea0eb88c65c714f4 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 30 Nov 2020 11:41:50 -0500 Subject: [PATCH 174/206] List decoding now supports 57 list messages. --- CMakeLists.txt | 1 + lib/q65_decode.f90 | 9 +++++---- lib/q65_sync.f90 | 34 +++++++++++++++++----------------- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b910350da..2dfdbc897 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -501,6 +501,7 @@ set (wsjt_FSRCS lib/qra_loops.f90 lib/qra/q65/q65_ap.f90 lib/qra/q65/q65_loops.f90 + lib/qra/q65/q65_set_list.f90 lib/refspectrum.f90 lib/savec2.f90 lib/sec0.f90 diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 819aba0d1..dcbcabc8e 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -90,16 +90,17 @@ contains this%callback => callback if(nutc.eq.-999) print*,lapdx,nfa,nfb,nfqso !Silence warning nFadingModel=1 + call q65_set_list(mycall,hiscall,hisgrid,codewords,ncw) dgen=0 call q65_enc(dgen,codewords) !Initialize Q65 ! nQSOprogress=3 !### dat4=0 call timer('sync_q65',0) - call q65_sync(iwave,ntrperiod*12000,mode65,nQSOprogress,nsps,nfqso, & - ntol,xdt,f0,snr1,dat4,snr2,irc) + call q65_sync(iwave,ntrperiod*12000,mode65,codewords,ncw,nsps, & + nfqso,ntol,xdt,f0,snr1,dat4,snr2,irc) call timer('sync_q65',1) - write(55,3055) nutc,xdt,f0,snr1,snr2,irc -3055 format(i4.4,4f9.2,i5) +! write(55,3055) nutc,xdt,f0,snr1,snr2,irc +!3055 format(i4.4,4f9.2,i5) if(irc.ge.0) then xdt1=xdt f1=f0 diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index d47997d9a..3062cbb8d 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -1,4 +1,4 @@ -subroutine q65_sync(iwave,nmax,mode_q65,nQSOprogress,nsps,nfqso,ntol, & +subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & xdt,f0,snr1,dat4,snr2,irc) ! Detect and align with the Q65 sync vector, returning time and frequency @@ -15,7 +15,6 @@ subroutine q65_sync(iwave,nmax,mode_q65,nQSOprogress,nsps,nfqso,ntol, & parameter (NSTEP=8) !Step size nsps/NSTEP parameter (LN=2176*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63 - character*37 msg,msgsent integer*2 iwave(0:nmax-1) !Raw data integer isync(22) !Indices of sync symbols integer itone(85) @@ -98,27 +97,28 @@ subroutine q65_sync(iwave,nmax,mode_q65,nQSOprogress,nsps,nfqso,ntol, & lag2=4.0/dtstep + 0.9999 !Include EME delays endif + if(ncw.lt.1) go to 100 + !###################################################################### ! Try list decoding via "Deep Likelihood". ipk=0 jpk=0 ccf_best=0. - do imsg=1,4 - ccf=0. - msg='K1ABC W9XYZ RRR' - if(imsg.eq.2) msg='K1ABC W9XYZ RR73' - if(imsg.eq.3) msg='K1ABC W9XYZ 73' - if(imsg.eq.4) msg='CQ K9AN EN50' - call genq65(msg,0,msgsent,itone,i3,n3) - j=0 - do k=1,85 - if(sync(k)>0.) cycle - j=j+1 - codewords(j,imsg)=itone(k) - 1 + do imsg=1,ncw + i=1 + k=0 + do j=1,85 + if(j.eq.isync(i)) then + i=i+1 + itone(j)=-1 + else + k=k+1 + itone(j)=codewords(k,imsg) + endif enddo - ! Compute 2D ccf using all 85 symbols in the list message + ccf=0. do lag=lag1,lag2 do k=1,85 j=j0 + NSTEP*(k-1) + 1 + lag @@ -162,7 +162,7 @@ subroutine q65_sync(iwave,nmax,mode_q65,nQSOprogress,nsps,nfqso,ntol, & do ibw=0,10 b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) - call q65_dec_fullaplist(s3,s3prob,codewords,4,esnodb,dat4,plog,irc) + call q65_dec_fullaplist(s3,s3prob,codewords,ncw,esnodb,dat4,plog,irc) if(irc.ge.0) then snr2=esnodb - db(2500.0/baud) go to 900 @@ -171,7 +171,7 @@ subroutine q65_sync(iwave,nmax,mode_q65,nQSOprogress,nsps,nfqso,ntol, & !###################################################################### ! Establish xdt, f0, and snr1 using sync symbols (and perhaps some AP symbols) - ccf=0. +100 ccf=0. irc=-2 dat4=0 ia=ntol/df From de6f5e497509753539696240e944282f797fc85a Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 30 Nov 2020 13:14:18 -0500 Subject: [PATCH 175/206] Q65 code cleanup. Use 3-digit format for the end-of-line flag. --- lib/decoder.f90 | 18 ++++++------------ lib/q65_decode.f90 | 39 +++++++++++++++------------------------ lib/q65_sync.f90 | 11 +++++++---- lib/qra/q65/q65_loops.f90 | 6 +++++- 4 files changed, 33 insertions(+), 41 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 49dca917b..011b98aa6 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -777,8 +777,7 @@ contains return end subroutine fst4_decoded - subroutine q65_decoded (this,nutc,sync,nsnr,dt,freq,decoded,irc, & - qual,ntrperiod,fmid,w50) + subroutine q65_decoded (this,nutc,sync,nsnr,dt,freq,decoded,idec,ntrperiod) use q65_decode implicit none @@ -790,22 +789,17 @@ contains real, intent(in) :: dt real, intent(in) :: freq character(len=37), intent(in) :: decoded - integer, intent(in) :: irc - real, intent(in) :: qual + integer, intent(in) :: idec integer, intent(in) :: ntrperiod - real, intent(in) :: fmid - real, intent(in) :: w50 - integer navg - navg=irc/100 if(ntrperiod.lt.60) then - write(*,1001) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg -1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) + write(*,1001) nutc,nsnr,dt,nint(freq),decoded,idec +1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i3.3) write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded 1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') else - write(*,1003) nutc,nsnr,dt,nint(freq),decoded,mod(irc,100),navg -1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i2,i4) + write(*,1003) nutc,nsnr,dt,nint(freq),decoded,idec +1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i3.3) write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded 1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index dcbcabc8e..5bfcc5215 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -8,7 +8,7 @@ module q65_decode abstract interface subroutine q65_decode_callback (this,nutc,sync,nsnr,dt,freq, & - decoded,nap,qual,ntrperiod,fmid,w50) + decoded,nap,ntrperiod) import q65_decoder implicit none class(q65_decoder), intent(inout) :: this @@ -19,10 +19,7 @@ module q65_decode 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 end subroutine q65_decode_callback end interface @@ -64,6 +61,9 @@ contains complex, allocatable :: c00(:) !Analytic signal, 6000 Sa/s complex, allocatable :: c0(:) !Analytic signal, 6000 Sa/s + id1=0 + id2=0 + id3=0 mode65=2**nsubmode npts=ntrperiod*12000 nfft1=ntrperiod*12000 @@ -93,21 +93,16 @@ contains call q65_set_list(mycall,hiscall,hisgrid,codewords,ncw) dgen=0 call q65_enc(dgen,codewords) !Initialize Q65 -! nQSOprogress=3 !### - dat4=0 call timer('sync_q65',0) - call q65_sync(iwave,ntrperiod*12000,mode65,codewords,ncw,nsps, & - nfqso,ntol,xdt,f0,snr1,dat4,snr2,irc) + call q65_sync(nutc,iwave,ntrperiod*12000,mode65,codewords,ncw,nsps, & + nfqso,ntol,xdt,f0,snr1,dat4,snr2,id1) call timer('sync_q65',1) -! write(55,3055) nutc,xdt,f0,snr1,snr2,irc -!3055 format(i4.4,4f9.2,i5) - if(irc.ge.0) then + if(id1.eq.1) then xdt1=xdt f1=f0 go to 100 endif - irc=-9 if(snr1.lt.2.8) go to 100 jpk0=(xdt+1.0)*6000 !### Is this OK? if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### @@ -116,7 +111,6 @@ contains dd=fac*iwave(1:npts) nmode=65 call ana64(dd,npts,c00) - call ft8apset(mycall,hiscall,ncontest,apsym0,aph10) where(apsym0.eq.-1) apsym0=0 @@ -148,31 +142,28 @@ contains call timer('q65loops',0) call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & nFadingModel,ndepth,jpk0,xdt,f0,iaptype,apmask,apsymbols, & - codewords,snr1,xdt1,f1,snr2,irc,dat4) + codewords,snr1,xdt1,f1,snr2,dat4,id2,id3) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) - if(irc.ge.0) exit + if(id2+id3.gt.0) exit enddo 100 decoded=' ' -! if(irc.lt.0 .and.iaptype.eq.4) print*,'AAA',irc,iaptype - if(irc.ge.0) then -!### - navg=irc/100 -! irc=100*navg + ipass - irc=100*navg + iaptype -!### + idec=100*id1 + 10*id2 + id3 + write(71,3071) nutc,id1,id2,id3,irc +3071 format(5i6) + if(idec.gt.0) then 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 nsnr=nint(snr2) call this%callback(nutc,sync,nsnr,xdt1,f1,decoded, & - irc,qual,ntrperiod,fmid,w50) + idec,ntrperiod) else ! Report sync, even if no decode. nsnr=db(snr1) - 35.0 call this%callback(nutc,sync,nsnr,xdt1,f1,decoded, & - irc,qual,ntrperiod,fmid,w50) + idec,ntrperiod) endif return diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index 3062cbb8d..87ac1fac5 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -1,5 +1,5 @@ -subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & - xdt,f0,snr1,dat4,snr2,irc) +subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & + xdt,f0,snr1,dat4,snr2,id1) ! Detect and align with the Q65 sync vector, returning time and frequency ! offsets and SNR estimate. @@ -32,6 +32,8 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & data sync(1)/99.0/ save sync + id1=0 + dat4=0 LL=64*(2+mode_q65) nfft=nsps df=12000.0/nfft !Freq resolution = baud @@ -157,14 +159,15 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & nsubmode=0 nFadingModel=1 baud=12000.0/nsps - dat4=0 - irc=-2 do ibw=0,10 b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) call q65_dec_fullaplist(s3,s3prob,codewords,ncw,esnodb,dat4,plog,irc) if(irc.ge.0) then snr2=esnodb - db(2500.0/baud) + id1=1 +! write(55,3055) nutc,xdt,f0,snr2,plog,irc +!3055 format(i4.4,4f9.2,i5) go to 900 endif enddo diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 5c48f85a1..59ba36c0e 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,6 +1,6 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & ndepth,jpk0,xdt0,f0,iaptype,APmask,APsymbols,codewords,snr1, & - xdt1,f1,snr2,irc,dat4) + xdt1,f1,snr2,dat4,id2,id3) use packjt77 use timer_module, only: timer @@ -29,6 +29,8 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & save nsave,s3avg + id2=0 + id3=0 ircbest=9999 allocate(c0(0:npts2-1)) irc=-99 @@ -101,10 +103,12 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & call q65_dec_fullaplist(s3,s3prob,codewords,4,esnodb, & dat4,plog,irc) call timer('q65_apli',1) + if(irc.ge.0) id2=4 else call timer('q65_dec ',0) call q65_dec(s3,s3prob,APmask,APsymbols,esnodb,dat4,irc) call timer('q65_dec ',1) + if(irc.ge.0) id2=iaptype endif ! write(71,3071) 100*nutc,0.0,ndf,ndt,nbw,ndist,irc,iaptype, & ! kavg,nsave From 5c947178ce2f2f97691ed0ec3f2de6cc23b61ab8 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 30 Nov 2020 13:26:14 -0500 Subject: [PATCH 176/206] Protect against a bounds error. --- lib/q65_sync.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index 87ac1fac5..a9d58537d 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -153,7 +153,7 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & cycle endif n=n+1 - s3(-64:LL-65,n)=s1(ia:ib,j) + if(j.ge.1 .and. j.le.jz) s3(-64:LL-65,n)=s1(ia:ib,j) enddo nsubmode=0 From adc4c3d78aa27b86e816e06da1599bec89b71417 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 30 Nov 2020 14:13:37 -0500 Subject: [PATCH 177/206] More Q65 cleanup. Single-digit at end of line. --- lib/decoder.f90 | 4 +- lib/q65_decode.f90 | 14 ++-- lib/qra/q65/q65_loops.f90 | 162 ++++++++++++-------------------------- 3 files changed, 60 insertions(+), 120 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 011b98aa6..d93f5a73a 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -794,12 +794,12 @@ contains if(ntrperiod.lt.60) then write(*,1001) nutc,nsnr,dt,nint(freq),decoded,idec -1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i3.3) +1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i1) write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded 1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') else write(*,1003) nutc,nsnr,dt,nint(freq),decoded,idec -1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i3.3) +1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i1) write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded 1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 5bfcc5215..0473b7119 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -63,7 +63,6 @@ contains id1=0 id2=0 - id3=0 mode65=2**nsubmode npts=ntrperiod*12000 nfft1=ntrperiod*12000 @@ -140,19 +139,17 @@ contains endif endif call timer('q65loops',0) - call q65_loops(c00,nutc,npts/2,nsps/2,nmode,mode65,nsubmode, & + call q65_loops(c00,npts/2,nsps/2,nmode,mode65,nsubmode, & nFadingModel,ndepth,jpk0,xdt,f0,iaptype,apmask,apsymbols, & - codewords,snr1,xdt1,f1,snr2,dat4,id2,id3) + xdt1,f1,snr2,dat4,id2) call timer('q65loops',1) snr2=snr2 + db(6912.0/nsps) - if(id2+id3.gt.0) exit + if(id2.gt.0) exit enddo 100 decoded=' ' - idec=100*id1 + 10*id2 + id3 - write(71,3071) nutc,id1,id2,id3,irc -3071 format(5i6) - if(idec.gt.0) then + if(id1.gt.0 .or. id2.gt.0) then + idec=id1+id2 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 @@ -162,6 +159,7 @@ contains else ! Report sync, even if no decode. nsnr=db(snr1) - 35.0 + idec=-1 call this%callback(nutc,sync,nsnr,xdt1,f1,decoded, & idec,ntrperiod) endif diff --git a/lib/qra/q65/q65_loops.f90 b/lib/qra/q65/q65_loops.f90 index 59ba36c0e..b440e076f 100644 --- a/lib/qra/q65/q65_loops.f90 +++ b/lib/qra/q65/q65_loops.f90 @@ -1,23 +1,17 @@ -subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & - ndepth,jpk0,xdt0,f0,iaptype,APmask,APsymbols,codewords,snr1, & - xdt1,f1,snr2,dat4,id2,id3) +subroutine q65_loops(c00,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & + ndepth,jpk0,xdt0,f0,iaptype,APmask,APsymbols,xdt1,f1,snr2,dat4,id2) use packjt77 use timer_module, only: timer parameter (NN=63) parameter (LN=1152*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63 - character*37 decoded - character*77 c77 complex c00(0:npts2-1) !Analytic representation of dd(), 6000 Hz complex ,allocatable :: c0(:) !Ditto, with freq shift real a(3) !twkfreq params f,f1,f2 real s3(LN) !Symbol spectra - real s3avg(LN) !Averaged symbol spectra real s3prob(64*NN) !Symbol-value probabilities - logical unpk77_success integer APmask(13) integer APsymbols(13) - integer codewords(63,64) integer cw4(63) integer dat4(13) !Decoded message (as 13 six-bit integers) integer nap(0:11) !AP return codes @@ -27,10 +21,7 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & 51,51,42,42,50,25,31,35,57,30, 1,54,54,10,10,22,44,58,57,40, & 21,21,19/ - save nsave,s3avg - - id2=0 - id3=0 + id2=-1 ircbest=9999 allocate(c0(0:npts2-1)) irc=-99 @@ -55,113 +46,64 @@ subroutine q65_loops(c00,nutc,npts2,nsps,mode,mode_q65,nsubmode,nFadingModel, & xdt1=xdt0 f1=f0 - maxavg=0 - if(iand(ndepth,16).ne.0) maxavg=1 - do iavg=0,maxavg - if(iavg.eq.1) then - idfmax=1 - idtmax=1 - endif - do idf=1,idfmax - ndf=idf/2 - if(mod(idf,2).eq.0) ndf=-ndf - a=0. - a(1)=-(f0+0.5*baud*ndf) - call twkfreq(c00,c0,npts2,6000.0,a) - do idt=1,idtmax - ndt=idt/2 - if(iaptype.eq.0 .and. iavg.eq.0) then - if(mod(idt,2).eq.0) ndt=-ndt - jpk=jpk0 + nsps*ndt/16 !tsym/16 - if(jpk.lt.0) jpk=0 - call timer('spec64 ',0) - call spec64(c0,nsps,mode,mode_q65,jpk,s3,LL,NN) - call timer('spec64 ',1) - call pctile(s3,LL*NN,40,base) - s3=s3/base - where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim - endif - kavg=0 - if(iavg.eq.1 .and. nsave.ge.2) then - s3(1:LL*NN)=s3avg(1:LL*NN) - kavg=nsave - endif - do ibw=ibwmin,ibwmax - nbw=ibw - ndist=ndf**2 + ndt**2 + ((nbw-2))**2 - if(ndist.gt.maxdist) cycle -! b90=1.728**ibw - b90=3.0**nbw - if(b90.gt.230.0) cycle - call timer('q65_intr',0) - b90ts = b90/baud - call q65_intrinsics_ff(s3,nsubmode,b90ts,nFadingModel,s3prob) - call timer('q65_intr',1) - if(iaptype.eq.4) then - codewords(1:63,4)=cw4 - call timer('q65_apli',0) - call q65_dec_fullaplist(s3,s3prob,codewords,4,esnodb, & - dat4,plog,irc) - call timer('q65_apli',1) - if(irc.ge.0) id2=4 - else - call timer('q65_dec ',0) - call q65_dec(s3,s3prob,APmask,APsymbols,esnodb,dat4,irc) - call timer('q65_dec ',1) - if(irc.ge.0) id2=iaptype - endif -! write(71,3071) 100*nutc,0.0,ndf,ndt,nbw,ndist,irc,iaptype, & -! kavg,nsave -!3071 format(i6.6,f8.4,8i5) - if(irc.ge.0) go to 100 + do idf=1,idfmax + ndf=idf/2 + if(mod(idf,2).eq.0) ndf=-ndf + a=0. + a(1)=-(f0+0.5*baud*ndf) + call twkfreq(c00,c0,npts2,6000.0,a) + do idt=1,idtmax + ndt=idt/2 + if(iaptype.eq.0) then + if(mod(idt,2).eq.0) ndt=-ndt + jpk=jpk0 + nsps*ndt/16 !tsym/16 + if(jpk.lt.0) jpk=0 + call timer('spec64 ',0) + call spec64(c0,nsps,mode,mode_q65,jpk,s3,LL,NN) + call timer('spec64 ',1) + call pctile(s3,LL*NN,40,base) + s3=s3/base + where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim + endif + do ibw=ibwmin,ibwmax + nbw=ibw + ndist=ndf**2 + ndt**2 + ((nbw-2))**2 + if(ndist.gt.maxdist) cycle + ! b90=1.728**ibw + b90=3.0**nbw + if(b90.gt.230.0) cycle + call timer('q65_intr',0) + b90ts = b90/baud + call q65_intrinsics_ff(s3,nsubmode,b90ts,nFadingModel,s3prob) + call timer('q65_intr',1) + call timer('q65_dec ',0) + call q65_dec(s3,s3prob,APmask,APsymbols,esnodb,dat4,irc) + call timer('q65_dec ',1) + if(irc.ge.0) id2=iaptype+2 + if(irc.ge.0) go to 100 ! irc > 0 ==> number of iterations required to decode ! -1 = invalid params ! -2 = decode failed ! -3 = CRC mismatch - enddo ! ibw (b90 loop) - enddo ! idt (DT loop) - enddo ! idf (f0 loop) - if(iaptype.eq.0 .and. iavg.eq.0) then - a=0. - a(1)=-f0 - call twkfreq(c00,c0,npts2,6000.0,a) - jpk=3000 !### Are these definitions OK? - if(nsps.ge.3600) jpk=6000 !### TR >= 60 s - call spec64(c0,nsps,mode,mode_q65,jpk,s3,LL,NN) - call pctile(s3,LL*NN,40,base) - s3=s3/base - where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim - s3avg(1:LL*NN)=s3avg(1:LL*NN) + s3(1:LL*NN) - nsave=nsave+1 - endif - if(iavg.eq.0 .and. nsave.lt.2) exit - enddo ! iavg + enddo ! ibw (b90 loop) + enddo ! idt (DT loop) + enddo ! idf (f0 loop) + if(iaptype.eq.0) then + a=0. + a(1)=-f0 + call twkfreq(c00,c0,npts2,6000.0,a) + jpk=3000 !### Are these definitions OK? + if(nsps.ge.3600) jpk=6000 !### TR >= 60 s + call spec64(c0,nsps,mode,mode_q65,jpk,s3,LL,NN) + call pctile(s3,LL*NN,40,base) + s3=s3/base + where(s3(1:LL*NN)>s3lim) s3(1:LL*NN)=s3lim + endif 100 if(irc.ge.0) then - navg=nsave snr2=esnodb - db(2500.0/baud) - if(kavg.eq.0) navg=0 xdt1=xdt0 + nsps*ndt/(16.0*6000.0) f1=f0 + 0.5*baud*ndf -!### For tests only: -! open(53,file='fort.53',status='unknown',position='append') -! write(c77,1100) dat4(1:12),dat4(13)/2 -!1100 format(12b6.6,b5.5) -! call unpack77(c77,0,decoded,unpk77_success) !Unpack to get msgsent -! m=nutc -! if(nsps.ge.3600) m=100*m -! ihr=m/10000 -! imin=mod(m/100,100) -! isec=mod(m,100) -! hours=ihr + imin/60.0 + isec/3600.0 -! write(53,3053) m,hours,ndf,ndt,nbw,ndist,irc,iaptype,kavg,snr1, & -! xdt1,f1,snr2,trim(decoded) -!3053 format(i6.6,f8.4,4i3,i4,2i3,f6.1,f6.2,f7.1,f6.1,1x,a) -! close(53) -!### - nsave=0 - s3avg=0. - irc=irc + 100*navg endif return From 7cb87e315b081d6bf15a7a47650afef0de585017 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 30 Nov 2020 14:15:59 -0500 Subject: [PATCH 178/206] Fix a format. --- lib/decoder.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index d93f5a73a..a9cd010ae 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -794,12 +794,12 @@ contains if(ntrperiod.lt.60) then write(*,1001) nutc,nsnr,dt,nint(freq),decoded,idec -1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i1) +1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2) write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded 1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') else write(*,1003) nutc,nsnr,dt,nint(freq),decoded,idec -1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i1) +1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i2) write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded 1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') From 65dda491d28f8fe33d0e009237dc6ccafb952b35 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 30 Nov 2020 15:20:19 -0500 Subject: [PATCH 179/206] More Q65 code cleanup. Make submodes higher than A work with List Decoding. --- lib/q65_decode.f90 | 2 +- lib/q65_sync.f90 | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 0473b7119..ef4e67060 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -93,7 +93,7 @@ contains dgen=0 call q65_enc(dgen,codewords) !Initialize Q65 call timer('sync_q65',0) - call q65_sync(nutc,iwave,ntrperiod*12000,mode65,codewords,ncw,nsps, & + call q65_sync(iwave,ntrperiod*12000,mode65,codewords,ncw,nsps, & nfqso,ntol,xdt,f0,snr1,dat4,snr2,id1) call timer('sync_q65',1) if(id1.eq.1) then diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index a9d58537d..cbdcbe4dc 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -1,4 +1,4 @@ -subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & +subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & xdt,f0,snr1,dat4,snr2,id1) ! Detect and align with the Q65 sync vector, returning time and frequency @@ -126,7 +126,7 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & j=j0 + NSTEP*(k-1) + 1 + lag if(j.ge.1 .and. j.le.jz) then do i=-ia,ia - ii=i0+itone(k)+i + ii=i0+mode_q65*itone(k)+i ccf(i,lag)=ccf(i,lag) + s1(ii,j) enddo endif @@ -157,6 +157,10 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & enddo 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 nFadingModel=1 baud=12000.0/nsps do ibw=0,10 From a03758e4904996de79740f26ee12eb7b83d12507 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Mon, 30 Nov 2020 17:44:33 -0500 Subject: [PATCH 180/206] Add a file that was missing. --- lib/qra/q65/q65_set_list.f90 | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 lib/qra/q65/q65_set_list.f90 diff --git a/lib/qra/q65/q65_set_list.f90 b/lib/qra/q65/q65_set_list.f90 new file mode 100644 index 000000000..f899cac66 --- /dev/null +++ b/lib/qra/q65/q65_set_list.f90 @@ -0,0 +1,42 @@ +subroutine q65_set_list(mycall,hiscall,hisgrid,codewords,ncw) + + character*12 mycall,hiscall + character*6 hisgrid + character*37 msg0,msg,msgsent + integer codewords(63,64) + integer itone(85) + integer isync(22) + data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ + + msg0=trim(mycall)//' '//trim(hiscall) + j0=len(trim(msg0))+2 + isnr0=-35 + do i=1,57 + msg=msg0 + if(i.eq.2) msg(j0:j0+2)='RRR' + if(i.eq.3) msg(j0:j0+3)='RR73' + if(i.eq.4) msg(j0:j0+1)='73' + if(i.ge.5 .and. i.le.56) then + isnr=isnr0 + (i-5)/2 + if(iand(i,1).eq.1) write(msg(j0:j0+2),'(i3.2)') isnr + if(iand(i,1).eq.0) write(msg(j0:j0+3),'("R",i3.2)') isnr + endif + if(i.eq.57) msg='CQ '//trim(hiscall)//' '//hisgrid(1:4) + call genq65(msg,0,msgsent,itone,i3,n3) + i0=1 + j=0 + do k=1,85 + if(k.eq.isync(i0)) then + i0=i0+1 + cycle + endif + j=j+1 + codewords(j,i)=itone(k) - 1 + enddo + ncw=57 +! write(*,3001) i,isnr,codewords(1:13,i),trim(msg) +!3001 format(i2,2x,i3.2,2x,13i3,2x,a) + enddo + + return +end subroutine q65_set_list From 5a3dd69331b81b3186efeb119ebb7de4ae64283a Mon Sep 17 00:00:00 2001 From: Nico Palermo/IV3NWV Date: Tue, 1 Dec 2020 03:26:00 +0100 Subject: [PATCH 181/206] decode_fullaplist updated. the decoding threshold is now adjusted in function of the number of codewords passed --- lib/qra/q65/q65.c | 14 +++++++------- lib/qra/q65/q65.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/qra/q65/q65.c b/lib/qra/q65/q65.c index c91571ba6..9c8544ffb 100644 --- a/lib/qra/q65/q65.c +++ b/lib/qra/q65/q65.c @@ -681,8 +681,7 @@ int q65_decode_fullaplist(q65_codec_ds *codec, int k; int nK, nN, nM; - float llh; - float maxllh = Q65_LLH_THRESHOLD-1; // set to a value less than the threshold + float llh, maxllh, llh_threshold; int maxcw = -1; // index of the most likely codeword const int *pCw; @@ -693,6 +692,12 @@ int q65_decode_fullaplist(q65_codec_ds *codec, nN = q65_get_codeword_length(codec); nM = q65_get_alphabet_size(codec); + // we adjust the llh threshold in order to mantain the + // same false decode rate independently from the size + // of the list + llh_threshold = Q65_LLH_THRESHOLD + logf(1.0f*nCodewords/3); + maxllh = llh_threshold; // at least one llh should be larger than the threshold + // compute codewords log likelihoods and find max pCw = pCodewords; // start from the first codeword for (k=0;k>6); } - - diff --git a/lib/qra/q65/q65.h b/lib/qra/q65/q65.h index 2e764a32b..1962509a3 100644 --- a/lib/qra/q65/q65.h +++ b/lib/qra/q65/q65.h @@ -34,7 +34,7 @@ // Verify loglikelihood after successful decoding #define Q65_CHECKLLH // Max codeword list size in q65_decode_fullaplist -#define Q65_FULLAPLIST_SIZE 64 +#define Q65_FULLAPLIST_SIZE 256 // maximum number of weights for the fast-fading metric evaluation #define Q65_FASTFADING_MAXWEIGTHS 65 From 68d964b5c7435f3977c2cb01064908ecee97eeda Mon Sep 17 00:00:00 2001 From: Nico Palermo/IV3NWV Date: Tue, 1 Dec 2020 03:41:23 +0100 Subject: [PATCH 182/206] merged Joe's changes in decode_fullaplist --- lib/qra/q65/q65.c | 4 +++- lib/qra/q65/q65.h | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/qra/q65/q65.c b/lib/qra/q65/q65.c index 46d88301c..ddd764615 100644 --- a/lib/qra/q65/q65.c +++ b/lib/qra/q65/q65.c @@ -712,7 +712,9 @@ int q65_decode_fullaplist(q65_codec_ds *codec, // point to next codeword pCw+=nN; } - q65_llh=maxllh; + + q65_llh=maxllh; // save for Joe's use + if (maxcw<0) // no llh larger than threshold found return Q65_DECODE_FAILED; diff --git a/lib/qra/q65/q65.h b/lib/qra/q65/q65.h index 94f6d568c..9e3d79adb 100644 --- a/lib/qra/q65/q65.h +++ b/lib/qra/q65/q65.h @@ -39,7 +39,8 @@ // maximum number of weights for the fast-fading metric evaluation #define Q65_FASTFADING_MAXWEIGTHS 65 -float q65_llh; +extern float q65_llh; + typedef struct { const qracode *pQraCode; // qra code to be used by the codec float decoderEsNoMetric; // value for which we optimize the decoder metric From 70e0a84fe872ed2ceff6d2a1f9f2ebfc00e07c0b Mon Sep 17 00:00:00 2001 From: Nico Palermo/IV3NWV Date: Tue, 1 Dec 2020 04:13:30 +0100 Subject: [PATCH 183/206] corrected a compile error. q65_llh declared as an external variable in q65.h and placed in q65.c --- lib/qra/q65/q65.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/qra/q65/q65.c b/lib/qra/q65/q65.c index ddd764615..c9d776bc6 100644 --- a/lib/qra/q65/q65.c +++ b/lib/qra/q65/q65.c @@ -36,6 +36,7 @@ static int _q65_crc6(int *x, int sz); static void _q65_crc12(int *y, int *x, int sz); +float q65_llh; int q65_init(q65_codec_ds *pCodec, const qracode *pqracode) { From 6b540aaad06230fb0d0a9c30d26a3d6d06aacf75 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 1 Dec 2020 11:23:35 -0500 Subject: [PATCH 184/206] Correct offset in (i,j) indices for selecting s3 from s1. --- lib/q65_sync.f90 | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index cbdcbe4dc..f1b056cb5 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -79,7 +79,6 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & i0=nint(nfqso/df) !Target QSO frequency call pctile(s1(i0-64:i0+192,1:jz),129*jz,40,base) -! s1=s1/base - 1.0 s1=s1/base ! Apply fast AGC @@ -107,6 +106,7 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & ipk=0 jpk=0 ccf_best=0. + imsg_best=-1 do imsg=1,ncw i=1 k=0 @@ -140,12 +140,16 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & jpk=ijpk(2)-53-1 f0=nfqso + ipk*df xdt=jpk*dtstep + imsg_best=imsg endif enddo ! imsg - ia=i0+ipk-63 + write(71,3071) imsg_best,ipk,jpk,xdt,f0,ccf_best +3071 format(3i5,3f10.2) + + ia=i0+ipk-64 ib=ia+LL-1 - j=j0+jpk-5 + j=j0+jpk-7 n=0 do k=1,85 j=j+8 @@ -155,6 +159,13 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & n=n+1 if(j.ge.1 .and. j.le.jz) s3(-64:LL-65,n)=s1(ia:ib,j) enddo + + write(73,3001) codewords(1:10,3) +3001 format(3x,10i7) + do i=-5,68 + write(73,3073) i,(s3(i,j),j=1,10) +3073 format(i3,10f7.1) + enddo nsubmode=0 if(mode_q65.eq.2) nsubmode=1 @@ -167,6 +178,8 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) call q65_dec_fullaplist(s3,s3prob,codewords,ncw,esnodb,dat4,plog,irc) + write(72,3072) ibw,dat4,plog,irc +3072 format(i2,2x,13i3,f8.1,i5) if(irc.ge.0) then snr2=esnodb - db(2500.0/baud) id1=1 From df3169ba22d6868b21df247865a625c061d08e2c Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 1 Dec 2020 11:24:21 -0500 Subject: [PATCH 185/206] Update test_q65. --- lib/test_q65.f90 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 0c71d64a5..68e28ed3d 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -4,7 +4,7 @@ program test_q65 character*22 msg character*8 arg character*1 csubmode - integer naptype(0:4) + integer naptype(1:6) logical decok nargs=iargc() @@ -89,9 +89,9 @@ program test_q65 !1000 format(/'Depth:',i2,' AP:',i2,' df:',i3,' dt:',i3,' bw1:',i3,' bw2:',i3, & ! ' dist:',i3) - write(*,1010) (j,j=0,4) - write(12,1010) (j,j=0,4) -1010 format(' SNR Mode d Dop Sync DecN Dec1 Bad',5i5,' tdec'/70('-')) + write(*,1010) (j,j=1,6) + write(12,1010) (j,j=1,6) +1010 format(' SNR Mode d Dop Sync DecN Dec1 Bad',6i5,' tdec'/75('-')) dterr=tsym/4.0 nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) @@ -120,16 +120,16 @@ program test_q65 if((abs(xdt-dt).le.dterr .and. abs(nf-nf0).le.nferr) .or. decok) then nsync=nsync+1 endif - irc=-1 + idec=-1 iavg=0 i0=23 if(ntrperiod.le.30) i0=25 - if(line(i0:i0).ne.' ') read(line(60:),*) irc,iavg - if(irc.lt.0) cycle + if(line(i0:i0).ne.' ') read(line(60:),*) idec + if(idec.lt.0) cycle if(decok) then ndecn=ndecn + 1 if(iavg.le.1) ndec1=ndec1 + 1 - naptype(irc)=naptype(irc) + 1 + naptype(idec)=naptype(idec) + 1 else nfalse=nfalse + 1 print*,'False: ',line @@ -142,7 +142,7 @@ program test_q65 ndec1,nfalse,naptype,tdec/nfiles write(12,1100) snr1,ntrperiod,csubmode,ndepth,fDop,nsync,ndecn, & ndec1,nfalse,naptype,tdec/nfiles -1100 format(f5.1,i4,1x,a1,i3,f5.1,3i5,i4,i6,4i5,f6.2) +1100 format(f5.1,i4,1x,a1,i3,f5.1,3i5,i4,i6,5i5,f6.2) if(ndec1.lt.nfiles/2 .and. ndec10.ge.nfiles/2) then snr_thresh=snr1 + float(nfiles/2 - ndec1)/(ndec10-ndec1) open(13,file='snr_thresh.out',status='unknown',position='append') From d1ac5f71e2c76f5f4209b53d4a5e58991c63a18d Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Tue, 1 Dec 2020 11:31:52 -0500 Subject: [PATCH 186/206] Remove several diagnostic writes. --- lib/q65_sync.f90 | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index f1b056cb5..9685b9099 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -144,9 +144,6 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & endif enddo ! imsg - write(71,3071) imsg_best,ipk,jpk,xdt,f0,ccf_best -3071 format(3i5,3f10.2) - ia=i0+ipk-64 ib=ia+LL-1 j=j0+jpk-7 @@ -160,13 +157,6 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & if(j.ge.1 .and. j.le.jz) s3(-64:LL-65,n)=s1(ia:ib,j) enddo - write(73,3001) codewords(1:10,3) -3001 format(3x,10i7) - do i=-5,68 - write(73,3073) i,(s3(i,j),j=1,10) -3073 format(i3,10f7.1) - enddo - nsubmode=0 if(mode_q65.eq.2) nsubmode=1 if(mode_q65.eq.4) nsubmode=2 @@ -178,8 +168,6 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) call q65_dec_fullaplist(s3,s3prob,codewords,ncw,esnodb,dat4,plog,irc) - write(72,3072) ibw,dat4,plog,irc -3072 format(i2,2x,13i3,f8.1,i5) if(irc.ge.0) then snr2=esnodb - db(2500.0/baud) id1=1 From 53e4052b8cb4883014d176714ba9ac7d7199f9a1 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Thu, 3 Dec 2020 14:28:30 -0500 Subject: [PATCH 187/206] Q65 additions for diagnostic purposes. --- lib/q65_decode.f90 | 2 +- lib/q65_sync.f90 | 31 ++++++++++++++++++++----------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index ef4e67060..0473b7119 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -93,7 +93,7 @@ contains dgen=0 call q65_enc(dgen,codewords) !Initialize Q65 call timer('sync_q65',0) - call q65_sync(iwave,ntrperiod*12000,mode65,codewords,ncw,nsps, & + call q65_sync(nutc,iwave,ntrperiod*12000,mode65,codewords,ncw,nsps, & nfqso,ntol,xdt,f0,snr1,dat4,snr2,id1) call timer('sync_q65',1) if(id1.eq.1) then diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index 9685b9099..aa238d69d 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -1,4 +1,4 @@ -subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & +subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & xdt,f0,snr1,dat4,snr2,id1) ! Detect and align with the Q65 sync vector, returning time and frequency @@ -12,7 +12,8 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & ! Output: xdt Time offset from nominal (s) ! f0 Frequency of sync tone ! snr1 Relative SNR of sync signal - + + use packjt77 parameter (NSTEP=8) !Step size nsps/NSTEP parameter (LN=2176*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63 integer*2 iwave(0:nmax-1) !Raw data @@ -21,6 +22,8 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & integer codewords(63,64) integer dat4(13) integer ijpk(2) + logical unpk77_success + character*77 c77,decoded*37 real, allocatable :: s1(:,:) !Symbol spectra, 1/8-symbol steps real, allocatable :: s3(:,:) !Data-symbol energies s3(LL,63) real, allocatable :: ccf(:,:) !CCF(freq,lag) @@ -78,14 +81,14 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & enddo i0=nint(nfqso/df) !Target QSO frequency - call pctile(s1(i0-64:i0+192,1:jz),129*jz,40,base) + call pctile(s1(i0-64:i0-65+LL,1:jz),LL*jz,40,base) s1=s1/base ! Apply fast AGC s1max=20.0 !Empirical choice - do j=1,jz - smax=maxval(s1(i0-64:i0+192,j)) - if(smax.gt.s1max) s1(i0-64:i0+192,j)=s1(i0-64:i0+192,j)*s1max/smax + do j=1,jz !### Maybe wrong way? ### + smax=maxval(s1(i0-64:i0-65+LL,j)) + if(smax.gt.s1max) s1(i0-64:i0-65+LL,j)=s1(i0-64:i0-65+LL,j)*s1max/smax enddo dtstep=nsps/(NSTEP*12000.0) !Step size in seconds @@ -93,7 +96,7 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & lag1=-1.0/dtstep lag2=1.0/dtstep + 0.9999 j0=0.5/dtstep - if(nsps.ge.6192) then + if(nsps.ge.7200) then j0=1.0/dtstep !Nominal index for start of signal lag2=4.0/dtstep + 0.9999 !Include EME delays endif @@ -164,15 +167,21 @@ subroutine q65_sync(iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & if(mode_q65.eq.16) nsubmode=4 nFadingModel=1 baud=12000.0/nsps - do ibw=0,10 + do ibw=2,4 b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) call q65_dec_fullaplist(s3,s3prob,codewords,ncw,esnodb,dat4,plog,irc) - if(irc.ge.0) then + if(irc.ge.0 .and. plog.ge.-255.0) then snr2=esnodb - db(2500.0/baud) id1=1 -! write(55,3055) nutc,xdt,f0,snr2,plog,irc -!3055 format(i4.4,4f9.2,i5) + 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 + open(55,file='fort.55',status='unknown',position='append') + write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & + irc,trim(decoded) +3055 format(i6,i3,6f8.2,i5,2x,a) + close(55) go to 900 endif enddo From bb08150e4bb61f4bfa14cbd80c56d6ab10476a9c Mon Sep 17 00:00:00 2001 From: Nico Palermo/IV3NWV Date: Fri, 4 Dec 2020 09:43:41 +0100 Subject: [PATCH 188/206] Threshold in q65_sync.f90 increased to -250 only for reports. Assumes that the list is in the order defined in q65_set_list.f90 (reports are at indexes 5..56). Beware if q65_set_list is changed!!! --- lib/q65_decode.f90 | 5 +++ lib/q65_sync.f90 | 103 +++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 104 insertions(+), 4 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index 0473b7119..e52870b61 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -102,6 +102,11 @@ contains go to 100 endif + ! Nico's trick to speed up data analysis + ! with fullaplist decoding + ! Uncomment to check only fullaplist synch and decode + ! snr1 = 1 ! skip non fullaplist decoding attempts + if(snr1.lt.2.8) go to 100 jpk0=(xdt+1.0)*6000 !### Is this OK? if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index aa238d69d..710a35c5b 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -27,6 +27,12 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & 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 :: ccfcw(:) ! Method 2 + ! real, allocatable :: ccfpk(:) ! Method 2 + ! integer cwpk(1) ! Method 2 + ! integer, allocatable :: cwtone(:,:) ! Method 2 + real, allocatable :: ccf1(:) !CCF(freq) at best lag real s3prob(0:63,63) !Symbol-value probabilities real sync(85) !sync vector @@ -52,6 +58,10 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & allocate(c0(0:nfft-1)) allocate(ccf(-ia:ia,-53:214)) allocate(ccf1(-ia:ia)) + + ! allocate(ccfcw(1:ncw)) ! Method 2 + ! allocate(ccfpk(1:ncw)) ! Method 2 + ! allocate(cwtone(ncw,85)) ! Method 2 if(sync(1).eq.99.0) then !Generate the sync vector sync=-22.0/63.0 !Sync tone OFF @@ -106,6 +116,7 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & !###################################################################### ! Try list decoding via "Deep Likelihood". +! Joe's method ipk=0 jpk=0 ccf_best=0. @@ -147,6 +158,66 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & endif enddo ! imsg +! Nico's Method 2 +! Computes the ccf in a different order so that +! we can see what the ccfs of the list looked like +! on ccfmax + +! Compute codeword tones +! cwtone = 0 +! do imsg=1,ncw +! i=1 +! k=0 +! do j=1,85 +! if(j.eq.isync(i)) then +! i=i+1 +! cwtone(imsg,j)=-1 +! else +! k=k+1 +! cwtone(imsg,j)=codewords(k,imsg) +! endif +! enddo +! enddo + +! ipk=0 +! jpk=0 +! ccf_best=0. +! imsg_best=-1 +! ccf=0. +! do lag=lag1,lag2 +! do i=-ia,ia +! ccfcw = 0. +! do k=1,85 +! j=j0 + NSTEP*(k-1) + 1 + lag +! if(j.ge.1 .and. j.le.jz) then +! do imsg=1,ncw +! ! if we would like to check only non systematic symbols +! ! uncomment the following if +! !if (k.gt.18 .or. cwtone(imsg,k).eq.-1) then +! ii=i0+mode_q65*cwtone(imsg,k)+i +! ccfcw(imsg)=ccfcw(imsg) + s1(ii,j) +! !endif +! enddo +! endif +! enddo +! ccfmax=maxval(ccfcw) +! ccf(i,lag) = ccfmax +! if(ccfmax.gt.ccf_best) then +! ccfpk = ccfcw +! cwpk = maxloc(ccfpk) +! imsg_best = cwpk(1) +! ccf_best = ccfmax +! endif +! enddo +! enddo +! ccfmax=maxval(ccf) +! ccf_best=ccfmax +! ijpk=maxloc(ccf) +! ipk=ijpk(1)-ia-1 +! jpk=ijpk(2)-53-1 +! f0=nfqso + ipk*df +! xdt=jpk*dtstep + ia=i0+ipk-64 ib=ia+LL-1 j=j0+jpk-7 @@ -167,22 +238,46 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & if(mode_q65.eq.16) nsubmode=4 nFadingModel=1 baud=12000.0/nsps + isreport = 0; do ibw=2,4 b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) call q65_dec_fullaplist(s3,s3prob,codewords,ncw,esnodb,dat4,plog,irc) - if(irc.ge.0 .and. plog.ge.-255.0) then +! Joe's threshold +! if(irc.ge.0 .and. plog.ge.-255.0) then +! Nico's threshold + if (irc.ge.0) then + ! if it is an RRR type or a CQ Mycall grid + ! we accept the fullaplist threshold + ! other cases in the list are reports which + ! are more frequent in the list and then + ! must be filtered with a higher threshold + if((irc.le.3.0 .or. irc.eq.56.0) .or. plog.ge.-250.0) then snr2=esnodb - db(2500.0/baud) id1=1 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 open(55,file='fort.55',status='unknown',position='append') - write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & - irc,trim(decoded) -3055 format(i6,i3,6f8.2,i5,2x,a) + +! Joe's dump +! write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & +! irc,trim(decoded) +!3055 format(i6,i3,6f8.2,i5,2x,a) + +! Nico's dump for Method 2 +! This are the ccfs of the codeword in the list at the +! ccf peak +! write(55,3083) ccfpk +!3083 format(10f6.1) +! Show also the imsg_best in order to compare it with +! irc. (Interestingly they are always equal!) +! write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & +! irc,(imsg_best-1),trim(decoded) +!3055 format(i6,i3,6f8.2,2i5,2x,a) close(55) go to 900 + endif endif enddo From 72bc2572e6b2e706afd02b1e0edba26146ed240a Mon Sep 17 00:00:00 2001 From: Nico Palermo/IV3NWV Date: Fri, 4 Dec 2020 10:07:56 +0100 Subject: [PATCH 189/206] forgot to uncomment fort.55 output. corrected --- lib/q65_sync.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index 710a35c5b..39475b4c3 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -261,9 +261,9 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & open(55,file='fort.55',status='unknown',position='append') ! Joe's dump -! write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & -! irc,trim(decoded) -!3055 format(i6,i3,6f8.2,i5,2x,a) + write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & + irc,trim(decoded) +3055 format(i6,i3,6f8.2,i5,2x,a) ! Nico's dump for Method 2 ! This are the ccfs of the codeword in the list at the From 978ea0f3b57b66da22832d279020d151231fd88a Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 4 Dec 2020 12:56:23 -0500 Subject: [PATCH 190/206] Revert "forgot to uncomment fort.55 output. corrected" This reverts commit 72bc2572e6b2e706afd02b1e0edba26146ed240a. --- lib/q65_sync.f90 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index 39475b4c3..710a35c5b 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -261,9 +261,9 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & open(55,file='fort.55',status='unknown',position='append') ! Joe's dump - write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & - irc,trim(decoded) -3055 format(i6,i3,6f8.2,i5,2x,a) +! write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & +! irc,trim(decoded) +!3055 format(i6,i3,6f8.2,i5,2x,a) ! Nico's dump for Method 2 ! This are the ccfs of the codeword in the list at the From aaf832cbd2c5e91392ba11c59d07b0b19609da83 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 4 Dec 2020 12:56:45 -0500 Subject: [PATCH 191/206] Revert "Threshold in q65_sync.f90 increased to -250 only for reports. Assumes that the list is in the order defined in q65_set_list.f90 (reports are at indexes 5..56). Beware if q65_set_list is changed!!!" This reverts commit bb08150e4bb61f4bfa14cbd80c56d6ab10476a9c. --- lib/q65_decode.f90 | 5 --- lib/q65_sync.f90 | 103 ++------------------------------------------- 2 files changed, 4 insertions(+), 104 deletions(-) diff --git a/lib/q65_decode.f90 b/lib/q65_decode.f90 index e52870b61..0473b7119 100644 --- a/lib/q65_decode.f90 +++ b/lib/q65_decode.f90 @@ -102,11 +102,6 @@ contains go to 100 endif - ! Nico's trick to speed up data analysis - ! with fullaplist decoding - ! Uncomment to check only fullaplist synch and decode - ! snr1 = 1 ! skip non fullaplist decoding attempts - if(snr1.lt.2.8) go to 100 jpk0=(xdt+1.0)*6000 !### Is this OK? if(ntrperiod.le.30) jpk0=(xdt+0.5)*6000 !### diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index 710a35c5b..aa238d69d 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -27,12 +27,6 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & 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 :: ccfcw(:) ! Method 2 - ! real, allocatable :: ccfpk(:) ! Method 2 - ! integer cwpk(1) ! Method 2 - ! integer, allocatable :: cwtone(:,:) ! Method 2 - real, allocatable :: ccf1(:) !CCF(freq) at best lag real s3prob(0:63,63) !Symbol-value probabilities real sync(85) !sync vector @@ -58,10 +52,6 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & allocate(c0(0:nfft-1)) allocate(ccf(-ia:ia,-53:214)) allocate(ccf1(-ia:ia)) - - ! allocate(ccfcw(1:ncw)) ! Method 2 - ! allocate(ccfpk(1:ncw)) ! Method 2 - ! allocate(cwtone(ncw,85)) ! Method 2 if(sync(1).eq.99.0) then !Generate the sync vector sync=-22.0/63.0 !Sync tone OFF @@ -116,7 +106,6 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & !###################################################################### ! Try list decoding via "Deep Likelihood". -! Joe's method ipk=0 jpk=0 ccf_best=0. @@ -158,66 +147,6 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & endif enddo ! imsg -! Nico's Method 2 -! Computes the ccf in a different order so that -! we can see what the ccfs of the list looked like -! on ccfmax - -! Compute codeword tones -! cwtone = 0 -! do imsg=1,ncw -! i=1 -! k=0 -! do j=1,85 -! if(j.eq.isync(i)) then -! i=i+1 -! cwtone(imsg,j)=-1 -! else -! k=k+1 -! cwtone(imsg,j)=codewords(k,imsg) -! endif -! enddo -! enddo - -! ipk=0 -! jpk=0 -! ccf_best=0. -! imsg_best=-1 -! ccf=0. -! do lag=lag1,lag2 -! do i=-ia,ia -! ccfcw = 0. -! do k=1,85 -! j=j0 + NSTEP*(k-1) + 1 + lag -! if(j.ge.1 .and. j.le.jz) then -! do imsg=1,ncw -! ! if we would like to check only non systematic symbols -! ! uncomment the following if -! !if (k.gt.18 .or. cwtone(imsg,k).eq.-1) then -! ii=i0+mode_q65*cwtone(imsg,k)+i -! ccfcw(imsg)=ccfcw(imsg) + s1(ii,j) -! !endif -! enddo -! endif -! enddo -! ccfmax=maxval(ccfcw) -! ccf(i,lag) = ccfmax -! if(ccfmax.gt.ccf_best) then -! ccfpk = ccfcw -! cwpk = maxloc(ccfpk) -! imsg_best = cwpk(1) -! ccf_best = ccfmax -! endif -! enddo -! enddo -! ccfmax=maxval(ccf) -! ccf_best=ccfmax -! ijpk=maxloc(ccf) -! ipk=ijpk(1)-ia-1 -! jpk=ijpk(2)-53-1 -! f0=nfqso + ipk*df -! xdt=jpk*dtstep - ia=i0+ipk-64 ib=ia+LL-1 j=j0+jpk-7 @@ -238,46 +167,22 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & if(mode_q65.eq.16) nsubmode=4 nFadingModel=1 baud=12000.0/nsps - isreport = 0; do ibw=2,4 b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) call q65_dec_fullaplist(s3,s3prob,codewords,ncw,esnodb,dat4,plog,irc) -! Joe's threshold -! if(irc.ge.0 .and. plog.ge.-255.0) then -! Nico's threshold - if (irc.ge.0) then - ! if it is an RRR type or a CQ Mycall grid - ! we accept the fullaplist threshold - ! other cases in the list are reports which - ! are more frequent in the list and then - ! must be filtered with a higher threshold - if((irc.le.3.0 .or. irc.eq.56.0) .or. plog.ge.-250.0) then + if(irc.ge.0 .and. plog.ge.-255.0) then snr2=esnodb - db(2500.0/baud) id1=1 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 open(55,file='fort.55',status='unknown',position='append') - -! Joe's dump -! write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & -! irc,trim(decoded) -!3055 format(i6,i3,6f8.2,i5,2x,a) - -! Nico's dump for Method 2 -! This are the ccfs of the codeword in the list at the -! ccf peak -! write(55,3083) ccfpk -!3083 format(10f6.1) -! Show also the imsg_best in order to compare it with -! irc. (Interestingly they are always equal!) -! write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & -! irc,(imsg_best-1),trim(decoded) -!3055 format(i6,i3,6f8.2,2i5,2x,a) + write(55,3055) nutc,ibw,xdt,f0,85.0*base,ccfmax,snr2,plog, & + irc,trim(decoded) +3055 format(i6,i3,6f8.2,i5,2x,a) close(55) go to 900 - endif endif enddo From 7500adce8b42b3d2f5c42e4dc23437de285deae5 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 4 Dec 2020 14:53:45 -0500 Subject: [PATCH 192/206] Allow "@1500", etc., single-tone transmissions in Q65 mode. --- Modulator/Modulator.cpp | 2 +- widgets/mainwindow.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modulator/Modulator.cpp b/Modulator/Modulator.cpp index 32645bec2..0d24485cd 100644 --- a/Modulator/Modulator.cpp +++ b/Modulator/Modulator.cpp @@ -318,7 +318,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize) sample=qRound(m_amp*qSin(m_phi)); //Here's where we transmit from a precomputed wave[] array: - if(!m_tuning and (m_toneSpacing < 0)) { + if(!m_tuning and (m_toneSpacing < 0) and (itone[0]<100)) { m_amp=32767.0; sample=qRound(m_amp*foxcom_.wave[m_ic]); } diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 32048bc9e..41e2098f3 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -5156,7 +5156,7 @@ void MainWindow::genCQMsg () msgtype (QString {"%1 %2"}.arg(m_CQtype).arg(m_config.my_callsign()),ui->tx6); } } - if ((m_mode=="JT4" or m_mode=="QRA64") and ui->cbShMsgs->isChecked()) { + if ((m_mode=="JT4" or m_mode=="QRA64" or m_mode=="Q65") and ui->cbShMsgs->isChecked()) { if (ui->cbTx6->isChecked ()) { msgtype ("@1250 (SEND MSGS)", ui->tx6); } else { From 3dd34e13bafa7310666bfd315acfb652dbd9c34e Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 4 Dec 2020 15:29:46 -0500 Subject: [PATCH 193/206] dd "MyCall DxCall DxGrid" to list. Set PLOG_MIN=-240. No list decoding if DxCall is not defined. --- lib/q65_sync.f90 | 3 ++- lib/qra/q65/q65_set_list.f90 | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index aa238d69d..62e3a72e6 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -16,6 +16,7 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & use packjt77 parameter (NSTEP=8) !Step size nsps/NSTEP parameter (LN=2176*63) !LN=LL*NN; LL=64*(mode_q65+2), NN=63 + parameter (PLOG_MIN=-240.0) !List decoding threshold integer*2 iwave(0:nmax-1) !Raw data integer isync(22) !Indices of sync symbols integer itone(85) @@ -171,7 +172,7 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) call q65_dec_fullaplist(s3,s3prob,codewords,ncw,esnodb,dat4,plog,irc) - if(irc.ge.0 .and. plog.ge.-255.0) then + if(irc.ge.0 .and. plog.ge.PLOG_MIN) then snr2=esnodb - db(2500.0/baud) id1=1 write(c77,1000) dat4(1:12),dat4(13)/2 diff --git a/lib/qra/q65/q65_set_list.f90 b/lib/qra/q65/q65_set_list.f90 index f899cac66..4e67e0ff4 100644 --- a/lib/qra/q65/q65_set_list.f90 +++ b/lib/qra/q65/q65_set_list.f90 @@ -8,10 +8,14 @@ subroutine q65_set_list(mycall,hiscall,hisgrid,codewords,ncw) integer isync(22) data isync/1,9,12,13,15,22,23,26,27,33,35,38,46,50,55,60,62,66,69,74,76,85/ + ncw=0 + if(hiscall(1:1).eq. ' ') return + + ncw=58 msg0=trim(mycall)//' '//trim(hiscall) j0=len(trim(msg0))+2 isnr0=-35 - do i=1,57 + do i=1,ncw msg=msg0 if(i.eq.2) msg(j0:j0+2)='RRR' if(i.eq.3) msg(j0:j0+3)='RR73' @@ -22,6 +26,7 @@ subroutine q65_set_list(mycall,hiscall,hisgrid,codewords,ncw) if(iand(i,1).eq.0) write(msg(j0:j0+3),'("R",i3.2)') isnr endif if(i.eq.57) msg='CQ '//trim(hiscall)//' '//hisgrid(1:4) + if(i.eq.58) msg(j0:j0+3)=hisgrid(1:4) call genq65(msg,0,msgsent,itone,i3,n3) i0=1 j=0 @@ -33,7 +38,6 @@ subroutine q65_set_list(mycall,hiscall,hisgrid,codewords,ncw) j=j+1 codewords(j,i)=itone(k) - 1 enddo - ncw=57 ! write(*,3001) i,isnr,codewords(1:13,i),trim(msg) !3001 format(i2,2x,i3.2,2x,13i3,2x,a) enddo From 8b9b71c8946b1f8011eacf593da5f5615de95529 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 4 Dec 2020 15:37:54 -0500 Subject: [PATCH 194/206] Fix the "off by one" issue in measuring f0 for list decodes. --- lib/q65_sync.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index 62e3a72e6..d761fd044 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -142,7 +142,7 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & ijpk=maxloc(ccf) ipk=ijpk(1)-ia-1 jpk=ijpk(2)-53-1 - f0=nfqso + ipk*df + f0=nfqso + (ipk-1)*df xdt=jpk*dtstep imsg_best=imsg endif From 6416777278b878fc2b43f87b7a792d5a7ede578f Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Fri, 4 Dec 2020 15:55:03 -0500 Subject: [PATCH 195/206] Set ':' as the "mode character" for Q65. --- lib/decoder.f90 | 4 ++-- widgets/displaytext.cpp | 1 + widgets/mainwindow.cpp | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/decoder.f90 b/lib/decoder.f90 index a9cd010ae..cb695e708 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -794,12 +794,12 @@ contains if(ntrperiod.lt.60) then write(*,1001) nutc,nsnr,dt,nint(freq),decoded,idec -1001 format(i6.6,i4,f5.1,i5,' + ',1x,a37,1x,i2) +1001 format(i6.6,i4,f5.1,i5,' : ',1x,a37,1x,i2) write(13,1002) nutc,nint(sync),nsnr,dt,freq,0,decoded 1002 format(i6.6,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') else write(*,1003) nutc,nsnr,dt,nint(freq),decoded,idec -1003 format(i4.4,i4,f5.1,i5,' + ',1x,a37,1x,i2) +1003 format(i4.4,i4,f5.1,i5,' : ',1x,a37,1x,i2) write(13,1004) nutc,nint(sync),nsnr,dt,freq,0,decoded 1004 format(i4.4,i4,i5,f6.1,f8.0,i4,3x,a37,' Q65') diff --git a/widgets/displaytext.cpp b/widgets/displaytext.cpp index d498f180e..75af0af68 100644 --- a/widgets/displaytext.cpp +++ b/widgets/displaytext.cpp @@ -484,6 +484,7 @@ void DisplayText::displayTransmittedText(QString text, QString modeTx, qint32 tx if(modeTx=="FT4") t1=" + "; if(modeTx=="FT8") t1=" ~ "; if(modeTx=="JT4") t1=" $ "; + if(modeTx=="Q65") t1=" : "; if(modeTx=="JT65") t1=" # "; if(modeTx=="MSK144") t1=" & "; if(modeTx=="FST4") t1=" ` "; diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 41e2098f3..cba367735 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -4711,7 +4711,8 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie || ("JT65" == m_mode && mode != "#") || ("JT9" == m_mode && mode != "@") || ("MSK144" == m_mode && !("&" == mode || "^" == mode)) - || ("QRA64" == m_mode && mode.left (1) != ":")) { + || ("QRA64" == m_mode && mode.left (1) != ":") + || ("Q65" == m_mode && mode.left (1) != ":")) { return; //Currently we do auto-sequencing only in FT4, FT8, MSK144, FST4, and Q65 } From 077811ae6dd7b99579da27f023ac1be01c1f60d5 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 5 Dec 2020 11:03:16 -0500 Subject: [PATCH 196/206] Update q65params.f90. --- lib/q65params.f90 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/q65params.f90 b/lib/q65params.f90 index c519cc94e..932dcfb36 100644 --- a/lib/q65params.f90 +++ b/lib/q65params.f90 @@ -3,7 +3,7 @@ program q65params integer ntrp(5) integer nsps(5) data ntrp/15,30,60,120,300/ - data nsps/1800,3600,7200,15680,40960/ + data nsps/1800,3600,7200,16000,41472/ write(*,1000) 1000 format('T/R tsym baud BW TxT SNR'/39('-')) @@ -17,4 +17,16 @@ program q65params 1010 format(i3,2f7.3,3f7.1) enddo + do j=1,5 + write(*,1020) char(ichar('A')+j-1) +1020 format(/a1,' T/R baud BW'/20('-')) + do i=1,5 + baud=12000.0/nsps(i) + spacing=baud*2**(j-1) + bw=65.0*spacing + write(*,1030) ntrp(i),spacing,nint(bw) +1030 format(i6,f7.2,i6) + enddo + enddo + end program q65params From 9f8336de4ecb22f0198bee35e234820ea07b0fad Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 5 Dec 2020 11:09:15 -0500 Subject: [PATCH 197/206] Code cleanup. --- lib/test_q65.f90 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 68e28ed3d..8c48d3639 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -95,7 +95,7 @@ program test_q65 dterr=tsym/4.0 nferr=max(1,nint(0.5*baud),nint(fdop/3.0)) - ndec10=nfiles + ndec1z=nfiles do nsnr=ia,ib,-1 snr1=nsnr @@ -143,8 +143,8 @@ program test_q65 write(12,1100) snr1,ntrperiod,csubmode,ndepth,fDop,nsync,ndecn, & ndec1,nfalse,naptype,tdec/nfiles 1100 format(f5.1,i4,1x,a1,i3,f5.1,3i5,i4,i6,5i5,f6.2) - if(ndec1.lt.nfiles/2 .and. ndec10.ge.nfiles/2) then - snr_thresh=snr1 + float(nfiles/2 - ndec1)/(ndec10-ndec1) + if(ndec1.lt.nfiles/2 .and. ndec1z.ge.nfiles/2) then + snr_thresh=snr1 + float(nfiles/2 - ndec1)/(ndec1z-ndec1) open(13,file='snr_thresh.out',status='unknown',position='append') write(13,1200) ntrperiod,csubmode,ndepth,nQSOprogress,nfiles, & fdop,snr_thresh,trim(msg) @@ -154,7 +154,7 @@ program test_q65 flush(6) flush(12) if(ndec1.eq.0 .and. ndecn.eq.0) exit !Bail out if no decodes at this SNR - ndec10=ndec1 + ndec1z=ndec1 enddo ! nsnr 999 end program test_q65 From 742e2ef59f8fab21bebe98d37fac7aabb007f9f8 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 5 Dec 2020 11:09:27 -0500 Subject: [PATCH 198/206] Fix pctile for larger arrays. --- lib/pctile.f90 | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/lib/pctile.f90 b/lib/pctile.f90 index 3bf2ffcf8..c0a6cdb72 100644 --- a/lib/pctile.f90 +++ b/lib/pctile.f90 @@ -1,16 +1,11 @@ subroutine pctile(x,npts,npct,xpct) - parameter (NMAX=256*1024) - real*4 x(npts) - real*4 tmp(NMAX) + real x(npts) + real,allocatable :: tmp(:) - if(npts.le.0) then - xpct=1.0 - go to 900 - endif - if(npts.gt.NMAX) stop + allocate(tmp(npts)) - tmp(1:npts)=x + tmp=x call shell(npts,tmp) j=nint(npts*0.01*npct) if(j.lt.1) j=1 From c50134691db53e9d164e0559c55b61ab896fa42b Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 5 Dec 2020 13:46:07 -0500 Subject: [PATCH 199/206] Adjustments to test_q65 for wider submodes. --- lib/test_q65.f90 | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 8c48d3639..77b3d106c 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -38,13 +38,13 @@ program test_q65 if(ntrperiod.eq.15) then nsps=1800 - i50=-21 + i50=-23 else if(ntrperiod.eq.30) then nsps=3600 - i50=-24 + i50=-26 else if(ntrperiod.eq.60) then nsps=7200 - i50=-28 + i50=-29 else if(ntrperiod.eq.120) then nsps=16000 i50=-31 @@ -54,6 +54,8 @@ program test_q65 else stop 'Invalid TR period' endif + + i50=i50 + 8.0*log(fDop)/log(240.0) ia=i50 + 7 ib=i50 - 10 if(snr.ne.0.0) then @@ -67,12 +69,12 @@ program test_q65 ! 1 2 3 4 5 6 7 ! 123456789012345678901234567890123456789012345678901234567890123456789012345' cmd1='q65sim "K1ABC W9XYZ EN37 " A 1500 5.0 0.0 60 100 F -10.0 > junk0' - cmd2='jt9 -3 -p 15 -L 300 -H 3000 -d 3 -b A -Q 3 *.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 write(cmd1(37:40),'(i4)') nf0 - write(cmd1(41:45),'(f5.1)') fDop + write(cmd1(41:45),'(f5.0)') fDop write(cmd1(46:50),'(f5.2)') dt write(cmd1(51:54),'(i4)') ntrperiod write(cmd1(55:59),'(i5)') nfiles @@ -80,7 +82,9 @@ program test_q65 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 + call system('rm -f *.wav') ! call qra_params(ndepth,maxaptype,idf0max,idt0max,ibwmin,ibwmax,maxdist) @@ -142,7 +146,7 @@ program test_q65 ndec1,nfalse,naptype,tdec/nfiles write(12,1100) snr1,ntrperiod,csubmode,ndepth,fDop,nsync,ndecn, & ndec1,nfalse,naptype,tdec/nfiles -1100 format(f5.1,i4,1x,a1,i3,f5.1,3i5,i4,i6,5i5,f6.2) +1100 format(f5.1,i4,1x,a1,i3,f5.0,3i5,i4,i6,5i5,f6.2) if(ndec1.lt.nfiles/2 .and. ndec1z.ge.nfiles/2) then snr_thresh=snr1 + float(nfiles/2 - ndec1)/(ndec1z-ndec1) open(13,file='snr_thresh.out',status='unknown',position='append') From 53f5e26580fe58ae3063b97088a4d29753fca380 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sat, 5 Dec 2020 13:46:44 -0500 Subject: [PATCH 200/206] First attempt ar reasonabkle values for nsmo and ibw range. --- lib/q65_sync.f90 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index d761fd044..6a723745c 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -47,6 +47,7 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & jz=(txt+1.0)*12000.0/istep !Number of quarter-symbol steps if(nsps.ge.6912) jz=(txt+2.0)*12000.0/istep !For TR 60 s and higher ia=ntol/df + nsmo=int(0.7*mode_q65*mode_q65) allocate(s1(iz,jz)) allocate(s3(-64:LL-65,63)) @@ -78,7 +79,9 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & s1(i,j)=real(c0(i))**2 + aimag(c0(i))**2 enddo ! For large Doppler spreads, should we smooth the spectra here? -! call smo121(s1(1:iz,j),iz) + do i=1,nsmo + call smo121(s1(1:iz,j),iz) + enddo enddo i0=nint(nfqso/df) !Target QSO frequency @@ -168,7 +171,9 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & if(mode_q65.eq.16) nsubmode=4 nFadingModel=1 baud=12000.0/nsps - do ibw=2,4 + ibwa=1.8*log(baud*mode_q65) + 2 + ibwb=ibwa+4 + do ibw=ibwa,ibwb b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) call q65_dec_fullaplist(s3,s3prob,codewords,ncw,esnodb,dat4,plog,irc) From a47f5e5103e27f98194196fd4200d69f16f87b90 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 6 Dec 2020 08:09:28 -0500 Subject: [PATCH 201/206] Correct what appears to be an error in q65_intrinsics_fastfading: max hidx=63, not 64? --- lib/qra/q65/q65.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/qra/q65/q65.c b/lib/qra/q65/q65.c index c9d776bc6..f47f25fa3 100644 --- a/lib/qra/q65/q65.c +++ b/lib/qra/q65/q65.c @@ -301,8 +301,7 @@ int q65_intrinsics_fastfading(q65_codec_ds *pCodec, const float *pCurSym, *pCurBin; float *pCurIx; -// printf("pcodec=%08x submode=%d fadingmodel=%d B90Ts=%f\n",pcodec, submode,fadingModel, B90Ts); - + // printf("pcodec=%08x submode=%d fadingmodel=%d B90Ts=%f\n",pCodec, submode,fadingModel, B90Ts); if (pCodec==NULL) return Q65_DECODE_INVPARAMS; // invalid pCodec pointer @@ -322,8 +321,8 @@ int q65_intrinsics_fastfading(q65_codec_ds *pCodec, if (hidx<0) hidx = 0; else - if (hidx > 64) - hidx=64; + if (hidx > 63) //Changed by K1JT: previously max was 64. + hidx=63; //Changed by K1JT: previously max was 64. // select the appropriate weighting fading coefficients array if (fadingModel==0) { // gaussian fading model @@ -337,7 +336,7 @@ int q65_intrinsics_fastfading(q65_codec_ds *pCodec, hptr = gptr_tab_lorentz[hidx]; // pointer to the first (L+1)/2 coefficients of w fun } else - return Q65_DECODE_INVPARAMS; // invalid fading model + return Q65_DECODE_INVPARAMS; // invalid fading model // compute (euristically) the optimal decoder metric accordingly the given spread amount // We assume that the decoder 50% decoding threshold is: @@ -400,7 +399,8 @@ int q65_intrinsics_fastfading(q65_codec_ds *pCodec, // compute the fast fading weights accordingly to the Es/No ratio // for which we compute the exact intrinsics probabilities for (k=0;k Date: Sun, 6 Dec 2020 08:12:16 -0500 Subject: [PATCH 202/206] Allow fDop = 0.0 in test_q65. --- lib/test_q65.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_q65.f90 b/lib/test_q65.f90 index 77b3d106c..d8c1f0763 100644 --- a/lib/test_q65.f90 +++ b/lib/test_q65.f90 @@ -55,7 +55,7 @@ program test_q65 stop 'Invalid TR period' endif - i50=i50 + 8.0*log(fDop)/log(240.0) + i50=i50 + 8.0*log(1.0+fDop)/log(240.0) ia=i50 + 7 ib=i50 - 10 if(snr.ne.0.0) then From 4b42937c3528c2d79ffefa3719c711968011a4ce Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 6 Dec 2020 08:12:58 -0500 Subject: [PATCH 203/206] Minor tweaks in q65_sync. --- lib/q65_sync.f90 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/q65_sync.f90 b/lib/q65_sync.f90 index 6a723745c..3e45f9b56 100644 --- a/lib/q65_sync.f90 +++ b/lib/q65_sync.f90 @@ -48,6 +48,7 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & if(nsps.ge.6912) jz=(txt+2.0)*12000.0/istep !For TR 60 s and higher ia=ntol/df nsmo=int(0.7*mode_q65*mode_q65) + if(nsmo.lt.1) nsmo=1 allocate(s1(iz,jz)) allocate(s3(-64:LL-65,63)) @@ -172,7 +173,7 @@ subroutine q65_sync(nutc,iwave,nmax,mode_q65,codewords,ncw,nsps,nfqso,ntol, & nFadingModel=1 baud=12000.0/nsps ibwa=1.8*log(baud*mode_q65) + 2 - ibwb=ibwa+4 + ibwb=min(10,ibwa+4) do ibw=ibwa,ibwb b90=1.72**ibw call q65_intrinsics_ff(s3,nsubmode,b90/baud,nFadingModel,s3prob) From f290cec93b41eca05107780aed7e5ba0279498b6 Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Sun, 6 Dec 2020 17:51:06 +0000 Subject: [PATCH 204/206] Revert "Remove JT9+JT65 mode. Remove labNextCall. Tighten up central array of GUI controls." This reverts commit df2daf60bda6ee68df9114666a10ed0a235782fc. --- widgets/mainwindow.cpp | 102 ++++++++++++++- widgets/mainwindow.h | 2 + widgets/mainwindow.ui | 286 +++++++++++++++++++++++------------------ 3 files changed, 263 insertions(+), 127 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index cba367735..265d1e4f5 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -601,6 +601,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionFT8->setActionGroup(modeGroup); ui->actionJT9->setActionGroup(modeGroup); ui->actionJT65->setActionGroup(modeGroup); + ui->actionJT9_JT65->setActionGroup(modeGroup); ui->actionJT4->setActionGroup(modeGroup); ui->actionWSPR->setActionGroup(modeGroup); ui->actionEcho->setActionGroup(modeGroup); @@ -859,6 +860,9 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_msg[0][0]=0; ui->labDXped->setVisible(false); ui->labDXped->setStyleSheet("QLabel {background-color: red; color: white;}"); + ui->labNextCall->setText(""); + ui->labNextCall->setVisible(false); + ui->labNextCall->setToolTip(""); //### Possibly temporary ? ### char const * const power[] = {"1 mW","2 mW","5 mW","10 mW","20 mW","50 mW","100 mW","200 mW","500 mW", "1 W","2 W","5 W","10 W","20 W","50 W","100 W","200 W","500 W","1 kW"}; @@ -1221,6 +1225,8 @@ void MainWindow::readSettings() m_settings->beginGroup("Common"); m_mode=m_settings->value("Mode","JT9").toString(); m_modeTx=m_settings->value("ModeTx","JT9").toString(); + if(m_modeTx.mid(0,3)=="JT9") ui->pbTxMode->setText("Tx JT9 @"); + if(m_modeTx=="JT65") ui->pbTxMode->setText("Tx JT65 #"); ui->actionNone->setChecked(m_settings->value("SaveNone",true).toBool()); ui->actionSave_decoded->setChecked(m_settings->value("SaveDecoded",false).toBool()); ui->actionSave_all->setChecked(m_settings->value("SaveAll",false).toBool()); @@ -2115,6 +2121,8 @@ void MainWindow::keyPressEvent (QKeyEvent * e) return; case Qt::Key_Escape: m_nextCall=""; + ui->labNextCall->setStyleSheet(""); + ui->labNextCall->setText(""); on_stopTxButton_clicked(); abortQSO(); return; @@ -3466,6 +3474,11 @@ void MainWindow::readFromStdout() //readFromStdout ui->decodedTextBrowser2->displayDecodedText(decodedtext0,m_baseCall,m_mode,m_config.DXCC(), m_logBook,m_currentBand,m_config.ppfx()); } + if(m_mode!="JT4") { + bool b65=decodedtext.isJT65(); + if(b65 and m_modeTx!="JT65") on_pbTxMode_clicked(); + if(!b65 and m_modeTx=="JT65") on_pbTxMode_clicked(); + } m_QSOText = decodedtext.string ().trimmed (); } @@ -4376,6 +4389,8 @@ void MainWindow::useNextCall() { ui->dxCallEntry->setText(m_nextCall); m_nextCall=""; + ui->labNextCall->setStyleSheet(""); + ui->labNextCall->setText(""); if(m_nextGrid.contains(grid_regexp)) { ui->dxGridEntry->setText(m_nextGrid); m_ntx=2; @@ -4787,9 +4802,11 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie if (message.isJT9()) { m_modeTx="JT9"; + ui->pbTxMode->setText("Tx JT9 @"); m_wideGraph->setModeTx(m_modeTx); } else if (message.isJT65()) { m_modeTx="JT65"; + ui->pbTxMode->setText("Tx JT65 #"); m_wideGraph->setModeTx(m_modeTx); } } else if ((message.isJT9 () and m_modeTx != "JT9" and m_mode != "JT4") or @@ -5021,6 +5038,17 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } } else { // nothing for us +// if(message_words.size () > 3 // enough fields for a normal message +// && SpecOp::RTTY == m_config.special_op_id() +// && (message_words.at(1).contains(m_baseCall) || "DE" == message_words.at(1)) +// && (!message_words.at(2).contains(qso_partner_base_call) and !bEU_VHF_w2)) { +//// Queue up the next QSO partner +// m_nextCall=message_words.at(2); +// m_nextGrid=message_words.at(3); +// m_nextRpt=message.report(); +// ui->labNextCall->setText("Next: " + m_nextCall); +// ui->labNextCall->setStyleSheet("QLabel {color: #000000; background-color: #66ff66}"); +// } return; } } @@ -5886,7 +5914,7 @@ void MainWindow::displayWidgets(qint64 n) if(i==8) ui->cbFast9->setVisible(b); if(i==9) ui->cbAutoSeq->setVisible(b); if(i==10) ui->cbTx6->setVisible(b); -// if(i==11) ui->pbTxMode->setVisible(b); + if(i==11) ui->pbTxMode->setVisible(b); if(i==12) ui->pbR2T->setVisible(b); if(i==13) ui->pbT2R->setVisible(b); if(i==14) ui->cbHoldTxFreq->setVisible(b); @@ -5907,7 +5935,7 @@ void MainWindow::displayWidgets(qint64 n) if(i==25) ui->actionEnable_AP_JT65->setVisible (b); if(i==26) ui->actionEnable_AP_DXcall->setVisible (b); if(i==27) ui->cbFirst->setVisible(b); -// if(i==28) ui->labNextCall->setVisible(b); + if(i==28) ui->labNextCall->setVisible(b); if(i==29) ui->measure_check_box->setVisible(b); if(i==30) ui->labDXped->setVisible(b); if(i==31) ui->cbRxAll->setVisible(b); @@ -6257,14 +6285,58 @@ void MainWindow::on_actionJT9_triggered() statusChanged(); } +void MainWindow::on_actionJT9_JT65_triggered() +{ + m_mode="JT9+JT65"; + WSPR_config(false); + switch_mode (Modes::JT65); + if(m_modeTx != "JT65") { + ui->pbTxMode->setText("Tx JT9 @"); + m_modeTx="JT9"; + } + m_nSubMode=0; //Dual-mode always means JT9 and JT65A + m_TRperiod=60.0; + m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe + m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe + m_nsps=6912; + m_FFTSize = m_nsps / 2; + Q_EMIT FFTSize (m_FFTSize); + m_hsymStop=174; + if(m_config.decode_at_52s()) m_hsymStop=183; + m_toneSpacing=0.0; + setup_status_bar (false); + ui->actionJT9_JT65->setChecked(true); + VHF_features_enabled(false); + m_wideGraph->setPeriod(m_TRperiod,m_nsps); + m_wideGraph->setMode(m_mode); + m_wideGraph->setModeTx(m_modeTx); + m_bFastMode=false; + m_bFast9=false; + ui->sbSubmode->setValue(0); + ui->lh_decodes_title_label->setText(tr ("Band Activity")); + ui->rh_decodes_title_label->setText(tr ("Rx Frequency")); + ui->lh_decodes_headings_label->setText("UTC dB DT Freq " + tr ("Message")); + ui->rh_decodes_headings_label->setText("UTC dB DT Freq " + tr ("Message")); + displayWidgets(nWidgets("111010000001111000010000000000001000")); + fast_config(false); + statusChanged(); +} + void MainWindow::on_actionJT65_triggered() { + if(m_mode=="JT4" or m_mode=="WSPR" or m_mode=="FST4W") { +// If coming from JT4, WSPR, or FST4W mode, pretend temporarily that we're coming +// from JT9 and click the pbTxMode button + m_modeTx="JT9"; + on_pbTxMode_clicked(); + } on_actionJT9_triggered(); m_mode="JT65"; m_modeTx="JT65"; bool bVHF=m_config.enable_VHF_features(); WSPR_config(false); switch_mode (Modes::JT65); + if(m_modeTx!="JT65") on_pbTxMode_clicked(); m_TRperiod=60.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe @@ -6416,6 +6488,7 @@ void MainWindow::on_actionMSK144_triggered() if("JT4"==m_mode) ui->actionJT4->setChecked(true); if("JT9"==m_mode) ui->actionJT9->setChecked(true); if("JT65"==m_mode) ui->actionJT65->setChecked(true); + if("JT9_JT65"==m_mode) ui->actionJT9_JT65->setChecked(true); if("ISCAT"==m_mode) ui->actionISCAT->setChecked(true); if("QRA64"==m_mode) ui->actionQRA64->setChecked(true); if("Q65"==m_mode) ui->actionQ65->setChecked(true); @@ -7000,6 +7073,21 @@ void MainWindow::on_readFreq_clicked() } } +void MainWindow::on_pbTxMode_clicked() +{ + if(m_mode=="JT9+JT65") { + if(m_modeTx=="JT9") { + m_modeTx="JT65"; + ui->pbTxMode->setText("Tx JT65 #"); + } else { + m_modeTx="JT9"; + ui->pbTxMode->setText("Tx JT9 @"); + } + m_wideGraph->setModeTx(m_modeTx); + statusChanged(); + } +} + void MainWindow::setXIT(int n, Frequency base) { if (m_transmitting && !m_config.tx_QSY_allowed ()) return; @@ -7478,6 +7566,15 @@ void MainWindow::transmitDisplay (bool transmitting) // the following are always disallowed in transmit ui->menuMode->setEnabled (!transmitting); + //ui->bandComboBox->setEnabled (!transmitting); + if (!transmitting) { + if (m_mode == "JT9+JT65") { + // allow mode switch in Rx when in dual mode + ui->pbTxMode->setEnabled (true); + } + } else { + ui->pbTxMode->setEnabled (false); + } } } @@ -9182,6 +9279,7 @@ void MainWindow::set_mode (QString const& mode) else if ("FT8" == mode) on_actionFT8_triggered (); else if ("JT4" == mode) on_actionJT4_triggered (); else if ("JT9" == mode) on_actionJT9_triggered (); + else if ("JT9+JT65" == mode) on_actionJT9_JT65_triggered (); else if ("JT65" == mode) on_actionJT65_triggered (); else if ("QRA64" == mode) on_actionQRA64_triggered (); else if ("Q65" == mode) on_actionQ65_triggered (); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index 4ab9a4102..3f3fad372 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -204,6 +204,7 @@ private slots: void on_logQSOButton_clicked(); void on_actionJT9_triggered(); void on_actionJT65_triggered(); + void on_actionJT9_JT65_triggered(); void on_actionJT4_triggered(); void on_actionFT4_triggered(); void on_actionFT8_triggered(); @@ -241,6 +242,7 @@ private slots: void on_bandComboBox_editTextChanged (QString const& text); void on_bandComboBox_activated (int index); void on_readFreq_clicked(); + void on_pbTxMode_clicked(); void on_RxFreqSpinBox_valueChanged(int n); void on_outAttenuation_valueChanged (int); void rigOpen (); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 51dc92757..b42410cd7 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 805 - 584 + 589 @@ -596,7 +596,7 @@ - + @@ -1225,6 +1225,25 @@ Yellow when too low + + + + true + + + + 0 + 0 + + + + Toggle Tx mode + + + Tx JT9 @ + + + @@ -1250,6 +1269,53 @@ Yellow when too low + + + + <html><head/><body><p>Submode determines tone spacing; A is narrowest.</p></body></html> + + + Submode determines tone spacing; A is narrowest. + + + Qt::AlignCenter + + + Submode + + + 0 + + + 7 + + + + + + + Qt::AlignCenter + + + + + + F High + + + 100 + + + 5000 + + + 100 + + + 1400 + + + @@ -1319,6 +1385,44 @@ Yellow when too low + + + + Qt::AlignCenter + + + F Low + + + 100 + + + 5000 + + + 100 + + + 600 + + + + + + + <html><head/><body><p>Double-click on another caller to queue that call for your next QSO.</p></body></html> + + + Double-click on another caller to queue that call for your next QSO. + + + Next Call + + + Qt::AlignCenter + + + @@ -1425,6 +1529,60 @@ Not available to nonstandard callsign holders. + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Tx# + + + 1 + + + 4095 + + + + + + + <html><head/><body><p>Check to keep Tx frequency fixed when double-clicking on decoded text.</p></body></html> + + + Check to keep Tx frequency fixed when double-clicking on decoded text. + + + Hold Tx Freq + + + + + + + <html><head/><body><p>Synchronizing threshold. Lower numbers accept weaker sync signals.</p></body></html> + + + Synchronizing threshold. Lower numbers accept weaker sync signals. + + + Qt::AlignCenter + + + Sync + + + -2 + + + 10 + + + 1 + + + @@ -1552,129 +1710,6 @@ When not checked you can view the calibration results. - - - - <html><head/><body><p>Check to keep Tx frequency fixed when double-clicking on decoded text.</p></body></html> - - - Check to keep Tx frequency fixed when double-clicking on decoded text. - - - Hold Tx Freq - - - - - - - Qt::AlignCenter - - - F Low - - - 100 - - - 5000 - - - 100 - - - 600 - - - - - - - Qt::AlignCenter - - - - - - F High - - - 100 - - - 5000 - - - 100 - - - 1400 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - Tx# - - - 1 - - - 4095 - - - - - - - <html><head/><body><p>Submode determines tone spacing; A is narrowest.</p></body></html> - - - Submode determines tone spacing; A is narrowest. - - - Qt::AlignCenter - - - Submode - - - 0 - - - 7 - - - - - - - <html><head/><body><p>Synchronizing threshold. Lower numbers accept weaker sync signals.</p></body></html> - - - Synchronizing threshold. Lower numbers accept weaker sync signals. - - - Qt::AlignCenter - - - Sync - - - -2 - - - 10 - - - 1 - - - @@ -2864,6 +2899,7 @@ list. The list can be maintained in Settings (F2). + From 3d9a099fcea2a705b701b4e6ca2fe651f1867a6d Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Mon, 7 Dec 2020 00:18:52 +0000 Subject: [PATCH 205/206] Reinstate changes that were reverted from commit df2daf6 Changes were moved aside to simplify a big merge commit with many conflicts. --- widgets/mainwindow.cpp | 102 +---------------------------------------- widgets/mainwindow.h | 2 - widgets/mainwindow.ui | 46 +------------------ 3 files changed, 3 insertions(+), 147 deletions(-) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index ad2713291..d6c407d7f 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -593,7 +593,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, ui->actionFT8->setActionGroup(modeGroup); ui->actionJT9->setActionGroup(modeGroup); ui->actionJT65->setActionGroup(modeGroup); - ui->actionJT9_JT65->setActionGroup(modeGroup); ui->actionJT4->setActionGroup(modeGroup); ui->actionWSPR->setActionGroup(modeGroup); ui->actionEcho->setActionGroup(modeGroup); @@ -853,9 +852,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_msg[0][0]=0; ui->labDXped->setVisible(false); ui->labDXped->setStyleSheet("QLabel {background-color: red; color: white;}"); - ui->labNextCall->setText(""); - ui->labNextCall->setVisible(false); - ui->labNextCall->setToolTip(""); //### Possibly temporary ? ### char const * const power[] = {"1 mW","2 mW","5 mW","10 mW","20 mW","50 mW","100 mW","200 mW","500 mW", "1 W","2 W","5 W","10 W","20 W","50 W","100 W","200 W","500 W","1 kW"}; @@ -1246,8 +1242,6 @@ void MainWindow::readSettings() m_settings->beginGroup("Common"); m_mode=m_settings->value("Mode","JT9").toString(); m_modeTx=m_settings->value("ModeTx","JT9").toString(); - if(m_modeTx.mid(0,3)=="JT9") ui->pbTxMode->setText("Tx JT9 @"); - if(m_modeTx=="JT65") ui->pbTxMode->setText("Tx JT65 #"); ui->actionNone->setChecked(m_settings->value("SaveNone",true).toBool()); ui->actionSave_decoded->setChecked(m_settings->value("SaveDecoded",false).toBool()); ui->actionSave_all->setChecked(m_settings->value("SaveAll",false).toBool()); @@ -2141,8 +2135,6 @@ void MainWindow::keyPressEvent (QKeyEvent * e) return; case Qt::Key_Escape: m_nextCall=""; - ui->labNextCall->setStyleSheet(""); - ui->labNextCall->setText(""); on_stopTxButton_clicked(); abortQSO(); return; @@ -3524,11 +3516,6 @@ void MainWindow::readFromStdout() //readFromStdout ui->decodedTextBrowser2->displayDecodedText(decodedtext0,m_baseCall,m_mode,m_config.DXCC(), m_logBook,m_currentBand,m_config.ppfx()); } - if(m_mode!="JT4") { - bool b65=decodedtext.isJT65(); - if(b65 and m_modeTx!="JT65") on_pbTxMode_clicked(); - if(!b65 and m_modeTx=="JT65") on_pbTxMode_clicked(); - } m_QSOText = decodedtext.string ().trimmed (); } @@ -4450,8 +4437,6 @@ void MainWindow::useNextCall() { ui->dxCallEntry->setText(m_nextCall); m_nextCall=""; - ui->labNextCall->setStyleSheet(""); - ui->labNextCall->setText(""); if(m_nextGrid.contains(grid_regexp)) { ui->dxGridEntry->setText(m_nextGrid); m_ntx=2; @@ -4865,11 +4850,9 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie if (message.isJT9()) { m_modeTx="JT9"; - ui->pbTxMode->setText("Tx JT9 @"); m_wideGraph->setModeTx(m_modeTx); } else if (message.isJT65()) { m_modeTx="JT65"; - ui->pbTxMode->setText("Tx JT65 #"); m_wideGraph->setModeTx(m_modeTx); } } else if ((message.isJT9 () and m_modeTx != "JT9" and m_mode != "JT4") or @@ -5112,17 +5095,6 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } } else { // nothing for us -// if(message_words.size () > 3 // enough fields for a normal message -// && SpecOp::RTTY == m_config.special_op_id() -// && (message_words.at(1).contains(m_baseCall) || "DE" == message_words.at(1)) -// && (!message_words.at(2).contains(qso_partner_base_call) and !bEU_VHF_w2)) { -//// Queue up the next QSO partner -// m_nextCall=message_words.at(2); -// m_nextGrid=message_words.at(3); -// m_nextRpt=message.report(); -// ui->labNextCall->setText("Next: " + m_nextCall); -// ui->labNextCall->setStyleSheet("QLabel {color: #000000; background-color: #66ff66}"); -// } return; } } @@ -5989,7 +5961,7 @@ void MainWindow::displayWidgets(qint64 n) if(i==8) ui->cbFast9->setVisible(b); if(i==9) ui->cbAutoSeq->setVisible(b); if(i==10) ui->cbTx6->setVisible(b); - if(i==11) ui->pbTxMode->setVisible(b); + // if(i==11) ui->pbTxMode->setVisible(b); if(i==12) ui->pbR2T->setVisible(b); if(i==13) ui->pbT2R->setVisible(b); if(i==14) ui->cbHoldTxFreq->setVisible(b); @@ -6010,7 +5982,7 @@ void MainWindow::displayWidgets(qint64 n) if(i==25) ui->actionEnable_AP_JT65->setVisible (b); if(i==26) ui->actionEnable_AP_DXcall->setVisible (b); if(i==27) ui->cbFirst->setVisible(b); - if(i==28) ui->labNextCall->setVisible(b); + // if(i==28) ui->labNextCall->setVisible(b); if(i==29) ui->measure_check_box->setVisible(b); if(i==30) ui->labDXped->setVisible(b); if(i==31) ui->cbRxAll->setVisible(b); @@ -6364,58 +6336,14 @@ void MainWindow::on_actionJT9_triggered() statusChanged(); } -void MainWindow::on_actionJT9_JT65_triggered() -{ - m_mode="JT9+JT65"; - WSPR_config(false); - switch_mode (Modes::JT65); - if(m_modeTx != "JT65") { - ui->pbTxMode->setText("Tx JT9 @"); - m_modeTx="JT9"; - } - m_nSubMode=0; //Dual-mode always means JT9 and JT65A - m_TRperiod=60.0; - m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe - m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe - m_nsps=6912; - m_FFTSize = m_nsps / 2; - Q_EMIT FFTSize (m_FFTSize); - m_hsymStop=174; - if(m_config.decode_at_52s()) m_hsymStop=183; - m_toneSpacing=0.0; - setup_status_bar (false); - ui->actionJT9_JT65->setChecked(true); - VHF_features_enabled(false); - m_wideGraph->setPeriod(m_TRperiod,m_nsps); - m_wideGraph->setMode(m_mode); - m_wideGraph->setModeTx(m_modeTx); - m_bFastMode=false; - m_bFast9=false; - ui->sbSubmode->setValue(0); - ui->lh_decodes_title_label->setText(tr ("Band Activity")); - ui->rh_decodes_title_label->setText(tr ("Rx Frequency")); - ui->lh_decodes_headings_label->setText("UTC dB DT Freq " + tr ("Message")); - ui->rh_decodes_headings_label->setText("UTC dB DT Freq " + tr ("Message")); - displayWidgets(nWidgets("111010000001111000010000000000001000")); - fast_config(false); - statusChanged(); -} - void MainWindow::on_actionJT65_triggered() { - if(m_mode=="JT4" or m_mode=="WSPR" or m_mode=="FST4W") { -// If coming from JT4, WSPR, or FST4W mode, pretend temporarily that we're coming -// from JT9 and click the pbTxMode button - m_modeTx="JT9"; - on_pbTxMode_clicked(); - } on_actionJT9_triggered(); m_mode="JT65"; m_modeTx="JT65"; bool bVHF=m_config.enable_VHF_features(); WSPR_config(false); switch_mode (Modes::JT65); - if(m_modeTx!="JT65") on_pbTxMode_clicked(); m_TRperiod=60.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe @@ -6567,7 +6495,6 @@ void MainWindow::on_actionMSK144_triggered() if("JT4"==m_mode) ui->actionJT4->setChecked(true); if("JT9"==m_mode) ui->actionJT9->setChecked(true); if("JT65"==m_mode) ui->actionJT65->setChecked(true); - if("JT9_JT65"==m_mode) ui->actionJT9_JT65->setChecked(true); if("ISCAT"==m_mode) ui->actionISCAT->setChecked(true); if("QRA64"==m_mode) ui->actionQRA64->setChecked(true); if("Q65"==m_mode) ui->actionQ65->setChecked(true); @@ -7152,21 +7079,6 @@ void MainWindow::on_readFreq_clicked() } } -void MainWindow::on_pbTxMode_clicked() -{ - if(m_mode=="JT9+JT65") { - if(m_modeTx=="JT9") { - m_modeTx="JT65"; - ui->pbTxMode->setText("Tx JT65 #"); - } else { - m_modeTx="JT9"; - ui->pbTxMode->setText("Tx JT9 @"); - } - m_wideGraph->setModeTx(m_modeTx); - statusChanged(); - } -} - void MainWindow::setXIT(int n, Frequency base) { if (m_transmitting && !m_config.tx_QSY_allowed ()) return; @@ -7647,15 +7559,6 @@ void MainWindow::transmitDisplay (bool transmitting) // the following are always disallowed in transmit ui->menuMode->setEnabled (!transmitting); - //ui->bandComboBox->setEnabled (!transmitting); - if (!transmitting) { - if (m_mode == "JT9+JT65") { - // allow mode switch in Rx when in dual mode - ui->pbTxMode->setEnabled (true); - } - } else { - ui->pbTxMode->setEnabled (false); - } } } @@ -9381,7 +9284,6 @@ void MainWindow::set_mode (QString const& mode) else if ("FT8" == mode) on_actionFT8_triggered (); else if ("JT4" == mode) on_actionJT4_triggered (); else if ("JT9" == mode) on_actionJT9_triggered (); - else if ("JT9+JT65" == mode) on_actionJT9_JT65_triggered (); else if ("JT65" == mode) on_actionJT65_triggered (); else if ("QRA64" == mode) on_actionQRA64_triggered (); else if ("Q65" == mode) on_actionQ65_triggered (); diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index d798d96bd..b9c43be17 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -209,7 +209,6 @@ private slots: void on_logQSOButton_clicked(); void on_actionJT9_triggered(); void on_actionJT65_triggered(); - void on_actionJT9_JT65_triggered(); void on_actionJT4_triggered(); void on_actionFT4_triggered(); void on_actionFT8_triggered(); @@ -247,7 +246,6 @@ private slots: void on_bandComboBox_editTextChanged (QString const& text); void on_bandComboBox_activated (int index); void on_readFreq_clicked(); - void on_pbTxMode_clicked(); void on_RxFreqSpinBox_valueChanged(int n); void on_outAttenuation_valueChanged (int); void rigOpen (); diff --git a/widgets/mainwindow.ui b/widgets/mainwindow.ui index 639a5b567..b945e9210 100644 --- a/widgets/mainwindow.ui +++ b/widgets/mainwindow.ui @@ -1504,25 +1504,6 @@ When not checked you can view the calibration results. - - - - true - - - - 0 - 0 - - - - Toggle Tx mode - - - Tx JT9 @ - - - @@ -1555,22 +1536,6 @@ When not checked you can view the calibration results. 0 - - - - <html><head/><body><p>Double-click on another caller to queue that call for your next QSO.</p></body></html> - - - Double-click on another caller to queue that call for your next QSO. - - - Next Call - - - Qt::AlignCenter - - - @@ -2828,7 +2793,7 @@ Double-click to reset to the standard 73 message 0 0 - 834 + 1110 21 @@ -2918,7 +2883,6 @@ Double-click to reset to the standard 73 message - @@ -3115,14 +3079,6 @@ Double-click to reset to the standard 73 message JT65 - - - true - - - JT9+JT65 - - true From d42363587ecec1ce4707be685e04e0758cd4b9e7 Mon Sep 17 00:00:00 2001 From: Joe Taylor Date: Sun, 6 Dec 2020 21:42:30 -0500 Subject: [PATCH 206/206] Swtich from a fast mode to Q65 now closes FastGraph and opens WideGraph, as it should. --- widgets/mainwindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index d6c407d7f..1a1990f07 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -6428,6 +6428,7 @@ void MainWindow::on_actionQ65_triggered() m_modeTx="Q65"; ui->actionQ65->setChecked(true); switch_mode(Modes::Q65); + fast_config(false); setup_status_bar(true); m_nsps=6912; //For symspec only m_FFTSize = m_nsps / 2;