**
前言
铁路设计院行车专业时长借助牵引电算软件进行列车运行模拟,出于兴趣,本文对多质点列车纵向动力学模型求解过程进行了分析。知网上搜了好多文章,看的不太懂,大多数都是采用Newmark或其它高级方法进行仿真。此文采用简单的动力学方程,以HXD单机,C70型货车54辆编组进行验证学习,纯C#代码实现,没有Matlab或其它仿真软件辅助。内容简单,期待有该方面大佬深入指点一二。模型及仿真按钮图片如下:
补充说明
以下代码在WinForm窗体运行,需要两个控件,Button与ListBox,代码较简单,先读懂再修改运行。
代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TractionCalculation
{
public partial class TrainDynamicsSolver : Form
{
public TrainDynamicsSolver()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
TrainDynamicsSolver solver = new TrainDynamicsSolver();
solver.TimeStep = 0.0000008;
solver.TotalTime = 0.08*2+0.03;
solver.TrainLength = 55;
solver.Mass = new double[(int)solver.TrainLength];
solver.Position = new double[(int)solver.TrainLength];
solver.Velocity = new double[(int)solver.TrainLength];
solver.Force= new double[(int)solver.TrainLength];
solver.couplingForce = new double[(int)solver.TrainLength];
for (int i = 0; i < solver.TrainLength; i++)
{
if (i < solver.TrainLength - 1)
{
solver.Mass[i] = 94;
solver.Position[i] = i * (14 + 14) / 2;
}
else
{
solver.Mass[i] = 150;
solver.Position[i] = 1.0*(14 + 23) / 2 + (solver.TrainLength - 2) * (14 + 14) / 2.0;
}
solver.Velocity[i] = 0;
if (i == solver.TrainLength - 1)
{
solver.Force[i] = solver.GetTractionForce(solver.Velocity[i]);
}
else
{
solver.Force[i] = 0;
}
}
solver.Solve();
// 输出结果
listBox1.Items.Add("迭代完成!!!");
//for (int i = solver.Mass.Length-1; i > -1; i--)
//{
// listBox1.Items.Add("车辆:" + ((solver.Mass.Length - 1) - i)+" "+"位置:"+ solver.Position[i] + " " +"速度:"+ solver.Velocity[i]);
//}
//for (int i = solver.Mass.Length - 1; i >0; i--)
//{
// listBox1.Items.Add("第"+ ((solver.Mass.Length - 1) - i) + "与"+ ((solver.Mass.Length - 1) - i+1) + "辆车"+" 位置差:" + (solver.Position[i]- solver.Position[i-1]) + " " + "速度差:" + (solver.Velocity[i]- solver.Velocity[i-1]));
//}
}
public double TimeStep { get; set; } // 时间步长
public double TotalTime { get; set; } // 总时间
public double TrainLength { get; set; } // 列车长度
public double[] Mass { get; set; } // 各质点质量,以数组形式存储
public double[] Position { get; set; } // 各质点位置,以数组形式存储
public double[] Velocity { get; set; } // 各质点速度,以数组形式存储
public double[] Force { get; set; }//各质点合力,以数组形式存储
public double[] couplingForce { get; set; }//车钩力
//public double a = 0.001;//位移限制数
public double thetaValue=12;//坡度值
public double lengthValue=2.6;//坡度长
public void Solve()
{
int numParticles = Mass.Length; // 质点个数
int numSteps = (int)(TotalTime / TimeStep); // 总步数
StringBuilder[] str = new StringBuilder[Mass.Length];//输出结果
for (int i = 0; i < str.Length; i++)
{
str[i] = new StringBuilder();
}
for (int i = 0; i < numSteps; i++)
{
double[] acceleration = CalculateAcceleration(Position, Velocity, Force,couplingForce); // 计算加速度
for (int j = 0; j < numParticles; j++)
{
Velocity[j] += acceleration[j] * TimeStep * 3600 * 3.6; // 更新速度
Position[j] += (1.0*Velocity[j] / 3.6) * (TimeStep*3600)+ acceleration[j] * (TimeStep*3600) * (TimeStep*3600) * 0.5; // 更新位置
}
// 存储结果
if (i % 475 == 0)
{
for (int j = Mass.Length - 1; j > -1; j--)
{
if (j > 0)
{
str[j].AppendLine("车辆:" + j + " " + "位置:" + Position[j] + " " + "速度:" + Velocity[j] + " " + "车钩力:" + couplingForce[j] +
" " + "位置差" + (Position[j] - Position[j - 1]) + " " + "速度差:" + (Velocity[j] - Velocity[j - 1]));
}
else
{
str[j].AppendLine("车辆:" + j + " " + "位置:" + Position[j] + " " + "速度:" + Velocity[j] + " " + "车钩力:" + couplingForce[j]);
}
}
}
}
for (int i = 0; i < str.Length; i++)
{
//WritetoTxt(i.ToString(),str[i].ToString(), @"C:\Users\Administrator\Desktop\迭代结果\");
}
}
/// <summary>
/// 计算加速度
/// </summary>
/// <param name="position">位置数组</param>
/// <param name="velocity">速度数组</param>
/// <param name="force">合外力数组</param>
/// <returns>加速度数组</returns>
private double[] CalculateAcceleration(double[] position, double[] velocity, double[] netForce,double[] couplingForce)
{
int numParticles = position.Length;
double[] acceleration = new double[numParticles];
// 计算每个质点的加速度
for (int i = 0; i < numParticles; i++)
{
double relativeVelocity, relativeDistance;
if (i == 0) // 第一个质点
{
relativeVelocity = (velocity[i + 1] - velocity[i])/3.6;
relativeDistance = position[i + 1] - position[i] - (14 + 14) / 2.0;
//if(relativeDistance>a)
//{
// position[i]= position[i + 1] - a - (14 + 14) / 2;
// relativeDistance = position[i + 1] - position[i] - (14 + 14) / 2;
//}
if (velocity[i] != 0)
{
if (position[i] > 2.5*1000 && position[i] < (2.5 + lengthValue)*1000)
{
couplingForce[i] = GetCouplingForce(relativeVelocity, relativeDistance);
netForce[i] = couplingForce[i] - GetBasicResistanceForce(i, velocity[i]) -
GetAdditionalResistanceForce(i, thetaValue, 0, double.MaxValue);
}
else
{
couplingForce[i] = GetCouplingForce(relativeVelocity, relativeDistance);
netForce[i] = couplingForce[i] - GetBasicResistanceForce(i, velocity[i]) -
GetAdditionalResistanceForce(i, 0, 0, double.MaxValue);
}
}
else
{
couplingForce[i] = GetCouplingForce(relativeVelocity, relativeDistance);
netForce[i] = couplingForce[i];
}
}
else if (i == numParticles - 1) // 最后一个质点
{
relativeVelocity = (velocity[i] - velocity[i - 1])/3.6;
relativeDistance = position[i] - position[i - 1] - (23 + 14) /2.0;
//if (relativeDistance > a)
//{
// position[i] = position[i - 1] + a + (23 + 14) / 2;
// relativeDistance = position[i] - position[i - 1] - (23 + 14) / 2;
//}
if (velocity[i] != 0)
{
if (position[i] > 2.5 * 1000 && position[i] < (2.5 + lengthValue) * 1000)
{
couplingForce[i] = GetCouplingForce(relativeVelocity, relativeDistance);
netForce[i] = GetTractionForce(velocity[i]) - couplingForce[i] - GetBasicResistanceForce(i, velocity[i]) -
GetAdditionalResistanceForce(i, thetaValue, 0, double.MaxValue);
}
else
{
couplingForce[i] = GetCouplingForce(relativeVelocity, relativeDistance);
netForce[i] = GetTractionForce(velocity[i]) - couplingForce[i] - GetBasicResistanceForce(i, velocity[i]) -
GetAdditionalResistanceForce(i, 0, 0, double.MaxValue);
}
}
else
{
couplingForce[i] = GetCouplingForce(relativeVelocity, relativeDistance);
netForce[i] = GetTractionForce(velocity[i]) - couplingForce[i];
}
}
else // 中间质点
{
double relativeVelocity1;
double relativeDistance1;
relativeVelocity = (velocity[i] - velocity[i - 1])/3.6;
relativeVelocity1 = (velocity[i + 1] - velocity[i])/3.6;
relativeDistance = position[i] - position[i - 1] - (14 + 14) / 2;
//if (relativeDistance > a)
//{
// position[i] = position[i - 1] + a + (14 + 14) / 2;
// relativeDistance = position[i] - position[i - 1] - (14 + 14) / 2;
//}
if (i == numParticles - 2)
{
relativeDistance1 = position[i + 1] - position[i] - (23 + 14) / 2.0;
//if (relativeDistance1 > a)
//{
// position[i] = position[i + 1] - a - (14 + 14) / 2;
// relativeDistance1 = position[i + 1] - position[i] - (23 + 14) / 2;
//}
}
else
{
relativeDistance1 = position[i + 1] - position[i] - (14 + 14) / 2;
//if (relativeDistance1 > a)
//{
// position[i] = position[i + 1] - a - (14 + 14) / 2;
// relativeDistance1 = position[i + 1] - position[i] - (14 + 14) / 2;
//}
}
if (velocity[i] != 0)
{
if (position[i] > 2.5 * 1000 && position[i] < (2.5 + lengthValue) * 1000)
{
couplingForce[i+1] = GetCouplingForce(relativeVelocity1, relativeDistance1);
couplingForce[i] = GetCouplingForce(relativeVelocity, relativeDistance);
netForce[i] = couplingForce[i + 1] - couplingForce[i]
- GetBasicResistanceForce(i, velocity[i]) - GetAdditionalResistanceForce(i, thetaValue, 0, double.MaxValue);
}
else
{
couplingForce[i + 1] = GetCouplingForce(relativeVelocity1, relativeDistance1);
couplingForce[i] = GetCouplingForce(relativeVelocity, relativeDistance);
netForce[i] = couplingForce[i + 1] - couplingForce[i]
- GetBasicResistanceForce(i, velocity[i]) - GetAdditionalResistanceForce(i, 0, 0, double.MaxValue);
}
}
else
{
couplingForce[i + 1] = GetCouplingForce(relativeVelocity1, relativeDistance1);
couplingForce[i] = GetCouplingForce(relativeVelocity, relativeDistance);
netForce[i] = couplingForce[i + 1] - couplingForce[i];
}
}
acceleration[i] = netForce[i] / Mass[i];
}
return acceleration;
}
/// <summary>
/// 获取车钩力
/// </summary>
/// <param name="relativeVelocity">相对速度</param>
/// <param name="relativeDistance">相对位移</param>
/// <returns>车钩力</returns>
private double GetCouplingForce(double relativeVelocity, double relativeDistance)
{
double k = 20000;//单位:KN/m
double d = 5000;//单位:KN/(m/s)
return k * relativeDistance + d * relativeVelocity;
}
/// <summary>
/// 获取机车牵引力
/// </summary>
/// <param name="speed">机车速度值</param>
/// <returns>机车牵引力</returns>
private double GetTractionForce(double speed)
{
if (speed < 10)
speed = 10;
return 288.2 + 99.29 * Math.Cos(0.02518 * speed) + 74.99 * Math.Sin(0.02518 * speed) +
25.03 * Math.Cos(0.05036 * speed) - 12.82 * Math.Sin(0.05036 * speed) + 7.143 * Math.Cos(0.07554 * speed) -
12.57 * Math.Sin(0.07554 * speed);
}
/// <summary>
/// 获取基本阻力
/// </summary>
/// <param name="i">第i个质点</param>
/// <param name="speed">速度</param>
/// <returns>基本阻力</returns>
private double GetBasicResistanceForce(int i, double speed)
{
if (i == Mass.Length - 1)//机车基本阻力
{
return (1.48 + 0.0018 * speed - 0.0003 * speed * speed) * Mass[i] * 9.8 / 1000;
}
else//车辆机车阻力
{
return (1.48 + 0.0018 * speed - 0.0003 * speed * speed) * Mass[i] * 9.8 / 1000;
}
}
/// <summary>
/// 获取附加阻力
/// </summary>
/// <param name="i">第i个质点</param>
/// <param name="theta">坡道附加单位阻力</param>
/// <param name="ls">隧道附加单位阻力</param>
/// <param name="r">曲线附加单位阻力</param>
/// <returns>附加阻力</returns>
private double GetAdditionalResistanceForce(int i, double theta, double ls, double r)
{
return (theta + 0.00013 * ls + 600.0 / r) * Mass[i] * 9.8 / 1000;
}
/// <summary>
/// 获取空气制动力
/// </summary>
/// <returns></returns>
private double GetAirBrakeForce()
{
return 0;
}
/// <summary>
/// 获取动力制动力
/// </summary>
/// <returns></returns>
private double GetDynamicBrakeForce()
{
return 0;
}
/// <summary>
/// 写入文本
/// </summary>
/// <param name="i">车辆序号</param>
/// <param name="strContext">文本内容</param>
/// <param name="strPath">文本路径</param>
private void WritetoTxt(string i,string strContext,string strPath)
{
DirectoryInfo theFolder = new DirectoryInfo(strPath);
if (theFolder.Exists)
{
}
else
{
Directory.CreateDirectory(strPath);
}
using (FileStream fs = new FileStream(strPath +i.ToString()+ ".txt", FileMode.Append, FileAccess.Write, FileShare.Delete | FileShare.ReadWrite))
{
byte[] data = Encoding.UTF8.GetBytes(strContext);
fs.Write(data, 0, data.Length);
fs.Flush();
fs.Close();
}
}
}
}