Merge branch 'develop' into working-freqs

This commit is contained in:
Brian Moran 2022-11-19 07:03:18 -08:00
commit f59e9cba04
36 changed files with 1374 additions and 742 deletions

View File

@ -71,7 +71,7 @@ message (STATUS "******************************************************")
include (set_build_type)
# RC 0 or omitted is a development build, GA is a General Availability release build
set_build_type (RC 4)
set_build_type (RC 5)
set (wsjtx_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}${BUILD_TYPE_REVISION}")
#

View File

@ -1436,7 +1436,9 @@ void Configuration::impl::initialize_models ()
ui_->TX_audio_source_button_group->button (rig_params_.audio_source)->setChecked (true);
ui_->CAT_poll_interval_spin_box->setValue (rig_params_.poll_interval);
ui_->opCallEntry->setText (opCall_);
ui_->udp_server_line_edit->setEnabled(false);
ui_->udp_server_line_edit->setText (udp_server_name_);
ui_->udp_server_line_edit->setEnabled(true);
on_udp_server_line_edit_editingFinished ();
ui_->udp_server_port_spin_box->setValue (udp_server_port_);
load_network_interfaces (ui_->udp_interfaces_combo_box, udp_interface_names_);
@ -2538,6 +2540,28 @@ void Configuration::impl::on_udp_server_line_edit_textChanged (QString const&)
void Configuration::impl::on_udp_server_line_edit_editingFinished ()
{
if (this->isVisible())
{
int q1,q2,q3,q4;
char tmpbuf[2];
int n = sscanf(ui_->udp_server_line_edit->text ().trimmed ().toLatin1(), "%d.%d.%d.%d.%1s", &q1, &q2, &q3, &q4, tmpbuf);
const char *iperr;
switch(n)
{
case 0: iperr = "Error before first number";break;
case 1: iperr = "Error between first and second number";break;
case 2: iperr = "Error between second and third number";break;
case 3: iperr = "Error between third and fourth number";break;
case 4: iperr = ""; break;
case 5: iperr = "Invalid characters after IP address"; break;
default: iperr = "Unknown error parsing network address";
}
if (n != 4)
{
MessageBox::warning_message (this, tr ("Error in network address"), tr (iperr));
return;
}
if (udp_server_name_edited_)
{
auto const& server = ui_->udp_server_line_edit->text ().trimmed ();
@ -2557,6 +2581,7 @@ void Configuration::impl::on_udp_server_line_edit_editingFinished ()
check_multicast (ha);
}
}
}
}
void Configuration::impl::host_info_results (QHostInfo host_info)

View File

@ -137,6 +137,7 @@ void MessageClient::impl::host_info_results (QHostInfo host_info)
if (QHostInfo::NoError != host_info.error ())
{
Q_EMIT self_->error ("UDP server DNS lookup failed: " + host_info.errorString ());
return;
}
else
{

View File

@ -437,15 +437,14 @@ QString DXLabSuiteCommanderTransceiver::command_with_reply (QString const& cmd)
};
}
auto result = commander_->readAll ();
// qDebug () << "result: " << result;
// for (int i = 0; i < result.size (); ++i)
// {
// qDebug () << i << ":" << hex << int (result[i]);
// }
QString result = commander_->readAll ();
if (result != NULL)
{
CAT_TRACE (cmd << " -> " << QString {result});
return result; // converting raw UTF-8 bytes to QString
}
return "";
}
bool DXLabSuiteCommanderTransceiver::write_to_port (QString const& s)

View File

@ -117,6 +117,10 @@ void PollingTransceiver::do_post_ptt (bool p)
retries_ = polls_to_stabilize;
//retries_ = 0; // fast feedback on PTT
}
else
{
next_state_.ptt(p); // ensure this is initialized
}
}
bool PollingTransceiver::do_pre_update ()

View File

@ -72,7 +72,7 @@ set (UG_IMGS
images/config-menu.png
images/decode-menu.png
images/download_samples.png
images/echo_144.png
images/Echo_1296.png
images/EME_Deep_0.png
images/EME_Deep_1.png
images/EME_Deep_2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

View File

@ -70,7 +70,8 @@ provides a mapping facility, archival storage, and many other
features.
*Echo* mode allows you to detect and measure your own station's echoes
from the moon, even if they are far below the audible threshold.
from the moon and to make other measurements useful for optimizing
your EME station's performance.
_WSJT-X_ provides spectral displays for receiver passbands as wide as
5 kHz, flexible rig control for nearly all modern radios used by

View File

@ -15,10 +15,11 @@ that station.
of situations with available _a priori_ (AP) information.
- *Echo* mode now offers a *Clear Avg* button and produces reliable
measurements of SNR even when Doppler spread is large. The *Measure*
function can be used to measure SNR for a received unmodulated carrier
-- for example, a key-down test signal emitted by another station and
reflected from the Moon.
measurements of SNR even when Doppler spread is large. Its *Monitor*
function can be used to measure SNR for a received unmodulated
carrier such as a key-down test signal emitted by another station and
reflected from the Moon, and to measure Sun, Moon, and ground noise as
aids for optimizing an EME station's performance.
- New buttons on the main window allow quick changes between modes
FT4, FT8, MSK144, Q65, and JT65. Another new button allows toggling

View File

@ -280,37 +280,43 @@ being readable by anyone listening in.
=== Echo Mode
*Echo* mode allows you to make sensitive measurements of your own
lunar echoes even when they are too weak to be heard. Select *Echo*
from the *Mode* menu, aim your antenna at the moon, pick a clear
frequency, and toggle click *Tx Enable*. _WSJT-X_ will then cycle
through the following loop every 6 seconds:
*Echo* mode provides tools for two types of measurements: echoes of
your transmitted signal from the Moon, and broadband noise power
received from the Sun, Moon, and possibly other sources including
nearby ground. In each case the system noise temperature (noise power
referred to the antenna terminals, expressed in Kelvin degrees) serves
as the reference noise level. Such measurements are widely used for
optimizing a station's capabilities for Earth-Moon-Earth (EME)
communication.
1. Transmit a 1500 Hz fixed tone for 2.3 s
2. Wait about 0.2 s for start of the return echo
3. Record the received signal for 2.3 s
4. Analyze, average, and display the results
5. Repeat from step 1
For lunar echoes, _WSJT_ generates short fixed-frequency transmissions
that alternate with reception intervals at the appropriate
Doppler-shifted frequency. With *Split Operation* set to *Rig* or
*Fake It* on the *Settings | Radio* tab, check *Doppler tracking* and
*Own Echo* on the Astronomical Data window. Point your antenna at the
Moon and click *Enable Tx* on the main window to start a sequence of
echo measurements. Each cycle takes 6 seconds. If strong enough,
echoes will be visible in the waterfall. Their average spectrum will
be displayed in the Echo Graph window, and numerical parameters of the
measurements appear in the main window:
To make a sequence of echo tests:
image::Echo_1296.png[align="center",alt="Echo 144 MHz"]
- Select *Echo* from the *Mode* menu.
At the end of each echo cycle a line of data in the main text window
displays the following information:
- Check *Doppler tracking* and *Constant frequency on the Moon* on the
Astronomical Data window.
UTC Time in hhmmss format
Hour UTC in hours and decimal fraction
Level Relative received noise power (dB)
Doppler EME Doppler shift at center of lunar disk
Width EME Doppler spread over full lunar disk
N Number of accumulated echo or monitor cycles
Q Estimated quality of averaged data on a 0 10 scale
DF Offset of spectral peak from 1500 Hz
SNR Average signal-to-noise ratio (dB/2500 Hz)
dBerr Estimated uncertainty of SNR
- Be sure that your rig control has been set up for _Split Operation_,
using either *Rig* or *Fake It* on the *Settings | Radio* tab.
- Click *Enable Tx* on the main window to start a sequence of 6-second
cycles.
- _WSJT-X_ calculates and compensates for Doppler shift automatically.
As shown in the screen shot below, when proper Doppler corrections
have been applied your return echo should always appear at the center
of the plot area on the Echo Graph window.
image::echo_144.png[align="center",alt="Echo 144 MHz"]
... more to come ...
=== Tips for EME

View File

@ -1,5 +1,5 @@
subroutine avecho(id2,ndop,nfrit,nauto,nqual,f1,xlevel,snrdb,db_err, &
dfreq,width,bDiskData)
subroutine avecho(id2,ndop,nfrit,nauto,navg,nqual,f1,xlevel,snrdb, &
db_err,dfreq,width,bDiskData)
integer TXLENGTH
parameter (TXLENGTH=27648) !27*1024
@ -8,6 +8,8 @@ subroutine avecho(id2,ndop,nfrit,nauto,nqual,f1,xlevel,snrdb,db_err, &
integer*2 id2(34560) !Buffer for Rx data
real sa(NZ) !Avg spectrum relative to initial Doppler echo freq
real sb(NZ) !Avg spectrum with Dither and changing Doppler removed
real, dimension (:,:), allocatable :: sax
real, dimension (:,:), allocatable :: sbx
integer nsum !Number of integrations
real dop0 !Doppler shift for initial integration (Hz)
real dop !Doppler shift for current integration (Hz)
@ -20,8 +22,18 @@ subroutine avecho(id2,ndop,nfrit,nauto,nqual,f1,xlevel,snrdb,db_err, &
equivalence (x,c),(ipk,ipkv)
common/echocom/nclearave,nsum,blue(NZ),red(NZ)
common/echocom2/fspread_self,fspread_dx
save dop0,sa,sb
data navg0/-1/
save dop0,navg0,sax,sbx
if(navg.ne.navg0) then
if(allocated(sax)) deallocate(sax)
if(allocated(sbx)) deallocate(sbx)
allocate(sax(1:navg,1:NZ))
allocate(sbx(1:navg,1:NZ))
nsum=0
navg0=navg
endif
fspread=fspread_dx !### Use the predicted Doppler spread ###
if(bDiskData) fspread=width
if(nauto.eq.1) fspread=fspread_self
@ -44,8 +56,8 @@ subroutine avecho(id2,ndop,nfrit,nauto,nqual,f1,xlevel,snrdb,db_err, &
if(nclearave.ne.0) nsum=0
if(nsum.eq.0) then
dop0=dop !Remember the initial Doppler
sa=0. !Clear the average arrays
sb=0.
sax=0. !Clear the average arrays
sbx=0.
endif
x(TXLENGTH+1:)=0.
@ -67,10 +79,14 @@ subroutine avecho(id2,ndop,nfrit,nauto,nqual,f1,xlevel,snrdb,db_err, &
endif
nsum=nsum+1
j=mod(nsum-1,navg)+1
do i=1,NZ
sa(i)=sa(i) + s(ia+i-2048) !Center at initial doppler freq
sb(i)=sb(i) + s(ib+i-2048) !Center at expected echo freq
sax(j,i)=s(ia+i-2048) !Center at initial doppler freq
sbx(j,i)=s(ib+i-2048) !Center at expected echo freq
sa(i)=sum(sax(1:navg,i))
sb(i)=sum(sbx(1:navg,i))
enddo
call echo_snr(sa,sb,fspread,blue,red,snrdb,db_err,dfreq,snr_detect)
nqual=snr_detect-2
if(nqual.lt.0) nqual=0
@ -87,12 +103,17 @@ subroutine avecho(id2,ndop,nfrit,nauto,nqual,f1,xlevel,snrdb,db_err, &
call smo121(blue,NZ)
enddo
ia=200.0/df
ib=400.0/df
call pctile(red(ia:ib),ib-ia+1,50,bred)
red=red-bred
call pctile(blue(ia:ib),ib-ia+1,50,bblue)
blue=blue-bblue
ia=50.0/df
ib=250.0/df
call pctile(red(ia:ib),ib-ia+1,50,bred1)
call pctile(blue(ia:ib),ib-ia+1,50,bblue1)
ia=1250.0/df
ib=1450.0/df
call pctile(red(ia:ib),ib-ia+1,50,bred2)
call pctile(blue(ia:ib),ib-ia+1,50,bblue2)
red=red-0.5*(bred1+bred2)
blue=blue-0.5*(bblue1+bblue2)
900 call sleep_msec(10) !Avoid the "blue Decode button" syndrome
return

View File

@ -8,7 +8,7 @@ program echosim
character arg*12,fname*17
complex c0(0:NMAX-1)
complex c(0:NMAX-1)
! complex cwave(0:NWAVE-1)
real*4 level_1,level_2
real*8 f0,dt,twopi,phi,dphi
real wave(NZ)
integer*2 iwave(NZ) !Generated full-length waveform
@ -20,9 +20,11 @@ program echosim
! Get command-line argument(s)
nargs=iargc()
if(nargs.ne.5) then
print*,'Usage: echosim f0 fdop fspread nfiles snr'
print*,'Examples: echosim 1500 0.0 4.0 10 -22'
if(nargs.ne.3 .and. nargs.ne.5) then
print*,'Usage 1: echosim f0 fdop fspread nfiles snr'
print*,'Example: echosim 1500 0.0 4.0 10 -22'
print*,'Usage 2: echosim level_1 level_2 nfiles'
print*,'Example: echosim 30.0 40.0 100'
go to 999
endif
@ -32,12 +34,21 @@ program echosim
read(arg,*) fdop !Doppler shift (Hz)
call getarg(3,arg)
read(arg,*) fspread !Frequency spread (Hz) (JHT Lorentzian model)
if(nargs.eq.3) then
level_1=f0
level_2=fdop
nfiles=fspread
snrdb=0.
go to 10
endif
call getarg(4,arg)
read(arg,*) nfiles !Number of files
call getarg(5,arg)
read(arg,*) snrdb !SNR_2500
twopi=8.d0*atan(1.d0)
10 twopi=8.d0*atan(1.d0)
fs=12000.0 !Sample rate (Hz)
dt=1.d0/fs !Sample interval (s)
bandwidth_ratio=2500.0/(fs/2.0)
@ -49,18 +60,23 @@ program echosim
1000 format(' N f0 fDop fSpread SNR File name'/51('-'))
do ifile=1,nfiles
phi=0.d0
do i=0,NWAVE-1
phi=phi + dphi
if(phi.gt.twopi) phi=phi-twopi
xphi=phi
c0(i)=cmplx(cos(xphi),sin(xphi))
enddo
c0(NWAVE:)=0.
if(fspread.gt.0.0) call fspread_lorentz(c0,fspread)
c=sig*c0
wave(1:NWAVE)=imag(c(1:NWAVE))
peak=maxval(abs(wave))
wave=0.
if(nargs.eq.5) then
phi=0.d0
do i=0,NWAVE-1
phi=phi + dphi
if(phi.gt.twopi) phi=phi-twopi
xphi=phi
c0(i)=cmplx(cos(xphi),sin(xphi))
enddo
c0(NWAVE:)=0.
if(fspread.gt.0.0) call fspread_lorentz(c0,fspread)
c=sig*c0
wave(1:NWAVE)=imag(c(1:NWAVE))
peak=maxval(abs(wave))
endif
if(snrdb.lt.90) then
do i=1,NWAVE !Add gaussian noise at specified SNR
xnoise=gran()
@ -73,6 +89,10 @@ program echosim
endif
gain=100.0
if(nargs.eq.3) then
gain=10.0**(0.05*level_1)
if(mod((ifile-1)/10,2).eq.1) gain=10.0**(0.05*level_2)
endif
if(snrdb.lt.90.0) then
wave=gain*wave
else

View File

@ -586,13 +586,26 @@ contains
xsig=xsig+s4(itone(i),i)
enddo
base=candidates(icand,5)
arg=600.0*(xsig/base)-1.0
select case(ntrperiod)
case(15)
snr_calfac=800.0
case(30)
snr_calfac=600.0
case(60)
snr_calfac=430.0
case(120)
snr_calfac=390.0
case(300)
snr_calfac=340.0
case(900)
snr_calfac=320.0
case(1800)
snr_calfac=320.0
case default
end select
arg=snr_calfac*xsig/base - 1.0
if(arg.gt.0.0) then
xsnr=10*log10(arg)-35.5-12.5*log10(nsps/8200.0)
if(ntrperiod.eq. 15) xsnr=xsnr+2
if(ntrperiod.eq. 30) xsnr=xsnr+1
if(ntrperiod.eq. 900) xsnr=xsnr+1
if(ntrperiod.eq.1800) xsnr=xsnr+2
xsnr=10*log10(arg)+10*log10(1.46/2500)+10*log10(8200.0/nsps)
else
xsnr=-99.9
endif

View File

@ -287,6 +287,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,nzhsym,lapon, &
! 5 : WW_DIGI
! 6 : FOX
! 7 : HOUND
! 8 : ARRL_DIGI
!
! Conditions that cause us to bail out of AP decoding
if(ncontest.le.5 .and. iaptype.ge.3 .and. (abs(f1-nfqso).gt.napwid .and. abs(f1-nftx).gt.napwid) ) cycle
@ -306,6 +307,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,nzhsym,lapon, &
if(ncontest.eq.4) llrz(1:29)=apmag*mcqru(1:29)
if(ncontest.eq.5) llrz(1:29)=apmag*mcqww(1:29)
if(ncontest.eq.7) llrz(1:29)=apmag*mcq(1:29)
if(ncontest.eq.8) llrz(1:29)=apmag*mcqtest(1:29)
apmask(75:77)=1
llrz(75:76)=apmag*(-1)
llrz(77)=apmag*(+1)
@ -313,7 +315,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,nzhsym,lapon, &
if(iaptype.eq.2) then ! MyCall,???,???
apmask=0
if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.5) then
if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.5.or.ncontest.eq.8) then
apmask(1:29)=1
llrz(1:29)=apmag*apsym(1:29)
apmask(75:77)=1
@ -353,7 +355,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,nzhsym,lapon, &
if(iaptype.eq.3) then ! MyCall,DxCall,???
apmask=0
if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.2.or.ncontest.eq.5.or.ncontest.eq.7) then
if(ncontest.eq.0.or.ncontest.eq.1.or.ncontest.eq.2.or.ncontest.eq.5.or.ncontest.eq.7.or.ncontest.eq.8) then
apmask(1:58)=1
llrz(1:58)=apmag*apsym
apmask(75:77)=1
@ -379,7 +381,7 @@ subroutine ft8b(dd0,newdat,nQSOProgress,nfqso,nftx,ndepth,nzhsym,lapon, &
if(iaptype.eq.5.and.ncontest.eq.7) cycle !Hound
if(iaptype.eq.4 .or. iaptype.eq.5 .or. iaptype.eq.6) then
apmask=0
if(ncontest.le.5 .or. (ncontest.eq.7.and.iaptype.eq.6)) then
if(ncontest.le.5 .or. (ncontest.eq.7.and.iaptype.eq.6) .or. ncontest.eq.8) then
apmask(1:77)=1 ! mycall, hiscall, RRR|73|RR73
llrz(1:58)=apmag*apsym
if(iaptype.eq.4) llrz(59:77)=apmag*mrrr

View File

@ -1,9 +1,10 @@
subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,s,candidate, &
subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,nzhsym,candidate, &
ncand,sbase)
include 'ft8_params.f90'
parameter (MAXPRECAND=500)
! Search over +/- 2.5s relative to 0.5s TX start time.
parameter (MAXPRECAND=1000)
! Maximum sync correlation lag +/- 2.5s relative to 0.5s TX start time.
! 2.5s / 0.16s/symbol * 4 samples/symbol = 62.5 lag steps in 2.5s
parameter (JZ=62)
complex cx(0:NH1)
real s(NH1,NHSYM)
@ -12,11 +13,14 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,s,candidate, &
real x(NFFT1)
real sync2d(NH1,-JZ:JZ)
real red(NH1)
real red2(NH1)
real candidate0(3,MAXPRECAND)
real candidate(3,maxcand)
real dd(NMAX)
integer jpeak(NH1)
integer jpeak2(NH1)
integer indx(NH1)
integer indx2(NH1)
integer ii(1)
integer icos7(0:6)
data icos7/3,1,4,0,6,5,2/ !Costas 7x7 tone pattern
@ -82,11 +86,16 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,s,candidate, &
enddo
red=0.
red2=0.
mlag=10
mlag2=JZ
do i=ia,ib
ii=maxloc(sync2d(i,-JZ:JZ)) - 1 - JZ
j0=ii(1)
jpeak(i)=j0
red(i)=sync2d(i,j0)
ii=maxloc(sync2d(i,-mlag:mlag)) - 1 - mlag
jpeak(i)=ii(1)
red(i)=sync2d(i,jpeak(i))
ii=maxloc(sync2d(i,-mlag2:mlag2)) - 1 - mlag2
jpeak2(i)=ii(1)
red2(i)=sync2d(i,jpeak2(i))
enddo
iz=ib-ia+1
call indexx(red(ia:ib),iz,indx)
@ -100,14 +109,29 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,s,candidate, &
if(ibase.gt.nh1) ibase=nh1
base=red(ibase)
red=red/base
call indexx(red2(ia:ib),iz,indx2)
ibase2=indx2(npctile) - 1 + ia
if(ibase2.lt.1) ibase2=1
if(ibase2.gt.nh1) ibase2=nh1
base2=red2(ibase2)
red2=red2/base2
do i=1,min(MAXPRECAND,iz)
n=ia + indx(iz+1-i) - 1
if(red(n).lt.syncmin.or.isnan(red(n)).or.k.eq.MAXPRECAND) exit
k=k+1
candidate0(1,k)=n*df
candidate0(2,k)=(jpeak(n)-0.5)*tstep
candidate0(3,k)=red(n)
if(k.ge.MAXPRECAND) exit
if( (red(n).ge.syncmin) .and. (.not.isnan(red(n))) ) then
k=k+1
candidate0(1,k)=n*df
candidate0(2,k)=(jpeak(n)-0.5)*tstep
candidate0(3,k)=red(n)
endif
if(abs(jpeak2(n)-jpeak(n)).eq.0) cycle
if(k.ge.MAXPRECAND) exit
if( (red2(n).ge.syncmin) .and. (.not.isnan(red2(n))) ) then
k=k+1
candidate0(1,k)=n*df
candidate0(2,k)=(jpeak2(n)-0.5)*tstep
candidate0(3,k)=red2(n)
endif
enddo
ncand=k
@ -116,7 +140,8 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,s,candidate, &
if(i.ge.2) then
do j=1,i-1
fdiff=abs(candidate0(1,i))-abs(candidate0(1,j))
if(abs(fdiff).lt.4.0) then
tdiff=abs(candidate0(2,i)-candidate0(2,j))
if(abs(fdiff).lt.4.0.and.tdiff.lt.0.04) then
if(candidate0(3,i).ge.candidate0(3,j)) candidate0(3,j)=0.
if(candidate0(3,i).lt.candidate0(3,j)) candidate0(3,i)=0.
endif
@ -148,6 +173,5 @@ subroutine sync8(dd,nfa,nfb,syncmin,nfqso,maxcand,s,candidate, &
endif
enddo
ncand=k-1
return
end subroutine sync8

View File

@ -44,7 +44,7 @@ contains
class(ft8_decoder), intent(inout) :: this
procedure(ft8_decode_callback) :: callback
parameter (MAXCAND=300,MAX_EARLY=100)
parameter (MAXCAND=600,MAX_EARLY=100)
real*8 tsec,tseq
real s(NH1,NHSYM)
real sbase(NH1)
@ -80,7 +80,9 @@ contains
dt0=0.
f0=0.
endif
if(nutc.ne.nutc0) then
!Added 41==nzhsym to force a reset if the same wav file is processed twice or more in a row,
!in which case nutc.eq.nutc0 and ndec(jseq,1) doesn't get reset
if(nzhsym==41 .or. (nutc.ne.nutc0)) then
! New UTC. Move previously saved 'a7' data from k=1 to k=0
iz=ndec(jseq,1)
dt0(1:iz,jseq,0) = dt0(1:iz,jseq,1)
@ -107,6 +109,7 @@ contains
dd=iwave
dd1=dd
endif
if(nzhsym.eq.41) then
ndecodes=0
allmessages=' '
@ -114,10 +117,12 @@ contains
else
ndecodes=ndec_early
endif
if(nzhsym.eq.47 .and. ndec_early.eq.0) then
dd1=dd
go to 800
endif
if(nzhsym.eq.47 .and. ndec_early.ge.1) then
lsubtracted=.false.
lrefinedt=.true.
@ -140,6 +145,7 @@ contains
dd1=dd
go to 900
endif
if(nzhsym.eq.50 .and. ndec_early.ge.1 .and. .not.nagain) then
n=47*3456
dd(1:n)=dd1(1:n)
@ -151,6 +157,7 @@ contains
enddo
call timer('sub_ft8c',1)
endif
ifa=nfa
ifb=nfb
if(nzhsym.eq.50 .and. nagain) then
@ -164,11 +171,12 @@ contains
! ndepth=2: subtraction, 3 passes, bp+osd (no subtract refinement)
! ndepth=3: subtraction, 3 passes, bp+osd
npass=3
if(ndepth.eq.1) npass=1
if(ndepth.eq.1) npass=2
do ipass=1,npass
newdat=.true.
syncmin=1.3
if(ndepth.le.2) syncmin=1.6
if(nzhsym.eq.41) syncmin=2.0
if(ipass.eq.1) then
lsubtract=.true.
ndeep=ndepth
@ -185,7 +193,7 @@ contains
endif
call timer('sync8 ',0)
maxc=MAXCAND
call sync8(dd,ifa,ifb,syncmin,nfqso,maxc,s,candidate, &
call sync8(dd,ifa,ifb,syncmin,nfqso,maxc,nzhsym,candidate, &
ncand,sbase)
call timer('sync8 ',1)
do icand=1,ncand
@ -221,10 +229,6 @@ contains
if(emedelay.ne.0) xdt=xdt+2.0
call this%callback(sync,nsnr,xdt,f1,msg37,iaptype,qual)
call ft8_a7_save(nutc,xdt,f1,msg37) !Enter decode in table
! ii=ndec(jseq,1)
! write(41,3041) jseq,ii,nint(f0(ii,jseq,0)),msg0(ii,jseq,0)(1:22),&
! nint(f0(ii,jseq,1)),msg0(ii,jseq,1)(1:22)
!3041 format(3i5,2x,a22,i5,2x,a22)
endif
endif
call timestamp(tsec,tseq,ctime)
@ -237,7 +241,7 @@ contains
if(nzhsym.lt.50) ndec_early=ndecodes
900 continue
if(nzhsym.eq.50 .and. ndec(jseq,0).ge.1) then
if(lft8apon .and. ncontest.ne.6 .and. ncontest.ne.7 .and. nzhsym.eq.50 .and. ndec(jseq,0).ge.1) then
newdat=.true.
do i=1,ndec(jseq,0)
if(f0(i,jseq,0).eq.-99.0) exit

View File

@ -55,6 +55,7 @@ subroutine symspec(shared_data,k,TRperiod,nsps,ingain,bLowSidelobes, &
endif
if(k.lt.k0) then !Start a new data block
k0=0
ja=0
ssum=0.
ihsym=0
@ -64,11 +65,8 @@ subroutine symspec(shared_data,k,TRperiod,nsps,ingain,bLowSidelobes, &
sq=0.
pxmax=0.;
! dwell_time=0.0001
! if(k.gt.k0 .and. npct.gt.0) call blanker(shared_data%id2(k0+1:k), &
! k-k0,dwell_time,npct)
do i=k0+1,k
if(k0.eq.0 .and. i.le.10) cycle
x1=shared_data%id2(i)
if (abs(x1).gt.pxmax) pxmax = abs(x1);
sq=sq + x1*x1

View File

@ -1,6 +1,6 @@
program testfast9
parameter (NMAX=359424)
parameter (NMAX=30*12000)
integer*2 id2(NMAX)
integer narg(0:11)
character*80 line(100)
@ -8,8 +8,8 @@ program testfast9
nargs=iargc()
if(nargs.ne.2) then
print*,'Usage: testfast9 submode infile'
print*,'Example: testfast9 E /data/VE1SKY/K1JT/JT9E/150806_123300.wav'
print*,'Usage: testfast9 submode infile'
print*,'Example: testfast9 E 150806_123300.wav'
go to 999
endif
call getarg(1,submode)

View File

@ -7,6 +7,7 @@
#include <stdio.h>
#include "SettingsGroup.hpp"
#include "commons.h"
#include <math.h>
extern "C" {
void astrosub_ (int* nyear, int* month, int* nday, double* uth, int* nfreq,
@ -44,7 +45,7 @@ Astro::~Astro()
}
void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid,
int fQSO, int nsetftx, int ntxFreq, QString azelDir)
int fQSO, int nsetftx, int ntxFreq, QString azelDir, double xavg)
{
static int ntxFreq0=-99;
char cc[300];
@ -86,6 +87,65 @@ void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid,
ntsky,xnr,dgrd);
ui->astroTextBrowser->setText(" "+ date + "\nUTC: " + utc + "\n" + cc);
double azOffset=0.0;
double elOffset=0.0;
double rad=57.2957795131;
int iCycle=2;
// Are we doing pointing tests?
bool bPointing=ui->cbPointingTests->isChecked();
ui->gbPointing->setVisible(bPointing);
if(bPointing) {
int nDwell=int(ui->sbDwell->value());
if(ui->cbAutoCycle->isChecked()) {
iCycle=(t.currentSecsSinceEpoch()%(6*nDwell))/nDwell + 1;
if(iCycle==1) {
azOffset = -ui->sbOffset->value()/cos(elsun/rad);
ui->rb1->setChecked(true);
}
if(iCycle==2 or iCycle==5) {
ui->rb2->setChecked(true);
}
if(iCycle==3) {
azOffset = +ui->sbOffset->value()/cos(elsun/rad);
ui->rb3->setChecked(true);
}
if(iCycle==4) {
elOffset = -ui->sbOffset->value();
ui->rb4->setChecked(true);
}
if(iCycle==6) {
elOffset = +ui->sbOffset->value();
ui->rb6->setChecked(true);
}
}
if(ui->cbOnOff->isChecked()) {
iCycle=(t.currentSecsSinceEpoch()%(2*nDwell))/nDwell + 1;
if(iCycle==1) {
azOffset = -ui->sbOffset->value()/cos(elsun/rad);
ui->rb1->setChecked(true);
}
if(iCycle==2) {
ui->rb2->setChecked(true);
}
}
if(ui->cbAutoCycle->isChecked() or ui->cbOnOff->isChecked()) {
QFile f("pointing.out");
if(f.open(QIODevice::WriteOnly | QIODevice::Append)) {
QTextStream out(&f);
out << t.toString("yyyy-MMM-dd hh:mm:ss");
sprintf(cc,"%7.1f %7.1f %d %7.1f %7.1f %10.1f %7.2f\n",
azsun,elsun,iCycle,azOffset,elOffset,xavg,10.0*log10(xavg));
out << cc;
f.close();
}
}
} else {
ui->rb2->setChecked(true);
ui->cbAutoCycle->setChecked(false);
ui->cbOnOff->setChecked(false);
}
// Write pointing data to azel.dat
QString fname=azelDir+"/azel.dat";
QFile f(fname);
if(!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
@ -107,7 +167,7 @@ void Astro::astroUpdate(QDateTime t, QString mygrid, QString hisgrid,
"%3d,%1d,fQSO\n"
"%3d,%1d,fQSO2\n",
nhr,nmin,isec,azmoon,elmoon,
nhr,nmin,isec,azsun,elsun,
nhr,nmin,isec,azsun+azOffset,elsun+elOffset,
nhr,nmin,isec,0.0,0.0,
nfreq,ndop,ndop00,
fQSO,nsetftx,
@ -120,3 +180,14 @@ void Astro::setFontSize(int n)
{
ui->astroTextBrowser->setFontPointSize(n);
}
void Astro::on_cbAutoCycle_clicked(bool checked)
{
if(checked) ui->cbOnOff->setChecked(false);
}
void Astro::on_cbOnOff_clicked(bool checked)
{
if(checked) ui->cbAutoCycle->setChecked(false);
}

View File

@ -15,10 +15,14 @@ class Astro : public QWidget
public:
explicit Astro (QString const& settings_filename, QWidget *parent = 0);
void astroUpdate(QDateTime t, QString mygrid, QString hisgrid,
int fQSO, int nsetftx, int ntxFreq, QString azelDir);
int fQSO, int nsetftx, int ntxFreq, QString azelDir, double xavg);
void setFontSize(int n);
~Astro ();
private slots:
void on_cbOnOff_clicked(bool checked);
void on_cbAutoCycle_clicked(bool checked);
private:
Ui::Astro *ui;
QString m_settings_filename;

View File

@ -6,30 +6,242 @@
<rect>
<x>0</x>
<y>0</y>
<width>262</width>
<width>441</width>
<height>483</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QTextBrowser" name="astroTextBrowser">
<widget class="QGroupBox" name="gbPointing">
<property name="geometry">
<rect>
<x>269</x>
<y>19</y>
<width>151</width>
<height>431</height>
</rect>
</property>
<property name="title">
<string/>
</property>
<widget class="QRadioButton" name="rb1">
<property name="geometry">
<rect>
<x>10</x>
<y>100</y>
<width>30</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>1</string>
</property>
</widget>
<widget class="QRadioButton" name="rb2">
<property name="geometry">
<rect>
<x>60</x>
<y>100</y>
<width>40</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>2, 5</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QRadioButton" name="rb3">
<property name="geometry">
<rect>
<x>110</x>
<y>100</y>
<width>30</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>3</string>
</property>
</widget>
<widget class="QRadioButton" name="rb4">
<property name="geometry">
<rect>
<x>60</x>
<y>150</y>
<width>30</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>4</string>
</property>
</widget>
<widget class="QRadioButton" name="rb6">
<property name="geometry">
<rect>
<x>60</x>
<y>50</y>
<width>30</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>6</string>
</property>
</widget>
<widget class="QDoubleSpinBox" name="sbOffset">
<property name="geometry">
<rect>
<x>10</x>
<y>230</y>
<width>130</width>
<height>22</height>
</rect>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="prefix">
<string>Offset </string>
</property>
<property name="suffix">
<string> deg</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>0.500000000000000</double>
</property>
<property name="maximum">
<double>20.000000000000000</double>
</property>
<property name="singleStep">
<double>0.500000000000000</double>
</property>
<property name="value">
<double>2.500000000000000</double>
</property>
</widget>
<widget class="QCheckBox" name="cbAutoCycle">
<property name="geometry">
<rect>
<x>30</x>
<y>330</y>
<width>91</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>Auto Cycle</string>
</property>
</widget>
<widget class="QCheckBox" name="cbOnOff">
<property name="geometry">
<rect>
<x>30</x>
<y>380</y>
<width>70</width>
<height>17</height>
</rect>
</property>
<property name="text">
<string>On Off</string>
</property>
</widget>
<widget class="QSpinBox" name="sbDwell">
<property name="geometry">
<rect>
<x>10</x>
<y>280</y>
<width>130</width>
<height>22</height>
</rect>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="suffix">
<string> s</string>
</property>
<property name="prefix">
<string>Dwell </string>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>300</number>
</property>
<property name="singleStep">
<number>10</number>
</property>
</widget>
</widget>
<widget class="QWidget" name="">
<property name="geometry">
<rect>
<x>0</x>
<y>10</y>
<width>256</width>
<height>451</height>
<width>258</width>
<height>471</height>
</rect>
</property>
<property name="font">
<font>
<family>Courier New</family>
<pointsize>20</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTextBrowser" name="astroTextBrowser">
<property name="font">
<font>
<family>Courier New</family>
<pointsize>20</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="cbPointingTests">
<property name="text">
<string>Pointing Tests</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<resources/>

View File

@ -14,6 +14,7 @@ subroutine decode0(dd,ss,savg,nstandalone)
mcall3,nkeep,ntol,nxant,nrxlog,nfsample,nxpol,nmode, &
nfast,nsave,max_drift,nhsym,mycall,mygrid,hiscall,hisgrid,datetime
common/early/nhsym1,nhsym2,ldecoded(32768)
common/decodes/ndecodes
data neme0/-99/,mcall3b/1/
save
@ -62,8 +63,8 @@ subroutine decode0(dd,ss,savg,nstandalone)
call sec0(1,tdec)
if(nhsym.eq.nhsym1) write(*,1010) nsum,nsave,nstandalone,nhsym,tdec
1010 format('<EarlyFinished>',3i4,i6,f6.2)
if(nhsym.eq.nhsym2) write(*,1012) nsum,nsave,nstandalone,nhsym,tdec
1012 format('<DecodeFinished>',3i4,i6,f6.2)
if(nhsym.eq.nhsym2) write(*,1012) nsum,nsave,nstandalone,nhsym,tdec,ndecodes
1012 format('<DecodeFinished>',3i4,i6,f6.2,i5)
flush(6)
return

View File

@ -34,12 +34,15 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
common/c3com/ mcall3a
common/testcom/ifreq
common/early/nhsym1,nhsym2,ldecoded(32768)
common/decodes/ndecodes
data blank/' '/,cm/'#'/
data shmsg0/'ATT','RO ','RRR','73 '/
data nfile/0/,nutc0/-999/,nid/0/,ip000/1/,ip001/1/,mousefqso0/-999/
save
ndecodes=0
! Clean start for Q65 at early decode
if(nhsym.eq.nhsym1 .or. nagain.ne.0) ldecoded=.false.
if(ndiskdat.eq.1) ldecoded=.false.
@ -50,7 +53,7 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
mode65=mod(nmode,10)
if(mode65.eq.3) mode65=4
mode_q65=nmode/10
nts_jt65=2**(mode65-1) !JT65 tone separation factor
nts_jt65=mode65 !JT65 tone separation factor
nts_q65=2**(mode_q65-1) !Q65 tone separation factor
xpol=(nxpol.ne.0)
@ -158,7 +161,7 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
ssmax=1.e30
call ccf65(ss(1,1,i),nhsym,ssmax,sync1,ipol,jpz,dt, &
flipk,syncshort,snr2,ipol2,dt2)
if(dt.lt.-2.6 .or. dt.gt.2.5) sync1=-99.0 !###
!### if(dt.lt.-2.6 .or. dt.gt.2.5) sync1=-99.0 !###
call timer('ccf65 ',1)
if(mode65.eq.0) syncshort=-99.0 !If "No JT65", don't waste time
@ -410,8 +413,8 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
if(cand(icand)%iflip.ne.0) cycle !Do only Q65 candidates here
if(candec(icand)) cycle !Skip if already decoded
freq=cand(icand)%f+nkhz_center-48.0-1.27046
! If here at nqd=1, do only candidates at mousefqso +/- ntol
if(nqd.eq.1 .and. abs(freq-mousefqso).gt.0.001*ntol) cycle
!###! If here at nqd=1, do only candidates at mousefqso +/- ntol
!### if(nqd.eq.1 .and. abs(freq-mousefqso).gt.0.001*ntol) cycle
ikhz=nint(freq)
f0=cand(icand)%f
call timer('q65b ',0)
@ -499,6 +502,7 @@ subroutine map65a(dd,ss,savg,newdat,nutc,fcenter,ntol,idphi,nfa,nfb, &
write(26,1014) f0,ndf,ndf0,ndf1,ndf2,dt,npol,nsync1, &
nsync2,nutc,decoded,cp,cmode
1014 format(f8.3,i5,3i3,f5.1,i4,i3,i4,i5.4,4x,a22,2x,a1,3x,a2)
ndecodes=ndecodes+1
write(21,1100) f0,ndf,dt,npol,nsync2,nutc,decoded,cp, &
cmode(1:1),cmode(2:2)
1100 format(f8.3,i5,f5.1,2i4,i5.4,2x,a22,2x,a1,3x,a1,1x,a1)

View File

@ -35,6 +35,7 @@ subroutine q65b(nutc,nqd,nxant,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, &
character*1 cp,cmode*2
common/cacb/ca,cb
common/early/nhsym1,nhsym2,ldecoded(32768)
common/decodes/ndecodes
data nutc00/-1/,msg00/' '/
save
@ -179,6 +180,7 @@ subroutine q65b(nutc,nqd,nxant,fcenter,nfcal,nfsample,ikhz,mousedf,ntol,xpol, &
! to map65_rx.log
if(nutc.ne.nutc00 .or. msg0(1:28).ne.msg00 .or. freq1.ne.freq1_00) then
! Write to file map65_rx.log:
ndecodes=ndecodes+1
write(21,1110) freq1,ndf,xdt0,npol,nsnr0,nutc,msg0(1:28),cq0
1110 format(f8.3,i5,f5.1,2i4,i5.4,2x,a28,': A',2x,a3)
nutc00=nutc

View File

@ -19,7 +19,7 @@ int main(int argc, char *argv[])
QApplication a {argc, argv};
// Override programs executable basename as application name.
a.setApplicationName ("MAP65");
a.setApplicationVersion ("3.0.0");
a.setApplicationVersion ("3.0.1");
// switch off as we share an Info.plist file with WSJT-X
a.setAttribute (Qt::AA_DontUseNativeMenuBar);
MainWindow w;

View File

@ -520,6 +520,8 @@ void MainWindow::dataSink(int k)
static int nkhz;
static int nfsample=96000;
static int nxpol=0;
static int nsec0=0;
static int nsum=0;
static float fgreen;
static int ndiskdat;
static int nb;
@ -529,6 +531,7 @@ void MainWindow::dataSink(int k)
static float rejectx;
static float rejecty;
static float slimit;
static double xsum=0.0;
if(m_diskData) {
ndiskdat=1;
@ -551,8 +554,22 @@ void MainWindow::dataSink(int k)
&nfsample, &fgreen, &m_adjustIQ, &m_applyIQcal,
&m_gainx, &m_gainy, &m_phasex, &m_phasey, &rejectx, &rejecty,
&px, &py, s, &nkhz, &ihsym, &nzap, &slimit, lstrong);
int nsec=QDateTime::currentSecsSinceEpoch();
if(nsec==nsec0) {
xsum+=pow(10.0,0.1*px);
nsum+=1;
} else {
m_xavg=0.0;
if(nsum>0) m_xavg=xsum/nsum;
xsum=pow(10.0,0.1*px);
nsum=1;
}
nsec0=nsec;
QString t;
m_pctZap=nzap/178.3;
ui->yMeterFrame->setVisible(m_xpol);
if(m_xpol) {
lab4->setText (
QString {" Rx noise: %1 %2 %3 %% "}
@ -1119,6 +1136,9 @@ void MainWindow::diskDat() //diskDat()
//These may be redundant??
m_diskData=true;
datcom_.newdat=1;
if(m_wide_graph_window->m_bForceCenterFreq) {
datcom_.fcenter=m_wide_graph_window->m_dForceCenterFreq;
}
if(m_fs96000) hsym=2048.0*96000.0/11025.0; //Samples per JT65 half-symbol
if(!m_fs96000) hsym=2048.0*95238.1/11025.0;
@ -1396,6 +1416,8 @@ void MainWindow::readFromStdout() //readFromStdout
QFile lockFile(m_appDir + "/.lock");
lockFile.open(QIODevice::ReadWrite);
if(t.indexOf("<DecodeFinished>") >= 0) {
int ndecodes=t.mid(40,5).toInt();
lab5->setText(QString::number(ndecodes));
m_map65RxLog=0;
m_startAnother=m_loopall;
}
@ -1404,6 +1426,8 @@ void MainWindow::readFromStdout() //readFromStdout
return;
}
read_log();
if(t.indexOf("!") >= 0) {
int n=t.length();
int m=2;
@ -1688,7 +1712,7 @@ void MainWindow::guiUpdate()
QDateTime t = QDateTime::currentDateTimeUtc();
int fQSO=m_wide_graph_window->QSOfreq();
m_astro_window->astroUpdate(t, m_myGrid, m_hisGrid, fQSO, m_setftx,
m_txFreq, m_azelDir);
m_txFreq, m_azelDir, m_xavg);
m_setftx=0;
QString utc = t.date().toString(" yyyy MMM dd \n") + t.time().toString();
ui->labUTC->setText(utc);
@ -2344,3 +2368,24 @@ bool MainWindow::isGrid4(QString g)
if(g.mid(3,1)<'0' or g.mid(3,1)>'9') return false;
return true;
}
void MainWindow::read_log()
{
// Update "m_worked" by reading wsjtx.log
m_worked.clear(); //Start from scratch
QFile f("wsjtx.log");
f.open(QIODevice::ReadOnly);
if(f.isOpen()) {
QTextStream in(&f);
QString line,callsign;
for(int i=0; i<99999; i++) {
line=in.readLine();
if(line.length()<=0) break;
callsign=line.mid(40,6);
int n=callsign.indexOf(",");
if(n>0) callsign=callsign.left(n);
m_worked[callsign]=true;
}
f.close();
}
}

View File

@ -194,12 +194,12 @@ private:
qint32 m_RxState;
qint32 m_dB;
double m_fAdd;
// double m_IQamp;
// double m_IQphase;
double m_cal570;
double m_TxOffset;
double m_xavg;
bool m_monitoring;
bool m_transmitting;
@ -294,6 +294,7 @@ private:
void stub();
bool isGrid4(QString g);
bool subProcessFailed (QProcess *, int exit_code, QProcess::ExitStatus);
void read_log();
};
extern void getfile(QString fname, bool xpol, int idInt);

View File

@ -90,6 +90,7 @@
#include "ExportCabrillo.h"
#include "ui_mainwindow.h"
#include "moc_mainwindow.cpp"
#include "Logger.hpp"
#define FCL fortran_charlen_t
@ -155,7 +156,7 @@ extern "C" {
void save_echo_params_(int* ndoptotal, int* ndop, int* nfrit, float* f1, float* fspread, short id2[], int* idir);
void avecho_( short id2[], int* dop, int* nfrit, int* nauto, int* nqual, float* f1,
void avecho_( short id2[], int* dop, int* nfrit, int* nauto, int* navg, int* nqual, float* f1,
float* level, float* sigdb, float* snr, float* dfreq,
float* width, bool* bDiskData);
@ -208,6 +209,8 @@ QVector<QColor> g_ColorTbl;
using SpecOp = Configuration::SpecialOperatingActivity;
bool m_displayBand = false;
bool no_a7_decodes = false;
bool keep_frequency = false;
namespace
{
@ -753,24 +756,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple,
}
});
// ensure a balanced layout of the mode buttons
qreal pointSize = m_config.text_font().pointSizeF();
if (pointSize < 11) {
ui->houndButton->setMaximumWidth(40);
ui->ft8Button->setMaximumWidth(40);
ui->ft4Button->setMaximumWidth(40);
ui->msk144Button->setMaximumWidth(40);
ui->q65Button->setMaximumWidth(40);
ui->jt65Button->setMaximumWidth(40);
} else {
ui->houndButton->setMinimumWidth(50);
ui->ft8Button->setMinimumWidth(50);
ui->ft4Button->setMinimumWidth(50);
ui->msk144Button->setMinimumWidth(50);
ui->q65Button->setMinimumWidth(50);
ui->jt65Button->setMinimumWidth(50);
}
// hook up save WAV file exit handling
connect (&m_saveWAVWatcher, &QFutureWatcher<QString>::finished, [this] {
// extract the promise from the future
@ -1224,6 +1209,7 @@ void MainWindow::writeSettings()
m_settings->setValue("Blanker",ui->sbNB->value());
m_settings->setValue("Score",m_score);
m_settings->setValue("labDXpedText",ui->labDXped->text());
m_settings->setValue("EchoAvg",ui->sbEchoAvg->value());
{
QList<QVariant> coeffs; // suitable for QSettings
@ -1357,6 +1343,7 @@ void MainWindow::readSettings()
ui->actionAuto_Clear_Avg->setChecked (m_settings->value ("AutoClearAvg", false).toBool());
ui->decodes_splitter->restoreState(m_settings->value("SplitterState").toByteArray());
ui->sbNB->setValue(m_settings->value("Blanker",0).toInt());
ui->sbEchoAvg->setValue(m_settings->value("EchoAvg",10).toInt());
{
auto const& coeffs = m_settings->value ("PhaseEqualizationCoefficients"
, QList<QVariant> {0., 0., 0., 0., 0.}).toList ();
@ -1374,6 +1361,7 @@ void MainWindow::readSettings()
m_audioThreadPriority = static_cast<QThread::Priority> (m_settings->value ("Audio/ThreadPriority", QThread::TimeCriticalPriority).toInt () % 8);
m_settings->endGroup ();
m_specOp=m_config.special_op_id();
checkMSK144ContestType();
if(displayMsgAvg) on_actionMessage_averaging_triggered();
if (displayFoxLog) on_fox_log_action_triggered ();
@ -1410,10 +1398,35 @@ void MainWindow::set_application_font (QFont const& font)
QFile sf {sheet};
if (sf.open (QFile::ReadOnly | QFile::Text))
{
ss = sf.readAll () + ss;
QString tmp = sf.readAll();
if (tmp != NULL) ss = sf.readAll () + tmp;
else qDebug() << "tmp==NULL at sf.readAll";
}
}
qApp->setStyleSheet (ss + "* {" + font_as_stylesheet (font) + '}');
// ensure a balanced layout of the mode buttons
qreal pointSize = m_config.text_font().pointSizeF();
if (pointSize < 11) {
ui->houndButton->setMaximumWidth(40);
ui->ft8Button->setMaximumWidth(40);
ui->ft4Button->setMaximumWidth(40);
ui->msk144Button->setMaximumWidth(40);
ui->q65Button->setMaximumWidth(40);
ui->jt65Button->setMaximumWidth(40);
ui->houndButton->setMinimumWidth(0);
ui->ft8Button->setMinimumWidth(0);
ui->ft4Button->setMinimumWidth(0);
ui->msk144Button->setMinimumWidth(0);
ui->q65Button->setMinimumWidth(0);
ui->jt65Button->setMinimumWidth(0);
} else {
ui->houndButton->setMinimumWidth(50);
ui->ft8Button->setMinimumWidth(50);
ui->ft4Button->setMinimumWidth(50);
ui->msk144Button->setMinimumWidth(50);
ui->q65Button->setMinimumWidth(50);
ui->jt65Button->setMinimumWidth(50);
}
for (auto& widget : qApp->topLevelWidgets ())
{
widget->updateGeometry ();
@ -1541,7 +1554,7 @@ void MainWindow::dataSink(qint64 frames)
if(m_ihsym <=0) return;
if(ui) ui->signal_meter_widget->setValue(m_px,m_pxmax); // Update thermometer
if(m_monitoring || m_diskData) {
m_wideGraph->dataSink2(s,m_df3,m_ihsym,m_diskData);
m_wideGraph->dataSink2(s,m_df3,m_ihsym,m_diskData,m_px);
}
if(m_mode=="MSK144") return;
@ -1616,11 +1629,12 @@ void MainWindow::dataSink(qint64 frames)
echocom_.nclearave=m_nclearave;
int nDop=m_fAudioShift;
int nDopTotal=m_fDop;
int navg=ui->sbEchoAvg->value();
if(m_diskData) {
int idir=-1;
save_echo_params_(&nDopTotal,&nDop,&nfrit,&f1,&width,dec_data.d2,&idir);
}
avecho_(dec_data.d2,&nDop,&nfrit,&nauto,&nqual,&f1,&xlevel,&sigdb,
avecho_(dec_data.d2,&nDop,&nfrit,&nauto,&navg,&nqual,&f1,&xlevel,&sigdb,
&dBerr,&dfreq,&width,&m_diskData);
//Don't restart Monitor after an Echo transmission
if(m_bEchoTxed and !m_auto) {
@ -1629,7 +1643,7 @@ void MainWindow::dataSink(qint64 frames)
}
if(m_monitoring or m_auto or m_diskData) {
QString t0;
QString t0,t1;
if(m_diskData) {
t0=t0.asprintf("%06d ",m_UTCdisk);
} else {
@ -1640,17 +1654,20 @@ void MainWindow::dataSink(qint64 frames)
if(m_auto) isec=isec - isec%6;
if(!m_auto) isec=isec - isec%3;
t0=t0.asprintf("%02d%02d%02d ",ihr,imin,isec);
t1=now.toString("yyMMdd_");
}
int n=t0.toInt();
int nsec=((n/10000)*3600) + (((n/100)%100)*60) + (n%100);
if(!m_echoRunning) m_echoSec0=nsec;
n=(nsec-m_echoSec0 + 864000)%86400;
if(!m_echoRunning or echocom_.nsum<2) m_echoSec0=nsec;
float hour=n/10000 + ((n/100)%100)/60.0 + (n%100)/3600.0;
m_echoRunning=true;
QString t;
t = t.asprintf("%6d %5.2f %7d %7.1f %7d %7d %7d %7.1f %7.1f",n,xlevel,
t = t.asprintf("%9.6f %5.2f %7d %7.1f %7d %7d %7d %7.1f %7.1f",hour,xlevel,
nDopTotal,width,echocom_.nsum,nqual,qRound(dfreq),sigdb,dBerr);
t = t0 + t;
if (ui) ui->decodedTextBrowser->appendText(t);
t=t1+t;
write_all("Rx",t);
}
if(m_echoGraph->isVisible()) m_echoGraph->plotSpec();
@ -3176,6 +3193,7 @@ void MainWindow::on_ClrAvgButton_clicked()
if(m_mode=="Echo") {
echocom_.nsum=0;
m_echoGraph->clearAvg();
m_wideGraph->restartTotalPower();
} else {
if(m_msgAvgWidget != NULL) {
if(m_msgAvgWidget->isVisible()) m_msgAvgWidget->displayAvg("");
@ -3682,6 +3700,10 @@ void MainWindow::readFromStdout() //readFromStdout
continue;
}
}
// Don't allow a7 decodes during the first period because they can be leftovers from the previous band
if (!(no_a7_decodes && line_read.contains("a7"))) {
if (m_mode!="FT8" and m_mode!="FT4" and !m_mode.startsWith ("FST4") and m_mode!="Q65") {
//Pad 22-char msg to at least 37 chars
line_read = line_read.left(44) + " " + line_read.mid(44);
@ -3748,6 +3770,7 @@ void MainWindow::readFromStdout() //readFromStdout
}
m_tBlankLine = line_read.left(ntime);
}
}
if ("FST4W" == m_mode)
{
uploadWSPRSpots (true, line_read);
@ -3797,7 +3820,8 @@ void MainWindow::readFromStdout() //readFromStdout
if (m_config.highlight_DXcall () && (m_hisCall!="") && ((decodedtext.string().contains(QRegularExpression {"(\\w+) " + m_hisCall}))
|| (decodedtext.string().contains(QRegularExpression {"(\\w+) <" + m_hisCall +">"}))
|| (decodedtext.string().contains(QRegularExpression {"<(\\w+)> " + m_hisCall})))) {
|| (decodedtext.string().contains(QRegularExpression {"<(\\w+)> " + m_hisCall}))
|| (decodedtext.string().contains(QRegularExpression {"<...> " + m_hisCall})))) {
ui->decodedTextBrowser->highlight_callsign(m_hisCall, QColor(255,0,0), QColor(255,255,255), true); // highlight dxCallEntry
QTimer::singleShot (500, [=] { // repeated highlighting to override JTAlert
ui->decodedTextBrowser->highlight_callsign(m_hisCall, QColor(255,0,0), QColor(255,255,255), true);
@ -4019,7 +4043,8 @@ void MainWindow::readFromStdout() //readFromStdout
if(f.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream s(&f);
QString t=s.readAll();
m_msgAvgWidget->displayAvg(t);
if (t != NULL) m_msgAvgWidget->displayAvg(t);
else qDebug() << "tmp==NULL at s.readAll";
}
}
}
@ -4119,7 +4144,7 @@ void MainWindow::pskPost (DecodedText const& decodedtext)
}
int snr = decodedtext.snr();
Frequency frequency = m_freqNominalPeriod + audioFrequency; // prevent spotting wrong band
if(grid.contains (grid_regexp)) {
if(grid.contains (grid_regexp) || decodedtext.string().contains(" CQ ")) {
// qDebug() << "To PSKreporter:" << deCall << grid << frequency << msgmode << snr;
if (!m_psk_Reporter.addRemoteStation (deCall, grid, frequency, msgmode, snr))
{
@ -6148,7 +6173,9 @@ void MainWindow::on_addButton_clicked() //Add button
// preserve symlinks
f1.open (QFile::WriteOnly | QFile::Text); // truncates
f2.seek (0);
f1.write (f2.readAll ()); // copy contents
QByteArray tmp = f2.readAll();
if (tmp != (const char*)NULL) f1.write (tmp); // copy contents
else qDebug() << "tmp==NULL at f1.write";
f2.remove ();
}
}
@ -6526,6 +6553,7 @@ void MainWindow::displayWidgets(qint64 n)
(m_config.RTTY_Exchange()=="DX" or m_config.RTTY_Exchange()=="#") );
}
if(m_mode=="MSK144") b=SpecOp::EU_VHF==m_specOp;
ui->sbEchoAvg->setVisible(m_mode=="Echo");
ui->sbSerialNumber->setVisible(b);
m_lastCallsign.clear (); // ensures Tx5 is updated for new modes
b=m_mode.startsWith("FST4");
@ -6634,6 +6662,7 @@ void MainWindow::on_actionFT4_triggered()
m_wideGraph->setMode(m_mode);
m_send_RR73=true;
VHF_features_enabled(bVHF);
ui->cbAutoSeq->setChecked(true);
m_fastGraph->hide();
m_wideGraph->show();
ui->rh_decodes_headings_label->setText(" UTC dB DT Freq " + tr ("Message"));
@ -6740,7 +6769,7 @@ void MainWindow::on_actionFT8_triggered()
ui->txb5->setEnabled(false);
ui->txb6->setEnabled(false);
} else {
switch_mode (Modes::FT8);
if (!(keep_frequency)) switch_mode (Modes::FT8);
}
if(m_specOp != SpecOp::HOUND) {
@ -6951,6 +6980,7 @@ void MainWindow::on_actionQ65_triggered()
m_mode="Q65";
ui->actionQ65->setChecked(true);
switch_mode(Modes::Q65);
ui->cbAutoSeq->setChecked(true);
fast_config(false);
WSPR_config(false);
setup_status_bar(true);
@ -7032,6 +7062,7 @@ void MainWindow::on_actionMSK144_triggered()
m_toneSpacing=0.0;
WSPR_config(false);
VHF_features_enabled(true);
ui->cbAutoSeq->setChecked(true);
m_bFastMode=true;
m_bFast9=false;
ui->sbTR->values ({5, 10, 15, 30});
@ -7108,7 +7139,13 @@ void MainWindow::on_actionWSPR_triggered()
void MainWindow::on_actionEcho_triggered()
{
int nd=int(m_ndepth&3);
on_actionJT4_triggered();
// Don't allow decoding depth to be changed just because Echo mode was entered:
if(nd==1) ui->actionQuickDecode->setChecked (true);
if(nd==2) ui->actionMediumDecode->setChecked (true);
if(nd==3) ui->actionDeepestDecode->setChecked (true);
m_mode="Echo";
ui->actionEcho->setChecked(true);
m_TRperiod=3.0;
@ -7131,11 +7168,11 @@ void MainWindow::on_actionEcho_triggered()
m_bFastMode=false;
m_bFast9=false;
WSPR_config(true);
ui->lh_decodes_headings_label->setText(" UTC Tsec Level Doppler Width N Q DF SNR dBerr");
ui->lh_decodes_headings_label->setText(" UTC Hour Level Doppler Width N Q DF SNR dBerr");
// 01234567890123456789012345678901234567
displayWidgets(nWidgets("00000000000000000010001000000000000000"));
fast_config(false);
if(m_astroWidget) m_astroWidget->selectOwnEcho();
ui->sbEchoAvg->values ({1, 2, 5, 10, 20, 50, 100});
statusChanged();
monitor(false);
}
@ -7455,6 +7492,10 @@ void MainWindow::on_bandComboBox_activated (int index)
void MainWindow::band_changed (Frequency f)
{
// Don't allow a7 decodes during the first period because they can be leftovers from the previous band
no_a7_decodes = true;
QTimer::singleShot ((int(1500.0*m_TRperiod)), [=] {no_a7_decodes = false;});
// Set the attenuation value if options are checked
if (m_config.pwrBandTxMemory() && !m_tune) {
auto const&curBand = ui->bandComboBox->currentText();
@ -7991,7 +8032,7 @@ void MainWindow::on_outAttenuation_valueChanged (int a)
tt_str = tr ("Transmit digital gain ");
}
tt_str += (a ? QString::number (-dBAttn, 'f', 1) : "0") + "dB";
if (!m_block_pwr_tooltip) {
if (ui->outAttenuation->hasFocus() && !m_block_pwr_tooltip) {
QToolTip::showText (QCursor::pos (), tt_str, ui->outAttenuation);
}
QString curBand = ui->bandComboBox->currentText();
@ -9734,45 +9775,55 @@ void MainWindow::write_all(QString txRx, QString message)
QString t;
QString msg;
QString mode_string;
if (message.size () > 5 && message[4]==' ') {
msg=message.mid(4,-1);
} else {
msg=message.mid(6,-1);
}
if (message.size () > 19 && message[19]=='#') {
mode_string="JT65 ";
} else if (message.size () > 19 && message[19]=='@') {
mode_string="JT9 ";
} else if(m_mode=="Q65") {
mode_string=mode_label.text();
} else {
mode_string=m_mode.leftJustified(6,' ');
}
msg=msg.mid(0,15) + msg.mid(18,-1);
t = t.asprintf("%5d",ui->TxFreqSpinBox->value());
if (txRx=="Tx") msg=" 0 0.0" + t + " " + message;
auto time = QDateTime::currentDateTimeUtc ();
if( txRx=="Rx" && !m_bFastMode ) time=m_dateTimeSeqStart;
t = t.asprintf("%10.3f ",m_freqNominalPeriod/1.e6); // prevent writing of wrong frequencies
if (m_diskData) {
if (m_fileDateTime.size()==11) {
line=m_fileDateTime + " " + t + txRx + " " + mode_string + msg;
} else {
line=m_fileDateTime + t + txRx + " " + mode_string + msg;
}
} else {
line=time.toString("yyMMdd_hhmmss") + t + txRx + " " + mode_string + msg;
}
QString file_name="ALL.TXT";
if (ui->actionSplit_ALL_TXT_yearly->isChecked()) file_name=(time.toString("yyyy") + "-" + "ALL.TXT");
if (ui->actionSplit_ALL_TXT_monthly->isChecked()) file_name=(time.toString("yyyy-MM") + "-" + "ALL.TXT");
if (m_mode=="WSPR") file_name="ALL_WSPR.TXT";
if(m_mode!="Echo") {
if (message.size () > 5 && message[4]==' ') {
msg=message.mid(4,-1);
} else {
msg=message.mid(6,-1);
}
if (message.size () > 19 && message[19]=='#') {
mode_string="JT65 ";
} else if (message.size () > 19 && message[19]=='@') {
mode_string="JT9 ";
} else if(m_mode=="Q65") {
mode_string=mode_label.text();
} else {
mode_string=m_mode.leftJustified(6,' ');
}
msg=msg.mid(0,15) + msg.mid(18,-1);
t = t.asprintf("%5d",ui->TxFreqSpinBox->value());
if (txRx=="Tx") msg=" 0 0.0" + t + " " + message;
auto time = QDateTime::currentDateTimeUtc ();
if( txRx=="Rx" && !m_bFastMode ) time=m_dateTimeSeqStart;
if (txRx=="Rx") {
t = t.asprintf("%10.3f ",m_freqNominalPeriod/1.e6); // prevent writing of wrong frequencies
} else {
t = t.asprintf("%10.3f ",m_freqNominal/1.e6);
}
if (m_diskData) {
if (m_fileDateTime.size()==11) {
line=m_fileDateTime + " " + t + txRx + " " + mode_string + msg;
} else {
line=m_fileDateTime + t + txRx + " " + mode_string + msg;
}
} else {
line=time.toString("yyMMdd_hhmmss") + t + txRx + " " + mode_string + msg;
}
if (ui->actionSplit_ALL_TXT_yearly->isChecked()) file_name=(time.toString("yyyy") + "-" + "ALL.TXT");
if (ui->actionSplit_ALL_TXT_monthly->isChecked()) file_name=(time.toString("yyyy-MM") + "-" + "ALL.TXT");
if (m_mode=="WSPR") file_name="ALL_WSPR.TXT";
} else {
file_name="all_echo.txt";
line=message;
}
QFile f{m_config.writeable_data_dir().absoluteFilePath(file_name)};
if (f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append)) {
QTextStream out(&f);
@ -9966,6 +10017,8 @@ void MainWindow::on_houndButton_clicked (bool checked)
} else {
ui->houndButton->setStyleSheet("");
m_config.setSpecial_None();
keep_frequency = true;
QTimer::singleShot (250, [=] {keep_frequency = false;});
}
m_specOp=m_config.special_op_id();
on_actionFT8_triggered();
@ -10025,26 +10078,3 @@ void MainWindow::on_jt65Button_clicked()
}
on_actionJT65_triggered();
}
void MainWindow::on_actionCopy_to_WSJTX_txt_triggered()
{
static QFile f {QDir {QStandardPaths::writableLocation (QStandardPaths::DataLocation)}.absoluteFilePath ("WSJT-X.txt")};
if(!f.open(QIODevice::Text | QIODevice::WriteOnly)) {
MessageBox::warning_message (this, tr ("WSJT-X.txt file error"),
tr ("Cannot open \"%1\" for writing").arg (f.fileName ()),
tr ("Error: %1").arg (f.errorString ()));
} else {
QString t=ui->decodedTextBrowser->toPlainText();
QTextStream out(&f);
out << t <<
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
endl
#else
Qt::endl
#endif
;
f.close();
}
}

View File

@ -173,7 +173,6 @@ private slots:
void on_actionOpen_next_in_directory_triggered();
void on_actionDecode_remaining_files_in_directory_triggered();
void on_actionDelete_all_wav_files_in_SaveDir_triggered();
void on_actionCopy_to_WSJTX_txt_triggered();
void on_actionOpen_log_directory_triggered ();
void on_actionNone_triggered();
void on_actionSave_all_triggered();

File diff suppressed because it is too large Load Diff

View File

@ -100,7 +100,6 @@ void CPlotter::resizeEvent(QResizeEvent* ) //resizeEvent()
if(m_bReference) m_h2=m_h-30;
if(m_h2<1) m_h2=1;
m_h1=m_h-m_h2;
// m_line=0;
m_2DPixmap = QPixmap(m_Size.width(), m_h2);
m_2DPixmap.fill(Qt::black);
m_WaterfallPixmap = QPixmap(m_Size.width(), m_h1);
@ -112,6 +111,8 @@ void CPlotter::resizeEvent(QResizeEvent* ) //resizeEvent()
m_ScalePixmap.fill(Qt::white);
m_Percent2DScreen0 = m_Percent2DScreen;
m_bResized = true;
m_vpixperdiv = float(m_h2)/float(VERT_DIVS);
m_x=0;
}
DrawOverlay();
}
@ -167,6 +168,8 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed)
static QPoint LineBuf[MAX_SCREENSIZE];
static QPoint LineBuf2[MAX_SCREENSIZE];
static QPoint LineBuf3[MAX_SCREENSIZE];
static QPoint LineBuf4[MAX_SCREENSIZE];
j=0;
j0=int(m_startFreq/m_fftBinWidth + 0.5);
int iz=XfromFreq(5000.0);
@ -231,7 +234,7 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed)
}
if(i==iz-1 and !m_bQ65_Sync) {
if(i==iz-1 and !m_bQ65_Sync and !m_bTotalPower) {
painter2D.drawPolyline(LineBuf,j);
}
LineBuf[j].setX(i);
@ -320,6 +323,22 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed)
painter2D.drawText(m_w-100,m_h2/2,t);
}
}
if(m_bTotalPower and m_pdB>1.0) {
painter2D.setPen(Qt::green);
if(m_x==m_w-1) {
for (int i=0; i<m_w-1; i++) {
LineBuf4[i].setY(LineBuf4[i+1].y());
}
}
int yy=m_h2 - 0.1*m_vpixperdiv*(m_pdB-20.0);
LineBuf4[m_x].setX(m_x);
LineBuf4[m_x].setY(yy);
if(LineBuf4[m_w-1].y()==0) LineBuf4[m_w-1].setY(yy);
painter2D.drawPolyline(LineBuf4,m_x);
if(m_x < m_w-1) m_x++;
}
update(); //trigger a new paintEvent
m_bScaleOK=true;
}
@ -333,6 +352,7 @@ void CPlotter::drawRed(int ia, int ib, float swide[])
void CPlotter::replot()
{
resizeEvent(NULL);
float swide[m_w];
m_bReplot=true;
for(int irow=0; irow<m_h1; irow++) {
@ -369,7 +389,6 @@ void CPlotter::DrawOverlay() //DrawOverlay()
painter.setBrush(Qt::SolidPattern);
m_fSpan = w*df;
// int n=m_fSpan/10;
m_freqPerDiv=10;
if(m_fSpan>100) m_freqPerDiv=20;
if(m_fSpan>250) m_freqPerDiv=50;
@ -377,25 +396,48 @@ void CPlotter::DrawOverlay() //DrawOverlay()
if(m_fSpan>1000) m_freqPerDiv=200;
if(m_fSpan>2500) m_freqPerDiv=500;
pixperdiv = m_freqPerDiv/df;
m_hdivs = w*df/m_freqPerDiv + 1.9999;
float xx0=float(m_startFreq)/float(m_freqPerDiv);
xx0=xx0-int(xx0);
int x0=xx0*pixperdiv+0.5;
for( int i=1; i<m_hdivs; i++) { //draw vertical grids
x = (int)((float)i*pixperdiv ) - x0;
if(x >= 0 and x<=m_w) {
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
painter.drawLine(x, 0, x , m_h2);
if(!m_bTotalPower) {
pixperdiv = m_freqPerDiv/df;
m_hdivs = w*df/m_freqPerDiv + 1.9999;
float xx0=float(m_startFreq)/float(m_freqPerDiv);
xx0=xx0-int(xx0);
int x0=xx0*pixperdiv+0.5;
for( int i=1; i<m_hdivs; i++) { //draw vertical grids
x = (int)((float)i*pixperdiv ) - x0;
if(x >= 0 and x<=m_w) {
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
painter.drawLine(x, 0, x , m_h2);
}
}
}
pixperdiv = (float)m_h2 / (float)VERT_DIVS;
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
for( int i=1; i<VERT_DIVS; i++) { //draw horizontal grids
y = (int)( (float)i*pixperdiv );
painter.drawLine(0, y, w, y);
if(m_bTotalPower) painter.setPen(QPen(Qt::white, 1,Qt::DashLine));
for( int i=1; i<VERT_DIVS; i++) { //draw horizontal grids
y = int(i*m_vpixperdiv);
if(m_bTotalPower) {
painter.drawLine(15, y, w, y);
} else {
painter.drawLine(0, y, w, y);
}
}
if(m_bTotalPower) {
painter.setPen(QPen(Qt::white));
for( int i=1; i<VERT_DIVS; i++) { //draw horizontal grids
y = int(i*m_vpixperdiv);
painter.drawText(0,y+5,QString::number(10*(VERT_DIVS-i) + 20));
}
}
if(m_bTotalPower and m_h2>100) {
painter.setPen(QPen(Qt::white, 1,Qt::DotLine));
for( int i=1; i<5*VERT_DIVS; i++) { //draw horizontal 2 dB grids
if(i%5 > 0) {
y = int(0.2*i*m_vpixperdiv);
painter.drawLine(0, y, w, y);
}
}
}
QRect rect0;
@ -730,7 +772,15 @@ int CPlotter::rxFreq() {return m_rxFreq;} //rxFreq
void CPlotter::mouseMoveEvent (QMouseEvent * event)
{
int x=event->x();
QToolTip::showText(event->globalPos(),QString::number(int(FreqfromX(x))));
int y=event->y();
float pdB=10.0*(m_h-y)/m_vpixperdiv + 20.0;
if(y<(m_h-m_h2)) {
QToolTip::showText(event->globalPos(),QString::number(int(FreqfromX(x))));
} else {
QString t;
t=t.asprintf("%4.1f dB",pdB);
QToolTip::showText(event->globalPos(),t);
}
QWidget::mouseMoveEvent(event);
}
@ -874,3 +924,13 @@ void CPlotter::setDiskUTC(int nutc)
{
m_nUTC=nutc;
}
void CPlotter::drawTotalPower(float pdB)
{
m_pdB=pdB;
}
void CPlotter::restartTotalPower()
{
m_x=0;
}

View File

@ -34,6 +34,7 @@ public:
QSize sizeHint() const Q_DECL_OVERRIDE;
void draw(float swide[], bool bScroll, bool bRed); //Update the waterfall
void drawTotalPower(float pdB);
void replot();
void SetRunningState(bool running);
void setPlotZero(int plotZero);
@ -81,12 +82,15 @@ public:
bool Reference() const {return m_bReference;}
void setQ65_Sync(bool b) {m_bQ65_Sync = b;}
bool Q65_Sync() const {return m_bQ65_Sync;}
void setTotalPower(bool b) {m_bTotalPower = b;}
bool TotalPower() const {return m_bTotalPower;}
void drawRed(int ia, int ib, float swide[]);
void setVHF(bool bVHF);
void setRedFile(QString fRed);
void setFST4_FreqRange(int fLow,int fHigh);
void setSingleDecode(bool b);
void setDiskUTC(int nutc);
void restartTotalPower();
bool scaleOK () const {return m_bScaleOK;}
signals:
@ -116,12 +120,15 @@ private:
bool m_bReference;
bool m_bReference0;
bool m_bQ65_Sync;
bool m_bTotalPower;
bool m_bVHF;
bool m_bSingleDecode;
bool m_bFirst=true;
bool m_bResized;
float m_fSpan;
float m_pdB=0.0;
float m_vpixperdiv;
qint32 m_plotZero;
qint32 m_plotGain;
@ -137,6 +144,7 @@ private:
qint32 m_nfa;
qint32 m_nfb;
qint32 m_nUTC;
qint32 m_x=0;
QPixmap m_WaterfallPixmap;
QPixmap m_2DPixmap;

View File

@ -71,11 +71,13 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) :
ui->widePlot->setLinearAvg(m_settings->value("LinearAvg",false).toBool());
ui->widePlot->setReference(m_settings->value("Reference",false).toBool());
ui->widePlot->setQ65_Sync(m_settings->value("Q65_Sync",false).toBool());
ui->widePlot->setTotalPower(m_settings->value("TotalPower",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);
if(ui->widePlot->Q65_Sync()) ui->spec2dComboBox->setCurrentIndex(4);
if(ui->widePlot->TotalPower()) ui->spec2dComboBox->setCurrentIndex(5);
int nbpp=m_settings->value("BinsPerPixel",2).toInt();
ui->widePlot->setBinsPerPixel(nbpp);
ui->sbPercent2dPlot->setValue(m_Percent2DScreen);
@ -133,6 +135,7 @@ void WideGraph::saveSettings() //saveS
m_settings->setValue ("LinearAvg", ui->widePlot->linearAvg());
m_settings->setValue ("Reference", ui->widePlot->Reference());
m_settings->setValue ("Q65_Sync", ui->widePlot->Q65_Sync());
m_settings->setValue ("TotalPower", ui->widePlot->TotalPower());
m_settings->setValue ("BinsPerPixel", ui->widePlot->binsPerPixel ());
m_settings->setValue ("StartFreq", ui->widePlot->startFreq ());
m_settings->setValue ("WaterfallPalette", m_waterfallPalette);
@ -148,11 +151,12 @@ void WideGraph::drawRed(int ia, int ib)
ui->widePlot->drawRed(ia,ib,m_swide);
}
void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dataSink2
void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata, float pdB) //dataSink2
{
static float splot[NSMAX];
int nbpp = ui->widePlot->binsPerPixel();
if(ui->widePlot->TotalPower()) ui->widePlot->drawTotalPower(pdB);
//Average spectra over specified number, m_waterfallAvg
if (m_n==0) {
for (int i=0; i<NSMAX; i++)
@ -313,6 +317,7 @@ void WideGraph::on_spec2dComboBox_currentIndexChanged(int index)
ui->widePlot->setLinearAvg(false);
ui->widePlot->setReference(false);
ui->widePlot->setQ65_Sync(false);
ui->widePlot->setTotalPower(false);
ui->smoSpinBox->setEnabled(false);
switch (index)
{
@ -332,7 +337,10 @@ void WideGraph::on_spec2dComboBox_currentIndexChanged(int index)
case 4:
ui->widePlot->setQ65_Sync(true);
break;
}
case 5:
ui->widePlot->setTotalPower(true);
break;
}
replot();
}
@ -473,6 +481,7 @@ void WideGraph::on_zeroSlider_valueChanged(int value) //Zero
void WideGraph::on_gain2dSlider_valueChanged(int value) //Gain2
{
ui->widePlot->setPlot2dGain(value);
if(ui->widePlot->TotalPower()) return;
if(ui->widePlot->scaleOK ()) {
ui->widePlot->draw(m_swide,false,false);
if(m_mode=="Q65") ui->widePlot->draw(m_swide,false,true);
@ -482,6 +491,7 @@ void WideGraph::on_gain2dSlider_valueChanged(int value) //Gain2
void WideGraph::on_zero2dSlider_valueChanged(int value) //Zero2
{
ui->widePlot->setPlot2dZero(value);
if(ui->widePlot->TotalPower()) return;
if(ui->widePlot->scaleOK ()) {
ui->widePlot->draw(m_swide,false,false);
if(m_mode=="Q65") ui->widePlot->draw(m_swide,false,true);
@ -540,3 +550,8 @@ void WideGraph::setDiskUTC(int nutc)
{
ui->widePlot->setDiskUTC(nutc);
}
void WideGraph::restartTotalPower()
{
ui->widePlot->restartTotalPower();
}

View File

@ -26,7 +26,7 @@ public:
explicit WideGraph(QSettings *, QWidget *parent = 0);
~WideGraph ();
void dataSink2(float s[], float df3, int ihsym, int ndiskdata);
void dataSink2(float s[], float df3, int ihsym, int ndiskdata, float pdB);
void setRxFreq(int n);
int rxFreq();
int nStartFreq();
@ -51,6 +51,7 @@ public:
void setFST4_FreqRange(int fLow,int fHigh);
void setSingleDecode(bool b);
void setDiskUTC(int nutc);
void restartTotalPower();
signals:
void freezeDecode2(int n);

View File

@ -340,6 +340,11 @@
<string>Q65_Sync</string>
</property>
</item>
<item>
<property name="text">
<string>Total power (dB)</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2">