Spring pendulum simulation

A lot of real-world phenomena can be called dynamical systems.  The state of such systems varies with time. Modeling such systems requires the use of differential equations. We will take here an example of modeling a pendulum attached to a spring, as shown in the following image. The pendulum swings to and fro. Furthermore, since the bob is attached to a spring, the bob also oscillates up and down:

 

We study the evolution of two variables over time:

  • Length l of the spring
  • Angle (θ) between the spring and the center line, as shown in the preceding diagram.

Since there are two variables changing over time, the state of our system at any time can be represented by using four state variables:

  • Spring length (l)
  • Change in spring length (dl/dt), which is  velocity
  • Angle (θ)
  • Change in angle (dθ/dt), which is the angular velocity

They are modeled by the following four differential equations:

The first equation measures linear velocity, which is the rate of change of L over time. The second equation is a second derivative and gives us the acceleration. The third equation measures change in theta over time and hence represents the angular velocity. The last equation is the second derivative of theta over time and hence it represents the angular acceleration.

Let us begin by defining the following constants:

UNSTRETCHED_SPRING_LENGTH = 30
SPRING_CONSTANT = 0.1
MASS = 0.3
GRAVITY = 9.8
NUMBER_OF_STEPS_IN_SIMULATION = 500

Accordingly, let us begin by defining the initial value for all these four state variables:

state_vector = [ 1, 1, 0.3, 1 ]  
# 4 values represent 'l', 'dl/dt', 'θ', 'dθ/dt' respectively

Then, we define the differentials_functions  method which returns an array of the four differential functions defined previously:

def differential_functions(state_vector, time):
func1 = state_vector[1]
func2 = (UNSTRETCHED_SPRING_LENGHT + state_vector[0]) *
state_vector[3]**2 -
(SPRING_CONSTANT / MASS * state_vector[0]) + GRAVITY *
np.cos(state_vector[2])
func3 = state_vector[3]
func4 = -(GRAVITY * np.sin(state_vector[2]) + 2.0 * state_vector[1] *
state_vector[3]) / (UNSTRETCHED_SPRING_LENGHT + state_vector[0])
return np.array([func1, func2, func3, func4])

Next, we will use scipy.integrate.odeint  to solve the differential equations. This method can be used to solve a system of ordinary differential equations of the following form:

Here's the signature of scipy.integrate.odeint:

scipy.integrate.odeint(func, y0, t, optional arguments)

Where:

  • func: Callable(y, t0, ...), which computes the derivative of y at t0
  • y0: Array of initial condition (can be a vector)
  • t: Array of time points for which to solve for y

The initial value point should be the first element of this sequence.

This method takes as input the derivative function (func), an array of initial state values (), and an array of times (t). It returns an array of state values corresponding to those times.

Since we are differentiating against time, we need a variable to track time (8.10_spring_pendulum.py):

time = np.linspace(0, 37, NUMBER_OF_STEPS_IN_SIMULATION)

The number 37 here is the step size for sampling time. Changing this value will change the speed of simulation.

Now we finally solve the sets of differential equations using scipy.integrate.odeint as follows (8.10_spring_pendulum.py):

ode_solution = odeint(differential_functions, state_vector, time)

Since we have set the number of simulation steps to 500 and there are four state variables, the odeint method returns a numpy array of the shape (500, 4), where each row represents the value of the four state variables at a given point of time.

Now recall that our state vector is a list of four values, ['l', 'dl/dt', 'θ', 'dθ/dt']. So the 0th column returns the value 'l' and the 2nd column represents the value 'θ'.  This is the polar format representation. Our canvas understands the Cartesian coordinate system. So we obtain the Cartesian coordinates (xy) for the values of each value of (lθ) as follows (8.10_spring_pendulum.py):

x_coordinates = (UNSTRETCHED_SPRING_LENGHT + ode_solution[:, 0]) 
* np.sin(ode_solution[:, 2])
y_coordinates = (UNSTRETCHED_SPRING_LENGHT + ode_solution[:, 0])
* np.cos(ode_solution[:, 2])

With that data in hand, it's now just a matter of plotting it on the canvas. So we create a Canvas widget in a mainloop and call an update_graph method that runs every 15 milliseconds, deleting everything on the canvas and redrawing the line and an oval (pendulum bob).  We also add an increment variable, plot_step, which is reset to zero every time the simulation ends. This keeps the pendulum swinging forever (8.10_spring_pendulum.py):

plot_step = 0

def update_graph():
global plot_step
if plot_step == NUMBER_OF_STEPS_IN_SIMULATION: # simulation ended
plot_step = 0 # repeat the simulation
x, y = int(x_coordinates[plot_step]) + w / 2,
int(y_coordinates[plot_step] + h / 2)
canvas.delete('all')
canvas.create_line(w / 2, 0, x, y, dash=(2, 1), width=1, fill="gold4")
canvas.create_oval(x - 10, y - 10, x + 10, y + 10, outline="gold4",
fill="lavender")
plot_step = plot_step + 1
root.after(15, update_graph)

This will create a spring pendulum, as shown in the following screenshot:

That concludes the iteration. You can explore this simulation by changing the values of the constants (mass, spring constant, and gravity). Also, change the initial state vector elements, such as the angle and velocity, and the program should respond as it would in a real-world situation.

We saw how to obtain ODE, which is a derivative with respect to only one variable. An extension of this concept is partial differential equations (PDEs), which are derivatives with respect to several variables. More complex phenomena, such as electromagnetism, fluid mechanics, heat transfer, electromagnetic theory and various biological models, are all modeled by partial differential equations. 

The FEniCS computing platform (https://fenicsproject.org/) is a popular open-source software tool for solving PDEs with a Python binding.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.60.62