mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-27 14:48:46 -05:00
Functioning JTMSK decoder, within stand-alone program msk.
git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/jtms3@2519 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
parent
71ddb3fd1e
commit
8b55eb3a28
@ -1,6 +1,6 @@
|
|||||||
[Setup]
|
[Setup]
|
||||||
AppName=JTMS3
|
AppName=JTMS3
|
||||||
AppVerName=JTMS3 Version 0.2 r2516
|
AppVerName=JTMS3 Version 0.2 r2517
|
||||||
AppCopyright=Copyright (C) 2001-2012 by Joe Taylor, K1JT
|
AppCopyright=Copyright (C) 2001-2012 by Joe Taylor, K1JT
|
||||||
DefaultDirName=c:\JTMS3
|
DefaultDirName=c:\JTMS3
|
||||||
DefaultGroupName=JTMS3
|
DefaultGroupName=JTMS3
|
||||||
|
@ -6,10 +6,10 @@
|
|||||||
|
|
||||||
QT += core gui network
|
QT += core gui network
|
||||||
CONFIG += qwt thread
|
CONFIG += qwt thread
|
||||||
#CONFIG += console
|
CONFIG += console
|
||||||
|
|
||||||
TARGET = jtms3
|
TARGET = jtms3
|
||||||
VERSION = 0.1
|
VERSION = 0.2
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
|
|
||||||
win32 {
|
win32 {
|
||||||
|
@ -17,7 +17,7 @@ CFLAGS = -I. -fbounds-check
|
|||||||
%.o: %.F90
|
%.o: %.F90
|
||||||
${FC} ${FFLAGS} -c $<
|
${FC} ${FFLAGS} -c $<
|
||||||
|
|
||||||
all: libm65.a ms3.exe t1.exe
|
all: libm65.a msk.exe
|
||||||
|
|
||||||
OBJS1 = trimlist.o display.o getdphi.o pctile.o ccf65.o \
|
OBJS1 = trimlist.o display.o getdphi.o pctile.o ccf65.o \
|
||||||
decode1a.o sort.o filbig.o fil6521.o afc65b.o \
|
decode1a.o sort.o filbig.o fil6521.o afc65b.o \
|
||||||
@ -32,15 +32,17 @@ OBJS1 = trimlist.o display.o getdphi.o pctile.o ccf65.o \
|
|||||||
geocentric.o moon2.o toxyz.o dot.o dcoord.o f77_wisdom.o \
|
geocentric.o moon2.o toxyz.o dot.o dcoord.o f77_wisdom.o \
|
||||||
gen65.o chkmsg.o ptt.o astrosub.o astro0.o recvpkt.o symspec.o \
|
gen65.o chkmsg.o ptt.o astrosub.o astro0.o recvpkt.o symspec.o \
|
||||||
iqcal.o iqfix.o timf2.o s3avg.o genjtms3.o analytic.o \
|
iqcal.o iqfix.o timf2.o s3avg.o genjtms3.o analytic.o \
|
||||||
db.o specjtms.o genmsk.o
|
db.o specjtms.o genmsk.o mskdf.o tweak1.o syncmsk.o \
|
||||||
|
lenmsk.o decodemsk.o ping.o makepings.o alignmsg.o match.o \
|
||||||
|
rtping.o jtmsk.o hipass.o setupmsk.o foldmsk.o
|
||||||
|
|
||||||
libm65.a: $(OBJS1)
|
libm65.a: $(OBJS1)
|
||||||
ar cr libm65.a $(OBJS1)
|
ar cr libm65.a $(OBJS1)
|
||||||
ranlib libm65.a
|
ranlib libm65.a
|
||||||
|
|
||||||
OBJS3 = ms3.o
|
OBJS3 = msk.o
|
||||||
ms3.exe: $(OBJS3) libm65.a
|
msk.exe: $(OBJS3) libm65.a
|
||||||
$(FC) -o ms3.exe $(OBJS3) libm65.a ../libfftw3f_win.a \
|
$(FC) -o msk.exe $(OBJS3) libm65.a ../libfftw3f_win.a
|
||||||
|
|
||||||
OBJS2 = JT65code.o
|
OBJS2 = JT65code.o
|
||||||
JT65code.exe: $(OBJS2) libm65.a
|
JT65code.exe: $(OBJS2) libm65.a
|
||||||
|
@ -2,9 +2,10 @@ subroutine analytic(d,npts,nfft,s,c)
|
|||||||
|
|
||||||
! Convert real data to analytic signal
|
! Convert real data to analytic signal
|
||||||
|
|
||||||
|
parameter (NFFTMAX=128*1024)
|
||||||
real d(npts)
|
real d(npts)
|
||||||
real s(npts)
|
real s(npts)
|
||||||
complex c(npts)
|
complex c(NFFTMAX)
|
||||||
|
|
||||||
nh=nfft/2
|
nh=nfft/2
|
||||||
fac=2.0/nfft
|
fac=2.0/nfft
|
||||||
|
39
libm65/decodemsk.f90
Normal file
39
libm65/decodemsk.f90
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
subroutine decodemsk(cdat,npts,cw,i1,nchar,s2,msg)
|
||||||
|
|
||||||
|
! DF snd sync have been established, now decode the message
|
||||||
|
|
||||||
|
complex cdat(npts)
|
||||||
|
complex cw(168,0:63) !Complex waveforms for codewords
|
||||||
|
real s2(0:63,400)
|
||||||
|
character msg*400
|
||||||
|
complex z,zmax
|
||||||
|
character cc*64
|
||||||
|
! 1 2 3 4 5 6
|
||||||
|
! 0123456789012345678901234567890123456789012345678901234567890123
|
||||||
|
data cc/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ./?- _ @'/
|
||||||
|
|
||||||
|
msg=' '
|
||||||
|
do j=1,nchar !Find best match for each character
|
||||||
|
ia=i1 + (j-1)*168
|
||||||
|
smax=0.
|
||||||
|
do k=0,40
|
||||||
|
kk=k
|
||||||
|
if(k.eq.40) kk=57
|
||||||
|
z=0.
|
||||||
|
do i=1,168
|
||||||
|
z=z + cdat(ia+i)*conjg(cw(i,kk))
|
||||||
|
enddo
|
||||||
|
ss=abs(z)
|
||||||
|
s2(k,j)=ss
|
||||||
|
if(ss.gt.smax) then
|
||||||
|
smax=ss
|
||||||
|
zmax=z
|
||||||
|
kpk=kk
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
msg(j:j)=cc(kpk+1:kpk+1)
|
||||||
|
if(kpk.eq.57) msg(j:j)=' '
|
||||||
|
enddo
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine decodemsk
|
50
libm65/foldmsk.f90
Normal file
50
libm65/foldmsk.f90
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
subroutine foldmsk(s2,msglen,nchar,mycall,msg,msg29)
|
||||||
|
|
||||||
|
! Fold the 2-d "goodness of fit" array s2 modulo message length,
|
||||||
|
! then decode the folded message.
|
||||||
|
|
||||||
|
real s2(0:63,400)
|
||||||
|
real fs2(0:63,29)
|
||||||
|
integer nfs2(29)
|
||||||
|
character mycall*12
|
||||||
|
character msg*400,msg29*29
|
||||||
|
character cc*64
|
||||||
|
! 1 2 3 4 5 6
|
||||||
|
! 0123456789012345678901234567890123456789012345678901234567890123
|
||||||
|
data cc/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ./?- _ @'/
|
||||||
|
|
||||||
|
fs2=0.
|
||||||
|
nfs2=0
|
||||||
|
do j=1,nchar !Fold s2 into fs2, modulo msglen
|
||||||
|
jj=mod(j-1,msglen)+1
|
||||||
|
nfs2(jj)=nfs2(jj)+1
|
||||||
|
do i=0,40
|
||||||
|
fs2(i,jj)=fs2(i,jj) + s2(i,j)
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
|
||||||
|
msg=' '
|
||||||
|
do j=1,msglen
|
||||||
|
smax=0.
|
||||||
|
do k=0,40
|
||||||
|
if(fs2(k,j).gt.smax) then
|
||||||
|
smax=fs2(k,j)
|
||||||
|
kpk=k
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
if(kpk.eq.40) kpk=57
|
||||||
|
msg(j:j)=cc(kpk+1:kpk+1)
|
||||||
|
if(kpk.eq.57) msg(j:j)=' '
|
||||||
|
enddo
|
||||||
|
|
||||||
|
msg29=msg(1:msglen)
|
||||||
|
|
||||||
|
call alignmsg(' ',2,msg29,msglen,idone)
|
||||||
|
if(idone.eq.0) call alignmsg('CQ', 3,msg29,msglen,idone)
|
||||||
|
if(idone.eq.0) call alignmsg('QRZ', 3,msg29,msglen,idone)
|
||||||
|
if(idone.eq.0) call alignmsg(mycall,4,msg29,msglen,idone)
|
||||||
|
if(idone.eq.0) call alignmsg(' ', 1,msg29,msglen,idone)
|
||||||
|
msg29=adjustl(msg29)
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine foldmsk
|
@ -65,7 +65,6 @@ subroutine genmsk(msg28,iwave,nwave)
|
|||||||
f0=48000.d0/nsps
|
f0=48000.d0/nsps
|
||||||
dfgen=0.5d0*f0
|
dfgen=0.5d0*f0
|
||||||
foffset=1500.d0 - f0
|
foffset=1500.d0 - f0
|
||||||
print*,f0,dfgen,foffset
|
|
||||||
t=0.d0
|
t=0.d0
|
||||||
k=0
|
k=0
|
||||||
phi=0.d0
|
phi=0.d0
|
||||||
@ -95,5 +94,9 @@ subroutine genmsk(msg28,iwave,nwave)
|
|||||||
if(isrch.eq.0) iwave(k+1:)=0
|
if(isrch.eq.0) iwave(k+1:)=0
|
||||||
nwave=k
|
nwave=k
|
||||||
|
|
||||||
|
! call makepings(iwave,nwave)
|
||||||
|
! write(71) iwave
|
||||||
|
! call flush(71)
|
||||||
|
|
||||||
return
|
return
|
||||||
end subroutine genmsk
|
end subroutine genmsk
|
||||||
|
86
libm65/jtmsk.f90
Normal file
86
libm65/jtmsk.f90
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
subroutine jtmsk(dat,npts,cfile6,t2,mswidth,ndb,nrpt,Nfreeze, &
|
||||||
|
ntol,MouseDF,pick)
|
||||||
|
|
||||||
|
! Decode a JTMS ping
|
||||||
|
|
||||||
|
parameter (NZ=30*48000)
|
||||||
|
real dat(npts) !Raw data
|
||||||
|
complex cdat(NZ) !Analytic form of signal
|
||||||
|
character*6 cfile6 !FileID
|
||||||
|
logical pick
|
||||||
|
character*12 mycall,hiscall
|
||||||
|
real s(NZ) !Power spectrum
|
||||||
|
real s2(0:63,400)
|
||||||
|
real r(60000)
|
||||||
|
complex cw(168,0:63) !Complex waveforms for all codewords
|
||||||
|
complex cwb(168) !Complex waveform for <space>
|
||||||
|
logical first
|
||||||
|
character msg*400,msg29*29
|
||||||
|
character*90 line
|
||||||
|
common/ccom/nline,tping(100),line(100)
|
||||||
|
data first/.true./
|
||||||
|
save first,cw,cwb
|
||||||
|
save cdat !Fix its address, for four2
|
||||||
|
|
||||||
|
if(first) call setupmsk(cw,cwb) !Calculate waveforms for codewords
|
||||||
|
first=.false.
|
||||||
|
|
||||||
|
nsps=24 !Samples per symbol
|
||||||
|
f0=1000.0 !Nominal frequency for bit=0
|
||||||
|
n=log(float(npts))/log(2.0) + 1.0
|
||||||
|
nfft1=2**n !FFT length
|
||||||
|
call analytic(dat,npts,nfft1,s,cdat) !Convert to analytic signal
|
||||||
|
|
||||||
|
call mskdf(cdat,npts,t2,nfft1,f0,nfreeze,mousedf,ntol, &
|
||||||
|
dfx,snrsq2) !Get DF
|
||||||
|
print*,'b',dfx,snrsq2
|
||||||
|
sq2lim=7.0
|
||||||
|
if(pick) sq2lim=5.0
|
||||||
|
if(snrsq2.lt.sq2lim) go to 900 !Reject non-JTMS signals
|
||||||
|
|
||||||
|
call tweak1(cdat,npts,-dfx,cdat) !Mix to standard frequency
|
||||||
|
|
||||||
|
! DF is known, now establish character sync.
|
||||||
|
|
||||||
|
call syncmsk(cdat,npts,cwb,r,i1) !Get character sync
|
||||||
|
|
||||||
|
call lenmsk(r,npts,msglen) !Find message length
|
||||||
|
|
||||||
|
s2=0.
|
||||||
|
nchar=(npts-168+1-i1)/168
|
||||||
|
if(nchar.gt.400) nchar=400
|
||||||
|
|
||||||
|
call decodemsk(cdat,npts,cw,i1,nchar,s2,msg) !Decode the message
|
||||||
|
print*,'B',i1,msglen,nchar
|
||||||
|
print*,msg(1:nchar)
|
||||||
|
|
||||||
|
! ia=1
|
||||||
|
! if(nchar.ge.40) ia=min(nchar/3,nchar-28)
|
||||||
|
! ib=min(ia+28,nchar) !Can better limits ia, ib be found?
|
||||||
|
! print*,'A',ia,ib,nchar
|
||||||
|
! print*,msg(1:nchar)
|
||||||
|
! msg29=adjustl(msg(ia:ib))
|
||||||
|
msg=adjustl(msg)
|
||||||
|
ib=min(nchar,45)
|
||||||
|
ndf=nint(dfx)
|
||||||
|
nchk=max(20,nint(1.5*msglen))
|
||||||
|
|
||||||
|
if(msglen.eq.0 .or. nchar.lt.nchk .or. pick) then
|
||||||
|
if(nline.le.99) nline=nline+1
|
||||||
|
tping(nline)=t2
|
||||||
|
write(line(nline),1110) cfile6,t2,mswidth,ndb,nrpt,ndf,msg(1:45)
|
||||||
|
1110 format(a6,f5.1,i5,i3,1x,i2.2,i5,5x,a45)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if(msglen.gt.0 .and. nchar.ge.nchk) then
|
||||||
|
call foldmsk(s2,msglen,nchar,mycall,msg,msg29) !Decode folded message
|
||||||
|
if(nline.le.99) nline=nline+1
|
||||||
|
tping(nline)=t2
|
||||||
|
write(line(nline),1120) cfile6,t2,mswidth,ndb,nrpt,ndf,msg29
|
||||||
|
1120 format(a6,f5.1,i5,i3,1x,i2.2,i5,5x,a29,11x,'*')
|
||||||
|
endif
|
||||||
|
|
||||||
|
900 continue
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine jtmsk
|
56
libm65/lenmsk.f90
Normal file
56
libm65/lenmsk.f90
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
subroutine lenmsk(r,npts,msglen)
|
||||||
|
|
||||||
|
! Determine length of the user message in a JTMS ping.
|
||||||
|
|
||||||
|
real r(60000)
|
||||||
|
real acf(4872)
|
||||||
|
integer np(9)
|
||||||
|
data np/5,7,9,11,13,17,19,23,29/ !Permissible message lengths
|
||||||
|
save acf !Why necessary? (But don't remove!)
|
||||||
|
|
||||||
|
msglen=0 !Use ACF to find msg length
|
||||||
|
if(npts.ge.8*168) then
|
||||||
|
r=r-sum(r(1:npts))/npts
|
||||||
|
acfmax=0.
|
||||||
|
acf0=dot_product(r(1:npts),r(1:npts))
|
||||||
|
kz=min(nint(0.75*npts),29*168)
|
||||||
|
do k=8,kz
|
||||||
|
fac=float(npts)/(npts-k)
|
||||||
|
acf(k)=fac*dot_product(r(1:npts),r(1+k:npts+k))/acf0
|
||||||
|
enddo
|
||||||
|
call hipass(acf(8),kz-7,50)
|
||||||
|
|
||||||
|
do k=8,kz !Find acfmax, kpk
|
||||||
|
if(acf(k).gt.acfmax) then
|
||||||
|
acfmax=acf(k)
|
||||||
|
kpk=k
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
|
||||||
|
sumsq=0.
|
||||||
|
n=0
|
||||||
|
do k=8,kz !Find rms, skipping around kpk
|
||||||
|
if(abs(k-kpk).gt.10) then
|
||||||
|
sumsq=sumsq+acf(k)**2
|
||||||
|
n=n+1
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
rms=sqrt(sumsq/n)
|
||||||
|
acf=acf/rms !Normalize the acf
|
||||||
|
|
||||||
|
amax2=0.
|
||||||
|
acflim=3.5
|
||||||
|
do i=1,9
|
||||||
|
k=168*np(i) !Check only the permitted lengths
|
||||||
|
if(k.gt.kz) go to 10
|
||||||
|
if(acf(k).gt.acflim .and. acf(k).gt.amax2) then
|
||||||
|
amax2=acf(k) !Save best value >3.5 sigma
|
||||||
|
msglen=np(i) !Save message length
|
||||||
|
kpk2=k
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
10 continue
|
||||||
|
endif
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine lenmsk
|
59
libm65/msk.f90
Normal file
59
libm65/msk.f90
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
program msk
|
||||||
|
|
||||||
|
! Starting code for a JTMSK decoder.
|
||||||
|
|
||||||
|
parameter (NSMAX=30*48000)
|
||||||
|
character*80 infile
|
||||||
|
character*6 cfile6
|
||||||
|
character*12 arg
|
||||||
|
real dat(NSMAX)
|
||||||
|
real x(NSMAX)
|
||||||
|
complex cx(0:NSMAX/2)
|
||||||
|
integer hdr(11)
|
||||||
|
integer*2 id
|
||||||
|
common/mscom/id(NSMAX),s1(215,703),s2(215,703)
|
||||||
|
|
||||||
|
nargs=iargc()
|
||||||
|
if(nargs.lt.1) then
|
||||||
|
print*,'Usage: msk <snr>'
|
||||||
|
go to 999
|
||||||
|
endif
|
||||||
|
call getarg(1,arg)
|
||||||
|
read(arg,*) snr
|
||||||
|
|
||||||
|
open(71,file='dat.71',form='unformatted',status='old')
|
||||||
|
read(71) id
|
||||||
|
cfile6='123400'
|
||||||
|
|
||||||
|
npts=30*48000
|
||||||
|
kstep=2048
|
||||||
|
minsigdb=6
|
||||||
|
mousedf=0
|
||||||
|
ntol=200
|
||||||
|
|
||||||
|
call random_number(x)
|
||||||
|
nfft=NSMAX
|
||||||
|
call four2a(x,nfft,1,-1,0)
|
||||||
|
df=48000.0/nfft
|
||||||
|
ia=nint(300.0/df)
|
||||||
|
ib=nint(2800.0/df)
|
||||||
|
cx(:ia)=0.
|
||||||
|
cx(ib:)=0.
|
||||||
|
call four2a(cx,nfft,1,1,-1)
|
||||||
|
x(1)=0.
|
||||||
|
sq=0.
|
||||||
|
do i=1,NSMAX
|
||||||
|
sq=sq + x(i)**2
|
||||||
|
enddo
|
||||||
|
rms=sqrt(sq/NSMAX)
|
||||||
|
x=x/rms
|
||||||
|
sig=(10.0**(0.05*snr))/32768.0
|
||||||
|
dat=sig*id + x
|
||||||
|
|
||||||
|
k=0
|
||||||
|
do iblk=1,npts/kstep
|
||||||
|
k=k+kstep
|
||||||
|
call rtping(dat,k,cfile6,MinSigdB,MouseDF,ntol)
|
||||||
|
enddo
|
||||||
|
|
||||||
|
999 end program msk
|
49
libm65/msk0.f90
Normal file
49
libm65/msk0.f90
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
program msk
|
||||||
|
|
||||||
|
! Starting code for a JTMSK decoder.
|
||||||
|
|
||||||
|
parameter (NSMAX=30*48000)
|
||||||
|
character*80 infile
|
||||||
|
character*6 cfile6
|
||||||
|
real dat(NSMAX)
|
||||||
|
integer hdr(11)
|
||||||
|
integer*2 id
|
||||||
|
common/mscom/id(NSMAX),s1(215,703),s2(215,703)
|
||||||
|
|
||||||
|
nargs=iargc()
|
||||||
|
if(nargs.lt.1) then
|
||||||
|
print*,'Usage: msk file1 [file2 ...]'
|
||||||
|
print*,' Reads data from *.wav files.'
|
||||||
|
go to 999
|
||||||
|
endif
|
||||||
|
|
||||||
|
npts=30*48000
|
||||||
|
kstep=2048
|
||||||
|
minsigdb=6
|
||||||
|
mousedf=0
|
||||||
|
ntol=200
|
||||||
|
|
||||||
|
do ifile=1,nargs
|
||||||
|
call getarg(ifile,infile)
|
||||||
|
open(10,file=infile,access='stream',status='old',err=998)
|
||||||
|
read(10) hdr
|
||||||
|
read(10) id
|
||||||
|
close(10)
|
||||||
|
hdr(1)=hdr(2)
|
||||||
|
i1=index(infile,'.wav')
|
||||||
|
cfile6=infile(i1-6:i1-1)
|
||||||
|
dat=id
|
||||||
|
|
||||||
|
k=0
|
||||||
|
do iblk=1,npts/kstep
|
||||||
|
k=k+kstep
|
||||||
|
call rtping(dat,k,cfile6,MinSigdB,MouseDF,ntol)
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
|
||||||
|
go to 999
|
||||||
|
|
||||||
|
998 print*,'Cannot open file:'
|
||||||
|
print*,infile
|
||||||
|
|
||||||
|
999 end program msk
|
75
libm65/mskdf.f90
Normal file
75
libm65/mskdf.f90
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
subroutine mskdf(cdat,npts,t2,nfft1,f0,nfreeze,mousedf,ntol,dfx,snrsq2)
|
||||||
|
|
||||||
|
! Determine DF for a JTMS signal. Also find ferr, a measure of
|
||||||
|
! frequency differerence between 1st and 2nd harmonic.
|
||||||
|
! (Should be 0.000)
|
||||||
|
|
||||||
|
parameter (NZ=128*1024)
|
||||||
|
complex cdat(npts)
|
||||||
|
integer ntol
|
||||||
|
real sq(NZ)
|
||||||
|
real ccf(-2600:2600) !Correct limits?
|
||||||
|
real tmp(NZ)
|
||||||
|
complex c(NZ)
|
||||||
|
data nsps/8/
|
||||||
|
save c
|
||||||
|
|
||||||
|
df1=48000.0/nfft1
|
||||||
|
nh=nfft1/2
|
||||||
|
fac=1.0/(nfft1**2)
|
||||||
|
|
||||||
|
do i=1,npts
|
||||||
|
c(i)=fac*cdat(i)**2
|
||||||
|
enddo
|
||||||
|
c(npts+1:nfft1)=0.
|
||||||
|
call four2a(c,nfft1,1,-1,1)
|
||||||
|
|
||||||
|
! In the "doubled-frequencies" spectrum of squared cdat:
|
||||||
|
fa=2.0*(f0-400)
|
||||||
|
fb=2.0*(f0+400)
|
||||||
|
j0=nint(2.0*f0/df1)
|
||||||
|
ja=nint(fa/df1)
|
||||||
|
jb=nint(fb/df1)
|
||||||
|
jd=nfft1/nsps
|
||||||
|
|
||||||
|
do j=1,nh+1
|
||||||
|
sq(j)=real(c(j))**2 + aimag(c(j))**2
|
||||||
|
! if(j*df1.lt.6000.0) write(54,3009) j*df1,sq(j),db(sq(j))
|
||||||
|
!3009 format(3f12.3)
|
||||||
|
enddo
|
||||||
|
|
||||||
|
ccf=0.
|
||||||
|
do j=ja,jb
|
||||||
|
ccf(j-j0-1)=sq(j)+sq(j+jd)
|
||||||
|
enddo
|
||||||
|
|
||||||
|
call pctile(ccf(ja-j0-1),tmp,jb-ja+1,50,base)
|
||||||
|
ccf=ccf/base
|
||||||
|
|
||||||
|
if(NFreeze.gt.0) then
|
||||||
|
fa=2.0*(f0+MouseDF-ntol)
|
||||||
|
fb=2.0*(f0+MouseDF+ntol)
|
||||||
|
endif
|
||||||
|
ja=nint(fa/df1)
|
||||||
|
jb=nint(fb/df1)
|
||||||
|
|
||||||
|
! rewind 51
|
||||||
|
smax=0.
|
||||||
|
do j=ja,jb
|
||||||
|
k=j-j0-1
|
||||||
|
if(ccf(k).gt.smax) then
|
||||||
|
smax=ccf(k)
|
||||||
|
jpk=j
|
||||||
|
endif
|
||||||
|
f=0.5*k*df1
|
||||||
|
! write(51,3002) f,ccf(k)
|
||||||
|
!3002 format(2f12.3)
|
||||||
|
enddo
|
||||||
|
! call flush(51)
|
||||||
|
|
||||||
|
fpk=(jpk-1)*df1
|
||||||
|
dfx=0.5*fpk-f0
|
||||||
|
snrsq2=smax
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine mskdf
|
42
libm65/ping.f90
Normal file
42
libm65/ping.f90
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
subroutine ping(s,nz,dtbuf,slim,wmin,pingdat,nping)
|
||||||
|
|
||||||
|
! Detect pings and make note of their start time, duration, and peak strength.
|
||||||
|
|
||||||
|
real*4 s(nz)
|
||||||
|
real*4 pingdat(3,100)
|
||||||
|
logical inside
|
||||||
|
|
||||||
|
nping=0
|
||||||
|
peak=0.
|
||||||
|
inside=.false.
|
||||||
|
snrlim=10.0**(0.1*slim) - 1.0
|
||||||
|
sdown=10.0*log10(0.25*snrlim+1.0)
|
||||||
|
|
||||||
|
i0=0 !Silence compiler warnings.
|
||||||
|
tstart=0.0
|
||||||
|
do i=2,nz
|
||||||
|
if(s(i).ge.slim .and. .not.inside) then
|
||||||
|
i0=i
|
||||||
|
tstart=i0*dtbuf
|
||||||
|
inside=.true.
|
||||||
|
peak=0.
|
||||||
|
endif
|
||||||
|
if(inside .and. s(i).gt.peak) then
|
||||||
|
peak=s(i)
|
||||||
|
endif
|
||||||
|
if(inside .and. (s(i).lt.sdown .or. i.eq.nz)) then
|
||||||
|
if(i.gt.i0) then
|
||||||
|
if(dtbuf*(i-i0).ge.wmin) then
|
||||||
|
if(nping.le.99) nping=nping+1
|
||||||
|
pingdat(1,nping)=tstart
|
||||||
|
pingdat(2,nping)=dtbuf*(i-i0)
|
||||||
|
pingdat(3,nping)=peak
|
||||||
|
endif
|
||||||
|
inside=.false.
|
||||||
|
peak=0.
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine ping
|
103
libm65/rtping.f90
Normal file
103
libm65/rtping.f90
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
subroutine rtping(dat,k,cfile6,MinSigdB,MouseDF,ntol)
|
||||||
|
|
||||||
|
!subroutine rtping(dat,jz,nz,MinSigdB,MinWidth,NFreeze,DFTolerance, &
|
||||||
|
! MouseDF,istart,pick,cfile6,mycall,hiscall,mode,ps0)
|
||||||
|
|
||||||
|
! Decode Multi-Tone FSK441 mesages.
|
||||||
|
|
||||||
|
parameter (NSMAX=30*48000)
|
||||||
|
parameter (NZMAX=NSMAX/2048)
|
||||||
|
real dat(NSMAX) !Raw audio data
|
||||||
|
logical pick
|
||||||
|
character*6 cfile6
|
||||||
|
real sig(NZMAX) !Sq-law detected signal, sampled at 43 ms
|
||||||
|
real sigdb(NZMAX) !Signal in dB, sampled at 43 ms
|
||||||
|
real work(NZMAX)
|
||||||
|
real pingdat(3,100)
|
||||||
|
! character msg*40,msg3*3
|
||||||
|
character*90 line
|
||||||
|
common/ccom/nline,tping(100),line(100)
|
||||||
|
data nping0/0/
|
||||||
|
save
|
||||||
|
|
||||||
|
slim=MinSigdB
|
||||||
|
! nf1=-ntol
|
||||||
|
! nf2=ntol
|
||||||
|
dt=1.0/48000.0
|
||||||
|
kstep=2048
|
||||||
|
! pick=.false.
|
||||||
|
istart=1
|
||||||
|
jz=k
|
||||||
|
|
||||||
|
! Find signal power
|
||||||
|
j=k/kstep
|
||||||
|
sig(j)=dot_product(dat(k-kstep+1:k),dat(k-kstep+1:k))/kstep
|
||||||
|
if(j.lt.10) return
|
||||||
|
|
||||||
|
! Remove baseline, compute signal level in dB
|
||||||
|
call pctile (sig,work,j,50,base1)
|
||||||
|
do i=1,j
|
||||||
|
sigdb(i)=db(sig(i)/base1)
|
||||||
|
if(j.eq.703) write(13,3001) i,sig(i),sigdb(i)
|
||||||
|
3001 format(i5,2e12.3)
|
||||||
|
enddo
|
||||||
|
|
||||||
|
dtbuf=kstep*dt
|
||||||
|
wmin=0.040
|
||||||
|
call ping(sigdb,j,dtbuf,slim,wmin,pingdat,nping)
|
||||||
|
|
||||||
|
! If this is a "mouse pick" and no ping was found, force a pseudo-ping
|
||||||
|
! at center of data.
|
||||||
|
! if(pick.and.nping.eq.0) then
|
||||||
|
! if(nping.le.99) nping=nping+1
|
||||||
|
! pingdat(1,nping)=0.5*jz*dt
|
||||||
|
! pingdat(2,nping)=0.16
|
||||||
|
! pingdat(3,nping)=1.0
|
||||||
|
! endif
|
||||||
|
|
||||||
|
do iping=1,nping
|
||||||
|
! Find starting place and length of data to be analyzed:
|
||||||
|
tstart=pingdat(1,iping)
|
||||||
|
width=pingdat(2,iping)
|
||||||
|
peak=pingdat(3,iping)
|
||||||
|
! mswidth=10*nint(100.0*width)
|
||||||
|
jj=(tstart-0.02)/dt
|
||||||
|
if(jj.lt.1) jj=1
|
||||||
|
jjz=nint((width+0.02)/dt)+1
|
||||||
|
jjz=min(jjz,jz+1-jj)
|
||||||
|
|
||||||
|
! Compute average spectrum of this ping.
|
||||||
|
! call spec441(dat(jj),jjz,ps,f0)
|
||||||
|
|
||||||
|
! Decode the message.
|
||||||
|
! msg=' '
|
||||||
|
! call longx(dat(jj),jjz,ps,DFTolerance,noffset,msg,msglen,bauderr)
|
||||||
|
|
||||||
|
! Assemble a signal report:
|
||||||
|
nwidth=0
|
||||||
|
if(width.ge.0.04) nwidth=1 !These might depend on NSPD
|
||||||
|
if(width.ge.0.12) nwidth=2
|
||||||
|
if(width.gt.1.00) nwidth=3
|
||||||
|
nstrength=6
|
||||||
|
if(peak.ge.11.0) nstrength=7
|
||||||
|
if(peak.ge.17.0) nstrength=8
|
||||||
|
if(peak.ge.23.0) nstrength=9
|
||||||
|
! nrpt=10*nwidth + nstrength
|
||||||
|
t2=tstart + dt*(istart-1)
|
||||||
|
|
||||||
|
jjzz=min(jjz,2*48000) !Max data size 2 s
|
||||||
|
!###
|
||||||
|
jjzz=14400
|
||||||
|
jj=jj-200
|
||||||
|
!###
|
||||||
|
|
||||||
|
if(nping.gt.nping0) then
|
||||||
|
print*,'a',jj,jjzz,jj*dt,jjzz*dt,t2,width
|
||||||
|
call jtmsk(dat(jj),jjzz,cfile6,t2,mswidth,int(peak),nrpt, &
|
||||||
|
nfreeze,DFTolerance,MouseDF,pick)
|
||||||
|
nping0=nping
|
||||||
|
endif
|
||||||
|
enddo
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine rtping
|
51
libm65/setupmsk.f90
Normal file
51
libm65/setupmsk.f90
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
subroutine setupmsk(cw,cwb)
|
||||||
|
|
||||||
|
! Calculate the JTMS character waveforms.
|
||||||
|
|
||||||
|
complex cw(168,0:63)
|
||||||
|
complex cwb(168)
|
||||||
|
integer nb(7)
|
||||||
|
! real*8 twopi,dt,f0,f1
|
||||||
|
character cc*64
|
||||||
|
! 1 2 3 4 5 6
|
||||||
|
! 0123456789012345678901234567890123456789012345678901234567890123
|
||||||
|
data cc/'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ./?- _ @'/
|
||||||
|
|
||||||
|
nsps=24
|
||||||
|
twopi=8.d0*atan(1.d0)
|
||||||
|
dt=1.d0/48000.d0 !Sample interval
|
||||||
|
f0=1000.d0
|
||||||
|
f1=2000.d0
|
||||||
|
dphi0=twopi*dt*f0
|
||||||
|
dphi1=twopi*dt*f1
|
||||||
|
|
||||||
|
do i=0,63
|
||||||
|
k=0
|
||||||
|
m=0
|
||||||
|
do n=5,0,-1 !Each character gets 6+1 bits
|
||||||
|
k=k+1
|
||||||
|
nb(k)=iand(1,ishft(i,-n))
|
||||||
|
m=m+nb(k)
|
||||||
|
enddo
|
||||||
|
k=k+1
|
||||||
|
nb(k)=iand(m,1) !Insert parity bit
|
||||||
|
|
||||||
|
phi=0.
|
||||||
|
j=0
|
||||||
|
do k=1,7 !Generate the waveform
|
||||||
|
if(nb(k).eq.0) then
|
||||||
|
dphi=dphi0
|
||||||
|
else
|
||||||
|
dphi=dphi1
|
||||||
|
endif
|
||||||
|
do ii=1,nsps
|
||||||
|
j=j+1
|
||||||
|
phi=phi+dphi
|
||||||
|
cw(j,i)=cmplx(cos(phi),sin(phi))
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
cwb=cw(1:168,57)
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine setupmsk
|
38
libm65/syncmsk.f90
Normal file
38
libm65/syncmsk.f90
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
subroutine syncmsk(cdat,npts,cwb,r,i1)
|
||||||
|
|
||||||
|
! Establish character sync within a JTMS ping.
|
||||||
|
|
||||||
|
complex cdat(npts) !Analytic signal
|
||||||
|
complex cwb(168) !Complex waveform for 'space'
|
||||||
|
real r(60000)
|
||||||
|
real tmp(60000)
|
||||||
|
integer hist(168),hmax(1)
|
||||||
|
complex z
|
||||||
|
|
||||||
|
r=0.
|
||||||
|
jz=npts-168+1
|
||||||
|
do j=1,jz
|
||||||
|
z=0.
|
||||||
|
ss=0.
|
||||||
|
do i=1,168
|
||||||
|
ss=ss + abs(cdat(i+j-1)) !Total power
|
||||||
|
z=z + cdat(i+j-1)*conjg(cwb(i)) !Signal matching <space>
|
||||||
|
enddo
|
||||||
|
r(j)=abs(z)/ss !Goodness-of-fit to <space>
|
||||||
|
! write(52,3001) j/168.0,r(j),cdat(j)
|
||||||
|
!3001 format(4f12.3)
|
||||||
|
enddo
|
||||||
|
|
||||||
|
ncut=99.0*float(jz-10)/float(jz)
|
||||||
|
call pctile(r,tmp,jz,ncut,rlim)
|
||||||
|
hist=0
|
||||||
|
do j=1,jz
|
||||||
|
k=mod(j-1,168)+1
|
||||||
|
if(r(j).gt.rlim) hist(k)=hist(k)+1
|
||||||
|
enddo
|
||||||
|
|
||||||
|
hmax=maxloc(hist)
|
||||||
|
i1=hmax(1)
|
||||||
|
|
||||||
|
return
|
||||||
|
end subroutine syncmsk
|
@ -1309,7 +1309,7 @@ void MainWindow::ba2msg(QByteArray ba, char message[]) //ba2msg()
|
|||||||
{
|
{
|
||||||
bool eom;
|
bool eom;
|
||||||
eom=false;
|
eom=false;
|
||||||
for(int i=0;i<22; i++) {
|
for(int i=0;i<28; i++) {
|
||||||
if((int)ba[i] == 0) eom=true;
|
if((int)ba[i] == 0) eom=true;
|
||||||
if(eom) {
|
if(eom) {
|
||||||
message[i]=32;
|
message[i]=32;
|
||||||
@ -1317,7 +1317,7 @@ void MainWindow::ba2msg(QByteArray ba, char message[]) //ba2msg()
|
|||||||
message[i]=ba[i];
|
message[i]=ba[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
message[22]=0;
|
message[28]=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::on_txFirstCheckBox_stateChanged(int nstate) //TxFirst
|
void MainWindow::on_txFirstCheckBox_stateChanged(int nstate) //TxFirst
|
||||||
|
Loading…
Reference in New Issue
Block a user