using System;
using System.Numerics;
namespace ActiveProtect.Utility
{
public static class MotionAlgorithm
{
///
/// 计算抛物线弹道最佳发射方向(选择较小的仰角)
///
/// 发射位置
/// 目标位置
/// 初始速度
/// 最佳发射方向,如果无解则返回null
public static (Orientation? orientation, Vector3D? velocity) CalculateBestLaunchOrientation(Vector3D startPos, Vector3D targetPos, double initialSpeed)
{
// 计算水平距离
double dx = targetPos.X - startPos.X;
double dz = targetPos.Z - startPos.Z;
double horizontalDistance = Math.Sqrt(dx * dx + dz * dz);
// 计算高度差
double dy = targetPos.Y - startPos.Y;
double[]? angles = CalculateLaunchAngles(initialSpeed, horizontalDistance, dy);
if (angles == null)
{
Console.WriteLine("无法计算发射角度");
return (null, null);
}
double bestAngle = Math.Min(angles[0], angles[1]);
double azimuth = Math.Atan2(dz, dx);
// 计算初始速度分量
double vx = initialSpeed * Math.Cos(bestAngle) * Math.Cos(azimuth);
double vy = initialSpeed * Math.Sin(bestAngle);
double vz = initialSpeed * Math.Cos(bestAngle) * Math.Sin(azimuth);
// 返回方向和速度
return (new Orientation(bestAngle, azimuth, 0), new Vector3D(vx, vy, vz));
}
///
/// 计算抛物线弹道发射角度
///
/// 初始速度(m/s)
/// 目标点x坐标(m)
/// 目标点y坐标(m)
/// 重力加速度(m/s²)
/// 两个可能的发射角度(弧度),如果无解则返回null
public static double[]? CalculateLaunchAngles(double v0, double x, double y, double g = 9.81)
{
double v0_2 = v0 * v0;
double v0_4 = v0_2 * v0_2;
double discriminant = v0_4 - g * (g * x * x + 2 * y * v0_2);
if (discriminant < 0)
{
Console.WriteLine("无实数解 - 目标不可达");
return null;
}
double angle1 = Math.Atan((v0_2 + Math.Sqrt(discriminant)) / (g * x));
double angle2 = Math.Atan((v0_2 - Math.Sqrt(discriminant)) / (g * x));
//Console.WriteLine($"计算得到的两个角度: {angle1 * 180 / Math.PI:F2}° 和 {angle2 * 180 / Math.PI:F2}°");
return new[] { angle1, angle2 };
}
///
/// 使用运动学定律计算导弹运动状态,用于无制导状态(无制导时,使用该方法可以降低计算量)
///
/// 当前位置
/// 当前速度
/// 加速度(通常包含重力加速度)
/// 时间步长
/// 包含新位置和新速度的元组
public static (Vector3D newPosition, Vector3D newVelocity) CalculateBallisticMotion(
Vector3D currentPosition,
Vector3D currentVelocity,
Vector3D acceleration,
double deltaTime)
{
// 使用标准运动学方程
Vector3D newPosition = new(
currentPosition.X + currentVelocity.X * deltaTime + 0.5 * acceleration.X * deltaTime * deltaTime,
currentPosition.Y + currentVelocity.Y * deltaTime + 0.5 * acceleration.Y * deltaTime * deltaTime,
currentPosition.Z + currentVelocity.Z * deltaTime + 0.5 * acceleration.Z * deltaTime * deltaTime
);
Vector3D newVelocity = new(
currentVelocity.X + acceleration.X * deltaTime,
currentVelocity.Y + acceleration.Y * deltaTime,
currentVelocity.Z + acceleration.Z * deltaTime
);
return (newPosition, newVelocity);
}
///
/// 使用四阶龙格库塔法计算物体运动状态,用于有制导状态
///
/// 时间步长
/// 导弹位置
/// 导弹速度
/// 导弹加速度
/// 新的位置和速度
public static (Vector3D newPosition, Vector3D newVelocity) RungeKutta4(double deltaTime, Vector3D position, Vector3D velocity, Vector3D acceleration)
{
// 定义一个局部函数来计算加速度
Vector3D AccelerationFunction(Vector3D pos, Vector3D vel)
{
// 这里可以添加更复杂的加速度计算,比如考虑空气阻力等
return acceleration;
}
// 第一步
Vector3D k1v = AccelerationFunction(position, velocity) * deltaTime;
Vector3D k1r = velocity * deltaTime;
// 第二步
Vector3D k2v = AccelerationFunction(position + k1r * 0.5, velocity + k1v * 0.5) * deltaTime;
Vector3D k2r = (velocity + k1v * 0.5) * deltaTime;
// 第三步
Vector3D k3v = AccelerationFunction(position + k2r * 0.5, velocity + k2v * 0.5) * deltaTime;
Vector3D k3r = (velocity + k2v * 0.5) * deltaTime;
// 第四步
Vector3D k4v = AccelerationFunction(position + k3r, velocity + k3v) * deltaTime;
Vector3D k4r = (velocity + k3v) * deltaTime;
// 计算新的位置和速度
Vector3D newPosition = position + (k1r + k2r * 2 + k3r * 2 + k4r) / 6;
Vector3D newVelocity = velocity + (k1v + k2v * 2 + k3v * 2 + k4v) / 6;
return (newPosition, newVelocity);
}
///
/// 计算比例导引加速度
///
/// 比例导引系数
/// 导弹位置
/// 导弹速度
/// 目标位置
/// 目标速度
/// 比例导引加速度
public static Vector3D CalculateProportionalNavigation(double proportionalNavigationCoefficient, Vector3D missilePosition, Vector3D missileVelocity, Vector3D targetPosition, Vector3D targetVelocity)
{
// 预测时间(预测目标前进方向该时间后到达的位置,可以调整)
double predictionTime = 0.01;
// 预测目标位置
Vector3D predictedTargetPosition = targetPosition + targetVelocity * predictionTime;
Vector3D r = predictedTargetPosition - missilePosition;
Vector3D v = targetVelocity - missileVelocity;
Vector3D LOS = r.Normalize();
Vector3D LOSRate = (v - (LOS * Vector3D.DotProduct(v, LOS))) / r.Magnitude();
Vector3D acceleration = Vector3D.CrossProduct(Vector3D.CrossProduct(LOS, LOSRate), missileVelocity.Normalize()) * proportionalNavigationCoefficient * missileVelocity.Magnitude();
return acceleration;
}
///
/// 添加高斯噪声
///
/// 向量
/// 添加高斯噪声后的向量
public static Vector3D AddRandomPerturbation(Vector3D vector)
{
Random random = new();
// 添加高斯噪声
double sigma = 0.1; // 扰动标准差
// 使用Box-Muller变换来生成高斯随机数
double u1 = random.NextDouble(); // 生成[0, 1)之间的随机数
double u2 = random.NextDouble(); // 生成[0, 1)之间的随机数
double r = Math.Sqrt(-2.0 * Math.Log(u1));
double theta = 2.0 * Math.PI * u2;
double gaussianX = r * Math.Cos(theta);
double gaussianY = r * Math.Sin(theta);
// 由于我们需要三个高斯随机数,我们将再次生成
u1 = random.NextDouble(); // 生成[0, 1)之间的随机数
u2 = random.NextDouble(); // 生成[0, 1)之间的随机数
r = Math.Sqrt(-2.0 * Math.Log(u1));
theta = 2.0 * Math.PI * u2;
double gaussianZ = r * Math.Cos(theta);
// 将高斯随机数转换为指定标准差的高斯随机数
gaussianX *= sigma;
gaussianY *= sigma;
gaussianZ *= sigma;
return new Vector3D(
vector.X + gaussianX,
vector.Y + gaussianY,
vector.Z + gaussianZ
);
}
}
}