diff --git a/Audio/tools/record_time_signal.cpp b/Audio/tools/record_time_signal.cpp index 8cd4f8ee1..6a78a0a2c 100644 --- a/Audio/tools/record_time_signal.cpp +++ b/Audio/tools/record_time_signal.cpp @@ -101,21 +101,22 @@ class Playback final Q_OBJECT; public: - Playback (int start, BWFFile * input, QAudioDeviceInfo const& sink_device, int notify_interval, int buffer_size) + Playback (int start, BWFFile * input, QAudioDeviceInfo const& sink_device, int notify_interval, int buffer_size, QString const& category) : input_ {input} , sink_ {sink_device, input->format ()} , notify_interval_ {notify_interval} { if (buffer_size) sink_.setBufferSize (input_->format ().bytesForFrames (buffer_size)); + if (category.size ()) sink_.setCategory (category); if (notify_interval_) { sink_.setNotifyInterval (notify_interval); connect (&sink_, &QAudioOutput::notify, this, &Playback::notify); } + connect (&sink_, &QAudioOutput::stateChanged, this, &Playback::sink_state_changed); if (start == -1) { start_playback (); - } else { @@ -136,7 +137,6 @@ private: qtout << "started playback at " << QDateTime::currentDateTimeUtc ().toString ("hh:mm:ss.zzz UTC") << endl; sink_.start (input_); qtout << QString {"buffer size used is: %1 (%2 frames)"}.arg (sink_.bufferSize ()).arg (sink_.format ().framesForBytes (sink_.bufferSize ())) << endl; - connect (&sink_, &QAudioOutput::stateChanged, this, &Playback::sink_state_changed); } Q_SLOT void notify () @@ -160,6 +160,7 @@ private: break; case QAudio::IdleState: stop_playback (); + qtout << "\naudio output state changed to idle\n"; break; #if QT_VERSION >= QT_VERSION_CHECK (5, 10, 0) case QAudio::InterruptedState: @@ -239,6 +240,9 @@ int main(int argc, char *argv[]) {{"P", "playback-device-number"}, app.translate ("main", "Playback to "), app.translate ("main", "device-number")}, + {{"C", "category"}, + app.translate ("main", "Playback "), + app.translate ("main", "category-name")}, {{"n", "notify-interval"}, app.translate ("main", "use notify signals every milliseconds, zero to use a timer"), app.translate ("main", "interval")}, @@ -276,6 +280,7 @@ int main(int argc, char *argv[]) { start = parser.value ("s").toInt (&ok); if (!ok) throw std::invalid_argument {"start time not a number"}; + if (0 > start || start > 59) throw std::invalid_argument {"0 > start > 59"}; } int sample_rate {48000}; if (parser.isSet ("r")) @@ -344,7 +349,7 @@ int main(int argc, char *argv[]) audio_format.setSampleType (QAudioFormat::SignedInt); audio_format.setCodec ("audio/pcm"); - auto source = input_device ? input_devices[input_device] : QAudioDeviceInfo::defaultInputDevice (); + auto source = input_device ? input_devices[input_device - 1] : QAudioDeviceInfo::defaultInputDevice (); if (!source.isFormatSupported (audio_format)) { qtout << "warning, requested format not supported, using nearest" << endl; @@ -367,14 +372,14 @@ int main(int argc, char *argv[]) } BWFFile input_file {audio_format, ifi.filePath ()}; if (!input_file.open (BWFFile::ReadOnly)) throw std::invalid_argument {QString {"cannot open input file \"%1\""}.arg (ifi.filePath ()).toStdString ()}; - auto sink = output_device ? output_devices[output_device] : QAudioDeviceInfo::defaultOutputDevice (); + auto sink = output_device ? output_devices[output_device - 1] : QAudioDeviceInfo::defaultOutputDevice (); if (!sink.isFormatSupported (input_file.format ())) { throw std::invalid_argument {"audio output device does not support input file audio format"}; } // run the application - Playback play {start, &input_file, sink, notify_interval, buffer_size}; + Playback play {start, &input_file, sink, notify_interval, buffer_size, parser.value ("category")}; QObject::connect (&play, &Playback::done, &app, &QCoreApplication::quit); return app.exec(); } diff --git a/CMakeLists.txt b/CMakeLists.txt index eb8ece5ac..a8093b100 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -383,9 +383,11 @@ set (wsjt_FSRCS lib/astro0.f90 lib/avecho.f90 lib/averms.f90 + lib/ft4/averaged_mf.f90 lib/azdist.f90 lib/badmsg.f90 lib/ft8/baseline.f90 + lib/ft4/ft4_baseline.f90 lib/bpdecode40.f90 lib/bpdecode128_90.f90 lib/ft8/bpdecode174_91.f90 @@ -564,7 +566,6 @@ set (wsjt_FSRCS lib/sync64.f90 lib/sync65.f90 lib/ft4/getcandidates4.f90 - lib/ft4/syncft4.f90 lib/ft8/sync8.f90 lib/ft8/sync8d.f90 lib/ft4/sync4d.f90 @@ -1283,6 +1284,9 @@ target_link_libraries (msk144sim wsjt_fort wsjt_cxx) add_executable (ft4sim lib/ft4/ft4sim.f90 wsjtx.rc) target_link_libraries (ft4sim wsjt_fort wsjt_cxx) +add_executable (averaged_mf lib/ft4/averaged_mf.f90 wsjtx.rc) +target_link_libraries (averaged_mf wsjt_fort wsjt_cxx) + add_executable (ft4sim_mult lib/ft4/ft4sim_mult.f90 wsjtx.rc) target_link_libraries (ft4sim_mult wsjt_fort wsjt_cxx) diff --git a/Configuration.cpp b/Configuration.cpp index cce8db23c..5526a1ec4 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -609,6 +609,7 @@ private: bool miles_; bool quick_call_; bool disable_TX_on_73_; + bool force_call_1st_; bool alternate_bindings_; int watchdog_; bool TX_messages_; @@ -705,6 +706,7 @@ bool Configuration::clear_DX () const {return m_->clear_DX_;} bool Configuration::miles () const {return m_->miles_;} bool Configuration::quick_call () const {return m_->quick_call_;} bool Configuration::disable_TX_on_73 () const {return m_->disable_TX_on_73_;} +bool Configuration::force_call_1st() const {return m_->force_call_1st_;} bool Configuration::alternate_bindings() const {return m_->alternate_bindings_;} int Configuration::watchdog () const {return m_->watchdog_;} bool Configuration::TX_messages () const {return m_->TX_messages_;} @@ -1242,6 +1244,7 @@ void Configuration::impl::initialize_models () ui_->miles_check_box->setChecked (miles_); ui_->quick_call_check_box->setChecked (quick_call_); ui_->disable_TX_on_73_check_box->setChecked (disable_TX_on_73_); + ui_->force_call_1st_check_box->setChecked (force_call_1st_); ui_->alternate_bindings_check_box->setChecked (alternate_bindings_); ui_->tx_watchdog_spin_box->setValue (watchdog_); ui_->TX_messages_check_box->setChecked (TX_messages_); @@ -1496,6 +1499,7 @@ void Configuration::impl::read_settings () miles_ = settings_->value ("Miles", false).toBool (); quick_call_ = settings_->value ("QuickCall", false).toBool (); disable_TX_on_73_ = settings_->value ("73TxDisable", false).toBool (); + force_call_1st_ = settings_->value ("ForceCallFirst", false).toBool (); alternate_bindings_ = settings_->value ("AlternateBindings", false).toBool (); watchdog_ = settings_->value ("TxWatchdog", 6).toInt (); TX_messages_ = settings_->value ("Tx2QSO", true).toBool (); @@ -1598,6 +1602,7 @@ void Configuration::impl::write_settings () settings_->setValue ("Miles", miles_); settings_->setValue ("QuickCall", quick_call_); settings_->setValue ("73TxDisable", disable_TX_on_73_); + settings_->setValue ("ForceCallFirst", force_call_1st_); settings_->setValue ("AlternateBindings", alternate_bindings_); settings_->setValue ("TxWatchdog", watchdog_); settings_->setValue ("Tx2QSO", TX_messages_); @@ -2042,6 +2047,7 @@ void Configuration::impl::accept () miles_ = ui_->miles_check_box->isChecked (); quick_call_ = ui_->quick_call_check_box->isChecked (); disable_TX_on_73_ = ui_->disable_TX_on_73_check_box->isChecked (); + force_call_1st_ = ui_->force_call_1st_check_box->isChecked (); alternate_bindings_ = ui_->alternate_bindings_check_box->isChecked (); watchdog_ = ui_->tx_watchdog_spin_box->value (); TX_messages_ = ui_->TX_messages_check_box->isChecked (); diff --git a/Configuration.hpp b/Configuration.hpp index 991e126fb..0ed7a4057 100644 --- a/Configuration.hpp +++ b/Configuration.hpp @@ -127,6 +127,7 @@ public: bool miles () const; bool quick_call () const; bool disable_TX_on_73 () const; + bool force_call_1st() const; bool alternate_bindings() const; int watchdog () const; bool TX_messages () const; diff --git a/Configuration.ui b/Configuration.ui index 9701fb633..9e36e7ee1 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -301,7 +301,14 @@ Behavior - + + + + Decode after EME delay + + + + @@ -347,10 +354,27 @@ - - + + - Decode after EME delay + Enable VHF/UHF/Microwave features + + + + + + + Single decode + + + + + + + <html><head/><body><p>Some rigs are not able to process CAT commands while transmitting. This means that if you are operating in split mode you may have to uncheck this option.</p></body></html> + + + Allow Tx frequency changes while transmitting @@ -367,31 +391,35 @@ - - - - Single decode - - - - - - - Enable VHF/UHF/Microwave features - - - - - + + - <html><head/><body><p>Some rigs are not able to process CAT commands while transmitting. This means that if you are operating in split mode you may have to uncheck this option.</p></body></html> + <html><head/><body><p>Check this if you wish to automatically return to the last monitored frequency when monitor is enabled, leave it unchecked if you wish to have the current rig frequency maintained.</p></body></html> - Allow Tx frequency changes while transmitting + Monitor returns to last used frequency - + + + + Alternate F1-F6 bindings + + + + + + + Turns off automatic transmissions after sending a 73 or any other free +text message. + + + Di&sable Tx after sending 73 + + + + @@ -444,34 +472,6 @@ quiet period when decoding is done. - - - - <html><head/><body><p>Check this if you wish to automatically return to the last monitored frequency when monitor is enabled, leave it unchecked if you wish to have the current rig frequency maintained.</p></body></html> - - - Monitor returns to last used frequency - - - - - - - Alternate F1-F6 bindings - - - - - - - Turns off automatic transmissions after sending a 73 or any other free -text message. - - - Di&sable Tx after sending 73 - - - @@ -482,6 +482,13 @@ text message. + + + + Calling CQ forces Call 1st + + + @@ -3078,13 +3085,13 @@ Right click for insert and delete options. + + - - - - + + diff --git a/Detector.cpp b/Detector.cpp index 69a10f5e8..05a631b13 100644 --- a/Detector.cpp +++ b/Detector.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "commons.h" #include "moc_Detector.cpp" @@ -10,7 +11,7 @@ extern "C" { void fil4_(qint16*, qint32*, qint16*, qint32*); } -Detector::Detector (unsigned frameRate, unsigned periodLengthInSeconds, +Detector::Detector (unsigned frameRate, double periodLengthInSeconds, unsigned downSampleFactor, QObject * parent) : AudioDevice (parent) , m_frameRate (frameRate) @@ -54,12 +55,14 @@ void Detector::clear () qint64 Detector::writeData (char const * data, qint64 maxSize) { - int ns=secondInPeriod(); - if(ns < m_ns) { // When ns has wrapped around to zero, restart the buffers + static unsigned mstr0=999999; + qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000; + unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time + if(mstr < mstr0) { //When mstr has wrapped around to 0, restart the buffer dec_data.params.kin = 0; m_bufferPos = 0; } - m_ns=ns; + mstr0=mstr; // no torn frames Q_ASSERT (!(maxSize % static_cast (bytesPerFrame ()))); @@ -72,7 +75,7 @@ qint64 Detector::writeData (char const * data, qint64 maxSize) if (framesAccepted < static_cast (maxSize / bytesPerFrame ())) { qDebug () << "dropped " << maxSize / bytesPerFrame () - framesAccepted << " frames of data on the floor!" - << dec_data.params.kin << ns; + << dec_data.params.kin << mstr; } for (unsigned remaining = framesAccepted; remaining; ) { @@ -120,13 +123,3 @@ qint64 Detector::writeData (char const * data, qint64 maxSize) return maxSize; // we drop any data past the end of the buffer on // the floor until the next period starts } - -unsigned Detector::secondInPeriod () const -{ - // we take the time of the data as the following assuming no latency - // delivering it to us (not true but close enough for us) - qint64 now (QDateTime::currentMSecsSinceEpoch ()); - - unsigned secondInToday ((now % 86400000LL) / 1000); - return secondInToday % m_period; -} diff --git a/Detector.hpp b/Detector.hpp index d5e5b0a38..4d584c130 100644 --- a/Detector.hpp +++ b/Detector.hpp @@ -22,9 +22,10 @@ public: // // the samplesPerFFT argument is the number after down sampling // - Detector (unsigned frameRate, unsigned periodLengthInSeconds, unsigned downSampleFactor = 4u, QObject * parent = 0); + Detector (unsigned frameRate, double periodLengthInSeconds, unsigned downSampleFactor = 4u, + QObject * parent = 0); - void setTRPeriod(unsigned p) {m_period=p;} + void setTRPeriod(double p) {m_period=p;} bool reset () override; Q_SIGNAL void framesWritten (qint64) const; @@ -40,10 +41,9 @@ protected: private: void clear (); // discard buffer contents - unsigned secondInPeriod () const; unsigned m_frameRate; - unsigned m_period; + double m_period; unsigned m_downSampleFactor; qint32 m_samplesPerFFT; // after any down sampling qint32 m_ns; diff --git a/Modulator.cpp b/Modulator.cpp index 725de9e42..4d0171770 100644 --- a/Modulator.cpp +++ b/Modulator.cpp @@ -25,15 +25,15 @@ double constexpr Modulator::m_twoPi; // unsigned m_nspd=1.2*48000.0/wpm; // m_nspd=3072; //18.75 WPM -Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, +Modulator::Modulator (unsigned frameRate, double periodLengthInSeconds, QObject * parent) : AudioDevice {parent} , m_quickClose {false} , m_phi {0.0} , m_toneSpacing {0.0} , m_fSpread {0.0} - , m_frameRate {frameRate} , m_period {periodLengthInSeconds} + , m_frameRate {frameRate} , m_state {Idle} , m_tuning {false} , m_cwLevel {false} @@ -45,19 +45,15 @@ Modulator::Modulator (unsigned frameRate, unsigned periodLengthInSeconds, void Modulator::start (unsigned symbolsLength, double framesPerSymbol, double frequency, double toneSpacing, SoundOutput * stream, Channel channel, - bool synchronize, bool fastMode, double dBSNR, int TRperiod) + bool synchronize, bool fastMode, double dBSNR, double TRperiod) { Q_ASSERT (stream); // Time according to this computer which becomes our base time qint64 ms0 = QDateTime::currentMSecsSinceEpoch() % 86400000; + unsigned mstr = ms0 % int(1000.0*m_period); // ms into the nominal Tx start time -// qDebug() << "ModStart" << symbolsLength << framesPerSymbol -// << frequency << toneSpacing; - - if(m_state != Idle) stop (); - + if(m_state != Idle) stop(); m_quickClose = false; - m_symbolsLength = symbolsLength; m_isym0 = std::numeric_limits::max (); // big number m_frequency0 = 0.; @@ -69,37 +65,33 @@ void Modulator::start (unsigned symbolsLength, double framesPerSymbol, m_toneSpacing = toneSpacing; m_bFastMode=fastMode; m_TRperiod=TRperiod; - unsigned delay_ms = 1920 == m_nsps && 15 == m_period ? 500 : 1000; + unsigned delay_ms=1000; + if(m_nsps==1920) delay_ms=500; //FT8 + if(m_nsps==576) delay_ms=300; //FT4 - // noise generator parameters +// noise generator parameters if (m_addNoise) { m_snr = qPow (10.0, 0.05 * (dBSNR - 6.0)); m_fac = 3000.0; if (m_snr > 1.0) m_fac = 3000.0 / m_snr; } - unsigned mstr = ms0 % (1000 * m_period); // ms in period - - // round up to an exact portion of a second that allows for startup - // delays +// round up to an exact portion of a second that allows for startup delays m_ic = (mstr / delay_ms) * m_frameRate * delay_ms / 1000; if(m_bFastMode) m_ic=0; m_silentFrames = 0; - // calculate number of silent frames to send, so that audio will start at - // the nominal time "delay_ms" into the Tx sequence. +// calculate number of silent frames to send, so that audio will start at +// the nominal time "delay_ms" into the Tx sequence. if (synchronize && !m_tuning && !m_bFastMode) { m_silentFrames = m_ic + m_frameRate / (1000 / delay_ms) - (mstr * (m_frameRate / 1000)); } - if(symbolsLength==105 and framesPerSymbol==512 - and (toneSpacing==12000.0/512.0 or toneSpacing==-2.0)) { -//### FT4 parameters - m_ic=0; - m_silentFrames=0; - } -// qDebug() << "Mod AA" << symbolsLength << framesPerSymbol << toneSpacing; -// qDebug() << "Mod AB" << delay_ms << mstr << m_ic << m_silentFrames; + +// qDebug() << "aa" << QDateTime::currentDateTimeUtc().toString("hh:mm:ss.zzz") +// << m_ic << m_silentFrames << m_silentFrames/48000.0 +// << mstr << fmod(double(ms0),1000.0*m_period); + initialize (QIODevice::ReadOnly, channel); Q_EMIT stateChanged ((m_state = (synchronize && m_silentFrames) ? @@ -183,12 +175,12 @@ qint64 Modulator::readData (char * data, qint64 maxSize) if(!m_tuning) isym=m_ic/(4.0*m_nsps); // Actual fsample=48000 bool slowCwId=((isym >= m_symbolsLength) && (icw[0] > 0)) && (!m_bFastMode); - if(m_TRperiod==3) slowCwId=false; + if(m_TRperiod==3.0) slowCwId=false; bool fastCwId=false; static bool bCwId=false; qint64 ms = QDateTime::currentMSecsSinceEpoch(); - float tsec=0.001*(ms % (1000*m_TRperiod)); - if(m_bFastMode and (icw[0]>0) and (tsec>(m_TRperiod-5.0))) fastCwId=true; + float tsec=0.001*(ms % int(1000*m_TRperiod)); + if(m_bFastMode and (icw[0]>0) and (tsec > (m_TRperiod-5.0))) fastCwId=true; if(!m_bFastMode) m_nspd=2560; // 22.5 WPM // qDebug() << "Mod A" << m_ic << isym << tsec; @@ -259,7 +251,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize) i1= m_symbolsLength * 4.0 * m_nsps; } if(m_bFastMode and !m_tuning) { - i1=m_TRperiod*48000 - 24000; + i1=m_TRperiod*48000.0 - 24000.0; i0=i1-816; } @@ -267,7 +259,7 @@ qint64 Modulator::readData (char * data, qint64 maxSize) for (unsigned i = 0; i < numFrames && m_ic <= i1; ++i) { isym=0; - if(!m_tuning and m_TRperiod!=3) isym=m_ic/(4.0*m_nsps); //Actual fsample=48000 + if(!m_tuning and m_TRperiod!=3.0) isym=m_ic/(4.0*m_nsps); //Actual fsample=48000 if(m_bFastMode) isym=isym%m_symbolsLength; if (isym != m_isym0 || m_frequency != m_frequency0) { if(itone[0]>=100) { diff --git a/Modulator.hpp b/Modulator.hpp index e8df7f2dd..3371cbe5e 100644 --- a/Modulator.hpp +++ b/Modulator.hpp @@ -23,7 +23,7 @@ class Modulator public: enum ModulatorState {Synchronizing, Active, Idle}; - Modulator (unsigned frameRate, unsigned periodLengthInSeconds, QObject * parent = nullptr); + Modulator (unsigned frameRate, double periodLengthInSeconds, QObject * parent = nullptr); void close () override; @@ -31,14 +31,14 @@ public: double frequency () const {return m_frequency;} bool isActive () const {return m_state != Idle;} void setSpread(double s) {m_fSpread=s;} - void setTRPeriod(unsigned p) {m_period=p;} + void setTRPeriod(double p) {m_period=p;} void set_nsym(int n) {m_symbolsLength=n;} void set_ms0(qint64 ms) {m_ms0=ms;} Q_SLOT void start (unsigned symbolsLength, double framesPerSymbol, double frequency, double toneSpacing, SoundOutput *, Channel = Mono, bool synchronize = true, bool fastMode = false, - double dBSNR = 99., int TRperiod=60); + double dBSNR = 99., double TRperiod=60.0); Q_SLOT void stop (bool quick = false); Q_SLOT void tune (bool newState = true); Q_SLOT void setFrequency (double newFrequency) {m_frequency = newFrequency;} @@ -72,14 +72,14 @@ private: double m_fac; double m_toneSpacing; double m_fSpread; + double m_TRperiod; + double m_period; qint64 m_silentFrames; qint64 m_ms0; - qint32 m_TRperiod; qint16 m_ramp; unsigned m_frameRate; - unsigned m_period; ModulatorState volatile m_state; bool volatile m_tuning; diff --git a/lib/decoder.f90 b/lib/decoder.f90 index 174b75115..d3f1153f4 100644 --- a/lib/decoder.f90 +++ b/lib/decoder.f90 @@ -152,8 +152,8 @@ subroutine multimode_decoder(ss,id2,params,nfsample) if(params%nmode.eq.5) then call timer('decft4 ',0) call my_ft4%decode(ft4_decoded,id2,params%nQSOProgress,params%nfqso, & - params%nutc,params%nfa,params%nfb,params%ndepth,ncontest, & - mycall,hiscall) + params%nutc,params%nfa,params%nfb,params%ndepth, & + logical(params%lapcqonly),ncontest,mycall,hiscall) call timer('decft4 ',1) go to 800 endif diff --git a/lib/freqcal.f90 b/lib/freqcal.f90 index 540237f6e..80ce90c66 100644 --- a/lib/freqcal.f90 +++ b/lib/freqcal.f90 @@ -41,6 +41,7 @@ subroutine freqcal(id2,k,nkhz,noffset,ntol,line) endif smax=0. s=0. + ipk=-99 do i=ia,ib s(i)=real(cx(i))**2 + aimag(cx(i))**2 if(s(i).gt.smax) then @@ -48,25 +49,32 @@ subroutine freqcal(id2,k,nkhz,noffset,ntol,line) ipk=i endif enddo - - call peakup(s(ipk-1),s(ipk),s(ipk+1),dx) - fpeak=df * (ipk+dx) - ap=(fpeak/fs+1.0/(2.0*NFFT)) - an=(fpeak/fs-1.0/(2.0*NFFT)) - sp=sum(id2((k-NFFT):k-1)*cmplx(cos(xi*ap),-sin(xi*ap))) - sn=sum(id2((k-NFFT):k-1)*cmplx(cos(xi*an),-sin(xi*an))) - fpeak=fpeak+fs*(abs(sp)-abs(sn))/(abs(sp)+abs(sn))/(2*NFFT) - xsum=0. - nsum=0 - do i=ia,ib - if(abs(i-ipk).gt.10) then - xsum=xsum+s(i) - nsum=nsum+1 - endif - enddo - ave=xsum/nsum - snr=db(smax/ave) - pave=db(ave) + 8.0 + + if(ipk.ge.1) then + call peakup(s(ipk-1),s(ipk),s(ipk+1),dx) + fpeak=df * (ipk+dx) + ap=(fpeak/fs+1.0/(2.0*NFFT)) + an=(fpeak/fs-1.0/(2.0*NFFT)) + sp=sum(id2((k-NFFT):k-1)*cmplx(cos(xi*ap),-sin(xi*ap))) + sn=sum(id2((k-NFFT):k-1)*cmplx(cos(xi*an),-sin(xi*an))) + fpeak=fpeak+fs*(abs(sp)-abs(sn))/(abs(sp)+abs(sn))/(2*NFFT) + xsum=0. + nsum=0 + do i=ia,ib + if(abs(i-ipk).gt.10) then + xsum=xsum+s(i) + nsum=nsum+1 + endif + enddo + ave=xsum/nsum + snr=db(smax/ave) + pave=db(ave) + 8.0 + else + snr=-99.9 + pave=-99.9 + fpeak=-99.9 + ferr=-99.9 + endif cflag=' ' if(snr.lt.20.0) cflag='*' n=n+1 @@ -77,7 +85,7 @@ subroutine freqcal(id2,k,nkhz,noffset,ntol,line) ncal=1 ferr=fpeak-noffset write(line,1100) nhr,nmin,nsec,nkhz,ncal,noffset,fpeak,ferr,pave, & - snr,cflag,char(0) + snr,cflag,char(0) 1100 format(i2.2,':',i2.2,':',i2.2,i7,i3,i6,2f10.3,2f7.1,2x,a1,a1) 900 return diff --git a/lib/ft4/averaged_mf.f90 b/lib/ft4/averaged_mf.f90 new file mode 100644 index 000000000..2986572b3 --- /dev/null +++ b/lib/ft4/averaged_mf.f90 @@ -0,0 +1,64 @@ +program averaged_mf + + parameter (nsps=32) + complex cgfsk(3*nsps,64) + complex clin(3*nsps,64) + complex cavg(3*nsps,4) + complex cavl(3*nsps,4) + real pulse(3*nsps) + real dphi(3*nsps) + + do i=1,3*NSPS + t=(i-1.5*nsps)/real(nsps) + pulse(i)=gfsk_pulse(1.0,t) + enddo + + twopi=8.0*atan(1.0) + hmod=1.0 + dphi_peak=twopi*hmod/real(nsps) + + do iwf=1,64 + i0=mod((iwf-1)/16,4) + i1=mod((iwf-1)/4,4) + i2=mod(iwf-1,4) + dphi=0.0 + dphi(1:64)=dphi_peak*pulse(33:96)*i1 + dphi(1:96)=dphi(1:96)+dphi_peak*pulse(1:96)*i0 + dphi(33:96)=dphi(33:96)+dphi_peak*pulse(1:64)*i2 + phi=0.0 + do j=1,96 + cgfsk(j,iwf)=cmplx(cos(phi),sin(phi)) + phi=mod(phi+dphi(j),twopi) + enddo + cgfsk(:,iwf)=cgfsk(:,iwf)*conjg(cgfsk(48,iwf)) + enddo + + do iwf=1,64 + i0=mod((iwf-1)/16,4) + i1=mod((iwf-1)/4,4) + i2=mod(iwf-1,4) + dphi=0.0 + dphi(1:32)=dphi_peak*i1 + dphi(33:64)=dphi_peak*i0 + dphi(65:96)=dphi_peak*i2 + phi=0.0 + do j=1,96 + clin(j,iwf)=cmplx(cos(phi),sin(phi)) + phi=mod(phi+dphi(j),twopi) + enddo + enddo + + + do i=1,4 + ib=(i-1)*16+1 + ie=ib+15 + cavg(:,i)=sum(cgfsk(:,ib:ie),2)/16.0 + cavl(:,i)=sum(clin(:,ib:ie),2)/16.0 + do j=1,96 +write(*,*) j +write(21,*) i,j,real(cavg(j,i)),imag(cavg(j,i)),real(cavl(j,i)),imag(cavl(j,i)) + enddo + enddo + +end program averaged_mf + diff --git a/lib/ft4/ft4_baseline.f90 b/lib/ft4/ft4_baseline.f90 new file mode 100644 index 000000000..85a60d9ec --- /dev/null +++ b/lib/ft4/ft4_baseline.f90 @@ -0,0 +1,49 @@ +subroutine ft4_baseline(s,nfa,nfb,sbase) + +! Fit baseline to spectrum +! Input: s(npts) Linear scale in power +! Output: sbase(npts) Baseline + + include 'ft4_params.f90' + implicit real*8 (a-h,o-z) + real*4 s(NH1) + real*4 sbase(NH1) + real*4 base + real*8 x(1000),y(1000),a(5) + data nseg/10/,npct/10/ + + df=12000.0/NFFT1 !5.21 Hz + ia=max(nint(200.0/df),nfa) + ib=min(NH1,nfb) + do i=ia,ib + s(i)=10.0*log10(s(i)) !Convert to dB scale + enddo + + nterms=5 + nlen=(ib-ia+1)/nseg !Length of test segment + i0=(ib-ia+1)/2 !Midpoint + k=0 + do n=1,nseg !Loop over all segments + ja=ia + (n-1)*nlen + jb=ja+nlen-1 + call pctile(s(ja),nlen,npct,base) !Find lowest npct of points + do i=ja,jb + if(s(i).le.base) then + if (k.lt.1000) k=k+1 !Save all "lower envelope" points + x(k)=i-i0 + y(k)=s(i) + endif + enddo + enddo + kz=k + a=0. + call polyfit(x,y,y,kz,nterms,0,a,chisqr) !Fit a low-order polynomial + do i=ia,ib + t=i-i0 + sbase(i)=a(1)+t*(a(2)+t*(a(3)+t*(a(4)+t*(a(5))))) + 0.65 +! write(51,3051) i*df,s(i),sbase(i) +!3051 format(3f12.3) + sbase(i)=10**(sbase(i)/10.0) + enddo + return +end subroutine ft4_baseline diff --git a/lib/ft4/ft4_downsample.f90 b/lib/ft4/ft4_downsample.f90 index d3760a506..ed55fb9a0 100644 --- a/lib/ft4/ft4_downsample.f90 +++ b/lib/ft4/ft4_downsample.f90 @@ -4,7 +4,7 @@ subroutine ft4_downsample(dd,newdata,f0,c) ! Output: Complex data in c(), sampled at 1200 Hz include 'ft4_params.f90' - parameter (NFFT2=NMAX/16) + parameter (NFFT2=NMAX/NDOWN) real dd(NMAX) complex c(0:NMAX/NDOWN-1) complex c1(0:NFFT2-1) diff --git a/lib/ft4/ft4_params.f90 b/lib/ft4/ft4_params.f90 index 46630cc25..2914260d8 100644 --- a/lib/ft4/ft4_params.f90 +++ b/lib/ft4/ft4_params.f90 @@ -6,11 +6,11 @@ parameter (ND=87) !Data symbols parameter (NS=16) !Sync symbols parameter (NN=NS+ND) !Sync and data symbols (103) parameter (NN2=NS+ND+2) !Total channel symbols (105) -parameter (NSPS=512) !Samples per symbol at 12000 S/s -parameter (NZ=NSPS*NN) !Sync and Data samples (52736) -parameter (NZ2=NSPS*NN2) !Total samples in shaped waveform (53760) -parameter (NMAX=18*3456) !Samples in iwave -parameter (NFFT1=2048, NH1=NFFT1/2) !Length of FFTs for symbol spectra +parameter (NSPS=576) !Samples per symbol at 12000 S/s +parameter (NZ=NSPS*NN) !Sync and Data samples (59328) +parameter (NZ2=NSPS*NN2) !Total samples in shaped waveform (60480) +parameter (NMAX=21*3456) !Samples in iwave (72576) +parameter (NFFT1=2304, NH1=NFFT1/2) !Length of FFTs for symbol spectra parameter (NSTEP=NSPS) !Coarse time-sync step size parameter (NHSYM=(NMAX-NFFT1)/NSTEP) !Number of symbol spectra (1/4-sym steps) -parameter (NDOWN=16) !Downsample factor +parameter (NDOWN=18) !Downsample factor diff --git a/lib/ft4/ft4sim.f90 b/lib/ft4/ft4sim.f90 index 94ab8218f..959cf423c 100644 --- a/lib/ft4/ft4sim.f90 +++ b/lib/ft4/ft4sim.f90 @@ -6,7 +6,7 @@ program ft4sim use packjt77 include 'ft4_params.f90' !Set various constants parameter (NWAVE=NN*NSPS) - parameter (NZZ=18*3456) !62208 + parameter (NZZ=21*3456) !72576 type(hdr) h !Header for .wav file character arg*12,fname*17 character msg37*37,msgsent37*37 @@ -51,12 +51,11 @@ program ft4sim hmod=1.0 !Modulation index (0.5 is MSK, 1.0 is FSK) tt=NSPS*dt !Duration of symbols (s) baud=1.0/tt !Keying rate (baud) - txt=NZ*dt !Transmission length (s) + txt=NZ2*dt !Transmission length (s) bandwidth_ratio=2500.0/(fs/2.0) sig=sqrt(2*bandwidth_ratio) * 10.0**(0.05*snrdb) if(snrdb.gt.90.0) sig=1.0 - txt=NN*NSPS/12000.0 ! Source-encode, then get itone() i3=-1 @@ -111,8 +110,10 @@ program ft4sim c0((NN+1)*NSPS:(NN+2)*NSPS-1)=c0((NN+1)*NSPS:(NN+2)*NSPS-1)*(1.0+cos(twopi*(/(i,i=0,NSPS-1)/)/(2.0*NSPS) ))/2.0 c0((NN+2)*NSPS:)=0. - k=nint((xdt+0.5)/dt) + k=nint((xdt+0.5)/dt)-NSPS c0=cshift(c0,-k) + if(k.gt.0) c0(0:k-1)=0.0 + if(k.lt.0) c0(NZZ+k:NZZ-1)=0.0 do ifile=1,nfiles c=c0 diff --git a/lib/ft4/ft4sim_mult.f90 b/lib/ft4/ft4sim_mult.f90 index 313093289..d93978e5f 100644 --- a/lib/ft4/ft4sim_mult.f90 +++ b/lib/ft4/ft4sim_mult.f90 @@ -6,7 +6,7 @@ program ft4sim_mult use packjt77 include 'ft4_params.f90' !FT4 protocol constants parameter (NWAVE=NN*NSPS) - parameter (NZZ=65760) !Length of .wav file (4.48+1.0)*12000 + parameter (NZZ=72576) !Length of .wav file (21*3456) type(hdr) h !Header for .wav file character arg*12,fname*17,cjunk*4 character msg37*37,msgsent37*37,c77*77 @@ -17,8 +17,6 @@ program ft4sim_mult integer itone(NN) integer*1 msgbits(77) integer*2 iwave(NZZ) !Generated full-length waveform - integer icos4(4) - data icos4/0,1,3,2/ ! Get command-line argument(s) nargs=iargc() @@ -55,8 +53,8 @@ program ft4sim_mult read(10,1003,end=100) cjunk,isnr,xdt0,ifreq,msg37 1003 format(a4,30x,i3,f5.1,i5,1x,a37) if(cjunk.eq.'File') go to 100 - if(isnr.lt.-16) isnr=-16 - f0=ifreq*93.75/50.0 + if(isnr.lt.-17) isnr=-17 + f0=ifreq*960.0/576.0 call random_number(r) xdt=r-0.5 ! Source-encode, then get itone() diff --git a/lib/ft4/gen_ft4wave.f90 b/lib/ft4/gen_ft4wave.f90 index c4cd2eafb..823993612 100644 --- a/lib/ft4/gen_ft4wave.f90 +++ b/lib/ft4/gen_ft4wave.f90 @@ -2,8 +2,8 @@ subroutine gen_ft4wave(itone,nsym,nsps,fsample,f0,cwave,wave,icmplx,nwave) real wave(nwave) complex cwave(nwave) - real pulse(6144) !512*4*3 - real dphi(0:240000-1) + real pulse(6912) !576*4*3 + real dphi(0:250000-1) integer itone(nsym) logical first data first/.true./ diff --git a/lib/ft4/getcandidates4.f90 b/lib/ft4/getcandidates4.f90 index badbbcfb5..dd875336d 100644 --- a/lib/ft4/getcandidates4.f90 +++ b/lib/ft4/getcandidates4.f90 @@ -10,7 +10,6 @@ subroutine getcandidates4(dd,fa,fb,syncmin,nfqso,maxcand,savg,candidate, & complex cx(0:NH1) real candidate(3,maxcand) real dd(NMAX) - integer indx(NH1) integer ipk(1) equivalence (x,cx) logical first @@ -26,7 +25,6 @@ subroutine getcandidates4(dd,fa,fb,syncmin,nfqso,maxcand,savg,candidate, & ! Compute symbol spectra, stepping by NSTEP steps. savg=0. - tstep=NSTEP/12000.0 df=12000.0/NFFT1 fac=1.0/300.0 do j=1,NHSYM @@ -40,28 +38,21 @@ subroutine getcandidates4(dd,fa,fb,syncmin,nfqso,maxcand,savg,candidate, & enddo savg=savg + s(1:NH1,j) !Average spectrum enddo + savg=savg/NHSYM savsm=0. do i=8,NH1-7 savsm(i)=sum(savg(i-7:i+7))/15. enddo + nfa=fa/df - if(nfa.lt.1) nfa=1 + if(nfa.lt.8) nfa=8 nfb=fb/df if(nfb.gt.nint(5000.0/df)) nfb=nint(5000.0/df) - n300=300/df - n2500=2500/df -! np=nfb-nfa+1 - np=n2500-n300+1 - indx=0 - call indexx(savsm(n300:n2500),np,indx) - xn=savsm(n300+indx(nint(0.3*np))) ncand=0 - if(xn.le.1.e-8) return - savsm=savsm/xn -! call ft4_baseline(savg,nfa,nfb,sbase) -! savsm=savsm/sbase - - f_offset = -1.5*12000/512 + call ft4_baseline(savg,nfa,nfb,sbase) + if(any(sbase(nfa:nfb).le.0)) return + savsm(nfa:nfb)=savsm(nfa:nfb)/sbase(nfa:nfb) + f_offset = -1.5*12000.0/NSPS do i=nfa+1,nfb-1 if(savsm(i).ge.savsm(i-1) .and. savsm(i).ge.savsm(i+1) .and. & savsm(i).ge.syncmin) then diff --git a/lib/ft4/subtractft4.f90 b/lib/ft4/subtractft4.f90 index 83470d7ea..ae104ddb3 100644 --- a/lib/ft4/subtractft4.f90 +++ b/lib/ft4/subtractft4.f90 @@ -9,8 +9,8 @@ subroutine subtractft4(dd,itone,f0,dt) use timer_module, only: timer - parameter (NMAX=18*3456,NFRAME=(103+2)*512) - parameter (NFFT=NMAX,NFILT=1400) + parameter (NMAX=21*3456,NSPS=576,NFFT=NMAX,NFILT=1400) + parameter (NFRAME=(103+2)*NSPS) real*4 dd(NMAX), window(-NFILT/2:NFILT/2), xjunk complex cref,camp,cfilt,cw integer itone(103) @@ -19,13 +19,13 @@ subroutine subtractft4(dd,itone,f0,dt) common/heap8/cref(NFRAME),camp(NMAX),cfilt(NMAX),cw(NMAX),xjunk(NFRAME) save first - nstart=dt*12000+1-512 + nstart=dt*12000+1-NSPS nsym=103 - nsps=512 fs=12000.0 icmplx=1 bt=1.0 - call gen_ft4wave(itone,nsym,nsps,fs,f0,cref,xjunk,icmplx,NFRAME) + nss=NSPS + call gen_ft4wave(itone,nsym,nss,fs,f0,cref,xjunk,icmplx,NFRAME) camp=0. do i=1,nframe id=nstart-1+i diff --git a/lib/ft4/syncft4.f90 b/lib/ft4/syncft4.f90 deleted file mode 100644 index 4841c560e..000000000 --- a/lib/ft4/syncft4.f90 +++ /dev/null @@ -1,145 +0,0 @@ -subroutine syncft4(iwave,nfa,nfb,syncmin,nfqso,maxcand,s,candidate, & - ncand,sbase) - - include 'ft4_params.f90' -! Search over +/- 2.5s relative to 0.5s TX start time. - parameter (JZ=20) - complex cx(0:NH1) - real s(NH1,NHSYM) - real savg(NH1) - real sbase(NH1) - real x(NFFT1) - real sync2d(NH1,-JZ:JZ) - real red(NH1) - real candidate0(3,maxcand) - real candidate(3,maxcand) - real dd(NMAX) - integer jpeak(NH1) - integer indx(NH1) - integer ii(1) - integer*2 iwave(NMAX) - integer icos4(0:3) - data icos4/0,1,3,2/ !Costas 4x4 tone pattern - equivalence (x,cx) - - dd=iwave/1e3 -! Compute symbol spectra, stepping by NSTEP steps. - savg=0. - tstep=NSTEP/12000.0 - df=12000.0/NFFT1 - fac=1.0/300.0 - do j=1,NHSYM - ia=(j-1)*NSTEP + 1 - ib=ia+NSPS-1 - x(1:NSPS)=fac*dd(ia:ib) - x(NSPS+1:)=0. - call four2a(x,NFFT1,1,-1,0) !r2c FFT - do i=1,NH1 - s(i,j)=real(cx(i))**2 + aimag(cx(i))**2 - enddo - savg=savg + s(1:NH1,j) !Average spectrum - enddo - - call baseline(savg,nfa,nfb,sbase) - - ia=max(1,nint(nfa/df)) - ib=nint(nfb/df) - nssy=NSPS/NSTEP ! # steps per symbol - nfos=NFFT1/NSPS ! # frequency bin oversampling factor - jstrt=0.25/tstep - candidate0=0. - k=0 - - do i=ia,ib - do j=-JZ,+JZ - ta=0. - tb=0. - tc=0. - t0a=0. - t0b=0. - t0c=0. - do n=0,3 - m=j+jstrt+nssy*n - if(m.ge.1.and.m.le.NHSYM) then - ta=ta + s(i+nfos*icos4(n),m) - t0a=t0a + sum(s(i:i+nfos*3:nfos,m)) - endif - tb=tb + s(i+nfos*icos4(n),m+nssy*36) - t0b=t0b + sum(s(i:i+nfos*3:nfos,m+nssy*36)) - if(m+nssy*72.le.NHSYM) then - tc=tc + s(i+nfos*icos4(n),m+nssy*72) - t0c=t0c + sum(s(i:i+nfos*3:nfos,m+nssy*72)) - endif - enddo - t=ta+tb+tc - t0=t0a+t0b+t0c - t0=(t0-t)/3.0 - sync_abc=t/t0 - t=tb+tc - t0=t0b+t0c - t0=(t0-t)/3.0 - sync_bc=t/t0 - sync2d(i,j)=max(sync_abc,sync_bc) - enddo - enddo - - red=0. - do i=ia,ib - ii=maxloc(sync2d(i,-JZ:JZ)) - 1 - JZ - j0=ii(1) - jpeak(i)=j0 - red(i)=sync2d(i,j0) - enddo - iz=ib-ia+1 - call indexx(red(ia:ib),iz,indx) - ibase=indx(nint(0.40*iz)) - 1 + ia - if(ibase.lt.1) ibase=1 - if(ibase.gt.nh1) ibase=nh1 - base=red(ibase) - red=red/base - do i=1,min(maxcand,iz) - n=ia + indx(iz+1-i) - 1 - if(red(n).lt.syncmin.or.isnan(red(n)).or.k.eq.maxcand) exit - k=k+1 -! candidate0(1,k)=n*df+37.5*1.5 - candidate0(1,k)=n*df - candidate0(2,k)=(jpeak(n)-1)*tstep - candidate0(3,k)=red(n) - enddo - ncand=k - -! Put nfqso at top of list, and save only the best of near-dupe freqs. - do i=1,ncand - if(abs(candidate0(1,i)-nfqso).lt.10.0) candidate0(1,i)=-candidate0(1,i) - 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 - 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 - enddo - endif - enddo - - fac=20.0/maxval(s) - s=fac*s - -! Sort by sync -! call indexx(candidate0(3,1:ncand),ncand,indx) -! Sort by frequency - call indexx(candidate0(1,1:ncand),ncand,indx) - k=1 -! do i=ncand,1,-1 - do i=1,ncand - j=indx(i) -! if( candidate0(3,j) .ge. syncmin .and. candidate0(2,j).ge.-1.5 ) then - if( candidate0(3,j) .ge. syncmin ) then - candidate(2:3,k)=candidate0(2:3,j) - candidate(1,k)=abs(candidate0(1,j)) - k=k+1 - endif - enddo - ncand=k-1 - return -end subroutine syncft4 diff --git a/lib/ft4_decode.f90 b/lib/ft4_decode.f90 index aa27387ce..50c9fa47d 100644 --- a/lib/ft4_decode.f90 +++ b/lib/ft4_decode.f90 @@ -24,7 +24,7 @@ module ft4_decode contains subroutine decode(this,callback,iwave,nQSOProgress,nfqso, & - nutc,nfa,nfb,ndepth,ncontest,mycall,hiscall) + nutc,nfa,nfb,ndepth,lapcqonly,ncontest,mycall,hiscall) use timer_module, only: timer use packjt77 include 'ft4/ft4_params.f90' @@ -74,7 +74,8 @@ contains logical nohiscall,unpk77_success logical one(0:255,0:7) ! 256 4-symbol sequences, 8 bits logical first, dobigfft - logical dosubtract + logical dosubtract,doosd + logical, intent(in) :: lapcqonly data icos4a/0,1,3,2/ data icos4b/1,0,2,3/ @@ -210,19 +211,23 @@ contains fb=nfb dd=iwave -! ndepth=3: 2 passes, subtract on each pass -! ndepth=2: 1 pass, no subtraction -! ndepth=1: 1 pass, no subtraction, fewer candidates +! ndepth=3: 3 passes, bp+osd +! ndepth=2: 3 passes, bp only +! ndepth=1: 1 pass, no subtraction max_iterations=40 syncmin=1.2 dosubtract=.true. + doosd=.true. nsp=3 - if(ndepth.lt.3) then + if(ndepth.eq.2) then + doosd=.false. + endif + if(ndepth.eq.1) then nsp=1 dosubtract=.false. + doosd=.false. endif - if(ndepth.eq.1) syncmin=2.0 do isp = 1,nsp if(isp.eq.2) then @@ -249,14 +254,14 @@ contains if(dobigfft) dobigfft=.false. sum2=sum(cd2*conjg(cd2))/(real(NMAX)/real(NDOWN)) if(sum2.gt.0.0) cd2=cd2/sqrt(sum2) -! Sample rate is now 12000/16 = 750 samples/second +! Sample rate is now 12000/18 = 666.67 samples/second do isync=1,2 if(isync.eq.1) then idfmin=-12 idfmax=12 idfstp=3 - ibmin=-200 - ibmax=950 + ibmin=-344 + ibmax=1012 ibstp=4 else idfmin=idfbest-4 @@ -403,6 +408,7 @@ contains apmag=maxval(abs(llra))*1.1 npasses=3+nappasses(nQSOProgress) + if(lapcqonly) npasses=4 if(ndepth.eq.1) npasses=3 if(ncontest.ge.5) npasses=3 ! Don't support Fox and Hound do ipass=1,npasses @@ -417,6 +423,7 @@ contains if(ipass .gt. 3) then llrd=llra iaptype=naptypes(nQSOProgress,ipass-3) + if(lapcqonly) iaptype=1 ! ncontest=0 : NONE ! 1 : NA_VHF @@ -482,10 +489,22 @@ contains llr=llrd endif message77=0 + dmin=0.0 call timer('bpdec174',0) call bpdecode174_91(llr,apmask,max_iterations,message77, & cw,nharderror,niterations) call timer('bpdec174',1) + + if(doosd .and. nharderror.lt.0) then + ndeep=3 + if(abs(nfqso-f1).le.napwid) then + ndeep=4 + endif + call timer('osd174_91 ',0) + call osd174_91(llr,apmask,ndeep,message77,cw,nharderror,dmin) + call timer('osd174_91 ',1) + endif + if(sum(message77).eq.0) cycle if( nharderror.ge.0 ) then message77=mod(message77+rvec,2) ! remove rvec scrambling @@ -493,7 +512,7 @@ contains call unpack77(c77,1,message,unpk77_success) if(unpk77_success.and.dosubtract) then call get_ft4_tones_from_77bits(message77,i4tone) - dt=real(ibest)/750.0 + dt=real(ibest)/666.67 call timer('subtract',0) call subtractft4(dd,i4tone,f0,dt) call timer('subtract',1) @@ -506,13 +525,13 @@ contains ndecodes=ndecodes+1 decodes(ndecodes)=message if(snr.gt.0.0) then - xsnr=10*log10(snr)-14.0 + xsnr=10*log10(snr)-14.8 else - xsnr=-20.0 + xsnr=-21.0 endif - nsnr=nint(max(-20.0,xsnr)) - xdt=ibest/750.0 - 0.5 -!write(21,'(i6.6,i5,2x,f4.1,i6,2x,a37,2x,f4.1,3i3)') nutc,nsnr,xdt,nint(f0),message,sync,iaptype,ipass,isp + nsnr=nint(max(-21.0,xsnr)) + xdt=ibest/666.67 - 0.5 +!write(21,'(i6.6,i5,2x,f4.1,i6,2x,a37,2x,f4.1,3i3,f5.1)') nutc,nsnr,xdt,nint(f0),message,sync,iaptype,ipass,isp,dmin call this%callback(sync,nsnr,xdt,f0,message,iaptype,qual) exit endif diff --git a/lib/jt4_decode.f90 b/lib/jt4_decode.f90 index da0fbda68..ff0b33c4d 100644 --- a/lib/jt4_decode.f90 +++ b/lib/jt4_decode.f90 @@ -156,7 +156,7 @@ contains nfreqz=nint(dfx) call timer('sync4 ',1) - nsnr=nint(snrx) + nsnr=-26 if(sync.lt.syncmin) then if (associated (this%decode_callback)) then call this%decode_callback(nsnr,dtxz,nfreqz,.false.,csync, & @@ -166,6 +166,7 @@ contains endif ! We have achieved sync + nsnr=nint(snrsync - 22.9) decoded=blank deepmsg=blank special=' ' diff --git a/lib/jt9.f90 b/lib/jt9.f90 index a0ffcda31..67e7ac319 100644 --- a/lib/jt9.f90 +++ b/lib/jt9.f90 @@ -157,7 +157,7 @@ program jt9 end do go to 999 endif - + iret=fftwf_init_threads() !Initialize FFTW threading ! Default to 1 thread, but use nthreads for the big ones @@ -179,6 +179,7 @@ program jt9 go to 999 endif + if(mode.eq.5) ndepth=3 allocate(shared_data) nflatten=0 @@ -225,7 +226,7 @@ program jt9 endif shared_data%id2=0 !??? Why is this necessary ??? - if(mode.eq.5) npts=62208 + if(mode.eq.5) npts=21*3456 do iblk=1,npts/kstep k=iblk*kstep if(mode.eq.8 .and. k.gt.179712) exit diff --git a/logbook/WorkedBefore.cpp b/logbook/WorkedBefore.cpp index daaf18fc7..31380b4c3 100644 --- a/logbook/WorkedBefore.cpp +++ b/logbook/WorkedBefore.cpp @@ -332,10 +332,15 @@ namespace // will parse a record { auto const& entity = prefixes->lookup (call); + auto mode = extractField (record, "MODE").toUpper (); + if (!mode.size () || "MFSK" == mode) + { + mode = extractField (record, "SUBMODE").toUpper (); + } worked.emplace (call.toUpper () , extractField (record, "GRIDSQUARE").left (4).toUpper () // not interested in 6-digit grids , extractField (record, "BAND").toUpper () - , extractField (record, "MODE").toUpper () + , mode , entity.entity_name , entity.continent , entity.CQ_zone diff --git a/logbook/logbook.cpp b/logbook/logbook.cpp index b84b65c1a..e4a04f64a 100644 --- a/logbook/logbook.cpp +++ b/logbook/logbook.cpp @@ -69,7 +69,14 @@ QByteArray LogBook::QSOToADIF (QString const& hisCall, QString const& hisGrid, Q QString t; t = "" + hisCall; t += " " + hisGrid; - t += " " + mode; + if (mode != "FT4") + { + t += " " + mode; + } + else + { + t += " MFSK " + mode; + } t += " " + rptSent; t += " " + rptRcvd; t += " " + dateTimeOn.date().toString("yyyyMMdd"); diff --git a/samples/FT4/000000_000002.wav b/samples/FT4/000000_000002.wav new file mode 100644 index 000000000..e5cdc8804 Binary files /dev/null and b/samples/FT4/000000_000002.wav differ diff --git a/samples/FT4/190106_000112.wav b/samples/FT4/190106_000112.wav deleted file mode 100644 index 2c6e0a9d4..000000000 Binary files a/samples/FT4/190106_000112.wav and /dev/null differ diff --git a/widgets/astro.cpp b/widgets/astro.cpp index 4ee55da4a..c1eee0157 100644 --- a/widgets/astro.cpp +++ b/widgets/astro.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "commons.h" #include "MessageBox.hpp" @@ -90,7 +91,7 @@ void Astro::write_settings () } auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const& hisgrid, Frequency freq, - bool dx_is_self, bool bTx, bool no_tx_QSY, int TR_period) -> Correction + bool dx_is_self, bool bTx, bool no_tx_QSY, double TR_period) -> Correction { Frequency freq_moon {freq}; double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx; @@ -211,8 +212,8 @@ auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const // // use a base time of (secs-since-epoch + 2) so as to be sure // we do the next period if we calculate just before it starts - auto sec_since_epoch = t.toMSecsSinceEpoch () / 1000 + 2; - auto target_sec = sec_since_epoch - sec_since_epoch % TR_period + TR_period / 2; + auto sec_since_epoch = t.toMSecsSinceEpoch ()/1000 + 2; + auto target_sec = sec_since_epoch - fmod(double(sec_since_epoch),TR_period) + 0.5*TR_period; auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000, Qt::UTC); QString date {target_date_time.date().toString("yyyy MMM dd").trimmed ()}; QString utc {target_date_time.time().toString().trimmed ()}; diff --git a/widgets/astro.h b/widgets/astro.h index 03d8c66c6..4f7f71d5b 100644 --- a/widgets/astro.h +++ b/widgets/astro.h @@ -44,7 +44,7 @@ public: bool dx_is_self, bool bTx, bool no_tx_QSY, - int TR_period); + double TR_period); bool doppler_tracking () const; Q_SLOT void nominal_frequency (Frequency rx, Frequency tx); diff --git a/widgets/fastgraph.cpp b/widgets/fastgraph.cpp index e599138f2..9efe5fc63 100644 --- a/widgets/fastgraph.cpp +++ b/widgets/fastgraph.cpp @@ -86,9 +86,9 @@ void FastGraph::on_greenZeroSlider_valueChanged(int value) ui->fastPlot->draw(); } -void FastGraph::setTRPeriod(int n) +void FastGraph::setTRPeriod(double p) { - m_TRperiod=n; + m_TRperiod=p; ui->fastPlot->setTRperiod(m_TRperiod); } diff --git a/widgets/fastgraph.h b/widgets/fastgraph.h index 7ed32671f..b5f7c0b8d 100644 --- a/widgets/fastgraph.h +++ b/widgets/fastgraph.h @@ -22,7 +22,7 @@ public: void plotSpec(bool diskData, int UTCdisk); void saveSettings(); - void setTRPeriod(int n); + void setTRPeriod(double p); void setMode(QString mode); signals: @@ -40,8 +40,8 @@ protected: private: QSettings * m_settings; - float m_ave; - qint32 m_TRperiod; + float m_ave; + double m_TRperiod; QScopedPointer ui; }; diff --git a/widgets/fastplot.cpp b/widgets/fastplot.cpp index 1437834d8..a388f0ac7 100644 --- a/widgets/fastplot.cpp +++ b/widgets/fastplot.cpp @@ -135,11 +135,11 @@ void FPlotter::setGreenZero(int n) m_bPaint2=true; } -void FPlotter::setTRperiod(int n) +void FPlotter::setTRperiod(double p) { - m_TRperiod=n; + m_TRperiod=p; m_pixPerSecond=12000.0/512.0; - if(m_TRperiod<30) m_pixPerSecond=12000.0/256.0; + if(m_TRperiod<30.0) m_pixPerSecond=12000.0/256.0; drawScale(); update(); } diff --git a/widgets/fastplot.h b/widgets/fastplot.h index b13913388..f24fcc24e 100644 --- a/widgets/fastplot.h +++ b/widgets/fastplot.h @@ -37,7 +37,7 @@ public: void setPlotZero(int plotZero); void setPlotGain(int plotGain); void setGreenZero(int n); - void setTRperiod(int n); + void setTRperiod(double p); void drawScale(); void setMode(QString mode); @@ -68,6 +68,7 @@ private: QString m_mode; double m_pixPerSecond; + double m_TRperiod; qint32 m_hdivs; qint32 m_h; @@ -75,7 +76,6 @@ private: qint32 m_h2; QPixmap m_HorizPixmap; qint32 m_jh0; - qint32 m_TRperiod; bool m_bPaint2; }; diff --git a/widgets/mainwindow.cpp b/widgets/mainwindow.cpp index 88fe0016e..99bcc410d 100644 --- a/widgets/mainwindow.cpp +++ b/widgets/mainwindow.cpp @@ -246,7 +246,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_logDlg (new LogQSO (program_title (), m_settings, &m_config, nullptr)), m_lastDialFreq {0}, m_dialFreqRxWSPR {0}, - m_detector {new Detector {RX_SAMPLE_RATE, NTMAX, downSampleFactor}}, + m_detector {new Detector {RX_SAMPLE_RATE, double(NTMAX), downSampleFactor}}, m_FFTSize {6192 / 2}, // conservative value to avoid buffer overruns m_soundInput {new SoundInput}, m_modulator {new Modulator {TX_SAMPLE_RATE, NTMAX}}, @@ -257,6 +257,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_freqTxNominal {0}, m_s6 {0.}, m_tRemaining {0.}, + m_TRperiod {60.0}, m_DTtol {3.0}, m_waterfallAvg {1}, m_ntx {1}, @@ -268,7 +269,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, m_nutc0 {999999}, m_ntr {0}, m_tx {0}, - m_TRperiod {60}, m_inGain {0}, m_secID {0}, m_idleMinutes {0}, @@ -877,7 +877,6 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, connect (&m_wav_future_watcher, &QFutureWatcher::finished, this, &MainWindow::diskDat); connect(&watcher3, SIGNAL(finished()),this,SLOT(fast_decode_done())); -// Q_EMIT startAudioInputStream (m_config.audio_input_device (), m_framesAudioInputBuffered, &m_detector, m_downSampleFactor, m_config.audio_input_channel ()); Q_EMIT startAudioInputStream (m_config.audio_input_device (), m_framesAudioInputBuffered, m_detector, m_downSampleFactor, m_config.audio_input_channel ()); Q_EMIT initializeAudioOutputStream (m_config.audio_output_device (), AudioDevice::Mono == m_config.audio_output_channel () ? 1 : 2, m_msAudioOutputBuffered); Q_EMIT transmitFrequency (ui->TxFreqSpinBox->value () - m_XIT); @@ -990,6 +989,7 @@ MainWindow::MainWindow(QDir const& temp_directory, bool multiple, void MainWindow::not_GA_warning_message () { + /* MessageBox::critical_message (this, "

" "This is a pre-release version of WSJT-X 2.1.0 made " @@ -998,6 +998,7 @@ void MainWindow::not_GA_warning_message () QDateTime now=QDateTime::currentDateTime(); QDateTime timeout=QDateTime(QDate(2019,6,7)); if(now.daysTo(timeout) < 0) Q_EMIT finished(); + */ } void MainWindow::initialize_fonts () @@ -1323,7 +1324,7 @@ void MainWindow::fixStop() } else if (m_mode=="FT8") { m_hsymStop=50; } else if (m_mode=="FT4") { - m_hsymStop=18; + m_hsymStop=21; } } @@ -1355,7 +1356,7 @@ void MainWindow::dataSink(qint64 frames) } // Get power, spectrum, and ihsym - int trmin=m_TRperiod/60; + int trmin=m_TRperiod/60.0; // int k (frames - 1); dec_data.params.nfa=m_wideGraph->nStartFreq(); dec_data.params.nfb=m_wideGraph->Fmax(); @@ -1452,19 +1453,20 @@ void MainWindow::dataSink(qint64 frames) if(!m_mode.startsWith ("WSPR")) decode(); //Start decoder if(!m_diskData) { //Always save; may delete later - if(m_mode=="FT8" or m_mode=="FT4") { - int n=now.time().second() % m_TRperiod; + int n=fmod(double(now.time().second()),m_TRperiod); if(n<(m_TRperiod/2)) n=n+m_TRperiod; auto const& period_start=now.addSecs(-n); m_fnameWE=m_config.save_directory().absoluteFilePath (period_start.toString("yyMMdd_hhmmss")); +// qDebug() << "datasink 2" << QDateTime::currentDateTimeUtc().toString("ss.zzz") +// << n << period_start.toString("ss.zzz"); } else { - auto const& period_start = now.addSecs (-(now.time ().minute () % (m_TRperiod / 60)) * 60); + auto const& period_start = now.addSecs (-(now.time ().minute () % (int(m_TRperiod) / 60)) * 60); m_fnameWE=m_config.save_directory ().absoluteFilePath (period_start.toString ("yyMMdd_hhmm")); } m_fileToSave.clear (); int samples=m_TRperiod*12000; - if(m_mode=="FT4") samples=18*3456; + if(m_mode=="FT4") samples=21*3456; // the following is potential a threading hazard - not a good // idea to pass pointer to be processed in another thread @@ -1589,7 +1591,7 @@ void MainWindow::fastSink(qint64 frames) int ihr=tnow.toString("hh").toInt(); int imin=tnow.toString("mm").toInt(); int isec=tnow.toString("ss").toInt(); - isec=isec - isec%m_TRperiod; + isec=isec - fmod(double(isec),m_TRperiod); int nutc0=10000*ihr + 100*imin + isec; if(m_diskData) nutc0=m_UTCdisk; char line[80]; @@ -1669,7 +1671,7 @@ void MainWindow::fastSink(qint64 frames) if(decodeNow or m_bFastDone) { if(!m_diskData) { QDateTime now {QDateTime::currentDateTimeUtc()}; - int n=now.time().second() % m_TRperiod; + int n=fmod(double(now.time().second()),m_TRperiod); if(n<(m_TRperiod/2)) n=n+m_TRperiod; auto const& period_start = now.addSecs (-n); m_fnameWE = m_config.save_directory ().absoluteFilePath (period_start.toString ("yyMMdd_hhmmss")); @@ -1679,11 +1681,11 @@ void MainWindow::fastSink(qint64 frames) // the following is potential a threading hazard - not a good // idea to pass pointer to be processed in another thread m_saveWAVWatcher.setFuture (QtConcurrent::run (std::bind (&MainWindow::save_wave_file, - this, m_fnameWE, &dec_data.d2[0], m_TRperiod*12000, m_config.my_callsign(), + this, m_fnameWE, &dec_data.d2[0], int(m_TRperiod*12000.0), m_config.my_callsign(), m_config.my_grid(), m_mode, m_nSubMode, m_freqNominal, m_hisCall, m_hisGrid))); } if(m_mode!="MSK144") { - killFileTimer.start (3*1000*m_TRperiod/4); //Kill 3/4 period from now + killFileTimer.start (int(750.0*m_TRperiod)); //Kill 3/4 period from now } } m_bFastDone=false; @@ -1984,7 +1986,7 @@ void MainWindow::keyPressEvent (QKeyEvent * e) if(e->modifiers() & Qt::ControlModifier) n+=100; if(e->modifiers() & Qt::ShiftModifier) { int offset=60; - if(m_mode=="FT4") offset=120; + if(m_mode=="FT4") offset=100; ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()-offset); } else{ bumpFqso(n); @@ -2000,7 +2002,7 @@ void MainWindow::keyPressEvent (QKeyEvent * e) if(e->modifiers() & Qt::ControlModifier) n+=100; if(e->modifiers() & Qt::ShiftModifier) { int offset=60; - if(m_mode=="FT4") offset=120; + if(m_mode=="FT4") offset=100; ui->TxFreqSpinBox->setValue(ui->TxFreqSpinBox->value()+offset); } else { bumpFqso(n); @@ -2218,7 +2220,6 @@ void MainWindow::createStatusBar() //createStatusBar statusBar()->addPermanentWidget(&progressBar); progressBar.setMinimumSize (QSize {150, 18}); - progressBar.setFormat ("%v/%m"); statusBar ()->addPermanentWidget (&watchdog_label); update_watchdog_label (); @@ -2631,7 +2632,8 @@ void MainWindow::read_wav_file (QString const& fname) bool ok=file.open (BWFFile::ReadOnly); if(ok) { auto bytes_per_frame = file.format ().bytesPerFrame (); - qint64 max_bytes = std::min (std::size_t (m_TRperiod * RX_SAMPLE_RATE), + int nsamples=m_TRperiod * RX_SAMPLE_RATE; + qint64 max_bytes = std::min (std::size_t (nsamples), sizeof (dec_data.d2) / sizeof (dec_data.d2[0]))* bytes_per_frame; auto n = file.read (reinterpret_cast (dec_data.d2), std::min (max_bytes, file.size ())); @@ -2822,7 +2824,7 @@ void MainWindow::decode() //decode() } m_msec0=QDateTime::currentMSecsSinceEpoch(); - if(!m_dataAvailable or m_TRperiod==0) return; + if(!m_dataAvailable or m_TRperiod==0.0) return; ui->DecodeButton->setChecked (true); if(!dec_data.params.nagain && m_diskData && !m_bFastMode && m_mode!="FT8" && m_mode!="FT4") { dec_data.params.nutc=dec_data.params.nutc/100; @@ -2832,14 +2834,16 @@ void MainWindow::decode() //decode() int imin=ms/60000; int ihr=imin/60; imin=imin % 60; - if(m_TRperiod>=60) imin=imin - (imin % (m_TRperiod/60)); + if(m_TRperiod>=60) imin=imin - (imin % (int(m_TRperiod)/60)); dec_data.params.nutc=100*ihr + imin; if(m_mode=="ISCAT" or m_mode=="MSK144" or m_bFast9 or m_mode=="FT8" or m_mode=="FT4") { - QDateTime t=QDateTime::currentDateTimeUtc().addSecs(2-m_TRperiod); + qint64 ms=1000.0*(2.0-m_TRperiod); + if(m_mode=="FT4") ms=1000.0*(2.0-m_TRperiod); + QDateTime t=QDateTime::currentDateTimeUtc().addMSecs(ms); ihr=t.toString("hh").toInt(); imin=t.toString("mm").toInt(); int isec=t.toString("ss").toInt(); - isec=isec - isec%m_TRperiod; + isec=isec - fmod(double(isec),m_TRperiod); dec_data.params.nutc=10000*ihr + 100*imin + isec; } } @@ -2849,7 +2853,7 @@ void MainWindow::decode() //decode() int ihr=t.toString("hh").toInt(); int imin=t.toString("mm").toInt(); int isec=t.toString("ss").toInt(); - isec=isec - isec%m_TRperiod; + isec=isec - fmod(double(isec),m_TRperiod); dec_data.params.nutc=10000*ihr + 100*imin + isec; } if(m_nPick==2) dec_data.params.nutc=m_nutc0; @@ -2948,8 +2952,8 @@ void MainWindow::decode() //decode() } static short int d2b[360000]; narg[0]=dec_data.params.nutc; - if(m_kdone>12000*m_TRperiod) { - m_kdone=12000*m_TRperiod; + if(m_kdone>int(12000.0*m_TRperiod)) { + m_kdone=int(12000.0*m_TRperiod); } narg[1]=m_kdone; narg[2]=m_nSubMode; @@ -2968,9 +2972,10 @@ void MainWindow::decode() //decode() narg[12]=0; narg[13]=-1; narg[14]=m_config.aggressive(); + int nTRperiod=m_TRperiod; memcpy(d2b,dec_data.d2,2*360000); watcher3.setFuture (QtConcurrent::run (std::bind (fast_decode_,&d2b[0], - &narg[0],&m_TRperiod,&m_msg[0][0], + &narg[0],&nTRperiod,&m_msg[0][0], dec_data.params.mycall,dec_data.params.hiscall,8000,12,12))); } else { memcpy(to, from, qMin(mem_jt9->size(), size)); @@ -3055,7 +3060,7 @@ void MainWindow::readFromStdout() //readFromStdout if(line_read.indexOf("") >= 0) { if(m_mode=="QRA64") m_wideGraph->drawRed(0,0); m_bDecoded = line_read.mid(20).trimmed().toInt() > 0; - int mswait=3*1000*m_TRperiod/4; + int mswait=750.0*m_TRperiod; if(!m_diskData) killFileTimer.start(mswait); //Kill in 3/4 period decodeDone (); m_startAnother=m_loopall; @@ -3065,7 +3070,7 @@ void MainWindow::readFromStdout() //readFromStdout } return; } else { - if(m_mode=="JT4" or m_mode=="JT65" or m_mode=="QRA64" or m_mode=="FT8" or m_mode=="FT4") { + if(m_mode=="JT4" or m_mode=="JT65" or m_mode=="QRA64") { int n=line_read.indexOf("f"); if(n<0) n=line_read.indexOf("d"); if(n>0) { @@ -3081,7 +3086,7 @@ void MainWindow::readFromStdout() //readFromStdout write_all("Rx",line_read.trimmed()); if (m_config.insert_blank () && m_blankLine && SpecOp::FOX != m_config.special_op_id()) { QString band; - if((QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged) > 4*m_TRperiod/4) { + if((QDateTime::currentMSecsSinceEpoch() / 1000 - m_secBandChanged) > 4*int(m_TRperiod)/4) { band = ' ' + m_config.bands ()->find (m_freqNominal); } ui->decodedTextBrowser->insertLineSpacer (band.rightJustified (40, '-')); @@ -3241,7 +3246,7 @@ void MainWindow::readFromStdout() //readFromStdout } // extract details and send to PSKreporter int nsec=QDateTime::currentMSecsSinceEpoch()/1000-m_secBandChanged; - bool okToPost=(nsec>(4*m_TRperiod)/5); + bool okToPost=(nsec > int(4*m_TRperiod)/5); if (stdMsg && okToPost) pskPost(decodedtext); if((m_mode=="JT4" or m_mode=="JT65" or m_mode=="QRA64") and m_msgAvgWidget!=NULL) { @@ -3421,9 +3426,9 @@ void MainWindow::guiUpdate() double txDuration; QString rt; - if(m_TRperiod==0) m_TRperiod=60; + if(m_TRperiod==0) m_TRperiod=60.0; txDuration=0.0; - if(m_modeTx=="FT4") txDuration=0.35 + 105*512/12000.0; // FT4 + if(m_modeTx=="FT4") txDuration=1.0 + 105*576/12000.0; // FT4 if(m_modeTx=="FT8") txDuration=1.0 + 79*1920/12000.0; // FT8 if(m_modeTx=="JT4") txDuration=1.0 + 207.0*2520/11025.0; // JT4 if(m_modeTx=="JT9") txDuration=1.0 + 85.0*m_nsps/12000.0; // JT9 @@ -3451,8 +3456,8 @@ void MainWindow::guiUpdate() double tsec=0.001*ms; double t2p=fmod(tsec,2*m_TRperiod); m_s6=fmod(tsec,6.0); - m_nseq = nsec % m_TRperiod; - m_tRemaining=m_TRperiod - fmod(tsec,double(m_TRperiod)); + m_nseq = fmod(double(nsec),m_TRperiod); + m_tRemaining=m_TRperiod - fmod(tsec,m_TRperiod); if(m_mode=="Echo") { txDuration=2.4; @@ -3493,10 +3498,9 @@ void MainWindow::guiUpdate() if(m_transmitting or m_auto or m_tune) { m_dateTimeLastTX = QDateTime::currentDateTimeUtc (); -// Check for "txboth" (testing purposes only) +// Check for "txboth" (FT4 testing purposes only) QFile f(m_appDir + "/txboth"); - if(f.exists() and - fmod(tsec,m_TRperiod)<(1.0 + 85.0*m_nsps/12000.0)) m_bTxTime=true; + if(f.exists() and fmod(tsec,m_TRperiod) < (0.5 + 105.0*576.0/12000.0)) m_bTxTime=true; // Don't transmit another mode in the 30 m WSPR sub-band Frequency onAirFreq = m_freqNominal + ui->TxFreqSpinBox->value(); @@ -3539,7 +3543,7 @@ void MainWindow::guiUpdate() tx_watchdog (true); // disable transmit } - float fTR=float((ms%(1000*m_TRperiod)))/(1000*m_TRperiod); + float fTR=float((ms%int(1000.0*m_TRperiod)))/int(1000.0*m_TRperiod); QString txMsg; if(m_ntx == 1) txMsg=ui->tx1->text(); @@ -3744,7 +3748,7 @@ void MainWindow::guiUpdate() genft4_(message, &ichk, msgsent, const_cast (ft4msgbits), const_cast(itone), 37, 37); int nsym=103; - int nsps=4*512; + int nsps=4*576; float fsample=48000.0; float f0=ui->TxFreqSpinBox->value() - m_XIT; int nwave=(nsym+2)*nsps; @@ -3943,7 +3947,7 @@ void MainWindow::guiUpdate() //Once per second: if(nsec != m_sec0) { -// qDebug() << "cc onesec" << (SpecOp::RTTY == m_config.special_op_id()); +// qDebug() << "onesec" << m_config.force_call_1st(); // if((!m_msgAvgWidget or (m_msgAvgWidget and !m_msgAvgWidget->isVisible())) // and (SpecOp::NONE < m_config.special_op_id()) and (SpecOp::HOUND > m_config.special_op_id())) on_actionFox_Log_triggered(); if(m_freqNominal!=0 and m_freqNominal<50000000 and m_config.enable_VHF_features()) { @@ -3959,17 +3963,21 @@ void MainWindow::guiUpdate() if(tHound >= 120 and m_ntx==1) auto_tx_mode(false); } -// progressBar.setVisible(!(m_mode=="FT4")); progressBar.setVisible(true); + progressBar.setFormat ("%v/%m"); if(m_auto and m_mode=="Echo" and m_bEchoTxOK) { - progressBar.setMaximum(6); + progressBar.setMaximum(3); progressBar.setValue(int(m_s6)); } -// if(m_mode!="Echo" and m_mode!="FT4") { if(m_mode!="Echo") { if(m_monitoring or m_transmitting) { progressBar.setMaximum(m_TRperiod); int isec=int(fmod(tsec,m_TRperiod)); + if(m_TRperiod-int(m_TRperiod)>0.0) { + QString progBarLabel; + progBarLabel.sprintf("%d/%3.1f",isec,m_TRperiod); + progressBar.setFormat (progBarLabel); + } progressBar.setValue(isec); } else { progressBar.setValue(0); @@ -4068,6 +4076,10 @@ void MainWindow::startTx2() t=ui->tx6->text(); if(t.mid(0,1)=="#") snr=t.mid(1,5).toDouble(); if(snr>0.0 or snr < -50.0) snr=99.0; + if((m_ntx==6 or m_ntx==7) and m_config.force_call_1st()) { + ui->cbAutoSeq->setChecked(true); + ui->cbFirst->setChecked(true); + } transmit (snr); ui->signal_meter_widget->setValue(0,0); if(m_mode=="Echo" and !m_tune) m_bTransmittedEcho=true; @@ -4152,7 +4164,8 @@ void MainWindow::set_dateTimeQSO(int m_ntx) } else { // we also take of m_TRperiod/2 to allow for late clicks auto now = QDateTime::currentDateTimeUtc(); - m_dateTimeQSOOn = now.addSecs (-(m_ntx - 2) * m_TRperiod - (now.time ().second () % m_TRperiod)); + m_dateTimeQSOOn = now.addSecs (-(m_ntx - 2) * int(m_TRperiod) - + int(fmod(double(now.time().second()),m_TRperiod))); } } @@ -4405,7 +4418,7 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie } } - int nmod = message.timeInSeconds () % (2*m_TRperiod); + int nmod = fmod(double(message.timeInSeconds()),2.0*m_TRperiod); m_txFirst=(nmod!=0); if( SpecOp::HOUND == m_config.special_op_id() ) m_txFirst=false; //Hound must not transmit first if( SpecOp::FOX == m_config.special_op_id() ) m_txFirst=true; //Fox must always transmit first @@ -4598,7 +4611,6 @@ void MainWindow::processMessage (DecodedText const& message, Qt::KeyboardModifie logQSOTimer.start(0); m_ntx=6; ui->txrb6->setChecked(true); - ui->cbFirst->setChecked(false); } else { m_ntx=5; ui->txrb5->setChecked(true); @@ -5632,7 +5644,7 @@ void MainWindow::on_actionFT4_triggered() { m_mode="FT4"; m_modeTx="FT4"; - m_TRperiod=6; + m_TRperiod=7.5; bool bVHF=m_config.enable_VHF_features(); m_bFast9=false; m_bFastMode=false; @@ -5641,9 +5653,9 @@ void MainWindow::on_actionFT4_triggered() m_nsps=6912; m_FFTSize = m_nsps/2; Q_EMIT FFTSize (m_FFTSize); - m_hsymStop=18; + m_hsymStop=21; setup_status_bar (bVHF); - m_toneSpacing=12000.0/512.0; + m_toneSpacing=12000.0/576.0; ui->actionFT4->setChecked(true); m_wideGraph->setMode(m_mode); m_wideGraph->setModeTx(m_modeTx); @@ -5693,7 +5705,7 @@ void MainWindow::on_actionFT8_triggered() m_wideGraph->setModeTx(m_modeTx); VHF_features_enabled(bVHF); ui->cbAutoSeq->setChecked(true); - m_TRperiod=15; + m_TRperiod=15.0; m_fastGraph->hide(); m_wideGraph->show(); ui->decodedTextLabel2->setText(" UTC dB DT Freq Message"); @@ -5782,7 +5794,7 @@ void MainWindow::on_actionJT4_triggered() WSPR_config(false); switch_mode (Modes::JT4); m_modeTx="JT4"; - m_TRperiod=60; + m_TRperiod=60.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; //For symspec only @@ -5855,7 +5867,7 @@ void MainWindow::on_actionJT9_triggered() ui->decodedTextLabel2->setText("UTC dB T Freq Message"); } else { ui->cbAutoSeq->setChecked(false); - m_TRperiod=60; + m_TRperiod=60.0; ui->decodedTextLabel->setText("UTC dB DT Freq Message"); ui->decodedTextLabel2->setText("UTC dB DT Freq Message"); } @@ -5884,7 +5896,7 @@ void MainWindow::on_actionJT9_JT65_triggered() m_modeTx="JT9"; } m_nSubMode=0; //Dual-mode always means JT9 and JT65A - m_TRperiod=60; + m_TRperiod=60.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; @@ -5926,7 +5938,7 @@ void MainWindow::on_actionJT65_triggered() WSPR_config(false); switch_mode (Modes::JT65); if(m_modeTx!="JT65") on_pbTxMode_clicked(); - m_TRperiod=60; + m_TRperiod=60.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; //For symspec only @@ -6102,7 +6114,7 @@ void MainWindow::on_actionWSPR_triggered() WSPR_config(true); switch_mode (Modes::WSPR); m_modeTx="WSPR"; - m_TRperiod=120; + m_TRperiod=120.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; //For symspec only @@ -6130,7 +6142,7 @@ void MainWindow::on_actionWSPR_LF_triggered() m_mode="WSPR-LF"; switch_mode (Modes::WSPR); m_modeTx="WSPR-LF"; - m_TRperiod=240; + m_TRperiod=240.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_hsymStop=813; @@ -6146,7 +6158,7 @@ void MainWindow::on_actionEcho_triggered() on_actionJT4_triggered(); m_mode="Echo"; ui->actionEcho->setChecked(true); - m_TRperiod=3; + m_TRperiod=3.0; m_modulator->setTRPeriod(m_TRperiod); // TODO - not thread safe m_detector->setTRPeriod(m_TRperiod); // TODO - not thread safe m_nsps=6912; //For symspec only @@ -6425,7 +6437,6 @@ void MainWindow::on_bandComboBox_activated (int index) void MainWindow::band_changed (Frequency f) { -// bool monitor_off=!m_monitoring; // Set the attenuation value if options are checked QString curBand = ui->bandComboBox->currentText(); if (m_config.pwrBandTxMemory() && !m_tune) { @@ -6461,7 +6472,6 @@ void MainWindow::band_changed (Frequency f) if(r<0.9 or r>1.1) m_bVHFwarned=false; setRig (f); setXIT (ui->TxFreqSpinBox->value ()); -// if(monitor_off) monitor(false); } } @@ -6942,7 +6952,7 @@ void MainWindow::transmit (double snr) m_dateTimeSentTx3=QDateTime::currentDateTimeUtc(); toneSpacing=-2.0; //Transmit a pre-computed, filtered waveform. Q_EMIT sendMessage (NUM_FT4_SYMBOLS, - 512.0, ui->TxFreqSpinBox->value() - m_XIT, + 576.0, ui->TxFreqSpinBox->value() - m_XIT, toneSpacing, m_soundOutput, m_config.audio_output_channel(), true, false, snr, m_TRperiod); } @@ -7245,7 +7255,7 @@ void MainWindow::on_sbSubmode_valueChanged(int n) on_cbFast9_clicked(false); ui->cbFast9->setEnabled(false); ui->sbTR->setVisible(false); - m_TRperiod=60; + m_TRperiod=60.0; } else { ui->cbFast9->setEnabled(true); } @@ -7267,9 +7277,9 @@ void MainWindow::on_cbFast9_clicked(bool b) if(b) { m_TRperiod = ui->sbTR->value (); } else { - m_TRperiod=60; + m_TRperiod=60.0; } - progressBar.setMaximum(m_TRperiod); + progressBar.setMaximum(int(m_TRperiod)); m_wideGraph->setPeriod(m_TRperiod,m_nsps); fast_config(b); statusChanged (); @@ -7813,7 +7823,7 @@ void MainWindow::setRig (Frequency f) void MainWindow::fastPick(int x0, int x1, int y) { float pixPerSecond=12000.0/512.0; - if(m_TRperiod<30) pixPerSecond=12000.0/256.0; + if(m_TRperiod<30.0) pixPerSecond=12000.0/256.0; if(m_mode!="ISCAT" and m_mode!="MSK144") return; if(!m_decoderBusy) { dec_data.params.newdat=0; @@ -8014,7 +8024,7 @@ void MainWindow::write_transmit_entry (QString const& file_name) { QTextStream out(&f); auto time = QDateTime::currentDateTimeUtc (); - time = time.addSecs (-(time.time ().second () % m_TRperiod)); + time = time.addSecs (-fmod(double(time.time().second()),m_TRperiod)); out << time.toString("yyMMdd_hhmmss") << " Transmitting " << qSetRealNumberPrecision (12) << (m_freqNominal / 1.e6) << " MHz " << m_modeTx @@ -8677,7 +8687,7 @@ void MainWindow::write_all(QString txRx, QString message) t.sprintf("%5d",ui->TxFreqSpinBox->value()); if (txRx=="Tx") msg=" 0 0.0" + t + " " + message; auto time = QDateTime::currentDateTimeUtc (); - time = time.addSecs(-(time.time().second() % m_TRperiod)); + time = time.addSecs(-fmod(double(time.time().second()),m_TRperiod)); t.sprintf("%10.3f ",m_freqNominal/1.e6); if (m_diskData) { if (m_fileDateTime.size()==11) { diff --git a/widgets/mainwindow.h b/widgets/mainwindow.h index eada752bc..ffa71c1fe 100644 --- a/widgets/mainwindow.h +++ b/widgets/mainwindow.h @@ -406,6 +406,7 @@ private: double m_s6; double m_tRemaining; + double m_TRperiod; float m_DTtol; float m_t0; @@ -428,7 +429,6 @@ private: qint32 m_ntr; qint32 m_tx; qint32 m_hsym; - qint32 m_TRperiod; qint32 m_nsps; qint32 m_hsymStop; qint32 m_inGain; diff --git a/widgets/plotter.cpp b/widgets/plotter.cpp index 98c1af168..badeff57b 100644 --- a/widgets/plotter.cpp +++ b/widgets/plotter.cpp @@ -241,9 +241,9 @@ void CPlotter::draw(float swide[], bool bScroll, bool bRed) painter1.setPen(Qt::white); QString t; qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - int n=(ms/1000) % m_TRperiod; + int n = fmod(0.001*ms,m_TRperiod); QDateTime t1=QDateTime::currentDateTimeUtc().addSecs(-n); - if(m_TRperiod < 60 or m_mode=="FT4") { + if(m_TRperiod<60.0) { t=t1.toString("hh:mm:ss") + " " + m_rxBand; } else { t=t1.toString("hh:mm") + " " + m_rxBand; @@ -411,7 +411,7 @@ void CPlotter::DrawOverlay() //DrawOverlay() } float bw=9.0*12000.0/m_nsps; //JT9 - if(m_mode=="FT4") bw=3*12000.0/512.0; //FT4 ### (3x, or 4x???) ### + if(m_mode=="FT4") bw=3*12000.0/576.0; //FT4 ### (3x, or 4x???) ### if(m_mode=="FT8") bw=7*12000.0/1920.0; //FT8 if(m_mode=="JT4") { //JT4 @@ -721,9 +721,9 @@ void CPlotter::mouseDoubleClickEvent (QMouseEvent * event) } } -void CPlotter::setNsps(int ntrperiod, int nsps) //setNsps +void CPlotter::setNsps(double trperiod, int nsps) //setNsps { - m_TRperiod=ntrperiod; + m_TRperiod=trperiod; m_nsps=nsps; m_fftBinWidth=1500.0/2048.0; if(m_nsps==15360) m_fftBinWidth=1500.0/2048.0; diff --git a/widgets/plotter.h b/widgets/plotter.h index e243c1777..2cbfd202b 100644 --- a/widgets/plotter.h +++ b/widgets/plotter.h @@ -56,7 +56,7 @@ public: void DrawOverlay(); int rxFreq(); void setFsample(int n); - void setNsps(int ntrperiod, int nsps); + void setNsps(double trperiod, int nsps); void setTxFreq(int n); void setMode(QString mode); void setSubMode(int n); @@ -145,6 +145,7 @@ private: double m_fftBinWidth; double m_dialFreq; double m_xOffset; + double m_TRperiod; float m_sum[2048]; @@ -161,7 +162,6 @@ private: qint32 m_h; qint32 m_h1; qint32 m_h2; - qint32 m_TRperiod; qint32 m_rxFreq; qint32 m_txFreq; qint32 m_fMin; diff --git a/widgets/widegraph.cpp b/widgets/widegraph.cpp index 1f3110cee..6234f731a 100644 --- a/widgets/widegraph.cpp +++ b/widgets/widegraph.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "ui_widegraph.h" #include "commons.h" #include "Configuration.hpp" @@ -23,7 +24,7 @@ WideGraph::WideGraph(QSettings * settings, QWidget *parent) : ui(new Ui::WideGraph), m_settings (settings), m_palettes_path {":/Palettes"}, - m_ntr0 {0}, + m_tr0 {0.0}, m_n {0}, m_bHaveTransmitted {false} { @@ -186,9 +187,8 @@ void WideGraph::dataSink2(float s[], float df3, int ihsym, int ndiskdata) //dat // Time according to this computer qint64 ms = QDateTime::currentMSecsSinceEpoch() % 86400000; - int ntr = (ms/1000) % m_TRperiod; - if((ndiskdata && ihsym <= m_waterfallAvg) || (!ndiskdata && - (ntrwidePlot->draw(swide,true,false); } } @@ -278,11 +278,11 @@ int WideGraph::fSpan() return ui->widePlot->fSpan (); } -void WideGraph::setPeriod(int ntrperiod, int nsps) //SetPeriod +void WideGraph::setPeriod(double trperiod, int nsps) //SetPeriod { - m_TRperiod=ntrperiod; + m_TRperiod=trperiod; m_nsps=nsps; - ui->widePlot->setNsps(ntrperiod, nsps); + ui->widePlot->setNsps(trperiod, nsps); } void WideGraph::setTxFreq(int n) //setTxFreq diff --git a/widgets/widegraph.h b/widgets/widegraph.h index 2b172ef7d..c87bab050 100644 --- a/widgets/widegraph.h +++ b/widgets/widegraph.h @@ -35,7 +35,7 @@ public: int fSpan(); void saveSettings(); void setFsample(int n); - void setPeriod(int ntrperiod, int nsps); + void setPeriod(double trperiod, int nsps); void setTxFreq(int n); void setMode(QString mode); void setSubMode(int n); @@ -95,10 +95,11 @@ private: WFPalette m_userPalette; QHash m_fMinPerBand; + double m_tr0; + double m_TRperiod; + qint32 m_waterfallAvg; - qint32 m_TRperiod; qint32 m_nsps; - qint32 m_ntr0; qint32 m_fMax; qint32 m_nSubMode; qint32 m_nsmo;