qweewq
@qweewq
ruby, ruby on rails, devops

Решение задачи асболютно упругого соударения двух шаров?

Есть ли решение задачи асболютно упругого соударения двух шаров, имеющих начальное положение, вектор скорости, радиус в системе линейных уравнений стандартными функциями (ode45,..)?

Или просто система линейных уравнений?

Может, есть анимация этого в MatLab?

Очень нужно…
  • Вопрос задан
  • 14999 просмотров
Решения вопроса 1
@hacklex
Думаю, если автор ещё не видел вот этой статьи, с ней обязательно стоит ознакомиться. В своё время писал код, опираясь именно на неё.
Разумеется, никаких дифференциальных уравнений.

Плюс, возможно это не сразу становится очевидным: для выполнения действительно точного расчёта порядок действий должен быть сложнее, чем просто выполнить расчёт сразу после обнаружения наложения двух кругов друг на друга, в связи с необходимостью дробить шаг симуляции ∆t.

В статье есть, помимо прочего, расчёт расстояния пробега до столкновения, поэтому, не заостряя внимание на самих формулах, приведу общий план итерации симулятора (для реализации описанного ниже плана потребуется позаимствовать процедуры определения дистанции свободного пробега до столкновения и вычисления векторов скоростей после соударения):

  1. просчитать предварительное новое положение каждого из шаров (прибавить ∆t *Vi к текущим координатам каждого i-го шара), и в случае наложения «предсказанных» шариков вычислить для каждого пробег ДО касания (я буду использовать значение доли λij от ∆t (шага симуляции);
    доля шага симуляции (лямбда) — это значение от 0 (почти столкнулись на предыдущем шаге моделирования) до 1 (ещё чуть-чуть, и столкновения на этом шаге бы не было совсем));
     
  2. отсортировать пары шаров по полученным значениям долей, чтобы рассматривать сначала те столкновения, которые случились раньше;
     
  3. для очередной пары столкнувшихся рассчитать
     
    (а) положения в момент касания (t+∆t*λij),
     
    (б) векторы скоростей (см. статью по ссылке выше),
     
    (в) положения на момент t+∆t (к положениям в момент касания добавить значение вектора скорости после соударения, умноженное на ∆t*(1−λij), корректируя таким образом положение пары на момент t+∆t с учётом столкновения;
     
  4. повторять цикл для всех пар шаров, заново определяя наложения после каждого уточнения и начиная расчёт уточнений сначала (для коллизий с самым маленьким значением λ)
     
  5. если больше коллизий среди набора предсказанных положений для t+∆t нет, значит, кхм, we could call it a step.

Разумеется, это всё ещё далеко не Virtual pool, но визуально, особенно для моделей с грубым шагом симуляции, это обеспечит ощутимо бóльшую точность. Разумеется, такие заморочки нужны только если таковая нужна. Если нет — из статьи выше достаточно позаимствовать формулы для расчёта углов отскока.

… Помимо этого, при моделировании поведения абсолютно упругих шаров есть тонкий момент, связанный с точным расчётом отскока шара от любого острого угла. Если этот вопрос вдруг также интересен (лично у меня этот вопрос возник непосредственно после решения вопроса с соударениями шаров), могу показать, как считать отскок и для этого случая.
Ответ написан
Пригласить эксперта
Ответы на вопрос 4
Prosolver
@Prosolver
Я использую такое решение для эмуляции движения и соударения пятнадцати шаров (Object Pascal):

for i:=1 to 15 do   // просчитываем соударения шаров
for j:=i+1 to 16 do begin
 dist:=sqrt(sqr(balls[i].x-balls[j].x)+sqr(balls[i].y-balls[j].y)); //расстояние между центрами шаров
 if dist<diametr then begin //если расстояние меньше диаметра, значит есть факт соударения
  a:=balls[i].x-balls[j].x; //вспомогательные переменные типа extended
  b:=balls[i].y-balls[j].y;
  p1:=a*b/sqr(dist);
  p2:=sqr(a/dist);
  p3:=sqr(b/dist);
  d1:=balls[i].dy*p1+balls[i].dx*p2-balls[j].dy*p1-balls[j].dx*p2;
  d2:=balls[i].dx*p1+balls[i].dy*p3-balls[j].dx*p1-balls[j].dy*p3;
  balls[i].dx:=balls[i].dx-d1; //меняем значение приращения координаты шаров при движении
  balls[i].dy:=balls[i].dy-d2;
  balls[j].dx:=balls[j].dx+d1;
  balls[j].dy:=balls[j].dy+d2;

  p3:=(diametr-dist)/2; //при соударении шары всегда "проникают" друг в друга, поэтому раздвигаем их
  p1:=p3*(a/dist);
  p2:=p3*(b/dist);
  balls[i].x:=balls[i].x+p1;
  balls[i].y:=balls[i].y+p2;
  balls[j].x:=balls[j].x-p1;
  balls[j].y:=balls[j].y-p2;
 end;
end;

for i:=1 to 15 do
 balls[i].x:=balls[i].x+balls[i].dx;  //эмулируем движение
 balls[i].y:=balls[i].y+balls[i].dy;
end;
Ответ написан
Muff
@Muff
Для двух шаров все решается точно, без всяких систем дифференциальных уравнений. Вот, например, uc.jinr.ru/mirea/classmex/gl_mex_5.pdf
Ответ написан
Figurnov
@Figurnov
Формулы для расчёта упругого столкновения частиц приведены практически в любой книжке по теоретической механике. Например, Ландау, Лифшиц «Механика», с. 62-65, или Яблонский, «Курс теоретической механики», т. 2 с. 284. Дифференциальные уравнения не требуются, хватает школьного курса математики
Ответ написан
qweewq
@qweewq Автор вопроса
ruby, ruby on rails, devops
Пока такое решение, но его нужно переделывать…

Код
clc; clear all; close all;

% Start points
x1 = 0; y1 = 0; r1 = 2;
x2 = 6; y2 = 1; r2 = 2;

% Absolute Velocity
v1 = 6;
v2 = 3;

% Velocity vectors
L1 = rand(1,2);
L2 = rand(1,2);

% Time
t = 0:0.02:10;

% Vectors with coordinates by steps (time)
vec1(1,:) = x1 + v1*L1(1)*t; vec1(2,:) = y1 + v1*L1(2)*t;
vec2(1,:) = x2 + v2*L2(1)*t; vec2(2,:) = y2 + v2*L2(2)*t;

% Draw circles
ang = 0:0.01:2*pi;
xp1 = r1*cos(ang); yp1 = r1*sin(ang);
xp2 = r2*cos(ang); yp2 = r2*sin(ang);

for i=1:length(vec1)
    plot(vec1(1,i)+xp1,vec1(2,i)+yp1);
    hold on
    plot(vec2(1,i)+xp2,vec2(2,i)+yp2);
    hold off
    axis([min(min(vec1(1,:), vec2(1,:))), max(max(vec1(1,:), vec2(1,:))), min(min(vec1(2,:), vec2(2,:))), max(max(vec1(2,:), vec2(2,:)))])
    pause(0.02) % delay
    
    if sqrt((vec1(1,i)-vec2(1,i)).^2 + (vec1(2,i)-vec2(2,i)).^2) < r1+r2
        
        disp('COLLAPSE!')
        
        L1 = rot90(L1,1);
        L2 = rot90(L2,1);
        tt = 0:0.02:10;
        
        newvec1(1,:) = vec1(1,i) + v1*L1(1)*tt;
        newvec1(2,:) = vec1(2,i) + v1*L1(2)*tt;
        newvec2(1,:) = vec2(1,i) + v2*L2(1)*tt;
        newvec2(2,:) = vec2(2,i) + v2*L2(2)*tt;
        
        for j=i:length(vec1)
            plot(newvec1(1,j-i+1)+xp1,newvec1(2,j-i+1)+yp1);
            hold on;
            
            plot(newvec2(1,j-i+1)+xp2,newvec2(2,j-i+1)+yp2);
            hold off;
            
            axis([min(min(vec1(1,:), vec2(1,:))), max(max(vec1(1,:), vec2(1,:))), min(min(vec1(2,:), vec2(2,:))), max(max(vec1(2,:), vec2(2,:)))])
            pause(0.1) % delay
        end
        
        return
        
    end
end

Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
ON Semiconductor Санкт-Петербург
от 100 000 до 200 000 ₽
EVEN Lab Москва
от 100 000 до 140 000 ₽
NZT Group Москва
от 150 000 до 300 000 ₽