在Julia中使用动画可视化微分方程的解

时间:2019-04-20 17:38:54

标签: animation julia

我已经使用Julia中的Euler方法实现了一个由两个二阶微分方程组成的系统。下面的代码显示了如何调用Euler方法来解决相关系统。

θ1 = 1.1900518004210798; θ2 = 0.3807445263738167
f(t, y) = [y[2], -2(y[1] - θ1) - 4y[2] + 0.5sin(3pi*t),
           y[4], -2(y[3] - θ2) - 4(y[4] + abs(y[2])) + 0.5sin(3pi*t)]
y0 = [pi/2, 0, pi/6, 0]; t0 = 0; tFinal = 50; h = 0.001
res = euler(f, y0, t0, tFinal, h)

结果res是四个数字的向量

1.18798735437173    
-0.0458294959470722  
0.31530569612003573 
-0.049213402534541074

第一个条目是底线段与x轴的夹角,而第三个条目是两个线段彼此的夹角(见下图)。

enter image description here

要创建此图,我称为plot_robotarm([res[1], res[3]]),它是根据以下代码实现的。

function plot_robotarm(thetav)
    # Plots a robotarm with angles thetav
    R = 1;
    xv=zeros(length(thetav)+1)
    yv=zeros(length(thetav)+1)
    for i in 1:length(thetav)
        xv[i+1]=xv[i]+R*cos(thetav[i])
        yv[i+1]=yv[i]+R*sin(thetav[i])
    end
    # Plot with colors 
    opts = (:circle, 10, 1., :blue, stroke(7, 1., :red))
    plt = plot(xv, yv,
               marker = opts,
               c = :red,
               w = 5,
               legend = false,
               xlims = (0, 2.0),
               ylims = (0, 2.0))
    display(plt)
end

如何创建动画来可视化欧拉方法的连续迭代如何使机械臂(即两个线段)朝着t = 50的最终点移动? (我不需要绘制每个迭代,只需绘制足够的动画就可以捕获机器人手臂的运动。)

1 个答案:

答案 0 :(得分:2)

您可以使用ffmpeg和Luxor.jl的动画功能制作动画GIF。需要修改框架功能以反映程序中每个步骤的图形显示。有关更多信息,请参阅卢克索的文档。

using Luxor
using Colors
using BoundaryValueDiffEq

# constants for differential equations and movie
const g = 9.81
const L = 1.0                         # pendulum length in meters
const bobd = 0.10                     # pendulum bob diameter in meters
const framerate = 50.0                # intended frame rate/sec
const t0 = 0.0                        # start time (s)
const tf = 2.3                        # end simulation time (s)
const dtframe = 1.0/framerate         # time increment per frame
const tspan = LinRange(t0, tf, Int(floor(tf*framerate)))  # array of time points in animation

const bgcolor = "black"               # gif background
const leaderhue = (0.80, 0.70, 0.20)  # gif swing arm hue light gold
const hslcolors = [HSL(col) for col in (distinguishable_colors(
                   Int(floor(tf*framerate)+3),[RGB(1,1,1)])[2:end])]
const giffilename = "pendulum.gif"    # output file

# differential equations copied from docs of DifferentialEquations.jl
simplependulum!(du, u, p, t) = (θ=u[1]; dθ=u[2]; du[1]=dθ; du[2]=-(g/L)*sin(θ))
bc1!(residual, u, p, t) = (residual[1] = u[div(end,2)][1] + pi/2; residual[2] = u[end][1] - pi/2)
bvp1 = TwoPointBVProblem(simplependulum!, bc1!, [pi/2,pi/2], (tspan[1],tspan[end]))
sol2 = solve(bvp1, GeneralMIRK4(), dt=dtframe) 

# movie making background
backdrop(scene, framenumber) = background(bgcolor)

function frame(scene, framenumber)
    u1, u2 = sol2.u[framenumber]
    y, x = L*cos(u1), L*sin(u1)
    sethue(leaderhue)
    poly([Point(-4.0, 0.0), Point(4.0, 0.0),
          Point(160.0x,160.0y)], :fill)
    sethue(Colors.HSV(framenumber*4.0, 1, 1))
    circle(Point(160.0x,160.0y), 160bobd, :fill)
    text(string("frame $framenumber of $(scene.framerange.stop)"),
        Point(0.0, -190.0),
        halign=:center)
end

muv = Movie(400, 400, "Pendulum Demo", 1:length(tspan))
animate(muv, [Scene(muv, backdrop),
              Scene(muv, frame, easingfunction=easeinoutcubic)],
              creategif=true, pathname=giffilename)