In Simthetic this can be done very flexibly by using the so-called 'loop controls'. Each stream driven simulation system (SDS) holds one or more loop controls. As a loop control, each class that is derived from the base class simth::LoopControl can serve. With simth::StreamDrivenSystem it is described that the SDS runs until a device sends the signal 'STOP_ITERATION' to the simulation system. This stops the simulation flow and the SDS calls the function nextIteration()
of the innermost loop control (i.e. the loop control with the lowest ID number). Since any device can connect with a loop control using the function insertControlInterface()
(see simth::Device), the control interface will call the function it is connected with. (Actually, a loop control is not connected with a device but with the member function of that device to be invoked.) If a loop control reached its lastIteration()
, the loop control is reset to its starting state and the function nextIteration()
of the next loop control is called. If the outermost loop control (i.e. the loop control with the highest ID number) reached its lastIteration()
, the simulation flow will be stopped and the (virtual) function endOfSimulation()
of each device is called before exiting the simulation run.
For clarification see the following example of the loop controls specification of a typical digital communication simulation run. In this example, one loop (the outermost) is used to set the SNR-range of the simulation run. With this loop at least the channel device and the monitor device (to store the results for each SNR) are connected. Note, the SNR loop is a 'double' loop, i.e. each member function of a device that takes one double argument can be connected with that loop (e.g. setSnr(double newSnr)
). The member function is connected by using the function insertControlInterface()
. The innermost loop is used to refresh the channel device (i.e. generates a new representation of the channel) several times for each SNR value. To this 'counter' loop control each member function of a device can be connected with, that takes no argument (e.g. refresh()
).
/* 'example_1.loo': Example loop control file. This example loop control file specifies the loop controls used in an EventDrivenSystem (see LoopControl). Loop controls are used to control the process flow of a simulation run. E.g. a LinearLoopControl<double> with start value 5 and end value 19 could represent an SNR-range from 5dB to 19dB in a simulation system that simulates a digital transmission chain. This loop control is specified by the argument 'type: linear_double'. To have an influence on the SNR of the simulated transmission system, the LinearLoopControl must be connected with a ControlInterface of the Channel device that wraps the function setSNR(double newValue). Therefore, the loop control must specifies a name which is referred to by the channel. Then, each time the function nextIteration() of this loop control is called, the function setSNR() of the channel is called with the current value of the linear loop control. It is also possible to use nested loops. The loop control with the smallest number, here loop_control0, represents the innermost loop; the loop control with the highest number, here loop_control1, represents the outermost loop. */ /* The innermost loop: Here, a so called counter loop is used. The number of loops to be performed are given by number_of_loops. This loop variable can be connected to any device function, that takes no argument, e.g. the function refresh() of the WSSUSChannel class can be connected with, to dice for each SNR value (see the loop control below) a given number (by number_of_loops:) of new channel represantives. Since in this example we are using an AWGN channel, no device is connected with this loop control and hence we can set the number_of_loops: to zero. In that case we could also delete that loop control from this file. */ [loop_control0] name: refresh_loop type: counter number_of_loops: 0 [end] /* Second loop: Here the outermost loop. See the description above for further explanation. */ [loop_control1] name: SNR_loop type: linear_double start_value: 0 end_value: 5 increment: 1 [end]
The mechanism to connect a member function of a device with a loop control is separated in two steps. In the first step, a device inserts a simth::ControlInterface using the function simth::Device::insertControlInterface(). E.g. the constructor of the channel device holds the following line to insert a control interface that is connected with its function setSNR()
:
insertControlInterface<double,Channel>
(this, &Channel::setSNR);
Then in a second step this control interface is connected with a loop control. Here the name of the loop control is given by the property list argument 'snr':
connectControlInterface
(0,pl.getProperty<std::string>("snr"));
Note, if the constructed simulation system does not hold a loop variable with the given name (specified by the parameter file) an error is throw. If the loop control does exist but takes not particularly the same arguments (that is here one 'double' argument), an error is also thrown. Deriving from simth::LoopControl you can define you your own loop control that can be connected with functions taking the arguments your new loop control supports.