diff --git a/Configuration.ui b/Configuration.ui index d9c801554..5d4bd8213 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -2280,7 +2280,7 @@ Right click for insert and delete options. - false + true <html><head/><body><p>Decode on-the-fly rather than at end of Rx sequence.</p></body></html> diff --git a/lib/mskrtd.f90 b/lib/mskrtd.f90 new file mode 100644 index 000000000..95c8b496c --- /dev/null +++ b/lib/mskrtd.f90 @@ -0,0 +1,224 @@ +subroutine mskrtd(id2,nutc0,tsec,ntol,line) + +! Real-time decoder for MSK144. +! Analysis block size = NZ = 7168 samples, t_block = 0.597333 s +! Called from hspec() at half-block increments, about 0.3 s + + parameter (NZ=7168) !Block size + parameter (NSPM=864) !Number of samples per message frame + parameter (NFFT1=8192) !FFT size for making analytic signal + parameter (NAVGMAX=7) !Coherently average up to 7 frames + parameter (NPTSMAX=7*NSPM) !Max points analyzed at once + + integer*2 id2(NZ) !Raw 16-bit data + character*22 msgreceived !Decoded message + character*80 line !Formatted line with UTC dB T Freq Msg + + complex cdat(NFFT1) !Analytic signal + complex cdat2(NFFT1) !Signal shifted to baseband + complex c(NSPM) !Coherently averaged complex data + complex ct(NSPM) + complex ct2(2*NSPM) + complex cs(NSPM) + complex cb(42) !Complex waveform for sync word + complex cfac,cca,ccb + complex cc(0:NSPM-1) + +! integer*8 count0,count1,count2,count3,clkfreq + integer s8(8),hardbits(144) + integer iloc(1) + integer ipeaks(10) + integer nav(6) + integer*1 decoded(80) + + real cbi(42),cbq(42) + real d(NFFT1) + real xcc(0:NSPM-1) + real xccs(0:NSPM-1) + real pp(12) !Half-sine pulse shape + real softbits(144) + real lratio(128) + real llr(128) + logical first + data first/.true./ + data s8/0,1,1,1,0,0,1,0/ + data nav/1,2,3,5,7,9/ + save first,cb,fs,pi,twopi,dt,s8,pp,t03,t12,nutc00 + +! call system_clock(count0,clkfreq) + if(first) then + pi=4.0*atan(1.0) + twopi=8.0*atan(1.0) + fs=12000.0 + dt=1.0/fs + + do i=1,12 !Define half-sine pulse + angle=(i-1)*pi/12.0 + pp(i)=sin(angle) + enddo + +! Define the sync word waveforms + s8=2*s8-1 + cbq(1:6)=pp(7:12)*s8(1) + cbq(7:18)=pp*s8(3) + cbq(19:30)=pp*s8(5) + cbq(31:42)=pp*s8(7) + cbi(1:12)=pp*s8(2) + cbi(13:24)=pp*s8(4) + cbi(25:36)=pp*s8(6) + cbi(37:42)=pp(1:6)*s8(8) + cb=cmplx(cbi,cbq) + + first=.false. + t03=0.0 + t12=0.0 + nutc00=-1 + endif + + msgreceived=' ' + max_iterations=10 + niterations=0 + d(1:NZ)=id2 + rms=sqrt(sum(d(1:NZ)*d(1:NZ))/NZ) + if(rms.lt.1.0) return + fac=1.0/rms + d(1:NZ)=fac*d(1:NZ) + d(NZ+1:NFFT1)=0. + call analytic(d,NZ,NFFT1,cdat) !Convert to analytic signal and filter + + nmessages=0 + line=char(0) + nshort=0 + npts=7168 + nsnr=-4 !### Temporary ### + + do iavg=1,5 + navg=nav(iavg) + ndf=nint(7.0/navg) + 1 + xmax=0.0 + bestf=0.0 +! call system_clock(count1,clkfreq) + do ifr=-ntol,ntol,ndf !Find freq that maximizes sync + ferr=ifr + call tweak1(cdat,NPTS,-(1500+ferr),cdat2) + c=0 + do i=1,navg + ib=(i-1)*NSPM+1 + ie=ib+NSPM-1 + c(1:NSPM)=c(1:NSPM)+cdat2(ib:ie) + enddo + + cc=0 + ct2(1:NSPM)=c + ct2(NSPM+1:2*NSPM)=c + do ish=0,NSPM-1 + cc(ish)=dot_product(ct2(1+ish:42+ish)+ct2(336+ish:377+ish),cb(1:42)) + enddo + + xcc=abs(cc) + xb=maxval(xcc)/(48.0*sqrt(float(navg))) + if(xb.gt.xmax) then + xmax=xb + bestf=ferr + cs=c + xccs=xcc + endif + enddo +! call system_clock(count2,clkfreq) + + fest=1500+bestf + c=cs + xcc=xccs + +! Find 2 largest peaks + do ipk=1,2 + iloc=maxloc(xcc) + ic2=iloc(1) + ipeaks(ipk)=ic2 + xcc(max(0,ic2-7):min(NSPM-1,ic2+7))=0.0 + enddo + + do ipk=1,2 + do is=1,3 + ic0=ipeaks(ipk) + if(is.eq.2) ic0=max(1,ic0-1) + if(is.eq.3) ic0=min(NSPM,ic0+1) + ct=cshift(c,ic0-1) + +! Estimate final frequency error and carrier phase. + cca=sum(ct(1:1+41)*conjg(cb)) + ccb=sum(ct(1+56*6:1+56*6+41)*conjg(cb)) + cfac=ccb*conjg(cca) +! ffin=atan2(imag(cfac),real(cfac))/(twopi*56*6*dt) + phase0=atan2(imag(cca+ccb),real(cca+ccb)) + +! Remove phase error: rotate constellation so sample points lie on I/Q axes + cfac=cmplx(cos(phase0),sin(phase0)) + ct=ct*conjg(cfac) + +! Use matched filter + softbits(1)=sum(imag(ct(1:6))*pp(7:12)) + & + sum(imag(ct(864-5:864))*pp(1:6)) + softbits(2)=sum(real(ct(1:12))*pp) + do i=2,72 + softbits(2*i-1)=sum(imag(ct(1+(i-1)*12-6:1+(i-1)*12+5))*pp) + softbits(2*i)=sum(real(ct(7+(i-1)*12-6:7+(i-1)*12+5))*pp) + enddo + +! Number of hard errors in sync word is a good discriminator for +! frames that have reasonable probability of decoding + hardbits=0 + do i=1,144 + if(softbits(i) .ge. 0.0) then + hardbits(i)=1 + endif + enddo + nbadsync1=(8-sum((2*hardbits(1:8)-1)*s8))/2 + nbadsync2=(8-sum((2*hardbits(1+56:8+56)-1)*s8))/2 + nbadsync=nbadsync1+nbadsync2 + if(nbadsync .gt. 3) cycle + +! Normalize softsymbols before submitting to decoder + sav=sum(softbits)/144 + s2av=sum(softbits*softbits)/144 + ssig=sqrt(s2av-sav*sav) + softbits=softbits/ssig + + sigma=0.70 + lratio(1:48)=softbits(9:9+47) + lratio(49:128)=softbits(65:65+80-1) + llr=2.0*lratio/(sigma*sigma) + + call bpdecode144(llr,max_iterations,decoded,niterations) + if(niterations .ge. 0.0) then + call extractmessage144(decoded,msgreceived,nhashflag) + if(nhashflag .gt. 0) then ! CRCs match, so print it + write(line,1020) nutc0,nsnr,tsec,nint(fest),msgreceived,char(0) +1020 format(i6.6,i4,f5.1,i5,' ^ ',a22,a1) + endif + goto 999 + else + msgreceived=' ' + ndither=-99 !Bad hash flag = -99 + endif + enddo !Slicer dither + enddo !Peak loop + enddo + + msgreceived=' ' + ndither=-98 +999 continue + +! call system_clock(count3,clkfreq) +! t12=t12 + float(count2-count1)/clkfreq +! t03=t03 + float(count3-count0)/clkfreq +! if(navg.gt.7) navg=0 +! write(*,3002) nutc0,tsec,t12,t03,xmax,nint(bestf),navg, & +! nbadsync,niterations,ipk,is,msgreceived(1:19) +! write(62,3002) nutc0,tsec,t12,t03,xmax,nint(bestf),navg, & +! nbadsync,niterations,ipk,is,msgreceived(1:19) +!3002 format(i6,f6.2,2f7.2,f6.2,i5,5i3,1x,a19) + + return +end subroutine mskrtd +