mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-11-03 21:40:52 -05:00 
			
		
		
		
	Improved WSPR band hopping band selection
When band hopping, coordinated slots that are unavailable may be substituted by non-coordinated bands or non-scheduled coordinated bands. Rather than randomly choosing a substitute band, random permutations of available receive-only and transmit allowed bands are generated and consumed one at a time when a substitute band is required. This ensures that all available bands get an airing on a regular basis while selections remain randomized as much as possible within the user defined constraints of coordinated bands, transmit ratio and Rx only bands. git-svn-id: svn+ssh://svn.code.sf.net/p/wsjt/wsjt/branches/wsjtx@5616 ab8295b8-cf94-4d9e-aec4-7959e3be5d79
This commit is contained in:
		
							parent
							
								
									9375c73b1c
								
							
						
					
					
						commit
						cecb01b446
					
				@ -4,6 +4,7 @@
 | 
			
		||||
#include <QSettings>
 | 
			
		||||
#include <QBitArray>
 | 
			
		||||
#include <QList>
 | 
			
		||||
#include <QSet>
 | 
			
		||||
#include <QtWidgets>
 | 
			
		||||
 | 
			
		||||
#include "SettingsGroup.hpp"
 | 
			
		||||
@ -221,6 +222,8 @@ public:
 | 
			
		||||
  Configuration const * configuration_;
 | 
			
		||||
  int tx_percent_;
 | 
			
		||||
  BandList WSPR_bands_;
 | 
			
		||||
  BandList rx_permutation_;
 | 
			
		||||
  BandList tx_permutation_;
 | 
			
		||||
  QWidget * parent_widget_;
 | 
			
		||||
 | 
			
		||||
  // 5 x 10 bit flags representing each hopping band in each period
 | 
			
		||||
@ -324,7 +327,7 @@ auto WSPRBandHopping::next_hop () -> Hop
 | 
			
		||||
  int frequencies_index {-1};
 | 
			
		||||
  auto const& frequencies = m_->configuration_->frequencies ();
 | 
			
		||||
  auto const& bands = m_->configuration_->bands ();
 | 
			
		||||
  auto const& band_name = bands->data (bands->index (band_index + 3, 0)).toString ();
 | 
			
		||||
  auto band_name = bands->data (bands->index (band_index + 3, 0)).toString ();
 | 
			
		||||
  if (m_->bands_[period_index].testBit (band_index + 3) // +3 for
 | 
			
		||||
                                                        // coordinated bands
 | 
			
		||||
      && m_->WSPR_bands_.contains (band_name))
 | 
			
		||||
@ -334,56 +337,86 @@ auto WSPRBandHopping::next_hop () -> Hop
 | 
			
		||||
      frequencies_index = frequencies->best_working_frequency (band_name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  // if we do not have a configured working frequency we next check
 | 
			
		||||
  // for a random selection from the other enabled bands in the
 | 
			
		||||
  // bands matrix
 | 
			
		||||
  // if we do not have a configured working frequency on the selected
 | 
			
		||||
  // coordinated hopping band we next pick from a random permutation
 | 
			
		||||
  // of the other enabled bands in the hopping bands matrix
 | 
			
		||||
  if (frequencies_index < 0)
 | 
			
		||||
    {
 | 
			
		||||
      Dialog::BandList target_bands {m_->WSPR_bands_};
 | 
			
		||||
      // // remove all coordinated bands here since they are
 | 
			
		||||
      // // scheduled above and including them in the random choice will
 | 
			
		||||
      // // give them a biased weighting
 | 
			
		||||
      // for (auto const& band : coordinated_bands)
 | 
			
		||||
      //   {
 | 
			
		||||
      //     target_bands.removeOne (band);
 | 
			
		||||
      //   }
 | 
			
		||||
 | 
			
		||||
      // build sets of available rx and tx bands
 | 
			
		||||
      auto target_rx_bands = m_->WSPR_bands_.toSet ();
 | 
			
		||||
      auto target_tx_bands = target_rx_bands;
 | 
			
		||||
      for (auto i = 0; i < m_->bands_[period_index].size (); ++i)
 | 
			
		||||
        {
 | 
			
		||||
          auto const& band = bands->data (bands->index (i, 0)).toString ();
 | 
			
		||||
          // remove bands that are not enabled for hopping in this phase
 | 
			
		||||
          if (!m_->bands_[period_index].testBit (i)
 | 
			
		||||
              // remove Rx only bands if we are wanting to transmit
 | 
			
		||||
              || (tx_next && m_->bands_[5].testBit (i)))
 | 
			
		||||
          if (!m_->bands_[period_index].testBit (i))
 | 
			
		||||
            {
 | 
			
		||||
              target_bands.removeOne (bands->data (bands->index (i, 0)).toString ());
 | 
			
		||||
              target_rx_bands.remove (band);
 | 
			
		||||
              target_tx_bands.remove (band);
 | 
			
		||||
            }
 | 
			
		||||
          // remove rx only bands from transmit list and vice versa
 | 
			
		||||
          if (m_->bands_[5].testBit (i))
 | 
			
		||||
            {
 | 
			
		||||
              target_tx_bands.remove (band);
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              target_rx_bands.remove (band);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      auto num_bands = target_bands.size ();
 | 
			
		||||
      if (num_bands)            // we have some extra bands available
 | 
			
		||||
      // if we have some bands to permute
 | 
			
		||||
      if (target_rx_bands.size () + target_tx_bands.size ())
 | 
			
		||||
        {
 | 
			
		||||
          int target_index = static_cast<int> (qrand () % num_bands); // random choice
 | 
			
		||||
          // here we have a random choice that is enabled in the
 | 
			
		||||
          // hopping matrix
 | 
			
		||||
          frequencies_index = frequencies->best_working_frequency (target_bands[target_index]);
 | 
			
		||||
          if (frequencies_index >= 0)
 | 
			
		||||
          if (!(m_->rx_permutation_.size () + m_->tx_permutation_.size ()) // all used up
 | 
			
		||||
              // or rx list contains a band no longer scheduled
 | 
			
		||||
              || !target_rx_bands.contains (m_->rx_permutation_.toSet ())
 | 
			
		||||
              // or tx list contains a band no longer scheduled for tx
 | 
			
		||||
              || !target_tx_bands.contains (m_->tx_permutation_.toSet ()))
 | 
			
		||||
            {
 | 
			
		||||
              // build new random permutations
 | 
			
		||||
              m_->rx_permutation_ = target_rx_bands.toList ();
 | 
			
		||||
              std::random_shuffle (std::begin (m_->rx_permutation_), std::end (m_->rx_permutation_));
 | 
			
		||||
              m_->tx_permutation_ = target_tx_bands.toList ();
 | 
			
		||||
              std::random_shuffle (std::begin (m_->tx_permutation_), std::end (m_->tx_permutation_));
 | 
			
		||||
              // qDebug () << "New random Rx permutation:" << m_->rx_permutation_
 | 
			
		||||
              //           << "random Tx permutation:" << m_->tx_permutation_;
 | 
			
		||||
            }
 | 
			
		||||
          if ((tx_next && m_->tx_permutation_.size ()) || !m_->rx_permutation_.size ())
 | 
			
		||||
            {
 | 
			
		||||
              Q_ASSERT (m_->tx_permutation_.size ());
 | 
			
		||||
              // use one from the current random tx permutation
 | 
			
		||||
              band_name = m_->tx_permutation_.takeFirst ();
 | 
			
		||||
            }
 | 
			
		||||
          else
 | 
			
		||||
            {
 | 
			
		||||
              Q_ASSERT (m_->rx_permutation_.size ());
 | 
			
		||||
              // use one from the current random rx permutation
 | 
			
		||||
              band_name = m_->rx_permutation_.takeFirst ();
 | 
			
		||||
            }
 | 
			
		||||
          // find the first WSPR working frequency for the chosen band
 | 
			
		||||
          frequencies_index = frequencies->best_working_frequency (band_name);
 | 
			
		||||
          if (frequencies_index >= 0) // should be a redundant check,
 | 
			
		||||
                                      // but to be safe
 | 
			
		||||
            {
 | 
			
		||||
              // we can use the random choice
 | 
			
		||||
              qDebug () << "random:" << frequencies->data (frequencies->index (frequencies_index, FrequencyList::frequency_column)).toString ();
 | 
			
		||||
              band_index = bands->find (target_bands[target_index]);
 | 
			
		||||
              if (band_index < 0)
 | 
			
		||||
              // qDebug () << "random:" << frequencies->data (frequencies->index (frequencies_index, FrequencyList::frequency_column)).toString ();
 | 
			
		||||
              band_index = bands->find (band_name);
 | 
			
		||||
              if (band_index < 0) // this shouldn't happen
 | 
			
		||||
                {
 | 
			
		||||
                  // this shouldn't happen
 | 
			
		||||
                  Q_ASSERT (band_index >= 0);
 | 
			
		||||
                  frequencies_index = -1;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
     }
 | 
			
		||||
  else
 | 
			
		||||
    {
 | 
			
		||||
      band_index += 3;
 | 
			
		||||
      qDebug () << "scheduled:" << frequencies->data (frequencies->index (frequencies_index, FrequencyList::frequency_column)).toString ();
 | 
			
		||||
      // qDebug () << "scheduled:" << frequencies->data (frequencies->index (frequencies_index, FrequencyList::frequency_column)).toString ();
 | 
			
		||||
      // remove from random permutations to stop the coordinated bands
 | 
			
		||||
      // getting too high a weighting - not perfect but surely helps
 | 
			
		||||
      m_->rx_permutation_.removeOne (band_name);
 | 
			
		||||
      m_->tx_permutation_.removeOne (band_name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
@ -391,13 +424,13 @@ auto WSPRBandHopping::next_hop () -> Hop
 | 
			
		||||
 | 
			
		||||
    , frequencies_index
 | 
			
		||||
 | 
			
		||||
    , frequencies_index >= 0  // new band
 | 
			
		||||
      && !tx_next               // not going to Tx anyway
 | 
			
		||||
      && m_->bands_[4].testBit (band_index) // tune up required
 | 
			
		||||
    , frequencies_index >= 0                 // new band
 | 
			
		||||
      && !tx_next                            // not going to Tx anyway
 | 
			
		||||
      && m_->bands_[4].testBit (band_index)  // tune up required
 | 
			
		||||
      && !m_->bands_[5].testBit (band_index) // not an Rx only band
 | 
			
		||||
 | 
			
		||||
    , frequencies_index >= 0  // new band
 | 
			
		||||
      && tx_next                // Tx scheduled
 | 
			
		||||
    , frequencies_index >= 0                 // new band
 | 
			
		||||
      && tx_next                             // Tx scheduled
 | 
			
		||||
      && !m_->bands_[5].testBit (band_index) // not an Rx only band
 | 
			
		||||
   };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -22,8 +22,9 @@ class QWidget;
 | 
			
		||||
//
 | 
			
		||||
//    http://physics.princeton.edu/pulsar/K1JT/doc/wspr/wspr-main.html
 | 
			
		||||
//
 | 
			
		||||
//  Along with selecting bands a flag indicating that a short tune up
 | 
			
		||||
//  signal is required for specified bands.
 | 
			
		||||
//  Along with selecting bands a flag  indicating that a short tune up
 | 
			
		||||
//  signal is  required for specified  bands before they are  used for
 | 
			
		||||
//  receive.
 | 
			
		||||
//
 | 
			
		||||
//  Provides a Qt property that holds  the Tx percentage which is used
 | 
			
		||||
//  to generate a semi-randomized schedule of period to transmit. This
 | 
			
		||||
@ -75,6 +76,7 @@ public:
 | 
			
		||||
  bool next_is_tx ();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
  // implementation hidden from public interface
 | 
			
		||||
  class impl;
 | 
			
		||||
  pimpl<impl> m_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -4328,10 +4328,10 @@ void MainWindow::WSPR_scheduling ()
 | 
			
		||||
  bool transmit {false};
 | 
			
		||||
  if (ui->band_hopping_group_box->isChecked ()) {
 | 
			
		||||
    auto hop_data = m_WSPR_band_hopping.next_hop ();
 | 
			
		||||
    qDebug () << "hop data: period:" << hop_data.period_name_
 | 
			
		||||
              << "frequencies index:" << hop_data.frequencies_index_
 | 
			
		||||
              << "tune:" << hop_data.tune_required_
 | 
			
		||||
              << "tx:" << hop_data.tx_next_;
 | 
			
		||||
    // qDebug () << "hop data: period:" << hop_data.period_name_
 | 
			
		||||
    // << "frequencies index:" << hop_data.frequencies_index_
 | 
			
		||||
    // << "tune:" << hop_data.tune_required_
 | 
			
		||||
    // << "tx:" << hop_data.tx_next_;
 | 
			
		||||
 | 
			
		||||
    transmit = hop_data.tx_next_;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user