МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ
Сибирский государственный аэрокосмический университет
имени академика М. Ф. Решетнева
Кафедра безопасности информационных технологий (БИТ)
Лабораторная работа №2
Невозмущённое движение
Выполнил ст. гр. КБ-81:
Билецкая Н.А.
Проверил преподаватель:
Малухин Д.В.
Красноярск 2011
Содержание
Содержание 2
ЦЕЛЬ РАБОТЫ: Изучить орбитальное движения космических аппаратов (КА), отработать расчёт траекторий орбитального движения космических аппаратов на практике. 3
ЗАДАЧИ 3
ЗАКЛЮЧЕНИЕ 17
Цель работы: Изучить орбитальное движения космических аппаратов (ка), отработать расчёт траекторий орбитального движения космических аппаратов на практике. Задачи
В программе реализовывались следующие возможности:
В области 3D-отображения:
Отображение осей координат (0X, 0Y, 0Z).
Создание модели планеты Земля с наложенной текстурой.
Создание орбиты КА посредством задания долготы восходящего узла, наклонения орбиты, аргумента перигея, эксцентриситета и фокального параметра орбиты.
Отображение проекции орбиты на поверхность Земли.
Моделирование движения КА по заданной орбите. Земля и КА вращаются в одном масштабе времени (По умолчанию масштаб времени 1:1).
Предусмотрена возможность ускорения течения времени и его остановку.
Отображение проекции КА на поверхность Земли.
В области 2D-отображения:
Отображение проекции трассы КА на поверхность Земли, её движение.
Отображение проекции КА на поверхность Земли.
Отображение текущих параметров КА:
Период обращения.
Широта, долгота.
Составляющие вектора скорости и абсолютная скорость.
Координаты и длина радиус-вектора.
ХОД РАБОТЫ
В области 3d-отображения.
Для того чтобы нарисовать оси координат 0X, 0Y, 0Z используем оператор рисования точек в 3D - glVertex3f(_,_,_), предварительно указав параметр GL_LINES в объявлении gLBegin(_). Также с помощью оператора glNormal3f(_,_,_) задаём координаты для источника света, а с помощью оператора glMaterialfv(_,_,_) задаём характеристики поверхности:
glBegin(GL_LINES);
glNormal3f(7,7,7);
glMaterialfv(GL_FRONT,GL_AMBIENT,@Material[1]);
glMaterialfv(GL_FRONT,GL_DIFFUSE,@Material[1]);
glMaterialfv(GL_FRONT,GL_SPECULAR,@Material[4]);
glVertex3f(0,0,0);
glVertex3f(3,0,0);
glMaterialfv(GL_FRONT,GL_AMBIENT,@Material[2]);
glMaterialfv(GL_FRONT,GL_DIFFUSE,@Material[2]);
glMaterialfv(GL_FRONT,GL_SPECULAR,@Material[4]);
glVertex3f(0,0,0);
glVertex3f(0,3,0);
glMaterialfv(GL_FRONT,GL_AMBIENT,@Material[3]);
glMaterialfv(GL_FRONT,GL_DIFFUSE,@Material[3]);
glMaterialfv(GL_FRONT,GL_SPECULAR,@Material[4]);
glVertex3f(0,0,0);
glVertex3f(0,0,3);
glEnd;
Создаем новый модуль Unit – OrbitUnit.
В нём создаём константу для радиуса, массивы для координат в пространстве и на плоскости, а также класс, в котором будут содержаться переменные эксцентриситет и фокальный параметр и функция GetPos, которая рассчитывает координаты точки от истинной аномалии согласно уравнению в полярных координатах, смысл котоого заключается в следующем:
Если принять фокус эллипса за полюс, а большую ось — за полярную ось, то его уравнение в полярных координатах будет иметь вид
где e — эксцентриситет, а p — фокальный параметр. При положительном знаке перед e второй фокус эллипса будет находиться в точке а при отрицательном — в точке где фокальное расстояние
е - эксцентриситет — числовая характеристика конического сечения, показывающая степень его отклонения от окружности.
р - фокальный параметр, .
Истинная аномалия - угол между большой полуосью и лучом из фокуса в положение.
function TOrbit.GetPos(uVal:real):TPoint3D;
var Rad:real;
Begin
Rad:=p/(1+e*cos(uVal));
Result[1]:=Rad*cos(uVal);
Result[2]:=Rad*sin(uVal);
Result[3]:=0;
End;
Создаём объект TОrbit с помощью вызова конструктора Orbit:=TOrbit.Create в модуле CreataForm. Затем мы создаём 2 скроллбара для изменения значений эксцентриситета и фокального параметра.
Для того чтобы нарисовать Землю, разобьём всю поверхность на треугольники. С помощью них будем накладывать текстуру, задавая координаты вершин треугольников.
с1 с3
с2 с4
Для того, чтобы совпадала лицевая сторона, обход должен быть в одну сторону, т.е. с1, с2, с3 => с2, с4, с3.
Чтобы преобразовывать координаты из 2D в 3D добавляем функцию Translate2Dto3D:
function TOrbit.Translate2Dto3D(Point2D:TPoint2D):TPoint3D;
begin
Result[1]:=EARTH_RAD*cos(Point2D[1]*2*pi)*cos((Point2D[2]-0.5)*pi);
Result[2]:=EARTH_RAD*sin(Point2D[1]*2*pi)*cos((Point2D[2]-0.5)*pi);
Result[3]:=EARTH_RAD*sin((Point2D[2]-0.5)*pi);
end;
Далее отрисовываем треугольники, предварительно задав переменные координат текстуры и координат в пространстве. Также для ощущения объёмности перед каждой точкой задаём нормали:
glMaterialfv(GL_FRONT,GL_AMBIENT,@Material[6]);
glMaterialfv(GL_FRONT,GL_DIFFUSE,@Material[6]);
glMaterialfv(GL_FRONT,GL_SPECULAR,@Material[4]);
glBegin(GL_Triangles);
for q1:= 0 to 99 do
for q2:=0 to 99 do begin
c1[1]:=q1/100;
c1[2]:=1-q2/100;
c2[1]:=q1/100;
c2[2]:=1-(q2+1)/100;
c3[1]:=(q1+1)/100;
c3[2]:=1-q2/100;
c4[1]:=(q1+1)/100;
c4[2]:=1-(1+q2)/100;
p1:=Orbit.Translate2DTo3d(c1);
p2:=Orbit.Translate2DTo3d(c2);
p3:=Orbit.Translate2DTo3d(c3);
p4:=Orbit.Translate2DTo3d(c4);
//1ый треугольник
glNormal3f(p1[1]/EARTH_Rad,p1[2]/Earth_Rad,p1[3]/Earth_Rad);
glTexCoord2f(c1[1],c1[2]);
glVertex3f(p1[1]/EARTH_Rad,p1[2]/Earth_Rad,p1[3]/Earth_Rad);
glNormal3f(p2[1]/EARTH_Rad,p2[2]/Earth_Rad,p2[3]/Earth_Rad);
glTexCoord2f(c2[1],c2[2]);
glVertex3f(p2[1]/EARTH_Rad,p2[2]/Earth_Rad,p2[3]/Earth_Rad);
glNormal3f(p3[1]/EARTH_Rad,p3[2]/Earth_Rad,p3[3]/Earth_Rad);
glTexCoord2f(c3[1],c3[2]);
glVertex3f(p3[1]/EARTH_Rad,p3[2]/Earth_Rad,p3[3]/Earth_Rad);
//2ой треугольник
glNormal3f(p2[1]/EARTH_Rad,p2[2]/Earth_Rad,p2[3]/Earth_Rad);
glTexCoord2f(c2[1],c2[2]);
glVertex3f(p2[1]/EARTH_Rad,p2[2]/Earth_Rad,p2[3]/Earth_Rad);
glNormal3f(p4[1]/EARTH_Rad,p4[2]/Earth_Rad,p4[3]/Earth_Rad);
glTexCoord2f(c4[1],c4[2]);
glVertex3f(p4[1]/EARTH_Rad,p4[2]/Earth_Rad,p4[3]/Earth_Rad);
glNormal3f(p3[1]/EARTH_Rad,p3[2]/Earth_Rad,p3[3]/Earth_Rad);
glTexCoord2f(c3[1],c3[2]);
glVertex3f(p3[1]/EARTH_Rad,p3[2]/Earth_Rad,p3[3]/Earth_Rad);
end;
glEnd;
Для отрисовки орбиты переходим в модуль рисования в пространстве. Делать это будем с помощью линий. Чтобы получать координаты точек нужно использовать значения истинной аномалии от 0 до 360 градусов:
glMaterialfv(GL_FRONT,GL_AMBIENT,@Material[1]);
glMaterialfv(GL_FRONT,GL_DIFFUSE,@Material[1]);
glMaterialfv(GL_FRONT,GL_SPECULAR,@Material[4]);
glNormal3f(1,1,1);//нормаль в точке с координатами 1 1 1
glBegin(gl_LINE_LOOP);
glVertex3f(0,0,0);
for q1:=0 to 360 do
begin
Cord:=Orbit.GetPos(pi*(q1/180));
glVertex3f(Cord[1]/EARTH_RAD,Cord[2]/EARTH_RAD,Cord[3]/EARTH_RAD);
end;
glEnd;
Для вращения орбиты по 3м направлениям нам необходимо вычислять координаты, зависящие от 3х углов: Q – долгота восходящего узла (угол между узлом восхождения и точкой восходящей орбиты),w – аргумент перегея (угол наклона прямой, на которой находится перегей относительно прямой долготы восходящего узла), ί – наклонение орбиты (угол, на который плоскость орбиты наклонена относительно плоскости эклиптики). Чтобы вычислять новые координаты необходимо старые координаты умножать на матрицу поворота, полученную в результате перемножения 3х матриц:
В модуле OrbitUnit добавляем эти переменные - Q, w и i. Для регулировки их значений добавляем на форму 3 скроллбара. Так же в модуле OrbitUnit добавляем процедуры RecountMatrix (считает матрицу поворота) и TranslatePos (преобразует координаты):
procedure TOrbit.RecountMatrix;
var M1,M2,M3,Hlp: array [1..3,1..3] of real;
q1,q2,q3: integer;
Begin
M1[1,1]:=cos(Q);
M1[2,1]:=-sin(Q);
M1[3,1]:=0;
M1[1,2]:=sin(Q);
M1[2,2]:=cos(Q);
M1[3,2]:=0;
M1[1,3]:=0;
M1[2,3]:=0;
M1[3,3]:=1;
M2[1,1]:=1;
M2[2,1]:=0;
M2[3,1]:=0;
M2[1,2]:=0;
M2[2,2]:=cos(i);
M2[3,2]:=sin(i);
M2[1,3]:=0;
M2[2,3]:=-sin(i);
M2[3,3]:=cos(i);
M3[1,1]:=cos(w);
M3[2,1]:=-sin(w);
M3[3,1]:=0;
M3[1,2]:=sin(w);
M3[2,2]:=cos(w);
M3[3,2]:=0;
M3[1,3]:=0;
M3[2,3]:=0;
M3[3,3]:=1;
for q1:=1 to 3 do
for q2:= 1 to 3 do
begin
Hlp[q1,q2]:=0;
for q3:= 1 to 3 do
Hlp[q1,q2]:=Hlp[q1,q2]+M1[q3,q2]*M2[q1,q3];
end;
for q1:=1 to 3 do
for q2:= 1 to 3 do
begin
TurnMatrix[q1,q2]:=0;
for q3:= 1 to 3 do
TurnMatrix[q1,q2]:=TurnMatrix[q1,q2]+Hlp[q3,q2]*M3[q1,q3];
end;
End;
procedure TOrbit.TranslatPos(var cord : TPoint3D);
var q1,q2: integer;
Hlp:TPoint3D;
Begin
for q1:= 1 to 3 do begin
Hlp[q1]:=0;
for q2 := 1 to 3 do
Hlp[q1]:=Hlp[q1]+Cord[q2]*TurnMatrix[q2,q1];
end;
for q1 := 1 to 3 do
Cord[q1]:=Hlp[q1];
End;
Для того, чтобы нарисовать проекцию орбиты на Землю, добавим после построения самой орбиты:
for q1:=0 to 360 do
Begin
Cord:=Orbit.GetPos(q1*pi/180);
a:=0.9*sqrt(sqr(Cord[1])+sqr(Cord[2])+sqr(Cord[3]));
glVertex3F(Cord[1]/a,Cord[2]/a,Cord[3]/a);
end;
Нам необходимо узнать истинную аномалию. Мы вычисляем её с помощью формул:
Данные формулы показывают зависимость истинной аномалии от эксцентрической.
Средняя аномалия — угловое расстояние от перицентра гипотетического тела движущегося с постоянной угловой скоростью, равной среднему движению.
Эксцентрическая аномалия (обозначается E) — параметр используемый для выражения переменной длины радиус-вектора. Средняя аномалия связана с эксцентрической уравнением Кеплера:
, где n – среднее движение.
Вычисляем точку пересечения графиков:
Разбиваем интервал на 2 половины и вычисляем разность;
Если Е-М<e-sin(E), то переходим вправо, а если наоборот, то переходим влево и снова повторяем шаг 1. Делаем это пока длина интервала не станет меньше, чем 1*10^(-10).
В методах класса добавляем функцию GetExAnomaly:
Function TOrbit.GetExAnomaly(BegAngle, EndAngle,LookingAnomaly:real):real;
Begin
while (LookingAnomaly<0) do
LookingAnomaly:=LookingAnomaly+2*pi;
while (LookingAnomaly>2*pi) do
LookingAnomaly:=LookingAnomaly-2*pi;
if(abs((BegAngle-E*sin(BegAngle))-LookingAnomaly)<ERROR_SIZE) then
GetExAnomaly:=BegAngle
else
begin
if(abs((EndAngle-E*sin(EndAngle))-LookingAnomaly)<ERROR_SIZE) then
GetExAnomaly:=EndAngle
else
begin
if((EndAngle+BegAngle)/2-e*sin((EndAngle+BegAngle)/2)<LookingAnomaly) then
GetExAnomaly:=GetExAnomaly((EndAngle+BegAngle)/2,EndAngle,LookingAnomaly) else
GetExAnomaly:=GetExAnomaly(BegAngle,(EndAngle+BegAngle)/2,LookingAnomaly);
end;
end;
end;
Добавляем ещё одну функцию, которая будет вычислять значение истинной аномалии по известному значению эксцентрической аномалии:
function TOrbit.GetU(EVal:real):real;
var u1,u2:real;
begin
U1:=ArcCos((cos(EVal)-e)/(1-e*cos(EVal)));
U2:=sin(EVal);
if(U2<0) then
GetU:=2*pi-u1 else
GetU:=U1;
end;
Моделируем вращение Земли и спутника. Зададем константу длительности звёздных суток, добавим таймер, который будет связан со скроллбаром, который будет задавать характеристику текущего времени – количество секунд, прошедших с начала запуска программы. Необходимо, чтобы в каждый момент времени Земля была повернута на определенный угол. CurrentTime=0 – «полночь».
function Torbit.GetEathAngle:real;
Begin
Result:=frac(CurrentTime/SEC_PER_DAY)*360;
end;
В код рисования Земли добавим переменную, отвечающую за угол поворота Земли и код, реализующий поворот:
Angle:=Orbit.GetEathAngle+180;
glRotate(Angle,0,0,1);
………………………...
glRotate(-Angle,0,0,1);
Для моделирования движения спутника нам понадобится знать период обращения спутника. Запишем в функцию RecountMatrix:
EARTH_MU = 3.98602E14;
..............................................
Period:=2*pi/sqrt(EARTH_MU/IntPower(p/(1-sqr(e)),3));
Добавим функцию поиска координат спутника по текущему времени:
function TOrbit.GetCurrentPos:TPoint3D;
var MVal:real;
begin
MVal:=frac(CurrentTime/Period)*2*pi;
Result:=GetPos(GetU(GetExAnomaly(0,2*pi,MVal)));
end;
Далее в модуле рисования в 3D добавим рисование радиус-вектора спутника:
glBegin(GL_LINES);
glVertex3f(0,0,0);
Cord:=Orbit.GetCurrentPos;
glVertex3f(Cord[1]/EARTH_RAD,Cord[2]/EARTH_RAD,Cord[3]/EARTH_RAD);
glEnd;