Objective c 速度Verlet算法:似乎无法确定稳定轨道的正确速度?

Objective c 速度Verlet算法:似乎无法确定稳定轨道的正确速度?,objective-c,game-physics,orbital-mechanics,Objective C,Game Physics,Orbital Mechanics,像许多关于这个主题的帖子一样,我正忙于为自己编写一个精确的模拟器,用于2D引力场中物体的运动 我很早就决定,我会选择Velocity Verlet积分,因为我希望我的物体能够保持稳定的轨道,并在时间步长相当大的情况下保持能量。那么,问题可能是什么 好吧,到目前为止,除了一个组件之外,所有的东西似乎都正常工作。当我试图计算一个稳定轨道在一定距离上的正确速度时,得到的速度会把它们送入奇怪的椭圆轨道,每次都会迅速增大 首先,以下是确定场景中物体下一个位置、速度和加速度的方法:(目标C) 加速: -(C

像许多关于这个主题的帖子一样,我正忙于为自己编写一个精确的模拟器,用于2D引力场中物体的运动

我很早就决定,我会选择Velocity Verlet积分,因为我希望我的物体能够保持稳定的轨道,并在时间步长相当大的情况下保持能量。那么,问题可能是什么

好吧,到目前为止,除了一个组件之外,所有的东西似乎都正常工作。当我试图计算一个稳定轨道在一定距离上的正确速度时,得到的速度会把它们送入奇怪的椭圆轨道,每次都会迅速增大

首先,以下是确定场景中物体下一个位置、速度和加速度的方法:(目标C)

加速:

-(CGVector)determineAccelerationFor:(SKObject *)object
{ // Ok, let's find Acceleration! 
    CGVector forceVector = (CGVector){0,0}; // Blank vector that we will add forces to
    for (SKObject *i in self.sceneObjects)
    {
        if (![i isEqual:object]) // Just make sure we're not counting ourselves here
        {
            CGPoint distance = [self getDistanceBetween:i.position And:object.position]; 
            float hypotenuse = sqrtf(powf(distance.x, 2)+ powf(distance.y, 2));
            float force = ((self.gravity * object.mass * i.mass)/powf(hypotenuse, 3));

            float xMagnitude = (force * distance.x);
            float yMagnitude = (force * distance.y);
            forceVector.dx += xMagnitude;
            forceVector.dy += yMagnitude;
        }
    }
    CGVector acceleration = (CGVector){forceVector.dx/object.mass, forceVector.dy/object.mass};

    return acceleration;
}
酷,所以基本上,我只是拿一个物体,加上其他物体施加在它身上的所有力,然后用X&Y因子除以当前物体的质量,得到加速度

接下来是速度。这里我使用以下等式:

其方法也非常简单:

-(CGVector)determineVelocityWithCurrentVelocity:(CGVector)v OldAcceleration:(CGVector)ao NewAcceleration:(CGVector)a
{
    float xVelocity = (v.dx + ((ao.dx + a.dx)/2) * self.timeStep);
    float yVelocity = (v.dy + ((ao.dy + a.dy)/2) * self.timeStep);
    CGVector velocity = (CGVector){xVelocity,yVelocity};
    return velocity;
}
最后,位置!其方程式为:

用以下方法确定

-(CGPoint)determinePositionWithCurrentPosition:(CGPoint)x CurrentVelocity:(CGVector)v OldAcceleration:(CGVector)ao
{
    float xPosition = (x.x + v.dx * self.timeStep + ((ao.dx * powf(self.timeStep, 2))/2));
    float yPosition = (x.y + v.dy * self.timeStep + ((ao.dy * powf(self.timeStep, 2))/2));
    CGPoint position = (CGPoint){xPosition,yPosition};
    return position;
}
这都是从下面的方法调用的

-(void)refreshPhysics:(SKObject *)object
{

    CGPoint position = [self determinePositionWithCurrentPosition:object.position CurrentVelocity:object.velocity OldAcceleration:object.acceleration]; // Determine new Position



    SKAction *moveTo = [SKAction moveTo:position duration:0.0];
    [object runAction:moveTo]; // Move to new position

    CGVector acceleration = [self determineAccelerationFor:object]; // Determine acceleration off new position

    CGVector velocity = [self determineVelocityWithCurrentVelocity:object.velocity OldAcceleration:object.acceleration NewAcceleration:acceleration];
    NSLog(@"%@ Old Velocity: %f, %f",object.name,object.velocity.dx,object.velocity.dy);
    NSLog(@"%@ New Velocity: %f, %f\n\n",object.name,velocity.dx,velocity.dy);


    [object setAcceleration:acceleration];
    [object setVelocity:velocity];
}
好的,上面这些方法规定了物体在场景中的移动方式。现在进入初始问题,实现稳定轨道这一始终存在的问题

为了确定物体维持轨道的速度,我使用以下等式:

我的实施如下:

-(void)setObject:(SKObject *)object ToOrbit:(SKObject *)parent
{
    float defaultSeparation = 200;
    // Move Object to Position at right of parent
    CGPoint defaultOrbitPosition = (CGPoint){parent.position.x + (parent.size.width/2)+ defaultSeparation,parent.position.y};
    [object setPosition:defaultOrbitPosition];

    // Determine Orbital Velocity
    float velocity = sqrtf((self.gravity * parent.mass)/(parent.size.width/2+defaultSeparation));

    CGVector vector = (CGVector){0,velocity};
    [object setVelocity:vector];
}
出于某种原因,尽管如此,我还是得到了糟糕的结果。以下是一些输出:

信息:

-(CGVector)determineAccelerationFor:(SKObject *)object
{ // Ok, let's find Acceleration! 
    CGVector forceVector = (CGVector){0,0}; // Blank vector that we will add forces to
    for (SKObject *i in self.sceneObjects)
    {
        if (![i isEqual:object]) // Just make sure we're not counting ourselves here
        {
            CGPoint distance = [self getDistanceBetween:i.position And:object.position]; 
            float hypotenuse = sqrtf(powf(distance.x, 2)+ powf(distance.y, 2));
            float force = ((self.gravity * object.mass * i.mass)/powf(hypotenuse, 3));

            float xMagnitude = (force * distance.x);
            float yMagnitude = (force * distance.y);
            forceVector.dx += xMagnitude;
            forceVector.dy += yMagnitude;
        }
    }
    CGVector acceleration = (CGVector){forceVector.dx/object.mass, forceVector.dy/object.mass};

    return acceleration;
}
重力(常数)=1000(用于测试)

质量(母体)=5000个单位

质量(卫星)=1个单位

分离=224像素

它确定为了使卫星绕父卫星轨道运行,速度为:

149.403580像素/时间步

是必需的。这在我的计算器上是正确的

所以这让我有点困惑,到底出了什么问题。我记录了所有关于新速度和位置的输出,它确实使用了我设置的速度,但这似乎没有什么区别。如果有人能帮我找出这里出了什么问题,我将不胜感激


如果有人认为我遗漏了什么,告诉我,我会马上编辑。谢谢

所给数字的周期约为9.4个时间单位。如果你每单位时间只走一步,这可能是你问题的根源。例如,在一个时间单位后,测试粒子(与父粒子相比可忽略的卫星质量极限)应从(x,y)=(224,0)移动到(176139),但算法的第一步将其移动到(174149)。这已经是2.4%的距离误差。缩短时间步是否会让事情变得更好?Simplectic积分器保持误差有界(稳定性),但最终您的方法仅为二阶,因此精度可能是一个问题。@ChrisWhite我可以对此进行测试,但如果您是正确的,如何通过增加时间步长来保持相对快速的模拟而不损失精度?使用更好的语言;老实说,我不知道objective C,但是我可以告诉你,做一个两体(甚至一百体)的模拟,甚至不应该强调以任何合理的“实时”定义运行的现代处理器,这可能是各种高级胡说八道阻碍了计算真正重要的东西的结果。@ChrisWhite我可以用C语言实现它(我在C语言中有一个),但将它与场景中的对象联系起来有困难。好吧,看看小步骤是否能使它工作。优化尚未运行的代码没有什么意义:)