This is a simpy [https://simpy.readthedocs.io/] based LoRa simulator.
It is inspired by LoRaSim from Lancaster University [http://www.lancaster.ac.uk/scc/sites/lora/lorasim.html]. Part of the collision processing functionality is imported from that.
The simulator adopts a modular structure providing:
- separation of the channel and channel model
- separation of the physical layer with handling of collisions
- separation of application layer (packet generation).
Most importantly, the simulator introduces the concept of layered network stack that should allow implementing LoRaWAN (work in progress) as well as other endeavours, such as an IPv6 stack.
Defines the top-level function simulate that runs a simulation with a set of parameters.
The function computes and returns the average DER of the network.
The file sim_test.py has several examples of how to define and run a simulation.
A node is defined following the template in loranode_template. An example for a node with periodic transmissions is provided in loranode. A node has:
- an ID
- a location
- a configuration (sf, tx power, bw, cr)
- a network stack
- a physical layer (consider this equivalent to the radio driver).
In addition the node should define
- an application process, that generates packets; this is connected to the simpy engine
- an application receive callback to be connected to the network stack.
A packet generated by the application process in the node is fed into the network stack.
The networks stack is a list of layers where each layer is connected to the upper and lower with send and receive methods. The layers need to follow the template in nwklayer_template (NwkLayerTemplate).
The config_net_stack of the node takes care of connecting the bottom layer of the network stack to the physical layer, and the latter to the channel.
Once a message reaches the bottom of the stack it is passed into the physical layer.
The physical layer inherits from the NwkLayerTemplate so it has the same send/recv interface as any other layer.
It implements the collision handling functionality. The phy layer handles the following types of collision
- pure ALOHA
- capture effect in the same spreading factor
- cross-SF interference. At the moment these are configured in the PhyLayer initialiser.
When sending packets it considers that packet transmission takes a certain amount of time. During that time, the channel around the node is occupied by the packet. As such, the packet transmission is implemented as a simpy process as follows:
- the start of the transmission is signaled to the channel
- yield for the airtime of the packet
- the end of the transmission is signaled to the channel.
In turn, the phy layer at the receiver end implements packet processing as
- recv_start, when the first symbols of the packet are received
- recv_end, when the packet is completely received.
The impact of an incoming transmission on existing transmissions is evaluated in recv_start. Just as in LoRaSim [http://www.lancaster.ac.uk/scc/sites/lora/lorasim.html] incoming packets are maintained in a list and collisions are evaluated on the entire list. Once a packet transmission has been completed (recv_done) the packet is removed from the incoming list, and, depending on the state (collided or not), it is sent upwards (or dropped) into the network stack.
The channel registers all the nodes and their positions. When a packet is transmitted the channel determines, using the channel model, which nodes will receive the transmission (which will cause interference).
The channel delivers a packet to all the phy layers of nodes that are within the radio reach of the packet. (WIP)
If the packet does not reach its intended destination, it is marked as lost.
The simulator implements a packet logger (PacketLogger in logger.py) that logs, for each node:
- the position
- how many packets it created
- how many packets it sent
- how many packets were successfully received ('tx_success')
- how many packets collided
- how many packets were lost
- the average rssi over all packets.
The log is a stored as a two level dictionary:
- first level the keys are node ids
- second level is node statistics (as above).
The log is pickled, so it can be opened directly in Python for processing.
Deploys the nodes within an area. A class implementing the deploy_nodes method.
Examples:
- random_node_deployer: random placement within an area of given size; no guarantee of connection the GW
- connected_random_random_deployer: random placement with connection to GW.
Configures the SF, TXP, freq, BW and CR of a node. A class implementing the configure method, as in node_config_template.
Derive class to implement custom configuration such as optimal allocation of SF and TXP.
Examples:
- node_config_slowest_setting: lowest bitrate, TXP 14
- node_config_custom_sf_setting: bw 125KHz, CR 4/8, TXP 14, custom SF.
The collision probability of the simulator was validated by comparing it with a theoretical ALOHA model. The simulator was run in pure ALOHA collisions, that is, without capture effect.