质量-弹簧-阻尼器模型
在本例中,我们将研究两种建模经典动态模型的方法,其中包括使用弹簧和阻尼器将给定质量的单点对象连接到支座上。 在选择具有常数和可变积分步骤的求解器时,让我们运行模型并比较结果。
Pkg.add(["Interpolations"])
gr()
模型描述
动态系统,包括质量、弹簧和阻尼器,通常用于研究振荡过程的性质、运动学和混沌运动的影响(如果有几个物体),或数值积分方法。
我们将考虑方向模型。 msd_causal.engee,其中执行方程的数值积分 .
您可以清楚地看到,如果您从这个公式中表达负载加速度的方程,那么它正是积分器输入的内容。 .
第二种模式 msd_acausal.engee 它是从Engee物理建模库的非定向(非因果)块创建的。 在上部有一个传感器,测量质量相对于支点的运动,以及一个块 SolverConfiguration 它向模型的全局求解器指示,连接到它的信号和块将具有自己的积分器,具有自己的设置。
在模型的底部有一组类似于标准教育插图的元素。 它通过具有刚性的弹簧连接到支撑件上 和具有吸收系数的阻尼器 (可变参数在这些块的属性中指定)。
由于模型的图形性质,这些元素很容易以多种方式排列,并联或串联连接,或多次重复。
设置模型参数
两种型号都使用相同的可变参数:货物重量 m、弹簧刚度 k 和阻尼器的吸收系数 b.
b,k,m = 1,2,3;
创建必要的变量后,您可以通过在变量窗口中更改变量的值来管理模型。 与价值 b=1, k=2, m=3 我们应该观察到一个相当缓慢的惯性过程,具有明显的衰减。
下载和探索模型
使用单行命令,我们将加载(load),或者打开已经加载的模型(open). 这里我们使用单行条件运算符的语法。 x = условие ? если_истинно : если_ложно.
# Однострочная команда для открытия/загрузки модели
mc = "msd_causal" in [m.name for m in engee.get_all_models()] ? engee.open( "msd_causal" ) : engee.load( "$(@__DIR__)/msd_causal.engee" );
ma = "msd_acausal" in [m.name for m in engee.get_all_models()] ? engee.open( "msd_acausal" ) : engee.load( "$(@__DIR__)/msd_acausal.engee" );
让我们看看两个模型中规定了哪些积分器参数。
using DelimitedFiles, DataFrames
# Собрем параметры моделей
mc_dict = engee.get_param( "msd_causal" );
ma_dict = engee.get_param( "msd_acausal" );
df_causal = DataFrame("Свойство"=>collect(keys(mc_dict)), "Направленная модель"=>collect(values(mc_dict)))
df_acausal = DataFrame("Свойство"=>collect(keys(ma_dict)), "Физическая модель"=>collect(values(ma_dict)))
# Таблица для сравнения параметров моделей
df = outerjoin(df_causal, df_acausal, on="Свойство")
# Отсеим свойства модели, которые нас интересуют
params_to_display = ["StartTime", "StopTime", "SolverType", "SolverName", "FixedStep"]
df[in(params_to_display).(df."Свойство"), :]
我们可以看到两个模型具有相同的积分器设置。
实际上,用于物理模型的数值解的算法在块中指定 Solver Configuration,但模型的上层积分器,其接收来自物理子系统的信号并以向量的形式返回测量值,以恒定的步长执行它们的采样 0.01 和。
可变间距模型的执行
让我们运行模型并将结果保存到变量中。 rc 和 ra 分别用于定向和物理模型。
rc = engee.run( "msd_causal" );
ra = engee.run( "msd_acausal" );
执行结果比较:
plot( rc["p"].time, rc["p"].value, title="Положение" )
p_pos = plot!( ra["p"].time, ra["p"].value )
plot( rc["v"].time, rc["v"].value, title="Скорость" )
p_vel = plot!( ra["v"].time, ra["v"].value )
plot( p_pos, p_vel, size=(600,200) )
由于数据是在两个模型中以相同的离散化收集的,我们可以查看算法和物理模型结果之间的差异。
using LaTeXStrings
d_pos = plot( ra["p"].value - rc["p"].value, title=L"\varepsilon_{положение}", legend=false)
d_vel = plot( ra["v"].value - rc["v"].value, title=L"\varepsilon_{скорость}", legend=false )
plot( d_pos, d_vel, size=(600,200) )
结果之间的差异显然很小,值的顺序为 .
让我们看看如果我们将*"算法"*模型切换到物理模型的求解器工作的相同模式会发生什么。
让我们切换到恒步求解器。
切换两种模式的操作模式。 现在,所有求解器都选择最佳步长,并以不同的采样率输出数据。
# Настроим направленную модель так, чтобы она решалась с переменным шагом интегрирования
engee.set_param!( "msd_causal", "SolverType"=>"variable-step" )
engee.set_param!( "msd_acausal", "SolverType"=>"variable-step" )
# Запустим модели
rc = engee.run( "msd_causal" );
ra = engee.run( "msd_acausal" );
为了比较不同分辨率的图形,我们需要插值。
using Interpolations
# Создаем два объекта для интерполяции положения и скорости каузальной модели
rc_p_interp_linear = linear_interpolation(rc["p"].time, rc["p"].value)
rc_v_interp_linear = linear_interpolation(rc["v"].time, rc["v"].value)
# Вычисляем разницу между интерполяцией и расчетом физической системы
e_pos = plot( ra["p"].time, ra["p"].value - rc_p_interp_linear.(ra["p"].time), title=L"\varepsilon_{положение}", legend=false )
e_vel = plot( ra["v"].time, ra["v"].value - rc_v_interp_linear.(ra["v"].time), title=L"\varepsilon_{скорость}", legend=false )
plot( e_pos, e_vel, size=(600,200) )
这一次,物理模型和定向模型之间的差异要小得多-差异有一个数量级。 .
Engee具有内置的数据检查器,可让您将不同的启动结果相互比较。
在不保存的情况下关闭模型
如果我们以后想从一开始就再次运行这个例子,那么我们需要关闭模型而不保存所做的更改。
engee.close( "msd_causal", force=true );
engee.close( "msd_acausal", force=true );
结论
与定向模型不同,物理模型通常不能使用具有恒定积分步骤的求解器来求解。 替代隐式初始条件的困难可能导致数值不稳定,例如无限梯度。
探索不同性质的模型并以自动化方式应用各种集成方法的能力使我们能够在两个方面选择最优解:最容易理解的建模形式主义和最稳定的求解器。


