Ao.Simulation
Ao.Simulation
The Ao.Simulation
namespace contains some basic ingredients for simulations.
Timestamp
This namespace contains a simulator class that can run a simulation based on an event queue, for which it needs a function returning a current timestamp. The event queue stores events ordered by their individual timestamp.
A timestamp is a Time
value that has been defined in the Ao.Measurements
namespace.
var t = new Time
{
Seconds = 1.2345
};
The framework class library provides the means to build a current timestamp generator.
public static class Timestamp
{
private static readonly DateTime Beginning = DateTime.Now;
public static Time Now => new Time
{
Seconds = (DateTime.Now - Beginning).TotalSeconds
};
}
However, the default Windows timer running behind DateTime.Now
updates every 15.6 milliseconds, only. A higher resolution is provided, for example, by the performance counter, which can be accessed using interop or the Performance
class in the Ao.Timing.Win32
namespace.
Event
An event can be anything, for which a timestamp can be specified, for example, the arrival of a message …
public class MessageEvent
{
public string Message { get; set; }
public Time Time { get; set; }
}
… or an update from a sensor.
public class SensorEvent
{
public Acceleration X { get; set; }
public Acceleration Y { get; set; }
public Acceleration Z { get; set; }
public Time Time { get; set; }
}
Event Queue
The generic EventQueue<T>
class is a priority queue for events, that internally orders events by their respective timestamp. The generic parameter T
represents the event. In order to do its job properly, the event queue needs a delegate returning an event’s timestamp.
var Q = new EventQueue<SensorEvent>(x => x.Time);
Thereby, it is not necessary for the event type T
to carry around the timestamp by itself. The specified delegate can get an event from elsewhere.
public static class TimestampProvider
{
public static Time Get(SensorEvent e)
{
// ...
}
}
var Q = new EventQueue<SensorEvent>(TimestampProvider.Get);
Simulator
The Simulator
class uses both an event queue and a current timestamp provider, in order to fire events accordingly.
var S = new Simulator<SensorEvent>(Q, Timestamp.Now);
There is a single public method, that permanently loops until the event queue is empty. Only then does it return. Therefore, it should better be called in a background thread.
S.Run();
With every iteration, it gets the current timestamp and removes all the items from the event queue that are due. For each item, it fires an event, that the application can listen to.
void OnEvent(object sender, SimulatorEventArgs<SensorEvent> e)
{
Console.WriteLine("Sensor event at {0} s.", e.Time.Seconds);
}
S.Event += OnEvent;