模块三:结构建模
如何描述一个系统由什么组成 — 以及每个结构关键字如何映射到底层精确的 KerML 构造。
KerML → SysML:结构建模概念对应关系
本模块中的每一个结构性关键字都是 KerML L1 构件在 SysML L2 的具体应用。下表展示了本模块所有概念的层次对应关系。
| SysML v2 概念(L2) | 底层 KerML 构件(L1) | SysML 额外添加了什么 |
|---|---|---|
part def | Class(一种 Classifier) | 关键字意味着默认复合包含;实例有身份,随时间持续存在 |
part(用法) | 由 Class 类型化的复合 Feature | isComposite = true;默认多重性 [1..1] |
ref part | 由 Class 类型化的非复合 Feature | isComposite = false;被引用对象独立存在 |
attribute def | DataType(一种 Classifier) | 实例无身份——纯値。可携带不变量和单位约束 |
attribute(用法) | 由 DataType 类型化的 Feature | 値类型子元素;生命周期与父级相同 |
enum def | 带 EnumerationLiteral 成员的 DataType | 封闭的命名値集合;每个字面量无身份 |
item def | Class(KerML 层与 part def 相同) | 仅是约定:表明流动参与者而非持久结构组件 |
port def | Type 边界上带方向的 Feature | 标记交互点;~T 共轭反转所有方向 |
connect | Connector(一种 Feature) | 连接 Feature 实例;SysML 提供命名和匿名两种形式 |
interface def | 带 end Feature 的 Association | 为命名的连接模板添加类型化流声明 |
specializes(在 part def 上) | Subclassification 关系 | 子类型继承父类型的所有特征 |
subsets(在 part 上) | Subsetting 关系 | 子特征的値从父特征的池中取得 |
redefines | Redefinition 关系 | 替换继承的特征,缩窄其类型、多重性或値 |
part def 和 item def 的关键区别是约定,而不是 KerML 语义。两者都映射到 Class。SysML 使用 item def 来表明某事物是流动的(信号、流体、数据包)而不是持久结构。工具可以利用这个约定验证流连接。
部件与分解
KerML 来源:part def → Class; part → 复合 Feature; ref part → 非复合 Feature
在 SysML v2 中,结构建模回答的是:这个系统由什么构成?这些部件之间是什么关系?主要工具是 part。
想想一辆汽车。它有发动机、四个车轮、底盘、油筒。发动机本身又有气缸、曲轴、燃油啦射器。SysML v2 让你精确地描述这种嵌套的“由…构成”结构,细化到你需要的任何层次。
定义与用法
part def— 声明一个可复用类型。KerML 层面:一个Class,其实例随时间持续存在且有身份。part— 在特定上下文中对该类型的用法。KerML 层面:由该Class类型化的复合 Feature,isComposite = true。
1 part def Engine { 2 attribute displacement : Real; 3 attribute cylinders : Integer; 4 } 5 6 part def Car { 7 part engine : Engine; // 一个复合 Engine 子元素 8 part wheel : Wheel[4]; // 四个复合 Wheel 子元素 9 part chassis : Chassis; 10 }
复合 vs 引用:part vs ref part
两者都是由 Class 类型化的 Feature。区别在于 KerML 的 isComposite 标志:
part—isComposite = true。父级独占子级,子级随父级创建和销毁。ref part—isComposite = false。子级独立存在;父级只持有对它的引用。同一个Person可以同时是多辆车的司机;销毁汽车不会销毁司机。attribute— 由DataType类型化的 Feature(见第 2 节)。没有身份,没有独立存在——只是实例内部的数据。
复合就像焊接在汽车里的发动机:它与汽车共生共死。引用就像坐在车里的司机:他们下车后仍然独立存在。
1 part def Fleet { 2 part car : Car[1..*]; // isComposite=true:被车队拥有 3 ref part driver : Person; // isComposite=false:司机独立存在 4 attribute name : String; // DataType 子元素:Fleet 删除时一同消失 5 } 6 7 // 删除 Fleet 也会删除它的 Car(复合所有权) 8 // 以及 name 値(DataType,没有独立对象)。Driver 不受影响。
| 关键字 | KerML 属性 | 生命周期 | 使用场景 |
|---|---|---|---|
part | isComposite = true | 与父级相同 | 子级是父级物理上的一部分 |
ref part | isComposite = false | 独立于父级 | 子级被共享或独立存在 |
attribute | 由 DataType 类型化 | 与父级相同 | 存储数字、字符串或量 |
每个 part 用法默认多重性为 [1..1]——恰好一个。忘记为可选部件写 [0..1] 或为集合写 [1..*] 是最常见的结构建模错误。
属性与値类型
KerML 来源:attribute def → DataType; attribute → 由 DataType 类型化的 Feature; enum def → 带 EnumerationLiteral 的 DataType
属性存储表征部件特性的数据値。在 KerML 中,它们是由 DataType 类型化的 Feature——DataType 是一种实例不携带身份的 Classifier。像 3.7 或 "Generic" 这样的値不是对象;它们只是属于所属实例的量或标签。
标量値类型——基本 DataType
SysML v2 在 ScalarValues 标准库中提供四种基本标量类型:
| 类型 | 表示的内容 | 典型用途 | 示例字面量 |
|---|---|---|---|
Real | 64 位 IEEE 754 浮点数。不附带单位时覆盖全范围物理量。 | 无量纲比値、原始传感器读数、系数 | 3.14、-0.5、1.0e6 |
Integer | 整数(无小数部分)。精确算法。 | 计数、索引、协议版本号、CAN ID | 4、-1、255 |
String | Unicode 字符序列。 | 标签、标识符、文字描述、供应商名称 | "GPS"、"BoschMotorsport" |
Boolean | 恰好是 true 或 false。 | 标志位、启用/禁用开关、有效性指示 | true、false |
1 private import ScalarValues::*; 2 3 part def Sensor { 4 attribute sampleRate : Real; // 无量纲;实际中优先使用 ISQ::FrequencyValue 5 attribute label : String; // 人可读的名称 6 attribute channelCount : Integer; // 必须是整数 7 attribute enabled : Boolean; // 该传感器当前是否激活? 8 }
仅对无量纲量使用 Real。对于携带单位的物理测量値,请使用 ISQ 类型——见下文。这让工具在模型验证时能检查单位兼容性。
ISQ 量类型——感知物理量的値类型
ISQ(国际量制)标准库为每种物理量定义了带类型的値。每个 ISQ 类型都是一个携带量纲元数据的 DataType:模型知道 MassValue 和 LengthValue 不是同种东西,3.7[V] 不能赋给 MassValue 属性。値的写法是 数字[单位]:
1 private import ISQ::*; // 量类型:MassValue、LengthValue 等 2 private import SI::*; // SI 单位:kg、m、s、A、K 及导出单位
| ISQ 类型 | 物理量 | SI 单位 | 示例赋値 |
|---|---|---|---|
MassValue | 质量 | kg | = 1.2[kg] |
LengthValue | 长度/距离 | m | = 0.35[m] |
TimeValue | 时间/持续时间 | s | = 2.5[s] |
ElectricPotentialValue | 电压 | V | = 3.7[V] |
ElectricCurrentValue | 电流 | A | = 15[A] |
EnergyValue | 能量/功 | J(或 W·h) | = 44.4[W*h] |
PowerValue | 功率 | W | = 250[W] |
FrequencyValue | 频率 | Hz | = 400[Hz] |
PressureValue | 压强 | Pa | = 101325[Pa] |
TemperatureValue | 热力学温度 | K(或 °C) | = 298[K] |
SpeedValue | 速度/速率 | m/s | = 340[m/s] |
AccelerationValue | 加速度 | m/s² | = 9.81[m/s^2] |
ForceValue | 力 | N | = 500[N] |
VolumeValue | 体积 | m³(或 L) | = 0.05[L] |
1 package DroneModel { 2 private import ISQ::*; 3 private import SI::*; 4 5 part def Battery { 6 attribute nominalVoltage : ISQ::ElectricPotentialValue = 22.2[V]; 7 attribute capacity : ISQ::EnergyValue; 8 attribute peakCurrent : ISQ::ElectricCurrentValue; 9 attribute mass : ISQ::MassValue; 10 } 11 12 part def Motor { 13 attribute kv : Real; // 无量纲:RPM/V 14 attribute maxCurrent : ISQ::ElectricCurrentValue; 15 attribute stallTorque : ISQ::TorqueValue; 16 } 17 }
不要对同一物理量混用 ISQ 类型和原始 Real。如果 Battery.voltage 是 ISQ::ElectricPotentialValue,所有赋値或比较它的约束也必须使用兼容单位的値。将裸展 Real 赋给 ISQ 属性是类型错误。
用 attribute def 定义自己的値类型
attribute def 创建一个新的命名 DataType——一种可复用的结构化値类型。当一个概念不只是单个数字时使用它:
1 attribute def GeoCoordinate { 2 private import ISQ::*; 3 attribute latitude : Real; // 度,-90 到 +90 4 attribute longitude : Real; // 度,-180 到 +180 5 attribute altitude : ISQ::LengthValue; 6 } 7 8 attribute def BatteryHealth { 9 attribute stateOfCharge : Real; // 0.0 到 1.0 10 attribute cycleCount : Integer; 11 attribute temperature : ISQ::TemperatureValue; 12 attribute internalResistance : ISQ::ElectricalResistanceValue; 13 } 14 15 part def UAV { 16 attribute homePosition : GeoCoordinate; 17 attribute batteryState : BatteryHealth; 18 }
attribute def 在 KerML 中是 DataType,不是 Class。这意味着 GeoCoordinate 的实例没有身份:两个字段相同的坐标被认为是相等的。不存在“这个特定坐标对象”的概念。如果你需要身份,请改用 part def。
用 enum def 定义枚举
当一个属性只能取一组固定命名値之一时,使用枚举。在 KerML 中,每个字面量是一个 EnumerationLiteral;枚举本身是一个 DataType:
1 enum def FlightMode { 2 enum MANUAL; 3 enum STABILISED; 4 enum AUTO; 5 enum RETURN_TO_HOME; 6 enum EMERGENCY; 7 } 8 9 enum def HealthStatus { 10 enum OK; 11 enum DEGRADED; 12 enum FAILED; 13 } 14 15 part def FlightController { 16 attribute currentMode : FlightMode := FlightMode::STABILISED; 17 attribute systemHealth : HealthStatus := HealthStatus::OK; 18 }
当有效値的集合是封闭的且建模时已知时(飞行模式、运行状态),使用 enum def。当値是测量値或计数(没有固定词汇表)时,使用 Real 或 Integer。对枚举概念避免使用 String——它没有封闭世界语义,无法被工具验证。
四种値赋値方式
| 语法 | 名称 | 回答的问题 | 能否被覆盖? |
|---|---|---|---|
= expr | 绑定値 | 这个値始终是什么? | 不能——永久不变量 |
:= expr | 初始値 | 这个値从什么开始? | 能——实例生命周期内可以改变 |
default = expr | 默认绑定 | 除非特化覆盖,値默认是什么? | 能——子类型可以重定义 |
default := expr | 默认初始 | 除非特化覆盖,値默认从什么开始? | 能——子类型可以重定义 |
想想汽车仪表盘。绑定値就像车轮数量永远是 4——结构不变量。初始値就像出厂时油量从满格开始——使用过程中会变化。默认绑定就像所有车型共用的标准胎压——除非运动车型覆盖它。默认初始就像座椅位置的出厂设置——每个司机都可以更改。
1 part def Motor { 2 attribute cylinders : Integer = 4; // 绑定:始终为4,不可改变 3 attribute currentRPM : Real := 0; // 初始:从0开始,运行时会变化 4 attribute idleRPM : Real default = 800; // 默认绑定:800,子类型可覆盖 5 attribute vendor : String default := "Generic"; // 默认初始:可覆盖的起始値 6 } 7 8 part def RacingMotor specializes Motor { 9 attribute idleRPM : Real = 1200 redefines idleRPM; // 覆盖默认绑定 10 }
= 是永久不变量,不是起始点。写 attribute rpm : Real = 0 意味着转速在整个实例生命周期内都不能偏离零。当你的意思是“从这个値开始,但运行过程中会变化”时,请使用 :=。
流动项(Item)——在部件间流动的事物
KerML 来源:item def → Class(KerML 层与 part def 相同;区别是 SysML 约定)
流动项(item)是在部件之间流动的事物——信号、数据包、流体、物理材料、能量。与 part def 一样,item def 映射到 KerML Class:实例有身份,可以携带属性。与 part def 的区别纯粹是约定——流动项是流中的参与者,而不是持久的结构组件。
部件是管道和泵;流动项是流过它们的东西。燃油管路(part)输送燃油(item)。网线(part)传输数据包(item)。转轴(part)传递扩矩(item)。
定义流动项
1 item def ElectricalPower { 2 private import ISQ::*; 3 attribute voltage : ISQ::ElectricPotentialValue; 4 attribute current : ISQ::ElectricCurrentValue; 5 } 6 7 item def DataPacket { 8 attribute payload : String; 9 attribute checksum : Integer; 10 attribute priority : Integer default = 0; 11 } 12 13 item def Fuel { 14 private import ISQ::*; 15 attribute volumeFlow : ISQ::VolumeFlowRateValue; 16 }
流动项在端口和流中的使用
1 port def PowerPort { 2 out item power : ElectricalPower; 3 } 4 5 part def DriveSystem { 6 part battery : Battery { port powerOut : PowerPort; } 7 part motor : Motor { port powerIn : ~PowerPort; } 8 9 flow of ElectricalPower 10 from battery.powerOut.power 11 to motor.powerIn.power; 12 }
| 概念 | 关键字 | KerML 来源 | 用途 |
|---|---|---|---|
| 流动项定义 | item def | Class | 描述流动事物是什么的模板 |
| 流动项用法 | item | 由 Class 类型化的复合 Feature | 特定上下文中的具体流动参与者 |
| 端口特征 | out item / in item | 带方向的 Feature | 声明端口发送或接收什么,以及方向 |
| 流语句 | flow of X from … to … | ItemFlow | 显式连接两个流动项端点 |
端口与连接
KerML 来源:port def → Type 边界上的带方向 Feature; connect → Connector; interface def → 带 end Feature 的 Association
端口(Port)是部件的定义交互点。在 KerML 中,端口是一个由 Type 拥有的带方向 Feature,位于类型的边界上。连接(Connection)通过 KerML Connector 实例将端口 Feature 链接在一起。
端口定义
1 port def ElectricalPort { 2 out item power : ElectricalPower; // 发送电力 3 in item control : ControlSignal; // 接收控制信号 4 } 5 6 // 共轭 ~ElectricalPort 反转所有方向: 7 // in item power, out item control
部件上的端口
1 part def PowerSupply { port output : ElectricalPort; } // 供方侧 2 part def Controller { port input : ~ElectricalPort; } // 需方侧(共轭)
连接端口
connect 语句创建一个连接两个 Feature 实例的 KerML Connector:
1 part def System { 2 part psu : PowerSupply; 3 part controller : Controller; 4 5 connect psu.output to controller.input; // 匿名 Connector 6 7 connection powerLink : ElectricalInterface // 命名、类型化 Connector 8 connect psu.output to controller.input; 9 }
接口定义
interface def 映射到 KerML Association——一个其实例就是连接本身的 Classifier,带有命名的 end Feature 标识每个参与者:
1 interface def PowerInterface { 2 end port supplier : ElectricalPort; 3 end port consumer : ~ElectricalPort; 4 flow of ElectricalPower from supplier.power to consumer.power; 5 } 6 7 part def System { 8 part psu : PowerSupply; part controller : Controller; 9 interface : PowerInterface 10 connect supplier ::> psu.output 11 to consumer ::> controller.input; 12 }
简单的点对点布线使用裸 connect。当你想记录协议、包含流声明,或在多个子系统中复用接口模式时,使用 interface def + interface。
分解模式
KerML 来源:直接 → 复合 Feature;子集 → Subsetting 关系;特化 → Subclassification;重定义 → Redefinition
四种将系统分解为部件的模式,每种模式映射到不同的 KerML 关系集合。
模式一——直接分解
1 part def AircraftSystem { 2 part airframe : Airframe; 3 part propulsion : PropulsionSystem; 4 part avionics : Avionics; 5 part fuelSystem : FuelSystem; 6 }
模式二——抽象池与子集
声明一个抽象池特征,然后使用 subsets 关键字(KerML Subsetting 关系)引入命名的个体。abstract 关键字强制池被完全覆盖:
1 part def PropulsionSystem { 2 abstract part engine : Engine[1..4]; // 池——必须完全命名 3 part leftEngine : TurboFan subsets engine; // KerML Subsetting 关系 4 part rightEngine : TurboFan subsets engine; 5 }
模式三——特化与重定义
使用 specializes(KerML Subclassification)进行特化,然后使用 redefines(KerML Redefinition)缩窄继承的特征:
1 part def Vehicle { 2 part powertrain : Powertrain; 3 attribute range : ISQ::LengthValue; 4 } 5 6 part def ElectricVehicle specializes Vehicle { 7 part powertrain : ElectricPowertrain redefines powertrain; // 缩窄类型 8 attribute range : ISQ::LengthValue = 500[km] redefines range; // 固定値 9 } 10 11 part def HybridVehicle specializes Vehicle { 12 part powertrain : HybridPowertrain redefines powertrain; 13 }
模式四——多重性驱动的分解
1 part def SolarArray { 2 part panel : SolarPanel[1..*]; // 至少一块板 3 part string : PanelString[2..8]; // 2到8串 4 part inverter : Inverter; // 恰好一个逆变器 5 }
| 模式 | KerML 机制 | 使用场景 | 关键语法 |
|---|---|---|---|
| 直接分解 | 复合 Feature(拥有成员) | 简单的扁平结构 | part x : T; |
| 抽象池 + 子集 | Subsetting 关系 | 从池中命名个体 | abstract part pool : T[n];part x : T subsets pool; |
| 特化 + 重定义 | Subclassification + Redefinition | 通用→具体的逐步精化 | part def Sub specializes Super { part x : NarrowT redefines x;} |
| 多重性驱动 | KerML 多重性 Feature | 数量可变的组件 | part x : T[1..*]; |
完整示例
一个综合了本模块所有内容的无人机系统。注意:末尾的 devUAV 用法使用了 :>> 简写——两种形式都有效;简写在紧凑的用法级覆盖中很常见。
1 package UAVSystem { 2 private import ISQ::*; private import SI::*; private import ScalarValues::*; 3 4 enum def FlightMode { enum MANUAL; enum STABILISED; enum AUTO; enum RTH; } 5 6 // 流动项(KerML Class,约定:流动) 7 item def ElectricalPower { 8 attribute voltage : ISQ::ElectricPotentialValue; 9 attribute current : ISQ::ElectricCurrentValue; } 10 item def ControlCommand { 11 attribute channel : Integer; attribute pwmValue : Integer; } 12 13 // 端口(KerML 带方向 Feature) 14 port def PowerPort { out item pwr : ElectricalPower; } 15 port def MotorPort { in item cmd : ControlCommand; in item pwr : ElectricalPower; } 16 17 // 部件(KerML Class) 18 part def Battery { 19 attribute capacity : ISQ::EnergyValue; 20 attribute nominalVoltage : ISQ::ElectricPotentialValue = 22.2[V]; 21 attribute health : Real default := 1.0; 22 port powerOut : PowerPort; } 23 24 part def FlightController { 25 attribute loopRate : ISQ::FrequencyValue = 400[Hz]; 26 attribute mode : FlightMode := FlightMode::STABILISED; 27 port powerIn : ~PowerPort; 28 port motorCmd : MotorPort[4]; } 29 30 part def Motor { 31 attribute kv : Real; 32 attribute maxCurrent : ISQ::ElectricCurrentValue; 33 port ctrl : MotorPort; } 34 35 part def MotorAssembly { part motor : Motor; part prop : Propeller; } 36 part def Propeller { 37 attribute diameter : ISQ::LengthValue; attribute pitch : ISQ::LengthValue; } 38 39 // UAV:抽象池 + 直接分解 40 part def UAV { 41 attribute mass : ISQ::MassValue; 42 attribute maxPayload : ISQ::MassValue; 43 part battery : Battery; part fc : FlightController; 44 abstract part motorAsm : MotorAssembly[4]; 45 part frontLeft : MotorAssembly subsets motorAsm; // 显式 subsets 46 part frontRight : MotorAssembly subsets motorAsm; 47 part rearLeft : MotorAssembly subsets motorAsm; 48 part rearRight : MotorAssembly subsets motorAsm; 49 connect battery.powerOut to fc.powerIn; 50 connect fc.motorCmd[1] to frontLeft.motor.ctrl; 51 connect fc.motorCmd[2] to frontRight.motor.ctrl; 52 connect fc.motorCmd[3] to rearLeft.motor.ctrl; 53 connect fc.motorCmd[4] to rearRight.motor.ctrl; } 54 55 // 用法级覆盖(此处使用 :>> 简写) 56 part devUAV : UAV { 57 :>> mass = 1.2[kg]; :>> maxPayload = 0.5[kg]; 58 part :>> battery { :>> capacity = 44.4[W*h]; } 59 part :>> fc { :>> loopRate = 500[Hz]; } } 60 }
此模型演示了:enum def(FlightMode)、ISQ 属性、item def(KerML Class,流动约定)、port def(带方向 Feature)、复合分解、显式 subsets 的抽象池、connect(Connector)以及用法级重定义简写。
本模块总结
| SysML v2 概念 | KerML 来源 | 关键规则 |
|---|---|---|
part def | Class | 实例有身份,随时间持续存在 |
part | 复合 Feature(isComposite=true) | 随父级创建和销毁;默认 [1..1] |
ref part | 非复合 Feature(isComposite=false) | 子级独立存在;父级持有引用 |
attribute def | DataType | 无身份——两个相等的値不可区分 |
attribute | 由 DataType 类型化的 Feature | 生命周期与父级相同;物理量使用 ISQ 类型 |
enum def | 带 EnumerationLiteral 的 DataType | 用于封闭的命名値集合 |
item def | Class(流动约定) | KerML 层与 part def 相同;表明流动参与者 |
port def | Type 边界上的带方向 Feature | ~T 共轭反转所有方向 |
connect | Connector | 连接 Feature 实例;类型化连接使用 interface def |
subsets | Subsetting 关系 | 从池中添加命名个体;原始池保留 |
specializes | Subclassification | 子类型继承所有特征;与 redefines 配合使用缩窄 |
redefines | Redefinition | 替换继承的特征;可缩窄类型、多重性或値 |