An annotated example

The examples directory in the SpectrumWars source tree contains a number of player code examples (see it on GitHub). You are encouraged to explore the example code and study how it works. To help you,, one of the examples, is explained step-by-step in this section.

Refer to the Class reference for details on SpectrumWars-specific method calls used. The examples also use numpy to simplify some parts of the code. See NumPy reference for details.

# Import the Transceiver base class.
from spectrumwars import Transceiver

# Also import NumPy to get some convenient array functions.
import numpy as np

# Two modules from the Python standard library we'll use.
import random
import time

# First, let's write the code that controls our source.
class Source(Transceiver):

   # We use the procedural style in this example, so we only override the
   # start() method. This way our code gets called right at the start of
   # the game. Our source will not leave this method until the game
   # ends.
   def start(self):

      # We simply make an infinite loop. We don't need to care what happens
      # when the game ends - game controller takes care of cleaning up
      # after us.
      while True:

         # Ignore this delay for now. Real testbeds have various delays
         # when sending packets or when sensing the spectrum. Sometimes it
         # helps to artificially slow down your algorithm.

         # self.get_status().spectrum returns a list of received signal
         # strength indicators (RSSI) for all channels in the testbed.
         # Index into this array directly translates to the radio channel
         # number.
         # We convert the result to a NumPy array for convenience.
         spectrum = np.array( self.get_status().spectrum )

         # These two lines take the RSSI list and select one channel at
         # random from 20 channels that have the lowest signal strength.
         chl = np.argsort(spectrum)
         ch = chl[random.randint(0, 20)]

         # Now we tune the radio to the selected channel. We also select
         # the slowest (and most reliable) bitrate setting and the
         # strongest transmission power.
         self.set_configuration(ch, 0, 0)

         # Next, we transmit 20 packets on the selected channel. We don't
         # add any control data to the packets, so the complete packet is
         # filled with payload by the game controller.
         for n in xrange(20):

            # We delay a little bit the transmission of packets.

         # After 20 packets have been transmitted, our loop rolls around
         # for another iteration. We again check the spectrum occupancy,
         # select one of the channels that appear to be least occupied and
         # transmit another 20 packets.
         # The spectrum sensor has some averaging. If we would loop
         # immediately from self.send() to self.get_status(), the spectral
         # scan would still contain the trace of our own packets. Hence the
         # 200 ms delay at the start of the loop to let our packets fall
         # out of the averaging window and make it possible to select the
         # same channel again.

# Now for the destination side of the code.
class Destination(Transceiver):

   # Again, destination spends the duration of the game in the start() method.
   def start(self):

      # Since the first thing we do in the source is a 200 ms delay,
      # there is no point in trying to receive anything earlier than that.

      # Another infinite loop.
      while True:

         # Wait a bit more to be sure that the source is transmitting
         # at this point and that its packets have been picket up by the
         # spectrum sensor.

         # Use the same method as in the source to get a NumPy array
         # containing RSSI values for all channels.
         spectrum = np.array( self.get_status().spectrum )

         # This line uses a similar argsort trick as in the source.
         # We want an array of channel numbers, sorted with the channel with
         # the highest signal strength on top.
         chl = np.argsort(spectrum)[::-1]

         # For each channel of the top five by signal strength...
         for ch in chl[:5]:

            # ... tune the radio to that channel. Set bitrate to the same
            # one as used by the source.
            # We also set the transmit power to the higher setting. However
            # we don't transmit anything from the destination side in this
            # example.
            self.set_configuration(ch, 0, 0)

            # On the selected channel, wait 200 ms for a packet.
            for packet in self.recv_loop(timeout=.2):

               # We don't do anything with the received packet - the
               # source did not include any control data that would be
               # interesting to us.
               # Game controller takes care of the payload data automatically.
               # If a packet has been received within 200 ms, the inner for
               # loop rolls around and waits 200 ms for another packet.

            # If a packet has not been received for 200 ms, the outer for
            # loop tries with the next most occupied channel.

         # If reception has been unsuccessful, the while loop rolls around
         # and performs another spectral scan, repeating the process.

At this point, you should try running this example in the simulation a few times and check the resulting time-frequency diagrams. Try to run it in a game competing with some other example players. Find its flaws and see how it can be improved.