diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index 7dd9e2c85..725aacad8 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -70,6 +70,8 @@ set (UG_IMGS images/freemsg.png images/help-menu.png images/JT4F.png + images/JT65B.png + images/QRA64.png images/jtalert.png images/keyboard-shortcuts.png images/log-qso.png diff --git a/doc/user_guide/en/images/JT65B.png b/doc/user_guide/en/images/JT65B.png new file mode 100644 index 000000000..b63ad6c9c Binary files /dev/null and b/doc/user_guide/en/images/JT65B.png differ diff --git a/doc/user_guide/en/images/QRA64.png b/doc/user_guide/en/images/QRA64.png new file mode 100644 index 000000000..88d696b50 Binary files /dev/null and b/doc/user_guide/en/images/QRA64.png differ diff --git a/doc/user_guide/en/vhf-features.adoc b/doc/user_guide/en/vhf-features.adoc index 7d332a41d..cb8a48a27 100644 --- a/doc/user_guide/en/vhf-features.adoc +++ b/doc/user_guide/en/vhf-features.adoc @@ -125,27 +125,47 @@ image::JT4F.png[align="center",alt="JT4F"] === JT65 -In most ways JT65 operation on VHF and higher bands is similar to HF -usage. However, a few differences should be noted. Typical VHF/UHF -operation involves only a single signal in the receiver passband, or -perhaps a few, rather than many. Normally it's best to check *Single -decode* on the *Settings -> General* tab and uncheck *Two pass -decoding* on the *Advanced* tab. In this mode the JT65 decoder will -respond to special message formats sometimes used for EME, including -the OOO signal report and shorthand messages for RO, RRR, and 73. -Those messages will be automatically generated if you check the -shorthand message box *Sh*. +In many ways JT65 operation on VHF and higher bands is similar to HF +usage, but a few important differences should be noted. Typical +VHF/UHF operation involves only a single signal (or perhaps two or +three) in the receiver passband. You may find it best to check +*Single decode* on the *Settings -> General* tab. There will be +little need for *Two pass decoding* on the *Advanced* tab. With VHF +features enabled the JT65 decoder will respond to special message +formats often used for EME: the OOO signal report and two-tone +shorthand messages for RO, RRR, and 73. These messages are always +enabled for reception; they will be automatically generated for +transmission if you check the shorthand message box *Sh*. -As for JT4, you should check *Deep* on *the *Decode* menu, and -optionally *Enable averaging* and *Deep search*. +Be sure to check *Deep* on *the *Decode* menu; you may optionally +include *Enable averaging* and *Deep search*. +The following screen shot shows three transmissions from a 144 MHz EME +QSO using submode JT65B and shorthand messages. Take note of the +colored tick marks on the Wide Graph frequency scale. The green +marker at 1220 Hz indicates the selected QSO frequency (the frequency +of the JT65 Sync tone) and the *F Tol* range. A green tick at 1575 Hz +marks the frequency of the highest JT65 data tone. Orange markers +indicate the frequency of the upper tone of the two-tone signals for +RO, RRR, and 73. + +image::JT65B.png[align="center",alt="JT65B"] === QRA64 -QRA64 is an experimental mode in the present alpha release of -_WSJT-X_, Version 1.7. The protocol is still subject to change, and -some features of the decoder will likely change. In most ways -operation of QRA64 is similar to JT65. +QRA64 is an experimental mode in the Version 1.7 alpha release of +_WSJT-X_. Some details of the protocol are still subject to change, +and some features of the decoder will almost surely change. In most +ways you will find operation of QRA64 similar to JT65. The following +screen shot shows examples of QRA64A transmissions recorded over the +EME path at 144 MHz (G4SWX transmitting to K1JT) and 10 GHz (VK7MO +transmitting to G3WDG). Notice the small red curve plotted below +frequency 1000 Hz in the Wide Graph. Even though the VK7MO signal is +scarcely visible in the waterfall, the red curve shows that the +decoder has accurately and reliably detected its synchronizing +symbols. + +image::QRA64.png[align="center",alt="QRA64"] === ISCAT diff --git a/lib/decode65a.f90 b/lib/decode65a.f90 index 916cce572..5ad316771 100644 --- a/lib/decode65a.f90 +++ b/lib/decode65a.f90 @@ -1,6 +1,6 @@ subroutine decode65a(dd,npts,newdat,nqd,f0,nflip,mode65,ntrials, & naggressive,ndepth,ntol,mycall,hiscall,hisgrid,nexp_decode, & - single_decode,sync2,a,dt,nft,nspecial,qual,nhist,nsmo,decoded) + bVHF,sync2,a,dt,nft,nspecial,qual,nhist,nsmo,decoded) ! Apply AFC corrections to a candidate JT65 signal, then decode it. @@ -15,7 +15,7 @@ subroutine decode65a(dd,npts,newdat,nqd,f0,nflip,mode65,ntrials, & complex c5a(512) real s2(66,126) real a(5) - logical single_decode,first + logical bVHF,first character decoded*22,decoded_best*22 character mycall*12,hiscall*12,hisgrid*6 character*27 cr @@ -30,7 +30,7 @@ subroutine decode65a(dd,npts,newdat,nqd,f0,nflip,mode65,ntrials, & ! NB: cx has sample rate 12000*77125/672000 = 1378.125 Hz ! Check for a shorthand message - if(single_decode .and. mode65.ne.101) then + if(bVHF .and. mode65.ne.101) then call sh65(cx,n5,mode65,ntol,xdf,nspecial,sync2) if(nspecial.gt.0) then a=0. diff --git a/lib/decoder.f90 b/lib/decoder.f90 index d8fc5d319..8cd5067c6 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -261,7 +261,7 @@ contains 1011 format(i4.4,i4,i5,f6.2,f8.0,i4,3x,a22,' QRA64',i3) go to 100 endif - + if(ft.eq.0 .and. minsync.ge.0 .and. int(sync).lt.minsync) then write(*,1010) params%nutc,snr,dt,freq else @@ -281,7 +281,7 @@ contains endif csync='# ' i=0 - if(single_decode .and. nflip.ne.0 .and. & + if(bVHF .and. nflip.ne.0 .and. & sync.ge.max(0.0,float(minsync))) then csync='#*' if(nflip.eq.-1) then diff --git a/lib/jt65_decode.f90 b/lib/jt65_decode.f90 index 221eb0d9a..8067183d6 100644 --- a/lib/jt65_decode.f90 +++ b/lib/jt65_decode.f90 @@ -75,7 +75,7 @@ contains character*22 decoded end type accepted_decode type(accepted_decode) dec(50) - logical :: first_time,robust,prtavg,single_decode + logical :: first_time,prtavg,single_decode,bVHF integer h0(0:11),d0(0:11) real r0(0:11) @@ -93,7 +93,6 @@ contains this%callback => callback first_time=newdat - robust=nrobust dd=dd0 ndecoded=0 @@ -134,13 +133,16 @@ contains nfa=nf1 nfb=nf2 single_decode=iand(nexp_decode,32).ne.0 - if(single_decode .or. (naggressive.gt.0 .and. ntol.lt.1000)) then + bVHF=iand(nexp_decode,64).ne.0 + +!### Q: should either of the next two uses of "single_decode" be "bVHF" instead? + if(single_decode .or. (bVHF .and. ntol.lt.1000)) then nfa=max(200,nfqso-ntol) nfb=min(4000,nfqso+ntol) thresh0=1.0 endif df=12000.0/8192.0 !df = 1.465 Hz - if(single_decode) then + if(bVHF) then ia=max(1,nint(nfa/df)-ntol) ib=min(NSZ,nint(nfb/df)+ntol) nz=ib-ia+1 @@ -151,30 +153,16 @@ contains width=a(4)*df endif -! robust = .false.: use float ccf. Only if ncand>50 fall back to robust (1-bit) ccf -! robust = .true. : use only robust (1-bit) ccf ncand=0 - if(.not.robust) then - call timer('sync65 ',0) - call sync65(ss,nfa,nfb,naggressive,ntol,nhsym,ca,ncand,0, & - single_decode) - - call timer('sync65 ',1) - endif - if(ncand.gt.50) robust=.true. - if(robust) then - ncand=0 - call timer('sync65 ',0) - call sync65(ss,nfa,nfb,naggressive,ntol,nhsym,ca,ncand,1, & - single_decode) - call timer('sync65 ',1) - endif + call timer('sync65 ',0) + call sync65(ss,nfa,nfb,naggressive,ntol,nhsym,ca,ncand,0,bVHF) + call timer('sync65 ',1) ! If a candidate was found within +/- ntol of nfqso, move it into ca(1). call fqso_first(nfqso,ntol,ca,ncand) if(single_decode) then - ncand=1 - if(abs(ca(1)%freq - f0).gt.width) width=2*df + if(ncand.eq.0) ncand=1 + if(abs(ca(1)%freq - f0).gt.width) width=2*df !### ??? ### endif nvec=ntrials if(ncand.gt.75) then @@ -194,19 +182,19 @@ contains nsave=0 endif - if(single_decode) then + if(bVHF) then ! Be sure to search for shorthand message at nfqso +/- ntol - ncand=2 - ca(2)%sync=5.0 - ca(2)%dt=2.5 - ca(2)%freq=nfqso + if(ncand.lt.300) ncand=ncand+1 + ca(ncand)%sync=5.0 + ca(ncand)%dt=2.5 + ca(ncand)%freq=nfqso endif do icand=1,ncand sync1=ca(icand)%sync dtx=ca(icand)%dt freq=ca(icand)%freq - if(single_decode) then + if(bVHF) then flip=ca(icand)%flip nflip=flip endif @@ -215,9 +203,10 @@ contains if(ipass.eq.2) ntry65b=ntry65b + 1 call timer('decod65a',0) nft=0 + nspecial=0 call decode65a(dd,npts,first_time,nqd,freq,nflip,mode65,nvec, & naggressive,ndepth,ntol,mycall,hiscall,hisgrid, & - nexp_decode,single_decode,sync2,a,dtx,nft,nspecial,qual, & + nexp_decode,bVHF,sync2,a,dtx,nft,nspecial,qual, & nhist,nsmo,decoded) if(nspecial.eq.2) decoded='RO' if(nspecial.eq.3) decoded='RRR' @@ -234,7 +223,7 @@ contains nfreq=nint(freq+a(1)) ndrift=nint(2.0*a(2)) - if(single_decode) then + if(bVHF) then s2db=sync1 - 30.0 + db(width/3.3) !### VHF/UHF/microwave if(nspecial.gt.0) s2db=sync2 else @@ -282,7 +271,8 @@ contains if(rtt.gt.r0(n)) cycle endif -5 if(decoded.eq.decoded0 .and. abs(freq-freq0).lt. 3.0 .and. & +5 continue + if(decoded.eq.decoded0 .and. abs(freq-freq0).lt. 3.0 .and. & minsync.ge.0) cycle !Don't display dupes if(decoded.ne.' ' .or. minsync.lt.0) then if(nsubtract.eq.1) then @@ -298,9 +288,7 @@ contains exit endif enddo - -! if(ndupe.ne.1 .or. minsync.lt.0) then - if(ndupe.ne.1) then + if(ndupe.ne.1 .and. sync1.ge.float(minsync)) then if(ipass.eq.1) n65a=n65a + 1 if(ipass.eq.2) n65b=n65b + 1 if(ndecoded.lt.50) ndecoded=ndecoded+1 @@ -493,8 +481,6 @@ contains nftt=nfttbest endif 900 continue -! write(*,3301) 'Z',nftt,nsave,nsum,nsmo,qave,avemsg -!3301 format(a1,4i3,f7.1,1x,a22) return end subroutine avg65 diff --git a/lib/sync65.f90 b/lib/sync65.f90 index 786a80312..794d5593f 100644 --- a/lib/sync65.f90 +++ b/lib/sync65.f90 @@ -1,11 +1,11 @@ subroutine sync65(ss,nfa,nfb,naggressive,ntol,nhsym,ca,ncand,nrobust, & - single_decode) + bVHF) parameter (NSZ=3413,NFFT=8192,MAXCAND=300) real ss(322,NSZ) real ccfblue(-11:540) !CCF with pseudorandom sequence real ccfred(NSZ) !Peak of ccfblue, as function of freq - logical single_decode + logical bVHF type candidate real freq @@ -35,7 +35,7 @@ subroutine sync65(ss,nfa,nfb,naggressive,ntol,nhsym,ca,ncand,nrobust, & do i=ia,ib call xcor(ss,i,nhsym,nsym,lag1,lag2,ccfblue,ccf0,lagpk0,flip,fdot,nrobust) ! Remove best-fit slope from ccfblue and normalize so baseline rms=1.0 - if(.not.single_decode) call slope(ccfblue(lag1),lag2-lag1+1, & + if(.not.bVHF) call slope(ccfblue(lag1),lag2-lag1+1, & lagpk0-lag1+1.0) ccfred(i)=ccfblue(lagpk0) if(ccfred(i).gt.ccfmax) then @@ -66,7 +66,7 @@ subroutine sync65(ss,nfa,nfb,naggressive,ntol,nhsym,ca,ncand,nrobust, & if(itry.ne.0) then call xcor(ss,i,nhsym,nsym,lag1,lag2,ccfblue,ccf0,lagpk,flip,fdot, & nrobust) - if(.not.single_decode) call slope(ccfblue(lag1),lag2-lag1+1, & + if(.not.bVHF) call slope(ccfblue(lag1),lag2-lag1+1, & lagpk-lag1+1.0) xlag=lagpk if(lagpk.gt.lag1 .and. lagpk.lt.lag2) then @@ -79,7 +79,7 @@ subroutine sync65(ss,nfa,nfb,naggressive,ntol,nhsym,ca,ncand,nrobust, & ca(ncand)%freq=freq ca(ncand)%dt=dtx ca(ncand)%flip=flip - if(single_decode) then + if(bVHF) then ca(ncand)%sync=db(ccfred(i)) - 16.0 else ca(ncand)%sync=ccfred(i) diff --git a/mainwindow.cpp b/mainwindow.cpp index bc5cfbfd0..75a65f27d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -2171,7 +2171,7 @@ void MainWindow::decode() //decode() dec_data.params.nfSplit=m_wideGraph->Fmin(); dec_data.params.nfb=m_wideGraph->Fmax(); dec_data.params.ntol=m_Ftol; - if(m_mode=="JT9+JT65" or !m_config.enable_VHF_features() or !m_config.single_decode()) { + if(m_mode=="JT9+JT65" or !m_config.enable_VHF_features()) { dec_data.params.ntol=20; dec_data.params.naggressive=0; } @@ -2443,10 +2443,10 @@ void MainWindow::readFromStdout() //readFromStdout //Right (Rx Frequency) window bool bDisplayRight=bAvgMsg; - if(!m_config.single_decode() and m_mode!="JT4" and + if(!m_config.enable_VHF_features() and (abs(decodedtext.frequencyOffset() - m_wideGraph->rxFreq()) <= 10)) bDisplayRight=true; if (bDisplayRight) { - // This msg is within 10 hertz of our tuned frequency, or a JT4 avg + // This msg is within 10 hertz of our tuned frequency, or a JT4 or JT65 avg ui->decodedTextBrowser2->displayDecodedText(decodedtext,m_baseCall,false, m_logBook,m_config.color_CQ(),m_config.color_MyCall(), m_config.color_DXCC(),m_config.color_NewCall()); @@ -4092,7 +4092,7 @@ void MainWindow::on_actionJT65_triggered() m_mode="JT65"; bool bVHF=m_config.enable_VHF_features(); if(bVHF) { - displayWidgets(nWidgets("11111000000011111011000")); + displayWidgets(nWidgets("11111001000011111011000")); } else { displayWidgets(nWidgets("11101000000011100001110")); } @@ -4121,14 +4121,11 @@ void MainWindow::on_actionJT65_triggered() ui->sbSubmode->setMaximum(2); if(bVHF) { ui->sbSubmode->setValue(m_nSubMode); - } else { - ui->sbSubmode->setValue(0); - ui->sbTR->setValue(0); - } - if(m_config.single_decode()) { ui->label_6->setText("Single-Period Decodes"); ui->label_7->setText("Average Decodes"); } else { + ui->sbSubmode->setValue(0); + ui->sbTR->setValue(0); ui->label_6->setText("Band Activity"); ui->label_7->setText("Rx Frequency"); }