From 0504d2af92dd652566294d18890198f9d2afc55d Mon Sep 17 00:00:00 2001 From: Bill Somerville Date: Tue, 19 May 2015 17:52:47 +0000 Subject: [PATCH] Rig frequency calibration The settings are a linear calibration correction for the rig. Calibration constants are supplied as an intercept error in Hertz and a slope error in parts per million. The correction is applied only to the final frequencies going to and from the radio. This means that any transverter offsets are not corrected. This is appropriate as each transverter will have its own error factors. Transvertor and other individual band specific errors can only be corrected by adjusting the offset for the band. Thanks to Mike W9MDB for an initial implementation of Joe K1JT's suggestion. See also the WSPR documentation for details of calculating the required calibration constants. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5396 ab8295b8-cf94-4d9e-aec4-7959e3be5d79 --- Configuration.cpp | 54 +++++++++++++++------ Configuration.ui | 116 ++++++++++++++++++++++++++++++++++++++++++---- Transceiver.hpp | 1 + 3 files changed, 148 insertions(+), 23 deletions(-) diff --git a/Configuration.cpp b/Configuration.cpp index 7a12ebbdf..2ddc86388 100644 --- a/Configuration.cpp +++ b/Configuration.cpp @@ -132,6 +132,7 @@ #include #include #include +#include #include #include @@ -384,6 +385,8 @@ private: bool validate (); void message_box (QString const& reason, QString const& detail = QString ()); void fill_port_combo_box (QComboBox *); + Frequency apply_calibration (Frequency) const; + Frequency remove_calibration (Frequency) const; Q_SLOT void on_font_push_button_clicked (); Q_SLOT void on_decoded_text_font_push_button_clicked (); @@ -488,6 +491,8 @@ private: bool have_rig_; bool rig_changed_; TransceiverState cached_rig_state_; + double frequency_calibration_intercept_; + double frequency_calibration_slope_ppm_; // the following members are required to get the rig into split the // first time monitor or tune or Tx occur @@ -503,7 +508,6 @@ private: // no split. bool enforce_mode_and_split_; - FrequencyDelta transceiver_offset_; // configuration fields that we publish QString my_callsign_; @@ -716,7 +720,6 @@ Configuration::impl::impl (Configuration * self, QSettings * settings, QWidget * , setup_split_ {false} , required_tx_frequency_ {0} , enforce_mode_and_split_ {false} - , transceiver_offset_ {0} , default_audio_input_device_selected_ {false} , default_audio_output_device_selected_ {false} { @@ -1019,6 +1022,8 @@ void Configuration::impl::initialize_models () ui_->accept_udp_requests_check_box->setChecked (accept_udp_requests_); ui_->udpWindowToFront->setChecked(udpWindowToFront_); ui_->udpWindowRestore->setChecked(udpWindowRestore_); + ui_->calibration_intercept_spin_box->setValue (frequency_calibration_intercept_); + ui_->calibration_slope_ppm_spin_box->setValue (frequency_calibration_slope_ppm_); if (rig_params_.ptt_port.isEmpty ()) { @@ -1202,6 +1207,8 @@ void Configuration::impl::read_settings () accept_udp_requests_ = settings_->value ("AcceptUDPRequests", false).toBool (); udpWindowToFront_ = settings_->value ("udpWindowToFront",false).toBool (); udpWindowRestore_ = settings_->value ("udpWindowRestore",false).toBool (); + frequency_calibration_intercept_ = settings_->value ("CalibrationIntercept", 0.).toDouble (); + frequency_calibration_slope_ppm_ = settings_->value ("CalibrationSlopePPM", 0.).toDouble (); } void Configuration::impl::write_settings () @@ -1286,6 +1293,8 @@ void Configuration::impl::write_settings () settings_->setValue ("AcceptUDPRequests", accept_udp_requests_); settings_->setValue ("udpWindowToFront", udpWindowToFront_); settings_->setValue ("udpWindowRestore", udpWindowRestore_); + settings_->setValue ("CalibrationIntercept", frequency_calibration_intercept_); + settings_->setValue ("CalibrationSlopePPM", frequency_calibration_slope_ppm_); } void Configuration::impl::set_rig_invariants () @@ -1636,6 +1645,8 @@ void Configuration::impl::accept () save_directory_ = ui_->save_path_display_label->text (); enable_VHF_features_ = ui_->enable_VHF_features_check_box->isChecked (); decode_at_52s_ = ui_->decode_at_52s_check_box->isChecked (); + frequency_calibration_intercept_ = ui_->calibration_intercept_spin_box->value (); + frequency_calibration_slope_ppm_ = ui_->calibration_slope_ppm_spin_box->value (); auto new_server = ui_->udp_server_line_edit->text (); if (new_server != udp_server_name_) @@ -2091,9 +2102,8 @@ void Configuration::impl::transceiver_frequency (Frequency f) cached_rig_state_.frequency (f); cached_rig_state_.mode (mode); - // lookup offset - transceiver_offset_ = stations_.offset (f); - Q_EMIT frequency (f + transceiver_offset_, mode); + // apply any offset & calibration + Q_EMIT frequency (apply_calibration (f + stations_.offset (f)), mode); } } @@ -2101,16 +2111,17 @@ void Configuration::impl::transceiver_tx_frequency (Frequency f) { if (/* set_mode () || */ cached_rig_state_.tx_frequency () != f || cached_rig_state_.split () != !!f) { - cached_rig_state_.tx_frequency (f); cached_rig_state_.split (f); + cached_rig_state_.tx_frequency (f); - // lookup offset if we are in split mode - if (f) + // lookup offset and apply calibration if we are in split mode + if (cached_rig_state_.split ()) { - transceiver_offset_ = stations_.offset (f); - f += transceiver_offset_; + // apply and offset and calibration + f = apply_calibration (f + stations_.offset (f)); } + // Rationalise TX VFO mode if we ask for split and are // responsible for mode. Q_EMIT tx_frequency (f, cached_rig_state_.split () @@ -2217,15 +2228,17 @@ void Configuration::impl::handle_transceiver_update (TransceiverState state) close_rig (); } - cached_rig_state_ = state; + // take off calibration & offset + state.frequency (remove_calibration (state.frequency ()) - stations_.offset (state.frequency ())); - // take off offset - cached_rig_state_.frequency (cached_rig_state_.frequency () - transceiver_offset_); - if (cached_rig_state_.tx_frequency ()) + if (state.tx_frequency ()) { - cached_rig_state_.tx_frequency (cached_rig_state_.tx_frequency () - transceiver_offset_); + // take off calibration & offset + state.tx_frequency (remove_calibration (state.tx_frequency ()) - stations_.offset (state.tx_frequency ())); } + cached_rig_state_ = state; + // pass on to clients Q_EMIT self_->transceiver_update (cached_rig_state_); } @@ -2408,6 +2421,17 @@ void Configuration::impl::fill_port_combo_box (QComboBox * cb) cb->setEditText (current_text); } +auto Configuration::impl::apply_calibration (Frequency f) const -> Frequency +{ + return std::llround (frequency_calibration_intercept_ + + (1. + frequency_calibration_slope_ppm_ / 1.e6) * f); +} + +auto Configuration::impl::remove_calibration (Frequency f) const -> Frequency +{ + return std::llround ((f - frequency_calibration_intercept_) + / (1. + frequency_calibration_slope_ppm_ / 1.e6)); +} #if !defined (QT_NO_DEBUG_STREAM) ENUM_QDEBUG_OPS_IMPL (Configuration, DataMode); diff --git a/Configuration.ui b/Configuration.ui index b49044eab..ae5b3d2e0 100644 --- a/Configuration.ui +++ b/Configuration.ui @@ -1807,8 +1807,8 @@ for assessing propagation and system performance. Working Frequencies - - + + Qt::ActionsContextMenu @@ -1836,7 +1836,89 @@ for assessing propagation and system performance. - + + + + See WSPR documentattion Appendix C for details of how to determine these factors for your radio. + + + Frequency Calibration + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Intercept: + + + calibration_intercept_spin_box + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Hz + + + 2 + + + -9999.989999999999782 + + + 9999.989999999999782 + + + 0.100000000000000 + + + + + + + Slope: + + + calibration_slope_ppm_spin_box + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + ppm + + + 4 + + + -9.999900000000000 + + + 9.999900000000000 + + + 0.100000000000000 + + + 0.000000000000000 + + + + + + + Qt::Horizontal @@ -1849,6 +1931,19 @@ for assessing propagation and system performance. + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -2122,7 +2217,9 @@ soundcard changes quick_call_check_box tx_QSY_check_box disable_TX_on_73_check_box + enable_VHF_features_check_box watchdog_check_box + decode_at_52s_check_box CW_id_after_73_check_box CW_id_interval_spin_box rig_combo_box @@ -2136,11 +2233,12 @@ soundcard changes CAT_handshake_none_radio_button CAT_handshake_xon_radio_button CAT_handshake_hardware_radio_button + CAT_control_lines_group_box CAT_DTR_check_box CAT_RTS_check_box PTT_VOX_radio_button - PTT_DTR_radio_button PTT_CAT_radio_button + PTT_DTR_radio_button PTT_RTS_radio_button PTT_port_combo_box TX_source_data_radio_button @@ -2176,6 +2274,8 @@ soundcard changes udpWindowToFront udpWindowRestore frequencies_table_view + calibration_intercept_spin_box + calibration_slope_ppm_spin_box stations_table_view pbCQmsg pbMyCall @@ -2251,12 +2351,12 @@ soundcard changes - - - - + + + + diff --git a/Transceiver.hpp b/Transceiver.hpp index c0e91aeb2..00548440a 100644 --- a/Transceiver.hpp +++ b/Transceiver.hpp @@ -72,6 +72,7 @@ public: // // Aggregation of all of the rig and PTT state accessible via this // interface. + // class TransceiverState { public: