problem01
1. Set up (define system, draw FBD, write ODEs) a particle problem. Just one particle. 2D or 3D, your choice. Use a force, or forces that you like (gravity, spring, air friction). Any example of interest. Find a numerical solution. Graph it. Animate it. Try to make an interesting observation.
System Description and Free Body Diagram
I think I have chosen a just hard enough interesting problem. A spring pendulum consists of a mass \(m\) attached to a spring of natural length \(l_0\) and spring constant \(k\).
The system experiences: - Spring force \(\vec{F_s} = k(\|{\vec{r}\|}-l_0)(-\hat{r})\) - Gravitational force \(\vec{F_g} = mg(-\hat{j})\) - Damping force \(\vec{F_d} = cv(-\hat{v})\)
Equations of Motion
In Cartesian coordinates, the equations of motion are:
\[\dot{\vec{r}} = \vec{v}\] \[\dot{\vec{v}} = -k(\|\vec{r}\|-l_0) \hat{r} - c \vec{v} - mg\hat{j}\]
The corresponding code for the ODE in file ./SpringPendulum/src/Physics.jl:
module Physics
using ..Parameters
using LinearAlgebra
using UnPack
export spring_pendulum!
function spring_pendulum!(du, u, p::Parameters.Param, t)
@unpack mass, gravity, stiffness, restinglen, viscosity = p
= u[1:2]
r⃗ = u[3:4]
v⃗
= [0.0; 1.0]
ĵ = mass * gravity * (-ĵ)
gravity = stiffness * (norm(r⃗) - restinglen) * (-normalize(r⃗))
spring = -viscosity * v⃗
drag
= (spring + drag + gravity)
force
1:2] = v⃗
du[3:4] = force / mass
du[end
end
Numerical Solution
In file ./SpringPendulum/src/SpringPendulum.jl
module SpringPendulum
using DifferentialEquations
include("Parameters.jl")
include("Physics.jl")
include("Visualization.jl")
# problem setup
= (1, 0)
x₀, y₀ = [x₀;y₀]
r₀ = [1.0;0.0]
v₀ = [r₀;v₀]
u₀ = (0.0,25.0)
tspan = Parameters.Param(m=1,g=1,c=0.0,k=1,l₀=0)
p = ODEProblem(Physics.spring_pendulum!, u₀, tspan, p)
prob
# solver
= 0.001
Δt = solve(prob, saveat=Δt, reltol=1e-6, abstol=1e-6)
sol
# visualize
# ...
end # module SpringPendulum
Phase Space Trajectory
Plot showing the system evolution in phase space. In file ./SpringPendulum/src/Visualization.jl:
Code corresponding to this in file SpringPendulum/src/Visualization.jl:
function plot_trajectory(sol; title="Spring Pendulum Trajectory")
= reduce(hcat, sol.u)'
a = a[:, 1]
x = a[:, 2]
y = atan.(a[:, 2], a[:, 1])
θ
= (minimum(x)-1, maximum(x)+1)
xlimits = (minimum(y)-1, maximum(y)+1)
ylimits
= Figure()
trajectory_plot = Axis(trajectory_plot[1, 1],
trajectory =title,
title="X position",
xlabel="Y position",
ylabel=(xlimits, ylimits),
limits=1,
aspect
)lines!(trajectory, x, y,
="Trajectory",
label
)axislegend(position=:rb)
= Axis(trajectory_plot[1, 2],
trajectory ="Theta vs time",
title="Time",
xlabel="Theta",
ylabel
)lines!(trajectory, sol.t, θ)
return trajectory_plot
end
Animation
The following shows the animation for the solution system. The code corresponding to this animation:
TODO: add springs to visualise
The code corresponding to this animation is in file ./SpringPendulum/src/Visualization.jl:
function makie_animation(sol; filename="sol_animation.gif", title="Animation")
= reduce(hcat, sol.u)'
sol_matrix = sol_matrix[:, 1]
x = sol_matrix[:, 2]
y = atan.(sol_matrix[:, 2], sol_matrix[:, 1])
θ
# coarse boundaries, for continuous(interpolated) boundary see: https://docs.sciml.ai/DiffEqDocs/stable/examples/min_and_max/
= (minimum(x)-1, maximum(x)+1)
xlimits = (minimum(y)-1, maximum(y)+1)
ylimits
= Observable(0.0)
time
= @lift(sol($time)[1])
x = @lift(sol($time)[2])
y
# Create observables for line coordinates
= @lift([0, $x])
line_x = @lift([0, $y])
line_y
= Figure()
animation = Axis(animation[1, 1], title = @lift("t = $(round($time, digits = 1))"), limits=(xlimits, ylimits), aspect=1)
ax
scatter!(ax, x, y, color=:red, markersize = 15)
lines!(ax, line_x, line_y, color=:black)
= 30
framerate = range(0, last(sol.t), step=1/framerate)
timestamps
record(animation, filename, timestamps;
= framerate) do t
framerate = t
time[] end
return animation
end
Observations
- Energy exchange between potential and kinetic forms
- Damped oscillations due to viscous friction
- For some parameters there is weird behaviour at very small scales. This is probably an artifact of the solver and floating point truncations. I was unable to reproduce this, but I had shown this to Professor Andy and Ganesh Bhaiya.
- Increasing
c
by a little has a drastic effect - The problem was fun to simulate
- Julia was fun to code in: Libraries were ergonomic to use, DifferentialEquations.jl, and Makie.jl
- I noticed only much later that all of the trajectories for when resting length is zero are elipses.