SVN r8748

This commit is contained in:
Jordan Sherer
2018-06-14 21:27:34 -04:00
parent 419c039d08
commit 4f1fe4fc94
581 changed files with 69338 additions and 39836 deletions
@@ -0,0 +1,544 @@
program wspr5d
! Decode WSPR-LF data read from *.c5 or *.wav files.
! WSPR-LF is a potential WSPR-like mode intended for use at LF and MF.
! It uses an LDPC (300,60) code, OQPSK modulation, and 5 minute T/R sequences.
!
! Still to do: find and decode more than one signal in the specified passband.
! include 'wsprlf_params.f90'
parameter (NDOWN=30)
parameter (KK=60)
parameter (ND=300)
parameter (NS=109)
parameter (NR=3)
parameter (NN=NR+NS+ND)
parameter (NSPS0=8640)
parameter (NSPS=16)
parameter (N2=2*NSPS)
parameter (NZ=NSPS*NN)
parameter (NZ400=288*NN)
parameter (NMAX=300*12000)
character arg*8,message*22,cbits*50,infile*80,fname*16,datetime*11
character*120 data_dir
complex csync(0:NZ-1) !Sync symbols only, from cbb
complex c400(0:NZ400-1) !Complex waveform
complex c(0:NZ-1) !Complex waveform
complex cd(0:NZ-1) !Complex waveform
complex ca(0:NZ-1) !Complex waveform
complex zz,zzsum
real*8 fMHz
real rxdata(ND),llr(ND) !Soft symbols
real pp(32) !Shaped pulse for OQPSK
real sbits(412),softbits(9)
real fpks(20)
integer id(NS+ND) !NRZ values (+/-1) for Sync and Data
integer isync(48) !Long sync vector
integer ib13(13) !Barker 13 code
integer ihdr(11)
integer*8 n8
integer*2 iwave(NMAX) !Generated full-length waveform
integer*1 idat(7)
integer*1 decoded(KK),apmask(ND),cw(ND)
integer*1 hbits(412),bits(13)
logical reset
data ib13/1,1,1,1,1,-1,-1,1,1,-1,1,-1,1/
nargs=iargc()
if(nargs.lt.2) then
print*,'Usage: wspr5d [-a <data_dir>] [-f fMHz] 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
open(13,file=trim(data_dir)//'/ALL_WSPR.TXT',status='unknown', &
position='append')
maxn=8 !Default value
twopi=8.0*atan(1.0)
fs=NSPS*12000.0/NSPS0 !Sample rate
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)
do i=1,32 !Half-sine pulse shape
pp(i)=sin(0.5*(i-1)*twopi/(32))
enddo
n8=z'cbf089223a51'
do i=1,48
isync(i)=-1
if(iand(n8,1).eq.1) isync(i)=1
n8=n8/2
enddo
! Define array id() for sync symbols
id=0
do j=1,48 !First group of 48
id(2*j-1)=2*isync(j)
enddo
do j=1,13 !Barker 13 code
id(j+96)=2*ib13(j)
enddo
do j=1,48 !Second group of 48
id(2*j+109)=2*isync(j)
enddo
csync=0.
do j=1,205
if(abs(id(j)).eq.2) then
ia=nint((j-0.5)*N2)
ib=ia+N2-1
csync(ia:ib)=pp*id(j)/abs(id(j))
endif
enddo
do ifile=iarg,nargs
call getarg(ifile,infile)
open(10,file=infile,status='old',access='stream')
j1=index(infile,'.c5')
j2=index(infile,'.wav')
if(j1.gt.0) then
read(10,end=999) fname,ntrmin,fMHz,c400
read(fname(8:11),*) nutc
write(datetime,'(i11)') nutc
else if(j2.gt.0) then
read(10,end=999) ihdr,iwave
read(infile(j2-4:j2-1),*) nutc
datetime=infile(j2-11:j2-1)
call wspr5_downsample(iwave,c400)
else
print*,'Wrong file format?'
go to 999
endif
close(10)
fa=100.0
fb=150.0
fs400=400.0
call getfc1(c400,fs400,fa,fb,fc1,xsnr) !First approx for freq
npeaks=5
call getfc2(c400,npeaks,fs400,fc1,fpks) !Refined freq
! do idf=1,npeaks ! consider the top npeak peaks
do idf=1,1 ! for genie-aided sync
fc1=125.0 ! genie provided
fc2=0.0 ! from the genie
! fc2=fpks(idf)
call downsample(c400,fc1+fc2,cd)
s2=sum(cd*conjg(cd))/(16*412)
cd=cd/sqrt(s2)
do is=0,0 ! dt search range is zeroed for genie-aided sync
idt=is/2
if( mod(is,2).eq. 1 ) idt=-(is+1)/2
xdt=real(22+idt)/22.222 - 1.0
ca=cshift(cd,22+idt)
zzsum=0.0
do iseq=3,4
if(iseq.eq.4) then
k=1-2*3
nseq=9
istep=3*4
else
k=1-2*iseq
nseq=iseq*3
istep=iseq*4
endif
do i=1,408,istep
j=(i+1)*16
if(iseq.eq.4) then
! phase=-1.18596900
! For now, average complex corr. coeffs over the entire frame to
! estimate phase
phase=atan2(imag(zzsum),real(zzsum))
k=k+3*2
call mskcohdet(nseq,ca(j),pp,id(k),softbits,phase)
else
k=k+iseq*2
call mskseqdet(nseq,ca(j),pp,id(k),softbits,1,zz)
zzsum=zzsum+zz
endif
sbits(i+1)=softbits(1)
sbits(i+2)=softbits(2)
if( id(k+1) .ne. 0 ) sbits(i+2)=id(k+1)*25
sbits(i+3)=softbits(3)
if( iseq .ge. 2 ) then
sbits(i+5)=softbits(4)
sbits(i+6)=softbits(5)
if( id(k+3) .ne. 0 ) sbits(i+6)=id(k+3)*25
sbits(i+7)=softbits(6)
if( iseq .ge. 3 ) then
sbits(i+9)=softbits(7)
sbits(i+10)=softbits(8)
if( id(k+5) .ne. 0 ) sbits(i+10)=id(k+5)*25
sbits(i+11)=softbits(9)
endif
endif
enddo
j=1
do i=1,205
if( abs(id(i)) .ne. 2 ) then
rxdata(j)=sbits(2*i-1)
j=j+1
endif
enddo
do i=1,204
rxdata(j)=sbits(2*i)
j=j+1
enddo
rxav=sum(rxdata)/ND
rx2av=sum(rxdata*rxdata)/ND
rxsig=sqrt(rx2av-rxav*rxav)
rxdata=rxdata/rxsig
sigma=1.20
llr=2*rxdata/(sigma*sigma)
apmask=0
max_iterations=40
ifer=0
call bpdecode300(llr,apmask,max_iterations,decoded,niterations,cw)
! niterations will be equal to the Hamming distance between hard received word and the codeword
nhardmin=0
if(niterations.lt.0) call osd300(llr,apmask,5,decoded,cw,nhardmin,dmin)
if(nhardmin.gt.0) niterations=nhardmin
nbadcrc=0
call chkcrc10(decoded,nbadcrc)
if(nbadcrc.ne.0) ifer=1
if( ifer.eq.0 ) then
write(cbits,1200) decoded(1:50)
1200 format(50i1)
read(cbits,1202) idat
1202 format(6b8,b2)
idat(7)=ishft(idat(7),6)
call wqdecode(idat,message,itype)
nsnr=nint(xsnr)
! freq=fMHz + 1.d-6*(fc1+fc2)
freq=fc1+fc2
nfdot=0
write(13,1210) datetime,0,nsnr,xdt,freq,message,nfdot
1210 format(a11,2i4,f6.2,f12.7,2x,a22,i3)
write(*,1212) datetime(8:11),nsnr,xdt,freq,nfdot,message,'*',idf,nseq,is,iseq,niterations
!1212 format(a4,i4,f5.1,f11.6,i3,2x,a22,a1,i3,i3,i3,i4)
1212 format(a4,i4,f8.3,f8.3,i3,2x,a22,a1,i3,i3,i3,i3,i4)
goto 888
endif
enddo !iseq
enddo
enddo
888 continue
enddo
write(*,1120)
1120 format("<DecodeFinished>")
999 end program wspr5d
subroutine getmetric(ib,ps,xmet)
real ps(0:511)
xm1=0
xm0=0
do i=0,511
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 getmetric
subroutine mskseqdet(ns,cdat,pp,bsync,softbits,ncoh,zz)
!
! Detect sequences of 3, 6, or 9 bits (ns).
! Sync bits are assumed to be known.
!
complex cdat(16*12),cbest(16*12),cideal(16*12)
complex cdf(16*12),cfac,zz
real cm(0:511),cmbest(0:511)
real pp(32),softbits(9)
integer bit(13),bestbits(13),sgn(13)
integer bsync(7)
twopi=8.0*atan(1.0)
dt=30.0*18.0/12000.0
cmax=0;
fbest=0.0;
np=2**ns-1
idfmax=40
if( ncoh .eq. 1 ) idfmax=0
do idf=0,idfmax
if( mod(idf,2).eq.0 ) deltaf=idf/2*0.02
if( mod(idf,2).eq.1 ) deltaf=-(idf+1)/2*0.02
dphi=twopi*deltaf*dt
cfac=cmplx(cos(dphi),sin(dphi))
cdf=1.0
do i=2,16*(ns-1)
cdf(i)=cdf(i-1)*cfac
enddo
cm=0
ibflag=0
do i=0,np
bit(1)=(bsync(1)+2)/4
bit(2)=iand(i/(2**(ns-1)),1)
bit(3)=iand(i/(2**(ns-2)),1)
if( bsync(2).ne.0 ) then ! force the barker bits
bit(3)=(bsync(2)+2)/4
endif
bit(4)=iand(i/(2**(ns-3)),1)
bit(5)=(bsync(3)+2)/4
if( ns .ge. 6 ) then
bit(6)=iand(i/(2**(ns-4)),1)
bit(7)=iand(i/(2**(ns-5)),1)
if( bsync(4).ne.0 ) then ! force the barker bits
bit(7)=(bsync(4)+2)/4
endif
bit(8)=iand(i/(2**(ns-6)),1)
bit(9)=(bsync(5)+2)/4
if( ns .eq. 9 ) then
bit(10)=iand(i/4,1)
bit(11)=iand(i/2,1)
if( bsync(6).ne.0 ) then ! force the barker bits
bit(11)=(bsync(6)+2)/4
endif
bit(12)=iand(i/1,1)
bit(13)=(bsync(7)+2)/4
endif
endif
sgn=2*bit-1
cideal(1:16) =cmplx(sgn(1)*pp(17:32),sgn(2)*pp(1:16))
cideal(17:32) =cmplx(sgn(3)*pp(1:16),sgn(2)*pp(17:32))
cideal(33:48) =cmplx(sgn(3)*pp(17:32),sgn(4)*pp(1:16))
cideal(49:64) =cmplx(sgn(5)*pp(1:16),sgn(4)*pp(17:32))
if( ns .ge. 6 ) then
cideal(65:80) =cmplx(sgn(5)*pp(17:32),sgn(6)*pp(1:16))
cideal(81:96) =cmplx(sgn(7)*pp(1:16),sgn(6)*pp(17:32))
cideal(97:112) =cmplx(sgn(7)*pp(17:32),sgn(8)*pp(1:16))
cideal(113:128)=cmplx(sgn(9)*pp(1:16),sgn(8)*pp(17:32))
if( ns .eq. 9 ) then
cideal(129:144) =cmplx(sgn(9)*pp(17:32),sgn(10)*pp(1:16))
cideal(145:160) =cmplx(sgn(11)*pp(1:16),sgn(10)*pp(17:32))
cideal(161:176) =cmplx(sgn(11)*pp(17:32),sgn(12)*pp(1:16))
cideal(177:192)=cmplx(sgn(13)*pp(1:16),sgn(12)*pp(17:32))
endif
endif
cideal=cideal*cdf
cm(i)=abs(sum(cdat(1:64*ns/3)*conjg(cideal(1:64*ns/3))))/1.e3
if( cm(i) .gt. cmax ) then
ibflag=1
cmax=cm(i)
bestbits=bit
cbest=cideal
fbest=deltaf
zz=sum(cdat*conjg(cbest))/1.e3
endif
enddo
if( ibflag .eq. 1 ) then ! new best found
cmbest=cm
endif
enddo
softbits=0.0
call getmetric(1,cmbest,softbits(ns))
call getmetric(2,cmbest,softbits(ns-1))
call getmetric(4,cmbest,softbits(ns-2))
if( ns .ge. 6 ) then
call getmetric(8,cmbest,softbits(ns-3))
call getmetric(16,cmbest,softbits(ns-4))
call getmetric(32,cmbest,softbits(ns-5))
if( ns .eq. 9 ) then
call getmetric(64,cmbest,softbits(3))
call getmetric(128,cmbest,softbits(2))
call getmetric(256,cmbest,softbits(1))
endif
endif
end subroutine mskseqdet
subroutine mskcohdet(ns,cdat,pp,bsync,softbits,phase)
!
! Coherent demodulate blocks of 9 bits (ns).
!
complex cdat(16*12),crot(16*12)
real pp(32),softbits(9)
np=2**ns-1
softbits=0.0
crot=cdat*cmplx(cos(phase),-sin(phase))
softbits(1)=sum(imag(crot(1:32)*pp))
softbits(2)=sum(real(crot(17:48)*pp))
softbits(3)=sum(imag(crot(33:64)*pp))
softbits(4)=sum(imag(crot(65:96)*pp))
softbits(5)=sum(real(crot(81:112)*pp))
softbits(6)=sum(imag(crot(97:128)*pp))
softbits(7)=sum(imag(crot(129:160)*pp))
softbits(8)=sum(real(crot(145:176)*pp))
softbits(9)=sum(imag(crot(161:192)*pp))
softbits=softbits/64.
end subroutine mskcohdet
subroutine downsample(ci,f0,co)
parameter(NI=412*288,NO=NI/18)
complex ci(0:NI-1),ct(0:NI-1)
complex co(0:NO-1)
df=400.0/NI
ct=ci
call four2a(ct,NI,1,-1,1) !c2c FFT to freq domain
i0=nint(f0/df)
co=0.0
co(0)=ct(i0)
! b=3.0 !optimized for sequence detection
b=6.0
do i=1,NO/2
arg=(i*df/b)**2
filt=exp(-arg)
co(i)=ct(i0+i)*filt
co(NO-i)=ct(i0-i)*filt
enddo
co=co/NO
call four2a(co,NO,1,1,1) !c2c FFT back to time domain
return
end subroutine downsample
subroutine getfc1(c,fs,fa,fb,fc1,xsnr)
! include 'wsprlf_params.f90'
parameter (NZ=288*412)
parameter (NSPS=288)
parameter (N2=2*NSPS)
parameter (NFFT1=16*NSPS)
parameter (NH1=NFFT1/2)
complex c(0:NZ-1) !Complex waveform
complex c2(0:NFFT1-1) !Short spectra
real s(-NH1+1:NH1) !Coarse spectrum
nspec=NZ/N2
df1=fs/NFFT1
s=0.
do k=1,nspec
ia=(k-1)*N2
ib=ia+N2-1
c2(0:N2-1)=c(ia:ib)
c2(N2:)=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
! call smo121(s,NFFT1)
smax=0.
ipk=0
fc1=0.
ia=nint(fa/df1)
ib=nint(fb/df1)
do i=ia,ib
f=i*df1
if(s(i).gt.smax) then
smax=s(i)
ipk=i
fc1=f
endif
! write(51,3001) f,s(i),db(s(i))
! 3001 format(f10.3,e12.3,f10.3)
enddo
! The following is for testing SNR calibration:
sp3n=(s(ipk-1)+s(ipk)+s(ipk+1)) !Sig + 3*noise
base=(sum(s)-sp3n)/(NFFT1-3.0) !Noise per bin
psig=sp3n-3*base !Sig only
pnoise=(2500.0/df1)*base !Noise in 2500 Hz
xsnr=db(psig/pnoise)
xsnr=xsnr+5.0
return
end subroutine getfc1
subroutine getfc2(c,npeaks,fs,fc1,fpks)
! include 'wsprlf_params.f90'
parameter (NZ=288*412)
parameter (NSPS=288)
parameter (N2=2*NSPS)
parameter (NFFT1=16*NSPS)
parameter (NH1=NFFT1/2)
complex c(0:NZ-1) !Complex waveform
complex cs(0:NZ-1) !For computing spectrum
real a(5)
real freqs(413),sp2(413),fpks(npeaks)
integer pkloc(1)
df=fs/NZ
baud=fs/NSPS
a(1)=-fc1
a(2:5)=0.
call twkfreq1(c,NZ,fs,a,cs) !Mix down by fc1
! Filter, square, then FFT to get refined carrier frequency fc2.
call four2a(cs,NZ,1,-1,1) !To freq domain
ia=nint(0.75*baud/df)
cs(ia:NZ-1-ia)=0. !Save only freqs around fc1
! do i=1,NZ/2
! filt=1/(1+((i*df)**2/(0.50*baud)**2)**8)
! cs(i)=cs(i)*filt
! cs(NZ+1-i)=cs(NZ+1-i)*filt
! enddo
call four2a(cs,NZ,1,1,1) !Back to time domain
cs=cs/NZ
cs=cs*cs !Square the data
call four2a(cs,NZ,1,-1,1) !Compute squared spectrum
! Find two peaks separated by baud
pmax=0.
fc2=0.
! ja=nint(0.3*baud/df)
ja=nint(0.5*baud/df)
k=1
sp2=0.0
do j=-ja,ja
f2=j*df
ia=nint((f2-0.5*baud)/df)
if(ia.lt.0) ia=ia+NZ
ib=nint((f2+0.5*baud)/df)
p=real(cs(ia))**2 + aimag(cs(ia))**2 + &
real(cs(ib))**2 + aimag(cs(ib))**2
if(p.gt.pmax) then
pmax=p
fc2=0.5*f2
endif
freqs(k)=0.5*f2
sp2(k)=p
k=k+1
! write(52,1200) f2,p,db(p)
!1200 format(f10.3,2f15.3)
enddo
do i=1,npeaks
pkloc=maxloc(sp2)
ipk=pkloc(1)
fpks(i)=freqs(ipk)
ipk0=max(1,ipk-2)
ipk1=min(413,ipk+2)
! ipk0=ipk
! ipk1=ipk
sp2(ipk0:ipk1)=0.0
enddo
return
end subroutine getfc2
@@ -0,0 +1,523 @@
#include "widegraph.h"
#include <algorithm>
#include <QApplication>
#include <QSettings>
#include "ui_widegraph.h"
#include "commons.h"
#include "Configuration.hpp"
#include "MessageBox.hpp"
#include "SettingsGroup.hpp"
#include "moc_widegraph.cpp"
namespace
{
auto user_defined = QObject::tr ("User Defined");
float swide[MAX_SCREENSIZE];
}
WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
QDialog(parent),
ui(new Ui::WideGraph),
m_settings (settings),
m_palettes_path {":/Palettes"},
m_ntr0 {0},
m_n {0},
m_bHaveTransmitted {false}
{
ui->setupUi(this);
setWindowTitle (QApplication::applicationName () + " - " + tr ("Wide Graph"));
setWindowFlags (Qt::WindowCloseButtonHint | Qt::WindowMinimizeButtonHint);
setMaximumWidth (MAX_SCREENSIZE);
setMaximumHeight (880);
ui->widePlot->setCursor(Qt::CrossCursor);
ui->widePlot->setMaximumHeight(800);
ui->widePlot->setCurrent(false);
connect(ui->widePlot, SIGNAL(freezeDecode1(int)),this,
SLOT(wideFreezeDecode(int)));
connect(ui->widePlot, SIGNAL(setFreq1(int,int)),this,
SLOT(setFreq2(int,int)));
{
//Restore user's settings
SettingsGroup g {m_settings, "WideGraph"};
restoreGeometry (m_settings->value ("geometry", saveGeometry ()).toByteArray ());
ui->widePlot->setPlotZero(m_settings->value("PlotZero", 0).toInt());
ui->widePlot->setPlotGain(m_settings->value("PlotGain", 0).toInt());
ui->widePlot->setPlot2dGain(m_settings->value("Plot2dGain", 0).toInt());
ui->widePlot->setPlot2dZero(m_settings->value("Plot2dZero", 0).toInt());
ui->zeroSlider->setValue(ui->widePlot->plotZero());
ui->gainSlider->setValue(ui->widePlot->plotGain());
ui->gain2dSlider->setValue(ui->widePlot->plot2dGain());
ui->zero2dSlider->setValue(ui->widePlot->plot2dZero());
int n = m_settings->value("BinsPerPixel",2).toInt();
m_bFlatten=m_settings->value("Flatten",true).toBool();
m_bRef=m_settings->value("UseRef",false).toBool();
ui->cbFlatten->setChecked(m_bFlatten);
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
ui->cbRef->setChecked(m_bRef);
ui->widePlot->setBreadth(m_settings->value("PlotWidth",1000).toInt());
ui->bppSpinBox->setValue(n);
m_nsmo=m_settings->value("SmoothYellow",1).toInt();
ui->smoSpinBox->setValue(m_nsmo);
m_Percent2DScreen=m_settings->value("Percent2D",30).toInt();
m_waterfallAvg = m_settings->value("WaterfallAvg",5).toInt();
ui->waterfallAvgSpinBox->setValue(m_waterfallAvg);
ui->widePlot->setWaterfallAvg(m_waterfallAvg);
ui->widePlot->setCurrent(m_settings->value("Current",false).toBool());
ui->widePlot->setCumulative(m_settings->value("Cumulative",true).toBool());
ui->widePlot->setLinearAvg(m_settings->value("LinearAvg",false).toBool());
ui->widePlot->setReference(m_settings->value("Reference",false).toBool());
if(ui->widePlot->current()) ui->spec2dComboBox->setCurrentIndex(0);
if(ui->widePlot->cumulative()) ui->spec2dComboBox->setCurrentIndex(1);
if(ui->widePlot->linearAvg()) ui->spec2dComboBox->setCurrentIndex(2);
if(ui->widePlot->Reference()) ui->spec2dComboBox->setCurrentIndex(3);
int nbpp=m_settings->value("BinsPerPixel",2).toInt();
ui->widePlot->setBinsPerPixel(nbpp);
ui->sbPercent2dPlot->setValue(m_Percent2DScreen);
ui->widePlot->setStartFreq(m_settings->value("StartFreq",0).toInt());
ui->fStartSpinBox->setValue(ui->widePlot->startFreq());
m_waterfallPalette=m_settings->value("WaterfallPalette","Default").toString();
m_userPalette = WFPalette {m_settings->value("UserPalette").value<WFPalette::Colours> ()};
m_fMinPerBand = m_settings->value ("FminPerBand").toHash ();
setRxRange ();
ui->controls_widget->setVisible(!m_settings->value("HideControls",false).toBool());
ui->cbControls->setChecked(!m_settings->value("HideControls",false).toBool());
}
int index=0;
for (QString const& file:
m_palettes_path.entryList(QDir::NoDotAndDotDot |
QDir::System | QDir::Hidden |
QDir::AllDirs | QDir::Files,
QDir::DirsFirst)) {
QString t=file.mid(0,file.length()-4);
ui->paletteComboBox->addItem(t);
if(t==m_waterfallPalette) ui->paletteComboBox->setCurrentIndex(index);
index++;
}
ui->paletteComboBox->addItem (user_defined);
if (user_defined == m_waterfallPalette) ui->paletteComboBox->setCurrentIndex(index);
readPalette ();
}
WideGraph::~WideGraph ()
{
}
void WideGraph::closeEvent (QCloseEvent * e)
{
saveSettings ();
QDialog::closeEvent (e);
}
void WideGraph::saveSettings() //saveSettings
{
SettingsGroup g {m_settings, "WideGraph"};
m_settings->setValue ("geometry", saveGeometry ());
m_settings->setValue ("PlotZero", ui->widePlot->plotZero());
m_settings->setValue ("PlotGain", ui->widePlot->plotGain());
m_settings->setValue ("Plot2dGain", ui->widePlot->plot2dGain());
m_settings->setValue ("Plot2dZero", ui->widePlot->plot2dZero());
m_settings->setValue ("PlotWidth", ui->widePlot->plotWidth ());
m_settings->setValue ("BinsPerPixel", ui->bppSpinBox->value ());
m_settings->setValue ("SmoothYellow", ui->smoSpinBox->value ());
m_settings->setValue ("Percent2D",m_Percent2DScreen);
m_settings->setValue ("WaterfallAvg", ui->waterfallAvgSpinBox->value ());
m_settings->setValue ("Current", ui->widePlot->current());
m_settings->setValue ("Cumulative", ui->widePlot->cumulative());
m_settings->setValue ("LinearAvg", ui->widePlot->linearAvg());
m_settings->setValue ("Reference", ui->widePlot->Reference());
m_settings->setValue ("BinsPerPixel", ui->widePlot->binsPerPixel ());
m_settings->setValue ("StartFreq", ui->widePlot->startFreq ());
m_settings->setValue ("WaterfallPalette", m_waterfallPalette);
m_settings->setValue ("UserPalette", QVariant::fromValue (m_userPalette.colours ()));
m_settings->setValue("Flatten",m_bFlatten);
m_settings->setValue("UseRef",m_bRef);
m_settings->setValue ("HideControls", ui->controls_widget->isHidden ());
m_settings->setValue ("FminPerBand", m_fMinPerBand);
}
void WideGraph::drawRed(int ia, int ib)
{
ui->widePlot->drawRed(ia,ib,swide);
}
void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dataSink2
{
static float splot[NSMAX];
int nbpp = ui->widePlot->binsPerPixel();
//Average spectra over specified number, m_waterfallAvg
if (m_n==0) {
for (int i=0; i<NSMAX; i++)
splot[i]=s[i];
} else {
for (int i=0; i<NSMAX; i++)
splot[i] += s[i];
}
m_n++;
if (m_n>=m_waterfallAvg) {
for (int i=0; i<NSMAX; i++)
splot[i] /= m_n; //Normalize the average
m_n=0;
int i=int(ui->widePlot->startFreq()/df3 + 0.5);
int jz=5000.0/(nbpp*df3);
if(jz>MAX_SCREENSIZE) jz=MAX_SCREENSIZE;
m_jz=jz;
for (int j=0; j<jz; j++) {
float ss=0.0;
float smax=0;
for (int k=0; k<nbpp; k++) {
float sp=splot[i++];
ss += sp;
smax=qMax(smax,sp);
}
// swide[j]=nbpp*smax;
swide[j]=nbpp*ss;
}
// Time according to this computer
qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000;
int ntr = (ms/1000) % m_TRperiod;
if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && ntr<m_ntr0)) {
float flagValue=1.0e30;
if(m_bHaveTransmitted) flagValue=2.0e30;
for(int i=0; i<MAX_SCREENSIZE; i++) {
swide[i] = flagValue;
}
for(int i=0; i<NSMAX; i++) {
splot[i] = flagValue;
}
m_bHaveTransmitted=false;
}
m_ntr0=ntr;
ui->widePlot->draw(swide,true,false);
}
}
void WideGraph::on_bppSpinBox_valueChanged(int n) //bpp
{
ui->widePlot->setBinsPerPixel(n);
}
void WideGraph::on_waterfallAvgSpinBox_valueChanged(int n) //Navg
{
m_waterfallAvg = n;
ui->widePlot->setWaterfallAvg(n);
}
void WideGraph::keyPressEvent(QKeyEvent *e) //F11, F12
{
switch(e->key())
{
int n;
case Qt::Key_F11:
n=11;
if(e->modifiers() & Qt::ControlModifier) n+=100;
emit f11f12(n);
break;
case Qt::Key_F12:
n=12;
if(e->modifiers() & Qt::ControlModifier) n+=100;
emit f11f12(n);
break;
default:
QDialog::keyPressEvent (e);
}
}
void WideGraph::setRxFreq(int n) //setRxFreq
{
ui->widePlot->setRxFreq(n);
ui->widePlot->draw(swide,false,false);
}
int WideGraph::rxFreq() //rxFreq
{
return ui->widePlot->rxFreq();
}
int WideGraph::nStartFreq() //nStartFreq
{
return ui->widePlot->startFreq();
}
void WideGraph::wideFreezeDecode(int n) //wideFreezeDecode
{
emit freezeDecode2(n);
}
void WideGraph::setRxRange ()
{
ui->widePlot->setRxRange (Fmin ());
ui->widePlot->DrawOverlay();
ui->widePlot->update();
}
int WideGraph::Fmin() //Fmin
{
return "60m" == m_rxBand ? 0 : m_fMinPerBand.value (m_rxBand, 2500).toUInt ();
}
int WideGraph::Fmax() //Fmax
{
return std::min(5000,ui->widePlot->Fmax());
}
int WideGraph::fSpan()
{
return ui->widePlot->fSpan ();
}
void WideGraph::setPeriod(int ntrperiod, int nsps) //SetPeriod
{
m_TRperiod=ntrperiod;
m_nsps=nsps;
ui->widePlot->setNsps(ntrperiod, nsps);
}
void WideGraph::setTxFreq(int n) //setTxFreq
{
emit setXIT2(n);
ui->widePlot->setTxFreq(n);
}
void WideGraph::setMode(QString mode) //setMode
{
m_mode=mode;
ui->fSplitSpinBox->setEnabled(m_mode=="JT9+JT65");
ui->widePlot->setMode(mode);
ui->widePlot->DrawOverlay();
ui->widePlot->update();
}
void WideGraph::setSubMode(int n) //setSubMode
{
m_nSubMode=n;
ui->widePlot->setSubMode(n);
ui->widePlot->DrawOverlay();
ui->widePlot->update();
}
void WideGraph::setModeTx(QString modeTx) //setModeTx
{
m_modeTx=modeTx;
ui->widePlot->setModeTx(modeTx);
ui->widePlot->DrawOverlay();
ui->widePlot->update();
}
//Current-Cumulative-Yellow
void WideGraph::on_spec2dComboBox_currentIndexChanged(const QString &arg1)
{
ui->widePlot->setCurrent(false);
ui->widePlot->setCumulative(false);
ui->widePlot->setLinearAvg(false);
ui->widePlot->setReference(false);
ui->smoSpinBox->setEnabled(false);
if(arg1=="Current") ui->widePlot->setCurrent(true);
if(arg1=="Cumulative") ui->widePlot->setCumulative(true);
if(arg1=="Linear Avg") {
ui->widePlot->setLinearAvg(true);
ui->smoSpinBox->setEnabled(true);
}
if(arg1=="Reference") {
ui->widePlot->setReference(true);
}
replot();
}
void WideGraph::on_fSplitSpinBox_valueChanged(int n) //fSplit
{
if (m_rxBand != "60m") m_fMinPerBand[m_rxBand] = n;
setRxRange ();
}
void WideGraph::setFreq2(int rxFreq, int txFreq) //setFreq2
{
emit setFreq3(rxFreq,txFreq);
}
void WideGraph::setDialFreq(double d) //setDialFreq
{
ui->widePlot->setDialFreq(d);
}
void WideGraph::setRxBand (QString const& band)
{
m_rxBand = band;
if ("60m" == m_rxBand)
{
ui->fSplitSpinBox->setEnabled (false);
ui->fSplitSpinBox->setValue (0);
}
else
{
ui->fSplitSpinBox->setValue (m_fMinPerBand.value (band, 2500).toUInt ());
ui->fSplitSpinBox->setEnabled (m_mode=="JT9+JT65");
}
ui->widePlot->setRxBand(band);
setRxRange ();
}
void WideGraph::on_fStartSpinBox_valueChanged(int n) //fStart
{
ui->widePlot->setStartFreq(n);
}
void WideGraph::readPalette () //readPalette
{
try
{
if (user_defined == m_waterfallPalette)
{
ui->widePlot->setColours (WFPalette {m_userPalette}.interpolate ());
}
else
{
ui->widePlot->setColours (WFPalette {m_palettes_path.absoluteFilePath (m_waterfallPalette + ".pal")}.interpolate());
}
}
catch (std::exception const& e)
{
MessageBox::warning_message (this, tr ("Read Palette"), e.what ());
}
}
void WideGraph::on_paletteComboBox_activated (QString const& palette) //palette selector
{
m_waterfallPalette = palette;
readPalette();
replot();
}
void WideGraph::on_cbFlatten_toggled(bool b) //Flatten On/Off
{
m_bFlatten=b;
if(m_bRef and m_bFlatten) {
m_bRef=false;
ui->cbRef->setChecked(false);
}
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
}
void WideGraph::on_cbRef_toggled(bool b)
{
m_bRef=b;
if(m_bRef and m_bFlatten) {
m_bFlatten=false;
ui->cbFlatten->setChecked(false);
}
ui->widePlot->setFlatten(m_bFlatten,m_bRef);
}
void WideGraph::on_cbControls_toggled(bool b)
{
ui->controls_widget->setVisible(b);
}
void WideGraph::on_adjust_palette_push_button_clicked (bool) //Adjust Palette
{
try
{
if (m_userPalette.design ())
{
m_waterfallPalette = user_defined;
ui->paletteComboBox->setCurrentText (m_waterfallPalette);
readPalette ();
}
}
catch (std::exception const& e)
{
MessageBox::warning_message (this, tr ("Read Palette"), e.what ());
}
}
bool WideGraph::flatten() //Flatten
{
return m_bFlatten;
}
bool WideGraph::useRef() //Flatten
{
return m_bRef;
}
void WideGraph::replot()
{
if(ui->widePlot->scaleOK()) ui->widePlot->replot();
}
void WideGraph::on_gainSlider_valueChanged(int value) //Gain
{
ui->widePlot->setPlotGain(value);
replot();
}
void WideGraph::on_zeroSlider_valueChanged(int value) //Zero
{
ui->widePlot->setPlotZero(value);
replot();
}
void WideGraph::on_gain2dSlider_valueChanged(int value) //Gain2
{
ui->widePlot->setPlot2dGain(value);
if(ui->widePlot->scaleOK ()) {
ui->widePlot->draw(swide,false,false);
if(m_mode=="QRA64") ui->widePlot->draw(swide,false,true);
}
}
void WideGraph::on_zero2dSlider_valueChanged(int value) //Zero2
{
ui->widePlot->setPlot2dZero(value);
if(ui->widePlot->scaleOK ()) {
ui->widePlot->draw(swide,false,false);
if(m_mode=="QRA64") ui->widePlot->draw(swide,false,true);
}
}
void WideGraph::setTol(int n) //setTol
{
ui->widePlot->setTol(n);
ui->widePlot->DrawOverlay();
ui->widePlot->update();
}
void WideGraph::on_smoSpinBox_valueChanged(int n)
{
m_nsmo=n;
}
int WideGraph::smoothYellow()
{
return m_nsmo;
}
void WideGraph::setWSPRtransmitted()
{
m_bHaveTransmitted=true;
}
void WideGraph::setVHF(bool bVHF)
{
ui->widePlot->setVHF(bVHF);
}
void WideGraph::on_sbPercent2dPlot_valueChanged(int n)
{
m_Percent2DScreen=n;
ui->widePlot->SetPercent2DScreen(n);
}
void WideGraph::setRedFile(QString fRed)
{
ui->widePlot->setRedFile(fRed);
}
@@ -0,0 +1,69 @@
// Status=review
The following controls appear just under the decoded text windows on
the main screen:
//.Main UI
image::main-ui-controls.png[align="center",width=650,alt="Main UI Controls"]
* When *CQ only* is checked, only messages from stations calling CQ will
be displayed in the left text panel.
* *Log QSO* raises a dialog window pre-filled with known information
about a QSO you have nearly completed. You can edit or add to this
information before clicking *OK* to log the QSO. If you check *Prompt
me to log QSO* on the *Settings -> Reporting* tab, the program will
raise the confirmation screen automatically when you send a message
containing +73+. *Start Date* and *Start Time* are set when you click
to send the *Tx 2* or *Tx 3* message, and backed up by one or two
sequence lengths, respectively. (Note that the actual start time may
have been earlier if repeats of early transmissions were required.)
End date and time are set when the *Log QSO* screen is invoked.
//.Log QSO Window
image::log-qso.png[align="center",alt="Log QSO"]
* *Stop* will terminate normal data acquisition in case you want to
freeze the waterfall or open and explore a previously recorded audio
file.
* *Monitor* toggles normal receive operation on or off. This button
is highlighted in green when the _WSJT-X_ is receiving. If you are
using CAT control, toggling *Monitor* OFF relinquishes control of the
rig; if *Monitor returns to last used frequency* is selected on the
*Settings | General* tab, toggling *Monitor* back ON will return to
the original frequency.
* *Erase* clears the right-hand decoded text window.
Double-clicking *Erase* clears both text windows.
TIP: Right-clicking on either text window brings up a context menu
with several options (including *Erase*) which operate on that window
alone.
* *Clear Avg* is present only in modes that support message averaging.
It provides a way to erase the accumulating information, thus
preparing to start a new average.
* *Decode* tells the program to repeat the decoding procedure at the
Rx frequency (green marker on waterfall scale), using the most recently
completed sequence of received data.
* *Enable Tx* toggles automatic T/R sequencing mode on or off and
highlights the button in red when ON. A transmission will start at
the beginning of the selected (odd or even) sequence, or immediately
if appropriate. Toggling the button to OFF during a transmission
allows the current transmission to finish.
* *Halt Tx* terminates a transmission immediately and disables
automatic T/R sequencing.
* *Tune* toggles the program into Tx mode and generates an unmodulated
carrier at the specified Tx frequency (red marker on waterfall scale).
This process is useful for adjusting an antenna tuner or tuning an
amplifier. The button is highlighted in red while *Tune* is active.
Toggle the button a second time or click *Halt Tx* to terminate the
*Tune* process. Note that activating *Tune* interrupts a receive
sequence and will prevent decoding during that sequence.
* Uncheck the box *Menus* to make the top-of-window menus disappear,
leaving more vertical space for decoded messages.
@@ -0,0 +1,320 @@
program jt9
! Decoder for JT9. Can run stand-alone, reading data from *.wav files;
! or as the back end of wsjt-x, with data placed in a shared memory region.
use options
use prog_args
use, intrinsic :: iso_c_binding
use FFTW3
use timer_module, only: timer
use timer_impl, only: init_timer, fini_timer
use readwav
include 'jt9com.f90'
integer(C_INT) iret
type(wav_header) wav
real*4 s(NSMAX)
character c
character(len=500) optarg, infile
character wisfile*80
!### ndepth was defined as 60001. Why???
integer :: arglen,stat,offset,remain,mode=0,flow=200,fsplit=2700, &
fhigh=4000,nrxfreq=1500,ntrperiod=1,ndepth=1,nexp_decode=0
logical :: read_files = .true., tx9 = .false., display_help = .false.
type (option) :: long_options(25) = [ &
option ('help', .false., 'h', 'Display this help message', ''), &
option ('shmem',.true.,'s','Use shared memory for sample data','KEY'), &
option ('tr-period', .true., 'p', 'Tx/Rx period, default MINUTES=1', &
'MINUTES'), &
option ('executable-path', .true., 'e', &
'Location of subordinate executables (KVASD) default PATH="."', &
'PATH'), &
option ('data-path', .true., 'a', &
'Location of writeable data files, default PATH="."', 'PATH'), &
option ('temp-path', .true., 't', &
'Temporary files path, default PATH="."', 'PATH'), &
option ('lowest', .true., 'L', &
'Lowest frequency decoded (JT65), default HERTZ=200', 'HERTZ'), &
option ('highest', .true., 'H', &
'Highest frequency decoded, default HERTZ=4007', 'HERTZ'), &
option ('split', .true., 'S', &
'Lowest JT9 frequency decoded, default HERTZ=2700', 'HERTZ'), &
option ('rx-frequency', .true., 'f', &
'Receive frequency offset, default HERTZ=1500', 'HERTZ'), &
option ('patience', .true., 'w', &
'FFTW3 planing patience (0-4), default PATIENCE=1', 'PATIENCE'), &
option ('fft-threads', .true., 'm', &
'Number of threads to process large FFTs, default THREADS=1', &
'THREADS'), &
option ('jt65', .false., '6', 'JT65 mode', ''), &
option ('jt9', .false., '9', 'JT9 mode', ''), &
option ('ft8', .false., '8', 'FT8 mode', ''), &
option ('jt4', .false., '4', 'JT4 mode', ''), &
option ('qra64', .false., 'q', 'QRA64 mode', ''), &
option ('sub-mode', .true., 'b', 'Sub mode, default SUBMODE=A', 'A'), &
option ('depth', .true., 'd', &
'JT9 decoding depth (1-3), default DEPTH=1', 'DEPTH'), &
option ('tx-jt9', .false., 'T', 'Tx mode is JT9', ''), &
option ('my-call', .true., 'c', 'my callsign', 'CALL'), &
option ('my-grid', .true., 'G', 'my grid locator', 'GRID'), &
option ('his-call', .true., 'x', 'his callsign', 'CALL'), &
option ('his-grid', .true., 'g', 'his grid locator', 'GRID'), &
option ('experience-decode', .true., 'X', &
'experience based decoding flags (1..n), default FLAGS=0', &
'FLAGS') ]
type(dec_data), allocatable :: shared_data
character(len=20) :: datetime=''
character(len=12) :: mycall='K1ABC', hiscall='W9XYZ'
character(len=6) :: mygrid='', hisgrid='EN37'
common/patience/npatience,nthreads
common/decstats/ntry65a,ntry65b,n65a,n65b,num9,numfano
data npatience/1/,nthreads/1/
nsubmode = 0
do
call getopt('hs:e:a:b:r:m:p:d:f:w:t:9864qTL:S:H:c:G:x:g:X:', &
long_options,c,optarg,arglen,stat,offset,remain,.true.)
if (stat .ne. 0) then
exit
end if
select case (c)
case ('h')
display_help = .true.
case ('s')
read_files = .false.
shm_key = optarg(:arglen)
case ('e')
exe_dir = optarg(:arglen)
case ('a')
data_dir = optarg(:arglen)
case ('b')
nsubmode = ichar (optarg(:1)) - ichar ('A')
case ('t')
temp_dir = optarg(:arglen)
case ('m')
read (optarg(:arglen), *) nthreads
case ('p')
read (optarg(:arglen), *) ntrperiod
case ('d')
read (optarg(:arglen), *) ndepth
case ('f')
read (optarg(:arglen), *) nrxfreq
case ('L')
read (optarg(:arglen), *) flow
case ('S')
read (optarg(:arglen), *) fsplit
case ('H')
read (optarg(:arglen), *) fhigh
case ('q')
mode = 164
case ('4')
mode = 4
case ('6')
if (mode.lt.65) mode = mode + 65
case ('9')
if (mode.lt.9.or.mode.eq.65) mode = mode + 9
case ('8')
mode = 8
case ('T')
tx9 = .true.
case ('w')
read (optarg(:arglen), *) npatience
case ('c')
read (optarg(:arglen), *) mycall
case ('G')
read (optarg(:arglen), *) mygrid
case ('x')
read (optarg(:arglen), *) hiscall
case ('g')
read (optarg(:arglen), *) hisgrid
case ('X')
read (optarg(:arglen), *) nexp_decode
end select
end do
if (display_help .or. stat .lt. 0 &
.or. (.not. read_files .and. remain .gt. 0) &
.or. (read_files .and. remain .lt. 1)) then
print *, 'Usage: jt9 [OPTIONS] file1 [file2 ...]'
print *, ' Reads data from *.wav files.'
print *, ''
print *, ' jt9 -s <key> [-w patience] [-m threads] [-e path] [-a path] [-t path]'
print *, ' Gets data from shared memory region with key==<key>'
print *, ''
print *, 'OPTIONS:'
print *, ''
do i = 1, size (long_options)
call long_options(i) % print (6)
end do
go to 999
endif
iret=fftwf_init_threads() !Initialize FFTW threading
! Default to 1 thread, but use nthreads for the big ones
call fftwf_plan_with_nthreads(1)
! Import FFTW wisdom, if available
wisfile=trim(data_dir)//'/jt9_wisdom.dat'// C_NULL_CHAR
iret=fftwf_import_wisdom_from_filename(wisfile)
ntry65a=0
ntry65b=0
n65a=0
n65b=0
num9=0
numfano=0
if (.not. read_files) then
call jt9a() !We're running under control of WSJT-X
go to 999
endif
allocate(shared_data)
nflatten=0
do iarg = offset + 1, offset + remain
call get_command_argument (iarg, optarg, arglen)
infile = optarg(:arglen)
call wav%read (infile)
nfsample=wav%audio_format%sample_rate
i1=index(infile,'.wav')
if(i1.lt.1) i1=index(infile,'.WAV')
if(infile(i1-5:i1-5).eq.'_') then
read(infile(i1-4:i1-1),*,err=1) nutc
else
read(infile(i1-6:i1-1),*,err=1) nutc
endif
go to 2
1 nutc=0
2 nsps=0
if(ntrperiod.eq.1) then
nsps=6912
shared_data%params%nzhsym=181
else if(ntrperiod.eq.2) then
nsps=15360
shared_data%params%nzhsym=178
else if(ntrperiod.eq.5) then
nsps=40960
shared_data%params%nzhsym=172
else if(ntrperiod.eq.10) then
nsps=82944
shared_data%params%nzhsym=171
else if(ntrperiod.eq.30) then
nsps=252000
shared_data%params%nzhsym=167
endif
if(nsps.eq.0) stop 'Error: bad TRperiod'
kstep=nsps/2
k=0
nhsym0=-999
npts=(60*ntrperiod-6)*12000
if(iarg .eq. offset + 1) then
call init_timer (trim(data_dir)//'/timer.out')
call timer('jt9 ',0)
endif
shared_data%id2=0 !??? Why is this necessary ???
do iblk=1,npts/kstep
k=iblk*kstep
if(mode.eq.8 .and. k.gt.179712) exit
call timer('read_wav',0)
read(unit=wav%lun,end=3) shared_data%id2(k-kstep+1:k)
go to 4
3 call timer('read_wav',1)
print*,'EOF on input file ',infile
exit
4 call timer('read_wav',1)
nhsym=(k-2048)/kstep
if(nhsym.ge.1 .and. nhsym.ne.nhsym0) then
if(mode.eq.9 .or. mode.eq.74) then
! Compute rough symbol spectra for the JT9 decoder
ingain=0
call timer('symspec ',0)
nminw=1
call symspec(shared_data,k,ntrperiod,nsps,ingain,nminw,pxdb, &
s,df3,ihsym,npts8,pxdbmax)
call timer('symspec ',1)
endif
nhsym0=nhsym
if(nhsym.ge.181) exit
endif
enddo
close(unit=wav%lun)
shared_data%params%nutc=nutc
shared_data%params%ndiskdat=.true.
shared_data%params%ntr=60
shared_data%params%nfqso=nrxfreq
shared_data%params%newdat=.true.
shared_data%params%npts8=74736
shared_data%params%nfa=flow
shared_data%params%nfsplit=fsplit
shared_data%params%nfb=fhigh
shared_data%params%ntol=20
shared_data%params%kin=64800
shared_data%params%nzhsym=181
shared_data%params%ndepth=ndepth
shared_data%params%lft8apon=.true.
shared_data%params%ljt65apon=.true.
shared_data%params%napwid=75
shared_data%params%dttol=3.
! shared_data%params%minsync=0 !### TEST ONLY
! shared_data%params%nfqso=1500 !### TEST ONLY
! mycall="G3WDG " !### TEST ONLY
! hiscall="VK7MO " !### TEST ONLY
! hisgrid="QE37 " !### TEST ONLY
if(mode.eq.164 .and. nsubmode.lt.100) nsubmode=nsubmode+100
shared_data%params%naggressive=0
shared_data%params%n2pass=2
! shared_data%params%nranera=8 !### ntrials=10000
shared_data%params%nranera=6 !### ntrials=3000
shared_data%params%nrobust=.false.
shared_data%params%nexp_decode=nexp_decode
shared_data%params%mycall=transfer(mycall,shared_data%params%mycall)
shared_data%params%mygrid=transfer(mygrid,shared_data%params%mygrid)
shared_data%params%hiscall=transfer(hiscall,shared_data%params%hiscall)
shared_data%params%hisgrid=transfer(hisgrid,shared_data%params%hisgrid)
if (tx9) then
shared_data%params%ntxmode=9
else
shared_data%params%ntxmode=65
end if
if (mode.eq.0) then
shared_data%params%nmode=65+9
else
shared_data%params%nmode=mode
end if
shared_data%params%nsubmode=nsubmode
datetime="2013-Apr-16 15:13" !### Temp
shared_data%params%datetime=transfer(datetime,shared_data%params%datetime)
if(mode.eq.9 .and. fsplit.ne.2700) shared_data%params%nfa=fsplit
call multimode_decoder(shared_data%ss,shared_data%id2,shared_data%params,nfsample)
enddo
call timer('jt9 ',1)
call timer('jt9 ',101)
999 continue
! Output decoder statistics
call fini_timer ()
! open (unit=12, file=trim(data_dir)//'/timer.out', status='unknown', position='append')
! write(12,1100) n65a,ntry65a,n65b,ntry65b,numfano,num9
!1100 format(58('-')/' JT65_1 Tries_1 JT65_2 Tries_2 JT9 Tries'/ &
! 58('-')/6i8)
! Save wisdom and free memory
iret=fftwf_export_wisdom_to_filename(wisfile)
call four2a(a,-1,1,1,1)
call filbig(a,-1,1,0.0,0,0,0,0,0) !used for FFT plans
call fftwf_cleanup_threads()
call fftwf_cleanup()
end program jt9