Guide · SysMLSystems Modeling Language A graphical modeling language for systems engineering, based on UML, with block, activity, state machine and parametric diagrams. v2
SysML v2 tutorial: model an electric drive in the textual notation
Build a small, complete SysML v2 model step by step: the electric drive of a hybrid car, with its parts, quantities and units, ports and connections, behavior, requirements, a verification case and views. Every listing on this page is SysML v2 text checked with a language engine.
On this page
- What you will build
- First idea: definitions and usages
- Step 1: a package and its imports
- Step 2: part definitions and attributes with units
- Step 3: the assembly, with values
- Step 4: ports, interfaces and connections
- Step 5: behavior with actions and flows
- Step 6: allocate behavior to structure
- Step 7: requirements with constraints
- Step 8: a verification case
- Step 9: views and diagrams
- The complete model
- How the listings were checked
- Try it in Holarch
- Where to go next
What you will build
The system is the electric drive of a small hybrid city car. A traction battery feeds an inverter, the inverter turns the battery's direct current into alternating current, and a motor turns that current into torque at its shaft. The model is small enough to read in one sitting and still has what a real model needs: structure, quantities with units, interfaces, behavior, requirements and a way to verify them.
The model has three packages:
| Package | Holds | Steps |
|---|---|---|
ElectricDrive | Ports, parts, the assembly with its values, and its behavior | 1 to 6 |
ElectricDriveRequirements | Requirements, a reusable constraint and a verification case | 7 and 8 |
ElectricDriveViews | Views that select parts of the model for diagrams | 9 |
No particular tool is needed to follow along: the text is plain SysMLSystems Modeling Language A graphical modeling language for systems engineering, based on UML, with block, activity, state machine and parametric diagrams. v2 and runs in any tool that reads the textual notation. The end of the page shows how to load it into Holarch.
First idea: definitions and usages
SysMLSystems Modeling Language A graphical modeling language for systems engineering, based on UML, with block, activity, state machine and parametric diagrams. v2 separates a definition from a usage. A definition says what a kind of thing is: part def Battery describes every battery of this design, with its attributes and ports. A usage is such a thing in a context: part battery : Battery inside the drive unit is the one battery in this drive unit, connected to this inverter.
The same pairing runs through the whole language: attribute def and attribute, port def and port, action def and action, requirement def and requirement. A keyword followed by def declares a kind; the same keyword without def uses one. Specific values usually belong on usages, because a usage is where a design decision is made.
Readers who know SysML v1 can compare a definition with a block and a usage with a part property. In SysML v2 the idea applies to every kind of element, and usages nest and refine one another to any depth.
Step 1: a package and its imports
A package is a namespace: it groups elements and gives them qualified names such as ElectricDrive::Battery. Start with an empty package and the library imports it needs.
package ElectricDrive {
doc /* The electric drive of a small hybrid car: a battery, an inverter and a motor. */
private import ScalarValues::*;
private import ISQ::*;
private import SI::*;
}
doc /* … */attaches documentation to the package. Unlike a//comment, it is part of the model, and tools show it with the element.ScalarValuesprovides basic types such asReal,Integer,BooleanandString.ISQprovides quantity types from the International System of Quantities, such asMassValueandPowerValue.SIprovides SIInternational System of Units The metric system of units: meter, kilogram, second, ampere, kelvin, mole and candela, plus derived units. units such askg,VandkW.privatekeeps the imported names inside this package, so a package that importsElectricDrivedoes not receive them through it.
Without the imports, a name such as MassValue cannot be resolved, and a checker reports it as unknown.
Step 2: part definitions and attributes with units
Each component gets a part definition with typed attributes. Typing an attribute by a quantity rather than by Real records what it measures: a mass, an energy, a voltage. A tool can then check every value and every expression for consistent dimensions.
part def Battery {
attribute mass : MassValue;
attribute capacity : EnergyValue;
attribute nominalVoltage : ElectricPotentialValue;
}
part def Inverter {
attribute mass : MassValue;
attribute efficiency : Real;
}
part def Motor {
attribute mass : MassValue;
attribute peakPower : PowerValue;
}
These lines go inside the package braces. The efficiency stays a plain Real because it is a ratio without a unit.
There are no values yet. A definition describes every battery of this kind; the numbers come with a specific battery in the next step.
Step 3: the assembly, with values
The drive unit is a part definition too, made of part usages: one battery, one inverter and one motor. Each usage gives the attributes it inherits from its definition their values.
part def DriveUnit {
part battery : Battery {
attribute redefines mass = 42 [kg];
attribute redefines capacity = 1.4 [kW*h];
attribute redefines nominalVoltage = 260 [V];
}
part inverter : Inverter {
attribute redefines mass = 9 [kg];
attribute redefines efficiency = 0.96;
}
part motor : Motor {
attribute redefines mass = 36 [kg];
attribute redefines peakPower = 60 [kW];
}
attribute totalMass : MassValue = battery.mass + inverter.mass + motor.mass;
}
part battery : Batterydeclares a usage namedbattery, typed by the definitionBattery.attribute redefines mass = 42 [kg]gives the inheritedmassa value. The short form:>> mass = 42 [kg];means the same. Withoutredefines, the line would declare a second attribute that only shares the name, and the inheritedmasswould still have no value.1.4 [kW*h]is a quantity: a number and a unit. Units combine with*,/and^.totalMassis computed from the other values. Change a component's mass and the total follows.
Because every value carries a unit, a dimension mistake shows up as soon as the model is checked. This listing gives a battery a mass in volts:
package UnitCheck {
private import ISQ::*;
private import SI::*;
part def Battery {
attribute mass : MassValue;
}
part battery : Battery {
attribute redefines mass = 42 [V];
}
}
A checker that evaluates units rejects the value: a voltage is not a mass. In Holarch the Editor marks the line with a dimension error.
Step 4: ports, interfaces and connections
Ports are the points where a part meets its surroundings. A port definition lists what crosses the boundary, each feature with a direction: out for what the owner sends, in for what it receives.
port def DCPowerPort {
out attribute voltage : ElectricPotentialValue;
out attribute current : ElectricCurrentValue;
}
port def ACPowerPort {
out attribute voltage : ElectricPotentialValue;
out attribute frequency : FrequencyValue;
}
port def TorquePort {
out attribute torque : TorqueValue;
}
interface def DCLink {
end source : DCPowerPort;
end load : ~DCPowerPort;
}
The receiving side uses the same port definition, conjugated with ~. ~DCPowerPort is the mirror image of DCPowerPort: every out becomes in. One port definition describes both ends of a link, so the two ends cannot drift apart.
An interface definition describes a kind of connection with typed ends. DCLink connects a source that sends DC power to a load that receives it.
Now add the ports to the parts and connect the parts inside the drive unit. The comment lines stand for the lines from the earlier steps.
part def Battery {
// attributes as in step 2
port dcOut : DCPowerPort;
}
part def Inverter {
// attributes as in step 2
port dcIn : ~DCPowerPort;
port acOut : ACPowerPort;
}
part def Motor {
// attributes as in step 2
port acIn : ~ACPowerPort;
port shaft : TorquePort;
}
part def DriveUnit {
// parts and totalMass as in step 3
port output : TorquePort;
interface dcLink : DCLink connect battery.dcOut to inverter.dcIn;
connect inverter.acOut to motor.acIn;
bind output = motor.shaft;
}
interface dcLink : DCLink connect … to …connects two ports through a typed interface, so the connection carries the meaning ofDCLink.connect inverter.acOut to motor.acInis a plain connection, enough when the link needs no definition of its own.bind output = motor.shaftstates that the drive unit's own output port and the motor's shaft are the same thing. This is how a part exposes an inner port at its boundary.
A common mistake is to give both ends the same, unconjugated port. Both ends then send and neither receives:
package PortCheck {
private import ISQ::*;
port def DCPowerPort {
out attribute voltage : ElectricPotentialValue;
}
part def Battery { port dcOut : DCPowerPort; }
part def Inverter { port dcIn : DCPowerPort; }
part def Pack {
part battery : Battery;
part inverter : Inverter;
connect battery.dcOut to inverter.dcIn;
}
}
The text parses, but a checker that compares directions warns that both ends of the connection send voltage. Conjugating the receiving end, port dcIn : ~DCPowerPort;, fixes it.
Step 5: behavior with actions and flows
Structure says what the system is; behavior says what it does. An action definition describes a behavior with input and output parameters. Item definitions describe the things that flow, here electrical power.
item def DCPower;
item def ACPower;
action def DrawPower {
in attribute demand : PowerValue;
out item dc : DCPower;
}
action def ConvertPower {
in item dc : DCPower;
out item ac : ACPower;
}
action def ProduceTorque {
in item ac : ACPower;
out attribute torque : TorqueValue;
}
action def ProvideTraction {
in attribute demand : PowerValue;
out attribute torque : TorqueValue;
action draw : DrawPower;
action convert : ConvertPower;
action produce : ProduceTorque;
flow draw.dc to convert.dc;
flow convert.ac to produce.ac;
first start then draw;
first draw then convert;
first convert then produce;
first produce then done;
}
inandoutparameters are the inputs and outputs of an action.- Inside
ProvideTraction, three action usages are the steps: draw, convert and produce. flow draw.dc to convert.dcsays that the output of one step is the input of the next.first draw then convertis a succession: one step finishes before the next starts. Flows say what moves; successions say in which order.startanddoneare the beginning and the end of the enclosing action.
A tool draws this as an action flow: the steps as boxes, the successions as arrows, and the flows between the steps' parameters.
Step 6: allocate behavior to structure
So far the behavior belongs to no component. A perform statement says which part carries out which step:
part driveUnit : DriveUnit {
perform action traction : ProvideTraction;
part redefines battery { perform traction.draw; }
part redefines inverter { perform traction.convert; }
part redefines motor { perform traction.produce; }
}
driveUnit is a usage of DriveUnit at the top of the package: the drive unit of this design. It performs ProvideTraction, and each of its parts performs one step. part redefines battery refines the battery usage inherited from DriveUnit instead of adding a new one.
This is the textual form of a functional allocation. From it, a tool can list the functions each component performs, or draw the action flow with one lane per part.
Step 7: requirements with constraints
Requirements go into their own package, which imports the design. In SysMLSystems Modeling Language A graphical modeling language for systems engineering, based on UML, with block, activity, state machine and parametric diagrams. v2 a requirement is a constraint on a subject: the doc text says what is needed in words, and a require constraint says the same in a form a tool can evaluate.
package ElectricDriveRequirements {
doc /* What the electric drive must do, and how each requirement is checked. */
private import ElectricDrive::*;
private import ScalarValues::*;
private import ISQ::*;
private import SI::*;
constraint def AtLeast {
in actual : PowerValue;
in minimum : PowerValue;
actual >= minimum
}
requirement def <'ED-1'> UnitMass {
doc /* The drive unit shall weigh no more than the mass limit. */
subject unit : DriveUnit;
attribute massLimit : MassValue;
require constraint { unit.totalMass <= massLimit }
}
requirement def <'ED-2'> PeakPower {
doc /* The motor shall deliver at least the required peak power. */
subject unit : DriveUnit;
attribute required : PowerValue;
require constraint : AtLeast {
in actual = unit.motor.peakPower;
in minimum = required;
}
}
requirement driveSpec {
doc /* The requirements the drive unit of the city car is built to. */
subject unit : DriveUnit;
requirement unitMass : UnitMass {
attribute redefines massLimit = 95 [kg];
}
requirement peakPower : PeakPower {
attribute redefines required = 50 [kW];
}
}
satisfy driveSpec by driveUnit;
}
<'ED-1'>is a short name: the identifier engineers quote in reviews. Other model elements refer to the full name,UnitMass.subject unit : DriveUnitnames what the requirement is about.require constraint { unit.totalMass <= massLimit }is the condition that must hold. The limit is a parameter, so the same definition serves cars with different limits.AtLeastis a reusable constraint definition.PeakPoweruses it and binds its two inputs.driveSpeccollects the requirements for this car and sets the limits: 95 kg and 50 kW.satisfy driveSpec by driveUnitclaims that the design meets the specification. With the values from step 3, the total mass is 87 kg against a limit of 95 kg, and the peak power is 60 kW against 50 kW, so both constraints hold.
Keep the doc text and the constraint saying the same thing. Reviewers read the text; tools evaluate the constraint.
Step 8: a verification case
A satisfy relationship is a claim. A verification case says how the claim is checked, by test, inspection, analysis or demonstration.
verification def <'VC-1'> WeighUnit {
doc /* Weigh the assembled drive unit on a calibrated scale. */
subject unit : DriveUnit;
objective {
verify driveSpec.unitMass;
}
return verdict : Boolean = unit.totalMass <= driveSpec.unitMass.massLimit;
}
verification weighing : WeighUnit {
subject unit = driveUnit;
}
objective { verify driveSpec.unitMass; }names the requirement this case verifies. These links are what a verification matrix is built from: each requirement against the cases that verify it.return verdictis the result: here, whether the weighed total mass is within the limit.weighingis a usage of the case for this drive unit: the planned test, with its subject bound todriveUnit.
Satisfaction and verification are kept apart on purpose. Satisfaction says which design element answers a requirement; verification says how you know that it does.
Step 9: views and diagrams
In SysMLSystems Modeling Language A graphical modeling language for systems engineering, based on UML, with block, activity, state machine and parametric diagrams. v2 a diagram is not a separate drawing. A view is an element of the model that states what to show (expose) and which kinds of elements to include (filter). A tool renders the view and keeps its layout; the content always comes from the model.
package ElectricDriveViews {
doc /* Views of the electric drive. Each view selects part of the model; the layout belongs to the tool. */
private import ElectricDrive::*;
private import ElectricDriveRequirements::*;
private import StandardViewDefinitions::*;
// The drive unit's parts, ports and connections.
view driveConnections : InterconnectionView {
expose ElectricDrive::DriveUnit;
}
// The traction behavior: its steps, their order and what flows between them.
view tractionFlow : ActionFlowView {
expose ElectricDrive::ProvideTraction;
}
// The requirements with what satisfies and verifies them.
view requirementTree : GeneralView {
filter @SysML::RequirementDefinition or @SysML::RequirementUsage or @SysML::SatisfyRequirementUsage;
expose ElectricDriveRequirements::**;
}
}
The standard library defines the common view kinds:
| View | Shows | In this model |
|---|---|---|
| General View | Any elements and their relationships, as boxes and lines | requirementTree |
| Interconnection View | The parts of one assembly with their ports and connections | driveConnections |
| Action Flow View | The steps of a behavior, their order and what flows between them | tractionFlow |
| State Transition View | States and the transitions between them | None |
| Sequence View | Messages between parts over time | None |
| Grid View | Elements or relationships as a table or matrix | None |
Because a view is part of the model, renaming the battery changes every diagram that shows it, and a reviewer can read in the text exactly what a diagram includes. The screenshots show two of these view kinds in Holarch on the Hybrid Car demo, a larger model of the same car with an engine, a transmission and wheels.
The complete model
The three packages together. Save them in one file, for example electric-drive.sysml.
package ElectricDrive {
doc /* The electric drive of a small hybrid car: a battery, an inverter and a motor. */
private import ScalarValues::*;
private import ISQ::*;
private import SI::*;
// ---- Ports and interfaces ----
port def DCPowerPort {
out attribute voltage : ElectricPotentialValue;
out attribute current : ElectricCurrentValue;
}
port def ACPowerPort {
out attribute voltage : ElectricPotentialValue;
out attribute frequency : FrequencyValue;
}
port def TorquePort {
out attribute torque : TorqueValue;
}
interface def DCLink {
end source : DCPowerPort;
end load : ~DCPowerPort;
}
// ---- Components ----
part def Battery {
attribute mass : MassValue;
attribute capacity : EnergyValue;
attribute nominalVoltage : ElectricPotentialValue;
port dcOut : DCPowerPort;
}
part def Inverter {
attribute mass : MassValue;
attribute efficiency : Real;
port dcIn : ~DCPowerPort;
port acOut : ACPowerPort;
}
part def Motor {
attribute mass : MassValue;
attribute peakPower : PowerValue;
port acIn : ~ACPowerPort;
port shaft : TorquePort;
}
// ---- The assembly ----
part def DriveUnit {
part battery : Battery {
attribute redefines mass = 42 [kg];
attribute redefines capacity = 1.4 [kW*h];
attribute redefines nominalVoltage = 260 [V];
}
part inverter : Inverter {
attribute redefines mass = 9 [kg];
attribute redefines efficiency = 0.96;
}
part motor : Motor {
attribute redefines mass = 36 [kg];
attribute redefines peakPower = 60 [kW];
}
port output : TorquePort;
interface dcLink : DCLink connect battery.dcOut to inverter.dcIn;
connect inverter.acOut to motor.acIn;
bind output = motor.shaft;
attribute totalMass : MassValue = battery.mass + inverter.mass + motor.mass;
}
// ---- Behavior ----
item def DCPower;
item def ACPower;
action def DrawPower {
in attribute demand : PowerValue;
out item dc : DCPower;
}
action def ConvertPower {
in item dc : DCPower;
out item ac : ACPower;
}
action def ProduceTorque {
in item ac : ACPower;
out attribute torque : TorqueValue;
}
action def ProvideTraction {
in attribute demand : PowerValue;
out attribute torque : TorqueValue;
action draw : DrawPower;
action convert : ConvertPower;
action produce : ProduceTorque;
flow draw.dc to convert.dc;
flow convert.ac to produce.ac;
first start then draw;
first draw then convert;
first convert then produce;
first produce then done;
}
part driveUnit : DriveUnit {
perform action traction : ProvideTraction;
part redefines battery { perform traction.draw; }
part redefines inverter { perform traction.convert; }
part redefines motor { perform traction.produce; }
}
}
package ElectricDriveRequirements {
doc /* What the electric drive must do, and how each requirement is checked. */
private import ElectricDrive::*;
private import ScalarValues::*;
private import ISQ::*;
private import SI::*;
constraint def AtLeast {
in actual : PowerValue;
in minimum : PowerValue;
actual >= minimum
}
requirement def <'ED-1'> UnitMass {
doc /* The drive unit shall weigh no more than the mass limit. */
subject unit : DriveUnit;
attribute massLimit : MassValue;
require constraint { unit.totalMass <= massLimit }
}
requirement def <'ED-2'> PeakPower {
doc /* The motor shall deliver at least the required peak power. */
subject unit : DriveUnit;
attribute required : PowerValue;
require constraint : AtLeast {
in actual = unit.motor.peakPower;
in minimum = required;
}
}
requirement driveSpec {
doc /* The requirements the drive unit of the city car is built to. */
subject unit : DriveUnit;
requirement unitMass : UnitMass {
attribute redefines massLimit = 95 [kg];
}
requirement peakPower : PeakPower {
attribute redefines required = 50 [kW];
}
}
satisfy driveSpec by driveUnit;
verification def <'VC-1'> WeighUnit {
doc /* Weigh the assembled drive unit on a calibrated scale. */
subject unit : DriveUnit;
objective {
verify driveSpec.unitMass;
}
return verdict : Boolean = unit.totalMass <= driveSpec.unitMass.massLimit;
}
verification weighing : WeighUnit {
subject unit = driveUnit;
}
}
package ElectricDriveViews {
doc /* Views of the electric drive. Each view selects part of the model; the layout belongs to the tool. */
private import ElectricDrive::*;
private import ElectricDriveRequirements::*;
private import StandardViewDefinitions::*;
// The drive unit's parts, ports and connections.
view driveConnections : InterconnectionView {
expose ElectricDrive::DriveUnit;
}
// The traction behavior: its steps, their order and what flows between them.
view tractionFlow : ActionFlowView {
expose ElectricDrive::ProvideTraction;
}
// The requirements with what satisfies and verifies them.
view requirementTree : GeneralView {
filter @SysML::RequirementDefinition or @SysML::RequirementUsage or @SysML::SatisfyRequirementUsage;
expose ElectricDriveRequirements::**;
}
}
How the listings were checked
Every listing on this page was parsed and checked with the Holarch Language Engine, the engine behind Holarch's SysMLSystems Modeling Language A graphical modeling language for systems engineering, based on UML, with block, activity, state machine and parametric diagrams. v2 Editor, with the SysML v2 standard library loaded. The checks resolve every name, compare units and dimensions, and compare port directions across connections.
- The complete model and the stand-alone listings give no errors and no warnings.
- Each excerpt appears line for line, in order, in the complete model.
- The two listings that show mistakes give exactly the error and the warning described next to them.
For which SysML v2 constructs the engine supports and its known gaps, see SysML v2 language coverage.
Try it in Holarch
- Save the complete model as
electric-drive.sysml. - Open Model → Import and Export, choose Into a new SysMLSystems Modeling Language A graphical modeling language for systems engineering, based on UML, with block, activity, state machine and parametric diagrams. v2 project and drop the file. See import files into a new project.
- Open Model → Editor to read and change the text. Each package is a document. See the Editor.
- Open the Diagrams list and click
driveConnections,tractionFloworrequirementTree. See open a view.
To type the model instead, create a SysML v2 project, click + New Package in the Editor, and write the steps in order; text that parses is applied after a short pause. See getting started with SysML v2 projects. For a larger model of the same car, open the Hybrid Car demo: Project Files ▾ → New Demo Project → Hybrid Car (SysML v2).
Where to go next
- SysML v2 projects in Holarch: text, views and engineering pages on one model.
- Textual notation reference: what Holarch supports, the checks and the standard library.
- Views reference: every view kind and how to edit the model in it.
- Requirements and verification in SysML v2 projects: requirement pages, the Test Center and the RVTMRequirements Verification Traceability Matrix A table of each requirement with how it is verified, the tests that verify it and their latest result..
- Analysis in SysML v2 projects: parametrics, budgets and trade studies.
- What is MBSE?: why engineers keep the system in a model.