Skip to content
This repository was archived by the owner on May 15, 2025. It is now read-only.

Latest commit

 

History

History
139 lines (109 loc) · 6.24 KB

File metadata and controls

139 lines (109 loc) · 6.24 KB

Model Development

Models represent entities that the RSIS framework can load, connect, and schedule. For those who are familiar with Simulink, this is similar to the idea of a block.

Development Languages

Models can be developed in both Rust & C++. Meson build system integration is provided for C++ models, and C++ models are compiled against the C++17 standard.

Ports

Ports are the method through which models are exposed to the framework. The top level of the model interface has a required structure with specific intent:

  • inputs
    • Represents model inputs
    • Each input port can be connected to a single output port
  • outputs
    • Represents model outputs
    • Each output port can be connected to multiple input ports
  • data
    • Exposes read-only internal state for logging and debugging purposes
  • params
    • Parameters that can be set before sim initialization

Ports can additionally be further organized into logical groupings; these map directly to structs in Rust & classes in C++. Permissions and intent for these further subdivisions are inheritied from the top level breakdown.

Code Generation

RSIS provides a YAML based interface code generate process to simplify the process of model development. The following are autogenerated for each language:

Language Generated Files Contains
Rust *_interface.rs Struct and reflection functions
C++ *_interface.hxx Class declarations, reflection function declarations
C++ *_interface.cxx Class constructor/destructors definitions, reflection function definitions

Example model interface:

model: Model

ModelIn:
  power: {type: Float32, value: 0.0, unit: V, desc: Voltage power input to model }

ModelOut:
    counter: {type: Int32, dims: [2], value: 0, desc: Randomly increments when on }

ModelData:
    on: {type: Bool, value: false, desc: Model On state }

ModelParams:
    turn_on: {type: Float32, value: 3.0, unit: V, desc: Base voltage requirement for turn on }

Model:
    inputs: {class: ModelIn }
    outputs: {class: ModelOut }
    data: {class: ModelData }
    params: {class: ModelParams }

The interface file is required to have a model element, specifying another element in the file that is the root of the model interface definition. That class is required to have the following elements: inputs, outputs, data, params. Each class member definition must be a dictionary.

The type key in a member definition indicates that the datatype is one of the supported data types, as listed here. The class key in a member definition indicates that the datatype is a user-defined type. The table below lists optional keys that can be defined.

key Meaning Definition Example
dims Array dimension. Defaults to scalar List of positive integers, or [-1] [2,3,2]
unit Units. Defaults to nothing See Units kg^2/m
desc Description. Defaults to nothing String Jet engine thrust output

If the array dimension is [-1], this is interpreted as a variable length one-dimension array. The following table describes how this is transformed:

Language Container
Rust Vec<>
C++ std::vector<>
Fortran ??

The value key can also be specified for non user defined types, indicating a default value that the member must take.

Planned Features

  • Referencing other YAML files
  • Multiple model declarations in a single YAML file
  • Pointer type definitions
  • Possible additional datatype support:
    • std::array<>
    • void *
    • char8_t (C++20)
  • Only adding #include <complex> when needed. Currently added always

Default Data Types

The following table represents how Julia datatypes correspond to datatypes in Rust and C++:

Julia Rust C++ Fortran 2008
Char char char character
String String std::string character (len=:), allocatable
Bool bool bool logical
Int8 i8 int8_t integer (int8)
Int16 i16 int16_t integer (int16)
Int32 i32 int32_t integer (int32)
Int64 i64 int64_t integer (int64)
UInt8 u8 uint8_t na
UInt16 u16 uint16_t na
UInt32 u32 uint32_t na
UInt64 u64 uint64_t na
Float32 f32 float real (real32)
Float64 f64 double real (real64)
Complex{Float32} Complex{f32} std::complex complex*8
Complex{Float64} Complex{f64} std::complex complex*16

Notes:

  • Complex values in Rust are supported with the num-complex crate. Complex values in C++ are supported with the <complex> header.]
  • Fortran integration utilizes use ISO_FORTRAN_ENV to specify integers

Units

The Unitful package is used to define units for ports. Connected ports that both have a defined unit must have matching units (this rule is relaxed if any or both ports don't have a unit). In order to convert between units, it is suggested that the user add a Unit Conversion block provided in the Framework Library.

The default symbols provided by Unitful are immediately available for model usage.

Connecting Model Ports

Input & output model ports can be connected via the Julia connect command (See Julia help for more info), creating connection objects in the simulation run-time. During the simulation, the connection objects copy output port data to connected input ports, which are called by the models containing those inputs.

Model Hooks

A variety of hooks are exposed for the user to extend:

  • initModel
    • Called during initialization of the simulation. The user must extend this.
  • configModel
    • Called when model parameters are updated.
    • Called once during each step of the simulation. The user must extend this.
  • stepModel
  • destroyModel
    • Called once during the end of the simulation

Compilation

Models are compiled as shared libraries that are loaded in during runtime. Library loading is handled within the Julia runtime. Currently, a C API is utilized to pass data from the model libraries into the RSIS core framework, though this may change in the future.

Model Port Pointers

TODO

Julia Pre-Hook

TODO

Additional User Callbacks

TODO