mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-11-04 05:50:31 -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
							
								
									232e5b8577
								
							
						
					
					
						commit
						8dbcf403aa
					
				@ -4,6 +4,7 @@
 | 
				
			|||||||
#include <QSettings>
 | 
					#include <QSettings>
 | 
				
			||||||
#include <QBitArray>
 | 
					#include <QBitArray>
 | 
				
			||||||
#include <QList>
 | 
					#include <QList>
 | 
				
			||||||
 | 
					#include <QSet>
 | 
				
			||||||
#include <QtWidgets>
 | 
					#include <QtWidgets>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "SettingsGroup.hpp"
 | 
					#include "SettingsGroup.hpp"
 | 
				
			||||||
@ -221,6 +222,8 @@ public:
 | 
				
			|||||||
  Configuration const * configuration_;
 | 
					  Configuration const * configuration_;
 | 
				
			||||||
  int tx_percent_;
 | 
					  int tx_percent_;
 | 
				
			||||||
  BandList WSPR_bands_;
 | 
					  BandList WSPR_bands_;
 | 
				
			||||||
 | 
					  BandList rx_permutation_;
 | 
				
			||||||
 | 
					  BandList tx_permutation_;
 | 
				
			||||||
  QWidget * parent_widget_;
 | 
					  QWidget * parent_widget_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // 5 x 10 bit flags representing each hopping band in each period
 | 
					  // 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};
 | 
					  int frequencies_index {-1};
 | 
				
			||||||
  auto const& frequencies = m_->configuration_->frequencies ();
 | 
					  auto const& frequencies = m_->configuration_->frequencies ();
 | 
				
			||||||
  auto const& bands = m_->configuration_->bands ();
 | 
					  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
 | 
					  if (m_->bands_[period_index].testBit (band_index + 3) // +3 for
 | 
				
			||||||
                                                        // coordinated bands
 | 
					                                                        // coordinated bands
 | 
				
			||||||
      && m_->WSPR_bands_.contains (band_name))
 | 
					      && m_->WSPR_bands_.contains (band_name))
 | 
				
			||||||
@ -334,46 +337,72 @@ auto WSPRBandHopping::next_hop () -> Hop
 | 
				
			|||||||
      frequencies_index = frequencies->best_working_frequency (band_name);
 | 
					      frequencies_index = frequencies->best_working_frequency (band_name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // if we do not have a configured working frequency we next check
 | 
					  // if we do not have a configured working frequency on the selected
 | 
				
			||||||
  // for a random selection from the other enabled bands in the
 | 
					  // coordinated hopping band we next pick from a random permutation
 | 
				
			||||||
  // bands matrix
 | 
					  // of the other enabled bands in the hopping bands matrix
 | 
				
			||||||
  if (frequencies_index < 0)
 | 
					  if (frequencies_index < 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      Dialog::BandList target_bands {m_->WSPR_bands_};
 | 
					      // build sets of available rx and tx bands
 | 
				
			||||||
      // // remove all coordinated bands here since they are
 | 
					      auto target_rx_bands = m_->WSPR_bands_.toSet ();
 | 
				
			||||||
      // // scheduled above and including them in the random choice will
 | 
					      auto target_tx_bands = target_rx_bands;
 | 
				
			||||||
      // // give them a biased weighting
 | 
					 | 
				
			||||||
      // for (auto const& band : coordinated_bands)
 | 
					 | 
				
			||||||
      //   {
 | 
					 | 
				
			||||||
      //     target_bands.removeOne (band);
 | 
					 | 
				
			||||||
      //   }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      for (auto i = 0; i < m_->bands_[period_index].size (); ++i)
 | 
					      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
 | 
					          // remove bands that are not enabled for hopping in this phase
 | 
				
			||||||
          if (!m_->bands_[period_index].testBit (i)
 | 
					          if (!m_->bands_[period_index].testBit (i))
 | 
				
			||||||
              // remove Rx only bands if we are wanting to transmit
 | 
					 | 
				
			||||||
              || (tx_next && m_->bands_[5].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);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					      // if we have some bands to permute
 | 
				
			||||||
      auto num_bands = target_bands.size ();
 | 
					      if (target_rx_bands.size () + target_tx_bands.size ())
 | 
				
			||||||
      if (num_bands)            // we have some extra bands available
 | 
					 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
          int target_index = static_cast<int> (qrand () % num_bands); // random choice
 | 
					          if (!(m_->rx_permutation_.size () + m_->tx_permutation_.size ()) // all used up
 | 
				
			||||||
          // here we have a random choice that is enabled in the
 | 
					              // or rx list contains a band no longer scheduled
 | 
				
			||||||
          // hopping matrix
 | 
					              || !target_rx_bands.contains (m_->rx_permutation_.toSet ())
 | 
				
			||||||
          frequencies_index = frequencies->best_working_frequency (target_bands[target_index]);
 | 
					              // or tx list contains a band no longer scheduled for tx
 | 
				
			||||||
          if (frequencies_index >= 0)
 | 
					              || !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
 | 
					              // we can use the random choice
 | 
				
			||||||
              qDebug () << "random:" << frequencies->data (frequencies->index (frequencies_index, FrequencyList::frequency_column)).toString ();
 | 
					              // qDebug () << "random:" << frequencies->data (frequencies->index (frequencies_index, FrequencyList::frequency_column)).toString ();
 | 
				
			||||||
              band_index = bands->find (target_bands[target_index]);
 | 
					              band_index = bands->find (band_name);
 | 
				
			||||||
              if (band_index < 0)
 | 
					              if (band_index < 0) // this shouldn't happen
 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                  // this shouldn't happen
 | 
					 | 
				
			||||||
                  Q_ASSERT (band_index >= 0);
 | 
					                  Q_ASSERT (band_index >= 0);
 | 
				
			||||||
                  frequencies_index = -1;
 | 
					                  frequencies_index = -1;
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
@ -383,7 +412,11 @@ auto WSPRBandHopping::next_hop () -> Hop
 | 
				
			|||||||
  else
 | 
					  else
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
      band_index += 3;
 | 
					      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 {
 | 
					  return {
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,8 @@ class QWidget;
 | 
				
			|||||||
//    http://physics.princeton.edu/pulsar/K1JT/doc/wspr/wspr-main.html
 | 
					//    http://physics.princeton.edu/pulsar/K1JT/doc/wspr/wspr-main.html
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//  Along with selecting bands a flag  indicating that a short tune up
 | 
					//  Along with selecting bands a flag  indicating that a short tune up
 | 
				
			||||||
//  signal is required for specified bands.
 | 
					//  signal is  required for specified  bands before they are  used for
 | 
				
			||||||
 | 
					//  receive.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//  Provides a Qt property that holds  the Tx percentage which is used
 | 
					//  Provides a Qt property that holds  the Tx percentage which is used
 | 
				
			||||||
//  to generate a semi-randomized schedule of period to transmit. This
 | 
					//  to generate a semi-randomized schedule of period to transmit. This
 | 
				
			||||||
@ -75,6 +76,7 @@ public:
 | 
				
			|||||||
  bool next_is_tx ();
 | 
					  bool next_is_tx ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 | 
					  // implementation hidden from public interface
 | 
				
			||||||
  class impl;
 | 
					  class impl;
 | 
				
			||||||
  pimpl<impl> m_;
 | 
					  pimpl<impl> m_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
				
			|||||||
@ -4328,10 +4328,10 @@ void MainWindow::WSPR_scheduling ()
 | 
				
			|||||||
  bool transmit {false};
 | 
					  bool transmit {false};
 | 
				
			||||||
  if (ui->band_hopping_group_box->isChecked ()) {
 | 
					  if (ui->band_hopping_group_box->isChecked ()) {
 | 
				
			||||||
    auto hop_data = m_WSPR_band_hopping.next_hop ();
 | 
					    auto hop_data = m_WSPR_band_hopping.next_hop ();
 | 
				
			||||||
    qDebug () << "hop data: period:" << hop_data.period_name_
 | 
					    // qDebug () << "hop data: period:" << hop_data.period_name_
 | 
				
			||||||
              << "frequencies index:" << hop_data.frequencies_index_
 | 
					    // << "frequencies index:" << hop_data.frequencies_index_
 | 
				
			||||||
              << "tune:" << hop_data.tune_required_
 | 
					    // << "tune:" << hop_data.tune_required_
 | 
				
			||||||
              << "tx:" << hop_data.tx_next_;
 | 
					    // << "tx:" << hop_data.tx_next_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    transmit = hop_data.tx_next_;
 | 
					    transmit = hop_data.tx_next_;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user