Preamble
.1. CopyRight and License
This document and accompanying code copyright © 2017-2021 EMPHYSIS partners.
This document released under Attribution-ShareAlike 4.0 International.
XML-schema files, that accompany this specification document, are released under the 3-Clause BSD License.
.2. Release Notes
.2.1. Version 1.0.0-alpha.4
Disclaimer
This alpha release is a draft version of the eFMI standard (= Functional Mock.Up Interface for embedded systems). It is planned to standardize a potentially improved version by the Modelica Association.
.3. Abstract
The eFMI (FMI for embedded systems) standard specified in this document aims to extend the scope of FMI (https://fmi-standard.org) from simulation towards software development. The eFMI standard is intended as exchange format for workflows and tool chains from physical models to embedded software. It is defined as a layered approach built upon the FMI for Co-Simulation standard (any version). An eFMI component, that is an eFMU (Functional Mock-Up Unit for embedded systems), can be packed in different formats. Especially, an eFMU can be packed as FMU and can then be simulated with any FMI compliant tool (https://fmi-standard.org/tools) to perform Software-in-the-loop (SiL) testing. Code generation for an embedded device requires however dedicated tool support for eFMI.
This effort is motivated by the fact that especially the development of advanced control functions and diagnosis functions can benefit from physical models. As of today the realization of such model-based functions incorporating physical models, in the following refered to as physics-based functions, is very involved. The expertise from the physical modeling domains, control design and numerics for real time applications are required as well as implementation knowledge in terms of rules & regulations for embedded software have to be taken into account in order to supply an industry grade function on an embedded device.
The eFMI standard describes a container format that will allow to exchange models in a variety of different types of model representations:
-
The Algorithm Code representation describes the mathematical model in a target and implementation independent fashion as input/output, sampled data block with one fixed or variable sample time using the standardized intermediate language GALEC (Guarded Algorithmic Language for Embedded Control) developed for this purpose. GALEC is based on a small subset of Modelica functions together with changes and extensions as needed for embbeded real-time systems. GALEC code can be scrambled to provide a certain degree of Intellectual Property protection. Physical modeling tools should be able to generate this representation with reasonable effort.
-
The Production Code representations allow to ship C or C++ code within the same container, either as nearly target-independent generic code and/or as highly optimized target specific code. Contrary to FMI, there is no standardized API (getX, setX, doStep, …), but a description of the actual code interface to allow the code to be integrated into existing software architectures with minimal calling overhead. When an eFMI is packed as FMU, an FMU wrapper is added to a selected code representation. Software development tools should be able to provide the transformation from an Algorithm Code to one or more Production Code representations with reasonable effort.
-
The Binary Code representations provide target specific executable codes. These code representations naturally provide the best Intellectual Property protection.
-
The Behavioral Model representation provides references results for different scenarios to allow automatic tests of the Production and Binary Code representations. In the future this representation might be extended to include the original model from which the eFMI representations are derived, or computable scenarios might be added in form of FMUs.
By means of one global content XML description of all parts of an eFMU and by one XML manifest file for every eFMI representation shipped in an eFMU, a highly flexible and extensible mechanism is provided that allow to integrate eFMUs into arbitrary software architectures being deployed to any kinds of execution environment, including for example AUTOSAR or adaptive AUTOSAR.
.4. Overview
This document specifies the eFMI (FMI for embedded systems standard) with references to the FMI (Functional Mock-Up Interface) standard (https://fmi-standard.org/)
In section Section .5 the development of the eFMI standard and its intended usage is motivated.
The technical key concepts with reference to the current FMI standard are explained in section Chapter 1 for the better understanding of the later sections.
Thereafter the eFMI standard is specified starting with the description of the overall container structure of an eFMU (Functional Mock-Up Unit for embedded systems) in section Chapter 2.
The following sections Chapter 3, Chapter 4, Chapter 5, Chapter 6 are dedicated to the different types of model representations supported by eFMI. Each description consists of an introductory section followed by the specifications of the corresponding meta data and language:
-
The Behavioral Model representation provides reference results to allow automatic verification of the Production and Binary Code representations.
-
The Algorithm Code representation describes the mathematical model of discrete-time, sampled data, input/output blocks in a target and implementation independent fashion with the standardized intermediate language GALEC (Guarded Algorithmic Language for Embedded Control - a small subset of the Modelica language (https://www.modelica.org/modelicalanguage) with extensions as needed for embbeded systems).
-
The Production Code representation defines one or more mappings of an Algorithm Code representation to C or C++ Code (for example 32-bit and/or 64-bit representation of floating point numbers, generic ANSI C-Code and/or code specialized to a particular target environment like AUTOSAR and/or specific target processors).
-
The Binary Code representation provides one or more target specific executable codes for one production code representation.
In the following image an overview of the eFMI representations is given, together with examples for potential tool chains:
This standard document is accompanied by the following open source codes and files to allow tools to more easily support the eFMI standard:
-
XML schema files for all xml manifest files defined in this document.
-
An eFMI compliance checker in form of a Python library, to check compliance of eFMUs (Functional Mock-Up Units for embedded systems) with this specification.
-
The eFMI_TestCases Modelica package providing > 20 dedicated Modelica models and variants of them to test eFMI tool chains.
-
The eFMI Modelica package providing all eFMI builtin-functions as Modelica functions with a Modelica implementation, in order that Modelica models can use these functions.
-
ReferenceResults for the models of the eFMI_TestCases library in form of > 50 csv files.
-
eFMUs for the eFMI_TestCases library generated with various tools.
.5. Introduction
The goal of the eFMI standard (FMI for embedded Systems) is to enhance Production Code of embedded control systems by physics-based models in an automated way. This shall improve the performance of the underlying systems, reduce the maintenance costs and increase the productivity of software development for embedded systems.
Embedded software is commonly used on ECUs (Electronic Control Units) to control or monitor a system. In these cases it is beneficial to incorporate knowledge of the system behavior into the function. Physical models aim to describe the behaviour of the system for a given range of operation. These models are well described by differential- and algebraic equations or can be approximated by projection on a neural network.
Physical models can be utilized to achieve a significantly better performance of the system in applications such as:
-
observers/virtual sensors (e.g. extended and unscented Kalman filters, moving horizon estimation),
-
model-based diagnosis (e.g. signal based fault detectors, linear/nonlinear residual generators),
-
feedback and feedforward controllers (e.g. linear controllers with gain scheduling, nonlinear inverse models, nonlinear dynamic inversion, feedback linearization, linear/nonlinear model-predictive control),
-
neural networks to approximate physical models and/or the above applications.
These types of functions are typically hand-coded software implemented and tested in an elaborate and time-consuming fashion. The eFMI standard aims to provide model exchange capabilities that allow to transfer physical models created in dedicated modeling and simulation tools to embedded code generating tools for ECU software. This enables an end to end workflow from physical modeling to the deployment of the software function on an embedded device.
The eFMI standard is an open standard based on the FMI standard (Functional Mock-Up Interface, https://fmi-standard.org/). eFMI components are able to interoperate with software components according to the automotive embedded system standards AUTOSAR (https://www.autosar.org/standards/classic-platform/) and Adaptive AUTOSAR (https://www.autosar.org/standards/adaptive-platform/). Generated code shall refer to typical safety measures and coding guidelines, e.g. in the Automotive industry the ISO 26262 and MISRA-C 2012 for Autocode (https://www.misra.org.uk/Activities/MISRAAutocode/tabid/72/Default.aspx).
Different types of model representation shall allow to separate the concerns of deriving a proper computation algorithm and its compliant implementation for an embedded device. The container architecture and rich meta information, extending the FMI model description, support the integration in existing development processes and tool chains.
1. General concepts
This section describes the general concepts of the eFMI standard
The goal of the standard is to extend the existing FMI standard to the embedded domain. The FMI standard is focused on simulation of models and model parts, on few standardized execution platforms (Windows, Linux) with well known tool chains. With this context in mind, the FMI standard does not consider any constraints with respect to resource consumption or run time characteristics of the model.
In contrast there is a considerable diversity of embedded platforms, each with their own constraints with respect to runtime performance, memory limits or available compiler support. Given these additional constraints the goal of the FMI standard "Compile once, run everywhere" is neither feasible nor desirable.
A further aspect is the use of models not only for the sake of simulation but in a broad application range, from advanced control strategies like model predictive control to model based diagnosis. The eFMI standard must consider these aspects and is therefore designed as an extension to the FMI standard as described in the following.
1.1. Comparing FMI with eFMI
A major enhancement of the eFMI standard in comparison to the FMI standard is the introduction of different abstraction levels. The FMI standard is based on an executable C Code with an interface of fixed and well defined functions (like getX, setX and doStep). This approach is well suited for the purpose of simulation on a standardized platform (either Windows or Linux).
However, such an approach is not very suitable for (deeply) embedded code due to the following reasons:
-
Support of a diverse number of execution targets.
-
Support of a diverse number of compilers.
-
Integration of the code into existing code structures (in the following we will call this the "Software context") with minimum overhead in data passing and function calling.
For this reason one fixed C Code (or one fixed executable) representing the implementation is not sufficient. Instead the eFMI supports the concept of several C Code implementations (or also binary implementations), each with a description of the interface of the C Code. These descriptions are defined in so-called manifest files and are bundled with the corresponding code files into a Production code container. More details on these manifest files can be found in the section on Production Code manifests (Section 5.2). Here you will also find examples demonstrating the influence of the software context onto the generated code and manifest descriptions.
An FMU represents exactly one model (implemented by the C Code or executable). The same shall be true also for an eFMU despite of the fact that it may contain any number of C Code implementations, and additionally, it shall be easily possible to add further implementations (e.g. for different targets or software contexts) into the eFMU at any time.
This requirement is enabled by adding a higher level abstraction to the eFMU, namely the "Algorithm Code".
The Algorithm Code contains an abstracted description of the function(s) to be computed, and serves as the input to generate the C Code implementations. The functions are described in a pseudo programming language (influenced by Modelica functions), and the meta data is also given in a manifest file. The Algorithm Code is a solution to a causalization of this system by specifying
-
Causalization: the input/output behaviour of the system.
-
Discretization: discretization of differential equations (use of solver, time discretization).
The Algorithm Code is organized in code containers in the eFMU, similar to the Production Code container. For more details on the organization of these containers to form a valid eFMU, please see the section on container architecture (Chapter 2).
The following table summarizes the differences between FMI and eFMI.
Topic |
FMI |
eFMI |
Goal |
(co-) simulation |
efficient ECU implementation |
Execution platform |
standardized (Windows (.dll), Linux) |
diverse: different ECUs, different compilers |
Reuse |
"as is" in "all" simulation environments |
highly limited (therefore several implementations possible) |
Interface |
fixed based on standardized API (getX, setX, doStep, …) |
not fixed, but description of the actual interface |
Implementation |
one implementation (one source code, one binary) |
any number of implementations (target, vendor and "architecture" dependent) |
Abstraction level |
C Code level |
Abstract model representation algorithm (Algorithm Code) in addition to (derived) C Code implementation (Production Code) |
1.2. FMI compliance
An important fact is that despite the broadened scope of the eFMI, an eFMU can be packed into an FMU. This is achieved by taking a distinguished Production Code level implementation and wrapping this to an FMI compliant interface with corresponding model description file. Surely this Production Code level implementation must be target independent and suitable for simulation targets like Windows or Linux.
1.3. Functions in eFMI
In the following different kinds of functions considered in the eFMI standard are described. It is mentioned for which model representation a certain function kind is available. Differences between the kind of functions and consequences and requirements for e.g. transformation tools are also covered.
1.3.1. Block methods
(Available in Algorithm Code and Production Code model representation)
The Algorithm and Production Code model representation is mathematically defined as a sampled input/output block with one (potentially varying) sample period for the whole block. All variables of the block have a defined type and all statements of the block are sorted and explicitely solved for a particular variable. Three block methods are defined, so functions that operate on the same memory self
that is exchanged between the function calls. Especially, methods are provided to initialize the self
memory with function Startup and to perform one step at the actual sample instant with method DoStep.
The block methods are defined in the Algorithm Code representation. A Production Code generator translates these methods to C-functions. It is also possible to define Production Code interface functions directly in C, without providing an Algorithm Code representation.
On Production Code level the block methods are highly integrated in the environment provided by the embedded control unit (ECU). For example, if the ECU provides input signals at certain addresses in memory or the parameters are part of an overall global C-struct. Consequently the actual implementation/interface of the methods is at liberty of the Production Code generating tool.
1.3.2. Built-in functions
(Available in Algorithm Code and Production Code model representation)
Built-in functions are functions with well defined syntax and semantics in the eFMI standard. This includes elementary functions such as sin
, cos
, log
, exp
, but also functions to solve linear equation systems in various ways, for example
x := solveLinearEquations(A, b);
to solve the linear equation system A*x = b
with regular A
matrix for x
.
Built-in functions can be used in Algorithm Code or Production Code. All built-in functions that are supported by the eFMI standard are defined in Section 4.2.6. The names of the built-in functions are reserved and must not be declared by the user.
A tool that transforms Algorithm Code into Production Code doesn’t need additional information for those functions, because their syntax and semantics are clearly defined thus the tool knows how to handle it.
1.3.3. Local functions
(Available at Algorithm Code and Production Code level)
In Algorithm Code, local functions can be defined together with the physics-based model that underlies the eFMU. A local function is formally defined with the GALEC language, see section [GALEC Language]. A Production Code generator generates a C-function from this definition. Alternatively, a local function can be provided as C Code, together with a GALEC wrapper that defines how the call of the GALEC function is mapped to C (the syntax and semantics is identical to the Modelica external function interface). The declaration of the logical function interface must be provided in the corresponding manifest file.
Example of a local function implemented with the GALEC language:
function add
input Real u1;
input Real u2;
output Real y;
algorithm
y := u1 + u2;
end add
Example of a local function wrapper with the GALEC language around a C-function:
// GALEC function wrapper
function dot // scalar product
input Real v1[:];
input Real v2[size(v1,1)];
output Real y;
external "C" y = dot(size(v1,1), v1, v2)
end dot
// C Code signature
float_t dot(const int32_t n, float_t const v1[], float_t const v2[]);
2. eFMU container architecture
An eFMU can be packed in different formats. The basic structure of the eFMU specific part is always:
<eFMU root directory> // depends on the package format // Directories for eFMU model representations (tool specific) schemas // directory with the used eFMI schemas __content.xml // defines the eFMU folder structure
The only required names are the file name __content.xml
and the directory name schemas
at the
root of the eFMU folder. All other directory and file names are defined by the eFMU generation tool.
The used directory and file names are stored in the __content.xml
file and can therefore be deduced by reading this file.
The following eFMU package formats are defined:
-
The
<eFMU root directory>
is a standard directory in the file system.
[This is useful to hold an eFMU in a text-based version control system, such as github, gitlab or svn.] -
The
<eFMU root directory>
of (1) is zipped with the efmu-content, especially__content.xml
, at the root of the zip-file. The zip-file has the extension.efmu
.
[This packaging is useful to ship or distribute an eFMU.] -
The
<eFMU root directory>
of (1) is pathextra/org.efmi-standard
inside a standard FMU (Functional Mock-Up Unit) of any FMU type and any FMU version. The path is defined according to the FMI 3.0 specification. With attributeactiveFMU
inside the__content.xml
file it is defined which of the Algorithm, Production or Binary code representations is used as basis of the FMU.
[This package format is useful to ship or distribute an eFMU for Software-in-the-Loop simulation with any suitable FMU tool.]
Note, Algorithm Code, Production Code and Binary Code representations can optionally store associated FMUs. For example Algorithm Code can store a Model-in-the-Loop FMU and Production Code can store one or more Software-in-the-Loop FMUs for different targets. In order to execute these FMUs directly, an eFMI tool is needed. Otherwise, one of the stored FMUs can be selected for package format (3) in order that any FMI-tool can simulate this specific FMU.
Example:
An eFMU could be stored as zip-file with extension .fmu
having the following internal structure:
modelDescription.xml // required FMI file // optional FMI directories and files extra // extra directoy of FMI 2.0 and 3.0 org.efmi-standard // eFMU root directory // tool specific directories, e.g. AlgorithmCode schemas // directory with the used eFMI schemas __content.xml // defines the eFMU folder structure
An eFMU may contain any number of additional subfolders below the <eFMU root directory>
with one subfolder for each model representation. An eFMU container can contain only one Behavioral Model Representation, one Algorithm Code Model Representation, but can contain multiple Production Code Model Representations and also multiple Binary Code Model Representations.
Each Model Representation itself can be organized in subfolders. It must have a dedicated manifest file. Other files describing the model representation such as code, an FMU, documentation, or license files may be organized in this subfolder.
The following diagram sketches the eFMU containers visually (details are given in the next sub-section):
2.1. Content description (efmiContainerManifest.xsd)
The __content.xml
file is the registry for all model representations in the eFMU container.
It has the following schema definition:
Name | Description |
---|---|
|
Version of the |
|
Value of name attribute of model representation whose FMU is currently unpacked in the root directory of the FMU. If no FMU is unpacked currently, the value of this attribute must not be set. |
|
A group of attributes that is identical for all manifest files. For details see [ManifestAttributesBase]. |
Each model representation that is a part in the eFMU container must have a corresponding entry in the __content.xml
file with the following information:
Name | Description |
---|---|
|
Unique name of the container, also defining its root directory name. |
|
The type of the model representation. The allowed values are
|
|
Name of the container’s manifest file. The manifest is located in the container’s root directory, cf. "name" attribute. |
|
SHA-1 checksum of the binary content of the manifest file. A checksum of the whole subfolder is not required, because the files belonging to a model representation and their checksums are listed in the manifest file itself. |
|
The unique GUID of the manifest file (= corresponding attribute of ManifestReference).
References a manifest using the Manifest elements |
The following is an example of such a content file:
<?xml version="1.1" encoding="utf-8"?>
<Content xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="schemas/efmiContainerManifest.xsd"
xsdVersion ="0.9.0"
efmiVersion="1.0.0"
id ="{92b7edbe-e77d-419a-8457-bf8d452a98f6}"
name ="MyModel"
generationDateAndTime="2021-02-27T15:43:25Z"
>
<ModelRepresentation kind ="ProductionCode"
name ="TLGeneratedCode_v1"
manifest ="mark.xml"
checksum ="e29810938a2a535dc8f6f9b8f51c5febe834ee01"
manifestRefId="63f8c810-f008-47f0-a4b6-7a243f83e46b" />
<ModelRepresentation kind ="AlgorithmCode"
name ="algoCode_v1"
manifest ="luke.xml"
checksum ="e29810938a2a535dc8f6f9b8f51c5febe834ee05"
manifestRefId="63f8c810-f008-47f0-a4b6-7a243f85e46b" />
<ModelRepresentation kind ="BinaryCode"
name ="binCode_v1"
manifest ="matthew.xml"
checksum ="e29810938a2a535dc8f6f9b8f51c5febe834ee08>"
manifestRefId="63f8c810-f008-47f0-a4b6-7a243f85e47b" />
</content>
This __content.xml
file describes therefore the following directory structure:
<eFMU root directory> TLGeneratedCode_v1 mark.xml algoCode_v1 luke.xml binCode_v1 matthew.xml schemas // directory with the used eFMI schemas __content.xml // the xml-file of the example above
This example just demonstrates that the folder names of the model representations and the manifest file names are defined by the generating tool. Typically, more descriptive names would be used, such as:
<eFMU root directory> BehavioralModel manifest.xml AlgorithmCode manifest.xml ProductionCode_Generic_C_Float32 manifest.xml ProductionCode_Generic_C_Float64 manifest.xml ProductionCode_Autosar_Float32 manifest.xml schemas __content.xml
2.2. Structure of Model Representations
Each model representation can have its own flexible structure. Its content and the structuring of information is described in the manifest file (for details on specific manifest files for the different kind of model representations refer to the corresponding sections). Which file in a model representation is its manifest file can be found as the reference entry in the __content.xml
file. The manifest file must be located in the model representation’s root folder.
eFMI allows for having model representations consisting of a manifest file only, hence information should not be doubled. For example, a tool generating directly a Production Code Model Representation must also generate an Algorithm Code Model Representation, because information relevant for Algorithm Code is stored only in the corresponding manifest file and not in the Production Code manifest.
2.3. Model Representation Manifests
The model representation manifests share the same guiding principles:
-
Entity names start with a capital letter
-
Attribute names start with a lower-case letter and use camelCase where needed.
-
Entities that serve as a group get the name of the grouped entities and an 's' as postfix.
-
Each entity that should be referred to has an attribute called
id
. -
The type of an
id
attribute is an arbitrary string. -
All
id
attribute values in a manifest file are unique. -
References to other elements within or across manifest are established through attributes ending with "RefId". The value is the
id
of the referenced element. -
For file references a string attribute is used and the value is interpreted as the relative path starting at the corresponding model representations root folder.
-
The context of a reference is specified in the definition of the manifest element and could be either within the same manifest (local context) or within the a referenced manifest (foreign context).
All manifests also share the principles outlined in the following sections:
2.3.1. Attributes of manifest files (efmiManifestAttributes.xsd)
The top-level element of a manifest file has the two attributes xsdVersion
and kind
that have a fixed value that is specific to the corresponding manifest file.
For example, these two attributes are defined for the AlgorithmCode manifest file in the
following way:
The attributes have the following meaning:
AName | Description |
---|---|
|
The version of this manifest schema file in semantic version number format (https://semver.org). |
|
The type of this manifest file. The allowed values are |
Additionally, the top-level element of a manifest file has the following attributes (that are not specific to the manifest kind):
The attributes have the following meaning:
Name | Description |
---|---|
|
The version of the efmi Standard in semantic version number format (https://semver.org) (currently: "0.7.0"). |
|
The UUID for this manifest file. |
|
The name of the block (controller, diagnosis system etc.) as used in the modeling environment from which the manifest file was created, such as "Modelica.Mechanics.Rotational.Examples.CoupledClutches". |
|
Optional string with a brief description of the block. |
|
Optional version number of the block as used in the modeling environment from which the manifest file was created. [Example: "1.0"]. |
|
Date and time of the last modification of the manifest file.
The format is a subset of "xs:dateTime" and should be: "YYYY-MM-DDThh:mm:ssZ" (with one "T" between date and time; "Z" characterizes the Zulu time zone, in other words, Greenwich meantime). |
|
Optional name of the tool that created the manifest file. If the files have been created manually use |
|
Optional information on the intellectual property copyright for the manifest and code files. |
|
Optional information on the intellectual property licensing for the manifest and code files. |
Note, optional attributes defined in the __content.xml
file, hold also for the manifest files in folders below this file, if not redefined in a manifest file. For example, if attribute license
is defined in the __content.xml
, but in no other manifest file of this eFMU, then the defined license holds for all directories and files below the <eFMU root directory>
. If, say, a Production Code manifest defines a license
attribute, then this license holds for all directories and folders in this Production Code model representation, independently what is defined in the __content.xml
file.
2.3.2. Listing of relevant other manifest files (efmiManifestReferences.xsd)
The information about the eFMU is layered into several model representations (e.g. Algorithm Code, Production Code). In order to allow cross referencing between
these model representations, the manifest files to be referenced need to be registered in a manifest file of a certain model representation. For this the ManifestReference
tag is used with the following attributes
Name | Description |
---|---|
|
Unique id of the manifest reference entry. This id is used to establish cross manifest references. |
|
The unique GUID of the manifest. [Note, the name of the associated model
representation in the |
|
The checksum of the referenced manifest file. |
|
Boolean flag to indicate if that referenced model representation is the one that was used to derive the current model representation. |
Example:
<ManifestReferences>
<ManifestReference id ="ID_1"
manifestRefId="{63f8c810-f008-47f0-a4b6-7a243f85e46b}"
checksum ="e29810938a2a535dc8f6f9b8f51c5febe834ee05"
origin = true />
<ManifestReference id ="ID_2"
manifestRefId="{63f8c810-f008-47f0-a4b1-7a243f85222b}"
checksum ="b4b84af148e587b95300d7a734302d1b911a6e58"
origin =false />
</ManifestReferences>
2.3.3. Listing of files belonging to the model representation (efmiFiles.xsd)
Each manifest contains a list of the files that are part of its model representation. These files are listed in a manifest as follows in the Files
elements tag.
A File
element has the following attributes:
Name | Description |
---|---|
|
id of the file reference entry. This is id is used to refer to the file reference within the manifests. |
|
Name of the file |
|
Directory part of path to the file (relative to root of model representation). Value has to start with |
|
boolean flag indicating that the file is considered in the checksum calculation (default value "true") |
|
The checksum of the file. |
|
The role of the file in the model representation. This attribute is an enumeration with the following valid values: - - - - - - NOTE: The enumeration values have been selected such that each value may be used on an arbitrary level of abstraction, that is kind of model representation. In the future, more enumeration values might be added. |
|
An optional description of the file (especially if |
|
See below. |
Example of a list of files:
<Files>
<File id="ID_1" name ="model.c"
path ="./code/"
needsChecksum="true"
checksum ="b4b84af148e587b95300d7a734302d1b912a6e58"
role ="Code"/>
<File id="ID_2" name ="model.h"
path ="./code/"
needsChecksum="true"
checksum ="b4b84af148e587b95300d7a734402d1b911a6e58"
role ="Code"/>
<File id="ID_3" name ="misra.doc"
path ="./code/"
needsChecksum="true"
checksum ="b4b84af148e587b95300d7a734302d1b914a6e58"
role ="other"/>
<File id="ID_4" name ="model.arxml"
path ="./code/"
needsChecksum="true"
checksum ="b4b84af148e587b95300d7a734302d1b911a7e58"
role ="other"/>
<File id="ID_5" name ="model.doc"
path ="./description/"
needsChecksum="false"
role ="other"/>
</Files>
2.3.4. Referencing
Referencing inside a model representation
Reference attributes pointing to entities in the same manifest must fulfill the naming convention that the attribute name consists of the original entity name and adding "RefId" as postfix.
The value of the reference attribute must thereby be a valid id in the given context of the reference attribute, meaning that the id must exist in the context and be of the right type. For example a value of reference attribute variableRefId
is an id number in the same manifest referencing a variable. In the Production Code Model Representation manifest file shown below, the DataReference with ID_100 references the variable T with ID_33 using the attribute variableRefId
.
Referencing files
Files play a certain role in the eFMU model representation and are listed in a Files
element of each manifest. Referencing files inside a model representation is done by using a FileReference
element that comes along with Files
and File
element itself and not using a fileRefId
attribute only.
The reason to use a certain FileReference
element is that the element comes along with a kind
attribute of type string to allow for specifying the kind of a file in more detail.
Name | Description |
---|---|
|
Reference to the id in the file overview |
|
Attribute for a more detailed specification of the kind of file used. The list of allowed values is not predescribed but should follow the guideline ???? |
<CodeFile id="ID_13" fileType="ProductionCode">
<FileReference fileRefId="ID_1" kind="SourceCode"/>
</CodeFile>
Note, that a FileReference
attribute has no id
attribute and therefore can’t be referenced.
This prevents transitive file referencing.
Referencing into other model representation - ForeignReference (efmiManifestReferences.xsd)
The eFMU describes one model on different levels of abstraction. Thereby the level of abstraction decreases in the following order
-
Behavioral Model
-
Algorithm Code
-
Production Code
-
Binary Code
In order to establish cross referencing between these model representations, the "derived" model representation must include a ManifestReference
to that model representation as described above. The consistency to the referenced one is ensured as follows:
The manifestRefId
is used to retrieve the (current) model representation checksum of the entry in the __content.xml
file. This (current) checksum can be compared with the (stored) checksum that is part of the ManifestReference and is the checksum at the point of creation of that container. Through comparison of both consistency can be ensured.
In order to cross reference into a referenced container’s manifest, a ForeignReference
element is present that has the following required two attributes:
Name | Description |
---|---|
|
The (manifest local) id of a |
|
The id inside the referenced manifest file. |
Example:
<ManifestReferences>
<ManifestReference id ="ID_1"
manifestRefId="{63f8c810-f008-47f0-a4b6-7a243f85e46b}"
checksum ="e29810938a2a535dc8f6f9b8f51c5febe835ee05"
origin ="true"/>
...
</ManifestReference>
...
<Variable name ="T"
id ="ID_33"
typeDefRefId="ID_25"
pointer ="false"
value ="0.1"
const ="false"
volatile ="true"
static ="false" />
<Variable name ="_Clocks_interval"
id ="ID_34"
typeDefRefId="ID_25"
pointer ="false"
value ="0.005"
const ="false"
volatile ="true"
static ="false" />
<Variable name ="gearRatio"
id ="ID_35"
typeDefRefId="ID_25"
pointer ="false"
value ="105"
const ="false"
volatile ="true"
static ="false" />
...
<DataReferences>
<DataReference id="ID_100" variableRefId="ID_33" >
<ForeignVariableReference manifestReferenceRefId="ID_1" foreignRefId="ALG_ID_101"/>
</DataReference>
<DataReference id="ID_101" variableRefId="ID_34" >
<ForeignVariableReference manifestReferenceRefId="ID_1" foreignRefId="ALG_ID_100"/>
</DataReference>
<DataReference id="ID_102" variableRefId="ID_35" >
<ForeignVariableReference manifestReferenceRefId="ID_1" foreignRefId="ALG_ID_103"/>
</DataReference>
...
In the example above (a cut-out of a Production Code Model Representation manifest file), the manifestReferenceRefId
attribute (with value "ID_1") identifies the ManifestReference
as the one that references the Algorithm Code Model Representation with the Manifest id "63f8c810-f008-47f0-a4b6-7a243f85e46b" in the eFMU container and the foreignVariableRefId
attribute the element in that container with the given id (e.g. "ALG_ID_102").
It has to be checked, that the referenced ids actually are valid and are used for the objects of the right type.
Important restriction:
The names of a variable can differ in the manifests of the Behavioral Model, the Algorithm Code, and the Production Code. But for input and output variables of the eFMI block, that are defined in the Algorithm Code manifest, the structure (e.g. scalar or vector or matrix) has to be preserved over the different model representations. It means, an output vector y
in the Algorithm Code manifest corresponds to a vector with the same length in all other model representations.
Referencing Files in Foreign Model Representations (efmiFiles.xsd)
In cases where a file in another model representation is used without change in the current model representation, one should use ForeignFile
elements in the Files
list.
Name | Description |
---|---|
|
The (manifest local) id. |
|
Identifying the foreign manifest and the file inside the manifest. |
Example:
<ManifestReferences>
<ManifestReference id="ID_0" manifestRefId="{63f8c810-f008-47f0-a4b6-7a243f85e46b}" checksum="???" origin="true"/>
...
</ManifestReference>
...
<Files>
<File id="ID_1" name="model.c" path="./code"
needsChecksum="true" checksum="e29810938a2a535dc8f6f9b8f51c5febe835ee05" role="Code"/>
<File id="ID_2" name="model.h" path="./code"
needsChecksum="true" checksum="e29810938a2a535dc8f6f9b8f51c6febe835ee05" role="Code"/>
<File id="ID_3" name="misra.doc" path="./code"
needsChecksum="true" checksum="e29810938a2a535dc8f6f9b8f51c5febe835ee06" role="other"/>
<File id="ID_4" name="model.arxml" path="./code"
needsChecksum="true" checksum="e29810938a2a535dc8f6f9b8f51c5febe835ee08" role="other"/>
<File id="ID_5" name="model.doc" path="./description"
needsChecksum="false" role="other"/>
<ForeignFile id="ID_6">
<ForeignFileReference manifestReferenceRefId="ID_0"
foreignRefId ="ID_26" />
</ForeignFile>
</Files>
Annotations (efmiAnnotation.xsd)
Additional data that a vendor might want to store and that other vendors might ignore
are defined with element Annotations
(this definition is identical to the
corresponding element of FMI 3.0):
Name | Description |
---|---|
|
Domain name in reverse domain notation of the tool that can interpret the annotation. Must be unique with respect to all other elements of the Annotation list. Domain names under both the |
2.3.5. Checksum calculation
The checksum is the mean to ensure integrity across different containers in an eFMU. These different container relate to each other and may be changed independent of each other. In order to ensure / check the integrity, with each change of a container, its checksum is updated in the reference entry in the __content.xml
file.
For containers, that reference information from other containers or depend on them, also the checksum of these referenced containers is locally stored in that manifest. The comparison of these checksums is now an appropriate mean to check the consistency within the eFMU.
The calculation of checksums is done on the files that are listed in the manifest of the container (for which the checksum
attribute has the value "true") and the checksum is stored in the checksum
attribute of the corresponding "File" list entry of the "Files" elememt of each manifest file. The calculation for each file is based on a hash algorithm, currently SHA1 [SHA1Wiki] (https://en.wikipedia.org/wiki/Secure_Hash_Algorithms).
The overall checksum of a model representation is the checksum of the manifest file, where all checksums of files of the model representation has been stored. Since the paths of the files are part of the manifest file itself it is ensured that a change of names, structure or content of the concerned files will result in a different checksum and allows for detecting changes, e.g. a model representation has been changed in the container, but has been taken as input for transformation tools before.
On the other hand, changes to "unchecksummed" files (e.g. description files) will not affect the checksum as well as adding of files not listed in the manifest (listing in the manifest would also alter the checksum).
2.3.6. FMU File References
An eFMU container must be downward-compatible to an FMU container. Hence, it may have an FMU which is stored in the root directory of the container (above the "eFMU" directory). Such FMU needs to be associated with a certain model representation located in the eFMU container. In general, each model representation may have an optional FMU, especially a Production Code model representation.
The currently activated FMU needs to be specified in the __content.xml
file by using the optional attribute activeFmu
.
If it is set, its value must correspond to the name of the associated model representation.
If no FMU is unpacked currently, the value of this attribute must not be set.
The optional FMU of a model representation is specified within the manifest file of the model representation, where one and only one file in the list of files has the role attribute set to FMU. Its value must be a relative path inside the model representation to the FMU file.
When the FMU of a model representation M is activated, the following steps are performed:
-
All files in the container’s root except the "eFMU" directory are removed.
-
The FMU file referenced by M is unzipped to the container’s root.
-
The value of the attribute
activeFmu
is set to the name of the model representation M.
3. Behavioral Model Representation
3.1. Introduction
The optional Behavioral Model representation provides reference results for different scenarios to allow automatic verification of the Production and Binary Code representations. The reference results are stored in csv format under the Behavioral Model folder (for details see section Section 3.3). In the future this representation might be extended to include the original model from which the eFMI representations are derived, or computable scenarios might be added in form of FMUs.
Basically, one reference result set consists of a table, where the columns represent the time and variables of the original source model
(for example a AMEsim, Modelica, or syq model).
Typically, these are the input and output variables of the Algorithm Code representation
and the data is produced by simulating the original source model and storing the
result in csv file format. Hereby, it is assumed that the simulations use the
default values of the tunable parameters and the initial values of the states
as defined in the Startup()
method of the Algorithm Code model representation.
Automatic testing of a Production Code or Binary Code representation requires the following steps:
-
The Algorithm Code variable ids of the input/output variables in the Production Code manifest need to be determined (note, the C variable names of the variables are usually different to the variables names in the Algorithm Code). Therefore an indirect link between the variables in the Production Code manifest and the Behavioral Model manifest is established. With additional information in the Behavioral Model manifest the expected reference results for the input/output variables of the Production Code can be deduced from the corresponding csv-files inside the Behavioral Model folder.
-
The units of the variables are defined in the Algorithm Code manifest file.
-
The results produced by executing compiled Production Code resp. Binary Code have to be compared with the results stored in the Behavioral Model representation. In the Behavioral Model manifest optionally relative and absolute error tolerances are defined to assess the match between the data. A second possibilty to specify error tolerances is enabled by having whole data sets of time dependent lower and upper bounds of variables in the reference results. More details are given in the next subsection.
3.2. Behavioral Model Manifest
The manifest file of the Behavioral Model representation is an instance of an XML schema definition and defines the available scenarios with reference results and maximum acceptable deviations from them.
3.2.1. Definition of an eFMU Behavioral Model (efmiBehavioralModelManifest.xsd)
This is the root-level schema file of the Behavioral Model representation and contains the following definition:
Element-Name | Description |
---|---|
|
The attributes of the top-level element are the same for all manifest kinds and are defined in section
Section 2.3.1. |
|
References to manifest files of other model representations for which referencing is needed within this Behavioral Model manifest. Mainly, the Algorithm Code manifest on which this Behavioral Model manifest is based on has to be listed. This element is the same for all manifest kinds and is defined in section Section 2.3.4.3. |
|
List of files referenced in this model representation. There must be at least one file that contains reference results in csv format. This element is the same for all manifest kinds and is defined in section Section 2.3.3. |
|
A scenario groups several simulation results (parts of one scenario) to one unit. At least one scenario definition must be present. For details see Section 3.2.2. |
|
Required list of variables for which a link between columns in reference results and variables in the Algorithm code manifest is established in the Behavioral Model manifest. For details see Section 4.1.6. |
|
Optional element that defines how the columns of the csv files are mapped to the variables. It also provides information for the variables in each scenario part how acceptable deviations between simulation results of Production/Binary code and reference results are specified. For details see [definition-of-csvdata]. |
|
Additional data that a vendor might want to store and that other vendors might ignore. For details see Section 2.3.4.5. |
3.2.2. Definition of a Scenario (efmiScenarios.xsd)
A scenario (e.g. open loop test simulations) consists of one or more scenario parts (e.g. simulation runs with different numerical solvers).
Element-Name | Description |
---|---|
|
Optional name of the scenario. |
|
The id of the scenario. |
One simulation within a scenario is defined with a ScenarioPart
element. The essential content of this element is the reference to a csv file.
Element-Name | Description |
---|---|
|
Optional name of the scenario part. |
|
The id of the scenario part. |
|
The reference id of the csv file, in which the reference result data for this scenario part is stored. |
3.2.3. Definition of Variables (efmiVariable.xsd)
The variables to be compared in one of the scenario parts are listed in the following element:
Element-Name | Description |
---|---|
|
The id of the variable within the Behavioral Model manifest. |
|
The reference to the variable defined in the Algorithm Code manifest file. For details see Section 2.3.4.3. A reference to other model representations is not allowed. It is not necessary to define all variables of the Algorithm Code manifest here. Only the variables for that reference data in csv files is provided need to be listed. |
3.2.4. Definition of CsvData (efmiCsvData.xsd)
This element is the essential part of the Behavioral Model manifest and provides the information where for the variables the data can be found in the reference data files (= csv files). It also contains the information how the assessment can be realized, that deviations between the eFMI simulation results (by compiled Production Code or Binary Code) and the reference data in the csv files are acceptable.
Element-Name | Description |
---|---|
|
Information where the time vectors can be found in the csv files. |
|
The name of the time variable in the header of the csv files that are referenced by the listed scenario parts in |
|
The reference id of the scenario part to which this definition of the time vector is associated with. |
|
Information about reference data and acceptable deviations associated with all variables (without time) of all scenario parts. |
In one element Data
the information about reference data and acceptable deviations associated with one variables (but not time) of one or several scenario parts are contained. Several scenario part can only be included, if the information to be provided is identical for these scenario parts. For the scenario parts, for which the information is different for a specific variable, a new element Data
has to be listed for this variable. The whole list of all Data
elements contains a combination of variables and scenario parts. It is not permitted to have the same combination twice, because otherwise the information is not unique.
Element-Name | Description |
---|---|
|
Reference id of the variable to be considered in this |
|
Reference id of the associated scenario part for which the information is provided in this |
|
The nominal reference value of the variable that is associated with a column of the table in the csv files. If the variable is a vector or a multidimensional array, then each relevant component of the vector/array is listed by a separate element |
|
The name of the nominal variable in the header of the csv files that are referenced by the listed scenario parts in |
|
Index of vectors resp. flattend index of multidimensional arrays. The element has to be absent for scalar variables and is required for vectors and mutlidimensional arrays. The index corresponds to the referenced Algorithm code variable (referenced by the element |
|
Optional error tolerance information to be used for comparison of computed and given values in the csv files of the variable considered in this |
The details of the error tolerance information valid for one variable (scalar or vector or multidimensional array) is given with the following element. For each possible value of floatPrecision
maximum one element Tolerance
has to be present.
Element-Name | Description |
---|---|
|
Floating point precision that has to be used to run the compiled Production Code or Binary code to be compared with the reference results ( |
|
Optional default value for the absolute error tolerance that should be used for signal comparisons. For vectors or multidimensional arrays these default values are used for all components. |
|
Optional default value for the relative error tolerance that should be used for signal comparisons. For vectors or multidimensional arrays these default values are used for all components. |
|
Optional list of detailed information about error tolerances and additional columns for time-dependent lower/upper bounds of nominal reference result values. |
The element ToleranceItem
contains detailed error tolerance information about a scalar variable resp. one component of a vector/multidimensional array. If the considered variable is a scalar, then only one element ToleranceItem
has to be present within the list of the element Tolerance
. For vectors or multidimensional arrays only entries for relevant indices are needed and the values of the attribute index
have to be different for each of the entries.
Element-Name | Description |
---|---|
|
Optional absolute error tolerance of the scalar value considered in this tolerance item. If there is already a default value of |
|
Optional relative error tolerance of the scalar value considered in this tolerance item. If there is already a default value of |
|
Optional name of the lower bound variable in the header of the csv files that are referenced by the listed scenario parts in |
|
Optional name of the upper bound variable in the header of the csv files that are referenced by the listed scenario parts in |
|
Index of vectors resp. flattend index of multidimensional arrays. The element has to be absent for scalar variables and is required for vectors and mutlidimensional arrays. The index corresponds to the referenced Algorithm code variable (referenced by the element |
The lower and upper bound variables are not listed or referenced elsewhere in the manifest. The corresponding columns in the csv files contain data to define time-dependent lower/upper bounds of an acceptable simulation with the given float precision in the element Tolerance
.
It is permitted to set all elements absTol
, relTol
, csvLower
and csvUpper
. If absTol
or relTol
are set, then csvLower
and csvUpper
cannot be set and vice versa. For the case, that csvLower
and csvUpper
are set and if there is already a default value of relTol
or absTol
specified in the element Tolerance
, then these default values have to be ignored for the specific scalar variable/component in this ToleranceItem
.
3.2.5. Comparison of signals
The Behavioral Model manifest contains the neccessary information to use inputs in csv files and to compare the simulation results of compiled Production Code or Binary Code with reference results in csv files. For the assessment, if the result deviations are acceptable, two cases have to be distinguished (depends individually on each variable and scenario part):
-
Check by using absolute and/or relative error tolerances or
-
Check by using lower and/or upper bounds.
For a scalar variable there is a column in a csv file that corresponds to the reference result data of this variable. Each row of the data is associated to a time instant of the time vector. In the following the data vector is called y_ref
. The corresponding simulation result is called y_sim
(also a time dependent vector with the same length as y_ref
and the values of the variable at the time instants given by the time vector). If the check is based on lower/upper bounds, then there are further columns in the csv files that are associated to the time dependent lower and upper bounds of the variable. In the following the vectors are called lower
and upper
. The i-th component of all the described vectors are access by y_ref_i
, y_sim_i
, lower_i
and upper_i
.
If for all time instances t_i
the following holds, then the test is passed otherwise not:
-
abs(y_ref_i - y_sim)_i ≤ max(absTol, relTol*abs(y_ref_i))
resp. -
lower_i ≤ y_sim_i ≤ upper_i
3.3. Behavioral Model Data
The csv files as they are contained in a Behavioral Model representation are according to (https://en.wikipedia.org/wiki/Comma-separated_values). In the first line there is a list of header names that define the names of the columns separated by a colon. In the following lines for each of the variables defined in the header a numeric value is provided separated by colon.
The unit of the time is seconds. Values of Boolean variables have to be represented by the Integer values 0 (false) and 1 (true).
Example:
Time,wLoadRef,wMotor,vMotor,isReset 0,0,10,-200,0 0.001,0.003,10,-193.70000000000002,0 0.002,0.006,10,-187.41e3,1 0.003,0.009,10,-181.12958499999996,1 0.004,0.012,10,-174.85834414999999,0
4. Algorithm Code Model Representation
The Algorithm Code model is a portable and tool-independent intermediate representation for coupling physics-modeling tools with embedded Production Code generation. Mathematically, it is described as a sampled input/output block with one (potentially varying) sample period Ti for the whole block where inputs ui and previous (block internal) states xi are provided at sample time ti and outputs yi and new states xi+1 are computed and are latest used at sample time ti+1 = ti + Ti (see figure to the right). All variables of the block have a defined type and all statements of the block are sorted and explicitely solved for a particular variable. Functions are provided to execute the relevant parts of the block, especially to initialize it and to perform one step.
The purpose of the Algorithm Code model representation is to provide a well defined reusable basis for the Production Code generating tools. It can be seen as a target-independent Production Code on a logical level where the relationship to the original model is clearly visible (for example, the hierarchy of the original model is visible in the variable names). Depending on the embedded device the eFMU should be run on, a single Algorithm Code model representation can be used to generate multiple Production Code model representations and is therefore the last target independent model representation of the eFMU.
The Algorithm Code model representation consists
-
of a manifest file in XML format in which all interface variables are defined (see section [Algorithm Code Manifest]),
-
one code file with extension .alg that represents the executable part of the block consisting of a
block
with declarations, and mandatory definitions of the three methodsStartup
,DoStep
andRecalibrate
. These methods are defined in a target-independent way with the new language GALEC (Guarded Algorithmic Language for Embedded Control) which is based on the syntax of a Modelica function (https://www.modelica.org/modelicalanguage) with extensions as needed for embbeded systems (see section [GALEC - The Algorithm Code Language]).
In the Algorithm Code specification and its examples the following coding conventions are used:
-
Types — primitives and components — start with capital letters, and each successive word part starts capitalized. Examples:
Real, Boolean, Pid, GearBox, CrankShaftPid
. -
Stateless functions — including builtin functions — are defined with keyword
function
. The function names start with lower-case letters, and each successive word part starts capitalized. Examples:sin, solveLinearEquations, computeCrankShaftPid
. -
Stateful functions are defined with keyword
method
. The method names start with capital letters, and each successive word part starts capitalized. Examples:Startup, Recalibrate, DoStep
. -
Functions for scalars that are generalized to one and two dimensions use the scalar function name with suffix
1D
and2D
appended. Examples:roundTowardsZero1D, interpolate2D
.
4.1. Manifest
The manifest file of the Algorithm Code model representation is an instance of an XML schema definition and defines the variables and block methods that represent a sampled input/output block, see figure to the right.
4.1.1. Definition of an eFMU Algorithm Code (efmiAlgorithmCodeManifest.xsd)
This is the root-level schema file of the Algorithm Code model representation and contains the following definition:
On the top level, the schema consists of the following elements (see figure above):
Element-Name | Description |
---|---|
|
The attributes of the top-level element are the same for all manifest kinds and are defined in section
Section 2.3.1. |
|
List of files referenced in this model representation. There must be at least one file that contains the code of the |
|
A reference to the fixed or variable sample period defined by a block variable. For details see Section 4.1.2. |
|
The properties of the block methods DoStep, Recalibrate, and DoStep. For details see Section 4.1.3. |
|
Semantic error signal status to be referenced from ProductionCode manifest to mark the single variable that represents the error status. For details see Section 4.1.4. |
|
An optional global list of unit and display unit definitions. These definitions are used in the XML element |
|
A list of all variables that are accessible from the block methods
defined in element |
|
Additional data that a vendor might want to store and that other vendors might ignore. For details see Section 2.3.4.5. |
4.1.2. Definition of Clock
Element Clock
provides a reference to the fixed or variable sample period defined by a block variable. The block should be executed periodically with the defined fixed or variable sample period.
Element-Name | Description |
---|---|
|
The id of the sample period of the block. |
|
Reference to the variable in |
The referenced variable variableRefId
defines the sample period for which the block was designed. When the production code of this block is integrated in the target system (for example as AUTOSAR runnable), then it is expected that the block is executed as periodic sampled data system with this sample period. It might be that also a slightly changed sample period in the target system may still result in reasonable performance.
4.1.3. Definition of BlockMethods
Element BlockMethods
defines properties of the defined block methods.
Exactly three BlockMethod
elements must be defined.
Name | Description |
---|---|
|
A reference to the file (defined in <Files><File>, see section Section 2.3.3) in which the code of the block methods is stored. |
|
Defines the recommended implementation scheme to utilize the calculated outputs. Default is |
|
The ID of the block method |
|
The kind of the block method (this is also the name of the method). Currently possible values are |
|
The error signals exposed by the respective block method (for details Section 4.2.5.1)
Attribute |
The scheme writeOutputs = "AsSoonAsPossible"
is typically used when the controller computes the outputs for the current clock tick (e.g. integrates from the previous to the current clock tick). Pseudo-Code for this scheme:
self = <instance of efmi component>
<initialize self with the manifest start values> or self.Startup()
<write outputs>
<wait until clock starts>
<at every clock tick>
<read inputs>
self.DoStep()
<write outputs>
if <calibration phase and tunable parameters available>
<set tunable parameters>
self.Recalibrate()
end
<wait for next clock tick>
<end>
The drawback of this scheme is that the computing time of efmu.DoStep()
introduces a time delay until the outputs are available.
Note, it is also possible to write the outputs inside DoStep directly after they are computed (without waiting until all statements are processed and the method returns). This implementation scheme of the Production Code
is recommended if attribute writeOutputs
has value AsSoonAsPossible
.
[There are also other implementation schemes that might by useful (currently, it is not possible to state this in the Manifest file). Examples:
Write outputs at next clock tick
This scheme is typically used when the controller computes the outputs for the next clock tick (e.g. integrates from the current to the next clock tick). Pseudo Code:
self = <instance of efmi component>
<initialize self with the manifest start values> or self.Startup()
<write outputs>
<at every clock tick>
<write outputs>
<read inputs>
self.DoStep()
if <calibration phase and tunable parameters available>
<set tunable parameters>
self.Recalibrate()
end
<wait for next clock tick>
<end>
The drawback of this scheme is that the inputs are extrapolated over the sample period because the inputs at the next clock tick are utilized in DoStep
but are not known when DoStep
is called.
Two different clocks for reading inputs and writing outputs
The reading of inputs and the writing of outputs might be performed with different clocks that have the same sample period, but the clock for the outputs is shifted relative to the clock for the inputs.
Event clock (purely event based)
The block might be triggered by an external event (e.g. at a particular angle of the engine shaft). The sample period (from the previous to the current clock tick) is provided as input signal.
4.1.4. Definition of ErrorSignalStatus
This element defines the single, hidden, error signal variable that holds the
error signal status and is referenced from the ProductionCode manifest.
It consists only of attribute id
that defines the ID of this hidden variable:
4.1.5. Definition of Units
Element Units
defines the units that are used by the Variables
element.
This element is identical to element UnitDefinitions
of FMI 3.0 with the only exception
that there is an additional attribute id
to identify a unit uniquely in the AlgorithmCode
manifest file and without element DisplayUnit
:
4.1.6. Definition of Variables
The Variables
element consists of an ordered list of all variables used as model states of the methods defined in element
BlockMethods
, so the values of these variables can be directly accessed and changed in the respective method using the name
of the variable prepended with the instance name self
(for example self.previous_x
if the variable has name previous_x
). Variables that are defined with blockCausality = input
are set from the environment at the beginning of a sampling period. Variables that are defined with blockCausality = output
are used at the end of the sampling period by the environment in an appropriate way. Variables that are defined locally in a block
method are not listed in the Variables
element.
Variables are defined as (hereby one variable is defined according to schema group efmiVariable
in file efmiVariable.xsd
):
The schema definition contains basically the same information as element ModelVariables
in FMI 3.0, but using mathematical instead of target types and having the following deviations:
-
There is no
String
type. -
A type might have
Dimensions
where the size of a dimension is an Integer literal (a dimension cannot depend on a structural parameter as in FMI 3.0). -
The variable attributes
causality
,variability
andinitial
of FMI 3.0 are replaced with the new attributeblockCausality
(see below). -
The following FMI 3.0 attributes are not present:
-
valueReference
-
canHandleMultipleSetPerTimeInstant
-
clockReference
-
clockElementIndex
-
intermediateUpdate
-
declaredType
-
quantity
-
displayUnit
-
unbounded
-
derivative
-
reinit
-
Variable Base (attributes + elements)
All variable kinds (so RealVariable, IntegerVariable, BooleanVariable
)
have the following base attributes/elements:
Name | Description |
---|---|
|
The unique identification of the variable with respect to the AlgorithmCode manifest file (can be referenced from other manifest files). |
|
The full, unique name of the variable. Every variable is uniquely identified within an eFMI AlgorithmCode instance by this name. |
|
An optional description string describing the meaning of the variable. |
|
Enumeration that defines the causality, variability and initialization of the variable. Allowed values of this enumeration:
|
|
Initial value of the variable as defined by default initialization. The given [For example, a table If the variable is a scalar, the string must encode a scalar value. If the variable is a multi-dimensional array, the string can either: (1) encode a scalar value, meaning that each element of the multi-dimensional array has the respective scalar value as start value or (2) encode a multi-dimensional value, meaning that the start values of the elements of the multi-dimensional array are the respective encoded multi-dimensional value. Encoded values must be of the variable’s type and each must satisfy its |
|
If the variable is an array, then the fixed dimensions of the array
are defined by this element.
For every dimension, the |
|
Additional data of the variable, e.g., for the dialog menu or the graphical layout. For details see Section 2.3.4.5. |
In FMI 3.0 the attributes causality, variability, initial
are defined, which combinations are allowed and why the allowed combinations are needed for an offline simulation program with events. However, for eFMI most of the combinations cannot occur. For simplicity, eFMI uses therefore only the attribute blockCausality
. In the following table the mapping of blockCausality
to the FMI 3.0 attributes is defined:
eFMI | FMI 3.0 | ||
---|---|---|---|
blockCausality |
causality |
variability |
initial |
|
|
|
--- (no initial) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
RealVariable-specific attributes
The following RealVariable
specific attributes are defined:
Attribute-Name | Description |
---|---|
unitRefId |
Identifier of the unit of the variable defined in list |
relativeQuantity |
Defines if BaseUnit-based unit conversions have to consider the base-unit’s offset (relativeQuantity=false) or not (relativeQuantity=true).
[For example, 10 degree Celsius = 10 Kelvin if |
min |
Minimum value of variable (variable value ≥ |
max |
Maximum value of variable (variable value ≤ |
nominal |
Nominal value of variable. If the variable is a multi-dimensional array, If not defined and no other information about the nominal value is available, then nominal = 1 is assumed. |
Example:
<Units>
<Unit id="UnitID_1" name="s"/>
</Units
<Variables>
<RealVariable id="ID_1" name="Ti" unitRefId="UnitID_1" blockCausality="tunableParameter" start="0.1"/>
<RealVariable id="ID_A" name="A" blockCausality="constant" start="1.1 1.2 2.1 2.2">
<Dimensions>
<Dimension number="1", size="4"/>
</Dimensions>
</RealVariable>
<RealVariable id="ID_2" name="previous(I.x)" blockCausality="state" start="0.0" min="0.0" />
</Variables>
IntegerVariable-specific attributes
The following IntegerVariable
specific attributes are defined:
Attribute-Name | Description |
---|---|
min |
Minimum value of variable (variable value ≥ |
max |
Maximum value of variable (variable value ≤ |
Examples:
<Variables>
<IntegerVariable id="ID_11" name="numberOfCylinders" blockCausality="tunableParameter" start="6" min="0" />
<IntegerVariable id="ID_12" name="pivots" start="0">
<Dimensions>
<Dimension number="1" size="8"/>
</Dimensions>
</IntegerVariable>
</Variables>
BooleanVariable-specific attributes
The BooleanVariable
element has no additional attributes.
4.2. GALEC: The Programming Language for Algorithm Code Containers' Source Code
The algorithm that defines an input/output, sampled data block is defined with the new language GALEC (Guarded Algorithmic Language for Embedded Control) that is specified in this sub-section. GALEC is based on a small subset of the Modelica Language (especially on Modelica functions, Modelica External Function Interface, and on Synchronous Language Elements) of the Modelica Specification 3.4 (https://www.modelica.org/documents/ModelicaSpec34.pdf) together with changes and extensions as needed for embbeded real-time systems. GALEC has the following features that are not present in the Modelica Language:
-
The language is designed so that only algorithms can be defined that have an upper-bound on the number of operations for each control-cycle to satisfy hard real-time constraints (for example, there are no while loops). Furthermore, all needed memory, especially of arrays and operations on arrays, is known statically.
-
The language is designed for computational safety. For example it can be statically guaranteed that out-of-bounds and otherwise illegal memory accesses for all possible executions cannot occur at run-time.
-
The language is designed for traceability so that GALEC code can be understood in terms of the original model and vice versa.
-
The language has a restricted set of methods to efficiently pass the block state between functions.
-
A set of built-in functions is defined so that physical models and their solvers can be reasonably mapped to GALEC code. For example, there are built-in functions for interpolation and for the solution of linear equation systems.
-
The language is designed to handle erroneous situations in a safe way. For example, it is possible to determine at the end of the algorithm whether the computed outputs can be used for further processing, or whether it is necessary to switch to a backup code, for example, if operations produced qNaN (quiet-Not-a-Number) values. Furthermore, min/max values defined in the declaration of variables are used to implicitly limit the variable values at the start and at the end of the
DoStep
method. This is different to the Modelica language that raises assertions if min/max definitions are violated.
The GALEC code of a block is stored in a file with extension *.alg
and is a self-contained file that can be parsed and interpreted without
inspecting the Algorithm Code manifest file.
For examples of GALEC programs, see Section 4.2.7.
4.2.1. Language-design Overview
GALEC code generation is subject to many, often contradicting, requirements imposed by physics and mathematics (physics-modeling domain), embedded real-time system-control (Production Code domain) and development processes for certified systems (embedded development domain):
- (a) An algorithmic source-language for embedded real-time
-
GALEC code has to take into account that further embedded code generation typically must satisfy hard real-time constraints. Generated algorithmic solutions must have an upper-bound of algorithmic steps executed each control-cycle, such that termination within a statically fixed number of computational steps can be guaranteed. To derive such upper-bounds for actual GALEC code is subject of the termination-analysis, which checks that functions of GALEC code are transitively non-recursive and loops always have a statically fixed maximal number of iterations. To transform equation-based models to such solutions may not always be possible. To that end, GALEC code generators are free to reject valid models of their modeling-language as not being suitable for GALEC code generation.
Another important concern of embedded applications is computational safety, requiring for example that programs are free of out-of-bounds or otherwise illegal memory accesses for all possible executions; and that control-flows for error detection and handling always shortcut normal program execution [1]. To that end, a dimensionality-analysis is enforced, which statically defines the sizes of multi-dimensions w.r.t. function call contexts; considering all possible call contexts is required to support generic functions working on arbitrary sized multi-dimensions. The dimensions derived are used to statically ensure that all multi-dimensional accesses always will be within bounds throughout later program executions. Dimensionality and termination-analysis are closely linked; bounded loops can conveniently iterate multi-dimensions whose statically known dimensions in turn define respective upper iteration bounds. Since iteration bounds can depend on the sizes of any multi-dimension, other iteration indices or integer expressions combining such, GALEC code supports advanced iteration schemes that are still guaranteed to be well-defined.
- (b) An algorithmic target-language for simulation of physics-models
-
GALEC code generators have to rearrange original physics-model equations to derive an algorithmic solution. The more comprehensive, complex and mathematically challenging a controller design is — and therefore interesting for modeling its physics — the more rigorous such transformations are typically. Particularly later real-time constraints as described in (a) often require radical transformations to handle algebraic loops and enable equation-system optimisations like symbolic processing, tearing and index reduction. GALEC code generators are therefore encouraged to apply whichever mathematical and logical equation-system transformations they consider required to yield an equivalent algorithmic solution.
Besides the requirement to achieve an algorithmic solution in terms of expression- and assignment-sequences that compute the next state of the simulated control-cycle, no further transformation has to be performed. GALEC provides means to compute with structured-data as common in physics-modeling languages, particularly higher-level matrix-operations. And a library of builtin functions supports common mathematical tasks like solving a linear system of equations. The exact implementation of all these mathematical-abstractions is the responsibility of Production Code generators, leaving opportunity for later target-machine specific optimization. To that end, GALEC code generators are highly encouraged to leverage on the provided mathematical-abstractions.
- (c) An intermediate-language leaning towards algorithm-logics and mathematical-optimization, not algorithm-implementation and target-specific optimization
-
The emphasis in (b) has been on mathematical transformations only; otherwise GALEC code generators should not apply transformations that curtail Production Code generators in their code generation decisions, particularly regarding optimisations leveraging on target-specifics. Typical target-specific optimisations are for example data-structure changes to improve memory-layout for faster access-operations or optimisations of the trade-off between code-size and performance like loop-unrolling. Especially higher-level matrix-operations and builtin function calls are interesting for target-specific Production Code optimisations. Although it seems obvious not to further reduce such mathematical abstractions, it is non-trivial in practice.
The mathematical equation-system transformations described in (b) typically imply separation or reduction of existing and introduction of new multi-dimensional data-structures, influencing matrix-operation and builtin function calls in turn. For example, tearing may be used to reduce the required numerical integration, in turn yielding smaller but also more frequent matrix allocations for linear solving. Fortunately, such mathematical transformations most often also result in more efficient embedded code generated by Production Code generators; but that is hard to say in general. Of course, if required to achieve an algorithmic solution at all, such transformations have to be done. But otherwise, the resulting decomposition of matrices accompanied by matrix-operation flattening and therefore increase in code size may very well supersede the advantage.
On the other hand, GALEC code generators have the domain-knowledge for mathematical-optimisations that Production Code generators lack. An important case for trade-offs between mathematical and Production Code optimisations is scalarization to eliminate controller-output irrelevant or redundant state-variables and equations. Physics-models often contain simple equality-equations between the state-variables of two components; likewise, the components constituting a certain controller may be generalized for more advanced cases than their actual application context, leaving equation-parts unused. GALEC code generators are encouraged to eliminate such system parts, which typically results in multi-dimensions with unused elements like a 2x3 matrix of which only four entries are actually required to compute the outputs. Eliminating the unused entries means to change model structure, while shifting the matrix or changing its dimensionality is not an option because of traceability and a lack of knowledge regarding the final matrix-layout Production Code will eventually apply.
As an alternative, GALEC code can scalarize such multi-dimensions, i.e., flatten the higher-level multi-dimensional entity to a set of scalars — and therefore dimension-less — otherwise equally typed entities. Unused scalars can then just be discarded. The drawback of scalarization is, that all expressions containing higher-level matrix-operations with scalarized multi-dimensions and loops referring to such must be expanded to respective sequences of scalar operations. Besides being in conflict with the requirement to not curtail Production Code from optimizing higher-level matrix-operations, the resulting code-size increase due to expansions may very well render the savings in elements futile.
- (d) A language for algorithmic controller implementation
-
TODO:
Startup
andDoStep
(with input parameters); eFMU state and method vs. function;previous
andderivative
state-variables. - (e) A language part of a trustworthy tool-chain from physics-models to embedded-code
-
GALEC code generators have to maintain traceability, such that embedded solutions derived from physics-based controller designs can be understood in terms of the original model; and vice versa, all parts of a controller-model can be traced to its embedded implementation. To link individual physics-equations to their respective algorithmic solution is very challenging in general, since equations are likely subject to rigorous transformations as described in (b). A common denominator between a physics-model and its transformed solution is however, that both simulate the same system. It therefore is a starting point for GALEC code to at least refer to the states of the original physics-model components whenever using or updating such. The premise is of course, that controllers are modeled as systems consisting of well-structured parts; only then GALEC code generators can, and are highly encouraged, to utilize original system-structure for traceability. To that end, GALEC does not only provide mathematical multi-dimensions as described in (b), but also nested multi-dimensional components with matrix- and scalar-variables; and in case of optimisations resulting in scalarization as described in (c), a quotation-based notation can be used to denote scalarized elements as if their original multi-dimensions still exist. GALEC code generators have to maintain traceability, such that embedded solutions derived from physics-based controller designs can be understood in terms of the original model; and vice versa, all parts of a controller-model can be traced to its embedded implementation. To link individual physics-equations to their respective algorithmic solution is very challenging in general, since equations are likely subject to rigorous transformations as described in (b). A common denominator between a physics-model and its transformed solution is however, that both simulate the same system. It therefore is a starting point for GALEC code to at least refer to the states of the original physics-model components whenever using or updating such. The premise is of course, that controllers are modeled as systems consisting of well-structured parts; only then GALEC code generators can, and are highly encouraged, to utilize original system-structure for traceability. To that end, GALEC does not only provide mathematical multi-dimensions as described in (b), but also nested multi-dimensional components with matrix- and scalar-variables; and in case of optimisations resulting in scalarization as described in (c), a quotation-based notation can be used to denote scalarized elements as if their original multi-dimensions still exist. For example, a scalarized real variable may have the name
'a.b[2].c[2,3]'
, linking it with original model structure for traceability although all output-relevant combinations of componentsa
andb
and matrixc
are scalarized into individual variables. - (f) A portable and tool-independent language for standardized tool-integration and distribution of controller implementations
-
GALEC code is at the center of eFMUs, linking physics-modeling with embedded-development tooling. Although eFMUs are free to only contain target-specific source code, build scripts and resulting binaries, such eFMUs are just fancy containers for embedded solutions; and vice versa, a pure modeling eFMU without executable embedded-solutions misses the actual purpose of eFMI compared to the ordinary FMI standard. It is the GALEC code that brings both worlds together and exposes their relation to eFMU users. The latter does not only imply traceability as described in (e), but also to adhere to a common specification of controller inputs, outputs, states and parameters and control-cycle functionality — an abstract controller usage interface. In the spirit of the FMI standard, and to not preclude a potential future integration with it, this interface is given in terms of an FMI like XML manifest declaring all entities and functionalities of interest for users of the eFMU. The control-state defined in GALEC code — the state components with state variables, control-inputs and -outputs and their nesting — therefore always is linked to entities declared in the manifest; likewise, the initialization and control-cycle functions are exposed in the manifest to clearly declare the functionality an eFMU provides. GALEC code generators are required to derive respective manifests if asked for.
4.2.2. Notation Conventions
The concrete syntax of GALEC code is defined using Extended Backus–Naur Form (EBNF) according to ISO/IEC 14977. The whole grammar is split into different sections, each defining a specific language construct — i.e., syntactic concept — of GALEC code like lexemes, references, expressions, statements etc. The EBNF-rules — i.e., syntactic rules — defining the syntactic concept a section is about can be amended with further semantic rules given in prose. Semantic rules constrain the applicability of the syntactic rules they refer to. They are in turn classified w.r.t. the different semantic concepts of GALEC code they contribute to like type-analysis, dimensionality-analysis, termination-analysis etc.
Due to the decision to structure the whole specification w.r.t. language constructs, semantic concepts cross-cut sections. Table TODO summarizes all semantic concepts, the semantic rules contributing to their definition and the section they are defined. The inevitable complexity of cross-dependencies, typical for any serious formal language, is further attenuated by using a consistent notation for semantic rules, enabling explicit linkage between defined rules, the semantic concepts they contribute to and further rules relevant for or later refining a definition. Likewise, syntactic rules are well-prepared for usage in semantic-rules, i.e., usage in prescriptive definitions given in prose.
Syntactic Rules, Terms and Relations
Each syntactic rule has a unique rule-number of the form G-X1.X2, where X1 is the section the rule is part of and X2 is its unique rule-number within that section; the actual EBNF rule follows separated by a colon. The non-terminals defined by syntactic rules are human readable terms that are well-suited for prose-text usage. Semantic rules denote such usage by writing the respective non-terminal in italic. For readability reasons, every non-terminal can be used in plural or singular form and its first letter can be capitalized when used at the beginning of a sentence. The meaning of a non-terminal within a semantic rule is defined by the following meta-rule:
M-1.1 requires that the syntactic rule a syntactic term refers to is unique; to that end we define:
M-1.1 has severe consequences. If, for example, the specification refers to loop-iterator-declarations, it is clear that this must be names declared by a for-loop regardless in which context the syntactic term loop-iterator-declaration is used; this implication is given because loop-iterator-declaration just derives to name and is only used by bounded-iteration[2] which in turn is only used by for-loop. Besides such implicit restrictions, further explicit restrictions about the syntactic relation between syntactic terms — i.e., that some term’s own derivation must be in a well-defined relation to another term’s derivation throughout the whole derivation — are used:
Using syntactic relations, complicated constraints can be conveniently and precisely defined. For example, the usage of references in statically-evaluated expressions is restricted; on the one hand, they never must be used to access control-state-dependent — i.e., runtime — values, but on the other hand, they should be available to access runtime-independent values provided by the dimensionality- and termination-analysis like the dimensional-sizes of variables or the iteration-values of loop-iterator variables which are always statically-bound. A respective formal definition, based on syntactic relations only, is: every reference contained in a constant-scalar-integer-expression must either, be the 3’rd child of a dimension-query or have a unique for-loop container whose loop-iterator-declaration is lexically-equivalent to the reference. Although such constraints sound like common prose, they are completely formally well-defined by meta-rules M-1.1 to M-1.3 and the derivation semantics of EBNF as defined in Section 5 of ISO/IEC 14977.
It is important to note, that meta-rules, like M-1.1 to M-1.3, are used by nearly all semantic rules and therefore not explicitly referenced by definitions even if relevant.
Semantic Rules
Likewise syntactic rules, also semantic rules have unique rule-numbers. The structure for semantic rule-numbers is S-X1.X2; again X1 is the section the rule is part of and X2 a unique rule-number within that section. The unique rule-number is followed by an informal rule name describing the rule-intention, a slash and finally one or more semantic concepts the rule contributes to, all wrapped in parenthesis. The actual definition follows separated by colon.
As an example consider the following semantic rule:
The general definition of dimensional-bounds and what it means for one to be within another is given by meta-rule M-TODO to which — like for all common meta-rules — is not explicitly referred to.
Rationales, Limitations and Examples
Besides syntactic and semantic rules, sections also list rationales, limitations and examples. A rationale gives further reason why something is specified as it is, like usage-considerations, other specifications of interest or easy overlooked cases that are non-trivial to handle. A limitation clarifies a language constraint that might be relaxed in further iterations of the standard to support future use-cases, that is required to support further tooling working with GALEC code or that is very hard to ease in general for which reason it has been introduced. Examples are used to investigate the implications of the specification by demonstrating code fragments that are illegal GALEC code or that are valid but with a twist fostering understanding of the specification. All three — rationales, limitations and examples — can be part of semantic rules, in which case they are uniquely numbered within the rule they are part of. If more general, they can also be freestanding, in which case their unique number is constructed likewise syntactic and semantic rule numbers, only that rationales are prefixed by R-, limitations by L- and examples by E-. In any case, rationales and limitations have an informal name describing their intention likewise semantic rules have. If freestanding, they also can be associated with semantic concepts, again separated by a slash like for semantic rules; if not freestanding and part of a semantic rule, they implicitly contribute to the same semantic concepts as the rule they are part of.
As an example consider the following non-freestanding rationales, example and limitation:
Other specification parts can refer to enclosed rationales, limitations and examples by appending their unique number separated by a colon to the number of the enclosing semantic rule; for example, one can refer to the limitation of above example by writing S-TODO:L-1.
4.2.3. Block-interface and life-cycle
This Section investigates the utilization of GALEC programs (i.e., blocks) that are due for deployment on an embedded target and its runtime environment.
§1: Embedded target, runtime environment, system integration, block instance & block-interface (terminology, system integration)
GALEC defines an operational interface for blocks — called block-interface — that must be preserved by Production Code generators when translating a block to code that is subject of embedded system integration. Embedded system integration is not just achieved by means of a block’s interface; it must over and above adhere to the operational restrictions defined in §1 to §3 (particularly the block life-cycle of §3 must be satisfied).
A single block can be instanziated many times on an embedded target and its runtime environment; each instance is operationally isolated. There are no restrictions on the number or kind of block instances (in particular different blocks can be instanciated within the same runtime environment). Any interaction of the runtime environment with a block instance must be via its block-interface (even instances of the same block must interact via their block-interface).
§2: Block-interface variables & methods (runtime semantic, system integration)
The block-interface constitues of block-interface variables and block-interface methods.
The block-interface variables are:
-
Block inputs: The sampling inputs provided by the runtime environment.
-
Block outputs: The sampling results consumed by the runtime environment; they must never be written by the runtime environment.
-
Tunable parameters: Parameters sporadically, and not necessarily each sampling, changed by the runtime environment.
Besides this block-interface variables, other block-variables exist, which are block internal and therefore cannot (and must not, cf. §1) be written or read by the runtime environment:
-
Dependent parameters: The parameters derived from tunable parameters.
-
Block states: The internal states.
All block-variables are persistently stored in block instances, such that their values survive block-interface method calls and therefore can be used in call sequences of such. Each block instance has its individual set of block-variables; changing some tunable parameter t
of a block instance b1
does not change t
of another block instance b2
of the same block.
The block-interface methods are:
-
Startup()
: Computes initial values for all block-variables. -
Recalibrate()
: Updates the dependent parameters considering the currently set tunable parameters. -
DoStep()
: Computes the block outputs and updates the block states for the given block inputs and the current tunable and dependent parameters for a single sampling.
§3: Block life-cycle (runtime semantic, system integration)
The permitted interactions with block instances are defined by the following state machine, specifying a universal life-cycle for block instances, called block life-cycle (the do-actions of states refer to the block-interface methods defined in §2):
The block-interface methods of a single block instance must be called in sequence by the runtime environment; parallel execution of such is prohibited. The block-interface methods of separate block instances can be executed in parallel. The block-interface variables of a block instance must not be read or written by the runtime environment while any of its block-interface methods is in execution.
4.2.4. General Syntactic and Semantic Rules
Lexemes
Blocks and Declarations: Control-state and -cycle (memory and inter-functional flowchart)
Expressions: Scalar and Multi-dimensional Arithmetic
Statements: State changes (intra-functional flowchart)
4.2.5. Error handling
GALEC incorporates dedicated language means for systematic, reliable and guaranteed error handling. Three integrated concepts can be distinguished: (1) error signals with enforced signal handling seamlessly incorporated into normal program control-flow, (2) well-defined floating point operations with guaranteed quiet Not-a-Number propagation and (3) variable ranges for guaranteed block saturation. Together, these concepts enable delayed, but ensured error handling avoiding any need to immediately check each and every possible failing operation by means of a plethora of exceptions.
The following sections present these three concepts.
Error Signals
Error-signal-declaration semantic
An error-signal-declaration D of the from
error-signal-declaration = "signal", identifier, ";" ;
is called an error signal. The name of an error signal is the name of its contained identifier; its name must be unique within the block D is part of.
Let Predefined be the following sequence of characters
signal INVALID_ARGUMENT;
signal OVERFLOW;
signal NAN;
signal SOLVE_LINEAR_EQUATIONS_FAILED;
signal NO_SOLUTION_FOUND;
signal UNSPECIFIED_ERROR;
Predefined implicitly follows the characters matched by the 6th child of block; its error signals are called predefined. Any other error signals are called user-defined.
Note: Above specification implies that pre- and user-defined error signals are error signals and can therefore be explicitly signaled and checked by user-code.
Note: The intended usage of the pre-defined error signals is:
-
INVALID_ARGUMENT
: Unspecified error in one or more input arguments. -
OVERFLOW
: Computed floating point result is -∞ or +∞. -
NAN
: Computed floating point result isqNaN
. -
SOLVE_LINEAR_EQUATIONS_FAILED
: Solving a linear equation system via thesolveLinearEquations
builtin function failed. -
NO_SOLUTION_FOUND:
Not used forsolveLinearEquations
, but for example if an optimizer, special nonlinear solver etc. does not find a solution. -
UNSPECIFIED_ERROR
: Error that is not further specified.
Error-signal-statement semantic
A error-signal statement S of the form
error-signal-statement =
"signal",
identifier, (* Set of signals set, at least one AND/OR signal-closure propagation *)
{ ",", identifier } ; (* Set of signals set, at least one AND/OR signal-closure propagation *)
has the following semantic:
-
Each identifier s of S referring to a signal-closure variable s in scope sets all the signals of s whenever S is executed.
-
Any other identifier s of S must refer to an error signal e. Whenever S is executed, e is set.
-
The union of all error signals set by S is called the signal-set of S.
Functional error interface and exposed error signals
A function-declaration F of the form
function-declaration =
( "function" | "method" ),
name,
[ signal-interface ], (* 3rd child defining the signal-set -- i.e, exposed error signals -- of the function *)
{ parameter-declaration },
[ "protected", { local-variable-declaration } ],
"algorithm",
{ statement },
"end",
name,
";" ;
has the following semantic w.r.t. error handling:
-
Let all identifiers contained in the 3rd child of F form the signal-set S of F. Each element s of S must refer to an error signal e; each such e is called an exposed error signal of F and F is said to expose e.
-
Block-interface functions must not expose user-defined error signals.
-
The signal-set of F must be identical to the out-reachable-signals-set an imaginary final statement following the last statement of F would have.
Error-signal-check semantic
An error-signal-check of the form
error-signal-check =
"signal",
[ identifier ], (* Optional signal-closure *)
[
[ "not" ], (* Optional signal-test-negation *)
"in",
identifier, (* Set of signals tested, at least one *)
{ ",", identifier }, (* Set of signals tested, at least one *)
],
[ "or", expression ] ; (* Optional fallback-condition *)
has the following semantic:
-
A signal-closure is a scoped variable that captures the current error-state (i.e., all the currently set error signals). Its scope is the body of the respective
if
/elseif
conditional — the error-signal-check-body — similar to loop-iterators (cf. loop-iterator-declaration, issue #49). It must never be assigned to. -
We define the signal-test-set of an error-signal-check as follows:
-
At least one signal tested is given: If, and only if, no signal-test-negation is given, the signal-test-set comprises all signals tested; otherwise, it comprises the signals of the in-reachable-signals-set of the error-signal-check minus the set of all signals tested.
-
No signal tested is given: The signal-test-set is the in-reachable-signals-set; the error-signal-check is called unrestricted.
In any case, the signal-test-set must be non-empty and a subset of the in-reachable-signals-set of the _error-signal-check_.
-
-
An error-signal-check is signal-satisfied, if, and only if, any of the signals of its signal-test-set is set when it is executed.
-
An error-signal-check is conditional-satisfied, if, and only if, it is not signal-satisfied and has an optional fallback-condition that is satisfied when the error-signal-check is executed.
-
An error-signal-check is satisfied if it is signal-satisfied or conditional-satisfied.
-
The error-signal-check-body B of an error-signal-check is the executed branch of its if-statement, if, and only if, it is satisfied. In this case, all signals of the signal-test-set are unset immediately before the execution of B but after initializing the signal-closure if any.
Error signal propagation semantic: static signal propagation analysis and reachable-signals-set
The idea is simple: To statically decide which error-signals could be set at any point of execution, we define a data-flow analysis, whereas the propagated data is a set of error signals — the reachable-signals-set; this set in turn can then be used to enforce that error-checks only check for error-signals that can be set according to their preceding control-flow and functions only expose signals that can be signaled but are not checked thereafter for any of their possible control-flows.
We define signal-sets for expressions and statements (a signal-set defines which additional signals can be set by the respective language construct):
-
The signal-set of a function-call is the referred function’s signal-set. The signal-set of any other expression is the union of the signal-sets of its contained function-calls.
-
The signal-set of single-assignments and multi-assignments is the signal-set of their right-hand sides.
-
The signal-set of a for-loop is the out-reachable-signals-set of its last statement.
-
The signal-set of an if-statement is the union of the out-reachable-signals-sets of the last statements of its bodies.
We define reachable-signals-sets for statements and the branches of if-statements, particularly error-signal-check branches. Thereby we distinguish between the signals that can be set before executing the respective construct (in-reachable-signals-set) and the ones that can be set after its execution finished (out-reachable-signals-set):
-
The in-reachable-signals-set of the first statement S of a function-body is the empty set.
-
The in-reachable-signals-set of the first branch of an if-statement S is the in-reachable-signals-set of S; for any further branch of S it is the out-reachable-signals-set of its preceding branch.
-
The in-reachable-signals-set of the body of a branch B of an if-statement is the out-reachable-signals-set of B.
-
The in-reachable-signals-set of any other statement S of a function-body is the union of the out-reachable-signals-sets of all its preceding statements (according to control-flow).
-
The out-reachable-signals-set of an error-signal-check branch is its in-reachable-signals-set minus its signal-test-set, finally unified with the signal-set of its fallback-condition if any. The out-reachable-signals-set for a non error-signal-check branch is its in-reachable-signals-set.
-
The out-reachable-signals-set of an if-statement is the out-reachable-signals-set of its last branch unified with its signal-set.
-
The out-reachable-signals-set of any other statement is its in-reachable-signals-set unified with its signal-set.
Production Code and exposing errors to the runtime environment
Since block-interface methods can only expose the 6 pre-defined error signals (cf. Section "Semantic: A"), a definition of signal-communication with the runtime environment is only required for such. To that end a unique mapping of each pre-defined error signal to a unique bit position within a 32 bit integer value is defined. These mappings are bidirectional, such that all exposed error signals can be returned to the runtime environment encoded in a single 32 bit integer value. The bit positions of the pre-defined error signals are:
-
Bit 0:
INVALID_ARGUMENT
-
Bit 1:
OVERFLOW
-
Bit 2:
NAN
-
Bit 3:
SOLVE_LINEAR_EQUATIONS_FAILED
-
Bit 4:
NO_SOLUTION_FOUND
-
Bit 5:
UNSPECIFIED_ERROR
Bit positions 6 to 15 of the returned error value are reserved for the future if there is need to add further pre-defined error signals in later specification versions; for now these bits must be never set by error values returned to the runtime environment.
To enable easy Production Code generator implementation by encoding all error signals — i.e., pre- and user-defined — in single, uniquely laid out (i.e., uniform bit position accessible) 32 bit integer values, GALEC programs must contain at most 16 user-defined error signals (i.e., 32 - 6 pre-defined - 10 reserved).
Examples
Example 1: The following Example sketches a typical mixed-mode coding style, where some error cases are avoided in the first place by special operation modes of the controller and others are treated after something failed by testing for respective error signals:
/*
Safe common control-code, potentially selecting or deselecting special
modes of operation:
*/
...
v := f(A); // f may signal the error f_ERROR.
...
if signal in f_ERROR or not(check(v)) then
/*
Error-handling path if f(A) signaled an f_ERROR or
returned a v not satisfying some check:
*/
...
elseif self.operation_mode == 1 then
/*
Safe control-code for some special operation mode:
*/
...
elseif self.operation_mode == 2 then
/*
Safe control-code for some special operation mode:
*/
...
else
/*
Control-code for normal mode of operations:
*/
...
x := solveLinearEquations(A, b * v);
...
if signal in SOLVE_LINEAR_EQUATIONS_FAILED then
/*
Handle the special case that the system of linear equations
has no solution:
*/
...
elseif signal then
/*
Handle any other unexpected error of the NORMAL operation mode:
*/
...
end if;
end if;
if signal s then
/*
The common control-code or the special modes of operation that are
supposed to be safe missed some error case or introduced
errors themselves. We now can set the control-outputs and state
variables to some reasonable default values and propagate the
unexpected error signals to the runtime environment:
*/
...
signal s;
end if;
Example 2: The following example summarises all possible combinations of error signaling and checking:
method DoStep
/*
(1) Signal interface of functions (signals exposed to callees):
*/
signals invalid_gear_switch, to_high_velocity;
algorithm
...
/*
(2) Universal signal checks, catching and un-setting all signals set:
*/
if signal then
...
end if;
...
/*
(3) Specialized signal checks, catching and un-setting
all signals within a specific set:
*/
if signal in error1, error2 then
...
end if;
...
/*
(4) Restricted universal signal checks, catching any signal that is
not within a certain set:
*/
if signal not in invalid_gear_switch, to_high_velocity then
...
end if;
...
/*
(3) Checks with signal variables enclosing the checked signals
that have been set at the check point:
*/
if signal s then
...
/*
(4) Propagation of signal variable, i.e., set all the signals that the
check s is part of unset:
*/
signal s;
...
else
...
end if;
...
if ... then
...
/*
Explicit setting of signals, i.e., signaling of errors:
*/
signal invalid_gear_switch, to_high_velocity;
...
end if;
...
/*
(*) And all kind of combinations of the above
(signals to check with signal variables, signal
propagation and explicit signaling):
*/
if signal s in f1_error, f2_error or condition1 then
...
signal s, invalid_gear_switch;
...
elseif signal s not in invalid_gear_switch, to_high_velocity or condition2 then
...
signal s;
...
end if;
...
/*
Catch all signals not exposed according to the function's interface:
*/
if signal not in invalid_gear_switch, to_high_velocity then
end if;
end DoStep;
Example 3: The following example shows typical violations of error signal propagation, demonstrating the advantages of a strict static signal-propagation analysis for code hardening:
function f
signals Error1; // Violates B.2: Error1 never exposed and Error2 is missing.
input Real i;
output Real o;
protected
algorithm
if i > 100.0 then
signal Error1;
elseif i > 200.0 then
signal Error2;
end if;
o := 2.0 * i;
if signal in Error1 or o > 350.0 then
o := 350.0;
end if;
end f;
method DoStep // Violates B.2: Error2 is exposed but 'signal in Error2;' is missing.
protected
algorithm
...
f(1.0);
...
if signal s then
...
s := Error1; /* Violates C.1: Signal-closures must not be assigned to. */
elseif signal in Error1 then
/*
Above error-signal-check violates C.2: Signal-test-sets must be non-empty.
Note, that the preceding branch already handles all error signals since it
is an unrestricted error-signal-check.
*/
end if;
signal Error1;
if signal in Error1, Error2 then
/*
Above error-signal-check violates C.2: The signal test-set is not a subset of the
in-reachable-signals-set since Error2 can never be set at this point.
*/
...
signal Error2;
elseif signal in Error2 then
/*
Above error-signal-check violates C.2: The signal test-set is not a subset of the
in-reachable-signals-set since Error2 can never be set at this point. Note, that the
signal-set of the error-signal-check-body of the preceding branch cannot be handled
by this branch; it requires handling in a completely separate if-statement.
*/
end if;
signal Error1;
if signal in Error1 then
end if;
if signal in Error1 then
/*
Above error-signal-check violates C.2: Signal-test-sets must be non-empty.
The preceding if-statement already implicitly unsets Error1 when its
single error-signal-check is satisfied.
*/
end if;
end DoStep;
method Startup
protected
algorithm
// signal in Error1; /* The following if-statement is erroneous, even if this line is uncommented. */
if signal not in Error1 then
/* Above error-signal-check violates C.2: Signal-test-sets must be non-empty.
end if;
end Startup;
Example 4: The following function fragment investigates interesting corner-cases of error-signal propagation. It is well-suited to exercise the formal definitions of signal-set, in-reachable-signals-set and out-reachable-signals-set of if-statements. The left-out code hooks denoted by …
are assumed to be arbitrary code not setting or checking error signals.
function f
signals f_Error;
output Boolean b;
protected
algorithm
b := true;
signal f_Error;
end f;
method DoStep
...
algorithm
...
if signal then // Unset all error signals.
end if;
signal in TestDefinitions1, TestDefinitions2;
if signal in TestDefinitions1 then
...
signal TestDefinitions3;
...
elseif signal in TestDefinitions2 then
...
if signal TestDefinitions3 then
...
end if;
...
elseif signal in TestDefinitions3 then
...
end if;
/*
At this point still TestDefinitions2 and TestDefinitions3 WILL be
set because only the first branch was tested, its test signal-satisfied,
the tested signal TestDefinitions1 unset and its body executed.
*/
...
if signal then // Unset all error signals.
end if;
signal TestDefinitions1, TestDefinitions2;
if signal in TestDefinitions1 then
...
if signal in TestDefinitions2 then
...
end if;
...
end if;
// At this point no error signals WILL be set.
...
/*
Assume for the following code an execution where NotSetSignal
is not set:
*/
if signal not in NotSetSignal then // Unset all error signals except NotSetSignal.
end if;
i := 2;
if signal in NotSetSignal or f() /* Cf. definition of f above! */ then
i := 2 * i;
elseif signal in f_Error then
i := 2 * i;
signal f_Error;
/*
The following branch would be invalid, because f_Error can never be set when it is tested:
elseif signal in f_Error then
i := 2 * i;
*/
end if;
// At this point i WILL be 8 and f_Error set.
end DoStep;
-∞, +∞ and quiet Not-a-Number propagation
GALEC assumes that the target system of the generated production code is compliant to IEEE Standard 754-2008. Even if GALEC code is as much as possible target independent, there are corner cases in which the properties of the target system need to be taken into account in GALEC. If a target system is not fully compliant to IEEE 754-2008, it should still be possible to map GALEC code to such a target, since only a small subset of IEEE 754 is used and/or potential deviations in corner cases might still be acceptable [(for example, if a processor does not support -∞ or +∞ handling, but saturates automatically to the largest/smallest representable floating point number)]. Note, in the following, IEEE 754 shall always mean IEEE 754-2008. Deviations to this standard are explicitly marked.
The language assumes, following IEEE 754 section 6, that exception handling of the processor is configured so that an overflow of Real numbers is handled automatically by the processor for all language operators without generating exceptions by mapping negative and positive overflows to -∞ and +∞ respectively (e.g. 2.0 < 1.0 / 0.0
is true
). With built-in function isInfinite(r)
it can be inquired whether a Real variable r
is -∞ or +∞ (e.g. isInfinite(1.0 / 0.0)
returns true
).
The language also assumes that IEEE 754 exception handling of the processor is always configured to never generate an exception in case of underflow of Real numbers (so deviating from the default exception handling of IEEE 754, section 7.5).
If the result of a mathematical operation on Real numbers is mathematically undefined (for example log(-1.0)
or 0.0 / 0.0
), then the standard operators of the language return quiet Not-a-Number (qNaN
) as defined by IEEE 754, section 7.5. It is assumed that the processor is configured so that qNaN
values are automatically propagated through all operations without generating exceptions (hence quiet Not-a-Number). With built-in function isNaN(r)
it can be inquired whether a Real
variable r
has qNaN
as value or not.
All relational operators (<, >, <=, >=, ==, <>
) trigger error signal NAN
if one of their operands is qNaN
. In such a case the operator returns false
. Conceptually, every relational operator a ⊕ b
is mapped to a built-in function call f_⊕(a, b)
with f_⊕
defined as:
function f_⊕
signals NAN;
input Real a;
input Real b;
output Boolean y;
algorithm
if isNaN(a) or isNaN(b) then
signal NAN;
y := false;
else
y := a ⊕ b;
end if;
end f_⊕;
[In C this function can be implemented efficiently for example as the expression (isNaN(a) || isNaN(b) ? (error_signal |= Bitmask setting NAN, 0) : a ⊕ b)
.]
All built-in functions (see section Section 4.2.6) that can have qNaN
input arguments and are not able to propagate qNaN
because the output argument(s) are not of type Real
trigger the NAN
error signal.
[Note, potential issues as sketched in Agner 2019 are not critical because relational operators and builtin functions trigger the NAN
error signal if a qNaN
value cannot be propagated.]
For some built-in functions that can return qNaN
, also companion built-in functions are provided, that do not return qNaN
, provided none of the input arguments is qNaN
. These functions start with the prefix safe_
and achieve this behavior (conceptually) by automatic limitation of their input argument(s).
Variable Ranges, explicit and implicit limitation and block saturation
All variables can be declared with range attributes min
and/or max
; variables with range attributes are called ranged.
Ranged variables are limited to their defined range at a particular point of execution by means of limit-statements. If a variable v
is ranged with lower bound ⊥ and upper bound ⊤, then the statement limit v;
is equivalent to v := (if v < ⊥ then ⊥ elseif v > ⊤ then ⊤ else v);
. If v
has only a lower bound ⊥, limit v
is equivalent to v := (if v < ⊥ then ⊥ else v);
. If v
has only an upper bound ⊤, limit v;
is equivalent to v := (if v > ⊤ then ⊤ else v);
. Limiting a non-ranged entity has no effect.
[Above definition implies that limitation on qNaN
values has no effect (the variable’s value remains qNaN
).]
limit
can also be used to limit all state variables according to their ranges (using keyword self
), or all nested state variables of a certain state component (by referring to that very state component):
limit self; // Limits all ranged state variables.
limit c; // Assume c refers to a state component: limits all nested state variables of c.
A single limit statement can limit a set of entities. For example,
limit self.c.d.vc, self.v, self.c, l;
limits the variable self.c.d.vc
(assuming self.c.d
refers to a state component and d
is one of its variables), the state variable self.v
(assuming self.v
refers to a state variable), all nested variables of the state component self.c
(assuming self.c
refers to a state component) and the local variable l
.
Every block-interface method implicitly limits all state entities whenever the method is entered and when it returns, except Startup()
, which only limits on returning. The implicit semantic is:
method Startup
protected
...
algorithm
...
// initialize stuff
...
limit self; // Implicit by semantic of language.
end Startup;
method DoStep
protected
...
algorithm
limit self; // Implicit by semantic of language.
...
// compute stuff
...
limit self; // Implicit by semantic of language.
end DoStep;
method Recalibrate
protected
...
algorithm
limit self; // Implicit by semantic of language.
...
// compute stuff
...
limit self; // Implicit by semantic of language.
end Recalibrate;
Every function implicitly limits its inputs whenever the function is entered and its outputs when it returns.
[Implicit limitation at the very beginning and end of block-interface methods means, that from the perspective of the runtime environment ranged state variables are effectively saturated at their defined ranges; the block as such is saturated and guarantees operation within its limits (except for state variables with qNaN
values that need special error handling).
Production Code generators are free to optimize and minimize limitation of variables. For example, limitation of constants, tunable parameters and dependent parameters will never be required in DoStep()
, since such cannot be assigned new values and their limitation is already performed in Startup()
and Recalibrate()
respectively. Limitation of inputs is only needed at the very beginning of DoStep()
code, because inputs are not changed afterwards. Limitation of outputs is only needed at the end of the DoStep()
code. Limitation of states needs to be performed only at the end of Startup()
and the end of DoStep()
, because the states are just passed between DoStep()
calls and then it is guaranteed that a state that is limited at the end of the previous DoStep()
call remains limited at the very beginning of the next DoStep()
call. Furthermore, interval arithmetic analyses can be used to conclude that a variable will never be outside of its valid range, such that limitation code for it can be avoided.
The rationale why limitation is not implicitly performed on every assignment to a ranged variable (i.e., why GALEC has no strict saturation arithmetic) is, that numerical algorithms and particularly integration typically fail if values are not continuous over time. For example, an integration algorithm such as a Runge-Kutta method of order 4 may not work as expected, if states are limited during one step because the smoothness requirements of the integration method are violated. Furthermore, limitations in the middle of computations often inadvertently break algebraic characteristics like distributivity and commutativity that are essential for symbolic processing and optimization. These pitfalls of limitation are however not violated by the implicit limitations at the very start and end of block-interface methods; the block as such — its interface — is saturated from the perspective of the runtime environment. Throughout the execution of a block-interface method however, variables may very-well get values assigned outside of their defined ranges. ]
Error Handling Recommendations
In practice it is typically required that all control-outputs are guaranteed to never be qNaN
and always be within their defined ranges. To that end, the following actions are recommended:
-
Provide min/max values for state variables, particularly control-inputs, -outputs and tunable parameters. Implicit limitation will guarantee, that the state variables are in their defined ranges when a block-interface method returns, or the variable values are
qNaN
. -
Before leaving
DoStep()
, check that none of the control-outputs isqNaN
and that the error signal is notNAN
. If one of these conditions does not hold, take appropriate actions, for example restore the state from the previous sample instant, compute the control-outputs with a backup algorithm (e.g. P-controller) that does not produceqNaN
values, or provide a default control-output, e.g. zero. In any case, the returned outputs should never beqNaN
. -
Use the
safe_⊕
builtin functions (see below) if this is possible, in order thatqNaN
values are not generated. -
Often problematic is the
/
-operator. A general approach to handle division in a meaningful way for all possible circumstances seems impossible. However, in many cases the time-varying denominator is guaranteed to not change sign; examples are: dividing by density, mass fraction, gear efficiency or slip. In such cases, the built-in operatorsafe_posdiv(num, den, eps)
should be used that provides a meaningful approximation ofnum / den
without generatingqNaN
values, if it is guaranteed thatden >= 0
.
4.2.6. Built-in Functions
In this section the built-in functions are defined. If the built-in function is also defined in IEEE 754, the semantic of the built-in function is according to this standard.
Any function that has Real
input and Real
output arguments can usually return qNaN
, because an input argument might be qNaN
that is typically propagated to one or more outputs. Whenever a function can return qNaN
(either because it is generated inside the function or a qNaN
input can be propagated to an output), this is explicitly mentioned and also in which situation this occurs. For many built-in functions ⊕
that can generate qNaN
, there is also a function safe_⊕
that approximates ⊕
so that no qNaN
is generated, in case this approximation is useful (but of course such a function can still return qNaN
if the input is qNaN
).
A built-in function only returns an error signal if explicitly mentioned in its definition below; most builtin functions do not signal any errors and instead rely on qNaN
propagation.
Overview
In the following table, an overview of the built-in functions is given (the follow-up sub-section contains the precise definition of the built-in functions):
Function-Name | Description |
---|---|
Properties of Integer |
|
|
Target-specific smallest Integer. |
|
Target-specific largest Integer. |
Properties of Real |
|
|
Target-specific smallest Real |
|
Target-specific largest Real |
|
Target-specific smallest Real |
|
Target-specific largest Real |
|
Target-specific quiet not-a-number representation ( |
|
|
|
Target-specific -∞ representation. |
|
Target-specific +∞ representation. |
|
|
|
|
Multi-dimensional properties of Real |
|
|
|
|
|
Numeric type conversions |
|
|
Convert Integer |
|
Convert Real |
Direct Real rounding |
|
|
Round |
|
Round |
Nearest Real rounding (using a tie-breaking rule) |
|
|
Also known as convergent rounding, statistician’s rounding, Dutch rounding. |
Division of Integers using rounding |
|
|
Divide |
Remainder of Integers using rounding |
|
|
|
Remainder of Reals using rounding |
|
|
Real remainder with rounding towards zero ( |
Relational Integer functions |
|
|
Minimum of |
|
Maximum of |
Relational Real functions |
|
|
Minimum of Real variables |
|
Maximum of Real variables r1 and r2. |
Mathematical Real constants and functions |
|
|
Target-specific, most-precise representation of Euler’s number ℯ (= 2.71828…). |
|
Sign of |
|
Absolute value of Real variable |
|
Fractional part of Real variable |
|
Square root of |
|
Natural base exponential of |
|
Natural logarithm of x. |
|
Logarithm of |
|
|
|
|
|
|
|
|
Trigonometric Real constants and functions |
|
|
Target-specific, most-precise representation of π (= 3.14159…), |
|
Sine of |
|
Cosine of |
|
Tangent of |
|
Inverse of |
|
Inverse of |
|
Inverse of |
|
Inverse two-argument tangent in the range -π < z ≤ π (angle in the Euclidean plane, given in radians, between the positive x axis and the ray to the point ( |
|
Hyperbolic sine of |
|
Hyperbolic cosine of |
|
Hyperbolic tangent of |
|
|
|
|
|
|
Systems of linear equations |
|
|
Solution |
|
LU decomposition with partial pivoting of square matrix |
|
Solution |
Interpolation in 1D/2D/3D |
|
|
Constant/linear interpolation in 1D with extrapolation. |
|
Constant/linear interpolation in 2D with extrapolation. |
|
Constant/linear interpolation in 3D with extrapolation. |
Precise Definitions
4.2.7. Example Application Scenarios
Modelica-modeled PID-controller
The following example has its origin in a Modelica model for a speed controller — a PID controller with output limitations — of a DC motor. The block diagram of the Modelica model has two input signals wLoadRef
and wMotor
. The input signal wLoadRef
is the desired value of the speed of the motor load whereas wMotor
is the current speed of the motor. The output of the controller is vMotor
— the voltage to be applied to the DC motor.
It follows one possible transformation of this Modelica model into an eFMI GALEC program. The discretization of the dynamic parts of the PID controller is realized by the Explicit Euler method. The respective eFMI GALEC program is:
block PID_Controller
input Real wLoadRef(min = -1.0e5, max = 1.0e5);
input Real wMotor (min = -1.0e5, max = 1.0e5);
output Real vMotor (min = -1.0e7, max = 1.0e7);
// Tunable parameters (can be changed via recalibration):
parameter Real 'limiter.uMax'(min = 1.0, max = 1.0e5);
parameter Real gearRatio(min = 10.0, max = 500.0);
parameter Real Ti(min = 1.0e-7, max = 100.0);
parameter Real Td(min = 1.0e-7, max = 100.0);
parameter Real kd(min = 0.0, max = 1000.0);
parameter Real k(min = 0.0, max = 1000.0);
parameter Real stepSize // Can be local constant (if recalibration is not supported).
(min = 1.0e-10, max = 0.01 /* in physics-simulation tested sampling-range */ );
protected
// Dependent parameters:
parameter Real 'limiter.uMin'(min = -1.0e5, max = -1.0);
// Discrete states:
Real 'PID.I.x';
Real 'PID.D.x';
Real 'previous(feedback.y)';
Boolean firstTick;
public
method Startup
algorithm
// Initialize tunable parameters:
self.'limiter.uMax' := 400.0;
self.gearRatio := 105.0;
self.Ti := 0.1;
self.Td := 0.1;
self.kd := 0.1;
self.k := 10.0;
self.stepSize := 1e-3;
// Initialize dependent parameters:
self.'limiter.uMin' := -self.'limiter.uMax';
// Initialize discrete states:
self.'PID.I.x' := 0.0;
self.'PID.D.x' := 0.0;
self.'previous(feedback.y)' := 0.0;
self.firstTick := true;
// Initialize outputs:
self.vMotor := 0.0;
end Startup;
method Recalibrate
algorithm
// Update dependent parameters:
self.'limiter.uMin' := -self.'limiter.uMax';
end Recalibrate;
/*
Control-cycle function: Called at every clock tick.
*/
method DoStep
protected
Real 'gain.y';
Real 'feedback.y';
Real 'derivative(PID.I.x)';
Real 'derivative(PID.D.x)';
Real 'PID.D.y';
Real 'PID.y';
algorithm
if self.firstTick then
self.firstTick := false;
else
'derivative(PID.I.x)' := self.'previous(feedback.y)' / self.Ti;
'derivative(PID.D.x)' := (self.'previous(feedback.y)' - self.'PID.D.x') / self.Td;
self.'PID.I.x' := self.'PID.I.x' + self.stepSize * 'derivative(PID.I.x)';
self.'PID.D.x' := self.'PID.D.x' + self.stepSize * 'derivative(PID.D.x)';
end if;
'gain.y' := self.gearRatio * self.wLoadRef;
'feedback.y' := 'gain.y' - self.wMotor;
'PID.D.y' := self.kd * ('feedback.y' - self.'PID.D.x') / self.Td;
'PID.y' := self.k * ('PID.D.y' + self.'PID.I.x' + 'feedback.y');
self.vMotor := (
if 'PID.y' > self.'limiter.uMax' then
self.'limiter.uMax'
elseif 'PID.y' < self.'limiter.uMin' then
self.'limiter.uMin'
else
'PID.y'
);
self.'previous(feedback.y)' := 'feedback.y';
end DoStep;
end PID_Controller;
The manifest for the controller, just describing its interface, is:
<?xml version="1.0" encoding="UTF-8"?>
<Manifest
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../schemas/AlgorithmCode/efmiAlgorithmCodeManifest.xsd"
xsdVersion="0.13.0"
kind="AlgorithmCode"
efmiVersion="1.0.0"
id="{1e111db5-90e6-4e17-b2e5-4e215dbbdd49}"
name="PID controller discretized by Explicit Euler method"
version="0.1"
generationDateAndTime="2020-11-10T12:33:22Z"
generationTool="Manual"
license="MIT">
<Files>
<File
name="Controller.alg"
id="FileID_1"
path="./"
needsChecksum="false"
role="Code"/>
</Files>
<Clock id="ID_Clock" variableRefId="ID_7"/>
<BlockMethods fileRefId="FileID_1" writeOutputs="AsSoonAsPossible">
<BlockMethod id="ID_Startup" kind="Startup"/>
<BlockMethod id="ID_Recalibrate" kind="Recalibrate"/>
<BlockMethod id="ID_DoStep" kind="DoStep"/>
</BlockMethods>
<ErrorSignalStatus id="ID_ErrorSignalStatus"/>
<Variables>
<RealVariable
name="'limiter.uMin'"
id="ID_1"
blockCausality="dependentParameter"
start="-400.0"
min="-1.0e5"
max="-1.0"/>
<RealVariable
name="'limiter.uMax'"
id="ID_2"
blockCausality="tunableParameter"
start="400.0"
min="1.0"
max="1.0e5"/>
<RealVariable
name="Ti"
id="ID_3"
blockCausality="tunableParameter"
start="0.1"
min="1.0e-7"
max="100.0"/>
<RealVariable
name="Td"
id="ID_4"
blockCausality="tunableParameter"
start="0.1"
min="1.0e-7"
max="100.0"/>
<RealVariable
name="kd"
id="ID_5"
blockCausality="tunableParameter"
start="0.1"
min="0.0"
max="1000.0"/>
<RealVariable
name="k"
id="ID_6"
blockCausality="tunableParameter"
start="10.0"
min="0.0"
max="1000.0"/>
<RealVariable
name="stepSize"
id="ID_7"
blockCausality="tunableParameter"
start="1e-3"
min="1.0e-10"
max="0.01"/>
<RealVariable
name="gearRatio"
id="ID_8"
blockCausality="tunableParameter"
start="105.0"
min="10.0"
max="500.0"/>
<RealVariable
name="wLoadRef"
id="ID_9"
blockCausality="input"
start="0.0"
min="-1.0e5"
max="1.0e5">
</RealVariable>
<RealVariable
name="wMotor"
id="ID_10"
blockCausality="input"
start="0.0"
min="-1.0e5"
max="1.0e5">
</RealVariable>
<RealVariable
name="vMotor"
id="ID_11"
blockCausality="output"
start="0.0"
min="-1.0e7"
max="1.0e7">
</RealVariable>
<RealVariable
name="'PID.I.x'"
id="ID_12"
blockCausality="state"
start="0.0"/>
<RealVariable
name="'PID.D.x'"
id="ID_13"
blockCausality="state"
start="0.0"/>
<RealVariable
name="'previous(feedback.y)'"
id="ID_14"
blockCausality="state"
start="0.0"/>
<BooleanVariable
name="firstTick"
id="ID_15"
blockCausality="state"
start="true"/>
</Variables>
</Manifest>
Mathematical Example using builtin Functions
The following example implements a linearly implicit second order differential equation system of the form M(x)*x'' = F(x,u), y = g(x) with an invertible matrix M(x) for a state vector x, inputs u and outputs y. The vector functions F and g describe the right hand sides of the dynamical system and the output equation respectively.
The following implementation in eFMI GALEC code is based on a discretization by the Explicit Euler method. Further, there are several expressions in M and F that use builtin functions like sin
, cos
and exp
. Additionally, the builtin function solveLinearEquations
is used to solve the linear system of equations. The respective eFMI GALEC program is:
block LinearEquationSystem
input Real u[4] (min=-1.0e7, max=1.0e7);
output Real y[4];
protected
// Constants:
constant Real pi;
constant Real stepSize;
// Discrete states:
Real x[4];
Real v[4];
Real 'derivative(x)'[4];
Real 'derivative(v)'[4];
public
/*
Startup function: Called once at startup to initialize the
internal memory of the block and return initial outputs.
*/
method Startup
algorithm
// Initialize constants
self.pi := 3.141592653589793;
self.stepSize := 1.0e-2;
// Initialize discrete states:
self.x := {-3.0, 7.0, 19.0, 1.0};
self.v := {0.0, 0.0, 0.0, 0.0};
// Initial values for derivatives:
self.'derivative(x)' := {0.0, 0.0, 0.0, 0.0};
self.'derivative(v)' := {0.0, 0.0, 0.0, 0.0};
// Return initial control-outputs:
self.y := {0.0, 0.0, 0.0, 0.0};
end Startup;
method Recalibrate
algorithm
end Recalibrate;
/*
Control-cycle function: Called at every clock tick.
*/
method DoStep
protected
Real M[4,4];
Real F[4];
algorithm
self.x := self.x + self.stepSize * self.'derivative(x)';
self.v := self.v + self.stepSize * self.'derivative(v)';
self.y := {
sin(self.x[1]) + self.x[3],
-self.x[2],
self.pi * 2.0 * cos(self.x[4] - self.x[2]),
self.x[3] + self.x[1] / self.x[4]
};
// Check for NaN, e.g. if there was no solution of the linear system in the previous call
if isNaN(self.y[1]) or isNaN(self.y[2]) or isNaN(self.y[3]) or isNaN(self.y[4]) then
// Re-initialize the whole system to its start state
self.x := {-3.0, 7.0, 19.0, 1.0};
self.v := {0.0, 0.0, 0.0, 0.0};
self.y := {0.0, 0.0, 0.0, 0.0};
end if;
M := {
{
-sin(self.x[3] + self.x[4]),
self.x[4]^2 - self.x[2]^3,
-4.0 * exp(self.x[3] * self.x[1]),
cos(-self.x[2]) * self.x[3]
},
{
(self.x[2] + 2.0 * self.x[4]) / self.x[1],
-self.x[1],
self.x[1] * self.x[2],
sin(self.x[1] * self.x[2] * self.x[3])
},
{
-self.x[4] + self.x[2] * self.x[1],
6.0 * self.pi * cos(self.x[2]),
-self.x[2],
2.0 * (self.x[1] + sin(self.x[3] * self.pi))
},
{
self.x[1]+cos(self.x[3]),
-2.0*self.x[3]*self.x[4],
-4.0 * self.x[3] * cos(self.x[2]),
self.x[4] - self.x[1] * self.x[2]
}
};
F := {
self.u[1] - self.x[3]^2,
-self.u[4] + self.x[2] * cos(self.x[1]),
-self.u[4] + self.u[2] * self.x[4],
self.u[2] + self.u[3]
};
self.'derivative(v)' := solveLinearEquations(M, F);
self.'derivative(x)' := self.v;
end DoStep;
end LinearEquationSystem;
The manifest summarising the controller’s interface is:
<?xml version="1.0" encoding="UTF-8"?>
<Manifest
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../schemas/AlgorithmCode/efmiAlgorithmCodeManifest.xsd"
efmiVersion="1.0.0"
xsdVersion="0.13.0"
id="{351131cd-1e50-46d0-913a-240451d247c7}"
kind="AlgorithmCode"
name="Dynamic system discretized by Explicit Euler method"
generationDateAndTime="2020-10-15T16:49:20Z"
version="0.4.0"
generationTool="Manual"
license="MIT">
<Files>
<File
name="Controller.alg"
id="FileID_1"
path="./"
needsChecksum="false"
role="Code"/>
</Files>
<Clock id="ID_Clock" variableRefId="ID_2"/>
<BlockMethods fileRefId="FileID_1" writeOutputs="AsSoonAsPossible">
<BlockMethod id="ID_Startup" kind="Startup"/>
<BlockMethod id="ID_Recalibrate" kind="Recalibrate"/>
<BlockMethod id="ID_DoStep" kind="DoStep"/>
</BlockMethods>
<ErrorSignalStatus id="ID_ErrorSignal"/>
<Variables>
<RealVariable
name="pi"
id="ID_1"
blockCausality="constant"
start="3.141592653589793"/>
<RealVariable
name="stepSize"
id="ID_2"
blockCausality="constant"
start="1e-2"/>
<RealVariable
name="u"
id="ID_3"
blockCausality="input"
start="0.0 0.0 0.0 0.0"
min="-1.0e7"
max="1.0e7">
<Dimensions>
<Dimension number="1" size="4"/>
</Dimensions>
</RealVariable>
<RealVariable
name="y"
id="ID_4"
blockCausality="output"
start="0.0 0.0 0.0 0.0">
<Dimensions>
<Dimension number="1" size="4"/>
</Dimensions>
</RealVariable>
<RealVariable
name="v"
id="ID_5"
blockCausality="state"
start="0.0 0.0 0.0 0.0">
<Dimensions>
<Dimension number="1" size="4"/>
</Dimensions>
</RealVariable>
<RealVariable
name="x"
id="ID_6"
blockCausality="state"
start="-3.0 7.0 19.0 1.0">
<Dimensions>
<Dimension number="1" size="4"/>
</Dimensions>
</RealVariable>
<RealVariable
name="'derivative(x)'"
id="ID_7"
blockCausality="state"
start="0.0 0.0 0.0 0.0">
<Dimensions>
<Dimension number="1" size="4"/>
</Dimensions>
</RealVariable>
<RealVariable
name="'derivative(v)'"
id="ID_8"
blockCausality="state"
start="0.0 0.0 0.0 0.0">
<Dimensions>
<Dimension number="1" size="4"/>
</Dimensions>
</RealVariable>
</Variables>
</Manifest>
Vehicle model with implicit integration method
The following example presents a discretized vehicle model. The model equations and parameters are according to Section 6.8 Rollover Avoidance of the book J. Ackermann et al.: Robust Control, Springer 2002 with some further assumptions. The vehicle model is a single track model with roll augmentation. The discretization is realized by a linear implicit Runge-Kutta method of order 1 (Rosenbrock method, linear implicit Euler method) suited for stiff systems. For such methods the input signals have to be differentiated, therefore the derivatives of the original input variables are added as inputs of the discretized model.
The example demonstrates the use of for-loops, vectors and matrices as well as several builtin functions, particularly for solving linear equation systems. The eFMI GALEC program is:
block VehicleModel
input Real u[2](min=-1.0e7, max=1.0e7);
input Real 'derivative(u)'[2](min=-1.0e7, max=1.0e7);
output Real x[8];
// Tunable parameters (can be changed via recalibration):
parameter Real FdF;
parameter Real m;
parameter Real m2;
parameter Real h;
parameter Real lF;
parameter Real lR;
parameter Real g;
parameter Real Jx2;
parameter Real mu;
parameter Real cF;
parameter Real cR;
parameter Real Jz1;
parameter Real Jz2;
parameter Real Jy2;
parameter Real cphi;
parameter Real dphidot;
parameter Real b1;
parameter Real b2;
parameter Real stepSize;
protected
// Dependent parameters:
parameter Real FlV;
parameter Real FzR;
parameter Real FzF;
// Discrete states:
Real q[4];
Real dx[8];
public
/*
Startup function: Called once at startup to initialize the
internal memory of the block and return initial outputs.
*/
method Startup
algorithm
// Initialize tunable parameters
self.FdF := 15.0;
self.m := 14300.0;
self.m2 := 12487.0;
self.h := 1.15;
self.lF := 1.95;
self.lR := 1.54;
self.g := 9.81;
self.Jx2 := 24201.0;
self.mu := 1.0;
self.cF := 582.0e+3;
self.cR := 783.0e3;
self.Jz1 := 3654.0;
self.Jz2 := 34917.0;
self.Jy2 := 3491.7;
self.cphi := 457.0e+3;
self.dphidot := 100.0e3;
self.b1 := 0.2;
self.b2 := 0.1;
self.stepSize := 1.0e-2;
// Initialize dependent parameters
self.FlV := self.FdF;
self.FzR := self.m*self.g*self.lF/(self.lR + self.lF);
self.FzF := self.m*self.g - self.FzR;
// Initialize inputs
// u = {0.0, 0.0};
// 'derivative(u)' = {0.0, 0.0};
// Initialize states and outputs
self.q := {0.0, 0.0, 0.0, 0.0};
self.dx := {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
self.x := {0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0};
end Startup;
/*
Recalibration function: Called to change tunable parameters
during operation.
*/
method Recalibrate
algorithm
// Update dependent parameters:
self.FlV := self.FdF;
self.FzR := self.m*self.g*self.lF/(self.lR + self.lF);
self.FzF := self.m*self.g - self.FzR;
end Recalibrate;
/*
Control-cycle function: Called at every clock tick.
*/
method DoStep
protected
Real sx;
Real sy;
Real psi;
Real phi;
Real vx;
Real vy;
Real r;
Real phidot;
Real delta;
Real FyD;
Real q1;
Real q2;
Real q3;
Real q4;
Real deltadot;
Real FyDdot;
Real FdF;
Real FlV;
Real m;
Real m2;
Real h;
Real lF;
Real lR;
Real g;
Real Jx2;
Real mu;
Real cF;
Real cR;
Real Jz1;
Real Jz2;
Real Jy2;
Real FzR;
Real FzF;
Real cphi;
Real dphidot;
Real b1;
Real b2;
Real G[4,4];
Real rs2[4];
Real dx1[4];
Real help1;
Real help2;
Real help3;
algorithm
for i in 1:8 loop
self.x[i] := self.x[i] + self.dx[i];
end for;
for i in 1:4 loop
self.q[i] := self.dx[4+i]/self.stepSize;
end for;
sx := self.x[1];
sy := self.x[2];
psi := self.x[3];
phi := self.x[4];
vx := self.x[5];
vy := self.x[6];
r := self.x[7];
phidot := self.x[8];
delta := self.u[1];
FyD := self.u[2];
q1 := self.q[1];
q2 := self.q[2];
q3 := self.q[3];
q4 := self.q[4];
deltadot := self.'derivative(u)'[1];
FyDdot := self.'derivative(u)'[2];
FdF := self.FdF;
FlV := self.FlV;
m := self.m;
m2 := self.m2;
h := self.h;
lF := self.lF;
lR := self.lR;
g := self.g;
Jx2 := self.Jx2;
mu := self.mu;
cF := self.cF;
cR := self.cR;
Jz1 := self.Jz1;
Jz2 := self.Jz2;
Jy2 := self.Jy2;
FzR := self.FzR;
FzF := self.FzF;
cphi := self.cphi;
dphidot := self.dphidot;
b1 := self.b1;
b2 := self.b2;
help1 := sqrt(vx^2 + vy^2);
help2 := (vx^2 + vy^2)^1.5;
help3 := h^2*m2 + Jy2 - Jz2;
G[1,1] :=
(
mu*(lF*r*vx + help1*vy)*self.stepSize*cF*sin(delta)
+ help2*m
)
/ (help2*self.stepSize);
G[1,2] :=
-(
mu*(-lF*r*vy + help1*vx)*cF*sin(delta)
+ help2*r*m
)
/ help2;
G[1,3] :=
(
2.0*h*m2*phidot*cos(phi)*self.stepSize*help1
- mu*cF*lF*sin(delta)*self.stepSize
+ h*m2*sin(phi)*help1
- m*vy*self.stepSize*help1
)
/ (self.stepSize*help1);
G[1,4] :=
h*m2*(
-2.0*sin(phi)*phidot*r*self.stepSize
+ cos(phi)*q3*self.stepSize
+ 2.0*r*cos(phi)
);
G[2,1] :=
(
(-cos(delta)*cF*mu*vy - cR*mu*vy + m*r*(vx^2+vy^2))*help1
- r*mu*vx*(cos(delta)*cF*lF - cR*lR)
)
/ help2;
G[2,2] :=
(
(cos(delta)*cF*mu*vx*self.stepSize + cR*mu*vx*self.stepSize + m*(vx^2 + vy^2))*help1
- self.stepSize*r*mu*vy*(cos(delta)*cF*lF - cR*lR)
)
/ (help2*self.stepSize);
G[2,3] :=
(
2.0*h*m2*r*sin(phi)*help1
+ mu*cF*lF*cos(delta)
+ m*vx*help1
- mu*cR*lR
)
/ help1;
G[2,4] :=
m2*(
(-1.0 + (phidot^2 + r^2)*self.stepSize^2)*cos(phi)
+ self.stepSize*sin(phi)*(q4*self.stepSize + 2.0*phidot)
)
* (h/self.stepSize);
G[3,1] :=
(
(
-cos(delta)*cF*lF*mu*vy*self.stepSize
+ h*m2*(vx^2 + vy^2)*sin(phi)
+ cR*lR*mu*vy*self.stepSize
) * help1
- self.stepSize*r*mu*vx*(lF^2*cF*cos(delta) + lR^2*cR)
)
/ (help2*self.stepSize);
G[3,2] :=
-(
(-cos(delta)*cF*lF*mu*vx + h*r*m2*(vx^2 + vy^2)*sin(phi) + cR*lR*mu*vx)*help1
+ vy*r*mu*(lF^2*cF*cos(delta) + lR^2*cR)
)
/ help2;
G[3,3] :=
2.0*(
(
(-0.5*h^2*m2 - 0.5*Jy2 + 0.5*Jz2)*cos(phi)^2
+ phidot*self.stepSize*sin(phi)*help3*cos(phi)
- 0.5*sin(phi)*h*m2*vy*self.stepSize
+ 0.5*h^2*m2
+ 0.5*Jy2
+ 0.5*Jz1
) * help1
+ 0.5*mu*self.stepSize*(lF^2*cF*cos(delta) + lR^2*cR)
)
/ (help1*self.stepSize);
G[3,4] :=
4.0*phidot*self.stepSize*r*help3*cos(phi)^2
+ (2.0*help3*(q3*self.stepSize + r)*sin(phi) - h*self.stepSize*m2*(r*vy - q1))*cos(phi)
- 2.0*phidot*self.stepSize*r*help3;
G[4,1] := -h*m2*r*cos(phi);
G[4,2] := -h*m2*cos(phi) / self.stepSize;
G[4,3] := -2.0*(help3*r*sin(phi) + 0.5*h*m2*vx)*cos(phi);
G[4,4] :=
(
-2.0*self.stepSize^2*r^2*help3*cos(phi)^2
- cos(phi)*g*h*m2*self.stepSize^2
+ self.stepSize^2*h*m2*(r*vx + q2)*sin(phi)
+ (help3*r^2 + cphi)*self.stepSize^2
+ dphidot*self.stepSize
+ h^2*m2
+ Jx2
)
/ self.stepSize;
rs2[1] :=
2.0*(
(
-0.5*self.stepSize*(cF*mu*(delta - atan2(vy, vx))*cos(delta) + sin(delta)*(cF*mu + FlV))*deltadot
+ 0.5*atan2(vy, vx)*sin(delta)*cF*mu
- 0.5*sin(delta)*cF*delta*mu
- 0.5*h*m2*phidot*(q3*self.stepSize + 2.0*r)*cos(phi)
+ 0.5*FlV*cos(delta)
+ r*(sin(phi)*h*m2*phidot^2*self.stepSize + 0.5*m*vy)
) * help1
+ 0.5*cF*lF*mu*r*(deltadot*cos(delta)*self.stepSize + sin(delta))
)
/ help1;
rs2[2] :=
-(
(
(
mu*cF*(delta - atan2(vy, vx))*sin(delta)
- cos(delta)*(cF*mu + FlV)
) * (self.stepSize*deltadot)
- FyDdot*self.stepSize
+ mu*(cos(delta)*cF + cR)*atan2(vy, vx)
- cos(delta)*cF*delta*mu
+ h*m2*(phidot*q4*self.stepSize + phidot^2+r^2)*sin(phi)
+ h*phidot*self.stepSize*m2*(phidot^2 + r^2)*cos(phi)
+ m*r*vx
- FlV*sin(delta)
- FyD
) * help1
- mu*r*(self.stepSize*sin(delta)*deltadot*cF*lF - cos(delta)*cF*lF + cR*lR)
)
/ help1;
rs2[3] :=
-2.0*(
(
0.5*lF*(mu*cF*(delta - atan2(vy, vx))*sin(delta) - cos(delta)*(cF*mu + FlV))*self.stepSize*deltadot
- 0.5*FyDdot*b1*self.stepSize
+ 0.5*mu*(cos(delta)*cF*lF - cR*lR)*atan2(vy, vx)
+ 2.0*r*phidot^2*self.stepSize*help3*cos(phi)^2
+ phidot*(help3*(q3*self.stepSize + r)*sin(phi) + 0.5*h*self.stepSize*m2*(-r*vy + q1))*cos(phi)
- 0.5*sin(phi)*h*m2*r*vy
- 0.5*cos(delta)*cF*delta*lF*mu
- 0.5*FlV*sin(delta)*lF
- r*phidot^2*self.stepSize*help3
- 0.5*b1*FyD
) * help1
- 0.5*r*mu*(deltadot*sin(delta)*cF*lF^2*self.stepSize - lF^2*cF*cos(delta) - lR^2*cR)
)
/ help1;
rs2[4] :=
self.stepSize*b2*FyDdot
+ 2.0*phidot*self.stepSize*r^2*help3*cos(phi)^2
+ (r^2*help3*sin(phi) + h*m2*(g*phidot*self.stepSize + r*vx))*cos(phi)
+ (-phidot*(r*vx+q2)*self.stepSize + g)*h*m2*sin(phi)
- phidot*(help3*r^2 + cphi)*self.stepSize
- cphi*phi
- dphidot*phidot
+ b2*FyD;
dx1 := solveLinearEquations(G, rs2);
for i in 1:4 loop
self.dx[4+i] := dx1[i];
self.dx[i] := self.stepSize*(self.x[4+i]+dx1[i]);
end for;
// Check for NaN, caused by e.g. a failed solution of the linear system
if isNaN(self.x[1]) or isNaN(self.x[2]) or isNaN(self.x[3]) or isNaN(self.x[4]) or
isNaN(self.x[5]) or isNaN(self.x[6]) or isNaN(self.x[7]) or isNaN(self.x[8]) then
self.q := {0.0, 0.0, 0.0, 0.0};
self.dx := {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
self.x := {0.0, 0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 0.0};
end if;
end DoStep;
end VehicleModel;
The resulting manifest is:
<?xml version="1.0" encoding="utf-8"?>
<Manifest efmiVersion="1.0.0"
generationDateAndTime="2020-10-15T16:52:13Z"
generationTool="Manual"
id="{e3eae104-6417-4783-8c05-7c14e6fab8a6}"
kind="AlgorithmCode"
license="MIT"
name="Vehicle model discretized by Linearly implicit Euler method"
version="0.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsdVersion="0.13.0"
xsi:noNamespaceSchemaLocation="../schemas/AlgorithmCode/efmiAlgorithmCodeManifest.xsd">
<Files>
<File
id="FileID_1"
name="Controller.alg"
needsChecksum="false"
path="./"
role="Code" />
</Files>
<Clock id="ID_Clock" variableRefId="ID_1" />
<BlockMethods fileRefId="FileID_1" writeOutputs="AsSoonAsPossible">
<BlockMethod id="ID_Startup" kind="Startup" />
<BlockMethod id="ID_DoStep" kind="DoStep" />
<BlockMethod id="ID_Recalibrate" kind="Recalibrate" />
</BlockMethods>
<ErrorSignalStatus id="ID_ErrorSignal"/>
<Variables>
<RealVariable blockCausality="tunableParameter"
id="ID_1"
name="stepSize"
start="1e-2" />
<RealVariable blockCausality="tunableParameter"
id="ID_2"
name="FdF"
start="15.0" />
<RealVariable blockCausality="dependentParameter"
id="ID_3"
name="FlV"
start="15.0" />
<RealVariable blockCausality="tunableParameter"
id="ID_4"
name="m"
start="14300.0" />
<RealVariable blockCausality="tunableParameter"
id="ID_5"
name="m2"
start="12487.0" />
<RealVariable blockCausality="tunableParameter"
id="ID_6"
name="h"
start="1.15" />
<RealVariable blockCausality="tunableParameter"
id="ID_7"
name="lF"
start="1.95" />
<RealVariable blockCausality="tunableParameter"
id="ID_8"
name="lR"
start="1.54" />
<RealVariable blockCausality="tunableParameter"
id="ID_9"
name="g"
start="9.81" />
<RealVariable blockCausality="tunableParameter"
id="ID_10"
name="Jx2"
start="24201.0" />
<RealVariable blockCausality="tunableParameter"
id="ID_11"
name="mu"
start="1.0" />
<RealVariable blockCausality="tunableParameter"
id="ID_12"
name="cF"
start="582e3" />
<RealVariable blockCausality="tunableParameter"
id="ID_13"
name="cR"
start="783e3" />
<RealVariable blockCausality="tunableParameter"
id="ID_14"
name="Jz1"
start="3654.0" />
<RealVariable blockCausality="tunableParameter"
id="ID_15"
name="Jz2"
start="34917.0" />
<RealVariable blockCausality="tunableParameter"
id="ID_16"
name="Jy2"
start="3491.7" />
<RealVariable blockCausality="dependentParameter"
id="ID_17"
name="FzR"
start="0.0" />
<RealVariable blockCausality="dependentParameter"
id="ID_18"
name="FzF"
start="0.0" />
<RealVariable blockCausality="tunableParameter"
id="ID_19"
name="cphi"
start="457.0e+3" />
<RealVariable blockCausality="tunableParameter"
id="ID_20"
name="dphidot"
start="100.0e3" />
<RealVariable blockCausality="tunableParameter"
id="ID_21"
name="b1"
start="0.2" />
<RealVariable blockCausality="tunableParameter"
id="ID_22"
name="b2"
start="0.1" />
<RealVariable blockCausality="input"
id="ID_23"
name="u"
start="0.0 0.0"
min="-1.0e7"
max="1.0e7">
<Dimensions>
<Dimension number="1"
size="2" />
</Dimensions>
</RealVariable>
<RealVariable blockCausality="input"
id="ID_24"
name="'derivative(u)'"
start="0.0 0.0"
min="-1.0e7"
max="1.0e7">
<Dimensions>
<Dimension number="1"
size="2" />
</Dimensions>
</RealVariable>
<RealVariable blockCausality="output"
id="ID_25"
name="x"
start="0.0 0.0 0.0 0.0 10.0 0.0 0.0 0.0">
<Dimensions>
<Dimension number="1"
size="8" />
</Dimensions>
</RealVariable>
<RealVariable blockCausality="state"
id="ID_26"
name="q"
start="0.0 0.0 0.0 0.0">
<Dimensions>
<Dimension number="1"
size="4" />
</Dimensions>
</RealVariable>
<RealVariable blockCausality="state"
id="ID_27"
name="dx"
start="0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0">
<Dimensions>
<Dimension number="1"
size="8" />
</Dimensions>
</RealVariable>
</Variables>
</Manifest>
5. Production Code Model Representation
5.1. Introduction
A Production Code Model Representation of an eFMU container contains the actual sources that implement the algorithm expressed in Algorithm Code Model Representation of the same eFMU container.
As mentioned before an eFMU container can contain any number of Production Code Model Representations.
The following code parts may be present inside each Production Code Model Representation:
-
Production Code: This section contains the actual Production Code running on the embedded device. In later development steps it shall be compiled and linked to be integrated on the target embedded device.
-
[optional] Simulation Code: This code is used to simulate the target environment of the Production Code. It may provide stub functions for communication with other software functions.
-
[optional] Tool Specific Code: Tool Specific Code may help tools to integrate the Production Code in their (execution) environment.
-
[optional] FMU container: This FMU container may be extracted and copied to the surrounding FMU Data to be consumed by FMI compatible tools directly.
The structure of the Model Representation is organized in a folder structure, but not standardized. Instead, the actual structure of the Model Representations’s content, e.g. code at least as far as interfaces and externally accessible parts are concerned, is formally described in the manifest file of the Model Representation. The Model Representation is "registered" in the "__content.xml" registry of the eFMU container.
The manifest itself references to a manifest of a Algorithm Code Model Representation for more detailed information.
For each different target - the combination of compiler and processor - there exist a dedicated Production Code section inside an eFMU container. A special target is the generic one, where the included C code doesn’t contain target specific parts, e.g. assember code sections or code assuming a certain hardware platform. Such a generic C code is therefore portable, i.e. compilable on an ARM architecture as well as on a i86 architecture. This flexibility allows for including an FMU into the Production Code Model Representation, that uses the generated Production Code and a FMI compatible interface.
An example use case for the FMU container is an early back-to-back test while already using the target datatypes: After modelling an controller, developers can easily check the resulting Production Code using FMI compatible tools. |
A generic target allows for testing and simulating the Production Code in an environment other than the target embedded device, which may require additional software parts to interface with the environment. These software parts can simulate parts of an operating system of the microcontroller, create stubs to represent other software functions that interact with the software-under-test or handle inputs, outputs and the execution.
Testing a Production Code Model Representation in a Processor-in-the-Loop scenario, tools using their own execution frame on the targed board. To support these use-cases this kind of code can be stored as Tool Specific Code inside the Production Code Model Representation. The name of the tool and its version have to be specified in the manifest file referencing the code. |
5.2. Production Code Manifest
The Production Code manifest follows the general guidelines as pertaining to all manifests, including the listing of relevant manifests and files. In addition it describes the content of the "Code Files":
On the top level, the schema consists of the following elements:
Name | Description |
---|---|
|
The attributes of the top-level element are the same for all manifest kinds and are defined in section
Section 2.3.1. |
|
Reference to the manifest of the Algorithm Code on which this Production Code manifest is based on. This element is the same for all manifest kinds and is defined in section Section 2.3.4.3. |
|
List of files referenced in this model representation. This element is the same for all manifest kinds and is defined in section Section 2.3.3. |
|
Defines the details of the production code. For details see Section 5.2.2. |
|
Additional data that a vendor might want to store and that other vendors might ignore. For details see Section 2.3.4.5. |
The Production Code manifest describes the structure of the contained "Production Code". Languages for the producion code include the "C" language and the "C++" language. The manifest will give more detailed information on the exact requirements on the Production Code language to integrate the code into an actual ECU software content.
The Production Code manifest focusses on aspect directly tied to the Production Code itself in particular the technical aspects. Relevant aspect relating to the algorithm or the "logical" concepts are referred to from the Algorithm Code manifest (e.g. whether an object is a state or calibration parameter, input or output etc.). |
The Production Code manifest is an xml file with structured information about the Production Code. It contains two sections:
-
Production code description section: This section contains all information directly pertaining to the code itself, i.e. the "technical realisation".
-
Mapping section: this section contains all information relating to mapping the elements of the technical realistion (aka. the C-code) to the logical elements of the Algorithm Code.
This distinction into logical (as e.g. described in the Algorithm Code) and technical parts is crucial and is shown in one example here.
Example: Suppose a (logical) function f that computes outputs y1 and y2 from inputs x1 and x2 and a state s1 using parameters p1 and p2. This logical function could be implemented in several ways, e.g.:
-
f1 working on global variables only. In this case the (technical) function signature is that of a void void function and the expressions directly access the elements.
void f1() { ... s1 = ... // update of state s1 y1 = ... // y1 expression y2 = ... // y2 expression }
-
f2 that takes the inputs as arguments and returns output y1 as return value and y2 via a pointer. Access to state and parameters is through global variables
float f2(float x1, float x2, float *y2) { ... s1 = ... // update of state s1 *y2 = ... // y2 expression return ...; // y1 expression }
-
f3 that that works like f2 but takes the states as a struct with two elements
… typedef struct { float s; float t; } states;
…
float f3(float x1, float x2, states myStates, float *y2) { … myStates.s = … // update of state s1 *y2 = … // y2 expression return …; // y1 expression }
-
f4: In this example the parameter and the state are coupled in a data structure (e.g. a spring with parameter being the rigidity of the spring and the state being the deflection). As both are not in the same memory (one is in ROM the other in RAM), the one value is referenced per pointer. The C function itselfs takes as input an array with the two pairs.
...
typedef struct {
float *deflection;
float rigidity;
} spring;
....
float f4(float x1, float x2, spring[] springs, float *y2) {
...
springs[0].deflection = .... // update of state s1
*y2 = ... // y2 expression
return ...; // y1 expression
}
As can be easily seen by these example, there is a big difference between the logical variables on which a function operates, and the representation of these in code. As the last two examples show, this can even go so far that the code structure contains elements that do not directly appear in the Algorithm Code.
Wheras the technical description part of the manifest relates solely to the technical (realisation) aspects of the C Code, the mapping section is dedicated to bridge the gap between the two levels of abstraction: the Algorithm Code and the Production Code.
5.2.1. Technical description of Production Code
The technical description part of the Production Code manifest specifies the following aspects of the code:
-
the underlying language including detailed information on the version of the language
-
any restrictions / specification on the target (e.g. HW) for which the code is intended for
-
any restrictions / specification on the compilers to be used included specifics on compiler versions and configuration
-
-
Definition of the type (numeric) type system on the target. This section maps the standardized (eFMI-) types onto the target types available on that specific target. These may depend on the compiler (e.g. some compilers use "int" for 32 bit and "long" for 64 bit, others use "long" for 32 bit and "long long" for 64 bit).
-
Definition of the code itself. The code is thereby grouped in "Modules" which contain source files (for the language "C" normally a module contains a ".c" and a ".h" file).
For each file the content (as far as relevant and accessible) is described. This includes:
-
references ("includes") to other files (defined in the Production Code manifest).
-
defined types in that file (refering to the defined and standardized target types). Usually these are specifically defined names for the type like e.g. "uint8" that are used in the actual Production Code. These defined types also contain definitions for structured types
-
defined macros (if any)
-
defined variables in the file
-
defined functions in the file.
For Production Code Model Representations that contain e.g. AUTOSAR Classic or Adaptive code, there exist additional so-called description files, describing the technical aspects of the code. Those description files must be listed in the Code Container and are the alternative to the above mentioned details in the manifest and must be use instead.
5.2.2. Code Container
The code container groups the actual Production Code Model Representaion content, and gives specification for the following details:
Name | Description |
---|---|
|
Language to be used. Currently,
the following values are possible: |
|
Relevant language standard to be used. |
|
The target platform. Currently, the following values are possible: |
|
Floating point precision of the target platform. Currently,
the following values are possible: |
|
Optional description |
|
Unique identifier, if the production code uses target-speciic code parts, for example
assembler op codes; otherwise the identifier is the default |
|
List of Compiler Options for Production or Binary Code. For more details, see section Section 5.2.2.1. |
|
List of Linker Options for Production or Binary Code. For more details, see section Section 5.2.2.4. |
|
Defines which kind of data type (kind) in the eFMI specification is mapped to a certain platform type. Usually all kinds are listed although they are not used in the production code container. E.g. a kind "Bool" may be mapped to unsigned char in case of C89; and using C99, the kind shall be mapped to _Bool. For each coded type, there exists a unique TargetType in order to abstract from the platform types. For more details, see section Section 5.2.2.7. |
|
List of files in model representation, i.e. source file and/or header file including any information needed to integrate the code in an environment. For more details, see section Section 5.2.3. |
|
List of files in model representation; files containing descriptive content, e.g. AUTOSAR files (.arxml). For more details, see section Section 5.2.4. |
|
Facilitates a quick access to information in the manifest and the associated C files. For more details, see section Section 5.2.5. |
|
Defines how the logical elements (variables, functions etc.) are mapped to the actual data structures and elements of functions and defined variables. For more details, see section Section 5.2.6. |
Compiler Options
Name | Description |
---|---|
|
Directory where compilation should be performed. |
|
Compiler switch, see Section 5.2.2.2. |
|
Preprocessor definition, see Section 5.2.2.2. |
|
Additional include directory, see Section 5.2.2.2. |
|
Reference to option in another manifest file, see Section 5.2.2.3. |
Compiler Option Type
Name | Description |
---|---|
|
Id of option. |
|
Name of option. |
|
Value of option. |
|
Optional description of option. |
|
Definition of option is optional. Possible values: |
Compiler Option Reference
Name | Description |
---|---|
|
Index of the option reference in the list of option references. |
|
Id of option reference. |
|
If of foreign manifest file. |
|
Id of option in foreign manifest file. |
Linker Options
Name | Description |
---|---|
|
The linker switches of type [LinkerOptionType]. |
|
Library of type [LinkerOptionType]. |
|
Additional library directory of type [LinkerOptionType]. |
|
A list of option references, see [OptionReference]. |
Linker Option Type
Name | Description |
---|---|
|
Id of option. |
|
Name of option. |
|
Value of option. |
|
Optional description of option. |
|
Definition of option is optional. Possible values: |
Linker Option Reference
Name | Description |
---|---|
|
Index of the option reference in the list of option references. |
|
Id of option reference. |
|
Id of foreign manifest file. |
|
Id of option in foreign manifest file. |
Target Types
Target types define which kind of data type (kind) in the eFMI specification is mapped to a certain platform type. Usually all kinds are listed although they are not used in the production code container. E.g. a kind "Bool" may be mapped to unsigned char in case of C89; and using C99, the kind shall be mapped to _Bool. For each coded type, there exists a unique TargetType in order to abstract from the platform types.
Name | Description |
---|---|
|
The unique id of the target type. |
|
The kind of the target type. The value must be one of the predefined kinds from the following list:
|
|
The actual Production Code type to be used, e.g. |
Example:
<TargetType id="TT_float64" kind="efmiFloat64" codedType="double"/>
5.2.3. Code Files
The code file section describes the actual content of a (production) code file. It refers to one of the files listed in the "Files" section, so it is clear which file’s content it actually species
Name | Description |
---|---|
|
Unique id. |
|
Type of the file. Allowed values: |
|
Type of the code. Allowed values: |
|
Reference to a file element in this manifest file, see Section 2.3.4.2. |
|
Definition of include files, see Section 5.2.3.1. |
|
Definition of typedefs, see Section 5.2.3.2. |
|
Definition of macros, see Section 5.2.3.2.3. |
|
Definition of variables, see Section 4.1.6. |
|
Definition of functions, see Section 5.2.3.2.5. |
Example:
<CodeFile id="C_1" fileType="ProductionCode" codeType="SourceFile">
<FileReference fileRefId="F_22" kind="code"/>
.....
</CodeFile>
Includes
Includes represent include preprocessor statements. Linker dependencies to certain libraries are part of the linker sections of the BuildInformation.
Name | Description |
---|---|
|
id of the included file. This attribute might be empty if the include is of a library. |
Example:
<Include codeFileRefId="F_1"/>
Typedefs
Typdefs are used to either define structured types, array types or alias types (of predefined types).
Name | Description |
---|---|
|
Unique id of typedef. |
|
name of the type |
|
Alias means renaming of types, e.g. |
|
Declares a type that is a pointer to another type. This type can be any other defined type. |
|
Definition of a struct. Structs in structs are allowed but Dimensions have to be specified at variable definitions only. For details see Section 5.2.3.2.1. |
|
Definition of an enum. For details see Section 5.2.3.2.2. |
The following is an example of a simple alias declaration
Example:
<Typedef name="Float32" id="TD_F32">
<Alias targetTypeRefId="TT_float32" />
</Typedef>
The more complex data structure of function spring of the fourth example would be described by the following snipppet:
<Typedef name="spring" id="TD_spring">
<Components>
<Component id="C_1" name="deflection" typeRefId="TD_F32" pointer="true">
<Component id="C_2" name="rigidity" typeRefId="TD_F32">
<Components>
<Alias targetTypeRefId="TT_float64" />
</Typedef>
Components (struct)
Components
declare a structure and are a list of Component
:
Name | Description |
---|---|
|
Unique id. |
|
Name of the field. Must be unique within one |
|
Reference of the type of the field. |
|
Boolean flag on whether the field is a reference or not (optional field). |
Each field can be an array. This is indicated with the subelement <Dimensions>
that contains a list of <Dimension>
elements, each with the following attributes:
Name | Description |
---|---|
|
The index of the dimension. |
|
The size (number of elements) of that dimension. |
|
Instead of the size a reference to the value macro defining the size. |
Enumeration Items (enum)
<EnumerationItems>
declares an enumeration type with the list of enumeration items.
Each <EnumerationItem>
has the following fields
Name | Description |
---|---|
|
Unique id. |
|
Name of the enumeration literal. This name must be unique within an enumeration definition (`<EnumerationItems>) |
|
Encoded value (this field is optional). |
Macros
Here all macro definitions in the source and header file of the module are listed that are relevant to integrate the code. For example system constants used to define integration relevant vector variables must be part of the list, whereas macros in the code used as guards must not be part of the list.
There are two kind of macros "ValueMacro" and "ParameterizedMacro". Both are contained as children in the "Macros" tag.
A value macros defines a symbol and assigns a value to it. The value must be a number
Name | Description |
---|---|
|
Unique id. |
|
Name of the macro variable. |
|
Concrete value of the macro variable. |
|
Additional data that a vendor might want to store and that other vendors might ignore. For details see Section 2.3.4.5. |
A parameterized macro defines however only the signature of a macro with parameters. Thereby each parameter is given as a "Parameter" element with attrubtes for its name and its position (since xml is not guaranteed to be order-preserving). The positions must be the values 0 … n-1 where n is the number of parameters.
Name | Description |
---|---|
|
Name of the macro argument. |
|
Position of the macro argument. |
The following example shows the declaration of a value and a parametrized macro
<Macros>
<ValueMacro id="VM_1" name="num_Cyl" value="4"/>
<ParameterizedMacro id="PM_1" name="myMax">
<Parameter name="a" number="0">
<Parameter name="b" number="1">
</ParameterizedMacro>
</Macros>
Variables
<Variable>
elements are grouped in the <Variables> element.
Each variable has the following attributes:
Name | Description |
---|---|
|
Unique id of the variable. |
|
Name of the variable. |
|
id of the defined type of the variable. |
|
Optional address. |
|
Optional initial value of that variable that must be consistent which the initial value
in Algorithm Code. Value might be different because of a decision to implement
the Algorithm Code variable in a different datatype, for example
Algorithm Code variable is |
|
Optional minimum value (see |
|
Optional maximum value (see |
|
Optional Boolean value on whether the variable is constant. |
|
Optional Boolean value on whether the variable is volatile. |
|
Optional Boolean value whether the variable is a pointer of the type or a variable of that type. |
|
Optional Boolean value whether the variable is a const pointer. |
|
Optional Boolean value on whether the variable is static. |
Similar like a field in a <Component>
a <Variable>
can also be multidimensional
by adding the <Dimensions>
element. The following example defines a 2x2 array of variables with name "T"
.
<Variable id="V_33" name="T" typeDefRefId="TD_F64" pointer="false" value="0.1" const="false" volatile="true" static="false">
<Dimensions>
<Dimension number="0" size="2">
<Dimension number="1" size="2">
</Dimensions>
</Functions>
Functions
The described functions of (production) code files are grouped in the "Functions" tag. Each function has an "id"
and a "name"
. In addition it has a subelement for the return parameter (if the function is void, the subelement is not present) and a list of "formal parameter". The return parameter (if present) and the formal parameters list.
Example:
<Functions>
<Function id="Func_1" name="doStep">
<FormalParameters>
<FormalParameter id="V_33" name="T" number="0" typeDefRefId="TD_F64">
</FormalParameters>
<Function/>
<Function id="Func_2" name="doStep2">
<ReturnParameter id="Func_2_ret" typeDefRefId="TD_F64" pointer="false">
<Function/>
<Functions/>
5.2.4. Description Files
List of files containing descriptive content, for example AUTOSAR files (.arxml). Those files are the alternative to the detailed code description by e.g. typedefs, variables, etc. Usually all kinds of description files are allowed, but as they are used as alternative to the detailed description, elements that should be mapped to elements in the algorithm code manifest must be uniquely identifyable, e.g. they must have identifiers that are unique within a file, similar to identifiers used in manifests, or reachable by a given path expression.
Technically, a DescriptionFile has a FileReference
pointing to a file in the manifest’s file list and additional optional Properties
as property value list.
5.2.5. Technical Information Lookups
Facilitates a quick access to information in the manifest and the associated C files.
Name | Description |
---|---|
|
List of all typedef statements in C code |
|
List of all global variables and global available access functions |
Both lists consist of elements, DeclaredTypedef
and GlobalAccessableDataElement
respectively, that only have a reference attribute to a certain kind of element.
Attribute of DeclaredTypedef
:
Name | Description |
---|---|
|
Reference to a TypeDef element in the manifest. |
Attribute of GlobalAccessableDataElement
:
Name | Description |
---|---|
|
Reference to a Variable element in the manifest. |
5.2.6. Logical Data
Defines how the logical elements (variables, functions etc.) are mapped to the actual data structures and elements of functions and defined variables.
The description in the code files basically describes only Production Code parts. As shown in the beginning of this section the mapping to the Algorithm Code is sometimes not obvious, for example because variables in the Algorithm Code do only appear as arguments or are may be part of structures or arrays. Therefore we describe this mapping explicitely.
The mapping is given in the element LogicalData
which contains the DataReferences
and the FunctionReferences
.
A DataReference
itself contains the following attributes and elements
to identify the variable in the Production Code and the mapped variable in the Algorithm Code
Name | Description |
---|---|
|
Subelement of type |
|
Reference to a declared global accessible variable in the current manifest. If the referenced variable is of a complex type, the |
|
Reference to a formal parameter of a global accessible function by the |
|
Reference to an item by the |
A FunctionReference
is similar to the DataReferences mapping Algorithm Code functions, mainly the block interface functions, to functions in the Production Code.
Name | Description |
---|---|
|
Subelement of type |
|
Reference to a declared global accessible function in the current manifest by |
|
Reference to an item by the |
5.3. Production Code Language
A Production Code Model Representation includes code files that are modules in terms of the C or C++ programming language.
The C programming language is described in [KR79] and in a destilled version in [CLangWiki]. A similar description of the C++ programming language gives [Str13] or as a destilled version [CPPLangWiki].
For both programming languages, the Motor Industry Software Reliability Association (MISRA) has published a set of guidelines to facilitate code safety, security, portability and reliability in the context of embedded software systems, see [MISRA12], [MISRA08]. In cases where the C code is not hand-coded but generated by a tool different guidelines [MISRA04] shall be fulfilled.
An example is the calling of an algorithm to solve a scalar nonlinear function, where a function pointer and a void pointer for the context is passed. (This is necessary, as the function depends on the internal state of the model.)
int solveOneNonlinearEquation (Real_t (*f_Nonlinear)(Real_t u, void* data), Real_t u_min, Real_t u_max, Real_t tolerance, Real_t *u, void *data)
This could be called from C Code, e.g., by
err = solveOneNonlinearEquation(my_f_Nonlinear, 1.0, 8.0, tol, &u, &mydata);
where the function 'my_f_Nonlinear' is defined by
Real_t f_Nonlinear_3(Real_t u, void *data) { myDataType *mydata = (myDataType*)data; return mydata->p[0] + log(mydata->p[1]*u) - u; }
This is considered safe for the usage for auto-generated code, where the void pointer is passed together with a function pointer to the function that uses this void pointer as one of its arguments.
For individual Production Code sections, compliance with Coding Guidelines like MISRA:2012 is annotated in the manifest xml-File.
Common for both languages is that especially for resource limited embedded systems a number of language features are limited or at least not available. For example:
-
dynamic memory handling
-
only compile-time fixed array sizes
-
functions typically offered by operating system
-
availability of mathematical functions
-
no runtime type information
-
…
Both languages are standardized by the International Organization for Standardization (ISO) and the following table lists an excerpt of different standards and their informal name(s):
Reference |
Name(s) |
ISO/IEC 9899:1990 |
ANSI C, ISO C, C89, C90 |
ISO/IEC 9899/AMD1:1995 |
C95 |
ISO/IEC 9899:1999 |
C99 |
ISO/IEC 9899:2011 |
C11 |
ISO/IEC 9899:2018 |
C18 |
ISO/IEC 14882:1998 |
C++98 |
ISO/IEC 14882:2003 |
C++03 |
ISO/IEC 14882:2011 |
C++11, C++0x |
ISO/IEC 14882:2014 |
C++14, C++1x |
ISO/IEC 14882:2017 |
C++17, C++1z |
A Production Code Model Representation must indicate the actually used language and standard of the modules in the manifest file.
6. Binary Code Model Representation
6.1. Introduction
The Binary Code Model Representation is intended to be a container to exchange software artifacts in binary form. Such binaries can be directly integrated with other embedded software running on an ECU. The main purpose of this format is the protection of intellectual property. Shareholders can exchange a software solution without revealing crucial implementation or algorithm details to the user of a particular solution. Beside the protection of intellectual property, the Binary Code Model Representation also provides protection of integrity of the solution. The software solution cannot be altered except for the intended interface such as calibration parameters. Furthermore the binary representation unitizes separate functionalities into dedicated binary files. These binary files can be used independently in different contexts.
An eFMU container might consist of multiple Binary Model Representations which may originate from the same Production Code Model Represention.
A Binary Code Model Representation consists at least of the following items:
-
Object files or static libraries in Executable and Linking Format (ELF) for the use for embedded devices or dynamic linked libraries for co-simulation purposes in Windows environments
-
Container manifest
Furthermore, it might include a file containing information necessary for calibration, measurement and diagnosis purposes and a linker script that contains the necessary information in order to link the software for a particular target.
6.2. Manifest
Since a binary container is subject to an integration on a particular target ECU, its manifest has to provide any necessary information about
-
the components interface,
-
the compiler and its configuration,
-
the linker and its configuration,
-
the target
Optionally, there might exists
-
information about the run time behavior
-
meta information regarding the source code (e.g. MISRA Compliance, Code Quality reports, etc.)
-
Calibration
The Binary Code manifest is an XML file with structured information about the Binary Model Representation.
Some of the above points are already available in the Production Code Model Representation. Such information (interface, MISRA Compliance) will be referenced by the Binary Code manifest from the Production Code manifest. |
6.2.1. Structure of the Manifest
The Binary Code manifest:
consists of the following elements:
On the top level, the schema consists of the following elements:
Name | Description |
---|---|
|
The attributes of the top-level element are the same for all manifest kinds and are defined in section
Section 2.3.1. |
|
Reference to the manifest of the Production Code on which this Binary Code manifest is based on. This element is the same for all manifest kinds and is defined in section Section 2.3.4.3. |
|
List of files referenced in this model representation. This element is the same for all manifest kinds and is defined in section Section 2.3.3. |
|
Defines the essential content of the actual container. For details see Section 6.2.2. |
|
Additional data that a vendor might want to store and that other vendors might ignore. For details see Section 2.3.4.5. |
The following subsections focus on the BinaryContainer
element which represents the actual Binary Model Representation.
6.2.2. Binary Container
Element BinaryContainer
consists of the following elements:
Name | Description |
---|---|
|
The |
|
The |
|
The |
Each of the above listed elements has to exist exactly once in a BinaryContainer
.
Additionally, the the BinaryContainer
has the following Attributes:
Name | Description |
---|---|
|
This attribute is used by the the generating tool to store its Name and Version. |
BuildConfiguration
Element BuildConfiguration
consists of all information related to the compilation and linking of the model representation:
This element contains exactly one of each of the following elements:
Name | Description |
---|---|
|
This element unambigously describes the compiler that has been used to create the binary artifacts. For details see Section 6.2.2.2. |
|
This element unambigously describes the linker that has been used to create the binary artifacts. For details see Section 6.2.2.3. |
|
This element stores all possible compiler settings used to create any binary element in the container. For details see Section 6.2.2.4. |
|
This element refers to a |
|
This element describes the relevant linker option for the above linker that has been used to create the binary object. For details see [definition-of-linker-option-set]. |
|
This element describes the target platform, the binary has been compiled for. For details see [definition-of-compile-target]. |
It is possible that a Binary Code Model Representation needs to be combined with some source from the Simulation Code, Tool-specific code of the Production Code model or even from external generators in order to analyze, integrate or test the model. In such cases additional sources need to be compiled and linked together. To support such a use case, the BuildConfiguration of a Binary Model Representation needs to provide all required information to be able to compile and link additional sources with the binary artifacts.
|
Compiler
In order to integrate the object code, it is required to have all relevant information about the compile process of a binary specified. Hence, the compiler is to be specified in the manifest as follows:
All attributes are mandatory and are defined as follows:
Name | Description |
---|---|
|
A unique |
|
The name of the Company/Vendor that has created or issued the compiler. |
|
A unique, unambiguous name of the compiler or compiler suite. |
|
The specific version of the above compiler that has been used to create the binary. |
|
The name of the actual executable of the compiler (suite). |
The attributes vendor
, name
and version
must clearly identify a particular compiler.
Furthermore, it should be possible to use the value executableName
together with a matching CompilerOptionSet
to automatically compile a source file.
The following example depicts a compiler configuration for a target compiler for the TriCore processor archtecture. |
<Compiler id="ID_1000001" vendor="Altium"
name="TASKING VX-toolset for TriCore: C compiler" version="v4.2r2" executableName="ctc"/>
Linker
Similar to the definition of the compiler infrastructure and options, the linker and link options have to be declared to be known to the integration engineer.
All attributes are mandatory and defined as follows:
Name | Description |
---|---|
|
The name of the Company/Vendor that have created or issued the linker. |
|
Unique, unambiguous name of the linker . |
|
The specific version of the above linker that have been used to create the binary. |
|
The name of the actual executable of the linker (suite). |
The attributes vendor
, name
and version
must clearly identify a particular linker.
Furthermore, it should be possible to use the value executableName
together with the below defined LinkerOptionSet
to automatically link object files together.
The following example depicts an linker configuration for the TriCore processor architecture. |
<Linker id="ID_1000002" vendor="Altium" name="TASKING VX-toolset for TriCore: object linker" version="v4.2r2" executableName="ltc"/>
CompilerOptionSets
The CompilerOptionSets
contains one or more CompilerOptionSet
which defines settings and switches used to create at least one of the contained binary artifacts.
Name | Description |
---|---|
|
The unique identifier of the the |
|
A reference to a configured compiler for the Compilers Section. |
|
List of compiler options for Production or Binary Code, see [CompilerOptions] |
Name | Description |
---|---|
|
Directory where compilation should be performed. |
|
The compiler switches of type [CompilerOptionType]. |
|
Preprocessor definitions of type [CompilerOptionType]. |
|
Additional include directory of type [CompilerOptionType]. |
|
A list of option references, see [CompilerOptionReference]. |
Name | Description |
---|---|
|
Index of the compiler option in the list of options (first compiler option = 1, second compiler option = 2, etc). The indices of the choice elements of each 'CompilerOptions' must be consecutive, unique and one element must have index 1. |
|
Unique id of compiler option. |
|
Name of option. |
|
Optional value of option. |
|
Optional description of option. |
|
Optional Boolean with default |
Name | Description |
---|---|
|
Index of the compiler option in the list of options (first compiler option = 1, second compiler option = 2, etc). The indices of the choice elements of each 'CompilerOptions' must be consecutive, unique and one element must have index 1. |
|
Unique id of option reference. |
|
Reference to another manifest file of type ForeignReference. For details see Section 2.3.4.3. |
The following example depicts some of the options that have to be provided in order to compile code for the Infineon Tricore TC27x family. Most options are special to this compiler family. |
<CompilerOptionSets>
<CompilerOptionSet id="ID_1001" compilerRefId="ID_1000001">
<CompilerOptions>
<CompilerSwitch>
<id>ID_100010</id>
<name>--iso</name>
<value>90</value>
</CompilerSwitch>
<CompilerSwitch>
<id>ID_100011</id>
<name>--align</name>
<value>4</value>
</CompilerSwitch>
<CompilerSwitch>
<id>ID_100012</id>
<name>--optimize</name>
<value>3</value>
</CompilerSwitch>
<CompilerSwitch>
<id>ID_100013</id>
<name>--tradeoff</name>
<value>4</value>
</CompilerSwitch>
<CompilerSwitch>
<id>ID_100014</id>
<name>--source</name>
</CompilerSwitch>
<CompilerSwitch>
<id>ID_100015</id>
<name>--error-file</name>
</CompilerSwitch>
<CompilerSwitch>
<id>ID_100016</id>
<name>--rename-sections=sect</name>
</CompilerSwitch>
<CompilerSwitch>
<id>ID_100017</id>
<name>--core</name>
<value>tc1.6.x>
</CompilerSwitch>
<CompilerSwitch>
<id>ID_100018</id>
<name>-Hsfr/regtc27x.sfr</name>
</CompilerSwitch>
<CompilerSwitch>
<id>ID_100019</id>
<name>--default-near-size</name>
<value>0</value>
</CompilerSwitch>
<CompilerOptionSets>
Default Compiler Options
While each module might have its own compiler options referenced from the CompilerOptionsSets
of the BinaryContainer
, a default option set for the container can be defined.
The default compiler options are used in any case where no other CompilerOptionsSet
is provided.
The DefaultCompilerOptions
are specified as follows:
Name | Description |
---|---|
|
Reference to a previously defined |
The following example depicts an default option set that refers to the CompilerOptionSet defined in the parent BinaryContainer element.
|
<DefaultCompilerOptions compilerOptionsRefId="ID_1001" />
LinkerOptionSet
The LinkerOptionSet
contains one LinkerOptions
which defines linker settings and switches.
Name | Description |
---|---|
|
List of linker options for Production or Binary Code, see [LinkerOptions] |
|
The linker script is referenced with a |
Name | Description |
---|---|
|
The linker switches of type [LinkerOptionType]. |
|
Library of type [LinkerOptionType]. |
|
Additional library directory of type [LinkerOptionType]. |
|
A list of option references, see [LinkerOptionReference]. |
Name | Description |
---|---|
|
Index of the option in the linker command line. |
|
Unique id of linker option. |
|
Name of option. |
|
Optional value of option. |
|
Optional description of option. |
|
Optional Boolean with default |
Name | Description |
---|---|
|
Index of the option in the linker command line. |
|
Unique id of option reference. |
|
Reference to another manifest file of type ForeignReference. For details see Section 2.3.4.3. |
The following example depicts some of the options that have to be provided in order to compile code for the Infineon Tricore TC27x family. Most options are special to this linker family. |
<LinkerOptionSet>
<LinkerOptions>
<LinkerSwitch>
<id>ID_100010</id>
<name>output</name>
<value>dummy.elf:ELF</value>
</LinkerSwitch>
<LinkerSwitch>
<id>ID_100011</id>
<name>no-warnings</name>
</LinkerSwitch>
<LinkerSwitch>
<id>ID_100012</id>
<name>incremental</name>
</LinkerSwitch>
<LinkerSwitch>
<id>ID_100013</id>
<name>lsl-file</name>
<value>TC277.lsl</value>
</LinkerSwitch>
<LinkerSwitch>
<id>ID_100014</id>
<name>map-file</name>
<value>mapfile.map</value>
</LinkerSwitch>
<LinkerOptions>
<FileReference fileRefId="ID_999915" kind="LinkerScript" />
</LinkerOptionSet>
Target
In order to decide whether a target ECU is (technically) suitable for a particular binary with respect to target optimization and assumptions done during Production Code generation regarding hardware, the manifest has to specify the following items:
To define the target ECU the binary representation is compiled for, this section defines the following attributes:
Name | Description |
---|---|
|
The manufacturer of the the target platform/processor. |
|
The name of the architecture. |
|
The exact version of processor used in the architecture. |
|
A unique identifier for the instruction set used by the chip. |
|
Describes whether the target uses Big-Endian or Little-Endian byte order. |
|
Declares the bit width of the registers of the chip. |
|
Declares the bit width of a memory address in the target. |
The following example depicts the target information needed for a TC277 Processor within a TriCore embedded target. |
<CompileTarget id="ID_100001" vendor="Infineon" targetName="TriCore" chipVersion="TC277 C-Step" instructionSetArchitecture="TC1.6E" endianess="LITTLE" registerWidth="32" addressWidth="32"/>
6.2.3. Modules
The Modules
section lists and describes all relevant binaries contained in the Binary Model Representation. Furthermore, it lists all source code references to the Production Code container that are provided with the binary files.
The Modules
section consist of a list of one or more BinaryModule
items.
A BinaryModule
describes a binary object in the Binary Code Model Representation.
It has the following attributes:
Name | Description |
---|---|
|
A unique identifier for further referencing. |
|
The creating tool or person. |
|
The date, the particular binary moduel has been created. |
|
A reference to the |
A BinaryModule
contains one ObjectFile
element and zero or more SourceFileReference
:
Name | Description |
---|---|
|
The actual binary object in the container. There can be only one object file per Binary module. |
|
Each element refers to a code file in production Code manifest. |
SourceFileReference elements refer to possibly required CodeFile elements from the Production Code Model.
Those files are not part of the object file but might be necessary for further processing steps, e.g., a PiL simulation of th object file.
|
The SourceFileReference
element has the following attributes:
Name | Description |
---|---|
|
A unique identifier for further referencing. |
|
Reference to the code Files in the Production Code manifest via a |
|
If a |
Each ObjectFile
has the following attributes:
Name | Description |
---|---|
|
A unique identifier for further referencing. |
Additionally, it consists of the following elements:
Name | Description |
---|---|
|
Reference to the actual binary object file.
The |
|
The |
The following example shows a snippet for a very simple model. It consists of one non-executable object file that have been generated from two ("Production Code") source files. |
<ForeignFile id="ID_999920">
<ForeignReference foreignRefId="ID_9" manifestReferenceRefId="ID_0000001" />
</ForeignFile>
<ForeignFile id="ID_999921">
<ForeignReference foreignRefId="ID_10" manifestReferenceRefId="ID_0000001" />
</ForeignFile>
<ForeignFile id="ID_999922">
<ForeignReference foreignRefId="ID_5" manifestReferenceRefId="ID_0000001"/>
</ForeignFile>
<ForeignFile id="ID_999923">
<ForeignReference foreignRefId="ID_1" manifestReferenceRefId="ID_0000001" />
</ForeignFile>
<ForeignFile id="ID_999924">
<ForeignReference foreignRefId="ID_3" manifestReferenceRefId="ID_0000001" />
</ForeignFile>
[...]
<Modules>
<BinaryModule id="ID_4" creator="JDoe" creationDate="2018-08-09">
<ObjectFile id="ID_10">
<FileReference fileRefId="ID_01" kind="RelocatableObjectFile" />
<SourceFileReference id="ID_02" fileRefId="ID_999920" />
<SourceFileReference id="ID_03" fileRefId="ID_999921" />
</ObjectFile>
<SourceFileReference id="ID_5"fileRefId="ID_999922" />
<SourceFileReference id="ID_1" compilerOptionSetRefId="ID_46" fileRefId="ID_999923" />
<SourceFileReference id="ID_3" compilerOptionSetRefId="ID_46" fileRefId="ID_999924" />
</BinaryModule>
</Modules>
6.2.4. Binary Container Info (optional)
The previously described elements of the manifest for the Binary Code Model Representation are mandatory. However, there is also information that might not be necessary to describe a binary but very helpful in the actual use cases for the Binary Code Model Representation such as integration or validation.
To store and provide this information, the manifest contains the BinaryContainerInfo
section.
A BinaryContainerInfo
element might contain a description for each of the following topics
-
mapping information (memory, registers, etc.)
-
run time behavior
-
calibration information
-
measurement information
-
information about the diagnosis interface
The BinaryContainerInfo
element is defined as follows:
It contains the following elements:
Name | Description |
---|---|
|
Information regarding run time behavior of the different functions provided by the Binary Code model representation. |
|
In addition to the run time information, it is also possible to provide reference to files that give further information regarding the above mentioned topics. The kind of the Possible kinds are: MapFile, CalibrationInformationFile, MeasurementInformationFile, DiagnosisInformationFile, ValidationAndVerificationFile, ComplianceInformationFile, LicenseFile, ConfigurationFile. |
Mapping Information
In order to provide the integration engineer with additional information about a binary file that has already has been linked, a map file can be specified in the MapFileReference
element.
The following example shows, how a map file can be provided using the combination of the File element declared for the Manifest and the actual FileReference with the kind="MapFile" .
|
<File id="ID_999913" path="/objects/" name="SpeedController.map" role="other" needsChecksum="true"
checksum="A43C0994FAD1247988C2AA8A90CCA2E241CF5687" />
[...]
<BinaryContainerInfo>
<FileReference fileRefId="ID_999913" kind="MapFile" />
</BinaryContainerInfo>
The map file can be used to easily inspect information about the memory mapping and, memory usage. Furthermore general information about estimated stack size and the overall link process can be provided here. |
Run Time Behavior
In order to integrate a function defined in an eFMI into a binary for the target ECU, it is required to have information about the run time behavior to decide whether there are enough resources available in order to coexist with additional functions or tasks running on the same ECU.
This information might help the integration engineer to identify possible bottlenecks before he starts the actual integration. |
Hence, the manifest can specify RunTimeComplianceInformation
as additional, optional information.
If RunTimeComplianceInformation
is provided, it can specify the run time behavior for one or more functions as follows:
It consists of one ForeignFunctionReference
that refers to the function in the manifest of the Production Code model representation.
The information about the run time behavior is described by the following attributes:
Name | Description |
---|---|
|
A unique identifier for further referencing. |
|
The maximum time consumed by the function in the worst case. |
|
The maximum stack size required by the function in the worst cas. |
|
The maximum memory consumed by the function in the worst case. |
Note that valid units have to be used for each attribute by the author.
The following example shows how the RunTimeComplianceInformation can be defined for some function.
|
<BinaryContainerInfo>
<RunTimeComplianceInformation>
<RunTimeCompliance id="ID_100301" wcExecTime="8.4ms" wcStackSize="70kb" wcMemSize="840kb">
<ForeignFunctionReference foreignRefId="ID_41" manifestReferenceRefId="ID_0000001" />
</RunTimeCompliance>
</RunTimeComplianceInformation>
</BinaryContainerInfo>
Calibration
In order to be able to calibrate the binary object provided by the Binary Code Model Representation with common, widely used calibration tools, the manifest might specify one or more files containing calibration information.
Calibration information is given using FileReference
elements with the kind="CalibrationInformationFile"
.
The following code snippet shows how a calibration file can be provided. |
<File id="ID_999912" path="/" name="myFunction.a2l" role="other" checksum="0DC09613F414FFCE10865AF3AD3EC31D3ED61EA8" needsChecksum="true" />
[...]
<BinaryContainerInfo>
<FileReference fileRefId="ID_999912" kind="CalibrationInformationFile" />
</BinaryContainerInfo>
An incomplete and optional A2L file provides the symbols used for calibration purposes. When the integrator performs the final linking, the memory addresses of all A2L files of the used software functions are updated. The resulting A2L files can be used by calibration tools to dynamically change parameters for example. |
Measurement
In order to measure internal values of the controller software during the testing and validation phase, the manifest might specify one or more file containing measurement information.
Measurement information is given using FileReference
elements with the kind="MeasurmentInformationFile"
.
The following code snippet shows how a measurement information file can be provided. Note that in this example, in case of an A2L-File, the same file might be used for calibration and measurement. |
<File id="ID_999912" path="/" name="myFunction.a2l" role="other" checksum="0DC09613F414FFCE10865AF3AD3EC31D3ED61EA8" needsChecksum="true" />
[...]
<BinaryContainerInfo>
<FileReference fileRefId="ID_999912" kind="MeasurmentInformationFile" />
</BinaryContainerInfo>
Diagnosis
ECU software often provides some subroutines for diagnosis that is used for testing and maintenance. Hence, the manifest of a Binary Model representation can contain one or more files that provide information for diagnosis tools.
Diagnosis information is given using FileReference
elements with the kind="DiagnosisInformationFile"
.
The following code snippet shows how a diagnosis information file can be provided. |
<File id="ID_999914" path="/" name="myFunction.cdd" role="other" checksum="E7A58CD816076EE26DE1D6BF2F13630000675FB2" needsChecksum="true" />
[...]
<BinaryContainerInfo>
<FileReference fileRefId="ID_999914" kind="DiagnosisInformationFile" />
</BinaryContainerInfo>
Compliance
Since the main intention of the Binary Code container is the protection of intellectual property, the source code usually cannot be checked according to compliance to relevant standards. However, since this information might be of interest for the integrating company, an eFMI binary container shall have an optional section to define one or more files describing the components compliance.
Diagnosis information is provided using FileReference
elements with the kind="ComplianceInformationFile"
.
The following code snippet shows how a compliance information file can be provided. |
<File id="ID_999910" path="/doc/" name="MISRA.doc" role="other" checksum="27D8D7BB69E1D7E98C7A278C5A48199CE7B65399" needsChecksum="true" />
[...]
<BinaryContainerInfo>
<FileReference fileRefId="ID_999910" kind="ComplianceInformationFile" />
</BinaryContainerInfo>
A FileReference can also point to a ForeignFile element and, hence, to an arbitrary file in the eFMU container. This means it can also point to a compliance information file from Production Code container.
|
Note that the eFMI standard does not define how the integrity of the compliance information can be ensured. It is up to the software provider and the integrating company to ensure the validity and integrity of this compliance information. |
License Information
In case that any third party licenses have to be shipped with the binary or to provide license information is provided using FileReference
elements with the kind="LicenseFile"
.
The following code snippet shows how a licenese file can be provided. |
<File id="ID_999911" path="/license/" name="BSD.TXT" role="other" checksum="A7549D084CFD2F9C6DEFA940B9BD5DA402B8341D" needsChecksum="true" />
[...]
<BinaryContainerInfo>
<FileReference fileRefId="ID_999910" kind="LicenseFile" />
</BinaryContainerInfo>
Validation & Verification
For Verification and Validation, additional files can be provide using one or more FileReference
elements with the kind="ValidationAndVerificationFile"
.
The following code snippet shows how some simulation results (e.g., ASAM MDF format) from a use case for back to back testing as well as some description of equivalence classes (e.g., properitary XML format) can be specified for th container. |
<File id="ID_999920" path="/v_n_v/" name="scenario1.mdf" role="other" checksum="DB1A8489D88604A5C896BAB2B35631314B257036" needsChecksum="true" />
<File id="ID_999921" path="/v_n_v/" name="equivalenceclasses.xml" role="other" checksum="F61E2D36002DD140653334E4871DEBE6EE3B721A" needsChecksum="true" />
[...]
<BinaryContainerInfo>
<FileReference fileRefId="ID_999910" kind="ValidationAndVerificationFile" />
</BinaryContainerInfo>
Configuration of Runtime
Certain binary files require additional information on runtime. The Binary Code container provides the possibility to link such information via FileReference
elements with the kind="ConfigurationFile"
.
The following code snippet shows how a SOME/IP stack configuration for Adaptive AUTOSAR application is referenced. |
<File id="ID_999910" path="/adaptive/" name="someip.json" role="other" checksum="DB1A8489D88604A5C896BAB2B35631314B257036" needsChecksum="true" />
[...]
<BinaryContainerInfo>
<FileReference fileRefId="ID_999910" kind="ConfigurationFile" />
</BinaryContainerInfo>
6.3. Binary Format
The Binary Code Model Representation contains object files and libraries in binary format.
For deployment on a target architecture the object file or library must be provided as a binary file ELF format [ELFLinux].
Hence, an ELF file should be be target specific (e.g., for a specific ECU) and, optionally, may be executable. Executable ELF files will be used in PiL Simulation and can contain dedicated frame code. PiL-simulation tools may also create their own harness for PiL simulation. Non-executable ELF files (relocatable ELF) can be used for the integration on the embedded target. |
For Windows-based co-simulation a Binary Code Model Representation might also contain Windows-compatible object files or dynamic link libraries [DLLWin].
For the (co-)simulation use case the binary artifacts support multiple use cases. On the one hand, it may be a DLL, shared library or object file for general purpose code for a general purpose platform (e.g., Windows or Linux) that can be used in a Software-in-the-Loop simulation. |
Additionally, the Binary Code Model Representation can refer to the following Production Code Model Represention items:
-
Simulation Code that might be necessary/used for a standalone SiL or PiL simulation of the eFMU.
-
Tool specific code that might be required to use simulation features of a particular tool.
An example for the tool specific code might be a TargetLink S-Function frame used for a SiL Simulation or an TargetLink TSM-Frame used for PiL simulation. Another example migth be a minimal stub for debugging purposes on the target architecture. |
Beside the actual binary format the Binary Code Model Representation might contain also files including information for calibration, measurement and diagnosis purposes.
An example format for the description of calibration, measurement and diagnosis is the ASAM A2L format. This might be an incomplete A2L since the absolute memory addresses will be updated after the final link process is completed. |
An eFMI Binary Model Represention might make use of service functions which do not necessarily have to be contained in the binary files. Especially for the use case of ECU integration these service functions might be provided by the ECU environment.
[] Tool Interface Standard (TIS) Executable and Linking Format (ELF) Specification. http://refspecs.linuxfoundation.org/elf/elf.pdf, last visited 2019-03-28.
[] Dynamic-Link Libraries. https://docs.microsoft.com/en-us/windows/desktop/Dlls/dynamic-link-libraries, last visited 2019-03-29.
7. Acronyms
Name | Description |
---|---|
AA |
Adaptive AUTOSAR Application |
AlgC |
Algorithm Code |
AlgCL |
Algorithm Code Language |
ARXML |
Classic AUTOSAR interface description file |
AST |
Abstract Syntax Tree |
Bin Code |
Binary Code |
DAE |
Differential Algebraic Equation system |
ECU |
Embedded Control Unit |
eFMI |
FMI for embedded systems |
eFMU |
FMU for embedded systems |
ELF |
Executable and Linking Format |
EqC |
Equation Code |
EqCL |
Equation Code Language |
FFT |
Fast Fourier Transform |
FMI |
Functional Mock-Up interface |
FMI-CS |
FMI for Co-Simulation |
FMU |
Functional Mock-Up unit |
GPL |
GNU General Public License |
LPV |
Linear Parameter-Varying (control / controller) |
LTI |
Linear Time-Invariant |
LTV |
Linear Time-Varying |
ML |
Machine Learning |
MPC |
Model Predictive Control |
NMPC |
Nonlinear Model Predictive Control |
NN |
Neural Network |
ODE |
Ordinary Differential Equations |
PID |
Proportional-Integral-Derivative (control / controller) |
PiL |
Processor-in-the-Loop |
Prod Code |
Production Code |
SiL |
Software-in-the-Loop |
SOA |
Service-oriented Architecture |
SW |
Software |
SWC |
Classic AUTOSAR Software Component |
V&V |
Validation & Verification |
8. Glossary
-
Calibration Parameter - Value equals the start value and can be changed anytime during evaluation of the system by an external source [Req_4.1.09, Req_5.1.13].
-
Calibration Variables - Constant for all execution steps, but changeable by eeprom-update [Req_6.2.05].
-
Code - Formal specification of the model behavior.
-
Production Code - Code intended for the execution on an embedded system.
-
Target Specific Code - Production Code with specific instructions for a certain target.
-
-
ECU software content - Pre-existing software into which the Production Code has to be integrated.
-
eFMU - Container of model representations and other artefacts according to the eFMI standard.
-
Manifest - Meta information in an extendable form describing an associated artefact.
-
eFMU Manifest - Manifest describing the available model representations of the eFMU container and how to get access to them, plus other general meta information.
-
Code Manifest - Manifest describing the model interface of the associated code and providing additional meta information on how to access and utilize the code.
-
-
Model Representation - Compound of Code + Code Manifest representing the model in one particular standardized form.
-
Parameter - Value equals the start value and can be changed only before initialization of the system.
-
State Machine - A (finite) state machine is used to model a system fluctuating between a fixed number of states. Transitions rules between one state to another are defined through entry and exit actions.
-
State-Space Representation - A mathematical model describing the dynamics of a system with a set of first order differential equations. Inputs, outputs and internal state variables are related by A, B, C, D matrices.
-
System constants - Values that are constant for a specific configuration of a software system under test (a specific variant of software and hardware components), but might be changed if the component is used for a slightly different configuration (e.g. number of battery cells available).
-
Target - The intended productive execution environment of the software function that is encapsulated in the eFMU. The eFMU target is characterized by the controller hardware (processor, …) and software (compiler, runtime environment, software architecture).
9. Tool Support
This eFMI version was evaluated with prototypes of the following tools (alphabetical list):
Tool | Vendor | eFMI support |
---|---|---|
AUTOSAR Builder |
Dassault Systèmes |
Generation of Adaptive AUTOSAR from eFMI Production and eFMI Binary Code |
Astrée |
AbsInt Angewandte Informatik GmbH |
Verification of eFMI Production Code |
CSD |
Siemens NV |
Test of eFMI Production Code with eFMI Behavioral Model; integration in existing code and verification of code |
Dymola |
Dassault Systèmes |
Generation of eFMI Algorithm Code and eFMI Behavioral Model (reference results) from Modelica model |
ESP |
Dassault Systèmes |
Generation of eFMI Production Code from eFMI Algorithm Code; Generation of eFMI Binary Code from eFMI Production Code |
Simcenter Amesim |
Siemens Digital Industries Software |
Generation of eFMI Algorithm Code from neural network approximation of Amesim model |
SCODE CONGRA |
ETAS GmbH |
Generation of eFMI Production Code from eFMI Algorithm Code; test of eFMI Production Code with eFMI Behavioral Model |
SimulationX |
ESI ITI GmbH |
Generation of eFMI Algorithm Code from Modelica model |
TargetLink |
dSPACE GmbH |
Generation of eFMI Production Code from eFMI Algorithm Code; test of eFMI Production Code with eFMI Behavioral Model |
TPT |
PikeTec GmbH |
Test of eFMI Production Code with eFMI Behavioral Model |
Literature
[] Blochwitz T., Otter M., Arnold M., Bausch C., Clauß C., Elmqvist H., Junghanns A., Mauss J., Monteiro M., Neidhold T., Neumerkel D., Olsson H., Peetz J.-V., Wolf S. (2011): The Functional Mockup Interface for Tool independent Exchange of Simulation Models. 8th International Modelica Conference, Dresden 2011. http://www.ep.liu.se/ecp/063/013/ecp11063013.pdf
[] Blochwitz T., Otter M., Akesson J., Arnold M., Clauß C., Elmqvist H., Friedrich M., Junghanns A., Mauss J,, Neumerkel D., Olsson H., Viel A. (2012): Functional Mockup Interface 2.0: The Standard for Tool independent Exchange of Simulation Models. 9th International Modelica Conference, Munich, 2012. http://www.ep.liu.se/ecp/076/017/ecp12076017.pdf
[] The C Programming Language. https://en.wikipedia.org/wiki/C_(programming_language), last visited 2019-02-06.
[] C++ Programming Language. https://en.wikipedia.org/wiki/C%2B%2B, last visited 2019-02-06.
[] Dynamic-Link Libraries. https://docs.microsoft.com/en-us/windows/desktop/Dlls/dynamic-link-libraries, last visited 2019-03-29.
[] Tool Interface Standard (TIS) Executable and Linking Format (ELF) Specification. http://refspecs.linuxfoundation.org/elf/elf.pdf, last visited 2019-03-28.
[] Kernighan Brian W., Ritchie Dennis M. (1978): The C Programming Language (1st ed.), Englewood Cliffs, NJ: Prentice Hall. ISBN 0-13-110163-3.
[] MISRA C:2012: Guidelines for the use of the C language in critical systems. ISBN 978-1-906400-10-1, MIRA Limited, Nuneaton, March 2013
[] MISRA C++:2008: Guidelines for the use of the C++ language in critical systems. ISBN 978-906400-04-0, MIRA Limited, Nuneaton, March 2013
[] MISRA AC AGC: Guidelines for the application of MISRA-C:2004 in the context of automatic code generation. ISBN ISBN 978-906400-02-6, MIRA Limited, Nuneaton, March 2004
[] Secure Hash Algorithm. https://en.wikipedia.org/wiki/Secure_Hash_Algorithms, last visited 2019-02-08.
Appendix A: eFMI Revision History
Version | Date | Release Status | Notes |
---|---|---|---|
0.0.1 |
April 01, 2019 |
EMPHYSIS internal |
Initial sketch. |
0.6.0 |
Aug. 04, 2020 |
EMPHYSIS internal |
Incomplete draft (for tool development). |
1.0.0-alpha.1 |
Nov. 12, 2020 |
EMPHYSIS internal + shared with FMI group |
Draft of specification. |
1.0.0-alpha.2 |
Jan. 26, 2021 |
EMPHYSIS internal + shared with FMI group |
Status before Equation Code Model representation was moved to appendix |
1.0.0-alpha.3 |
Jan. 27, 2021 |
Publicly available |
Equation Code Model representation moved to appendix. |
1.0.0-alpha.4 |
Feb. 22, 2021 |
Publicly available |
Remaining Equation Code references removed. |
Version 1.0.0
Contributors of Specification
The eFMI specification was developed within the ITEA EMPHYSIS project (https://itea3.org/project/emphysis.html) that was initiated and organized by Oliver Lenord, Christian Bertsch (Robert Bosch GmbH), Pacôme Magnin (Siemens) and Martin Otter (DLR-SR).
The development of the eFMI specification was headed and managed by Oliver Lenord (Robert Bosch GmbH). The essential part of the design of this version was performed by the following core development groups that closely worked together (alphabetical listings in the respective subgroups) and that utilized feedback and input from Benchmark Test Cases, Tool Assessment, as well as Demonstrators:
-
Behavorial Model
Yuri Durodié (Siemens NV)
Andreas Pfeiffer (DLR-SR)
Robert Reicherdt (PikeTec) -
Rudimentary Equation Code
Andreas Pfeiffer (DLR-SR)
Robert Reicherdt (PikeTec) -
Algorithm Code
Christoff Bürger (Dassault Systèmes AB)
Martin Otter (DLR-SR)
Andreas Pfeiffer (DLR-SR) -
Production Code
Jörg Niere (dSPACE GmbH)
Michael Hussmann (dSPACE GmbH)
Kai Werther (ETAS GmbH) -
Binary Code
David Brenken (EFS)
Pierre Le Bihan (Dassault Systèmes)
Robert Reicherdt (PikeTec)
Benchmark Test Cases
The specification was assessed with benchmark tests cases provided in the Modelica library EMPHYSIS_TestCases and with Simcenter Amesim models. The EMPHYSIS_TestCases library was managed by Andreas Pfeiffer (DLR-SR) and Christoff Bürger (Dassault Systèmes AB).
The benchmark test cases have been developed by:
-
Robert Bosch GmbH
Siva Sankar Armugham
Christian Bertsch
Oliver Lenord
Naresh Mandipalli
Jonathan Neudorfer
Christian Potthast
Vishnupriya Veeraragavan -
DLR-SR
Jonathan Brembeck
Ricardo de Castro
Michael Fleps-Dezasse
Martin Otter
Andreas Pfeiffer
Jakub Tobolar -
Siemens Digital Industries Software
Jérôme André
Tool Assessment
The eFMI specification was assessed by implementing eFMI support in various tools whose interoperability as a tool chain was evaluated. To that end, more than a hundred test models and variants of the benchmark test cases provided by the EMPHYSIS_TestCases library have been used to validate tool interoperability and correctness.
The developed and bechmarked tools are, in alphabetic order:
- AUTOSAR Builder (Dassault Systèmes)
-
-
Production and Binary Code → Adaptive AUTOSAR
-
Developers: Fabien Aillerie
-
- Astrée (AbsInt Angewandte Informatik GmbH)
-
-
Verification of Production Code
-
Developers: Reinhold Heckmann
-
- CSD (Siemens NV)
-
-
Test of Production Code with Behavioral Model, integration in existing code and verification of code
-
Developers: Jishnu Jayaram
-
- Dymola (Dassault Systèmes AB)
-
-
Modelica → Algorithm Code
-
Modelica → Behavioral Model
-
Developers: Christoff Bürger
-
- ESP (Dassault Systèmes)
-
-
Algorithm Code → Production Code
-
Production Code → Binary Code
-
Developers: Samuel Devulder, Pierre Le Bihan, Laurent Le Goff
-
- SCODE CONGRA (ETAS GmbH)
-
-
Algorithm Code → Production Code
-
Test of Production Code with BehavioralModel
-
Developers: Kai Werther
-
- Behavioral Model Scripts (DLR-SR)
-
-
Generation of Behavioral Model
-
Developers: Andreas Pfeiffer
-
- Simcenter Amesim (Siemens Digital Industries Software)
-
-
Amesim model → neural network approximation as Algorithm Code
-
Developers: Jérôme André
-
- SimulationX (ESI ITI GmbH)
-
-
Modelica → Algorithm Code
-
Developers: Gerd Kurzbach
-
- TargetLink (dSPACE GmbH)
-
-
Algorithm Code → Production Code
-
Test of Production Code with Behavioral Model
-
Developers: Michael Hussmann, Jörg Niere
-
- TPT (PikeTec)
-
-
Test of Production Code with Behavioral Model
-
Developers: Robert Reicherdt
-
Demonstrators
The eFMI specification and the developed tools have been assessed by industrial demonstrators:
- Performance assessment (Robert Bosch GmbH)
-
Comparing generated Production Code of nine benchmark test cases of the EMPHYSIS_TestCases library with manually developed code. This includes comparison of execution performance on the Bosch ECU MDG1.
-
Tooling: Performance Test Environment
-
Developer: Vishnupriya Veeraragavan
-
- Powertrain vibration reduction (Robert Bosch GmbH)
-
Generate a controller with a nonlinear inverse model on the Bosch ECU MDG1 to reduce vibrations in a powertrain.
-
Tooling: Dymola, SCODE-CONGRA, TPT, Astrée and eFMI2AUTOSAR (Robert Bosch GmbH)
-
Contributors: Oliver Lenord, Kai Werther, Siva Sankar Armugham
-
- Model-based diagnosis of thermo systems (Robert Bosch GmbH)
-
Generate diagnosis functions on the Bosch ECU MDG1.
-
Tooling: OpenModelica (www.openmodelica.org), SCODE-CONGRA, ECU Test Environment
-
Contributors: Oliver Lenord, Christian Potthast
-
- Virtual sensor for hybrid drivetrain (Siemens)
-
Generate virtual sensor by approximating a dynamic model by means of a neural network.
-
Tooling: Simcenter Amesim and TargetLink
-
Contributors:
-
Jérôme André (Siemens Digital Industries Software)
-
Alexander Van Bellinghen (Siemens NV)
-
Yuri Durodié (Siemens NV)
-
Jishnu Jayaram (Siemens NV)
-
Jorg Niere (dSPACE GmbH)
-
-
- Semi-active damping controller and observer (DLR-SR)
-
Generate a controller (with a nonlinear inverse model) and a prediction model (nonlinear extended Kalman Filter or nonlinear unscented Kalman Filter) on a pre-development ECU from EFS and on an ECU of KW automotive. The implementation with the KW automotive ECU has been tested in real driving tests.
-
Tooling: Dymola and TargetLink
-
Contributors:
-
Florian Bitter (EFS)
-
Jonathan Brembeck (DLR-SR)
-
Daniel Baumgartner (DLR-SR)
-
Christoff Bürger (Dassault Systèmes AB)
-
David Brenken (EFS)
-
Dario Celan (EFS)
-
Georg Hofstetter (EFS)
-
Michael Hussmann (dSPACE GmbH)
-
Konrad Krauter (EFS)
-
Severin Kirpal (EFS)
-
Jorg Niere (dSPACE GmbH)
-
Andreas Pfeiffer (DLR-SR)
-
Raik Ritter (EFS)
-
Julian Ruggaber (DLR-SR)
-
Christina Schreppel (DLR-SR)
-
Jakub Tobolar (DLR-SR)
-
Johannes Ultsch (DLR-SR)
-
Christoph Winter (DLR-SR)
-
-
- Dual-clutch use case (Daimler AG)
-
Standardized, parameterized, reusable module for a simplified dual clutch transmission model with state events. The model extensively uses typically stiff components of the Modelica Standard Library (modelica.org) like clutches with friction and non-linear springs, resulting in a stiff, mixed eqution system with discontinous states due to gear shifts. The objective is to demonstrate the portability of the generated module to hardware-in-the-loop (HiL) systems and to a pre-development transmission controller unit.
-
Tooling:
-
Model development and eFMU generation: Dymola and TargetLink
-
Software-in-the-loop tests: Dymola
-
Hardware-in-the-loop tests: TargetLink, ConfigurationDesk (dSPACE GmbH) and PROVEtech (Akka Technologies)
-
-
Contributors:
-
Zdenek Husar (Daimler AG)
-
Jan Röper (Daimler AG)
-
Emmanuel Chrisofakis (Daimler AG)
-
Klaus Riedl (Daimler AG)
-
Christoff Bürger (Dassault Systèmes AB)
-
Hans Olsson (Dassault Systèmes AB)
-
-
- Transmission model as virtual sensor (Volvo Cars)
-
Virtual sensor for electric machine control based on a Modelica transmission model. The virtual sensor provides vehicle state estimation used to mitigate, e.g., backlash in the electric driveline, and thereby increase the overall performance of the whole electric driveline.
-
Tooling: Dymola and TargetLink
-
Contributors:
-
Sarah Bellis (Volvo Cars)
-
Martin Johnsson (Volvo Cars)
-
Jart Hageman (Volvo Cars)
-
Sabina Linderoth (Volvo Cars)
-
Edvin Eriksson Johannsson (Volvo Cars)
-
David Kastö (Volvo Cars)
-
Aditya Naronikar (Volvo Cars)
-
Ottilia Wahlgren (Volvo Cars)
-
Emma Kroon (Volvo Cars)
-
Johannes Emilsson (Volvo Cars)
-
Joachim Härsjö (Volvo Cars)
-
Per Jacobsson (Volvo Cars)
-
Johan Bergeld (Volvo Cars)
-
Christoff Bürger (Dassault Systèmes AB)
-
-
- AEBS: Advanced Emergency Braking System (Dassault Systèmes)
-
Advanced emergency braking controller derived from industrial Simulink (MathWorks) model with enabled subsystems and signal locks. For correct handling of the side-effects of enabled subsystems Modelica state machines are used; the signal locks are modeled using
previous
of Modelica synchronous. The final objective is the generation and validation of an AUTOSAR Adaptive Platform component starting from the Modelica model via a seamless tool chain based on eFMI.-
Tooling:
-
Model development and Algorithm Code generation: Dymola
-
Production and Binary Code generation: ESP
-
AUTOSAR Adaptive Platform component generation: AUTOSAR Builder
-
-
Contributors:
-
Christoff Bürger (Dassault Systèmes AB)
-
Samuel Devulder (Dassault Systèmes)
-
Fabien Aillerie (Dassault Systèmes)
-
-
- pNMPC controller for semi-active suspension (GIPSA-lab)
-
Model-based controller for semi-active suspension regulation with hardware-in-the-loop (HiL) test via the INOVE vehicle suspension test rig. The controller is a parameterized nonlinear model predictive controller (pNMPC) from GIPSA-lab using a neural network model to predict the future behavior of the car like the response of chassis and wheel to a given road profile and suspension parameter. The suspension control is realized by means of this simulated prediction. A Simcenter Amesim physics model of the whole car including suspension, chassis and wheels is used to derive and train the neural network model, for which in turn an implementation as eFMI GALEC code is generated (all within Simcenter Amesim). Respective eFMI production code is generated using TargetLink. The final solution is deployed on a dSPACE MicroAutoBox II ECU, based on GIPSA-lab’s pNMPC module and a S-function block wrapping the production code.
-
Tooling: Simcenter Amesim and TargetLink
-
Contributors:
-
Olivier Sename (Gipsa Lab)
-
Rattena Tang (Gipsa Lab)
-
Suzanne De Conti (Gipsa Lab)
-
Karthik Murali Madhavan Rathai (Gipsa Lab)
-
Thanh-Phong Pham (Gipsa Lab)
-
Manh-Hung Do (Gipsa Lab)
-
Marc Alirand (Siemens Digital Industries Software)
-
Jérôme André (Siemens Digital Industries Software)
-
Joerg Niere (dSPACE GmbH)
-
-
Appendix B: Reserved Built-in Functions
This section lists already designed built-in functions that are not yet part of the efmi standard but might be added to it in the future. Therefore, the names and functionality of these functions are reserved:
Overview of the reserved built-in functions
Function-Name | Description |
---|---|
Round Real |
|
|
Round towards zero (also known as truncation). |
|
Round towards infinity. |
|
Round half towards negative infinity. |
|
Round half towards positive infinity. |
|
Round half towards zero (also knowns as: round half aways from infinity). |
|
Round half away zero (also known as: round half towards infinity) |
|
Round half towards odd number. |
Division of Integer variables |
|
|
integer( roundDown(i1/i2) ). |
|
integer( roundUp(i1/i2) ). |
|
integer( roundAwayZero(i1/i2) ). |
|
integer( roundHalfDown(i1/i2) ). |
|
integer( roundHalfUp(i1/i2) ). |
|
integer( roundHalfTowardsZero(i1/i2) ). |
|
integer( roundHalfAwayZero(i1/i2) ). |
|
integer( roundHalfToEven(i1/i2) ). |
|
integer( roundHalfToOdd(i1/i2) ). |
|
Euclidean division of two integers. |
Integer remainder of division of Integer variables |
|
|
Integer remainder of roundDown(i1/i2). |
|
Integer remainder of roundUp(i1/i2). |
|
Integer remainder of roundAwayZero(i1/i2). |
|
Integer remainder of roundHalfDown(i1/i2). |
|
Integer remainder of roundHalfUp(i1/i2). |
|
Integer remainder of roundHalfTowardsZero(i1/i2). |
|
Integer remainder of roundHalfAwayZero(i1/i2). |
|
Integer remainder of roundHalfToEven(i1/i2). |
|
Integer remainder of roundHalfToOdd(i1/i2). |
|
Integer remainder of Euclidean division. |
Remainder of division of Real variables |
|
|
Real remainder of roundDown(r1/r2). |
|
Real remainder of roundUp(r1/r2). |
|
Real remainder of roundAwayZero(r1/r2). |
|
Real remainder of roundHalfDown(r1/r2). |
|
Real remainder of roundHalfUp(r1/r2). |
|
Real remainder of roundHalfTowardsZero(r1/r2) |
|
Real remainder of roundHalfAwayZero(r1/r2) |
|
Real remainder of roundHalfToEven(r1/r2) |
|
Real remainder of roundHalfToOdd(r1/r2) |
Definition of the reserved built-in functions
The following functions are appended to Cbuiltin1:
/*********************************************************************************************
Direct rounding to an integer:
*********************************************************************************************/
function roundTowardsZero
input Real r;
output Real i;
algorithm /*
Also known as: truncation, round away from infinity.
i := (if r >= 0.0 then roundDown(r) else roundUp(r));
*/ end roundTowardsZero;
function roundAwayZero
input Real r;
output Real i;
algorithm /*
Also known as: round towards infinity.
i := (if r <= 0.0 then roundDown(r) else roundUp(r));
*/ end roundAwayZero;
/*********************************************************************************************
Rounding to the nearest integer (using a tie-breaking rule):
*********************************************************************************************/
function roundHalfDown
input Real r;
output Real i;
algorithm /*
Also known as: round half towards negative infinity.
i := roundUp(r - 0.5);
*/ end roundHalfDown;
function roundHalfUp
input Real r;
output Real i;
algorithm /*
Also known as: round half towards positive infinity.
i := roundDown(r + 0.5);
*/ end roundHalfUp;
function roundHalfTowardsZero
input Real r;
output Real i;
algorithm /*
Also known as: round half away from infinity.
i := roundAwayZero(r - sign(r) * 0.5);
*/ end roundHalfTowardsZero;
function roundHalfAwayZero
input Real r;
output Real i;
algorithm /*
Also known as: round half towards infinity.
i := roundTowardsZero(r + sign(r) * 0.5);
*/ end roundHalfAwayZero;
function roundHalfToOdd
input Real r;
output Real i;
algorithm /*
i := (if roundHalfDown(r) < roundHalfUp(r)
then (if integer(remainder(r + 0.5, 2.0)) == 0 then r - 0.5 else r + 0.5)
else roundHalfDown(r));
*/ end roundHalfToOdd;
/************************************** END OF LISTING **************************************/
The following functions redefine Cbuiltin2, which defines builtin functions for Integer division. For every function named roundα
of Cbuiltin1 with α
an arbitrary sequence of characters, Cbuiltin2 contains the character sequence:
/************************************* BEGIN OF LISTING *************************************/
function divisionα
input Integer dividend;
input Integer divisor;
output Integer quotient;
algorithm /*
quotient := integer(roundα(real(dividend) / real(divisor)));
*/ end divisionα;
function remainderα
input Integer dividend;
input Integer divisor;
output Integer remainder;
algorithm /*
remainder := dividend - divisor * divisionα(dividend, divisor);
*/ end remainderα;
/************************************** END OF LISTING **************************************/
Further, Cbuiltin2 contains the following character sequence:
/************************************* BEGIN OF LISTING *************************************/
function divisionEuclidean
input Integer dividend;
input Integer divisor;
output Integer quotient;
algorithm /*
quotient := integer((if divisor > 0
then roundDown(real(dividend) / real(divisor))
else roundUp(real(dividend) / real(divisor))));
*/ end divisionEuclidean;
function remainderEuclidean
input Integer dividend;
input Integer divisor;
output Integer remainder;
algorithm /*
remainder := dividend - divisor * divisionEuclidean(dividend, divisor);
*/ end remainderEuclidean;
/************************************** END OF LISTING **************************************/
Above functions are in lexical order w.r.t. their names; they constitute Cbuiltin2 in its entirety.
The following functions redefine Cbuiltin3, which defines builtin functions for Real division, where the quotient is forced to be an integer according to a rounding strategy. For every function named roundα
of Cbuiltin1 with α
an arbitrary sequence of characters, Cbuiltin3 contains the character sequence:
/************************************* BEGIN OF LISTING *************************************/
function realRemainderα
input Real dividend;
input Real divisor;
output Real remainder;
algorithm /*
remainder := dividend - divisor * round_α(dividend / divisor);
*/ end realRemainderα;
/************************************** END OF LISTING **************************************/
Above functions are in lexical order w.r.t. their names; they constitute Cbuiltin3 in its entirety.
Appendix C: Equation Code Model Representation
This section describes rudimentary support for the planned Equation Code model. It is not part of the eFMI standard, because the development is not yet finalized. This appendix summarizes the status of the development. An improved version might be added to a future version of the eFMI standard.
Introduction
The Equation Code model shall describe the mathematical model of the acausal, continuous-time physical system with a standardized, intermediate language (a subset of the Modelica language (https://www.modelica.org/modelicalanguage), often also referred to as Flat Modelica).
Conceptually, the Equation Code model representation depicts the earliest stage of the model analyses. Here any language specific analyses, e.g. such as syntax checks are already done. However, the model is still acausal, i.e. the inputs and outputs are not yet fixed, the states not yet selected and the equations are not yet sorted and discretized.
This representation form is currently under developement and is not yet defined in this specification, with exception of a very rudimentary manifest file that is needed to connect Behavioral Model and Algorithm Code representations.
Manifest schema
The rudimentary manifest file of the Equation Code model representation is an instance of an XML schema definition and defines the names and types of the variables that are used in the interface of the model.
Definition of an eFMU Equation Code (efmiEquationCodeManifest.xsd)
On the top level, the schema consists of the following elements:
Name | Description |
---|---|
|
The attributes of the top-level element are the same for all manifest kinds and are defined in section
Section 2.3.1. |
|
List of files referenced in this model representation. Currently, no Files are defined. This element is the same for all manifest kinds and is defined in section Section 2.3.3. |
|
A list of the discrete-time interface variables of the model. A variable might be a scalar or an array of an elementary type. For details see Definition of an Equation Code Variable (efmiEqVariable.xsd). |
|
Additional data that a vendor might want to store and that other vendors might ignore. For details see Section 2.3.4.5. |
Definition of an Equation Code Variable (efmiEqVariable.xsd)
An Equation Code defines a set of Variables. A Variable is defined in the following way:
The schema consists of the following elements:
Name | Description |
---|---|
|
The unique identification of the variable with respect to the EquationCode manifest file (can be referenced from other manifest files). |
|
The full, unique name of the variable. Every variable is uniquely identified within an eFMI EquationCode instance by this name. |
|
The base type of the variable. Valid values are: |
|
An optional description string describing the meaning of the variable. |
|
If the variable is an array, then the fixed dimensions of the array
are defined by this element.
For every dimension, the |
|
Additional data of the variable, e.g., for the dialog menu or the graphical layout. For details see Section 2.3.4.5. |