Почему мой двойной маятник теряет энергию? Написан на С++

Я попытался написать физически точный двойной маятник. И я нашел метод под названием XPBD. https://matthias-research.github.io/pages/publications/XPBD.pdf вы можете прочитать это отсюда.

https://thewikihow.com/video_EzuNFaqsfEY

Как видно на видео, система со временем теряет энергию. Я думаю, что это связано с ограничением длины в классе Spring, но я не смог найти свою ошибку. Как заставить систему работать правильно без потери энергии?

void Spring::solveForConstraints(float dt) {

    Vector2Custom diffVector = end_p->pos - start_p->pos;
    double currentLen = diffVector.Length();

    double a_hat = inverseStiffnes / (dt * dt);
    double w1 = start_p->invMass;
    double w2 = end_p->invMass;


    if (currentLen != originalLen) {


        double lambda = 0;
        double lambda_delta;

        for (int k = 0; k < 8; k++)
        {

            double C = (end_p->pos - start_p->pos).Length() - originalLen;

            Vector2Custom delta_C1 = (start_p->pos - end_p->pos).Normalize();
            Vector2Custom delta_C2 = (end_p->pos - start_p->pos).Normalize(); // -delta_C1

            // formula from paper   delta_x = inverseMass * delta_C * delta_lambda;
            // formula from paper   delta lambda = (-C - â * lambda) / (delta_C * inverseMass  + a_hat);



            if ((!start_p->isFixed) && (!end_p->isFixed)) { // w1 / (w1+ w2) * (l-l0 ) * diffvectorNormalized


                lambda_delta = (-C - a_hat * lambda) / (delta_C1.DotProduct(delta_C1 * w1) + delta_C2.DotProduct(delta_C2 * w2) + a_hat);
                lambda += lambda_delta;

                Vector2Custom delta_x1 = delta_C1 * lambda_delta * w1;
                Vector2Custom delta_x2 = delta_C2 * lambda_delta * w2;

                start_p->pos = start_p->pos + delta_x1;
                end_p->pos = end_p->pos + delta_x2;


            }
            else if (!start_p->isFixed) {

                lambda_delta = (-C - a_hat * lambda) / (delta_C1.DotProduct(delta_C1 * w1) + a_hat);
                lambda += lambda_delta;

                Vector2Custom delta_x1 = delta_C1 * lambda_delta * w1;

                start_p->pos = start_p->pos + delta_x1;

            }
            else if (!end_p->isFixed) {

                lambda_delta = (-C - a_hat * lambda) / (delta_C2.DotProduct(delta_C2 * w2) + a_hat);
                lambda += lambda_delta;

                Vector2Custom delta_x2 = delta_C2 * lambda_delta * w2;

                end_p->pos = end_p->pos + delta_x2;

            }
        }
    }
}

часть, где я взял формулы

формулы 17 и 18 — это то, что я пытался сделать.

для лучшего понимания. есть алгоритм ниже

алгоритм

Ниже я вызываю функцию.


        // Update 
        int substeps = 10;
        float dt_sub = dt / substeps;

        for (int j = 0; j < substeps; j++)
        {

            //Verlet Integration
            // First, guess where is particles is going to be.

            for (int i = 1; i < numOfParticles; i++)
            {
                Particle* currentBall = &ParticleList[i];

                Vector2Custom accVector = gravVec * currentBall->invMass;               //acceleration vector  a = F/m 
                currentBall->pos = currentBall->pos + accVector * (dt_sub * dt_sub);    //add acc * dt * dt 
                currentBall->pos = currentBall->pos + currentBall->speed * dt_sub;      //add speed * dt

            }

            // Solve lenght Constraints
      
            for (int j = 0; j < springList.size(); j++)
            {
                springList[j].solveForConstraints(dt_sub);
            }

            //Update velocity
            for (int i = 1; i < numOfParticles; i++)
            {
                Particle* currentBall = &ParticleList[i];
                currentBall->speed = (currentBall->pos - currentBall->old_pos) / dt_sub;
                currentBall->old_pos = currentBall->pos;

            }

        }


Как исправить формулу, если я использую ее неправильно?

Я предполагаю, что это просто ошибки округления, подобные дополнительные вычисления имеют тенденцию усиливать ошибки с плавающей запятой en.wikipedia.org/wiki/Floating-point_error_mitigation

Alan Birtles 28.07.2024 17:23

@AlanBirtles, но в этом видео youtube.com/watch?v=9gQQAO4I1Ck&t=314s pezza использует тот же метод xpbd. Его маятник работает нормально.

Hero-- 28.07.2024 17:50

Пробовали ли вы запустить их код и измерить энергию так же, как вы?

Alan Birtles 28.07.2024 17:55

Я пытался запустить, но не смог заставить его работать. Репо для меня сложен. Но сейчас попробую еще раз запустить.

Hero-- 28.07.2024 17:57

Сначала замените все float на double. Тип float часто недостаточно точен для научных вычислений.

prapin 28.07.2024 18:05

Я заменил floats на double, но, похоже, ничего не изменилось.

Hero-- 28.07.2024 18:18

@AlanBirtles Репо очень сложное и нет объяснений. Я смог его построить, но он не работает. Есть ли у вас другие предложения?

Hero-- 28.07.2024 23:17

Какое отношение пружина имеет к двойному маятнику?

lastchance 28.07.2024 23:37

@lastchance — это просто имя класса для ограничения длины. Вы можете установить жесткость ограничения. Если inverseStiffnes равен нулю, он ведет себя как твердая палка.

Hero-- 28.07.2024 23:46

Мне следует просто использовать уравнения Эйлера-Лагранжа для двух степеней свободы; (например, два угла, образуемые стержнями маятника с вертикалью). Тогда вы гарантированно сэкономите электроэнергию. Каким бы ни был ваш метод, вам лучше включить в свой пост фактические уравнения, которые вы используете (чтобы их не вытащили из чьего-либо исследовательского отчета), и представить полный код, который действительно можно использовать для его запуска.

lastchance 29.07.2024 18:50

@lastchance Когда я использую уравнения Эйлера-Лагранжа, смогу ли я переместить точку, на которой она висит? Мне нужна система, которая реагирует на движение точки?

Hero-- 30.07.2024 09:59

Да, вы можете переместить точку (горизонтальный импульс сохранится, как и энергия), но не могли бы вы четко сформулировать свою проблему в своем вопросе.

lastchance 30.07.2024 10:46
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
12
94
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Фактически в статье говорится, что потеря энергии будет ограничением метода XPBD:

5 Демпфирование

Наш метод основан на неявной схеме временного шага, которая естественно включает в себя некоторую диссипацию механической энергии. Тем не менее, может быть полезно смоделировать дополнительное демпфирование ограничений[....]

Ожидаются потери энергии.

Возможно вы и правы, но потери энергии были очень велики, поэтому я и задал вопрос. Я установил номер подшага равным 10, когда я увеличил его до 6000, производительность снизилась, но точность значительно возросла. Я думаю, в этом была проблема.

Hero-- 30.07.2024 10:02

Другие вопросы по теме