Автор: Петров А.
Алгоритм реализован в виде нескольких программ на языке С. На камень в полете действует только одна сила - сила тяжести. Если масса камня
m, то сила тяжести, равна F=mg, где g-ускорение свободного
падения, вблизи Земли g=9.81 (м с2)-1
Введем координаты камня. Пусть x - расстояние по горизонтали от места, с
которого кидали камень, пусть y - расстояние от поверхности Земли до камня.
Условно примем, что в начальный момент времени x=0, y=0. Если мы хотим узнать
поведение камня в любой момент времени, естественно, что эти координаты зависят
от времени: x(t), y(t). Пусть vx(t), vy(t) -
скорость камня в горизонтальном
и вертикальном направлении, соответственно. Пусть ax(t),
ay(t) - ускорение
камня в горизонтальном и вертикальном направлении соответственно.
Воспользуемся вторым законом Ньютона, который связывает ускорение движущегося
тела и силы, действующие на него:
F = ma
Здесь F - сумма всех сил, действующих на тело, a - полное ускорение. Обе эти
величины векторные. т.е. имеют направление.
Это же уравнение можно записать в проекциях на оси x, y.
Fx = m ax - сила, действующая в горизонтальном направлении.
Сила тяжести действует на тело в вертикальном направлении и направлена вниз.
То есть
Fx = m ax = 0
Как известно из курса кинематики скорость, ускорение и координата тела
связаны друг с другом. Скорость равна производной координаты по времени.
Ускорение равно производной скорости по времени, т.е. ускорение равно второй
производной координаты по времени. Далее штрих (') означает производную по
времени.
vx = x'
Заменим в уравнениях Ньютона ускорения на скорости и запишем все уравнения
в виде системы, где в левой части стоят производные, а в правой части сами
переменные.
m v'x = 0
Поделим первое и второе уравнение на m:
x' = vx
Полученная система является системой линейных уравнений первой степени.
Неизвестными в ней являются x(t), y(t), vx(t), vy(t).
Для того, чтобы решение этой системы существовало и было единственным необходимо
и достаточно, чтобы были заданы значения неизвестных в начальный момент времени
t=0. Действительно, мы их чаще всего знаем. В нашей задаче мы так ввели
оси координат, что x(0)=0, y(0)=0. Пусть мы знаем и проекции начальной скорости
тела vx(0), vy(0). Чаще всего задают не проекции, а
полную скорость тела v и угол к горизонту, под которым тело бросали.
Введем четырехмерный вектор U(x, y, vx, vy). Это может
показаться странным, что для такой простой задачи нам понадобились какие-то
четырехмерные вектора. Не пугайтесь. Четырехмерных векторов в природе не бывает.
Это лишь абстракция, которая поможет нам проще записать решение этой задачи
и программу, которая этот метод реализует. Итак, координатами этого вектора
являются координаты камня и проекции его скорости. Нашу систему уравнений можно
записать в виде:
U' = F(U,t)
где F(U,t) = (vx, vy, 0, -g)
Перейдем к описанию метода решения таких задач. Метода Рунге-Кутта.
Это численный метод. Суть метода состоит в том, чтобы разбить интервал
времени, в течение которого нам надо узнать координаты и скорости на некоторое
большое количество отрезков времени dt.
Пусть мы знаем значение вектора U в некоторый момент времени t и хотим
узнать его в момент времени t+dt.
Методом Эйлера называется метод, в котором
Этот метод действительно работает. Посмотрите покомпонентно расписанную
эту же запись:
x(t+dt) = x(t) + vxdt
Эти равенства являются приближенными и следуют из определения производной,
Чем меньше dt, тем точнее эти равенства.
Методом Рунге-Кутта 4-го порядка называется метод, в котором
k1 = F(U,t)dt
Понимаю, что это довольно абстрактное выражение, непонятное интуитивно,
но можете считать, что это тот же метод Эйлера, только уточненный. Более
подробно о методе Рунге-Кутта (с доказательствами) можно почитать в книгах по
численным методам (например, Калиткин Н.Н., Численные методы).
Напишем часть кода на С++, который позволит нам реализовать этот метод:
В данном участке кода мы ввели класс под названием vector. У него есть 4
компонента: x, y, vx, vy. Далее мы ввели операции сложения и вычитания таких
векторов (покомпонентное сложение или вычитание) а также операции умножения
вектора на число и числа на вектор (которые совпадают с точностью до
перестановки множителей местами).
Напишем функцию F(U,t) для нашей задачи с камнем:
Дальше нам осталось только написать главную часть программы, которая будет
использовать этот код:
Здесь мы бросаем камень со скоростью 1 м/с по горизонтали и 2 м/с по
вертикали. Интервал времени равен 0.05 секунды. Программа печатает
время, прошедшее со старта камня и его координаты x, y.
При заданных условиях программа напишет следующее:
Мы видим, что за 0.4 секунды камень пролетит на 0.4 метра вперед и упадет
на землю (в следующий момент времени его координата y является отрицательной,
что означает, что камень упал на землю). Максимальная высота подъема камня
над землей составит приблизительно 0.2 метра. Эти результаты в очень хорошо
совпадают с расчетными.
Надеюсь, вам все стало понятно, и вы сможете применить эти методы в своих
расчетах.
E-MAILspm111@yandex.ru
Опишем сначала, что такое дифференциальные уравнения на примере из механики и введем несколько обозначений.
Представьте себе, что вы бросили камень (можно бросать и гранату, но это
негуманно) по направлению вверх и вперед.
Из житейского опыта известно, что он полетит вперед
по гладкой дуге, сначала вверх,
потом вниз. На уроках физики вы может быть решали эту задачу аналитически
и узнали, что камень летит по параболе. Естественно, для простоты будем считать,
что воздух не оказывает никакого сопротивления камню.
Fy = m ay - сила действующая в вертикальном направлении.
Fy = m ay = - m g
vy = y'
ax = x''
ay = y''
m v'y = - m g
x' = vx
y' = vy
y' = vy
v'x = 0
v'y = - g
U(t+dt) = U(t) + F(U,t)dt.
y(t+dt) = y(t) + vydt
vx(t+dt) = vx(t) + axdt
vy(t+dt) = vy(t) + aydt
U(t+dt) = U(t) + (k1 + 2k2 + 2k3 + k4)/6.
где
k2 = F(U+k1/2, t+dt/2)dt
k3 = F(U+k2/2, t+dt/2)dt
k4 = F(U+k3, t+dt)dt
class vector{
public:
float x, y, vx, vy;
vector(){
x = 0;
y = 0;
vx = 0;
vy = 0;
}
vector(float ax, float ay, float avx, float avy){
x = ax;
y = ay;
vx = avx;
vy = avy;
}
void out(){
printf("x=%f\t", x);
printf("y=%f\t", y);
printf("vx=%f\t", vx);
printf("vy=%f\t", vy);
}
};
vector operator +(vector a, vector b){
vector c;
c.x = a.x + b.x;
c.y = a.y + b.y;
c.vx = a.vx + b.vx;
c.vy = a.vy + b.vy;
return(c);
}
vector operator -(vector a, vector b){
vector c;
c.x = a.x - b.x;
c.y = a.y - b.y;
c.vx = a.vx - b.vx;
c.vy = a.vy - b.vy;
return(c);
}
vector operator *(float a, vector b){
vector c;
c.x = a * b.x;
c.y = a * b.y;
c.vx = a * b.vx;
c.vy = a * b.vy;
return(c);
}
vector operator *(vector b, float a){
vector c;
c.x = a * b.x;
c.y = a * b.y;
c.vx = a * b.vx;
c.vy = a * b.vy;
return(c);
}
vector F(vector U, float t){
vector res;
float g = 9.81;
res.x = U.vx;
res.y = U.vy;
res.vx = 0;
res.vy = - g;
return(res);
}
#include <stdio.h>
void main(){
float t=0, dt = 0.05;
float vx = 1, vy = 2;
float x=0, y=0;
vector U(x, y, vx, vy);
vector k1, k2, k3, k4;
while(U.y >= 0){
k1 = F(U, t)*dt;
k2 = F(U + 0.5*k1, t+0.5*dt)*dt;
k3 = F(U + 0.5*k2, t+0.5*dt)*dt;
k4 = F(U + k3, t+dt)*dt;
U = U + 1.0/6.0 * (k1 + 2*k2 + 2*k3 + k4);
t += dt;
printf("t=%f x=%f y=%f\n", t, U.x, U.y);
}
}
t=0.050000 x=0.050000 y=0.087738
t=0.100000 x=0.100000 y=0.150950
t=0.150000 x=0.150000 y=0.189637
t=0.200000 x=0.200000 y=0.203800
t=0.250000 x=0.250000 y=0.193437
t=0.300000 x=0.300000 y=0.158550
t=0.350000 x=0.350000 y=0.099137
t=0.400000 x=0.400000 y=0.015200
t=0.450000 x=0.450000 y=-0.093263