mirror of
https://github.com/saitohirga/WSJT-X.git
synced 2024-11-25 05:38:46 -05:00
Add simulator (ft2sim.f90) and decoder (ft2d.f90) for experimental medium-fast mode.
This commit is contained in:
parent
97e04fd7e1
commit
e0658f183f
@ -459,6 +459,7 @@ set (wsjt_FSRCS
|
||||
lib/ft8/genft8.f90
|
||||
lib/genmsk_128_90.f90
|
||||
lib/genmsk40.f90
|
||||
lib/fsk4hf/genft2.f90
|
||||
lib/genqra64.f90
|
||||
lib/ft8/genft8refsig.f90
|
||||
lib/genwspr.f90
|
||||
@ -503,6 +504,8 @@ set (wsjt_FSRCS
|
||||
lib/msk144signalquality.f90
|
||||
lib/msk144sim.f90
|
||||
lib/mskrtd.f90
|
||||
lib/fsk4hf/ft2sim.f90
|
||||
lib/fsk4hf/ft2d.f90
|
||||
lib/77bit/my_hash.f90
|
||||
lib/wsprd/osdwspr.f90
|
||||
lib/ft8/osd174_91.f90
|
||||
@ -1247,6 +1250,12 @@ target_link_libraries (ft8sim wsjt_fort wsjt_cxx)
|
||||
add_executable (msk144sim lib/msk144sim.f90 wsjtx.rc)
|
||||
target_link_libraries (msk144sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (ft2sim lib/fsk4hf/ft2sim.f90 wsjtx.rc)
|
||||
target_link_libraries (ft2sim wsjt_fort wsjt_cxx)
|
||||
|
||||
add_executable (ft2d lib/fsk4hf/ft2d.f90 wsjtx.rc)
|
||||
target_link_libraries (ft2d wsjt_fort wsjt_cxx)
|
||||
|
||||
endif(WSJT_BUILD_UTILS)
|
||||
|
||||
# build the main application
|
||||
|
12
lib/fsk4hf/ft2_params.f90
Normal file
12
lib/fsk4hf/ft2_params.f90
Normal file
@ -0,0 +1,12 @@
|
||||
! LDPC (128,90) code
|
||||
parameter (KK=90) !Information bits (77 + CRC13)
|
||||
parameter (ND=128) !Data symbols
|
||||
parameter (NS=16) !Sync symbols (2x8)
|
||||
parameter (NN=NS+ND) !Total channel symbols (144)
|
||||
parameter (NSPS=160) !Samples per symbol at 12000 S/s
|
||||
parameter (NZ=NSPS*NN) !Samples in full 1.92 s waveform (23040)
|
||||
parameter (NMAX=3*12000) !Samples in iwave (36,000)
|
||||
parameter (NFFT1=2*NSPS, NH1=NFFT1/2) !Length of FFTs for symbol spectra
|
||||
parameter (NSTEP=NSPS/4) !Rough time-sync step size
|
||||
parameter (NHSYM=NMAX/NSTEP-3) !Number of symbol spectra (1/4-sym steps)
|
||||
parameter (NDOWN=10) !Downsample factor
|
325
lib/fsk4hf/ft2d.f90
Normal file
325
lib/fsk4hf/ft2d.f90
Normal file
@ -0,0 +1,325 @@
|
||||
program ft2d
|
||||
|
||||
use crc
|
||||
use packjt77
|
||||
include 'ft2_params.f90'
|
||||
character arg*8,message*37,c77*77,infile*80,fname*16,datetime*11
|
||||
character*37 decodes(100)
|
||||
character*120 data_dir
|
||||
character*90 dmsg
|
||||
complex c2(0:3*1200-1) !Complex waveform
|
||||
complex cd(0:144*10-1) !Complex waveform
|
||||
complex c1(0:9),c0(0:9)
|
||||
complex ccor(0:1,144)
|
||||
complex csum,cterm,cc0,cc1
|
||||
real*8 fMHz
|
||||
|
||||
real rxdata(128),llr(128) !Soft symbols
|
||||
real llr2(128)
|
||||
real sbits(144),sbits1(144),sbits3(144)
|
||||
real ps(0:8191),psbest(0:8191)
|
||||
real candidates(100,2)
|
||||
integer ihdr(11)
|
||||
integer*2 iwave(NMAX) !Generated full-length waveform
|
||||
integer*1 message77(77),apmask(128),cw(128)
|
||||
integer*1 hbits(144),hbits1(144),hbits3(144)
|
||||
logical unpk77_success
|
||||
|
||||
fs=12000.0/NDOWN !Sample rate
|
||||
dt=1/fs !Sample interval after downsample (s)
|
||||
tt=NSPS*dt !Duration of "itone" symbols (s)
|
||||
baud=1.0/tt !Keying rate for "itone" symbols (baud)
|
||||
txt=NZ*dt !Transmission length (s)
|
||||
twopi=8.0*atan(1.0)
|
||||
h=0.8 !h=0.8 seems to be optimum for AWGN sensitivity (not for fading)
|
||||
|
||||
dphi=twopi/2*baud*h*dt*16 ! dt*16 is samp interval after downsample
|
||||
dphi0=-1*dphi
|
||||
dphi1=+1*dphi
|
||||
phi0=0.0
|
||||
phi1=0.0
|
||||
do i=0,9
|
||||
c1(i)=cmplx(cos(phi1),sin(phi1))
|
||||
c0(i)=cmplx(cos(phi0),sin(phi0))
|
||||
phi1=mod(phi1+dphi1,twopi)
|
||||
phi0=mod(phi0+dphi0,twopi)
|
||||
enddo
|
||||
the=twopi*h/2.0
|
||||
cc1=cmplx(cos(the),-sin(the))
|
||||
cc0=cmplx(cos(the),sin(the))
|
||||
nargs=iargc()
|
||||
if(nargs.lt.1) then
|
||||
print*,'Usage: ft2d [-a <data_dir>] [-f fMHz] [-c ncoh] file1 [file2 ...]'
|
||||
go to 999
|
||||
endif
|
||||
iarg=1
|
||||
data_dir="."
|
||||
call getarg(iarg,arg)
|
||||
if(arg(1:2).eq.'-a') then
|
||||
call getarg(iarg+1,data_dir)
|
||||
iarg=iarg+2
|
||||
endif
|
||||
call getarg(iarg,arg)
|
||||
if(arg(1:2).eq.'-f') then
|
||||
call getarg(iarg+1,arg)
|
||||
read(arg,*) fMHz
|
||||
iarg=iarg+2
|
||||
endif
|
||||
ncoh=1
|
||||
npdi=16
|
||||
if(arg(1:2).eq.'-c') then
|
||||
call getarg(iarg+1,arg)
|
||||
read(arg,*) ncoh
|
||||
iarg=iarg+2
|
||||
npdi=16/ncoh
|
||||
endif
|
||||
! write(*,*) 'ncoh: ',ncoh,' npdi: ',npdi
|
||||
|
||||
xs1=0.0
|
||||
xs2=0.0
|
||||
fr1=0.0
|
||||
fr2=0.0
|
||||
nav=0
|
||||
ngood=0
|
||||
|
||||
do ifile=iarg,nargs
|
||||
call getarg(ifile,infile)
|
||||
j2=index(infile,'.wav')
|
||||
open(10,file=infile,status='old',access='stream')
|
||||
read(10,end=999) ihdr,iwave
|
||||
read(infile(j2-4:j2-1),*) nutc
|
||||
datetime=infile(j2-11:j2-1)
|
||||
close(10)
|
||||
|
||||
ndecodes=0
|
||||
ncand=1
|
||||
do icand=1,ncand
|
||||
fc0=1500.0
|
||||
xsnr=1.0
|
||||
istart=6000+8
|
||||
call ft2_downsample(iwave,c2) ! downsample from 160s/Symbol to 10s/Symbol
|
||||
|
||||
ib=istart/16
|
||||
cd=c2(ib:ib+144*10-1)
|
||||
s2=sum(cd*conjg(cd))/(10*144)
|
||||
cd=cd/sqrt(s2)
|
||||
do nseq=1,7
|
||||
if( nseq.eq.1 ) then ! noncoherent single-symbol detection
|
||||
sbits1=0.0
|
||||
do ibit=1,144
|
||||
ib=(ibit-1)*10
|
||||
ccor(1,ibit)=sum(cd(ib:ib+9)*conjg(c1(0:9)))
|
||||
ccor(0,ibit)=sum(cd(ib:ib+9)*conjg(c0(0:9)))
|
||||
sbits1(ibit)=abs(ccor(1,ibit))-abs(ccor(0,ibit))
|
||||
hbits1(ibit)=0
|
||||
if(sbits1(ibit).gt.0) hbits1(ibit)=1
|
||||
enddo
|
||||
sbits=sbits1
|
||||
hbits=hbits1
|
||||
sbits3=sbits1
|
||||
hbits3=hbits1
|
||||
elseif( nseq.ge.2 ) then
|
||||
nbit=2*nseq-1
|
||||
numseq=2**(nbit)
|
||||
ps=0
|
||||
do ibit=nbit/2+1,144-nbit/2
|
||||
ps=0.0
|
||||
pmax=0.0
|
||||
do iseq=0,numseq-1
|
||||
csum=0.0
|
||||
cterm=1.0
|
||||
k=1
|
||||
do i=nbit-1,0,-1
|
||||
ibb=iand(iseq/(2**i),1)
|
||||
csum=csum+ccor(ibb,ibit-(nbit/2+1)+k)*cterm
|
||||
if(ibb.eq.0) cterm=cterm*cc0
|
||||
if(ibb.eq.1) cterm=cterm*cc1
|
||||
k=k+1
|
||||
enddo
|
||||
ps(iseq)=abs(csum)
|
||||
if( ps(iseq) .gt. pmax ) then
|
||||
pmax=ps(iseq)
|
||||
ibflag=1
|
||||
endif
|
||||
enddo
|
||||
if( ibflag .eq. 1 ) then
|
||||
psbest=ps
|
||||
ibflag=0
|
||||
endif
|
||||
call getbitmetric(2**(nbit/2),psbest,numseq,sbits3(ibit))
|
||||
hbits3(ibit)=0
|
||||
if(sbits3(ibit).gt.0) hbits3(ibit)=1
|
||||
enddo
|
||||
sbits=sbits3
|
||||
hbits=hbits3
|
||||
endif
|
||||
rxdata(1:48)=sbits(9:56)
|
||||
rxdata(49:128)=sbits(65:144)
|
||||
rxav=sum(rxdata(1:128))/128.0
|
||||
rx2av=sum(rxdata(1:128)*rxdata(1:128))/128.0
|
||||
rxsig=sqrt(rx2av-rxav*rxav)
|
||||
rxdata=rxdata/rxsig
|
||||
sigma=0.90
|
||||
llr(1:128)=2*rxdata/(sigma*sigma)
|
||||
apmask=0
|
||||
max_iterations=40
|
||||
ifer=0
|
||||
do ibias=0,0
|
||||
llr2=llr
|
||||
if(ibias.eq.1) llr2=llr+0.4
|
||||
if(ibias.eq.2) llr2=llr-0.4
|
||||
call bpdecode128_90(llr2,apmask,max_iterations,message77,cw,nharderror,niterations)
|
||||
if(nharderror.ge.0) exit
|
||||
enddo
|
||||
nhardmin=-1
|
||||
if(sum(message77).eq.0) cycle
|
||||
if( nharderror.ge.0 ) then
|
||||
write(c77,'(77i1)') message77(1:77)
|
||||
call unpack77(c77,message,unpk77_success)
|
||||
do i=1,ndecodes
|
||||
if(decodes(i).eq.message) idupe=1
|
||||
enddo
|
||||
if(idupe.eq.1) goto 888
|
||||
ndecodes=ndecodes+1
|
||||
decodes(ndecodes)=message
|
||||
nsnr=nint(xsnr)
|
||||
freq=fMHz + 1.d-6*(fc1+fbest)
|
||||
1210 format(a11,2i4,f6.2,f12.7,2x,a22,i3)
|
||||
write(*,1212) datetime(8:11),nsnr,xdt,freq,message,'*',idf,nseq,ijitter,nharderror,nhardmin
|
||||
1212 format(a4,i4,f5.1,f11.6,2x,a22,a1,i5,i5,i5,i5,i5)
|
||||
goto 888
|
||||
endif
|
||||
enddo ! nseq
|
||||
888 continue
|
||||
enddo !candidate list
|
||||
enddo !files
|
||||
|
||||
write(*,1120)
|
||||
1120 format("<DecodeFinished>")
|
||||
|
||||
999 end program ft2d
|
||||
|
||||
subroutine getbitmetric(ib,ps,ns,xmet)
|
||||
real ps(0:ns-1)
|
||||
xm1=0
|
||||
xm0=0
|
||||
do i=0,ns-1
|
||||
if( iand(i/ib,1) .eq. 1 .and. ps(i) .gt. xm1 ) xm1=ps(i)
|
||||
if( iand(i/ib,1) .eq. 0 .and. ps(i) .gt. xm0 ) xm0=ps(i)
|
||||
enddo
|
||||
xmet=xm1-xm0
|
||||
return
|
||||
end subroutine getbitmetric
|
||||
|
||||
subroutine downsample2(ci,f0,co)
|
||||
parameter(NI=144*160,NH=NI/2,NO=NI/16) ! downsample from 200 samples per symbol to 10
|
||||
complex ci(0:NI-1),ct(0:NI-1)
|
||||
complex co(0:NO-1)
|
||||
fs=12000.0
|
||||
df=fs/NI
|
||||
ct=ci
|
||||
call four2a(ct,NI,1,-1,1) !c2c FFT to freq domain
|
||||
i0=nint(f0/df)
|
||||
ct=cshift(ct,i0)
|
||||
co=0.0
|
||||
co(0)=ct(0)
|
||||
b=8.0
|
||||
do i=1,NO/2
|
||||
arg=(i*df/b)**2
|
||||
filt=exp(-arg)
|
||||
co(i)=ct(i)*filt
|
||||
co(NO-i)=ct(NI-i)*filt
|
||||
enddo
|
||||
co=co/NO
|
||||
call four2a(co,NO,1,1,1) !c2c FFT back to time domain
|
||||
return
|
||||
end subroutine downsample2
|
||||
|
||||
subroutine getcandidate2(c,npts,fs,fa,fb,ncand,candidates)
|
||||
parameter(NDAT=200,NFFT1=120*12000/32,NH1=NFFT1/2,NFFT2=120*12000/320,NH2=NFFT2/2)
|
||||
complex c(0:npts-1) !Complex waveform
|
||||
complex cc(0:NFFT1-1)
|
||||
complex csfil(0:NFFT2-1)
|
||||
complex cwork(0:NFFT2-1)
|
||||
real bigspec(0:NFFT2-1)
|
||||
complex c2(0:NFFT1-1) !Short spectra
|
||||
real s(-NH1+1:NH1) !Coarse spectrum
|
||||
real ss(-NH1+1:NH1) !Smoothed coarse spectrum
|
||||
real candidates(100,2)
|
||||
integer indx(NFFT2-1)
|
||||
logical first
|
||||
data first/.true./
|
||||
save first,w,df,csfil
|
||||
|
||||
if(first) then
|
||||
df=10*fs/NFFT1
|
||||
csfil=cmplx(0.0,0.0)
|
||||
do i=0,NFFT2-1
|
||||
csfil(i)=exp(-((i-NH2)/20.0)**2)
|
||||
enddo
|
||||
csfil=cshift(csfil,NH2)
|
||||
call four2a(csfil,NFFT2,1,-1,1)
|
||||
first=.false.
|
||||
endif
|
||||
|
||||
cc=cmplx(0.0,0.0)
|
||||
cc(0:npts-1)=c;
|
||||
call four2a(cc,NFFT1,1,-1,1)
|
||||
cc=abs(cc)**2
|
||||
call four2a(cc,NFFT1,1,-1,1)
|
||||
cwork(0:NH2)=cc(0:NH2)*conjg(csfil(0:NH2))
|
||||
cwork(NH2+1:NFFT2-1)=cc(NFFT1-NH2+1:NFFT1-1)*conjg(csfil(NH2+1:NFFT2-1))
|
||||
|
||||
call four2a(cwork,NFFT2,1,+1,1)
|
||||
bigspec=cshift(real(cwork),-NH2)
|
||||
il=NH2+fa/df
|
||||
ih=NH2+fb/df
|
||||
nnl=ih-il+1
|
||||
call indexx(bigspec(il:il+nnl-1),nnl,indx)
|
||||
xn=bigspec(il-1+indx(nint(0.3*nnl)))
|
||||
bigspec=bigspec/xn
|
||||
ncand=0
|
||||
do i=il,ih
|
||||
if((bigspec(i).gt.bigspec(i-1)).and. &
|
||||
(bigspec(i).gt.bigspec(i+1)).and. &
|
||||
(bigspec(i).gt.1.15).and.ncand.lt.100) then
|
||||
ncand=ncand+1
|
||||
candidates(ncand,1)=df*(i-NH2)
|
||||
candidates(ncand,2)=10*log10(bigspec(i))-30.0
|
||||
endif
|
||||
enddo
|
||||
! do i=1,ncand
|
||||
! write(*,*) i,candidates(i,1),candidates(i,2)
|
||||
! enddo
|
||||
return
|
||||
end subroutine getcandidate2
|
||||
|
||||
subroutine ft2_downsample(iwave,c)
|
||||
|
||||
! Input: i*2 data in iwave() at sample rate 12000 Hz
|
||||
! Output: Complex data in c(), sampled at 1200 Hz
|
||||
|
||||
include 'ft2_params.f90'
|
||||
parameter (NFFT2=NMAX/16)
|
||||
integer*2 iwave(NMAX)
|
||||
complex c(0:NMAX/16-1)
|
||||
complex c1(0:NFFT2-1)
|
||||
complex cx(0:NMAX/2)
|
||||
real x(NMAX)
|
||||
equivalence (x,cx)
|
||||
|
||||
df=12000.0/NMAX
|
||||
x=iwave
|
||||
call four2a(x,NMAX,1,-1,0) !r2c FFT to freq domain
|
||||
i0=nint(1500.0/df)
|
||||
c1(0)=cx(i0)
|
||||
do i=1,NFFT2/2
|
||||
c1(i)=cx(i0+i)
|
||||
c1(NFFT2-i)=cx(i0-i)
|
||||
enddo
|
||||
c1=c1/NFFT2
|
||||
call four2a(c1,NFFT2,1,1,1) !c2c FFT back to time domain
|
||||
c=c1(0:NMAX/16-1)
|
||||
return
|
||||
end subroutine ft2_downsample
|
||||
|
139
lib/fsk4hf/ft2sim.f90
Normal file
139
lib/fsk4hf/ft2sim.f90
Normal file
@ -0,0 +1,139 @@
|
||||
program ft2sim
|
||||
|
||||
! Generate simulated signals for experimental "FT2" mode
|
||||
|
||||
use wavhdr
|
||||
use packjt77
|
||||
include 'ft2_params.f90' !Set various constants
|
||||
parameter (NWAVE=NN*NSPS)
|
||||
type(hdr) h !Header for .wav file
|
||||
character arg*12,fname*17
|
||||
character msg37*37,msgsent37*37
|
||||
character c77*77
|
||||
complex c0(0:NMAX-1)
|
||||
complex c(0:NMAX-1)
|
||||
real wave(NMAX)
|
||||
integer itone(NN)
|
||||
integer*1 msgbits(77)
|
||||
integer*2 iwave(NMAX) !Generated full-length waveform
|
||||
|
||||
! Get command-line argument(s)
|
||||
nargs=iargc()
|
||||
if(nargs.ne.8) then
|
||||
print*,'Usage: ft2sim "message" f0 DT fdop del width nfiles snr'
|
||||
print*,'Examples: ft2sim "K1ABC W9XYZ EN37" 1500.0 0.0 0.1 1.0 0 10 -18'
|
||||
print*,' ft2sim "WA9XYZ/R KA1ABC/R FN42" 1500.0 0.0 0.1 1.0 0 10 -18'
|
||||
print*,' ft2sim "K1ABC RR73; W9XYZ <KH1/KH7Z> -11" 300 0 0 0 25 1 -10'
|
||||
go to 999
|
||||
endif
|
||||
call getarg(1,msg37) !Message to be transmitted
|
||||
call getarg(2,arg)
|
||||
read(arg,*) f0 !Frequency (only used for single-signal)
|
||||
call getarg(3,arg)
|
||||
read(arg,*) xdt !Time offset from nominal (s)
|
||||
call getarg(4,arg)
|
||||
read(arg,*) fspread !Watterson frequency spread (Hz)
|
||||
call getarg(5,arg)
|
||||
read(arg,*) delay !Watterson delay (ms)
|
||||
call getarg(6,arg)
|
||||
read(arg,*) width !Filter transition width (Hz)
|
||||
call getarg(7,arg)
|
||||
read(arg,*) nfiles !Number of files
|
||||
call getarg(8,arg)
|
||||
read(arg,*) snrdb !SNR_2500
|
||||
|
||||
nsig=1
|
||||
if(f0.lt.100.0) then
|
||||
nsig=f0
|
||||
f0=1500
|
||||
endif
|
||||
|
||||
nfiles=abs(nfiles)
|
||||
twopi=8.0*atan(1.0)
|
||||
fs=12000.0 !Sample rate (Hz)
|
||||
dt=1.0/fs !Sample interval (s)
|
||||
hmod=0.8 !Modulation index (0.5 is MSK, 1.0 is FSK)
|
||||
tt=NSPS*dt !Duration of symbols (s)
|
||||
baud=1.0/tt !Keying rate (baud)
|
||||
bw=1.5*baud !Occupied bandwidth (Hz)
|
||||
txt=NZ*dt !Transmission length (s)
|
||||
bandwidth_ratio=2500.0/(fs/2.0)
|
||||
sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb)
|
||||
if(snrdb.gt.90.0) sig=1.0
|
||||
txt=NN*NSPS/12000.0
|
||||
|
||||
! Source-encode, then get itone()
|
||||
i3=-1
|
||||
n3=-1
|
||||
call pack77(msg37,i3,n3,c77)
|
||||
read(c77,'(77i1)') msgbits
|
||||
call genft2(msg37,0,msgsent37,itone,itype)
|
||||
write(*,*)
|
||||
write(*,'(a9,a37,3x,a7,i1,a1,i1)') 'Message: ',msgsent37,'i3.n3: ',i3,'.',n3
|
||||
write(*,1000) f0,xdt,txt,snrdb,bw
|
||||
1000 format('f0:',f9.3,' DT:',f6.2,' TxT:',f6.1,' SNR:',f6.1, &
|
||||
' BW:',f5.1)
|
||||
write(*,*)
|
||||
if(i3.eq.1) then
|
||||
write(*,*) ' mycall hiscall hisgrid'
|
||||
write(*,'(28i1,1x,i1,1x,28i1,1x,i1,1x,i1,1x,15i1,1x,3i1)') msgbits(1:77)
|
||||
else
|
||||
write(*,'(a14)') 'Message bits: '
|
||||
write(*,'(77i1)') msgbits
|
||||
endif
|
||||
write(*,*)
|
||||
write(*,'(a17)') 'Channel symbols: '
|
||||
write(*,'(79i1)') itone
|
||||
write(*,*)
|
||||
|
||||
call sgran()
|
||||
|
||||
do ifile=1,nfiles
|
||||
k=nint((xdt+0.5)/dt)
|
||||
ia=k
|
||||
phi=0.0
|
||||
c0=0.0
|
||||
do j=1,NN !Generate complex waveform
|
||||
dphi=twopi*(f0*dt+(hmod/2.0)*(2*itone(j)-1)/real(NSPS))
|
||||
do i=1,NSPS
|
||||
if(k.ge.0 .and. k.lt.NMAX) c0(k)=cmplx(cos(phi),sin(phi))
|
||||
k=k+1
|
||||
phi=mod(phi+dphi,twopi)
|
||||
enddo
|
||||
enddo
|
||||
if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c0,NMAX,NWAVE,fs,delay,fspread)
|
||||
c=sig*c0
|
||||
|
||||
ib=k
|
||||
wave=real(c)
|
||||
peak=maxval(abs(wave(ia:ib)))
|
||||
nslots=1
|
||||
if(width.gt.0.0) call filt8(f0,nslots,width,wave)
|
||||
|
||||
if(snrdb.lt.90) then
|
||||
do i=1,NMAX !Add gaussian noise at specified SNR
|
||||
xnoise=gran()
|
||||
wave(i)=wave(i) + xnoise
|
||||
enddo
|
||||
endif
|
||||
|
||||
gain=100.0
|
||||
if(snrdb.lt.90.0) then
|
||||
wave=gain*wave
|
||||
else
|
||||
datpk=maxval(abs(wave))
|
||||
fac=32766.9/datpk
|
||||
wave=fac*wave
|
||||
endif
|
||||
if(any(abs(wave).gt.32767.0)) print*,"Warning - data will be clipped."
|
||||
iwave=nint(wave)
|
||||
h=default_header(12000,NMAX)
|
||||
write(fname,1102) ifile
|
||||
1102 format('000000_',i6.6,'.wav')
|
||||
open(10,file=fname,status='unknown',access='stream')
|
||||
write(10) h,iwave !Save to *.wav file
|
||||
close(10)
|
||||
write(*,1110) ifile,xdt,f0,snrdb,fname
|
||||
1110 format(i4,f7.2,f8.2,f7.1,2x,a17)
|
||||
enddo
|
||||
999 end program ft2sim
|
124
lib/fsk4hf/genft2.f90
Normal file
124
lib/fsk4hf/genft2.f90
Normal file
@ -0,0 +1,124 @@
|
||||
subroutine genft2(msg0,ichk,msgsent,i4tone,itype)
|
||||
! s8 + 48bits + s8 + 80 bits = 144 bits (72ms message duration)
|
||||
!
|
||||
! Encode an MSK144 message
|
||||
! Input:
|
||||
! - msg0 requested message to be transmitted
|
||||
! - ichk if ichk=1, return only msgsent
|
||||
! if ichk.ge.10000, set imsg=ichk-10000 for short msg
|
||||
! - msgsent message as it will be decoded
|
||||
! - i4tone array of audio tone values, 0 or 1
|
||||
! - itype message type
|
||||
! 1 = standard message "Call_1 Call_2 Grid/Rpt"
|
||||
! 2 = type 1 prefix
|
||||
! 3 = type 1 suffix
|
||||
! 4 = type 2 prefix
|
||||
! 5 = type 2 suffix
|
||||
! 6 = free text (up to 13 characters)
|
||||
! 7 = short message "<Call_1 Call2> Rpt"
|
||||
|
||||
use iso_c_binding, only: c_loc,c_size_t
|
||||
use packjt77
|
||||
character*37 msg0
|
||||
character*37 message !Message to be generated
|
||||
character*37 msgsent !Message as it will be received
|
||||
character*77 c77
|
||||
integer*4 i4tone(144)
|
||||
integer*1 codeword(128)
|
||||
integer*1 msgbits(77)
|
||||
integer*1 bitseq(144) !Tone #s, data and sync (values 0-1)
|
||||
integer*1 s8(8)
|
||||
real*8 pp(12)
|
||||
real*8 xi(864),xq(864),pi,twopi
|
||||
data s8/0,1,1,1,0,0,1,0/
|
||||
equivalence (ihash,i1hash)
|
||||
logical first,unpk77_success
|
||||
data first/.true./
|
||||
save
|
||||
|
||||
if(first) then
|
||||
first=.false.
|
||||
nsym=128
|
||||
pi=4.0*atan(1.0)
|
||||
twopi=8.*atan(1.0)
|
||||
do i=1,12
|
||||
pp(i)=sin((i-1)*pi/12)
|
||||
enddo
|
||||
endif
|
||||
|
||||
message(1:37)=' '
|
||||
itype=1
|
||||
if(msg0(1:1).eq.'@') then !Generate a fixed tone
|
||||
read(msg0(2:5),*,end=1,err=1) nfreq !at specified frequency
|
||||
go to 2
|
||||
1 nfreq=1000
|
||||
2 i4tone(1)=nfreq
|
||||
else
|
||||
message=msg0
|
||||
|
||||
do i=1, 37
|
||||
if(ichar(message(i:i)).eq.0) then
|
||||
message(i:37)=' '
|
||||
exit
|
||||
endif
|
||||
enddo
|
||||
do i=1,37 !Strip leading blanks
|
||||
if(message(1:1).ne.' ') exit
|
||||
message=message(i+1:)
|
||||
enddo
|
||||
|
||||
if(message(1:1).eq.'<') then
|
||||
i2=index(message,'>')
|
||||
i1=0
|
||||
if(i2.gt.0) i1=index(message(1:i2),' ')
|
||||
if(i1.gt.0) then
|
||||
call genmsk40(message,msgsent,ichk,i4tone,itype)
|
||||
if(itype.lt.0) go to 999
|
||||
i4tone(41)=-40
|
||||
go to 999
|
||||
endif
|
||||
endif
|
||||
|
||||
i3=-1
|
||||
n3=-1
|
||||
call pack77(message,i3,n3,c77)
|
||||
call unpack77(c77,msgsent,unpk77_success) !Unpack to get msgsent
|
||||
|
||||
if(ichk.eq.1) go to 999
|
||||
read(c77,"(77i1)") msgbits
|
||||
call encode_128_90(msgbits,codeword)
|
||||
|
||||
!Create 144-bit channel vector:
|
||||
!8-bit sync word + 48 bits + 8-bit sync word + 80 bits
|
||||
bitseq=0
|
||||
bitseq(1:8)=s8
|
||||
bitseq(9:56)=codeword(1:48)
|
||||
bitseq(57:64)=s8
|
||||
bitseq(65:144)=codeword(49:128)
|
||||
|
||||
i4tone=bitseq
|
||||
|
||||
! bitseq=2*bitseq-1
|
||||
! xq(1:6)=bitseq(1)*pp(7:12) !first bit is mapped to 1st half-symbol on q
|
||||
! do i=1,71
|
||||
! is=(i-1)*12+7
|
||||
! xq(is:is+11)=bitseq(2*i+1)*pp
|
||||
! enddo
|
||||
! xq(864-5:864)=bitseq(1)*pp(1:6) !last half symbol
|
||||
! do i=1,72
|
||||
! is=(i-1)*12+1
|
||||
! xi(is:is+11)=bitseq(2*i)*pp
|
||||
! enddo
|
||||
! Map I and Q to tones.
|
||||
! i4tone=0
|
||||
! do i=1,72
|
||||
! i4tone(2*i-1)=(bitseq(2*i)*bitseq(2*i-1)+1)/2;
|
||||
! i4tone(2*i)=-(bitseq(2*i)*bitseq(mod(2*i,144)+1)-1)/2;
|
||||
! enddo
|
||||
endif
|
||||
|
||||
! Flip polarity
|
||||
! i4tone=-i4tone+1
|
||||
|
||||
999 return
|
||||
end subroutine genft2
|
@ -1,194 +0,0 @@
|
||||
program msksim
|
||||
|
||||
! Simulate characteristics of a potential "MSK10" mode using LDPC (168,84)
|
||||
! code, OQPDK modulation, and 30 s T/R sequences.
|
||||
|
||||
! Reception and Demodulation algorithm:
|
||||
! 1. Compute coarse spectrum; find fc1 = approx carrier freq
|
||||
! 2. Mix from fc1 to 0; LPF at +/- 0.75*R
|
||||
! 3. Square, FFT; find peaks near -R/2 and +R/2 to get fc2
|
||||
! 4. Mix from fc2 to 0
|
||||
! 5. Fit cb13 (central part of csync) to c -> lag, phase
|
||||
! 6. Fit complex ploynomial for channel equalization
|
||||
! 7. Get soft bits from equalized data
|
||||
|
||||
parameter (KK=84) !Information bits (72 + CRC12)
|
||||
parameter (ND=168) !Data symbols: LDPC (168,84), r=1/2
|
||||
parameter (NS=65) !Sync symbols (2 x 26 + Barker 13)
|
||||
parameter (NR=3) !Ramp up/down
|
||||
parameter (NN=NR+NS+ND) !Total symbols (236)
|
||||
parameter (NSPS=1152/72) !Samples per MSK symbol (16)
|
||||
parameter (N2=2*NSPS) !Samples per OQPSK symbol (32)
|
||||
parameter (N13=13*N2) !Samples in central sync vector (416)
|
||||
parameter (NZ=NSPS*NN) !Samples in baseband waveform (3776)
|
||||
parameter (NFFT1=4*NSPS,NH1=NFFT1/2)
|
||||
|
||||
character*8 arg
|
||||
complex cbb(0:NZ-1) !Complex baseband waveform
|
||||
complex csync(0:NZ-1) !Sync symbols only, from cbb
|
||||
complex cb13(0:N13-1) !Barker 13 waveform
|
||||
complex c(0:NZ-1) !Complex waveform
|
||||
complex c0(0:NZ-1) !Complex waveform
|
||||
complex zz(NS+ND) !Complex symbol values (intermediate)
|
||||
complex z
|
||||
real xnoise(0:NZ-1) !Generated random noise
|
||||
real ynoise(0:NZ-1) !Generated random noise
|
||||
real rxdata(ND),llr(ND) !Soft symbols
|
||||
real pp(2*NSPS) !Shaped pulse for OQPSK
|
||||
real a(5) !For twkfreq1
|
||||
real aa(20),bb(20) !Fitted polyco's
|
||||
integer id(NS+ND) !NRZ values (+/-1) for Sync and Data
|
||||
integer ierror(NS+ND)
|
||||
integer icw(NN)
|
||||
integer*1 msgbits(KK),decoded(KK),apmask(ND),cw(ND)
|
||||
! integer*1 codeword(ND)
|
||||
data msgbits/0,0,1,0,0,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1, &
|
||||
1,1,1,0,1,1,1,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,0,1,1,0,1,1, &
|
||||
1,1,0,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,1,0,1,0,1,0/
|
||||
|
||||
nargs=iargc()
|
||||
if(nargs.ne.6) then
|
||||
print*,'Usage: mskhfsim f0(Hz) delay(ms) fspread(Hz) maxn iters snr(dB)'
|
||||
print*,'Example: mskhfsim 0 0 0 5 10 -20'
|
||||
print*,'Set snr=0 to cycle through a range'
|
||||
go to 999
|
||||
endif
|
||||
call getarg(1,arg)
|
||||
read(arg,*) f0 !Generated carrier frequency
|
||||
call getarg(2,arg)
|
||||
read(arg,*) delay !Delta_t (ms) for Watterson model
|
||||
call getarg(3,arg)
|
||||
read(arg,*) fspread !Fspread (Hz) for Watterson model
|
||||
call getarg(4,arg)
|
||||
read(arg,*) maxn !Max nterms for polyfit
|
||||
call getarg(5,arg)
|
||||
read(arg,*) iters !Iterations at each SNR
|
||||
call getarg(6,arg)
|
||||
read(arg,*) snrdb !Specified SNR_2500
|
||||
|
||||
twopi=8.0*atan(1.0)
|
||||
fs=12000.0/72.0 !Sample rate = 166.6666667 Hz
|
||||
dt=1.0/fs !Sample interval (s)
|
||||
tt=NSPS*dt !Duration of "itone" symbols (s)
|
||||
ts=2*NSPS*dt !Duration of OQPSK symbols (s)
|
||||
baud=1.0/tt !Keying rate for "itone" symbols (baud)
|
||||
txt=NZ*dt !Transmission length (s)
|
||||
bandwidth_ratio=2500.0/(fs/2.0)
|
||||
write(*,1000) f0,delay,fspread,maxn,iters,baud,3*baud,txt
|
||||
1000 format('f0:',f5.1,' Delay:',f4.1,' fSpread:',f5.2,' maxn:',i3, &
|
||||
' Iters:',i6/'Baud:',f7.3,' BW:',f5.1,' TxT:',f5.1,f5.2/)
|
||||
write(*,1004)
|
||||
1004 format(/' SNR err ber fer fsigma'/37('-'))
|
||||
|
||||
do i=1,N2 !Half-sine pulse shape
|
||||
pp(i)=sin(0.5*(i-1)*twopi/(2*NSPS))
|
||||
enddo
|
||||
|
||||
call genmskhf(msgbits,id,icw,cbb,csync)!Generate baseband waveform and csync
|
||||
cb13=csync(1680:2095) !Copy the Barker 13 waveform
|
||||
a=0.
|
||||
a(1)=f0
|
||||
call twkfreq1(cbb,NZ,fs,a,cbb) !Mix to specified frequency
|
||||
|
||||
isna=-10
|
||||
isnb=-30
|
||||
if(snrdb.ne.0.0) then
|
||||
isna=nint(snrdb)
|
||||
isnb=isna
|
||||
endif
|
||||
do isnr=isna,isnb,-1 !Loop over SNR range
|
||||
snrdb=isnr
|
||||
sig=sqrt(bandwidth_ratio) * 10.0**(0.05*snrdb)
|
||||
if(snrdb.gt.90.0) sig=1.0
|
||||
nhard=0
|
||||
nhardsync=0
|
||||
nfe=0
|
||||
sqf=0.
|
||||
do iter=1,iters !Loop over requested iterations
|
||||
c=cbb
|
||||
if(delay.ne.0.0 .or. fspread.ne.0.0) then
|
||||
call watterson(c,NZ,fs,delay,fspread)
|
||||
endif
|
||||
c=sig*c !Scale to requested SNR
|
||||
if(snrdb.lt.90) then
|
||||
do i=0,NZ-1 !Generate gaussian noise
|
||||
xnoise(i)=gran()
|
||||
ynoise(i)=gran()
|
||||
enddo
|
||||
c=c + cmplx(xnoise,ynoise) !Add AWGN noise
|
||||
endif
|
||||
|
||||
call getfc1(c,fc1) !First approx for freq
|
||||
call getfc2(c,csync,fc1,fc2,fc3) !Refined freq
|
||||
sqf=sqf + (fc1+fc2-f0)**2
|
||||
|
||||
!NB: Measured performance is about equally good using fc2 or fc3 here:
|
||||
a(1)=-(fc1+fc2)
|
||||
a(2:5)=0.
|
||||
call twkfreq1(c,NZ,fs,a,c) !Mix c down by fc1+fc2
|
||||
|
||||
! The following may not be necessary?
|
||||
! z=sum(c(1680:2095)*cb13)/208.0 !Get phase from Barker 13 vector
|
||||
! z0=z/abs(z)
|
||||
! c=c*conjg(z0)
|
||||
|
||||
!---------------------------------------------------------------- DT
|
||||
! Not presently used:
|
||||
amax=0.
|
||||
jpk=0
|
||||
do j=-20*NSPS,20*NSPS !Get jpk
|
||||
z=sum(c(1680+j:2095+j)*cb13)/208.0
|
||||
if(abs(z).gt.amax) then
|
||||
amax=abs(z)
|
||||
jpk=j
|
||||
endif
|
||||
enddo
|
||||
xdt=jpk/fs
|
||||
|
||||
nterms=maxn
|
||||
c0=c
|
||||
do itry=1,10
|
||||
idf=itry/2
|
||||
if(mod(itry,2).eq.0) idf=-idf
|
||||
nhard0=0
|
||||
nhardsync0=0
|
||||
ifer=1
|
||||
a(1)=idf*0.01
|
||||
a(2:5)=0.
|
||||
call twkfreq1(c0,NZ,fs,a,c) !Mix c0 into c
|
||||
call cpolyfit(c,pp,id,maxn,aa,bb,zz,nhs)
|
||||
call msksoftsym(zz,aa,bb,id,nterms,ierror,rxdata,nhard0,nhardsync0)
|
||||
if(nhardsync0.gt.12) cycle
|
||||
rxav=sum(rxdata)/ND
|
||||
rx2av=sum(rxdata*rxdata)/ND
|
||||
rxsig=sqrt(rx2av-rxav*rxav)
|
||||
rxdata=rxdata/rxsig
|
||||
ss=0.84
|
||||
llr=2.0*rxdata/(ss*ss)
|
||||
apmask=0
|
||||
max_iterations=40
|
||||
ifer=0
|
||||
call bpdecode168(llr,apmask,max_iterations,decoded,niterations,cw)
|
||||
nbadcrc=0
|
||||
if(niterations.ge.0) call chkcrc12(decoded,nbadcrc)
|
||||
if(niterations.lt.0 .or. count(msgbits.ne.decoded).gt.0 .or. &
|
||||
nbadcrc.ne.0) ifer=1
|
||||
! if(ifer.eq.0) write(67,1301) snrdb,itry,idf,niterations, &
|
||||
! nhardsync0,nhard0
|
||||
!1301 format(f6.1,5i6)
|
||||
if(ifer.eq.0) exit
|
||||
enddo !Freq dither loop
|
||||
nhard=nhard+nhard0
|
||||
nhardsync=nharsdync+nhardsync0
|
||||
nfe=nfe+ifer
|
||||
enddo
|
||||
|
||||
fsigma=sqrt(sqf/iters)
|
||||
ber=float(nhard)/((NS+ND)*iters)
|
||||
fer=float(nfe)/iters
|
||||
write(*,1050) snrdb,nhard,ber,fer,fsigma
|
||||
! write(60,1050) snrdb,nhard,ber,fer,fsigma
|
||||
1050 format(f6.1,i7,f8.4,f7.3,f8.2)
|
||||
enddo
|
||||
|
||||
999 end program msksim
|
@ -70,14 +70,14 @@ endfunction
|
||||
# M-ary PSK Block Coded Modulation," Igal Sason and Gil Weichman,
|
||||
# doi: 10.1109/EEEI.2006.321097
|
||||
#-------------------------------------------------------------------------------
|
||||
N=174
|
||||
K=75
|
||||
N=128
|
||||
K=90
|
||||
R=K/N
|
||||
|
||||
delta=0.01;
|
||||
[ths,fval,info,output]=fzero(@f1,[delta,pi/2-delta], optimset ("jacobian", "off"));
|
||||
|
||||
for ebnodb=-6:0.5:4
|
||||
for ebnodb=-3:0.5:4
|
||||
ebno=10^(ebnodb/10.0);
|
||||
esno=ebno*R;
|
||||
A=sqrt(2*esno);
|
||||
|
19
lib/fsk4hf/spb_128_90.dat
Normal file
19
lib/fsk4hf/spb_128_90.dat
Normal file
@ -0,0 +1,19 @@
|
||||
N = 128
|
||||
K = 90
|
||||
R = 0.70312
|
||||
-3.000000 0.000341
|
||||
-2.500000 0.001513
|
||||
-2.000000 0.006049
|
||||
-1.500000 0.021280
|
||||
-1.000000 0.064283
|
||||
-0.500000 0.162755
|
||||
0.000000 0.338430
|
||||
0.500000 0.571867
|
||||
1.000000 0.791634
|
||||
1.500000 0.930284
|
||||
2.000000 0.985385
|
||||
2.500000 0.998258
|
||||
3.000000 0.999893
|
||||
3.500000 0.999997
|
||||
4.000000 1.000000
|
||||
|
Loading…
Reference in New Issue
Block a user