def run(self): # Schedule initial node transmissions for tx_node in self.topology.node_list: tx_node.txList = [] sf = self.__get_sf(tx_node) self.__add_to_event_queue(tx_node.schedule_tx(packet_rate=self.packetRate, packet_size=self.packetSize, simulation_duration=self.simulationDuration, sf=sf)) for event_index, event in enumerate(self.eventQueue): tx_node = self.topology.get_node(event.source) rx_gw_list = [] # Check which gateways can receive for gw in self.topology.gateway_list: distance_to_gw = Location.get_distance(tx_node.location, gw.location) rx_sensitivity_dbm = Packet.get_receive_sensitivity(event.sf) propagation_loss_dbm = Packet.calculate_propagation_loss(distance_to_gw) rx_signal_dbm = event.tx_power_dbm - propagation_loss_dbm if rx_signal_dbm < rx_sensitivity_dbm: logging.info('Under sensitivity ({} - {:.3f}) < {} for {} at gw {}'.format(event.tx_power_dbm, propagation_loss_dbm, rx_sensitivity_dbm, event, gw.id)) pass else: rx_gw_list.append([gw, rx_signal_dbm]) if len(rx_gw_list) == 0: # No gateway received the packet logging.info('lost due to under sensitivity {}'.format(event)) event.status = PacketStatus.under_sensitivity else: # Check overlapping events overlapping_events = [] for previous_event_index in range(event_index - 1, 0, -1): previous_event = self.eventQueue[previous_event_index] if (previous_event.time + previous_event.duration) < event.time: break # Events are overlapping overlapping_events.append(previous_event) logging.info('previous {} and {} are overlapping for {:.3f} s'.format(previous_event, event, previous_event.time + previous_event.duration - event.time)) for next_event_index in range(event_index + 1, len(self.eventQueue)): next_event = self.eventQueue[next_event_index] if (event.time + event.duration) < next_event.time: break # Events are overlapping overlapping_events.append(next_event) logging.info('next {} and {} are overlapping for {:.3f} s'.format(next_event, event, event.time + event.duration - next_event.time)) if len(overlapping_events) > 0: # Check interference at gateways for rx_gw_index in range(len(rx_gw_list)): rx_gw = rx_gw_list[rx_gw_index][0] rx_signal_dbm = rx_gw_list[rx_gw_index][1] cumulative_interference_energy_j = [0] * 6 rx_signal_energy_j = Packet.calculate_energy(rx_signal_dbm, event.duration) logging.debug('event_node={},' 'event_sf={},' 'rx_gw={},' 'rx_signal_dbm={},' 'rx_signal_energy_j={}'.format( event.source, event.sf.value, rx_gw.id, rx_signal_dbm, rx_signal_energy_j)) for interferer_event in overlapping_events: if event.time > interferer_event.time: # Overlap with previous event overlap_duration = interferer_event.time + interferer_event.duration - event.time else: # Overlap with next event overlap_duration = event.time + event.duration - interferer_event.time interferer_node = self.topology.get_node(interferer_event.source) interferer_to_gw_distance = Location.get_distance(rx_gw.location, interferer_node.location) interferer_propagation_loss = Packet.calculate_propagation_loss(interferer_to_gw_distance) interferer_power_dbm = interferer_event.tx_power_dbm - interferer_propagation_loss interference_energy_j = Packet.calculate_energy(interferer_power_dbm, overlap_duration) logging.debug('interferer_node={},' 'interferer_sf={},' 'interferer_gw_distance={:.3f},' 'interferer_propagation_loss={:.3f},' 'overlap_duration={:.3f},' 'interferer_power_dbm={:.3f},' 'interference_energy_j={}'.format( interferer_event.source, interferer_event.sf.value, interferer_to_gw_distance, interferer_propagation_loss, overlap_duration, interferer_power_dbm, interference_energy_j)) cumulative_interference_energy_j[interferer_event.sf.value - 7] += interference_energy_j for sf_index in range(len(cumulative_interference_energy_j)): if cumulative_interference_energy_j[sf_index] != 0: logging.debug('Cumulative interference energy={} for sf={} at gw={}'.format(cumulative_interference_energy_j[sf_index], sf_index + 7, rx_gw.id)) snir_isolation = collision_snir[event.sf.value-7][sf_index] logging.debug('needed isolation to survive={}'.format(snir_isolation)) snir = 10 * math.log10( rx_signal_energy_j / cumulative_interference_energy_j[sf_index]) logging.debug('snir={}'.format(snir)) if snir >= snir_isolation: logging.info('survived {} from interference at gw={}'.format(event, rx_gw.id)) pass else: logging.info('interfered {} at gw={}'.format(event, rx_gw.id)) rx_gw_list[rx_gw_index] = None if all(rx_gw is None for rx_gw in rx_gw_list): logging.info('lost due to interference {}'.format(event)) event.status = PacketStatus.interfered # If packet is not interfered or under sensitivity, then transmitted if event.status == PacketStatus.pending: event.status = PacketStatus.transmitted logging.info('Event simulated {}'.format(event)) # Schedule next event for this node sf = self.__get_sf(tx_node) self.__add_to_event_queue(tx_node.schedule_tx(packet_rate=self.packetRate, packet_size=self.packetSize, simulation_duration=self.simulationDuration, sf=sf)) # Collect statistics cumulativeSuccessfulDataSize = 0 cumulativeDataDuration = 0 for event in self.eventQueue: self.simulationResult.txEnergyConsumption += event.tx_energy_j self.simulationResult.totalPacket += 1 cumulativeDataDuration += event.duration if event.status == PacketStatus.under_sensitivity: self.simulationResult.underSensitivityPacket += 1 elif event.status == PacketStatus.interfered: self.simulationResult.interferencePacket += 1 elif event.status == PacketStatus.transmitted: self.simulationResult.successfulPacket += 1 cumulativeSuccessfulDataSize += event.size self.simulationResult.pdr = 100 * float(self.simulationResult.successfulPacket) / self.simulationResult.totalPacket self.simulationResult.throughput = 8 * float(cumulativeSuccessfulDataSize) / cumulativeDataDuration return self.simulationResult