转自: 么的聊
链接:https://www.jianshu.com/p/a0b4598f928a
虽然用户不需要掌握太多 JSBSim 飞行模拟器的细节,但是了解 JSBSim 的基本工作流程也会对学习帮助很大。本章将介绍 JSBSim 的基本概念。
仿真系统
通过参考坐标系描述不同部件在飞行器模型中的安装位置——都支持英制和国标两种单位制。为了增强 JSBSim 的通用模拟特性,采用属性(properties)作为不同系统之间的参数(parameters / variables)通信接口。飞机和发动机的配置文件都采用属性的形式进行表征。在飞行建模中,数学元素扮演着重要的角色。JSBSim 采用数据表(data tables)存储飞行特性和参数。JSBSim 能够建立任意形式的代数方程,允许在气动力和飞行控制系统中扩展自由度。
坐标系 (Frames of Reference)
在介绍配置文件的语法前,需要首先理解描述飞行器的坐标系统。
-
结构坐标系:
加工制造方使用的坐标系,常用语定义飞机的重心、起落架滚轮、驾驶员视角和推进器等,JSBSim 的配置文件也采用结构坐标系来定义飞机部件的安装位置。X 轴从飞机的头部指向尾部,Y 轴从机身指向右侧(从飞机尾部看),按照右手定则 Z 指向上方。典型的,坐标系原点位于飞机的头部(可以选择为头部的尖端、或者在头部之前的一段距离),X 轴通常与机身的中心线重合,穿过螺旋桨的轮轴或者发动机的轴线。沿 X 轴方向的距离称作 stations;沿 Z 轴方向的距离称作 waterline,沿 Y 轴方向的距离称作 buttline。
值得注意的是,在 JSBSim 中进行飞机建模时,结构坐标系的原点可以在任意位置,因为 JSBSim 内部只使用与重心的相对位置,而不是各部件的坐标位置。 -
体坐标系:
JSBSim中的体坐标系与结构坐标系相似,只是沿着 Y 轴旋转了180度,坐标原点与重心相重合。作用在飞机上的力和力矩都是在体坐标系内进行运算求和的,得到的加速度也是在体坐标系内进行积分求速度的。 -
稳定性坐标系:
与体坐标系相比,稳定坐标系的 X 轴指向相对风速在飞机对称面的投影,Y 轴仍指向右侧机翼,Z 轴遵循右手定则。 -
风速坐标系:
和稳定坐标系相似,只是风速坐标系的 X 轴直接指向相对风速方向,Z 轴与 X 轴垂直,并保持在体坐标系的 XZ 平面(也称作参考平面)内,Y 轴遵循右手定则。
单位制
除非特殊说明,JSBSim都采用英制单位进行内部的计算。但是,在配置文件中也可以输入其他单位制的参数。实践中为避免单位制紊乱,建议总是显式定义单位。采用 unit 属性来定义,例如下面定义翼展长度的语句:
<wingspan unit="FT"> 35.8 </wingspan>
上述语句定义了翼展长度为35.8 Feet。下面等效语句则将长度单位定义为国标m(35.8 feet = 10.91 m):
<wingspan unit="M"> 10.91 </wingspan>
两个语句在 JSBSim 中的效果是相同的,只是采用了两种单位制。JSBSim 中的单位及其缩写分类如下:
- 长度:M KM -> FT IN
- 角度:RAD -> DEG
- 面积:M2 -> FT2
- 体积:CC M3 LTR -> IN3 FT3
- 力:N -> LBS
- 力矩:NM -> FTLBS
- 速度:M/S -> FT/SEC
- 弹簧力:N/M -> LBS/FT
- 阻尼力:N/M/SEC -> LBS/FT/SEC
- 质量:KG -> LBS
- 能量:WATTS -> HP
- 压强:PA ATM -> PSF INHG
通过代码模板的形式展示 JSBSim 中飞行器相关的参数如下:
<metrics>
<wingarea unit="{FT2 | M2}"> {number} </wingarea>
<wingspan unit="{FT | M}"> {number} </wingspan>
<chord unit="{FT | M}"> {number} </chord>
<htailarea unit="{FT2 | M2}"> {number} </htailarea>
<htailarm unit="{FT | M}"> {number} </htailarm>
<vtailarea unit="{FT2 | M}"> {number} </vtailarea>
<vtailarm unit="{FT | M}"> {number} </vtailarm>
<wing_incidence unit="{RAD | DEG}"> {number} </wing_incidence>
<pitot_angle unit="{RAD | DEG}"> {number} </pitot_angle>
<location name="{AERORP | EYEPOINT | VRP}" unit="{IN | M}">
<x> {number} </x>
<y> {number} </y>
<z> {number} </z>
</location>
{other location blocks}
</metrics>
代码中除了飞机的几何参数外,还有三个参考位置:
- AERORP:气动力的作用点,为保证飞行的稳定性,气动力作用点通常在重心之后;
- EYEPOINT:计算飞行员/驾驶仪加速度(G-forces)的点;
- VRP(Virtual Reference Point):JSBSim 输出位置相关参数的对应点,用结构坐标系中的坐标表示。
属性(properties)
仿真系统需要管理大量的状态信息。对于大型的程序而言,数据的管理任务可能导致的问题有一下几类:
- 扩展性下降:若希望添加额外的功能,贡献者可能会觉得越来越难管理数目增加的通信接口;
- 配置性减弱:当对于不同机理(例如,环境变量、自定义文件、命令行选项等)的不同模块进行处理时,运行配置文件会变得越来越难;
- 初始化流程复杂:程序的初始化流程随着模型的复杂度增加而变得复杂,因为部分模块的初始化可能会使用到一些尚未来得及初始化的模块;
- 子工具扩展性差:通过子工具中的脚本、配置文件对程序进行扩展受限于程序提供的状态信息,如果是非代码开发用户则需要等待开发团队添加相应的变量。
属性管理系统(Property Manager system, PM)提供了一个单独的接口,接口允许在程序运行过程中动态地选择状态信息,甚至是生成一个新变量。 其中,动态生成新变量的功能对 JSBSim 的飞行控制系统至关重要,因为组成飞控系统的部分组件(例如,PID控制器、开关、加法器、增益等)只在特定的状态文件中出现。运行过程一旦稀疏地定义了这些组件后,组件本身只是瞬时存在的,但属性管理系统会将各组件的输出值按照属性的方式进行存储。
属性本身是一系列能够选择性可视的全局变量,各属性按照继承性、树状进行分类(类似于Unix的文件系统)。 属性树的结构包含一个根节点和一系列子节点以及终端节点。与Unix的文件系统类似,属性能够被当前节点或根节点引用,属性也能够被嫁接到其他节点上(类似于文件系统中的符号化链接和文件目录)。在 JSBSim 和 FlightGear 的程序代码中,属性被特定的参数广泛地引用。属性能够通过命令行、配置文件和脚本进行分配,甚至一个信道也可以分配属性。属性的命名方式如下:position/h-sl-ft、aero/qbar-psf。
为展示属性和配置文件的功能,以高性能喷气式飞机模型为对象进行描述。假设某一时刻一个新功能开关被添加到飞行控制面板上,例如飞机允许飞行员在飞控系统中进行超量程俯仰。对于 FlightGear 而言,器件面板是由一个配置文件定义的,开关就是在该文件上进行可视化。当进行开关定义时,开关被赋予一个属性名。在 JSBSim 飞行控制的配置部分,器件面板定义文件中一个被赋予该属性名的超量程俯仰开关就能够以通道的形式更新控制率,开关的位置函数能够按照需要的路径进行信息传递。整个功能添加的过程中并不涉及任何的代码编写。
仿真参数的定义既可以在 JSBSim 中,也可以在配置文件中通过属性完成。前文已经提到,属性是用于描述参数的选项,能够通过配置文件、命令行等获取和设置属性。
标准属性指的是那些在任何飞行器中都会出现的属性。但是气动力系数、发动机、推进器、飞控/自动驾驶仪等有时也需要动态定义一些属性。因为在相关的飞机配置文件被完全读入之前,气动力系数、发动机等参数并不是完全知晓的。用户必须知道这些参数对应的属性名,这样才能够对属性进行修改和更新。例如,X-15飞机的飞行控制系统具有以下特性:
<flight_control name="X-15">
<channel name="Pitch">
<summer name="fcs/pitch-trim-sum">
<input>fcs/elevator-cmd-norm</input>
<input>fcs/pitch-trim-cmd-norm</input>
<clipto>
<min>-1</min>
<max>1</max>
</clipto>
</summer>
<aerosurface_scale name="fcs/pitch-command-scale">
<input>fcs/pitch-trim-sum</input>
<range>
<min>-50</min>
<max>50</max>
</range>
</aerosurface_scale>
<pure_gain name="fcs/pitch-gain-1">
<input>fcs/pitch-command-scale</input>
<gain>-0.36</gain>
</pure_gain>
上述代码中的第一个组件 "fcs/pitch-trim-sum" 包含两个已知的静态输入,即 fcs/elevator-cmd-norm 和 fcs/pitch-trim-cmd-norm。第二个组件将第一个组件的输出作为自身的输入,最后一个增益组件又以上一个输出(fcs/pitch-command-scale)作为自身的输入。
至此,用于已经拥有了一种获取JSBSim参数的方法,也了解了飞控系统是如何嵌入到JSBSim系统中。飞控系统中相同的组件也能够用于构建自动驾驶仪等其他子系统
数学表达式:
作者:么的聊
链接:https://www.jianshu.com/p/e3dd2472ef2c
JSBSim 的函数定义方式功能强大,能够在配置文件中定义代数表达式。函数的语法和 MathML (Mathematical Markup Language, www.w3.org/Math/)相似,但是要更简洁。
函数(function)
函数的定义由操作符(operation)、数值(value)、表格(table)和属性(property)组成。当前 JSBSim 支持的操作符包含:
- 求和:sum
- 求乘:product
- 求商:quotient
- 乘方:pow
- 幂指数:exp
- 绝对值:abs
- 三角函数:sin, cos, tan
- 反三角函数:asin, acos, atan, atan2
- 最小、最大值:min, max
- 变量:avg
- 分数:fraction
- 整除:mod
- 随机数:random
- 微积分:difference, integer
在配置文件中,操作符的使用方法如下:
<sum>
<value>3.14159</value>
<property>velocities/qbar</property>
<product>
<value>0.125</value>
<property>metrics/wingarea</property>
</product>
</sum>
上述代码定义的运算或公式如下:
3.14159 + qbar + (0.125 * wingarea)
一个完整的函数定义应当包含函数元素(即 <function ...>)和其他元素两部分,如下文的气动力定义代码所示。值得注意的是,函数定义中只能有一个非选项型元素,如函数定义代码段中顶端处的代数运算符。也就是说, <function> 元素中不能有多个立即的子运算、属性、表格或者数值。几乎所有的情况下,函数元素的第一个运算符都是求乘(product)或者求和(sum),例如:
<function name="aero/coefficient/Clr">
<description>Roll moment due to yaw rate</description>
<product>
<property>aero/qbar-area</property>
<property>metrics/bw-ft</property>
<property>aero/bi2vel</property>
<property>velocities/r-aero-rad_sec</property>
<table>
<independentVar>aero/alpha-rad</independentVar>
<tableData>
0.000 0.08
0.094 0.19
</tableData>
</table>
</product>
</function>
如上述求和以及气动力定义代码所示,函数定义中最低一级总是数值(value)或者属性(property),在最低级别中的元素是不可以自身包含另外元素的。代码也显示,运算符代码段中是可以包含数值、属性、表格和其他运算符的。在运算中可以只包含一个输入,但是这个输入可以是单个变量或属性,也可以是嵌套的子运算(例如求和),再在自运算内包含其他更多的变量。但需要记住的是,只包含一个输入值的运算只有三角函数(atan2除外)。
译者注:
函数定义中提到的数值(value)、属性(property)、表格(table)和运算符(operation)是函数的四类基本元素,对于有一定编程基础的读者,可能保留英文原文更容易说明(下文将保留英文形式)。下面将四类元素进行列表说明:
- 运算符(operation):即加减乘除这些代数运算;
- 数值(value):特指具有固定大小的数字,可以理解为常数;
- 属性(property):程序中生成的相关变量,即上一章属性管理系统中介绍的属性;
- 表格(table):由数值组成的表格,主要应用于插值运算,因此需要声明独立变量(independentVar)。
在函数定义中,元素的表达可以采用缩写形式,当然也只有数值(value)、属性(property)、表格(table)和运算符(operation)四类元素可以采用缩写。例如,上述气动力定义代码段也可等效的写成如下形式:
<function name="aero/coefficient/Clr">
<description>Roll moment due to yaw rate</description>
<product>
<p>aero/qbar-area</p>
<p>metrics/bw-ft</p>
<p>aero/bi2vel</p>
<p>velocities/r-aero-rad_sec</p>
<t>
<independentVar>aero/alpha-rad</independentVar>
<tableData>
0.000 0.08
0.094 0.19
</tableData>
</t>
</product>
</function>
表格(table)
在四个元素中,表格的定义相对特殊。JSBSim 中的表格可以是一维、二维和三维形式,通常用于气动力的插值运算(译者注:这里的表格应当理解为表格和插值运算的结合体)。一个单向量插值运算定义形式如下:
<table>
<independentVar lookup="row">property_name</independentVar>
<tableData>
key_1 value_1
key_2 value_2
... ...
</tableData>
</table>
这里,用于插值的独立变量是可选的,一方面独立变量本身需要进行声明(property_name),另一方面插值表格的矢量形式也可以声明(lookup="row" 选择按行插值)。上述模板表明,以 property_name 为独立变量并且按照行插值的形式进行运算。
一个二维表格的定义如以下代码段所示:
<table>
<independentVar lookup="row">property_name</independentVar>
<independentVar lookup="column">property_name</independentVar>
<tableData>
{col_1_key} {col_2_key} {...} {col_n_key}
{row_1_key} {value_11} {value_12} {...} {value_1n}
{row_2_key} {value_21} {value_22} {...} {value_2n}
{...} ... ... ... ...
{row_n_key} {value_n1} {value_n2} {...} {value_nn}
</tableData>
</table>
如代码所示,二维表格采用的是网格输入形式,分别按照行和列进行二维插值,用于行和列索引的独立变量也需要声明。
三维表格则是将其拆分为多个二维表格的形式进行代码输入,代码段格式如下:
<table>
<independentVar lookup="row">property_name</independentVar>
<independentVar lookup="column">property_name</independentVar>
<independentVar lookup="table">property_name</independentVar>
<tableData breakpoint="table_1_key">
{col_1_key} {col_2_key} {...} {col_n_key}
{row_1_key} {value_11} {value_12} {...} {value_1n}
{row_2_key} {value_21} {value_22} {...} {value_2n}
{...} ... ... ... ...
{row_n_key} {value_n1} {value_n2} {...} {value_nn}
</tableData>
<tableData breakpoint="table_2_key">
{col_1_key} {col_2_key} {...} {col_n_key}
{row_1_key} {value_11} {value_12} {...} {value_1n}
{row_2_key} {value_21} {value_22} {...} {value_2n}
{...} ... ... ... ...
{row_n_key} {value_n1} {value_n2} {...} {value_nn}
</tableData>
...
<tableData breakpoint="table_n_key">
{col_1_key} {col_2_key} {...} {col_n_key}
{row_1_key} {value_11} {value_12} {...} {value_1n}
{row_2_key} {value_21} {value_22} {...} {value_2n}
{...} ... ... ... ...
{row_n_key} {value_n1} {value_n2} {...} {value_nn}
</tableData>
</table>
注意:JSBSim中表格的插值都采用线性内插算法,并不具备外插功能,即输入的最大值只能返回到表格中的最大索引对应数值。
至此,相信读者已经能够在 XML 配置文件中完成数学公式的输入了,后续将围绕具体物理变量开展飞行参数的学习