Физический движок для железнодорожного транспорта

Здравствуйте.
В данной статье представлена концепция написания физического движка для железнодорожного транспорта.
Одна из главных задач, которую должен решать данный физический движок – это расчет взаимодействия между вагонами.


Определение коллизий


Железную дорогу можно представить в виде графа, узлами которого являются стрелки. При переводе стрелка соединяет две дуги графа и разрывает связь с третьей. Кривая, состоящая из нескольких дуг графа, по которым может проехать вагон без перевода стрелок, далее будет называться «маршрут».
Взаимодействие между вагонами на одном маршруте происходит в одномерном пространстве. На момент перевода стрелки можно вычислить: какой вагон находится впереди и позади данного вагона. Пока стрелка на маршруте не будет переведена, связи какой вагон спереди, а какой сзади, остаются неизменными.
В трехмерном пространстве остаются проверки боковых столкновений, когда пути проходят очень близко. В таких местах вагоны на разных маршрутах не смогут разъехаться и столкнуться. Для оптимизации расчетов в трехмерном пространстве можно разбить площадь на клеточки и искать столкновения вагонов в рамках данной и соседних клеточках. При этом боковые столкновения между вагонами на одном маршруте проверять не нужно.
Вышеперечисленные методы оптимизации расчетов позволяют сделать сложность алгоритма поиска коллизий практически линейно зависимой от количества вагонов.

Концепция взаимодействия вагонов, находящихся на одном «маршруте»



Вагон постоянно обладает импульсом mv.
В момент времени t рассчитываем суммарный вектор сил F=ma. Который изменяет импульс P=mv за этот промежуток времени по формуле:
a=F/m;
v = (v + a*t);
P = m*v;

Где: a – ускорение, m – масса вагона, v – скорость вагона

Взаимодействие с другими вагонами происходит путем передачи импульса между ними.
Алгоритм взаимодействия между вагонами сводится к решению нескольких задач.

Задача:
Необходимо рассчитать координаты и импульсы вагонов через время t. t — интервал времени меньше секунды.
Решение:
Попарно сравниваем все вагоны. Расстояние между вагонами S.
Если расстояние между вагонами сокращается (вагоны идут навстречу друг другу, или один вагон догоняет другой вагон), рассчитываем, сколько времени нужно, чтобы они столкнулись. Находим такое минимальное время tстолкновения.
Ели один вагон сцеплен с другим, и они удаляются друг от друга, то находим, сколько времени требуется, чтобы натянулась автосцепка. Находим минимальное время натяжения автосцепки tнатяжения.
Находим минимальное время взаимодействия между вагонами: tвзаимодействия= min(tстолкновения, tнатяжения).
Если tвзаимодействия>t, то двигаем вагоны на время t и завершаем алгоритм.
Иначе, объединяем столкнувшиеся вагоны в группу, считаем для них общий импульс. Вычитаем время из интервала t=t- tвзаимодействия.
Двигаем все вагоны на расстояние, которое они пройдут в течении времени tвзаимодействия.
Повторяем операцию алгоритма взаимодействия между вагонами, группу считаем как единое целое. При этом если сталкивается группа вагонов с другим телом, и в группе есть натянутая автосцепка, то группы должны быть снова разбиты на отдельные вагоны, так как вагоны внутри группы могут сблизиться.

Упрощения: Так как t – малый промежуток времени, считаем, что импульс вагона изменяется совокупной силой моментально, при этом сила остается неизменной, даже не смотря на то, что вагон меняет координаты и, следовательно, для него меняется профиль пути (наклон, разница высот). Чтобы увеличить точность можно разбить интервал t на менее длинные промежутки времени и последовательно запустить алгоритм несколько раз.

Задача: Расчет времени до столкновения вагонов.
Есть два вагона или группы вагонов. Между их ближайшими друг к другу точками есть некоторое расстояние S

Вагоны имеют некоторую координату X. Значение координаты X у «Вагона 2» больше чем у «Вагона 1». Движение направленное условно вправо будем считать положительным, влево – отрицательным.
Вагон обладает ускорением и начальной скоростью на момент начала вычислительной итерации. Начальная скорость будет обозначаться v1 и v2, ускорение вагонов a1 и a2 соответственно для первого и второго вагона.
Чтобы вагоны столкнулись, они должны сократить расстояние S за некоторое время t. Решение задачи сводится к нахождению времени t.
Упрощение:
Так как временной интервал одной итерации расчетов вычислительной системы может быть достаточно малым, считаем, что профиль пути и прочие внешние факторы, влияющие на вагоны, не могут сильно измениться за этот промежуток времени. Поэтому ускорение на одну итерацию расчета будем считаться постоянным.
Так же в данном алгоритме не учитывается специфика силы трения. Сила трения направлена против движения. И если вагон меняет направления под действием каких-либо сил, то ускорение в этот момент должно значительно измениться, так сила трения поменяет свое направление и окажет свое влияние на ускорение.
Решение:
Каждый вагон до столкновения переместится:
Первый вагон на S1 = v1*t+a1*t*t/2
Второй вагон на S2 = v2*t+a2*t*t/2
Начальное расстояние между вагонами до столкновения есть разница перемещения первого и второго вагона.
S=S1-S2;
S=(v1-v2)*t+(a1-a2)*t*t/2
Получаем квадратное уравнение. Корень этого уравнения будет решением задачи.
Блок схема алгоритма изображена на рисунке. Реализация данного алгоритма на C# изображена в листинге.


/// <summary>
/// Расчет времени до столкновения двух групп вагонов
/// </summary>
/// <param name="s">
/// расстояние между крайними ближайшими друг к другу точками 
/// 2-х вагонов в метрах</param>
/// <param name="v1">скорость первого вагона м/с</param>
/// <param name="v2">скорость второго вагона м/с</param>
/// <param name="a1">ускорение первого вагона м/(с*с)</param>
/// <param name="a2">ускорение второго вагона м/(с*с)</param>
/// <returns>
/// Возвращает время в секундах до столкновения двух групп вагонов. 
/// Если столкновение не произойдет в ближайшее время при заданной траектории движения
/// То может вернуть значение бесконечность (double.PositiveInfinity)
/// </returns>
public static double ClashTime(double s, double v1, double v2, double a1, double a2){
    double A = (a1 - a2) / 2;
    double B = v1 - v2;
    double T;
    if (Math.Abs(A) < 0.000001)    {
        if (Math.Abs(B) < 0.000001)        {
            T = double.PositiveInfinity;
        }
        else        {
            T = s / B;
        }
    }
    else    {
        //Дискриминант квадратного уравнения
        double D = B * B + 4 * A * s;
        if (D < 0)        {
            T = double.PositiveInfinity;
        }
        else        {
            double pD = Math.Sqrt(D) / (2 * A);
            double pB = -B / (2 * A);
            double t1 = pB + pD;
            double t2 = pB - pD;
            if (t1 >= 0)            {
                if (t2 >= 0)
                    T = Math.Min(t1, t2);
                else T = t1;
            }
            else            {
                if (t2 >= 0)
                    T = t2;
                else T = double.PositiveInfinity;
            }
        }
    }
    return T;
}


Задача: Расчет времени до остановки или смены направления движения вагонов
Есть вагон или группа вагонов движущаяся вместе. Вагон имеет начальную скорость V. На вагон действуют различные силы, которые придают ускорения A и сила трения, которая придает ускорение Atr.
Вагон имеет некоторую координату X. Значение координаты X возрастает при движении условно вправо и уменьшается при движении условно влево. То есть направленное условно вправо будем считать положительным, а влево – отрицательным.
Необходимо узнать, сколько времени потребуется, чтобы вагон сменил направление движения или остановился.
Упрощение:
Так как временной интервал одной итерации расчетов вычислительной системы может быть достаточно малым, считаем, что профиль пути и прочие внешние факторы, влияющие на вагоны, не могут сильно измениться за этот промежуток времени. Поэтому ускорение на одну итерацию расчета будем считаться постоянным.
Решение:
Сила трения направлена против направления движения. Поэтому для решения этой задачи нужно найти такой время, при котором скорость снизится до нуля.
KofTr – коэффициент, обозначающий направления силы трения
A – ускорение проекции суммы всех сил, кроме силы трения
Если V>0 то KofTr = -1 иначе KofTr = 1
V0+A*T+ KofTr*Atr*T=0
V0+T*(A+ KofTr*Atr)=0
T=-V0/(A+ KofTr*Atr);

/// <summary>
/// Расчет времени до остановки или смены 
/// направления движения для группы вагонов
/// </summary>
public static double StoppingTime(double frictionForceAcceleration,
    double otherForcesAcceleration, double speed) 
{
    double Atr = Math.Abs(frictionForceAcceleration);
    double A = otherForcesAcceleration;
    double V = speed;
    double KofTr;
            
    if (V == 0) 
        return 0;
            
    if (V > 0) 
        KofTr = -1; 
    else 
        KofTr = 1;
            
    double a = (A+ KofTr*Atr);

    //Если a = 0, скорость не изменяется 
    if (Math.Abs(a) < 0. 0000001)
        return double.PositiveInfinity;

    //Если V и a направлены в одну сторону 
    if (a * V > 0) 
        return double.PositiveInfinity;

    double t = -V / a;
    return t;
}


Расчет влияния силы тяжести на один вагон


Расчет силы трения, действующий на один вагон


Расчет смещения вагона или связанной группы вагонов


Конечно, это еще только маленькая часть физического движка для железной дороги, об остальном в следующей статье.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 20

    +13
    А ваш движок может смоделировать замечательный бегущий БАБАМ, когда грузовой состав начинает трогаться и импульс передается вдоль поезда? :)
      +6
      В движке учтен люфт автосцепки, из-за чего есть следующий эффект:
      Когда автосцепка в составе сжата, а локомотив начинает тащить вагоны, то вагоны начинают двигаться не одновременно, а последовательно, по мере натяжения автосцепки.
      Если я правильно понял, это то, о чем вы говорите.
      Тем не менее, звук в движке я не делал, для моей задачи это было не нужно. Думаю, там много нюансов.
        +1
        Кстати, для ещё большей правдоподобности я бы еще добавил учет растяжения/сжатия стальной рамы вагона (для расчета использовать длину от сцепки до сцепки, модуль упругости ну и сила, действующая на данный вагон).
          0
          А ещё модуль линейного расширения металла под воздействием температуры (Эйфелева башня, как мы знаем, ± 20 см гуляет зимой/летом)
            0
            Вполне достаточно реализовать работу поглощающего аппарата автосцепки — его растяжение в сотни раз больше.
          +12
          А еще тыдым-тыдым колес по рельсам надо обязательно делать, иначе никакого удовольствия ;)
            +1
            Сейчас рельсы сваривают между собой, так что тыдым-тыдым уже нет. Точнее есть, но он совсем малозаметный на поездах.
              +6
              Пару недель назад ездили в командировку на поезде. Тыдым-тыдым в пути присутствовал и вполне себе заметный.
                +2
                Это да. Но к счастью дорог в стране много, и капитальный ремонт с заменой рельс будет идти еще долго. Так что отъезжаешь немного от главного хода Окт. ж.д. и тыдым-тыдым-тыдым-тыдым :-)
                  +4
                  Нам препод по ОКЖД (Общий курс железных дорог) рассказывал, что в Америке на некоторых участках жд полотна на рельсах делают мелкие пропилы — иммитируют теплый ламповый «ТЫДЫМ». :)
                    +2
                    Было бы цинично напилить промежутки таким образом, чтобы колеса выстукивали какой-то знакомый мотив :)
                      +3
                      Азбукой Морзе название приближающегося населенного пункта или станции, что уж там :)
            +1
            С детства люблю ЖД
            увидеть бы модель интерактивно :)
              +2
              В какой-то степени Вам может помочь Train Simulator 2013 :-)
              0
              А для чего делается этот движок? Это для реального применения на ЖД, или для игры, или в порядке хобби?

              Исходя из того, что много внимания уделено столкновениям вагонов — похоже, предполагается симулировать сортировочные станции с горками?
                0
                Будет интересно увидеть симуляцию саморасцепа.
                  0
                  Движок разработан для тренажеров оперативного персонала сортировочных горок, предполагается использовать его и для имитационных систем, и для виртуальной грузовой станции. На грузовой станции тоже есть операции, для которых важно взаимодействие между вагонами, например: расформирование толчком. Локомотив толкает отцеп перед собой, часть вагонов в отцепе расцеплены. Потом локомотив тормозит, а отцепленные вагоны едут вперед на нужный путь, их там ловят башмаками.
                    0
                    Это ваш тренажер сортировочной станции Бекасово сейчас используется в новом учебном центре?
                    Сам работаю дежурным по горке, интересно было бы посмотреть.
                    Если желаете, могу вам много чего рассказать :)
                  +4
                  Физический движок для железнодорожного транспорта
                  Почему-то представил сначала огромные электромоторы и тысячесильные дизеля.
                    0
                    Наконец-то кто-то занялся делами более близкими к реальности, чем стартаповщина!

                    Only users with full accounts can post comments. Log in, please.