使用python将Spring物理应用于四元数

使用python将Spring物理应用于四元数,python,numpy,physics,quaternions,Python,Numpy,Physics,Quaternions,我想用python创建一个简单的物理系统,它以与velocity/position类似的方式处理quaternions。它的主要目标是模拟一个被拖动的对象,并试图随着时间的推移赶上另一个对象。模拟使用3个变量:k:弹簧常数,d:阻尼系数,m:拖动对象的质量 使用经典的euler积分,我可以通过以下方法求解位置: import numpy as np from numpy.core.umath_tests import inner1d # init simulation values dt =

我想用python创建一个简单的物理系统,它以与
velocity/position
类似的方式处理
quaternions
。它的主要目标是模拟一个被拖动的对象,并试图随着时间的推移赶上另一个对象。模拟使用3个变量:
k
:弹簧常数,
d
:阻尼系数,
m
:拖动对象的质量

使用经典的euler积分,我可以通过以下方法求解位置:

import numpy as np
from numpy.core.umath_tests import inner1d

# init simulation values
dt = 1./30. # delta t @ 30fps
k = 0.5 # Spring constant
d = 0.1 # Damping
m = 0.1 # Mass

p_ = np.array([0,0,0]) # initial position of the dragged object
p  = np.array([1,2,0]) # position to catch up to, in real life this value could change over time
v  = np.array([0,0,0]) # velocity buffer (init speed is assumed to be 0)

# Euler Integration
n = 200 # loop over 200 times just to see the values converge
for i in xrange(n):
    x  = (p-p_)
    F  = (k*x - d*v) / m # spring force
    v  = v + F * dt # update velocity
    p_ = p_ + v * dt # update dragged position

    print p_ # values oscillate and eventually stabilize to p
    
    
    
这对职位很有用。通过更改
k
d
m
我可以获得更快/更重的结果,总的来说,我对感觉很满意:

现在我想对四元数做同样的事情。因为我没有使用
四元数
做物理的经验,所以我走了一条简单的道路,应用了相同的函数,并做了一些修改来处理
四元数
翻转和规范化

# quaternion expressed as x,y,z,w
q_ = np.array([0., 0., 0., 1.]) # initial quaternion of the dragged object
q  = np.array([0.382683, 0., 0., 0.92388]) # quaternion to catch up to (equivalent to xyz euler rotation of 45,0,0 degrees)
v  = np.array([0.,0.,0.,0.]) # angular velocity buffer (init speed is assumed to be 0)

# Euler Intration
n = 200
for i in xrange(n):
    
    # In a real life use case, q varies over time and q_ tries to catch up to it.
    # Test to see if q and q_ are flipped with a dot product (innder1d).
    # If so, negate q
    if inner1d(q,q_) < 0:
        q = np.negative(q)
    
    x  = (q-q_)
    F  = (k*x - d*v) / m # spring force
    v  = v + F * dt # update velocity
    q_ = q_ + v * dt # update dragged quaternion
    q_ /= inner1d(q_,q_) # normalize
    
    print q_ # values oscillate and eventually stabilize to q
用x,y,z,w表示的四元数 q_u=np.数组([0,0,0,1.])#拖动对象的初始四元数 q=np.数组([0.382683,0,0,0.92388])#要赶上的四元数(相当于45,0,0度的xyz欧拉旋转) v=np.数组([0,0,0,0.])#角速度缓冲器(初始速度假定为0) #欧拉插管 n=200 对于x范围内的i(n): #在现实生活中的用例中,q随时间而变化,q_uu试图跟上它。 #测试以查看q和q_是否用点积翻转(innder1d)。 #如果是,则否定q 如果inner1d(q,q_)<0: q=np.负(q) x=(q-q_389;) F=(k*x-d*v)/m#弹簧力 v=v+F*dt#更新速度 q_=q_+v*dt#更新拖动的四元数 q_/=inner1d(q_,q_)#规格化 打印q#值振荡并最终稳定到q 令我大吃一惊的是,它给了我非常好的结果

因为我凭直觉行事,所以我确信我的解决方案是有缺陷的(比如q和q_是对立的),并且有一种正确/更好的方法来实现我想要的

问题: 模拟四元数上弹簧力的正确方法是什么?该方法考虑(至少)被拖动对象的质量、弹簧刚度和阻尼系数

非常感谢实际的python代码,因为我很难阅读博士论文:)。同样对于我通常提到的
四元数
操作,但请在回答中随意使用任何其他操作。

关于“模拟四元数上弹簧力的正确方法是什么”的问题,回答是正确地写下势能

  • 四元数通过操作为您提供对象的方向

    orientation = vector_part(q_ r q_*)
    
    其中恒星表示共轭,r是一个固定方向(例如“沿z的单位向量”,它在系统中对于所有对象都必须是唯一的)。假设q_,r和q_*的乘法是“四元数乘法”

  • 例如,使用此方向定义能量函数

    energy = dot_product(orientation, unit_z)
    
  • 取能量对四元数的“负导数”,你就有了施加在系统上的力

  • 您当前的代码中有一个“四元数空间中的阻尼振荡器”,这可能是解决问题的一个很好的方法,但它不是对象上的弹簧力:-)

    附言:评论时间太长了,我希望能有所帮助。 PS2:我没有对上面的问题使用直接代码,因为(I)我觉得阅读上面的图书馆文档并不容易,(ii)问题的第一部分是做数学/物理。

    实际上,“更好”在这里是非常主观的

    你是在谋杀四元数的概念,因为你的步长和位移都很小。根据您的应用程序,这实际上可能是可行的(游戏引擎通常利用类似的技巧来简化实时计算),但如果您的目标是准确性,或者您希望增加步长,而不是获得不稳定的结果,则需要使用四元数,因为它们本来就是要使用的

    正如@z0r在评论中解释的,由于四元数通过乘法变换旋转,它们之间的“区别”是乘法逆-基本上是四元数除法

    qinv = quaternion_inverse(q)  # Using Gohlke's package 
    x = quaternion_multiply(q_, qinv)
    
    现在,对于小的θ,
    theta=~sin(θ)
    ,只要差很小,这个
    x
    与减法的结果没有太大差别。像这样滥用“小角度定理”通常用于所有类型的模拟,但重要的是要知道何时打破它们以及它对模型的限制

    加速度和速度仍然在增加,所以我认为这仍然有效:

    F  = (k*x - d*v) / m 
    v  = v + F * dt 
    
    组成单元旋转

    q_ = quaternion_multiply(q_, unit_vector(v * dt)) # update dragged quaternion
    
    同样,对于小角度(即与速度相比,
    dt
    很小),总和和乘积非常接近

    然后,如有必要,像以前一样正常化

    q_ = unit_vector(q_)
    

    我认为这应该行得通,但会比您以前的版本慢一点,并且可能会有非常相似的结果。

    我怀疑您在将四元数与numpy结合使用时领先于我们大多数人。我不确定如何正确地找到
    v
    ,但
    x
    可能应该与,而且
    q\uu
    可能应该使用步进法;我想你偶然发现了一个四元数振荡器的快速数值近似。