198 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Fortran
		
	
	
	
	
	
		
		
			
		
	
	
			198 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			Fortran
		
	
	
	
	
	
|   | 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,1,1,1,1,0,0,0, &
 | ||
|  |        0,0,1,1,1,1,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=4
 | ||
|  |        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(1)=0.5*cx(1)
 | ||
|  |   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
 | ||
|  | 
 |