mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-28 19:43:15 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			375 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			375 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "astro.h"
 | |
| 
 | |
| #include <stdio.h>
 | |
| 
 | |
| #include <QApplication>
 | |
| #include <QFile>
 | |
| #include <QTextStream>
 | |
| #include <QSettings>
 | |
| #include <QDateTime>
 | |
| #include <QTimeZone>
 | |
| #include <QDir>
 | |
| #include <QCloseEvent>
 | |
| #include <QDebug>
 | |
| #include <math.h>
 | |
| 
 | |
| #include "commons.h"
 | |
| #include "MessageBox.hpp"
 | |
| #include "Configuration.hpp"
 | |
| #include "SettingsGroup.hpp"
 | |
| #include "qt_helpers.hpp"
 | |
| 
 | |
| #include "ui_astro.h"
 | |
| #include "moc_astro.cpp"
 | |
| 
 | |
| 
 | |
| extern "C" {
 | |
|   void astrosub(int nyear, int month, int nday, double uth, double freqMoon,
 | |
|                 const char * mygrid, const char * hisgrid,
 | |
|                 double * azsun, double * elsun, double * azmoon,
 | |
|                 double * elmoon, double * azmoondx, double * elmoondx, int * ntsky,
 | |
|                 int * ndop, int * ndop00, double * ramoon, double * decmoon, double * dgrd,
 | |
|                 double * poloffset, double * xnr, double * techo, double * width1,
 | |
|                 double * width2, bool bTx, const char * AzElFileName,
 | |
|                 const char * jpleph);
 | |
| }
 | |
| 
 | |
| Astro::Astro(QSettings * settings, Configuration const * configuration, QWidget * parent)
 | |
|   : QDialog {parent, Qt::WindowTitleHint}
 | |
|   , settings_ {settings}
 | |
|   , configuration_ {configuration}
 | |
|   , ui_ {new Ui::Astro}
 | |
|   , m_DopplerMethod {0}
 | |
|   , m_dop {0}
 | |
|   , m_dop00 {0}
 | |
|   //, m_dx_two_way_dop {0}
 | |
| {
 | |
|   ui_->setupUi (this);
 | |
|   setWindowTitle (QApplication::applicationName () + " - " + tr ("Astronomical Data"));
 | |
|   setBackgroundRole (QPalette::Base);
 | |
|   setAutoFillBackground (true);
 | |
|   connect (ui_->cbDopplerTracking, &QAbstractButton::toggled, ui_->doppler_widget, &QWidget::setVisible);
 | |
|   read_settings ();
 | |
|   ui_->text_label->clear ();
 | |
| }
 | |
| 
 | |
| Astro::~Astro ()
 | |
| {
 | |
|   Q_EMIT tracking_update ();
 | |
|   if (isVisible ()) write_settings ();
 | |
| }
 | |
| 
 | |
| void Astro::closeEvent (QCloseEvent * e)
 | |
| {
 | |
|   write_settings ();
 | |
|   e->ignore ();                 // do not allow closure by the window system
 | |
| }
 | |
| 
 | |
| void Astro::read_settings ()
 | |
| {
 | |
|   SettingsGroup g (settings_, "Astro");
 | |
|   bool b=settings_->value("DopplerTracking",false).toBool();
 | |
|   ui_->cbDopplerTracking->setChecked(b);
 | |
|   ui_->doppler_widget->setVisible (ui_->cbDopplerTracking->isChecked ());
 | |
|   m_DopplerMethod=settings_->value("DopplerMethod",0).toInt();
 | |
|   switch (m_DopplerMethod)
 | |
|     {
 | |
|     case 0: ui_->rbNoDoppler->setChecked (true); break;
 | |
|     case 1: ui_->rbFullTrack->setChecked (true); break;
 | |
|     case 2: ui_->rbConstFreqOnMoon->setChecked (true); break;
 | |
|     case 3: ui_->rbOwnEcho->setChecked (true); break;
 | |
|     case 4: ui_->rbOnDxEcho->setChecked (true); break;
 | |
|     case 5: ui_->rbCallDx->setChecked (true); break;
 | |
|     }
 | |
|   move (settings_->value ("window/pos", pos ()).toPoint ());
 | |
| }
 | |
| 
 | |
| void Astro::write_settings ()
 | |
| {
 | |
|   SettingsGroup g (settings_, "Astro");
 | |
|   settings_->setValue ("DopplerTracking", ui_->cbDopplerTracking->isChecked());
 | |
|   settings_->setValue ("DopplerMethod",m_DopplerMethod);
 | |
|   settings_->setValue ("window/pos", pos ());
 | |
| }
 | |
| 
 | |
| auto Astro::astroUpdate(QDateTime const& t, QString const& mygrid, QString const& hisgrid, Frequency freq,
 | |
|                         bool bEchoMode, bool bTx, bool bAuto, bool no_tx_QSY, double TR_period) -> Correction
 | |
| {
 | |
|   Frequency freq_moon {freq};
 | |
|   double azsun,elsun,azmoon,elmoon,azmoondx,elmoondx;
 | |
|   double ramoon,decmoon,dgrd,poloffset,xnr,techo,width1,width2;
 | |
|   int ntsky;
 | |
|   QString date {t.date().toString("yyyy MMM dd").trimmed ()};
 | |
|   QString utc {t.time().toString().trimmed ()};
 | |
|   int nyear {t.date().year()};
 | |
|   int month {t.date().month()};
 | |
|   int nday {t.date().day()};
 | |
|   int nhr {t.time().hour()};
 | |
|   int nmin {t.time().minute()};
 | |
|   double sec {t.time().second() + 0.001*t.time().msec()};
 | |
|   double uth {nhr + nmin/60.0 + sec/3600.0};
 | |
|   if(freq_moon < 1) freq_moon = 144000000;
 | |
|   auto const& AzElFileName = QDir::toNativeSeparators (configuration_->azel_directory ().absoluteFilePath ("azel.dat"));
 | |
|   auto const& jpleph = configuration_->data_dir ().absoluteFilePath ("JPLEPH");
 | |
| 
 | |
|   astrosub(nyear, month, nday, uth, static_cast<double> (freq_moon),
 | |
|            mygrid.toLatin1 ().data (),
 | |
|            hisgrid.toLatin1().data(),
 | |
|            &azsun, &elsun, &azmoon, &elmoon,
 | |
|            &azmoondx, &elmoondx, &ntsky, &m_dop, &m_dop00, &ramoon, &decmoon,
 | |
|            &dgrd, &poloffset, &xnr, &techo, &width1, &width2,
 | |
|            bTx,
 | |
|            AzElFileName.toLocal8Bit ().constData (),
 | |
|            jpleph.toLocal8Bit ().constData ());
 | |
| 
 | |
|   QString message;
 | |
|   {
 | |
|     QTextStream out {&message};
 | |
|     out << " " << date << "\n"
 | |
|       "UTC:  " << utc << "\n"
 | |
| #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
 | |
|         << Qt::fixed
 | |
| #else
 | |
|       << fixed
 | |
| #endif
 | |
|       << qSetFieldWidth (6)
 | |
|       << qSetRealNumberPrecision (1)
 | |
|       << "Az:     " << azmoon << "\n"
 | |
|       "El:     " << elmoon << "\n"
 | |
|       "SelfDop:" << m_dop00 << "\n"
 | |
|       "Width:  " << int(width1+0.5) << "\n"
 | |
|       << qSetRealNumberPrecision (2)
 | |
|       << "Delay:  " << techo << "\n"
 | |
|       << qSetRealNumberPrecision (1)
 | |
|       << "DxAz:   " << azmoondx << "\n"
 | |
|       "DxEl:   " << elmoondx << "\n"
 | |
|       "DxDop:  " << m_dop << "\n"
 | |
|       "DxWid:  " << int(width2+0.5) << "\n"
 | |
|       "Dec:    " << decmoon << "\n"
 | |
|       "SunAz:  " << azsun << "\n"
 | |
|       "SunEl:  " << elsun << "\n"
 | |
|       "Freq:   " << freq / 1.e6 << "\n";
 | |
|     if(freq>=5000000ull) {                     //Suppress data not relevant below VHF
 | |
|       out << "Tsky:   " << ntsky << "\n"
 | |
|         "Dpol:   " << poloffset << "\n"
 | |
|         "MNR:    " << xnr << "\n"
 | |
|         "Dist:   " << int((techo*149896)) << "\n" //wdg
 | |
|         "Dgrd:   " << dgrd;
 | |
|     }
 | |
|   }
 | |
|   ui_->text_label->setText(message);
 | |
| 
 | |
|   Correction correction;
 | |
|   correction.dop=m_dop00;
 | |
|   correction.width=width1;
 | |
|   if(hisgrid!="" and !bAuto) {
 | |
|     correction.dop=m_dop;
 | |
|     correction.width=width2;
 | |
|   }
 | |
|   if (ui_->cbDopplerTracking->isChecked()) {
 | |
|     ui_->sbRIT->setEnabled(bEchoMode and m_DopplerMethod==0);
 | |
|     switch (m_DopplerMethod)
 | |
|       {
 | |
|       case 1: // All Doppler correction done here; DX station stays at nominal dial frequency.
 | |
|         correction.rx =  m_dop;
 | |
|         break;
 | |
|       case 4: // All Doppler correction done here; DX station stays at nominal dial frequency. (Trial for OnDxEcho)
 | |
|         correction.rx =  m_dop;
 | |
|         break;
 | |
|         //case 5: // All Doppler correction done here; DX station stays at nominal dial frequency.
 | |
|       case 3: // Both stations do full correction on Rx and none on Tx
 | |
|         //correction.rx = bEchoMode ? m_dop00 : m_dop;
 | |
|         correction.rx =  m_dop00; // Now always sets RX to *own* echo freq
 | |
|         break;
 | |
|       case 2:
 | |
|         // Doppler correction to constant frequency on Moon
 | |
|         correction.rx = m_dop00 / 2;
 | |
|         break;
 | |
|       }
 | |
|     switch (m_DopplerMethod)
 | |
|       {
 | |
|       case 1: correction.tx = -correction.rx;
 | |
|         break;
 | |
|       case 2: correction.tx = -correction.rx;
 | |
|         break;
 | |
|       case 3: correction.tx = 0;
 | |
|         break;
 | |
|       case 4: // correction.tx = m_dop - m_dop00;
 | |
|         correction.tx = (2 * (m_dop - (m_dop00/2))) - m_dop;
 | |
|         //qDebug () << "correction.tx:" << correction.tx;
 | |
|         break;
 | |
|       case 5: correction.tx = - m_dop00;
 | |
|         break;
 | |
|       }
 | |
|     //if (3 != m_DopplerMethod || 4 != m_DopplerMethod) correction.tx = -correction.rx;
 | |
|     
 | |
|     if(bEchoMode && m_DopplerMethod == 1) correction.rx = 0;
 | |
| 
 | |
|     if (no_tx_QSY && 3 != m_DopplerMethod && 0 != m_DopplerMethod)
 | |
|       {
 | |
|        // calculate a single correction for transmit half way through
 | |
|        // the period as a compromise for rigs that can't CAT QSY
 | |
|        // while transmitting
 | |
|         //
 | |
|         // 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 - fmod(double(sec_since_epoch),TR_period) + 0.5*TR_period;
 | |
|         auto target_date_time = QDateTime::fromMSecsSinceEpoch (target_sec * 1000, Qt::UTC);
 | |
|         int nyear {target_date_time.date().year()};
 | |
|         int month {target_date_time.date().month()};
 | |
|         int nday {target_date_time.date().day()};
 | |
|         int nhr {target_date_time.time().hour()};
 | |
|         int nmin {target_date_time.time().minute()};
 | |
|         double sec {target_date_time.time().second() + 0.001*target_date_time.time().msec()};
 | |
|         double uth {nhr + nmin/60.0 + sec/3600.0};
 | |
|         astrosub(nyear, month, nday, uth, static_cast<double> (freq_moon),
 | |
|                   mygrid.toLatin1 ().data (),
 | |
|                   hisgrid.toLatin1().data(),
 | |
|                   &azsun, &elsun, &azmoon, &elmoon,
 | |
|                   &azmoondx, &elmoondx, &ntsky, &m_dop, &m_dop00, &ramoon, &decmoon,
 | |
|                   &dgrd, &poloffset, &xnr, &techo, &width1, &width2,
 | |
|                   bTx,
 | |
|                   nullptr,      // don't overwrite azel.dat
 | |
|                   jpleph.toLocal8Bit ().constData ());
 | |
|         FrequencyDelta offset {0};
 | |
|         switch (m_DopplerMethod)
 | |
|           {
 | |
|           case 1:
 | |
|             // All Doppler correction done here; DX station stays at nominal dial frequency.
 | |
|             offset = bEchoMode ? m_dop00 : m_dop;
 | |
|             break;
 | |
| 
 | |
|           case 2:
 | |
|             // Doppler correction to constant frequency on Moon
 | |
|             offset = m_dop00 / 2;
 | |
|             break;
 | |
| 
 | |
|           case 4:
 | |
|             // Doppler correction for OnDxEcho
 | |
|             offset = m_dop - (2 * (m_dop - (m_dop00/2)));
 | |
|             break;
 | |
| 
 | |
|             //case 5: correction.tx = - m_dop00;
 | |
|           case 5: offset = m_dop00;// version for _7
 | |
|             break;
 | |
|           }
 | |
|         correction.tx = -offset;
 | |
|         //qDebug () << "correction.tx (no tx qsy):" << correction.tx;
 | |
|       }
 | |
|   }
 | |
| 
 | |
| //  qDebug() << "AA0" << m_DopplerMethod << bAuto << correction.tx << correction.rx << correction.width;
 | |
|   return correction;
 | |
| }
 | |
| 
 | |
| void Astro::check_split ()
 | |
| {
 | |
|   /*  TEMPORARILY DISABLE
 | |
|   if (doppler_tracking () && !configuration_->split_mode ())
 | |
|     {
 | |
|       MessageBox::warning_message (this, tr ("Doppler Tracking Error"),
 | |
|                                    tr ("Split operating is required for Doppler tracking"),
 | |
|                                    tr ("Go to \"Menu->File->Settings->Radio\" to enable split operation"));
 | |
|       ui_->rbNoDoppler->click ();
 | |
|     }
 | |
|   */
 | |
| }
 | |
| 
 | |
| void Astro::on_rbFullTrack_clicked(bool)
 | |
| {
 | |
|   m_DopplerMethod = 1;
 | |
|   check_split ();
 | |
|   Q_EMIT tracking_update ();
 | |
| }
 | |
| 
 | |
| void Astro::on_rbOnDxEcho_clicked(bool)
 | |
| {
 | |
|   m_DopplerMethod = 4;
 | |
|   check_split ();
 | |
|   //if (checked) {
 | |
|   //  m_dx_two_way_dop = 2 * (m_dop - (m_dop00/2));
 | |
|   //  qDebug () << "Starting Doppler:" << m_dx_two_way_dop;
 | |
|   //}
 | |
|   Q_EMIT tracking_update ();
 | |
| }
 | |
| 
 | |
| void Astro::on_rbOwnEcho_clicked(bool)
 | |
| {
 | |
|   m_DopplerMethod = 3;
 | |
|   check_split ();
 | |
|   Q_EMIT tracking_update ();
 | |
| }
 | |
| 
 | |
| void Astro::on_rbCallDx_clicked(bool)
 | |
| {
 | |
|   m_DopplerMethod = 5;
 | |
|   check_split ();
 | |
|   Q_EMIT tracking_update ();
 | |
| }
 | |
| 
 | |
| void Astro::on_rbConstFreqOnMoon_clicked(bool)
 | |
| {
 | |
|   m_DopplerMethod = 2;
 | |
|   check_split ();
 | |
|   Q_EMIT tracking_update ();
 | |
| }
 | |
| 
 | |
| void Astro::on_rbNoDoppler_clicked(bool)
 | |
| {
 | |
|   m_DopplerMethod = 0;
 | |
|   Q_EMIT tracking_update ();
 | |
| }
 | |
| 
 | |
| bool Astro::doppler_tracking () const
 | |
| {
 | |
|   return ui_->cbDopplerTracking->isChecked () && m_DopplerMethod;
 | |
| }
 | |
| 
 | |
| void Astro::on_cbDopplerTracking_toggled(bool)
 | |
| {
 | |
|   check_split ();
 | |
|   Q_EMIT tracking_update ();
 | |
| }
 | |
| 
 | |
| void Astro::nominal_frequency (Frequency rx, Frequency tx)
 | |
| {
 | |
|   ui_->sked_frequency_label->setText (Radio::pretty_frequency_MHz_string (rx));
 | |
|   ui_->sked_tx_frequency_label->setText (Radio::pretty_frequency_MHz_string (tx));
 | |
| }
 | |
| 
 | |
| void Astro::hideEvent (QHideEvent * e)
 | |
| {
 | |
|   Q_EMIT tracking_update ();
 | |
|   QWidget::hideEvent (e);
 | |
| }
 | |
| 
 | |
| bool Astro::bDither()
 | |
| {
 | |
|   return ui_->cbDither->isChecked();
 | |
| }
 | |
| 
 | |
| void Astro::selectOwnEcho()
 | |
| {
 | |
|   ui_->rbOwnEcho->click();
 | |
| }
 | |
| 
 | |
| void Astro::selectOnDxEcho()
 | |
| {
 | |
|   ui_->rbOnDxEcho->click();
 | |
| }
 | |
| 
 | |
| qint32 Astro::nfRIT()
 | |
| {
 | |
|   if(m_DopplerMethod==0) {
 | |
|     return ui_->sbRIT->value();
 | |
|   } else {
 | |
|     return 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| qint32 Astro::DopplerMethod()
 | |
| {
 | |
|   return m_DopplerMethod;
 | |
| }
 |