如何在Dymos中指定车辆动力学场景下的时变变量取值?
在Dymos中指定时变变量的两种实现方案
针对车辆动力学场景中时变输入(如双移线转向角、车轮位移时序)的需求,以下是基于解析函数和时序数值的具体实现方法:
一、用解析函数定义时变输入
如果时变变量可以用数学表达式描述(比如双移线转向角的分段函数),可以通过自定义OpenMDAO组件封装解析逻辑,再接入Dymos的轨迹流程中。
实现步骤
- 编写自定义组件,以时间
t为输入,输出计算得到的时变变量值; - 将该组件作为外部子系统添加到Dymos的Phase中;
- 把组件输出连接到车辆动力学ODE的对应输入端口。
代码示例(双移线转向角)
import openmdao.api as om import dymos as dm import numpy as np # 封装双移线转向角的解析组件 class DoubleLaneChangeSteering(om.ExplicitComponent): def initialize(self): self.options.declare('num_nodes', types=int) def setup(self): nn = self.options['num_nodes'] self.add_input('t', shape=(nn,), units='s') self.add_output('delta', shape=(nn,), units='rad') # 声明偏导数(用自动微分或手动定义均可) self.declare_partials(of='delta', wrt='t', method='fd') def compute(self, inputs, outputs): t = inputs['t'] # 双移线转向角分段解析逻辑(可根据工况调整参数) t1, t2, t3 = 2.0, 3.0, 5.0 # 分段时间节点 delta_max = np.deg2rad(15) # 最大转向角 outputs['delta'] = np.where(t < t1, 0.0, np.where(t < t2, delta_max * np.sin(np.pi*(t-t1)/(t2-t1)), np.where(t < t3, delta_max * np.cos(np.pi*(t-t2)/(t3-t2)), 0.0))) # 构建Dymos问题 prob = om.Problem() traj = prob.model.add_subsystem('traj', dm.Trajectory()) # 定义包含车辆动力学ODE的Phase phase = traj.add_phase('phase0', dm.Phase(ode_class=VehicleDynamicsODE, # 替换为你的车辆动力学模型 transcription=dm.GaussLobatto(num_segments=10, order=3))) # 添加转向角解析组件作为外部输入 phase.add_external_subsystem('steering_input', DoubleLaneChangeSteering(num_nodes=phase.num_nodes), inputs=['t'], outputs=['delta']) # 连接转向角到车辆模型 phase.connect('steering_input.delta', 'delta') # 设置时间边界 phase.set_time_options(fix_initial=True, fix_duration=True, duration_val=10.0) # 后续配置变量边界、目标函数等... prob.setup() prob.run_model()
二、用时序数值定义时变输入
如果时变变量是离散测试数据(如采集到的转向角时序),可以通过OpenMDAO的插值组件将离散数据转换为Dymos所需的连续时变输入。
实现步骤
- 准备离散时间点数组和对应的变量值数组;
- 使用
InterpolationComp创建插值组件,选择合适的插值方法; - 将插值后的连续输出连接到车辆动力学模型。
代码示例(基于测试数据的转向角插值)
import openmdao.api as om import dymos as dm import numpy as np # 准备离散测试数据 t_data = np.array([0.0, 2.0, 3.0, 5.0, 10.0]) # 离散时间点 delta_data = np.deg2rad(np.array([0.0, 0.0, 15.0, 0.0, 0.0])) # 对应转向角 # 构建Dymos问题 prob = om.Problem() traj = prob.model.add_subsystem('traj', dm.Trajectory()) phase = traj.add_phase('phase0', dm.Phase(ode_class=VehicleDynamicsODE, transcription=dm.GaussLobatto(num_segments=10, order=3))) # 添加插值组件(样条插值保证平滑性) interp_comp = phase.add_external_subsystem('steering_interp', om.InterpolationComp(method='spline', num_nodes=phase.num_nodes, extrapolate=True), inputs={'x': 't'}, outputs={'y': 'delta'}) # 传入离散数据到插值组件 prob.set_val('traj.phase0.steering_interp.x_ref', t_data) prob.set_val('traj.phase0.steering_interp.y_ref', delta_data) # 连接插值后的转向角到车辆模型 phase.connect('steering_interp.y', 'delta') # 设置时间边界 phase.set_time_options(fix_initial=True, fix_duration=True, duration_val=10.0) # 后续配置变量边界、目标函数等... prob.setup() prob.run_model()
关键注意事项
- 解析函数尽量手动定义偏导数,比自动微分更高效稳定;
- 时序数据插值时,优先选择样条插值保证输入平滑,避免车辆模型出现数值震荡;
- 确保输入的时间范围与Dymos Phase的时间区间匹配,减少外推误差。
内容的提问来源于stack exchange,提问作者HMCheong
相关产品推荐
相关产品推荐

