Pull to refresh

Comments 19

Если просто уравнения Эйлера интегрировать, метод четвертого порядка заметно лучше метода второго. Подозреваю, что все-таки у вас где-то есть ошибка

https://gist.github.com/uranix/7c137c2c3a0fb22579f54d96721e69be

Думаю, что ошибка в update - вы сначала обновляете omega, а затем этой обновленной omega доворачиваете углы поворота. Правильно же применять метод интегрирования к совместной системе для углов и скоростей

Думаю, что ошибка в update

К сожалению да, в примере ошибка, которую в коде я давно исправил, а там забыл. В коде сейчас вроде бы корректно.


На момент построения графиков было так:


class State3d(val transform: Transform3d, val velocity: Velocity3d):
  def updated(s: State3dDerivative, dt: Double): State3d =
    State3d(
      transform.copy().update(s.velocity, dt),
      velocity.copy().update(s.acceleration, dt)
    )

Я явно копирую transform и velocity, state3d не меняется, создаётся новая копия.


class Transform3d(val position: Vector3d, val rotation: Quaternion):
  def update(velocity: Velocity3d, dt: Double): Transform3d =
    position.madd(velocity.linear, dt)
    val dRot = Quaternion().setFromExp(velocity.angular * (0.5 * dt))
    dRot *> rotation
    rotation.normalize()
    this

class Velocity3d(val linear: Vector3d, val angular: Vector3d):
  def update(acceleration: Acceleration3d, dt: Double): Velocity3d =
    linear.madd(acceleration.linear, dt)
    angular.madd(acceleration.angular, dt)
    this

Я посмотрел Ваш пример, но в нём производятся вычисления в локальной системе отсчёта и вообще не затрагивается вопрос ориентации тела в пространстве. Попробую его воспроизвести и прям по шагам сравнить вычисления со своими, но не уверен, что быстро найду ошибку.

Сделал в инерциальной системе отсчета
https://gist.github.com/uranix/b101ca6ce8dcc2b616502dd8e9a2f9e9

Тут, конечно, нужно следить за единичностью кватерниона в процессе, иначе она плывет (для Эйлера критично, для остальных терпимо). Но порядок погрешности первых интегралов тот же.

Огромное спасибо, а то я уже отчаялся.


К Вашему коду можно добавить


L0Vec = I0 * w0

def LVec(I0, xs):
    ws = xs[:, :3]
    Rs = R(xs)
    I = np.einsum('m,tim,tjm->tij', I0, Rs, Rs)
    Lvec = np.einsum('tij,tj->ti', I, ws)
    return Lvec

и построить график разницы между начальным L и конечным.


plt.plot(ts4, np.linalg.norm((L4Vec - L0Vec[np.newaxis, :]), axis=1) / L0)

И это то самое место, где мой солвер почему-то теряет точность, а Ваш — нет!

Я смог воспроизвести Ваш способ!
Идея брать производную от кватерниона даже не приходила мне в голову. Что для меня странно — на курсе теормеха кватернионов вообще не было, я их как-то сам потом освоил.


Вместо производной я просто на основе w делал кватернион поворота на приращение угла вокруг оси и домножал на него. Что интересно, на методах второго порядка точности это работает немного лучше или так же.
А вот на Рунге-Кутте четвёртого порядка, видимо, влияет на порядок.


Я добавил новые солверы в код и в графики в ноутбуке — они там с именем типа RungeKutta4Alt.


Точность намного выше, порядка 10^-9 для шага 0.01 и 10^-13 для шага 0.001

А ещё правильней использовать симплектический метод интегрирования (схема Верле, полу-неявный метод Ньютона: у него много названий). Этот метод консервативен (т.е. сохраняет Гамильтониан) по построению.

Большое спасибо за пример!


В Вашем примере в качестве ошибки берётся (|L| — |L0|) / |L0|. Если в моём коде считать ошибку так, то она тоже получется порядка 10^-8.
Но если считать ошибку как |L — L0|/|L0|, то получается, что L отклоняется в сторону и получается ошибка порядка 10^-4.


Я повторил Ваши рассчёты в локальной СО для скорости и ускорений. Они работают с такой же точностью: 10^8 при dt =0.01. И для E, и для модуля L.


После этого я попробовал добавить обновление ориентации. Рассчёты в локальной СО от неё никак не зависят, но станет можно повернуть L из локальной СО в глобальную. В глобальной СО L не должен отклоняться. К сожалению, он отклоняется, и итоговая ошибка тоже получается порядка 10^-4 (как и у меня). По крайней мере, у меня лучше не получилось :(

Раз уж проводится сравнение численных методов интегрирования ДУ, то,вероятно, следует сказать о том, что для немонотонных решений использование постоянного шага - не самая лучшая идея. Есть версии Рунге-Кутта с оценкой ошибки на шаге (версия Мерсона, например). Более естественным является использование многошаговых методов типа Адамса-Башфорта, где оценка ошибки на шаге получается естественным образом.

Лучше использовать роторы из алгебры Клиффорда вместо кватернионов.

А подробнее можно? Чем лучше? Очень интересно. Что такое кватернион я понимаю, а вот ротор из алгербы Клиффорда...

Кватернионы - это подалгебра алгебры Клиффорда, причём кватернионы в трёхмерном пространстве в силу их законов умножения работают в левостороннем базисе. Ротор - это сумма скаляра и бивектора, который действует не только на вектор, но и на другие объекты алгебры.

UFO just landed and posted this here

У double мантисса 52 бита, это примерно 16 значащих цифр. Я думаю, такой точности с запасом хватит почти для всего, кроме каких-то спецефических случаев.

UFO just landed and posted this here

Уместить в одно число и галактические масштабы и сантиметры — это очень спецефическая задача.
Например, расстояние от Солнца до реальной Земли 150 млн км, это 1.5 * 10^8 км = 1.5 * 10^14 мм. Даже в таких масштабах double что-то может.
Если же ограничиться только Землёй c радиусом 6400 км, то это 6.4 * 10^9 мм или 6.4 * 10^15 нм.


KSP внутри сделаны сложнее, чем кажется на первый взгляд: https://www.youtube.com/watch?v=mXTxQko-JH0


Формулы для операций с векторами, матрицами и численным решением диффуров не зависят от того, как представлены числа. Там можно использовать float, double или что Вашей душе угодно.

Довольно интересно, спасибо за труд!

Огромное спасибо за труд ! Сейчас как раз изучаю scala, и одновременно очень активно пишу на scala-js (срочно требуется веб-обёртка для некоей моей приблудины). А тут на scala описана вполне интересная и содержательная тема ! Будет что почитать vscode !

Sign up to leave a comment.

Articles