class RemoteDeviceUnderTest(DeviceUnderTest): def add_options(self, parser): add_communication_options(parser) parser.add_option("-n", "--node", dest="node", metavar="ADDR", type="int", help="Connect to node with ZigBit address ADDR") def setup(self, options): if not options.verbosity: options.verbosity = "warning" coor = get_coordinator(options) coor.post("prog/firstcall", "1") self.node = ALHProxy(coor, options.node) self.node.post("prog/firstcall", "1") self.spectrumsensor = SpectrumSensor(self.node) self.config_list = self.spectrumsensor.get_config_list() if not self.config_list.configs: raise Exception("Device returned no configurations. " "It is still scanning or not responding.") self.config = self.config_list.get_config(self.device_id, self.config_id) def get_fw_version(self): return self.node.get("hello").strip() def get_status(self): resp = self.node.get("sensing/deviceStatus").strip() return [v.strip() for v in resp.split("\n")] def measure_ch_impl(self, ch, n): sweep_config = SweepConfig(self.config, ch, ch + 1, 1) duration = int(math.ceil(self.config.time * n * 1e-3 + 1.0)) now = time.time() sensor_program = SpectrumSensorProgram(sweep_config, now + 1, duration, 2) self.spectrumsensor.program(sensor_program) while not self.spectrumsensor.is_complete(sensor_program): time.sleep(1) result = self.spectrumsensor.retrieve(sensor_program) measurements = [sweep.data[0] for sweep in result.sweeps] measurements = measurements[:n] assert len(measurements) == n return measurements
class IsmtvModule(wishful_module.AgentModule): node = None sensor = None sweep_config = None generator = None tx_config = None def __init__(self, dev): super(IsmtvModule, self).__init__() self.log = logging.getLogger('IsmtvModule') ser = serial.Serial(dev, 115200) self.node = alh.ALHTerminal(ser) @wishful_module.bind_function(upis.radio.get_measurements) def get_measurements(self, params): if not self.sensor: self.sensor = SpectrumSensor(self.node) config_list = self.sensor.get_config_list() self.sweep_config = config_list.get_sweep_config( params[0], params[1], params[2]) if self.sweep_config is None: self.sensor = None raise Exception("Node can not scan specified frequency range.") sweep = self.sensor.sweep(self.sweep_config) f = list(self.sweep_config.get_hz_list()) p = sweep.data return {'frequency': f, 'power': p} @wishful_module.bind_function(upis.radio.play_waveform) def play_waveform(self, iface, freq, power_lvl, kwargs): if not self.generator: self.generator = SignalGenerator(self.node) config_list = self.generator.get_config_list() self.tx_config = config_list.get_tx_config(freq, power_lvl) if self.tx_config is None: self.generator = None return 2 now = time.time() program = SignalGeneratorProgram(self.tx_config, now + 5, kwargs['play_time']) self.generator.program(program) return 0 @wishful_module.bind_function(upis.radio.get_radio_info) def get_radio_info(self, platform_id): if platform_id == "sensor": sensor = SpectrumSensor(self.node) config_list = sensor.get_config_list() elif platform_id == "generator": generator = SignalGenerator(self.node) config_list = generator.get_config_list() else: config_list = str( platform_id) + ": Not supported! Try: sensor or generator" return config_list
def get_radio_info(self, platform_id): if platform_id == "sensor": sensor = SpectrumSensor(self.node) config_list = sensor.get_config_list() elif platform_id == "generator": generator = SignalGenerator(self.node) config_list = generator.get_config_list() else: config_list = str(platform_id) + ": Not supported! Try: sensor or generator" return config_list
def get_measurements(self, params): if not self.sensor: self.sensor = SpectrumSensor(self.node) config_list = self.sensor.get_config_list() self.sweep_config = config_list.get_sweep_config(params[0], params[1], params[2]) if self.sweep_config is None: self.sensor = None raise Exception("Node can not scan specified frequency range.") sweep = self.sensor.sweep(self.sweep_config) f = list(self.sweep_config.get_hz_list()) p = sweep.data return {'frequency':f, 'power':p}
class RemoteDeviceUnderTest(DeviceUnderTest): def add_options(self, parser): add_communication_options(parser) parser.add_option( "-n", "--node", dest="node", metavar="ADDR", type="int", help="Connect to node with ZigBit address ADDR" ) def setup(self, options): if not options.verbosity: options.verbosity = "warning" coor = get_coordinator(options) coor.post("prog/firstcall", "1") self.node = ALHProxy(coor, options.node) self.node.post("prog/firstcall", "1") self.spectrumsensor = SpectrumSensor(self.node) self.config_list = self.spectrumsensor.get_config_list() if not self.config_list.configs: raise Exception("Device returned no configurations. " "It is still scanning or not responding.") self.config = self.config_list.get_config(self.device_id, self.config_id) def get_fw_version(self): return self.node.get("hello").strip() def get_status(self): resp = self.node.get("sensing/deviceStatus").strip() return [v.strip() for v in resp.split("\n")] def measure_ch_impl(self, ch, n): sweep_config = SweepConfig(self.config, ch, ch + 1, 1) duration = int(math.ceil(self.config.time * n * 1e-3 + 1.0)) now = time.time() sensor_program = SpectrumSensorProgram(sweep_config, now + 1, duration, 2) self.spectrumsensor.program(sensor_program) while not self.spectrumsensor.is_complete(sensor_program): time.sleep(1) result = self.spectrumsensor.retrieve(sensor_program) measurements = [sweep.data[0] for sweep in result.sweeps] measurements = measurements[:n] assert len(measurements) == n return measurements
def test_sweep_1(self): class MockALH(ALHProtocol): def _post(self, resource, data, *args): return b"\x00\x00\x01\x00\x02\x00D\xa4H;" alh = MockALH() ss = SpectrumSensor(alh) sc = self._get_sc() r = ss.sweep(sc) self.assertEqual(r.data, [0., .01, .02])
def test_get_config_list_corrupt_1(self): class TestALH: def get(self, resource): return "".encode('ascii') alh = TestALH() s = SpectrumSensor(alh) cl = s.get_config_list() self.assertEqual(cl.configs, []) self.assertEqual(cl.devices, [])
def test_get_config_list_corrupt_1(self): class TestALH: def get(self, resource): return "" alh = TestALH() s = SpectrumSensor(alh) cl = s.get_config_list() self.assertEquals(cl.configs, []) self.assertEquals(cl.devices, [])
def test_sweep_2(self): class MockALH(ALHProtocol): def _post(self, resource, data, *args): # negative CRC return b"\x00\x00\x01\x00\x08\x00\xceL\xa7\xc1" alh = MockALH() ss = SpectrumSensor(alh) sc = self._get_sc() r = ss.sweep(sc) self.assertEqual(r.data, [0., .01, .08])
def __init__(self, txnode, rxnode): # We set up the SignalGenerator and SpectrumSensor objects here # for later use. We also query both nodes for their # corresponding lists of available hardware configurations. # # Since hardware will not change during the experiment, we only # do the query once in object constructor. This makes repeated # measurements faster. self.generator = SignalGenerator(txnode) self.generator_cl = self.generator.get_config_list() self.sensor = SpectrumSensor(rxnode) self.sensor_cl = self.sensor.get_config_list()
def test_get_config_list_corrupt_1(self): class TestALH: def get(self, resource): return ALHResponse("".encode('ascii')) alh = TestALH() s = SpectrumSensor(alh) cl = s.get_config_list() self.assertEqual(cl.configs, []) self.assertEqual(cl.devices, [])
def test_get_config_list(self): class TestALH: def get(self, resource): s = "dev #0, Test, 1 configs:\n" \ " cfg #0: Test:\n" \ " base: 10 Hz, spacing: 1 Hz, bw: 1 Hz, channels: 10, time: 1 ms" return s.encode('ascii') alh = TestALH() s = SpectrumSensor(alh) cl = s.get_config_list() self.assertEqual(len(cl.devices), 1) self.assertEqual(len(cl.configs), 1)
def test_get_config_list(self): class TestALH: def get(self, resource): return "dev #0, Test, 1 configs:\n" \ " cfg #0: Test:\n" \ " base: 10 Hz, spacing: 1 Hz, bw: 1 Hz, channels: 10, time: 1 ms" alh = TestALH() s = SpectrumSensor(alh) cl = s.get_config_list() self.assertEquals(len(cl.devices), 1) self.assertEquals(len(cl.configs), 1)
def setSenseConfiguration(self, start_freq_hz, end_freq_hz, step_freq_hz): #sets the sensing configuration for sensing node. It measure the power in the band of [ start_freq_hz end_freq_hz]. #The sweep step is step_freq_hz self.sweep_config = SpectrumSensor(self.node).get_config_list().get_sweep_config(start_freq_hz, end_freq_hz, step_freq_hz) if self.sweep_config is None: raise Exception("Something went wrong with the sweep_config. Sweep_config is None")
def setSenseConfigurationChannel(self, start_ch, stop_ch, step_ch): #sets the sensing configuration for sensing node. It measures the power from start_ch to stop_ch #The sweep step is step_ch self.sweep_config = SweepConfig(SpectrumSensor(self.node).get_config_list().get_config(0,0) , start_ch, stop_ch, step_ch ) if self.sweep_config is None: raise Exception("Something went wrong with the sweep_config. Sweep_config is None")
def test_retrieve(self): class MockALH(ALHProtocol): def _get(self, resource, *args): if b"Info" in resource: return b"status=COMPLETE,size=14" else: return b"\x00\x00\x00\x00\x00\x00\x01\x00\x02\x00\x91m\x00i" alh = MockALH() ss = SpectrumSensor(alh) sc = self._get_sc() p = SpectrumSensorProgram(sc, 0, 10, 1) r = ss.retrieve(p) self.assertEqual(len(r.sweeps), 1) self.assertEqual(r.sweeps[0].data, [0., .01, .02]) self.assertEqual(r.sweeps[0].timestamp, 0)
def test_get_config_list_corrupt_2(self): class TestALH: def get(self, resource): s = "dev #0, Test, 2 configs:" return s.encode('ascii') alh = TestALH() s = SpectrumSensor(alh) self.assertRaises(CRCError, s.get_config_list)
def setSenseConfigurationFuulSweep(self): """Set sensing configuration. This method will sense the entire band that device supports. """ self.sensorNode = SpectrumSensor(self.node) sensorConfigList = self.sensorNode.get_config_list() # self.sweepConfig = SpectrumSensor(self.node).get_config_list().get_config(0,0).get_full_sweep_config() self.sweepConfig = sensorConfigList.get_config(0, 0).get_full_sweep_config() if self.sweepConfig is None: raise Exception("Something went wrong with the sweepConfig. sweepConfig is None")
def senseStart(self, time_start, time_duration , slot_id): #start spectrum sensing on node with the given configuration (self.sweep_config it is what matter) #may perform a few frequency sweeps, depends on the time duration #this can generate exception if sweep_config is None if self.sweep_config is None: print "Cannot start sensing, configuration is missing" return None #get a program object. program = SpectrumSensorProgram(self.sweep_config, time_start, time_duration , slot_id ) #get sensor object, with this we'll program the node sensor = SpectrumSensor(self.node) #program the sensor sensor.program(program) #waiting for the sensor to finish the job while not sensor.is_complete(program): print "waiting..." time.sleep(1) if time.time() > (program.time_start + program.time_duration + 60): raise Exception("Something went wrong with the sensing") print "Experiment is finished. retrieving data." result = sensor.retrieve(program) #try to make a folder try: os.mkdir("./data") except OSError: pass try: os.mkdir("./data/coor_%d" %self.coordinator_id) except OSError: pass #write results in a file result.write("./data/coor_%d/node_%s.dat" %(self.coordinator_id ,self.node_id))
def setup(self, options): if not options.verbosity: options.verbosity = "warning" coor = get_coordinator(options) coor.post("prog/firstcall", "1") self.node = ALHProxy(coor, options.node) self.node.post("prog/firstcall", "1") self.spectrumsensor = SpectrumSensor(self.node) self.config_list = self.spectrumsensor.get_config_list() if not self.config_list.configs: raise Exception("Device returned no configurations. " "It is still scanning or not responding.") self.config = self.config_list.get_config(self.device_id, self.config_id)
def setSenseConfigurationChannel(self, startCh, endCh, stepCh): """Set sensing configuration. Measure the power from start_ch to stop_ch with predefined step startCh -- Lowest frequency channel to sweep endCh -- One past the highest frequency channel to sweep stepCh -- How many channels in a step """ self.sensorNode = SpectrumSensor(self.node) sensorConfigList = self.sensorNode.get_config_list() self.sweepConfig = SweepConfig(sensorConfigList.get_config(0, 0), startCh, endCh, stepCh) if self.sweepConfig is None: raise Exception("Something went wrong with the sweepConfig. sweepConfig is None")
def setSenseConfiguration(self, startFreqHz, endFreqHz, stepFerqHz): """Set sensing configuration. Measure the power in frequency band [startFrewHz, endFreqHz] with a predefined step. startFreqHz -- Lower bound of the frequency band to check (inclusive) endFreqHz -- Upper bound of the frequency band to check (inclusive) stepFerqHz -- Frequency step """ self.sensorNode = SpectrumSensor(self.node) sensorConfigList = self.sensorNode.get_config_list() self.sweepConfig = sensorConfigList.get_sweep_config(startFreqHz, endFreqHz, stepFerqHz) if self.sweepConfig is None: raise Exception("Something went wrong with the sweepConfig. sweepConfig is None")
def main(): # Turn on logging so that we can see ALH requests happening in the # background. logging.basicConfig(level=logging.INFO) coor = alh.ALHWeb("https://crn.log-a-tec.eu/communicator", 10001) # Node 19 is equipped with an UHF receiver (TDA18219 on SNE-ISMTV-UHF) node = alh.ALHProxy(coor, 19) # Node 17 is equipped with an 2.4 GHz receiver (CC2500 on SNE-ISMTV-24) #node = alh.ALHProxy(coor, 17) # Wrap an ALHProxy object with a SpectrumSensor object that provides an # convenient interface to spectrum sensing functionality of the node # exposed through ALH resources. sensor = SpectrumSensor(node) # Get a ConfigList object that contains a list of device configurations # supported by the chosen sensor node. config_list = sensor.get_config_list() # ConfigList.get_sweep_config() method will automatically choose # the best device and configuration that can cover the requested # frequency range. # # It returns an instance of SweepConfig class that describes all # the settings for a frequency sweep. # # First example defines a sweep starting at 550 MHz and ending at # 574 MHz with 2 MHz steps (use with node 19) # # Second example define a sweep starting at 2420 MHz and ending at # 2430 MHz with 400 kHz steps (use with node 17) sweep_config = config_list.get_sweep_config(550e6, 574e6, 1e6) #sweep_config = config_list.get_sweep_config(2420e6, 2430e6, 400e3) if sweep_config is None: raise Exception("Node can not scan specified frequency range.") pyplot.ion() while True: # Perform the sweep sweep = sensor.sweep(sweep_config) # Get the list of frequencies covered by the sweep f_hz = sweep_config.get_hz_list() # Convert list from Hz to MHz for nicer plot f_mhz = numpy.array(f_hz) / 1e6 pyplot.clf() pyplot.grid() pyplot.xlabel("frequency [MHz]") pyplot.ylabel("power [dBm]") # Plot data pyplot.plot(f_mhz, sweep.data) pyplot.axis([min(f_mhz), max(f_mhz), -110, -50]) pyplot.draw() pyplot.pause(1)
def main(): # Turn on logging so that we can see ALH requests happening in the # background. logging.basicConfig(level=logging.INFO) coor = alh.ALHWeb("https://crn.log-a-tec.eu/communicator", 10001) # Nodes 16 and 17 are equipped with an 2.4 GHz tranceiver (CC2500 on # SNE-ISMTV-24) that is capable of transmitting and receiving on the # 2.4 GHz ISM band. node16 = alh.ALHProxy(coor, 16) node17 = alh.ALHProxy(coor, 17) # We will use node 16 as a signal generator. We wrap its ALHProxy # object with a SignalGenerator object for convenience. generator = SignalGenerator(node16) # Set up a transmission configuration for 2.425 GHz and 0 dBm generator_config_list = generator.get_config_list() tx_config = generator_config_list.get_tx_config(2425e6, 0) if tx_config is None: raise Exception("Node can not scan specified frequency range.") # We will use node 17 as a spectrum sensor. Again, we wrap it with a # SpectrumSensor object for convenience. sensor = SpectrumSensor(node17) # We set up a frequency sweep configuration covering 2.40 GHz to 2.45 # GHz band with 400 kHz steps. sensor_config_list = sensor.get_config_list() sweep_config = sensor_config_list.get_sweep_config(2400e6, 2450e6, 400e3) if sweep_config is None: raise Exception("Node can not scan specified frequency range.") # Take note of current time. now = time.time() # SignalGeneratorProgram and SpectrumSensorProgram objects allow us to # program signal generation and spectrum sensing tasks in advance. # # In this case, we setup a signal generation task using the # configuration we prepared above starting 10 seconds from now and # lasting for 20 seconds. # # Similarly for spectrum sensing, we setup a task using frequency sweep # we prepared above starting 5 seconds from now and lasting for 30 # seconds. Results of the measurement will be stored in slot 4. generator_program = SignalGeneratorProgram(tx_config, now + 10, 20) sensor_program = SpectrumSensorProgram(sweep_config, now + 5, 30, 4) # Now actually send instructions over the management network to nodes # in the testbed. generator.program(generator_program) sensor.program(sensor_program) # Query the spectrum sensing node and wait until the task has been # completed. while not sensor.is_complete(sensor_program): print "waiting..." time.sleep(2) # Retrieve spectrum sensing results. This might take a while since the # management mesh network is slow. result = sensor.retrieve(sensor_program) # Write results into a CSV file. result.write("06-programmed-tasks.dat")
def main(): # Turn on logging so that we can see requests and responses in the # terminal. logging.basicConfig(level=logging.INFO) # We must first create an object representing the coordinator node. coor_campus = alh.ALHWeb("https://crn.log-a-tec.eu/communicator", 9501) # Our experiment will start 15 seconds into the future - this should # give us plenty of time to set up everything. time_start = time.time() + 15 # First we set up the two transmitting nodes: # # Node 53 in the LOG-a-TEC Campus Zone will be playing the role of # the cognitive terminal. cognitive_terminal = SignalGenerator(alh.ALHProxy(coor_campus, 53)) # All nodes we will be using are equipped with SNE-ISMTV-2400 radio # boards with CC2500 transceivers. From the available list of # signal generation configurations supported by this hardware, we # choose the first one: It allows to transmit in 200 kHz wide channels. config_list = cognitive_terminal.get_config_list() device_config = config_list.get_config(0, 0) # Here we program the "cognitive_terminal" node to transmit for 25 # seconds on channel 110 (2422.0 MHz) and then change to channel 225 # (2445.0 MHz). Transmission power is set to 0 dBm. cognitive_terminal.program( SignalGeneratorProgram(TxConfig(device_config, 110, 0), time_start=(time_start + 5), time_duration=25)) cognitive_terminal.program( SignalGeneratorProgram(TxConfig(device_config, 225, 0), time_start=(time_start + 32), time_duration=23)) # Node 54 in the LOG-a-TEC Campus Zone will be playing the role of # the legacy terminal. legacy_terminal = SignalGenerator(alh.ALHProxy(coor_campus, 54)) # The legacy terminal, lacking the capability to change channels on # demand, is programmed to just transmit for 30 seconds on channel 114 # (2422.8 MHz) legacy_terminal.program( SignalGeneratorProgram(TxConfig(device_config, 114, 0), time_start=(time_start + 25), time_duration=30)) # Now we setup some sensing nodes so that we can observe the # transmissions from different points in the testbed. # We will use nodes 51 and 58 for this purpose. sensor_node_ids = [51, 58] sensor_nodes = [alh.ALHProxy(coor_campus, id) for id in sensor_node_ids] sensors = [SpectrumSensor(sensor_node) for sensor_node in sensor_nodes] # For sensing, we will use the first sensing configuration (255 # channels starting at 2.4 GHz with 400 kHz bandwidth) config_list = sensors[0].get_config_list() sweep_config = config_list.get_config(0, 0).get_full_sweep_config() # We instruct the nodes to perform spectrum sensing for 60 seconds. program = SpectrumSensorProgram(sweep_config, time_start, time_duration=60, slot_id=5) for sensor in sensors: sensor.program(program) # All nodes have been programmed at this point - wait for the experiment to finish. for sensor in sensors: while not sensor.is_complete(program): print "waiting..." time.sleep(2) if time.time() > (program.time_start + program.time_duration + 60): raise Exception("Something went wrong") print "experiment is finished. retrieving data." result = sensor.retrieve(program) # We will save the sensing results in a "data/" subdirectory. # Create it, if it doesn't already exist. try: os.mkdir("data") except OSError: pass # For each sensing node, we write the results into a CSV file. # The CSV file can be easily imported and plotted into tools # like MatLab. For example, to plot the recorded spectrogram # using GNU Plot, use the following commands: # # gnuplot> set pm3d map # gnuplot> set xlabel "frequency [MHz]" # gnuplot> set ylabel "time [s]" # gnuplot> set cblabel "power [dBm]" # gnuplot> unset key # gnuplot> splot "node17.csv" using ($2/1e6):1:3 result.write("data/node_%d.csv" % (sensor.alh.addr, ))
def main(): # Turn on logging so that we can see requests and responses in the # terminal. This is useful to keep track of what is going on during the # experiment. logging.basicConfig(level=logging.INFO) # We must first create an object representing the coordinator node. # Each cluster in the LOG-a-TEC has its own coordinator and all # communication with the nodes must go through it. # # The parameters used here correspond to the LOG-a-TEC City Center # out-door cluster (see LOG-a-TEC documentation for other valid # options). # # Note that you must have a valid user name and password saved in an # "alhrc" file in order for this to work. See vesna-alh-tools README # for instructions on how to do that. # # Also make sure you reserved the cluster in the calendar before # running the experiment! coor = alh.ALHWeb("https://crn.log-a-tec.eu/communicator", 10002) # We will be using node 45 in this example. First we create a generic # node object for it. node = alh.ALHProxy(coor, 45) # We will use our node as a spectrum sensor. Here, we wrap the generic # node object with the SpectrumSensor class that provides a convenient # interface to the spectrum sensing capabilities of the node's radio # hardware. sensor = SpectrumSensor(node) # Request the list of spectrum sensing configurations that the node # supports. # # Node 45 is equipped with a SNE-ISMTV-2400 radio board that contains a # CC2500 reconfigurable transceiver. This tranceiver supports a number # of configurations that cover the 2.4 GHz ISM band. sensor_config_list = sensor.get_config_list() # Let's print the list out in a nice format for future reference. print print "Spectrum sensing devices and configurations available" print "=====================================================" print sensor_config_list print # For a demonstration, we'll choose to sense the whole ISM band between # 2.4 GHz and 2.5 GHz with 400 kHz steps. We create a SweepConfig object # that describes this frequency range. sweep_config = sensor_config_list.get_sweep_config(2400e6, 2500e6, 400e3) if sweep_config is None: raise Exception("Node can not scan specified frequency range.") # Take note of current time. now = time.time() # SpectrumSensorProgram object allows us to program a node to perform a # spectrum sensing task in advance. We'll setup a task for sensing the # frequency range we selected above, starting 5 seconds from now and # lasting for 30 seconds. # # Each node has local slots for temporary storage of spectrum sensing # results. Since we are only performing one scan of the spectrum, it # doesn't matter which slot we use. Let's pick slot 1. sensor_program = SpectrumSensorProgram(sweep_config, now + 5, 30, 1) # Now we actually send the programming instructions over the testbed's # management network to the node. sensor.program(sensor_program) # Wait until the programmed task has been completed. while not sensor.is_complete(sensor_program): print "patience..." time.sleep(2) # The task is complete. We must now retrieve spectrum sensing results # back from the node to our computer. This might take a while since the # management mesh network is slow. result = sensor.retrieve(sensor_program) # Finally, we write results into a CSV file for further analysis. # # Alternatively, we could do something else with the results directly # from this program. The SpectrumSensorResult object provides some # convenient methods for accessing the result of the scan. result.write("logatec.csv")
def main(): coor_industrial_zone = alh.ALHWeb(get_communicator_url(), 10001) time_start = time.time() + 30 # Set up transmissions for node_id in [10, 8, 7]: node = alh.ALHProxy(coor_industrial_zone, node_id) node.post("prog/firstCall", "1") su1 = SignalGenerator(alh.ALHProxy(coor_industrial_zone, 10)) su2 = SignalGenerator(alh.ALHProxy(coor_industrial_zone, 8)) mic = SignalGenerator(alh.ALHProxy(coor_industrial_zone, 7)) config_list = su1.get_config_list() tx_config = config_list.get_tx_config(0, 0) mic.program( SignalGeneratorProgram( config_list.get_tx_config(f_hz=790e6, power_dbm=0), time_start=time_start+30, time_duration=40) ) mic.program( SignalGeneratorProgram( config_list.get_tx_config(f_hz=807e6, power_dbm=0), time_start=time_start+80, time_duration=40) ) su1.program( SignalGeneratorProgram( config_list.get_tx_config(f_hz=787e6, power_dbm=0), time_start=time_start, time_duration=35) ) su1.program( SignalGeneratorProgram( config_list.get_tx_config(f_hz=780e6, power_dbm=0), time_start=time_start+35, time_duration=90) ) su2.program( SignalGeneratorProgram( config_list.get_tx_config(f_hz=795e6, power_dbm=0), time_start=time_start, time_duration=35) ) su2.program( SignalGeneratorProgram( config_list.get_tx_config(f_hz=800e6, power_dbm=0), time_start=time_start+35, time_duration=50) ) su2.program( SignalGeneratorProgram( config_list.get_tx_config(f_hz=797e6, power_dbm=0), time_start=time_start+85, time_duration=35) ) # Set up spectrum sensing sensor_node_ids = [ 19 ] sensor_nodes = [ alh.ALHProxy(coor_industrial_zone, id) for id in sensor_node_ids ] sensors = [ SpectrumSensor(sensor_node) for sensor_node in sensor_nodes ] config_list = sensors[0].get_config_list() sweep_config = config_list.get_sweep_config( start_hz=770000000, stop_hz=820000000, step_hz=400000) # -1 below is a work-around for an off-by-one error somewhere in the spectrum sensing # resource handler sweep_config.num_channels -= 1 program = SpectrumSensorProgram(sweep_config, time_start, time_duration=120, slot_id=5) for sensor in sensors: sensor.program(program) # Wait for the experiment to finish for sensor in sensors: while not sensor.is_complete(program): print "waiting..." time.sleep(2) if time.time() > (program.time_start + program.time_duration + 30): raise Exception("Something went wrong") print "experiment is finished. retrieving data." result = sensor.retrieve(program) try: os.mkdir("data") except OSError: pass result.write("data/node_%d.dat" % (sensor.alh.addr,))
def setSenseConfigurationFullSweep(self): #sets the sensing configuration for node . The difference is that this method will sense the entire band that device supports self.sweep_config = SpectrumSensor(self.node).get_config_list().get_config(0,0).get_full_sweep_config() if self.sweep_config is None: raise Exception("Something went wrong with the sweep_config. Sweep_config is None")
def main(): coor_industrial_zone = alh.ALHWeb(get_communicator_url(), 10001) time_start = time.time() + 15 # Set up transmissions cognitive_terminal = SignalGenerator(alh.ALHProxy(coor_industrial_zone, 25)) config_list = cognitive_terminal.get_config_list() device_config = config_list.get_config(0, 0) cognitive_terminal.program( SignalGeneratorProgram(TxConfig(device_config, 110, 0), time_start=(time_start + 5), time_duration=25)) cognitive_terminal.program( SignalGeneratorProgram(TxConfig(device_config, 225, 0), time_start=(time_start + 32), time_duration=23)) legacy_terminal = SignalGenerator(alh.ALHProxy(coor_industrial_zone, 16)) legacy_terminal.program( SignalGeneratorProgram(TxConfig(device_config, 114, 0), time_start=(time_start + 25), time_duration=30)) # Set up spectrum sensing sensor_node_ids = [2, 17, 6] sensor_nodes = [ alh.ALHProxy(coor_industrial_zone, id) for id in sensor_node_ids ] sensors = [SpectrumSensor(sensor_node) for sensor_node in sensor_nodes] config_list = sensors[0].get_config_list() sweep_config = config_list.get_config(0, 0).get_full_sweep_config() program = SpectrumSensorProgram(sweep_config, time_start, time_duration=60, slot_id=5) for sensor in sensors: sensor.program(program) # Wait for the experiment to finish for sensor in sensors: while not sensor.is_complete(program): print "waiting..." time.sleep(2) if time.time() > (program.time_start + program.time_duration + 60): raise Exception("Something went wrong") print "experiment is finished. retrieving data." result = sensor.retrieve(program) try: os.mkdir("data") except OSError: pass result.write("data/node_%d.dat" % (sensor.alh.addr, ))
class Node: #This class has methods for configuring the VESNA nodes, for generating a signal, for spectrum sensing #This class uses VESNA modules. tx_config = None sweep_config = None def __init__(self, coordinator_id, node_id): #get a coordinator object self.coordinator = alh.ALHWeb("https://crn.log-a-tec.eu/communicator", coordinator_id) #get a node object self.node = alh.ALHProxy(self.coordinator, node_id) #save the coordinator_id and node_id self.coordinator_id = coordinator_id self.node_id = node_id logging.basicConfig(level=logging.INFO) def NodeTest(self): #just try to communicate with the coordinator and with the node to see if they are working print self.coordinator.get("hello") print self.node.get("sensor/mcuTemp") def getSenseConfig(self): #just get a configuration list so you can see it SpectrumSensor(self.node).get_config_list() def getGeneratorConfig(self): #just get a configuration list so you can see it SignalGenerator(self.node).get_config_list() def setSenseConfiguration(self, start_freq_hz, end_freq_hz, step_freq_hz): #sets the sensing configuration for sensing node. It measure the power in the band of [ start_freq_hz end_freq_hz]. #The sweep step is step_freq_hz self.sweep_config = SpectrumSensor(self.node).get_config_list().get_sweep_config(start_freq_hz, end_freq_hz, step_freq_hz) if self.sweep_config is None: raise Exception("Something went wrong with the sweep_config. Sweep_config is None") def setSenseConfigurationChannel(self, start_ch, stop_ch, step_ch): #sets the sensing configuration for sensing node. It measures the power from start_ch to stop_ch #The sweep step is step_ch self.sweep_config = SweepConfig(SpectrumSensor(self.node).get_config_list().get_config(0,0) , start_ch, stop_ch, step_ch ) if self.sweep_config is None: raise Exception("Something went wrong with the sweep_config. Sweep_config is None") def setSenseConfigurationFullSweep(self): #sets the sensing configuration for node . The difference is that this method will sense the entire band that device supports self.sweep_config = SpectrumSensor(self.node).get_config_list().get_config(0,0).get_full_sweep_config() if self.sweep_config is None: raise Exception("Something went wrong with the sweep_config. Sweep_config is None") def senseStart(self, time_start, time_duration , slot_id): #start spectrum sensing on node with the given configuration (self.sweep_config it is what matter) #may perform a few frequency sweeps, depends on the time duration #this can generate exception if sweep_config is None if self.sweep_config is None: print "Cannot start sensing, configuration is missing" return None #get a program object. program = SpectrumSensorProgram(self.sweep_config, time_start, time_duration , slot_id ) #get sensor object, with this we'll program the node sensor = SpectrumSensor(self.node) #program the sensor sensor.program(program) #waiting for the sensor to finish the job while not sensor.is_complete(program): print "waiting..." time.sleep(1) if time.time() > (program.time_start + program.time_duration + 60): raise Exception("Something went wrong with the sensing") print "Experiment is finished. retrieving data." result = sensor.retrieve(program) #try to make a folder try: os.mkdir("./data") except OSError: pass try: os.mkdir("./data/coor_%d" %self.coordinator_id) except OSError: pass #write results in a file result.write("./data/coor_%d/node_%s.dat" %(self.coordinator_id ,self.node_id)) def senseStartQuick(self): #returns a list : [[frequencies] , [power_dbm]] #starts spectrum sensing on node with the given configuration (self.sweep_config it is what matter) #The difference is that this method will do a quick step. Use this if time is critical #Bandwidth you can measure in this case is limited #This will perform a single frequency step with the sweep method defined in the SpectrumSensor class #this can generate exception if sweep_config is None if self.sweep_config is None: print "Cannot start sensing, configuration is missing" return None sweep = SpectrumSensor(self.node).sweep(self.sweep_config) #get the frequency list f_hz = self.sweep_config.get_hz_list() data_received = [] data_received.append(f_hz) data_received.append(sweep.data) return data_received def setGeneratorConfiguration(self, f_hz, power_dbm): #sets configuration for the signal generation. #In this case, the parameters are f_hz and power_dbm, the choosen configuration rely on this parameters. #get a tx_config object self.tx_config = SignalGenerator(self.node).get_config_list().get_tx_config(f_hz, power_dbm) if self.tx_config is None: raise Exception("something went wrong with configuration, tx_config is None") def setGeneratorConfigurationChannel(self, f_ch, power_dbm): #sets configuration for the signal generation. #In this case, the parameters are f_ch and power_dbm #get a tx_config object self.tx_config = TxConfig(SignalGenerator(self.node).get_config_list().get_config(0, 0), f_ch, power_dbm) if self.tx_config is None: raise Exception("Something went wrong with configuration") def generatorStart(self, time_start, time_duration): #starts signal generation with the given configuration (tx_config is what matter) #this can generate exceptions if self.tx_config is None if self.tx_config is None: print "Cannot start signal generating, configuration is missing" return None #get a program object program = SignalGeneratorProgram(self.tx_config, time_start, time_duration) SignalGenerator(self.node).program(program)
class GameNode: # transmitting and receiving configurations sweepConfig = None txConfig = None # reference to sensor and generator objects sensorNode = None generatorNode = None def __init__(self, coordinatorId, nodeId, showLog=True): """node constructor Keywords arguments: coordinatorId -- Numerical cluster id. nodeId -- id number of node. """ # get coordinator object self.coordinator = alh.ALHWeb("https://crn.log-a-tec.eu/communicator", coordinatorId) # get node object self.node = alh.ALHProxy(self.coordinator, nodeId) # save Ids self.coordinatorId = coordinatorId self.nodeId = nodeId if showLog: logging.basicConfig(level=logging.INFO) def nodeTest(self): """Print a string if node is active""" print self.node.get("sensor/mcuTemp") def coordinatorTest(self): """Print a string if coordinator is active""" print self.coordinator.get("hello") def getNodeID(self): return self.nodeId def getSenseConfig(self): """just get a configuration list so I can see it""" SpectrumSensor(self).get_config_list() def getGeneratorConfig(self): """just get a configuration list so I can see it""" SignalGenerator(self).get_config_list() def setSenseConfiguration(self, startFreqHz, endFreqHz, stepFerqHz): """Set sensing configuration. Measure the power in frequency band [startFrewHz, endFreqHz] with a predefined step. startFreqHz -- Lower bound of the frequency band to check (inclusive) endFreqHz -- Upper bound of the frequency band to check (inclusive) stepFerqHz -- Frequency step """ self.sensorNode = SpectrumSensor(self.node) sensorConfigList = self.sensorNode.get_config_list() self.sweepConfig = sensorConfigList.get_sweep_config(startFreqHz, endFreqHz, stepFerqHz) if self.sweepConfig is None: raise Exception("Something went wrong with the sweepConfig. sweepConfig is None") def setSenseConfigurationChannel(self, startCh, endCh, stepCh): """Set sensing configuration. Measure the power from start_ch to stop_ch with predefined step startCh -- Lowest frequency channel to sweep endCh -- One past the highest frequency channel to sweep stepCh -- How many channels in a step """ self.sensorNode = SpectrumSensor(self.node) sensorConfigList = self.sensorNode.get_config_list() self.sweepConfig = SweepConfig(sensorConfigList.get_config(0, 0), startCh, endCh, stepCh) if self.sweepConfig is None: raise Exception("Something went wrong with the sweepConfig. sweepConfig is None") def setSenseConfigurationFuulSweep(self): """Set sensing configuration. This method will sense the entire band that device supports. """ self.sensorNode = SpectrumSensor(self.node) sensorConfigList = self.sensorNode.get_config_list() # self.sweepConfig = SpectrumSensor(self.node).get_config_list().get_config(0,0).get_full_sweep_config() self.sweepConfig = sensorConfigList.get_config(0, 0).get_full_sweep_config() if self.sweepConfig is None: raise Exception("Something went wrong with the sweepConfig. sweepConfig is None") def senseStart(self, timeStart, timeDuration, slotID): """Start spectrum sensing on node with predefined configuration (self.sweep_config). May perform a few frequency sweeps, depends on the time duration. If sweepConfig is None raise exception. timeStart -- Time to start the task (UNIX timestamp). timeDuration -- Duration of the task in seconds. slotID -- Numerical slot id used for storing measurements. """ if self.sweepConfig is None: print "Cannot start Sensing. Configuration is missing!!" return None # get program object program = SpectrumSensorProgram(self.sweepConfig, timeStart, timeDuration, slotID) # get sensor object and program the node self.sensorNode.program(program) # wait for sensor to finish the job while not self.sensorNode.is_complete(program): print "waiting..." time.sleep(1) if time.time() > (program.time_start + program.time_duration + 60): raise Exception("Something went wrong when sensing") print "Sensing finished, retrieving data." result = self.sensorNode.retrieve(program) # for simplicity save data in a folder try: os.mkdir("./data") except OSError: pass try: os.mkdir("./data/coor_%d" % (self.coordinatorId)) except OSError: pass # write data, overwrite existing file result.write("./data/coor_%d/node_%d.dat" % (self.coordinatorId, self.nodeId)) def senseStartQuick(self): """returns a list : [[frequencies] , [power_dbm]] Starts spectrum sensing on node with predefined configuration (self.sweepConfig). This method will do a quick step. Use this if time is critical! Bandwidth you can measure in this case is limited. This will perform a single frequency step with the sweep method defined in the SpectrumSensor class. If sweepConfig is None raise exception. """ if self.sweepConfig is None: print "Cannot start Sensing. Configuration is missing!!" return None sweep = SpectrumSensor(self.node).sweep(self.sweepConfig) # get frequency list fHz = self.sweepConfig.get_hz_list() dataReceived = [] dataReceived.append(fHz) dataReceived.append(sweep.data) return dataReceived def setGeneratorConfiguration(self, fHz, powerDBm): """Set configuration for signal generation. fHz -- Frequency to generate. powerDBm -- Transmission power. """ self.generatorNode = SignalGenerator(self.node) generatorConfigList = self.generatorNode.get_config_list() self.txConfig = generatorConfigList.get_tx_config(fHz, powerDBm) if self.txConfig is None: raise Exception("Something went wrong with configuration, txConfig is None.") def setGeneratorConfigurationChannel(self, fCh, powerDBm): """Set configuration for signal generation. fHz -- Frequency to generate. powerDBm -- Transmission power. """ self.generatorNode = SignalGenerator(self.node) generatorConfigList = self.generatorNode.get_config_list() self.txConfig = TxConfig(generatorConfigList.get_config(0, 0), fCh, powerDBm) if self.txConfig is None: raise Exception("Something went wrong with configuration, txConfig is None.") def generatorStart(self, timeStart, timeDuration): """Start signal generation with predefined configuration (txConfig). If txConfig is None raise exception. timeStart -- Time when node starts transmitting. timeDuration -- Time for which node is transmitting. """ if self.txConfig is None: print "Cannot start signal generating, configuration is missing" return None # get a program object program = SignalGeneratorProgram(self.txConfig, timeStart, timeDuration) self.generatorNode.program(program)
class NodePair(object): # Object constructor takes two nodes: Node doing the signal # transmission and node doing power measurements. def __init__(self, txnode, rxnode): # We set up the SignalGenerator and SpectrumSensor objects here # for later use. We also query both nodes for their # corresponding lists of available hardware configurations. # # Since hardware will not change during the experiment, we only # do the query once in object constructor. This makes repeated # measurements faster. self.generator = SignalGenerator(txnode) self.generator_cl = self.generator.get_config_list() self.sensor = SpectrumSensor(rxnode) self.sensor_cl = self.sensor.get_config_list() # This method performs the power measurement. f_hz parameter is the # central frequency in hertz on which the channel measurement will be done. # ptx_dbm is the transmission power in dbm. If ptx_dbm is None, then # the transmitting node will remain silent. def measure(self, f_hz, ptx_dbm): now = time.time() if ptx_dbm is not None: # If transmission was requested, setup the transmitter. tx_config = self.generator_cl.get_tx_config(f_hz, ptx_dbm) if tx_config is None: raise Exception("Node can not scan specified frequency range.") generator_p = SignalGeneratorProgram(tx_config, now + 1, 14) self.generator.program(generator_p) # Setup the receiver for power measurement at the same # frequency as the transmitter. We will only sense a single # frequency, hence both start and stop parameters of the sweep # are set to f_hz. sweep_config = self.sensor_cl.get_sweep_config(f_hz, f_hz, 400e3) if sweep_config is None: raise Exception("Node can not scan specified frequency range.") sensor_p = SpectrumSensorProgram(sweep_config, now + 3, 10, 1) self.sensor.program(sensor_p) # Note that the transmit interval is longer than the receive # interval: # # now + 1 + 3 / + 13 + 15 # | tx start rx start \ rx stop tx stop # | | | / | | # | | |===========\===========| | # | | receive / | | # | | \ | # | |======================/======================| # transmit # # This is to make sure that signal transmission is happening # during the whole time the receiver is measuring signal power. # Start times may differ +/- 1 second due to unsynchronized # clocks and management network latency. while not self.sensor.is_complete(sensor_p): print "waiting..." time.sleep(2) # Retrieve the data and return a single vector with power # measurements (in dBm) from the sensing node. result = self.sensor.retrieve(sensor_p) return np.array(result.get_data())[:, 0] # This method calculates the channel gain between the nodes. def get_channel_gain(self, f_hz, ptx_dbm): def db_to_mw(db): return 10.**(db / 10.) def mw_to_db(mw): return 10. * np.log10(mw) # First, measure just the noise level on the receiving node. # Transmitter is turned off. pnoise_dbm = self.measure(f_hz, None) # Second, measure the received signal power level with the # transmitter turned on. prx_dbm = self.measure(f_hz, ptx_dbm) # Convert all power values to linear scale. ptx_mw = db_to_mw(ptx_dbm) pnoise_mw = db_to_mw(pnoise_dbm) prx_mw = db_to_mw(prx_dbm) # Take the mean of both noise and received signal power # measurements. pnoise_mw_mean = np.mean(pnoise_mw) prx_mw_mean = np.mean(prx_mw) print "p_noise = %.1f dBm (mean=%e mW std=%e mW)" % ( mw_to_db(pnoise_mw_mean), pnoise_mw_mean, np.std(pnoise_mw)) print "p_rx = %.1f dBm (mean=%e mW std=%e mW)" % ( mw_to_db(prx_mw_mean), prx_mw_mean, np.std(prx_mw)) # Use the mean values to estimate the channel gain. h_mean = (prx_mw_mean - pnoise_mw_mean) / ptx_mw # Convert back to logarithmic scale. h_mean_db = mw_to_db(h_mean) print "h = %.1f dB" % (h_mean_db, ) return h_mean_db