Методическое пособие 366
.pdfelse state_changed=%t;
end
(в противном случае, признак изменения принимает значение 1, а за изменение положения тела на рисунке будет отвечать другая функция, см. функцию show)
endfunction
Следом идут 6 функций, вызываемых движением ползунка (по числу обобщѐнных координат). Входным аргументом служит значение соответствующей обобщѐнной координаты.
function update_xplane(xplane) global body_controls
(глобальная переменная, которая была определена в функции body_gui и содержащая в себе переменные, управляющие ползунком и текстом справа от ползунка, показывающим значение соответствующей обобщѐнной координаты)
Slider_Xplane=body_controls(1,1)
Value_Xplane=body_controls(1,2)
(первая из этих переменных отвечает за ползунок, а вторая – за текст)
if argn(2)==1 then Slider_Xplane.Value=xplane*100/0.2;
(если у функции один аргумент, xplane, то это значение передаѐтся переменной, управляющей ползунком, и ползунок перемещается на соответствующую позицию. Множитель 100/0.2 определяет, какому значению координаты соответствует положение ползунка, иными словами, это масштабный коэффициент. Так, в данном случае крайнему левому положению ползунка будет соответствовать значение координаты, равное 0, а крайнему правому – значение 0.2; шаг ползунка составляет
0.002) else
xplane=Slider_Xplane.Value xplane=xplane*0.2/100;
29
end
(есть второй вариант, когда у этой функции нет входных аргументов. Такая ситуация возникает, когда ползунок при инициализации передвигается вручную. В этом случае по значению, определяющему местоположение ползунка, определяется значение соответствующей координаты путѐм умножения на множитель, обратный тому, который был описан выше)
Value_Xplane.String=msprintf("%.3f",xplane)
(переменной, управляющей текстом, передаѐтся значение координаты, которое преобразовывается в текст)
update_state(1,xplane) endfunction
Таким образом, у этой функции возможны 2 варианта вызова: при ручном управлении ползунком она вызывается без аргументов и по значению, определяющему положение ползунка, определяется координата, которая, в свою очередь, передаѐтся в функцию update_state, которая в этом случае отображает тело на рисунке, учитывая произведѐнные изменения координат. Во втором случае на вход функции подаѐтся значение координаты, и в этом случае уже функция управляет ползунком. Аналогичным образом определяются остальные 5 функций, с тем лишь различием, что в функциях, отвечающих за угловые координаты, другой масштабный коэффициент.
function update_yplane(yplane) global body_controls Slider_Yplane=body_controls(2,1) Value_Yplane=body_controls(2,2) if argn(2)==1 then
Slider_Yplane.Value=yplane*100/0.2; else
yplane=Slider_Yplane.Value yplane=yplane*0.2/100
end Value_Yplane.String=msprintf("%.3f",yplane)
30
update_state(2,yplane) endfunction
function update_height(h) global body_controls
Slider_Height=body_controls(3,1) Value_Height=body_controls(3,2) if argn(2)==1 then
Slider_Height.Value=h*100/0.2; else
h=Slider_Height.Value h=h*0.2/100
end Value_Height.String=msprintf("%.3f",h) update_state(3,h)
endfunction
function update_theta(t) global body_controls
Slider_Theta=body_controls(4,1) Value_Theta=body_controls(4,2) if argn(2)==1 then
Slider_Theta.Value=t*10000/360; else
t=Slider_Theta.Value t=t*360/10000;
end Value_Theta.String=msprintf("%.3f",t) update_state(4,t)
endfunction
function update_phi(p) global body_controls
Slider_Phi=body_controls(5,1)
Value_Phi=body_controls(5,2) if argn(2)==1 then
Slider_Phi.Value=p*10000/360;
31
else p=Slider_Phi.Value p=360*p/10000
end Value_Phi.String=msprintf("%.3f",p) update_state(5,p)
endfunction
function update_psi(p) global body_controls
Slider_Psi=body_controls(6,1) Value_Psi=body_controls(6,2) if argn(2)==1 then
Slider_Psi.Value=p*10000/360; else
p=Slider_Psi.Value p=360*p/10000
end Value_Psi.String=msprintf("%.3f",p) update_state(6,p)
endfunction
Далее идут шесть функций, вызываемых посредством нажатия на соответствующие кнопки.
function body_start()
(функция вызывается путѐм нажатия на кнопку Start) global Stop;Stop=%f;
(при нажатии на кнопку Start признак остановки Stop принимает значение 0)
show();
(вызывается функция, основным назначением которой является решение системы дифференциальных уравнений и построение графического изображения тела с новыми координатами, описание см. ниже)
endfunction
32
function body_stop() global Stop;Stop=%t
endfunction
(функция вызывается путѐм нажатия на кнопку Stop. Признак остановки принимает значение 1 и тело останавливается) function body_reinit()
(функция, вызывающаяся нажатием кнопки Reinit. Возвращает тело в исходное положение)
global y0 y1 Stop Stop=%t
(после вызова функции Stop принимает значение 1 и тело останавливается)
y1=y0
(значению текущего вектора состояния присваивается значение начального вектора состояния)
update_xplane(0) update_yplane(0) update_height(0) update_theta(0) update_phi(0) update_psi(0)
(изображение тела возвращается в начальное положение. Аргументами этих функций являются начальные значения обобщѐнных координат)
endfunction
Далее идут 6 функций, отвечающих за графическое построение зависимости обобщѐнных координат от времени:
function plot_Xplane()
(вызывается путѐм нажатия на кнопку Xplot. Строит график зависимости координаты Xplane от времени)
global Stop XPLANE
(переменная XPLANE – массив, содержащий значения координаты X центра масс тела в каждый момент времени, в который
33
происходит интегрирование системы дифференциальных уравнений. Массив заполняется в функции show, см. ниже)
if (Stop == %t) then scf(666); clf(); b=gca();
(функция вызывается только после остановки тела; если признак остановки равен 1, то создаѐтся новое графическое окно и дескриптор осей)
nn = size(XPLANE, '*');
(запоминается размер массива с координатами центра масс тела в каждый момент времени)
b.x_label.text="Time"; b.y_label.text="X";
(подписываются оси: под осью абсцисс будет стоять надпись Time, а слева от оси ординат – надпись X)
pp = 0.05:0.05:nn/20; plot(pp, XPLANE);
(переменная pp – массив, содержащий время интегрирования дифференциальных уравнений движения в секундах. Интегрирование происходит каждые 0.05 секунд. После этого строится график зависимости переменной XPLANE от времени)
end endfunction
Аналогичным образом строятся функции для построения графиков зависимости остальных обобщѐнных координат от времени.
function plot_Yplane() global Stop YPLANE if (Stop == %t) then
scf(666); clf(); b=gca(); nn = size(YPLANE, '*'); b.x_label.text="Time"; b.y_label.text="Y";
pp = 0.05:0.05:nn/20; plot(pp, YPLANE);
end
34
endfunction
function plot_Height() global Stop HEIGHT if (Stop == %t) then
scf(666); clf(); b=gca(); nn = size(HEIGHT, '*'); b.x_label.text="Time"; b.y_label.text="Height"; pp = 0.05:0.05:nn/20; plot(pp, HEIGHT);
end endfunction
function plot_Theta() global Stop THETA if (Stop == %t) then
scf(666); clf(); b=gca(); nn = size(THETA, '*'); b.x_label.text="Time"; b.y_label.text="Theta"; pp = 0.05:0.05:nn/20; plot(pp, THETA);
end endfunction function plot_Psi()
global Stop PSI
if (Stop == %t) then scf(666); clf(); b=gca(); nn = size(PSI, '*'); b.x_label.text="Time"; b.y_label.text="Psi"; pp = 0.05:0.05:nn/20; plot(pp, PSI);
end endfunction
35
function plot_Phi() global Stop PHI
if (Stop == %t) then scf(666); clf(); b=gca(); nn = size(PHI, '*'); b.x_label.text="Time"; b.y_label.text="Phi"; pp = 0.05:0.05:nn/20; plot(pp, PHI);
end endfunction
И, наконец, последняя функция, основными задачами которой являются решение системы уравнений движения и анимация. Эта функция вызывается внутри функции body_start (т.е. она вызывается после нажатия кнопки Start)
function show()
global y1 state_changed init Stop XPLANE YPLANE HEIGHT PSI PHI THETA
(глобальные переменные – текущий вектор состояния системы, признаки изменения состояния, инициализации и остановки, а также массивы с обобщѐнными координатами)
y=y1;
(текущий вектор состояния помещается в промежуточную переменную)
init=%f; dt=0.05
(задаются признак инициализации – 0, т.к. нажата кнопка Start и шаг интегрирования дифференциальных уравнений)
[y,w,iw]=ode(y,0,dt,body_dyn); y1=y;
(первый шаг интегрирования: аргументы – вектор с начальными условиями для решения задачи Коши, последующие 2 аргумента – начало и конец временного интервала интегрирования, четвѐртый аргумент – вектор из правых частей уравнений системы, выходные аргументы – вектор решения и 2 вектора с
36
параметрами интегрирования. После интегрирования в текущий вектор состояния помещается вектор решения)
realtimeinit(dt)
(задаются временные единицы; это нужно для регулировки скорости анимации – чем меньше параметр, тем быстрее будет двигаться тело на рисунке; в данном случае за временную единицу взят шаг интегрирования)
t0=dt
(осуществляется переход к второму шагу интегрирования – задаѐтся начало временного интервала второго шага интегрирования)
k=1
(количество шагов интегрирования, прошедших с момента нажатия кнопки Start)
while %t
(запускается бесконечный цикл, из которого можно выйти только с помощью команды break)
if state_changed then
[y,w,iw]=ode(y1,t0,t0+dt,body_dyn);y1=y; else
[y,w,iw]=ode(y,t0,t0+dt,body_dyn,w,iw);y1=y; end
(если состояние не поменялось, то интегрирование производится с теми же параметрами, что и на прошлом шаге (переменные w,iw в числе аргументов функции ode) и после интегрирования в текущий вектор состояния помещается вектор решения; если состояние поменялось, то эти переменные в качестве аргументов не используются. Таким образом, после выполнения этого условного оператора в переменной y1 хранится текущий вектор состояния системы после интегрирования)
if Stop then init=%t,break,end
if ~is_handle_valid(H) then break; end
(выход из цикла происходит только в тех случаях, если нажать на кнопку Stop или когда дескриптор графического объекта
37
становится недействительным (например, при закрытии графического окна))
set_body(H,y);
(изображается тело в положении, соответствующем текущему вектору состояния)
XPLANE(k)=y(1); YPLANE(k)=y(3); HEIGHT(k)=y(5); THETA(k)=y(7)*180/%pi; PHI(k)=modulo(y(9)*180/%pi,360); PSI(k)=modulo(y(11)*180/%pi,360);
(заполняются массивы с обобщѐнными координатами в каждый момент времени: в последних трѐх случаях производится перевод из радиан в градусы, к тому же в последних двух случаях значения берутся по модулю 360; это сделано на тот случай, если соответствующие углы меняются настолько, что их значения выходят за пределы 360 градусов)
if %t then update_xplane(y(1)) update_yplane(y(3)) update_height(y(5)) update_theta(y(7)*180/%pi)
update_phi(modulo(y(9)*180/%pi,360)) update_psi(modulo(y(11)*180/%pi,360))
end
(производится управление соответствующими ползунками – см. описание соответствующих функций в случае, когда у них есть входной аргумент)
k=k+1;t0=t0+dt;
(переход к следующей итерации – обновляется счѐтчик числа интегрирований, перемещается начало временного интервала интегрирования)
realtime(k);
38