Сообщество Engee

Анимация маятника

Автор
avatar-maximsidorovmaximsidorov
Notebook

Анимация движения маятника с использованием Julia

Этот пример показывает реализацию симуляции движения физического маятника с использованием дифференциальных уравнений и создания анимации на языке программирования Julia.

Введение

Маятник — это простейшая физическая система, широко используемая для изучения периодического движения и осцилляций. В данном примере рассмотрена задача моделирования движения простого маятника с помощью системы обыкновенных дифференциальных уравнений второго порядка, которая затем решается в рамках краевой задачи методом коллокаций (MIRK). После нахождения решения, происходит его визуализация в формате GIF-анимации с помощью библиотеки Luxor.jl, основанной на Cairo.

Основной целью является демонстрация возможностей языка Julia при численном решении физических задач и генерации графической визуализации. Анимация позволяет понять динамику движения маятника — как он перемещается по времени, начиная с заданного положения и заканчивая противоположной точкой через определённый интервал времени.

# Установка требуемых пакетов
import Pkg; Pkg.add("Luxor")
import Pkg; Pkg.add("Colors")
import Pkg; Pkg.add("BoundaryValueDiffEq")

Подключение библиотек

using Luxor        # для рисования анимации
using Colors       # для управления цветами элементов анимации
using BoundaryValueDiffEq  # для решения краевых задач обыкновенных дифференциальных уравнений

Определение констант и параметров для модели

Константы физической модели и анимации

const g = 9.81;     # ускорение свободного падения (м/с²)
const L = 1.0;      # длина нити маятника (метры)
const bobd = 0.10;  # диаметр груза (bob) маятника (в метрах)

Параметры анимации

const framerate = 50.0;                # частота кадров анимации (кадр/сек)
const t_0 = 0.0;                        # начальное время моделирования (сек)
const tf = 2.3;                        # конечное время моделирования (сек)
const dtframe = 1.0/framerate;         # длительность 1 кадра в секундах
const tspan = LinRange(t_0, tf, Int(floor(tf*framerate)));  # массив моментов времени для анимации

Цвета и названия файлов

const bgcolor = "black";               # цвет фона анимации
const leaderhue = (0.80, 0.70, 0.20);  # светло-золотой цвет для рычага
const hslcolors = [HSL(col) for col in (distinguishable_colors(
                   Int(floor(tf*framerate)+3),[RGB(1,1,1)])[2:end])];  # набор цветов для элементов
const giffilename = "pendulum.gif";    # имя выходного файла GIF

Формулировка задачи и решение дифференциального уравнения

Определение функции для уравнений движения маятника

function simplependulum(du, u, p, t)
    θ = u[1]   # угол отклонения
     = u[2]  # скорость изменения угла (угловая скорость)
    
    du[1] =                      # производная угла = угловая скорость
    du[2] = -(g/L) * sin(θ)        # уравнение движения: θ'' = -(g/L) * sin(θ)
end
simplependulum (generic function with 1 method)

Задание граничных условий

function bc2(residual, u, p, t)
    residual[1] = u[end÷2][1] + pi/2     # значение угла в середине интервала равно π/2 (положение слева)
    residual[2] = u[end][1] - pi/2       # значение угла в конце равно -π/2 (положение справа)
end
bc2 (generic function with 1 method)

Формирование и решение краевой задачи

bvp2 = BVProblem(simplependulum, bc2, [pi/2, pi/2], (tspan[1], tspan[end]));
sol2 = solve(bvp2, MIRK4(), dt=dtframe);   # метод Рунге–Кутты 4-го порядка с коррекцией

Функции отрисовки анимации

Фоновая функция для отрисовки кадра

function backdrop(scene, framenumber)
    background(bgcolor)   # установка черного фона
end
backdrop (generic function with 1 method)

Основная функция рисования каждого кадра

function anim_frame(scene, framenumber)
    # Получаем текущие значения угла и угловой скорости
    u1, u2 = sol2.u[framenumber]
    # Вычисляем координаты центра боба по формулам тригонометрии
    y = L * cos(u1)
    x = L * sin(u1)
    
    # Нарисовать рычаг (от точки подвеса до груза)
    sethue(leaderhue)
    poly([Point(-4.0, 0.0), Point(4.0, 0.0),
          Point(160.0x, 160.0y)], :fill)
    
    # Нарисовать груз (bob) маятника
    sethue(Colors.HSV(framenumber*4.0, 1, 1))  # меняющийся цвет в зависимости от номера кадра
    circle(Point(160.0x, 160.0y), 160*bobd, :fill)

    # Напечатать информацию о текущем кадре
    Luxor.text(string("frame $framenumber of $(scene.framerange.stop)"),
         Point(0.0, -190.0), halign=:center)
end
anim_frame (generic function with 1 method)

Создание и воспроизведение анимации

Создаем объект анимации с указанным размером окна

muv = Movie(400, 400, "Pendulum Demo", 1:length(tspan))
Movie(400.0, 400.0, "Pendulum Demo", 1:114)

Добавляем две сцены: фон и основную

Luxor.animate(muv, [
    Luxor.Scene(muv, backdrop),             # фоновая сцена
    Luxor.Scene(muv, anim_frame, easingfunction=easeinoutcubic)  # главная сцена с плавным переходом
], creategif=true, pathname=joinpath(@__DIR__, giffilename))            # создаём .gif и сохраняем его под именем "pendulum.gif"
Info: Frames for animation "Pendulum Demo" are being stored in directory: 
	 /tmp/jl_1cbAyz
Info: ... 114 frames saved in directory:
	 /tmp/jl_1cbAyz
[ Info: GIF is: /user/animate_a_pendulum/pendulum.gif
No description has been provided for this image

Заключение

Мы рассмотрели программу на языке Julia, которая решает краевую задачу для модели движения маятника и строит на её основе плавную анимацию в формате GIF. Ключевые элементы: физическая модель (уравнения движения), численное решение (метод MIRK4), и визуализация (с помощью Luxor). Такой подход полезен не только в образовательных целях, но и для моделирования более сложных систем с ограничениями на начальные или конечные условия. Этот пример иллюстрирует мощные инструменты в области научных вычислений и графической визуализации в экосистеме Julia.

Пример разработан с использованием материалов Rosetta Code