Code cleanup. Implement use of fQSO, ntol, etc.

git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@2671 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
Joe Taylor 2012-10-19 19:26:07 +00:00
parent ed2cd7b155
commit b10df1efdc
12 changed files with 58 additions and 44 deletions

View File

@ -12,10 +12,10 @@ extern struct {
int nutc; //UTC as integer, HHMM
int ndiskdat; //1 ==> data read from *.wav file
int ntrperiod; //TR period (seconds)
int mousefqso; //User-selected QSO freq (kHz)
int nfqso; //User-selected QSO freq (kHz)
int nagain; //1 ==> decode only at fQSO +/- Tol
int newdat; //1 ==> new data, must do long FFT
int nfa; //Low decode limit (kHz)
int npts8; //npts for c0() array
int nfb; //High decode limit (kHz)
int ntol; //+/- decoding range around fQSO (Hz)
int kin;

18
jt9.txt
View File

@ -1,7 +1,7 @@
JT9 is a mode designed for amateur QSOs at MF and LF. The mode uses
the same 72-bit structured messages as JT65. Error control coding
(ECC) uses a convolutional code with constraint length K=32, rate
r=1/2, and a zero tail, leading to an encoded message length of
(ECC) uses a strong convolutional code with constraint length K=32,
rate r=1/2, and a zero tail, leading to an encoded message length of
(72+31)*2 = 206 information-carrying bits. Modulation is 9-FSK: 8
tones for data, one for synchronization. Sixteen symbol intervals are
used for synchronization, so a transmission requires a total of 207/3
@ -10,12 +10,14 @@ used for synchronization, so a transmission requires a total of 207/3
Exact symbol lengths are chosen so that nsps, the number of samples
per symbol (at 12000 samples per second) is a number with no prime
factor greater than 7. This choice makes for efficient FFTs. Tone
spacing of the 9-FSK modulation is df=1/tsym=12000/nsps, equal to
the keying rate. The total occupied bandwidth is 9*df.
spacing of the 9-FSK modulation is df=1/tsym=12000/nsps, equal to the
keying rate. The total occupied bandwidth is 9*df. The generated
signal has continuous phase, and there are no key clicks.
Parameters of five JT9 sub-modes are summarized in the following
table, along with S/N thresholds measured by simulation on an AWGN
channel.
channel. Numbers following "JT9-" in the sub-mode names specify the
T/R period in minutes.
--------------------------------------------------------------------------
Mode nsps nsps2 df tsym BW S/N* Tdec Tfree Factors
@ -46,12 +48,12 @@ Receiving
2. Filter to 1000 Hz bandwidth and downsample (1/8) to 1500 Hz, saving
complex data to array c0(2,700,000).
3. Compute spectra at half-symbol steps. Use for waterfall display
s(22000) and save in ss(184,22000) and
savg(22000), for detecting sync vectors.
s(22000) and save in ss(184,22000) and savg(22000) for detecting
sync vectors.
4. At time Tdec, find sync vectors in ss(); get approx DF or list of DFs
5. Do full-length FFT, NFFT1=96*nsps2, zero-padded as required.
6. For each candidate signal, do inverse FFT of length 1536 (or 3072?).
This yields 16 complex samples per symbol, and sync tone should be
This yields 16 complex samples per symbol; sync tone should be
close to zero frequency.
7. Use afc65b method to get improved values of DF, DT.
8. Tweak freq and time offset to 0.

View File

@ -14,7 +14,7 @@ subroutine decoder(ntrSeconds,c0)
integer*2 id2
complex c0(NDMAX)
common/jt9com/ss(184,NSMAX),savg(NSMAX),id2(NMAX),nutc,ndiskdat, &
ntr,mousefqso,nagain,newdat,nfa,nfb,ntol,kin
ntr,nfqso,nagain,newdat,npts8,nfb,ntol,kin
ntrMinutes=ntrSeconds/60
newdat=1
@ -35,24 +35,22 @@ subroutine decoder(ntrSeconds,c0)
! Now do the decoding
nutc=0
kstep=nsps/2
tstep=kstep/12000.0
ntol=500
nfqso=1500
! Get sync, approx freq
call sync9(ss,tstep,df3,ntol,nfqso,sync,fpk,red)
npts8=170880 !### TEST ONLY ###
print*,'A',nfqso,ntol,fpk
call spec9(c0,npts8,nsps,fpk,xdt,i1SoftSymbols)
call decode9(i1SoftSymbols,msg)
open(73,file='decoded.txt',status='unknown')
rewind 73
open(13,file='decoded.txt',status='unknown')
rewind 13
! write(*,1010) nutc,sync,xdt,1000.0+fpk,msg
write(73,1010) nutc,sync,xdt,1000.0+fpk,msg
write(13,1010) nutc,sync,xdt,1000.0+fpk,msg
1010 format(i4.4,3f7.1,2x,a22)
call flush(73)
close(73)
call flush(13)
close(13)
return
end subroutine decoder

View File

@ -2,6 +2,7 @@ subroutine spec9(c0,npts8,nsps,fpk,xdt,i1SoftSymbols)
parameter (MAXFFT=31500)
complex c0(0:npts8-1)
complex c1(0:2700000)
real ssym(0:7,69)
complex c(0:MAXFFT-1)
integer*1 i1SoftSymbolsScrambled(207)
@ -27,17 +28,17 @@ subroutine spec9(c0,npts8,nsps,fpk,xdt,i1SoftSymbols)
phi=phi+dphi
if(phi.gt.twopi) phi=phi-twopi
if(phi.lt.-twopi) phi=phi+twopi
c0(i)=cmplx(aimag(c0(i)),real(c0(i)))*cmplx(cos(phi),sin(phi))
c1(i)=cmplx(aimag(c0(i)),real(c0(i)))*cmplx(cos(phi),sin(phi))
enddo
nsps8=nsps/8
foffset=fpk
istart=1520
call peakdf9(c0,npts8,nsps8,istart,foffset,idf)
call peakdf9(c1,npts8,nsps8,istart,foffset,idf)
fpk=fpk + idf*0.1*1500.0/nsps8
foffset=foffset + idf*0.1*1500.0/nsps8
call peakdt9(c0,npts8,nsps8,istart,foffset,idt)
call peakdt9(c1,npts8,nsps8,istart,foffset,idt)
istart=istart + 0.0625*nsps8*idt
xdt=istart/1500.0 - 1.0
! write(*,3002) 0.0625*nsps8*idt/1500.0,idf*0.1*1500.0/nsps8
@ -57,7 +58,7 @@ subroutine spec9(c0,npts8,nsps,fpk,xdt,i1SoftSymbols)
k=k+1
ia=(j-1)*nsps8 + istart
ib=ia+nsps8-1
c(0:nfft-1)=c0(ia:ib)
c(0:nfft-1)=c1(ia:ib)
phi=0.
do i=0,nfft-1

View File

@ -37,7 +37,7 @@ subroutine symspec(k,ntrperiod,nsps,nb,nbslider,pxdb,s,red, &
data rms/999.0/,k0/99999999/,ntrperiod0/0/,nfft3z/0/
save
if(ntrperiod.eq.1) nfft3=1024
if(ntrperiod.eq.1) nfft3=2048
if(ntrperiod.eq.2) nfft3=2048
if(ntrperiod.eq.5) nfft3=6144
if(ntrperiod.eq.10) nfft3=12288

View File

@ -373,9 +373,9 @@ void MainWindow::dataSink(int k)
ntr0=ntr;
n=0;
}
if(ihsym == m_hsymStop) {
jt9com_.newdat=1;
jt9com_.nagain=0;
// This is a bit strange. Why do we need the "-3" ??
if(ihsym == m_hsymStop-3) {
jt9com_.npts8=(ihsym*m_nsps)/16;
QDateTime t = QDateTime::currentDateTimeUtc();
m_dateTime=t.toString("yyyy-MMM-dd hh:mm");
decode(); //Start the decoder
@ -509,19 +509,17 @@ void MainWindow::keyPressEvent( QKeyEvent *e ) //keyPressEvent
case Qt::Key_F11:
if(e->modifiers() & Qt::ShiftModifier) {
} else {
int n0=g_pWideGraph->DF();
int n=(n0 + 10000) % 5;
if(n==0) n=5;
g_pWideGraph->setDF(n0-n);
int n=g_pWideGraph->QSOfreq();
n--;
g_pWideGraph->setQSOfreq(n);
}
break;
case Qt::Key_F12:
if(e->modifiers() & Qt::ShiftModifier) {
} else {
int n0=g_pWideGraph->DF();
int n=(n0 + 10000) % 5;
if(n==0) n=5;
g_pWideGraph->setDF(n0+n);
int n=g_pWideGraph->QSOfreq();
n++;
g_pWideGraph->setQSOfreq(n);
}
break;
case Qt::Key_G:
@ -726,10 +724,12 @@ void MainWindow::on_actionDecode_remaining_files_in_directory_triggered()
void MainWindow::diskDat() //diskDat()
{
int k;
int kstep=m_nsps/2;
m_diskData=true;
for(int n=1; n<=m_hsymStop; n++) { // Do the half-symbol FFTs
int k=(n+1)*kstep;
k=(n+1)*kstep;
jt9com_.npts8=k/8;
dataSink(k);
if(n%10 == 1 or n == m_hsymStop) qApp->processEvents(); //Keep GUI responsive
}
@ -831,12 +831,16 @@ void MainWindow::on_DecodeButton_clicked() //Decode request
void MainWindow::freezeDecode(int n) //freezeDecode()
{
decode();
}
void MainWindow::decode() //decode()
{
m_len1=80;
jt9com_.newdat=1;
jt9com_.nagain=0;
jt9com_.nfqso=g_pWideGraph->QSOfreq();
m_tol=g_pWideGraph->Tol();
jt9com_.ntol=m_tol;
*future3 = QtConcurrent::run(decoder_, &m_TRperiod, &c0[0]);
watcher3->setFuture(*future3);
}

View File

@ -136,6 +136,7 @@ private:
qint32 m_nsps;
qint32 m_hsymStop;
qint32 m_len1;
qint32 m_fQSO;
bool m_monitoring;
bool m_transmitting;

View File

@ -66,7 +66,7 @@
</size>
</property>
<property name="title">
<string> UTC T dB DF</string>
<string> UTC T dB Freq</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>

View File

@ -27,7 +27,7 @@ CPlotter::CPlotter(QWidget *parent) : //CPlotter Constructor
m_ScalePixmap = QPixmap(0,0);
m_OverlayPixmap = QPixmap(0,0);
m_Size = QSize(0,0);
m_fQSO = 1050;
m_fQSO = 1020;
m_line = 0;
m_fSample = 12000;
m_nsps=6912;
@ -296,7 +296,7 @@ void CPlotter::DrawOverlay() //DrawOverlay()
}
}
QPen pen0(Qt::green, 3); //Mark Cal Freq with green tick
QPen pen0(Qt::green, 3); //Mark QSO Freq with green tick
painter0.setPen(pen0);
x = m_xClick;
painter0.drawLine(x,15,x,30);
@ -407,6 +407,7 @@ void CPlotter::setFQSO(int x, bool bf) //setFQSO()
{
if(bf) {
m_fQSO=x; // x is freq in kHz
m_xClick=XfromFreq(m_fQSO);
} else {
if(x<0) x=0; // x is pixel number
if(x>m_Size.width()) x=m_Size.width();
@ -564,7 +565,7 @@ double CPlotter::fGreen()
void CPlotter::setNsps(int n) //setNSpan()
{
m_nsps=n;
m_fftBinWidth=1500.0/1024.0;
m_fftBinWidth=1500.0/2048.0;
if(m_nsps==15360) m_fftBinWidth=1500.0/2048.0;
if(m_nsps==40960) m_fftBinWidth=1500.0/6144.0;
if(m_nsps==82944) m_fftBinWidth=1500.0/12288.0;

View File

@ -16,7 +16,7 @@ extern struct {
int mousefqso; //User-selected QSO freq (kHz)
int nagain; //1 ==> decode only at fQSO +/- Tol
int newdat; //1 ==> new data, must do long FFT
int nfa; //Low decode limit (kHz)
int npts8; //npts in c0() array
int nfb; //High decode limit (kHz)
int ntol; //+/- decoding range around fQSO (Hz)
int kin;

View File

@ -183,6 +183,12 @@ void WideGraph::keyPressEvent(QKeyEvent *e)
}
}
void WideGraph::setQSOfreq(int n)
{
m_qsoFreq=n;
ui->widePlot->setFQSO(m_qsoFreq,true);
}
int WideGraph::QSOfreq()
{
return ui->widePlot->fQSO();

View File

@ -18,6 +18,7 @@ public:
void dataSink2(float s[], float red[], float df3, int ihsym,
int ndiskdata, uchar lstrong[]);
void setQSOfreq(int n);
int QSOfreq();
int nSpan();
int nStartFreq();