diff --git a/CMakeLists.txt b/CMakeLists.txt index 01f4959c4..dbb70f147 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -456,6 +456,7 @@ set (wsjt_FSRCS lib/ft8.f90 lib/ft8dec.f90 lib/ft8/ft8sim.f90 + lib/ft8/ft8sim_gfsk.f90 lib/gen4.f90 lib/gen65.f90 lib/gen9.f90 @@ -465,6 +466,7 @@ set (wsjt_FSRCS lib/genmsk40.f90 lib/ft4/genft4.f90 lib/ft4/gen_ft4wave.f90 + lib/ft8/gen_ft8wave.f90 lib/genqra64.f90 lib/ft8/genft8refsig.f90 lib/genwspr.f90 @@ -1265,6 +1267,9 @@ target_link_libraries (ft8 wsjt_fort wsjt_cxx) add_executable (ft8sim lib/ft8/ft8sim.f90 wsjtx.rc) target_link_libraries (ft8sim wsjt_fort wsjt_cxx) +add_executable (ft8sim_gfsk lib/ft8/ft8sim_gfsk.f90 wsjtx.rc) +target_link_libraries (ft8sim_gfsk wsjt_fort wsjt_cxx) + add_executable (msk144sim lib/msk144sim.f90 wsjtx.rc) target_link_libraries (msk144sim wsjt_fort wsjt_cxx) diff --git a/lib/ft8/ft8sim_gfsk.f90 b/lib/ft8/ft8sim_gfsk.f90 new file mode 100644 index 000000000..335e63f6b --- /dev/null +++ b/lib/ft8/ft8sim_gfsk.f90 @@ -0,0 +1,129 @@ +program ft8sim_gfsk + +! Generate simulated "type 2" ft8 files +! Output is saved to a *.wav file. + + use wavhdr + use packjt77 + include 'ft8_params.f90' !Set various constants + parameter (NWAVE=(NN+2)*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) + complex cwave(0:NWAVE-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.7) then + print*,'Usage: ft8sim "message" f0 DT fdop del nfiles snr' + print*,'Examples: ft8sim "K1ABC W9XYZ EN37" 1500.0 0.0 0.1 1.0 10 -18' + print*,' ft8sim "WA9XYZ/R KA1ABC/R FN42" 1500.0 0.0 0.1 1.0 10 -18' + print*,' ft8sim "K1ABC RR73; W9XYZ -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,*) nfiles !Number of files + call getarg(7,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) + tt=NSPS*dt !Duration of symbols (s) + baud=1.0/tt !Keying rate (baud) + bw=8*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) + call genft8(msg37,i3,n3,msgsent37,msgbits,itone) + call gen_ft8wave(itone,NN,NSPS,fs,f0,cwave,NWAVE) + + write(*,*) + write(*,'(a23,a37,3x,a7,i1,a1,i1)') 'New Style FT8 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:',f4.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() + + msg0=msg + do ifile=1,nfiles + c0=0. + c0(0:NWAVE-1)=cwave + c0=cshift(c0,-nint((xdt+0.5)/dt)) + if(fspread.ne.0.0 .or. delay.ne.0.0) call watterson(c0,NMAX,NWAVE,fs,delay,fspread) + c=sig*c0 + + wave=imag(c) + peak=maxval(abs(wave)) + nslots=1 + + 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 ft8sim_gfsk diff --git a/lib/ft8/gen_ft8wave.f90 b/lib/ft8/gen_ft8wave.f90 new file mode 100644 index 000000000..609cb2000 --- /dev/null +++ b/lib/ft8/gen_ft8wave.f90 @@ -0,0 +1,63 @@ +subroutine gen_ft8wave(itone,nsym,nsps,fsample,f0,cwave,nwave) +! +! generate ft8 waveform using Gaussian-filtered frequency pulses. +! + + parameter(MAX_SECONDS=20) + real wave(nwave) + complex cwave(nwave) + real pulse(5760) + real dphi(0:(nsym+2)*nint(fsample)-1) + integer itone(nsym) + logical first + data first/.true./ + save pulse,first,twopi,dt,hmod + + if(nsave .gt. MAX_SECONDS*nint(fsample)) then + print*,"gen_ft8wave: ERROR - waveform length too large." + endif + + if(first) then + twopi=8.0*atan(1.0) + dt=1.0/fsample + hmod=1.0 + bt=1.0 +! Compute the frequency-smoothing pulse + do i=1,3*nsps + tt=(i-1.5*nsps)/real(nsps) + pulse(i)=gfsk_pulse(bt,tt) + enddo + first=.false. + endif + +! Compute the smoothed frequency waveform. +! Length = (nsym+2)*nsps samples, zero-padded + dphi_peak=twopi*hmod/real(nsps) + dphi=0.0 + do j=1,nsym + ib=(j-1)*nsps + ie=ib+3*nsps-1 + dphi(ib:ie) = dphi(ib:ie) + dphi_peak*pulse(1:3*nsps)*itone(j) + enddo + +! Calculate and insert the audio waveform + phi=0.0 + dphi = dphi + twopi*f0*dt !Shift frequency up by f0 + wave=0. + k=0 + do j=0,nwave-1 + k=k+1 + wave(k)=sin(phi) + cwave(k)=cmplx(cos(phi),sin(phi)) + phi=mod(phi+dphi(j),twopi) + enddo + +! Compute the ramp-up and ramp-down symbols + cwave(1:nsps)=cwave(1:nsps) * & + (1.0-cos(twopi*(/(i,i=0,nsps-1)/)/(2.0*nsps)))/2.0 + k1=(nsym+1)*nsps+1 + cwave(k1:k1+nsps-1)=cwave(k1:k1+nsps-1) * & + (1.0+cos(twopi*(/(i,i=0,nsps-1)/)/(2.0*nsps)))/2.0 + + return +end subroutine gen_ft8wave