Skip to content

Commit

Permalink
Feature real-time scaling #215
Browse files Browse the repository at this point in the history
  • Loading branch information
bernhard-thiele committed May 26, 2017
1 parent ed8bf71 commit 6da353f
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 15 deletions.
15 changes: 14 additions & 1 deletion Modelica_DeviceDrivers/Blocks/OperatingSystem.mo
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,27 @@ package OperatingSystem

parameter Boolean setPriority = true "true, if process priority is to be set, otherwise false";
parameter Types.ProcessPriority priority = "Normal" "Priority of the simulation process" annotation(Dialog(enable=setPriority));
parameter Boolean enableRealTimeScaling = false
"true, enable external real-time scaling input signal"
annotation (Dialog(group="Advanced"), choices(checkBox=true));
Modelica.Blocks.Interfaces.RealInput scaling if enableRealTimeScaling
"Real-time scaling factor; > 1 means the simulation is made slower than real-time"
annotation (Placement(transformation(extent={{-140,-20},{-100,20}})));
output Modelica.SIunits.Time calculationTime "Time needed for calculation";
output Modelica.SIunits.Time availableTime "Time available for calculation (integrator step size)";
protected
ProcessPriority procPrio(priority = priority) if setPriority;
Real dummyState(start = 0, fixed=true) "dummy state to be integrated, to force synchronization in every integration step";
Modelica_DeviceDrivers.OperatingSystem.RealTimeSynchronization rtSync = Modelica_DeviceDrivers.OperatingSystem.RealTimeSynchronization();
/* Connectors for conditional connect equations */
Modelica.Blocks.Interfaces.RealInput defaultScaling = 1 if not enableRealTimeScaling "Default real-time scaling";
Modelica.Blocks.Interfaces.RealInput actScaling annotation (HideResult=true);
equation
(calculationTime, availableTime) = Modelica_DeviceDrivers.OperatingSystem.realtimeSynchronize(rtSync, time);
/* Conditional connect equations to either use external real-time scaling input or default scaling */
connect(defaultScaling, actScaling);
connect(scaling, actScaling);

This comment has been minimized.

Copy link
@tbeu

tbeu Oct 9, 2017

Collaborator

Just wondering: Is it OK to connect two input connectors?

This comment has been minimized.

Copy link
@sjoelund

sjoelund Oct 9, 2017

Contributor

A connection set of causal variables ( input / output ) may at most contain variables from one inside output connector or one public outside input connector. [i.e., a connection set may at most contain one source of a signal.]

So.... sometimes allowed?

This comment has been minimized.

Copy link
@tbeu

tbeu Oct 9, 2017

Collaborator

connect(defaultScaling, actScaling);: Two protected outside input connectors
connect(scaling, actScaling);: One public outside input connector and one protected outside input connector


(calculationTime, availableTime) = Modelica_DeviceDrivers.OperatingSystem.realtimeSynchronize(rtSync, time, enableRealTimeScaling, actScaling);
der(dummyState) = calculationTime;
annotation (preferredView="info",
Icon(coordinateSystem(preserveAspectRatio=true, extent={{-100,
Expand Down
14 changes: 13 additions & 1 deletion Modelica_DeviceDrivers/ClockedBlocks/OperatingSystem.mo
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,30 @@ package OperatingSystem

parameter Boolean setPriority = true "true, if process priority is to be set, otherwise false";
parameter Types.ProcessPriority priority = "Normal" "Priority of the simulation process" annotation(Dialog(enable=setPriority));
parameter Boolean enableRealTimeScaling = false
"true, enable external real-time scaling input signal"
annotation (Dialog(group="Advanced"), choices(checkBox=true));
Modelica.Blocks.Interfaces.RealInput scaling if enableRealTimeScaling
"Real-time scaling factor; > 1 means the simulation is made slower than real-time"
annotation (Placement(transformation(extent={{-140,-20},{-100,20}})));
output Modelica.SIunits.Time calculationTime "Time needed for calculation";
output Modelica.SIunits.Time availableTime "Time available for calculation (integrator step size)";
protected
ProcessPriority procPrio(priority = priority) if setPriority;
Modelica.Blocks.Interfaces.BooleanInput initialized;
Modelica.Blocks.Interfaces.BooleanOutput dummyTrue = true if not setPriority;
Modelica_DeviceDrivers.OperatingSystem.RealTimeSynchronization rtSync = Modelica_DeviceDrivers.OperatingSystem.RealTimeSynchronization();
/* Connectors for conditional connect equations */
Modelica.Blocks.Interfaces.RealInput defaultScaling = 1 if not enableRealTimeScaling "Default real-time scaling";
Modelica.Blocks.Interfaces.RealInput actScaling annotation (HideResult=true);
algorithm
if initialized then
(calculationTime, availableTime) := Modelica_DeviceDrivers.OperatingSystem.realtimeSynchronize(rtSync, time);
(calculationTime, availableTime) := Modelica_DeviceDrivers.OperatingSystem.realtimeSynchronize(rtSync, time, enableRealTimeScaling, actScaling);
end if;
equation
/* Condional connect equations */
connect(defaultScaling, actScaling);
connect(scaling, actScaling);
connect(procPrio.initialized, initialized);
connect(dummyTrue, initialized);
annotation (preferredView="info",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class RealTimeSynchronization "An object for real-time synchronization."
import Modelica;
extends Modelica.Icons.Function;
output RealTimeSynchronization rtSync;
external "C" rtSync= MDD_realtimeSynchronizeConstructor()
external "C" rtSync = MDD_realtimeSynchronizeConstructor()
annotation(Include = "#include \"MDDRealtimeSynchronize.h\"",
Library = {"rt", "Winmm"},
__iti_dll = "ITI_MDD.dll",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ function realtimeSynchronize
extends Modelica.Icons.Function;
input Modelica_DeviceDrivers.OperatingSystem.RealTimeSynchronization rtSync;
input Real simTime;
input Boolean enableScaling = false "true, enable real-time scaling, else disable scaling";
input Real scaling(min=0) = 1 "real-time scaling factor; > 1 means the simulation is made slower than real-time";
output Real calculationTime;
output Real availableTime;
external "C" calculationTime = MDD_realtimeSynchronize(rtSync, simTime, availableTime)
external "C" calculationTime = MDD_realtimeSynchronize(rtSync, simTime, enableScaling, scaling, availableTime)
annotation(Include = "#include \"MDDRealtimeSynchronize.h\"",
Library = {"rt", "Winmm"},
__iti_dll = "ITI_MDD.dll",
Expand Down
49 changes: 38 additions & 11 deletions Modelica_DeviceDrivers/Resources/Include/MDDRealtimeSynchronize.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ typedef struct {
double lastSimTime;
double lastIntegratorTimeStep;
double lastCalculationTime;
double lastSyncTime; /* last (potentially scaled) syncronization time */
} RTSync;

DllExport void* MDD_realtimeSynchronizeConstructor(void) {
Expand All @@ -187,6 +188,7 @@ DllExport void* MDD_realtimeSynchronizeConstructor(void) {
rtSync->lastSimTime = 0.;
rtSync->lastIntegratorTimeStep = 0.;
rtSync->lastCalculationTime = 0.;
rtSync->lastSyncTime = 0.;
}
timeBeginPeriod(1);
return (void*) rtSync;
Expand Down Expand Up @@ -216,10 +218,12 @@ DllExport double MDD_getTimeMS(double dummy) {
*
* @param[in] Real-time synchronization object
* @param[in] simTime (s) simulation time
* @param[out] availableTime time that is left before realtime deadline is reached.
* @param[in] enableScaling if true enable real-time scaling, else disable scaling
* @param[in] scaling real-time scaling factor; > 1 means the simulation is made slower than real-time
* @param[out] availableTime time that is left before realtime deadline is reached BUG Windows-Linux implementation differ!
* @return (s) Time between invocation of this function, i.e. "computing time" in seconds
*/
DllExport double MDD_realtimeSynchronize(void* rtSyncObj, double simTime, double * integratorTimeStep) {
DllExport double MDD_realtimeSynchronize(void* rtSyncObj, double simTime, int enableScaling, double scaling, double * integratorTimeStep) {
double calculationTime = 0.;
RTSync* rtSync = (RTSync*) rtSyncObj;
if (rtSync && integratorTimeStep) {
Expand All @@ -229,10 +233,16 @@ DllExport double MDD_realtimeSynchronize(void* rtSyncObj, double simTime, double
double timeLeft;
QueryPerformanceCounter(&now);
calculationTime = (double)(now.QuadPart * 1e6 - rtSync->lastTime.QuadPart * 1e6)/(double)rtSync->frequency.QuadPart*1.e-6;

*integratorTimeStep = simTime - rtSync->lastSimTime;

/* scaled syncronization time. "scaling > 1" means the simulation takes longer than real-time.
No scaling => syncTime == simTime */
double syncTime = enableScaling ? rtSync->lastSyncTime + (simTime - rtSync->lastSimTime)*scaling : simTime;

do {
QueryPerformanceCounter(&now);
timeLeft = simTime - (double)(now.QuadPart - rtSync->startTime.QuadPart)/(double)rtSync->frequency.QuadPart;
timeLeft = syncTime - (double)(now.QuadPart - rtSync->startTime.QuadPart)/(double)rtSync->frequency.QuadPart;
if (timeLeft > 0) {
if (timeLeft > 0.002) {
Sleep(1);
Expand All @@ -249,6 +259,7 @@ DllExport double MDD_realtimeSynchronize(void* rtSyncObj, double simTime, double
rtSync->lastSimTime = simTime;
rtSync->lastIntegratorTimeStep = *integratorTimeStep;
rtSync->lastCalculationTime = calculationTime;
rtSync->lastSyncTime = syncTime;
}
else {
calculationTime = rtSync->lastCalculationTime;
Expand Down Expand Up @@ -375,9 +386,15 @@ void MDD_setPriority(void* dummyPrioObj, int priority) {
typedef struct {
struct timespec t_start;
struct timespec t_clockRealtime; /* current/last time of real time clock */
double lastSimTime; /* last simulation time */
double lastSyncTime; /* last (potentially scaled) syncronization time */
} RTSync;

void* MDD_realtimeSynchronizeConstructor(void) {
/** RTSync constructor
*
* @return RTSync object
*/
void* MDD_realtimeSynchronizeConstructor() {
RTSync* rtSync = (RTSync*) malloc(sizeof(RTSync));
if (rtSync) {
int ret = clock_gettime(CLOCK_MONOTONIC, &rtSync->t_start);
Expand All @@ -387,6 +404,8 @@ void* MDD_realtimeSynchronizeConstructor(void) {
ModelicaError("MDDRealtimeSynchronize.h: clock_gettime(..) failed\n");
}
rtSync->t_clockRealtime = rtSync->t_start;
rtSync->lastSimTime = 0; /* Presume we start from initial time = 0 */
rtSync->lastSyncTime = 0; /* Presume we start from initial time = 0 */
}
return (void*) rtSync;
}
Expand All @@ -402,16 +421,18 @@ void MDD_realtimeSynchronizeDestructor(void* rtSyncObj) {
*
* @param[in] Real-time synchronization object
* @param[in] simTime (s) simulation time
* @param[out] availableTime time that is left before realtime deadline is reached.
* @param[in] enableScaling if true enable real-time scaling, else disable scaling
* @param[in] scaling real-time scaling factor; > 1 means the simulation is made slower than real-time
* @param[out] availableTime time that is left before realtime deadline is reached BUG Windows-Linux implementation differ!
* @return (s) Time between invocation of this function, i.e. "computing time" in seconds
*/
double MDD_realtimeSynchronize(void* rtSyncObj, double simTime, double * availableTime) {
double MDD_realtimeSynchronize(void* rtSyncObj, double simTime, int enableScaling, double scaling, double * availableTime) {
double deltaTime = 0.;
RTSync* rtSync = (RTSync*) rtSyncObj;
RTSync* rtSync = (RTSync*) rtSyncObj;
if (rtSync && availableTime) {
struct timespec t_abs; /* Absolute time until which execution will be delayed (to catch up with real-time) */
double fractpart, intpart;
int ret;
int ret;

/* save away value of last time that the real-time clock was inquired */
deltaTime = rtSync->t_clockRealtime.tv_sec + (double)rtSync->t_clockRealtime.tv_nsec/NSEC_PER_SEC;
Expand All @@ -421,8 +442,12 @@ double MDD_realtimeSynchronize(void* rtSyncObj, double simTime, double * availab
* old value of the real-time clock from the current (new) value of the real-time clock */
deltaTime = (rtSync->t_clockRealtime.tv_sec + (double)rtSync->t_clockRealtime.tv_nsec/NSEC_PER_SEC) - deltaTime;

/* convert simulation time to corresponding real-time clock value */
fractpart = modf(simTime, &intpart);
/* scaled syncronization time. "scaling > 1" means the simulation takes longer than real-time.
No scaling => syncTime == simTime */
double syncTime = enableScaling ? rtSync->lastSyncTime + (simTime - rtSync->lastSimTime)*scaling : simTime;

/* convert (scaled) simulation time to corresponding real-time clock value */
fractpart = modf(syncTime, &intpart);
t_abs.tv_sec = rtSync->t_start.tv_sec + (time_t) intpart;
t_abs.tv_nsec = rtSync->t_start.tv_nsec + (long) floor(fractpart*NSEC_PER_SEC);
while (t_abs.tv_nsec >= NSEC_PER_SEC) {
Expand All @@ -435,14 +460,16 @@ double MDD_realtimeSynchronize(void* rtSyncObj, double simTime, double * availab
/* printf("t_abs.tv_sec: %d, t_cr.tv_sec: %d, t_abs.tv_nsec: %d, t_cr.tv_nsec: %d\n",
t_abs.tv_sec, rtSync->t_clockRealtime.tv_sec, t_abs.tv_nsec, rtSync->t_clockRealtime.tv_nsec); */

/* wait until simulation time == real-time */
/* wait until (scaled) simulation time == real-time */
ret = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &t_abs, NULL);
if (ret) {
ModelicaError("MDDRealtimeSynchronize.h: clock_nanosleep(..) failed\n");
}

/* get value the current time of the real-time clock (should be equal to t_abs if everything is OK) */
clock_gettime(CLOCK_MONOTONIC, &rtSync->t_clockRealtime);
rtSync->lastSimTime = simTime;
rtSync->lastSyncTime = syncTime;
}

return deltaTime;
Expand Down

3 comments on commit 6da353f

@vijeesht
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi
where to get rt.lib, I could find rt.dll but not rt.lib

@tbeu
Copy link
Collaborator

@tbeu tbeu commented on 6da353f Feb 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a dummy dependency on Win only and not needed for linking.

@vijeesht
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So can I remove rt and compile on windows

Please sign in to comment.