WSJT-X/lib/fsk4hf/dbpsksim.f90

242 lines
7.6 KiB
Fortran

program dbpsksim
parameter (ND=121) !Data symbols: LDPC (120,60), r=1/2
parameter (NN=ND) !Total symbols (121)
parameter (NSPS=28800) !Samples per symbol at 12000 sps
parameter (NZ=NSPS*NN) !Samples in waveform (3484800)
parameter (NFFT1=65536,NH1=NFFT1/2)
parameter (NFFT2=128,NH2=NFFT2/2)
character*8 arg
complex c(0:NZ-1) !Complex waveform
complex c2(0:NFFT1-1) !Short spectra
complex cr(0:NZ-1)
complex ct(0:NZ-1)
complex cz(0:NFFT2-1)
complex z0,z,zp
real s(-NH1+1:NH1)
real s2(-NH2+1:NH2)
real xnoise(0:NZ-1) !Generated random noise
real ynoise(0:NZ-1) !Generated random noise
real rxdata(120),llr(120)
integer id(NN) !Encoded NRZ data (values +/-1)
integer id1(NN) !Recovered data (1st pass)
integer id2(NN) !Recovered data (2nd pass)
! integer icw(NN)
integer*1 msgbits(60),decoded(60),codeword(120),apmask(120),cw(120)
data msgbits/0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,&
0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,1,0,0,1,0,1,1,0,1,0/
nnn=0
nargs=iargc()
if(nargs.ne.6) then
print*,'Usage: dbpsksim f0(Hz) delay(ms) fspread(Hz) ndiff iters snr(dB)'
print*,'Example: dbpsksim 1500 0 0 10 -35'
print*,'Set snr=0 to cycle through a range'
go to 999
endif
call getarg(1,arg)
read(arg,*) f0 !Low tone frequency
call getarg(2,arg)
read(arg,*) delay
call getarg(3,arg)
read(arg,*) fspread
call getarg(4,arg)
read(arg,*) ndiff
call getarg(5,arg)
read(arg,*) iters
call getarg(6,arg)
read(arg,*) snrdb
twopi=8.d0*atan(1.d0)
fs=12000.d0
dt=1.0/fs
ts=NSPS*dt
baud=1.d0/ts
txt=NZ*dt
bandwidth_ratio=2500.0/6000.0
write(*,1000) baud,5*baud,txt,delay,fspread,ndiff
1000 format('Baud:',f6.3,' BW:',f4.1,' TxT:',f6.1,' Delay:',f5.2, &
' fSpread:',f5.2,' ndiff:',i2/)
write(*,1004)
1004 format(' SNR err ber fer fsigma'/35('-'))
call encode120(msgbits,codeword) !Encode the test message
isna=-28
isnb=-40
if(snrdb.ne.0.0) then
isna=nint(snrdb)
isnb=isna
endif
do isnr=isna,isnb,-1
snrdb=isnr
sig=sqrt(bandwidth_ratio) * 10.0**(0.05*snrdb)
if(snrdb.gt.90.0) sig=1.0
nhard=0
nhardc=0
nfe1=0
nfe2=0
sqf=0.
do iter=1,iters
nnn=nnn+1
id(1)=1 !First bit is always 1
id(2:NN)=2*codeword-1
call genbpsk(id,f0,ndiff,0,c) !Generate the 4-FSK waveform
if(delay.ne.0.0 .or. fspread.ne.0.0) call watterson(c,delay,fspread)
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 noise to signal
endif
! First attempt at finding carrier frequency fc: 64k FFTs ==> avg power spectra
nspec=NZ/NFFT1
df1=12000.0/NFFT1
s=0.
do k=1,nspec
ia=(k-1)*NSPS
ib=ia+NSPS-1
c2(0:NSPS-1)=c(ia:ib)
c2(NSPS:)=0.
call four2a(c2,NFFT1,1,-1,1)
do i=0,NFFT1-1
j=i
if(j.gt.NH1) j=j-NFFT1
s(j)=s(j) + real(c2(i))**2 + aimag(c2(i))**2
enddo
enddo
s=1.e-6*s
smax=0.
ipk=0
ia=(1400.0)/df1
ib=(1600.0)/df1
do i=ia,ib
f=i*df1
if(s(i).gt.smax) then
smax=s(i)
ipk=i
fc=f
endif
enddo
a=(s(ipk+1)-s(ipk-1))/2.0
b=(s(ipk+1)+s(ipk-1)-2.0*s(ipk))/2.0
dx=-a/(2.0*b)
fc=fc + df1*dx !Estimated carrier frequency
sqf=sqf + (fc-f0)**2
! The following is for testing SNR calibration:
! sp5n=(s(ipk-2)+s(ipk-1)+s(ipk)+s(ipk+1)+s(ipk+2)) !Sig + 5*noise
! base=(sum(s)-sp5n)/(NFFT1-5.0) !Noise per bin
! psig=sp5n-5*base !Sig only
! pnoise=(2500.0/df1)*base !Noise in 2500 Hz
! xsnrdb=db(psig/pnoise)
call genbpsk(id,fc,ndiff,1,cr) !Generate reference carrier
c=c*conjg(cr) !Mix signal to baseband
z0=1.0
do j=1,NN !Demodulate
ia=(j-1)*NSPS
ib=ia+NSPS-1
z=sum(c(ia:ib))
cz(j-1)=z
zp=z*conjg(z0)
p=1.e-4*real(zp)
id1(j)=-1
if(p.ge.0.0) id1(j)=1
if(j.ge.2) rxdata(j-1)=p
z0=z
enddo
rxav=sum(rxdata)/120
rx2av=sum(rxdata*rxdata)/120
rxsig=sqrt(rx2av-rxav*rxav)
rxdata=rxdata/rxsig
ss=0.84
llr=2.0*rxdata/(ss*ss)
apmask=0
max_iterations=10
call bpdecode120(llr,apmask,max_iterations,decoded,niterations,cw)
! Count frame errors
if(niterations.lt.0 .or. count(msgbits.ne.decoded).gt.0) nfe1=nfe1+1
! Find carrier frequency from squared cz array.
cz(121:)=0.
cz=cz*cz
call four2a(cz,NFFT2,1,-1,1)
s2max=0.
do i=0,NFFT2-1
j=i
if(i.gt.NH2) j=j-NFFT2
s2(j)=real(cz(i))**2 + aimag(cz(i))**2
if(s2(j).gt.s2max) then
s2max=s2(j)
jpk=j
endif
! write(16,1200) j*baud/NFFT2,1.e-12*s2(j)
!1200 format(2f12.3)
enddo
a=(s2(jpk+1)-s2(jpk-1))/2.0
b=(s2(jpk+1)+s2(jpk-1)-2.0*s2(jpk))/2.0
dx=-a/(2.0*b)
fc2=0.5*(jpk+dx)*baud/NFFT2
call genbpsk(id,fc2,ndiff,1,cr) !Generate new ref carrier at fc2
c=c*conjg(cr)
z0=1.0
do j=1,NN !Demodulate
ia=(j-1)*NSPS
ib=ia+NSPS-1
z=sum(c(ia:ib))
if(j.eq.1) z0=z
zp=z*conjg(z0)
p=1.e-4*real(zp)
id2(j)=-1
if(p.ge.0.0) id2(j)=1
if(j.ge.2) rxdata(j-1)=p
ierr=0
if(id2(j).ne.id(j)) ierr=1
id3=-1
if(real(z).ge.0.0) id3=1
if(j.ge.2 .and. id3.ne.id(j)) nhardc=nhardc+1
if(j.ge.2 .and. ndiff.eq.0) rxdata(j-1)=real(z)
z0=z
enddo
nhard=nhard + count(id2.ne.id) !Count hard errors
rxav=sum(rxdata)/120
rx2av=sum(rxdata*rxdata)/120
rxsig=sqrt(rx2av-rxav*rxav)
rxdata=rxdata/rxsig
ss=0.84
llr=2.0*rxdata/(ss*ss) !Soft symbols
apmask=0
max_iterations=10
decoded=0
call bpdecode120(llr,apmask,max_iterations,decoded,niterations,cw)
! if(niterations.lt.0) then
! llr=-llr
! call bpdecode120(llr,apmask,max_iterations,decoded,niterations,cw)
! if(niterations.ge.0) nhard=NN*iters-nhard
! endif
if(niterations.ge.0) call chkcrc10(decoded,nbadcrc)
if(niterations.lt.0 .or. count(msgbits.ne.decoded).gt.0 .or. &
nbadcrc.ne.0) nfe2=nfe2+1
enddo
if(ndiff.eq.0) nhard=nhardc
fsigma=sqrt(sqf/iters)
ber=float(nhard)/(NN*iters)
fer=float(nfe2)/iters
write(*,1050) snrdb,nhard,ber,fer,fsigma
write(14,1050) snrdb,nhard,ber,fer,fsigma
1050 format(f6.1,i5,f8.4,f7.3,f8.2)
enddo
999 end program dbpsksim