My internship and thesis revolves around WSNs: Wireless Sensor Networks. To get some more insights in the workings of these networks and I built a small simulator in Python. The full source can be found on the SLACTest1 repository on GitHub.
The setup of the simulation is simple: a fixed world (without obstructions) contains a set of nodes. A subset of these nodes are fixed (i.e. Access Points or AP’s) and the rest is moving (e.g. users, usually one). All nodes are randomly places within the boundaries of the world, all moving nodes are initialised with a random movement (speed and direction).
An example simulation consisting of 100 static access points and one moving node. The blue line is the movement trace of the user. The left figure represents the simulated world. The right is the predicted movement trace of the user based on signal strengths measurements (using PCA); this I will address in a seperate post.
For brevity I won’t show the full source code here (see the repo) but only the relevant parts. The movement of the users is a simple bounce or pinball effect:
def move(self):
xn = max(min(self.x + math.cos(self.r) * self.s, self.maxX), 0)
yn = max(min(self.y + math.sin(self.r) * self.s, self.maxY), 0)
if xn == 0 or xn == self.maxX:
self.r = math.pi - self.r
elif yn == 0 or yn == self.maxY:
self.r = 2 * math.pi - self.r
self.moveToPosition(xn, yn)
Running the simulation only requires setting up a specific controller with the appropriate nodes:
# Create a new world
world = env.World(xMax, yMax)
# Instantiate nodes with a random position
nodes = [wsn.FixedAP(maxX = world.getMaxX(), maxY = world.getMaxY()) for x in range(0, fixedNodes)]
user = wsn.MovingAP(maxX = world.getMaxX(), maxY = world.getMaxY())
nodes.append(user)
# Create a network controller, containing the world and nodes
controller = NetworkController(world, nodes, False)
# Initialize the world, gives nodes initial speed and direction
controller.initialize()
# Simulate movement in the network
for i in range(0, steps):
# Update the total network
controller.iterate()
Creating a moving figure
The most difficult part of the whole simulator is not simulating movement or the world state, its the visualization. Matplotlib has support for animations2 but the documentation is not as extensive as for the other types of plots. The most basic example uses a update function to plot every frame (through FuncAnimation). For the WSN simulation I opted for the subclassing method:
class PlaybackAnimation(animation.TimedAnimation):
'''
Animator object
'''
def __init__(self, <plot data>):
# Setup a figure object
fig, (combAx, predAx) = plt.subplots(1, 2, squeeze=True, figsize=(24,10) )
# Setup your plots here as you would normally do
# self.plt = ...
animation.TimedAnimation.__init__(self, fig, interval=100, blit=True)
def show(self):
self.plt.show()
def _draw_frame(self, iteration):
# Update the data of your plots
# You can retrieve the data with:
# yourplt.get_data()
# and set the data with:
# yourplt.set_data(x, y)
# This step is important as it tells the animation which plots have been updated
# Set _drawn_artists to a list of all the plot objects that have changed.
self._drawn_artists = [ plots ]
def _init_draw(self):
# Init all plots by setting there data to zero, e.g.:
# self.plt.set_data([], [])
def new_frame_seq(self):
# here you return an enumerate object describing the length of the animation
# e.g.:
# return iter(range(len(self.data) - 2))
Read the comments in the above snippet for some guidelines during the implementation of your animator. The animation can then be showed using the show() function or it can be saved to a file (make sure that you have a version of ffmpeg installed):
anim = PlayBackAnimation(data)
anim.save("simulation.mp4", writer="ffmpeg")
Closing remarks
Creating this simulation showed me one thing: sometimes it takes you more work to show what you have done (i.e. showing the simulation) than doing the actual work self (the world model). In Python, creating the world and simulating the nodes is trivial and very easy. Unfortunately, the animation capabilities of Matplotlib are a bit more difficult and underdocumented. If your focus is primarily animating than you’re better off with something like Matlab.
The repo contains the full SLAC project in which I combine Gaussian Processes with localization. ↩︎
Mohammad Fazlul Hasan Shariff on
Great work on the SLACTest project. I am also working on something similar and I was wondering if there is a way I can modify your original project to run it on a terminal in Ubuntu? I mean, I don't exactly need an animation like how you have created (awesome work on that by the way!) but where exactly can I make some modifications so that I can "simulate" some "messages" being passed through the nodes and it would show the same on the terminal? (for example: "node1: message passed to neighbours 2,3,4","node2: message passed to neighbours 1,3,4"... and so on). Thanks in advance for your help and great article! :)