197 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
		
		
			
		
	
	
			197 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
|   | program msk144sd | ||
|  | ! | ||
|  | ! A simple decoder for slow msk144. | ||
|  | ! Can be used as a (slow) brute-force multi-decoder by looping | ||
|  | ! over a set of carrier frequencies. | ||
|  | ! | ||
|  |   use options | ||
|  |   use timer_module, only: timer | ||
|  |   use timer_impl, only: init_timer | ||
|  |   use readwav | ||
|  | 
 | ||
|  |   parameter (NRECENT=10) | ||
|  |   parameter (NSPM=864) | ||
|  |   parameter (NPATTERNS=4) | ||
|  | 
 | ||
|  |   character ch | ||
|  |   character*80 line | ||
|  |   character*500 infile | ||
|  |   character*12 mycall,hiscall | ||
|  |   character*6 mygrid | ||
|  |   character(len=500) optarg | ||
|  |   character*22 msgreceived | ||
|  |   character*12 recent_calls(NRECENT) | ||
|  | 
 | ||
|  |   complex cdat(30*375) | ||
|  |   complex c(NSPM) | ||
|  |   complex ct(NSPM) | ||
|  | 
 | ||
|  |   real softbits(144) | ||
|  |   real xmc(NPATTERNS) | ||
|  | 
 | ||
|  |   logical :: display_help=.false. | ||
|  | 
 | ||
|  |   type(wav_header) :: wav | ||
|  | 
 | ||
|  |   integer iavmask(8) | ||
|  |   integer iavpatterns(8,NPATTERNS) | ||
|  |   integer npkloc(10) | ||
|  | 
 | ||
|  |   integer*2 id2(30*12000) | ||
|  |   integer*2 ichunk(7*1024) | ||
|  |    | ||
|  |   data iavpatterns/ & | ||
|  |        1,1,1,1,0,0,0,0, & | ||
|  |        0,0,1,1,1,1,0,0, & | ||
|  |        1,1,1,1,1,0,0,0, & | ||
|  |        1,1,1,1,1,1,0,0/ | ||
|  |   data xmc/2.0,4.5,2.5,3.0/ | ||
|  | 
 | ||
|  |   type (option) :: long_options(2) = [ & | ||
|  |        option ('frequency',.true.,'f','rxfreq',''), & | ||
|  |        option ('help',.false.,'h','Display this help message','') & | ||
|  |        ] | ||
|  |   t0=0.0 | ||
|  |   ntol=100 | ||
|  |   nrxfreq=1500 | ||
|  |   | ||
|  |   do | ||
|  |      call getopt('f:h',long_options,ch,optarg,narglen,nstat,noffset,nremain,.true.) | ||
|  |      if( nstat .ne. 0 ) then | ||
|  |         exit | ||
|  |      end if | ||
|  |      select case (ch) | ||
|  |      case ('f') | ||
|  |         read (optarg(:narglen), *) nrxfreq | ||
|  |      case ('h') | ||
|  |         display_help = .true. | ||
|  |      end select | ||
|  |   end do | ||
|  | 
 | ||
|  |   if(display_help .or. nstat.lt.0 .or. nremain.lt.1) then | ||
|  |      print *, '' | ||
|  |      print *, 'Usage: msk144sd [OPTIONS] file1 [file2 ...]' | ||
|  |      print *, '' | ||
|  |      print *, '       decode pre-recorded .WAV file(s)' | ||
|  |      print *, '' | ||
|  |      print *, 'OPTIONS:' | ||
|  |      do i = 1, size (long_options) | ||
|  |         call long_options(i) % print (6) | ||
|  |      end do | ||
|  |      go to 999 | ||
|  |   endif | ||
|  | 
 | ||
|  |   call init_timer ('timer.out') | ||
|  |   call timer('msk144  ',0) | ||
|  |   ndecoded=0 | ||
|  |   do ifile=noffset+1,noffset+nremain | ||
|  |      call get_command_argument(ifile,optarg,narglen) | ||
|  |      infile=optarg(:narglen) | ||
|  |      call timer('read    ',0) | ||
|  |      call wav%read (infile) | ||
|  |      i1=index(infile,'.wav') | ||
|  |      if( i1 .eq. 0 ) i1=index(infile,'.WAV') | ||
|  |      read(infile(i1-6:i1-1),*,err=998) nutc | ||
|  |      inquire(FILE=infile,SIZE=isize) | ||
|  |      npts=min((isize-216)/2,360000) | ||
|  |      read(unit=wav%lun) id2(1:npts) | ||
|  |      close(unit=wav%lun) | ||
|  |      call timer('read    ',1) | ||
|  | 
 | ||
|  | !   do if=1,89  ! brute force multi-decoder | ||
|  |      fo=nrxfreq | ||
|  | !     fo=(if-1)*25.0+300.0 | ||
|  |      call msksddc(id2,npts,fo,cdat) | ||
|  |      np=npts/32 | ||
|  |      ntol=200  ! actual ntol is ntol/32=6.25 Hz. Detection window is 12.5 Hz wide | ||
|  |      fc=1500.0 | ||
|  |      call msk144spd(cdat,np,ntol,ndecodesuccess,msgreceived,fc,fest,tdec,navg,ct, & | ||
|  |                     softbits,recent_calls,nrecent) | ||
|  |      nsnr=0  ! need an snr estimate | ||
|  |      if( ndecodesuccess .eq. 1 ) then | ||
|  |        fest=fo+fest-fc   ! fudging because spd thinks input signal is at 1500 Hz | ||
|  |        goto 900  | ||
|  |      endif | ||
|  | ! If short ping decoder doesn't find a decode  | ||
|  |      npat=NPATTERNS | ||
|  |      do iavg=1,npat | ||
|  |        iavmask=iavpatterns(1:8,iavg) | ||
|  |        navg=sum(iavmask) | ||
|  |        deltaf=4.0/real(navg)  ! search increment for frequency sync | ||
|  |        npeaks=3 | ||
|  |        ntol=200 | ||
|  |        fc=1500.0 | ||
|  |        call msk144sync(cdat(1:6*NSPM),6,ntol,deltaf,iavmask,npeaks,fc,           & | ||
|  |           fest,npkloc,nsyncsuccess,xmax,c) | ||
|  |        if( nsyncsuccess .eq. 0 ) cycle | ||
|  | 
 | ||
|  |        do ipk=1,npeaks | ||
|  |          do is=1,3    | ||
|  |            ic0=npkloc(ipk) | ||
|  |            if(is.eq.2) ic0=max(1,ic0-1) | ||
|  |            if(is.eq.3) ic0=min(NSPM,ic0+1) | ||
|  |            ct=cshift(c,ic0-1) | ||
|  |            call msk144decodeframe(ct,softbits,msgreceived,ndecodesuccess,      & | ||
|  |                                   recent_calls,nrecent) | ||
|  |            if(ndecodesuccess .gt. 0) then | ||
|  |               tdec=tsec+xmc(iavg)*tframe | ||
|  |               fest=fo+(fest-fc)/32.0    | ||
|  |               goto 900 | ||
|  |            endif | ||
|  |          enddo                         !Slicer dither | ||
|  |        enddo                            !Peak loop  | ||
|  |      enddo | ||
|  | 
 | ||
|  | !   enddo | ||
|  | 900 continue | ||
|  |     if( ndecodesuccess .gt. 0 ) then | ||
|  |        write(*,1020) nutc,nsnr,tdec,nint(fest),' % ',msgreceived,navg | ||
|  | 1020   format(i6.6,i4,f5.1,i5,a3,a22,i4) | ||
|  |     endif | ||
|  |   enddo | ||
|  | 
 | ||
|  |   call timer('msk144  ',1) | ||
|  |   call timer('msk144  ',101) | ||
|  |   go to 999 | ||
|  | 
 | ||
|  | 998 print*,'Cannot read from file:' | ||
|  |   print*,infile | ||
|  | 
 | ||
|  | 999 continue | ||
|  | end program msk144sd | ||
|  | 
 | ||
|  | subroutine msksddc(id2,npts,fc,cdat) | ||
|  | 
 | ||
|  | ! The msk144 detector/demodulator/decoder will decode signals | ||
|  | ! with carrier frequency, fc, in the range fN/4 +/- 0.03333*fN.  | ||
|  | ! | ||
|  | ! For slow MSK144 with nslow=32:  | ||
|  | !  fs=12000/32=375 Hz, fN=187.5 Hz | ||
|  | ! | ||
|  | ! This routine accepts input samples with fs=12000 Hz. It | ||
|  | ! downconverts and decimates by 32 to center a signal with input carrier | ||
|  | ! frequency fc at new carrier frequency 1500/32=46.875 Hz. | ||
|  | ! The analytic signal is returned. | ||
|  |   | ||
|  |   parameter (NFFT1=30*12000,NFFT2=30*375) | ||
|  |   integer*2 id2(npts) | ||
|  |   complex cx(0:NFFT1) | ||
|  |   complex cdat(30*375) | ||
|  | 
 | ||
|  |   dt=1.0/12000.0 | ||
|  |   df=1.0/(NFFT1*dt) | ||
|  |   icenter=int(fc/df+0.5) | ||
|  |   i46p875=int(46.875/df+0.5) | ||
|  |   ishift=icenter-i46p875 | ||
|  |   cx=cmplx(0.0,0.0) | ||
|  |   cx(1:npts)=id2 | ||
|  |   call four2a(cx,NFFT1,1,-1,1) | ||
|  |   cx=cshift(cx,ishift) | ||
|  |   cx(2*i46p875+1:)=cmplx(0.0,0.0) | ||
|  |   call four2a(cx,NFFT2,1,1,1) | ||
|  |   cdat(1:npts/32)=cx(0:npts/32-1)/NFFT1 | ||
|  |   return | ||
|  | 
 | ||
|  | end subroutine msksddc | ||
|  | 
 |