Contents

Double Pendulum Fractal Map

Author: Tyler Jones Contact: tjjones6@wisc.edu Institution: University of Wisconsin-Madison Date: 05.27.2024

Description: This script simulates a double pendulum system and generates a fractal map that illustrates the behavior of the system for various initial conditions. The simulation uses the ODE45 solver to numerically integrate the equations of motion, capturing the time at which the second pendulum flips. The resulting data is visualized in a heatmap, where each point represents the time of the flip for a specific set of initial angles.

Analysis: https://tjjones6.github.io/DoublePendulum/

close all; clear all; clc;

User Input

g = 9.80665;  % Acceleration due to gravity (m/s^2)
L1 = 1.0;        % Length of the first pendulum arm (m)
L2 = 1.0;        % Length of the second pendulum arm (m)
m1 = 1.0;       % Mass of the first pendulum bob (kg)
m2 = 1.0;       % Mass of the second pendulum bob (kg)

% Initial Conditions
fidelity = 250; % Controls the number of gridpoints
theta1 = linspace(-pi,pi,fidelity);  % Initial angle of the first pendulum (radians)
theta2 = linspace(-pi,pi,fidelity);  % Initial angle of the second pendulum (radians)
omega1_0 = 0;  % Initial angular velocity of the first pendulum (rad/s)
omega2_0 = 0;  % Initial angular velocity of the second pendulum (rad/s)

% Time Span of Simulation
t_final = 25; % (s)
tspan = [0 t_final];

Numerical Integration using ODE45

% Initialize a matrix to store the flip times
flipTimes = NaN(fidelity, fidelity);

% WARNING: Must have the parallel computing toolbox installed. Otherwise
% replace 'parfor' with 'for' loop
tic % Not needed, but keeps track of how long the code runs
parfor i = 1:fidelity

    % Uncomment below if using a simple for loop
    % clc
    % fprintf('Map Completed: %.2f%%\n', i/fidelity*100)

    for j = 1:fidelity
        % Set initial conditions for the current pair of angles
        IC = [theta1(i), omega1_0, theta2(j), omega2_0];

        % Use ODE45 to integrate until the event (flip) occurs
        options = odeset('RelTol', 1e-6, 'AbsTol', 1e-6, 'Events', @stopEvent);
        [~, ~, t_event, ~, ~] = ode45(@(t, y) doublePendulumODE(t, y, g, L1, L2, m1, m2), tspan, IC, options);

        % Store the time of the event (flip) if it occurred
        if ~isempty(t_event)
            flipTimes(i, j) = t_event(1);
        end
    end
end
toc
Elapsed time is 89.751643 seconds.

Plotting Results

% Set NaN values to a specific number outside the range of normal flip times
flipTimesWithNaN = flipTimes;
flipTimesWithNaN(isnan(flipTimes)) = NaN;

% Transpose the data to correct orientation if necessary
flipTimesWithNaN = flipTimesWithNaN';

% Create a custom colormap
cmap = colormap(jet);
cmap = [0 0 0; cmap];  % Add black color for NaN values

% Plotting the fractal map using a heatmap
figure('units','normalized','Position',[0.1 0.1 .8 .8])
myfigpref
hold on; axis tight; axis equal;
imagesc(theta1, theta2, flipTimesWithNaN)
colormap(cmap); colorbar;
clim([-1 max(flipTimes(:))]);  % Set color axis to include the special NaN value
fig_xytit('$\theta_1$ [rad]','$\theta_2$ [rad]','Double Pendulum Fractal')
hold off

Define the function for the double pendulum ODEs

function dydt = doublePendulumODE(~, y, g, L1, L2, m1, m2)
    % Unpack the state variables
    theta1 = y(1);
    omega1 = y(2);
    theta2 = y(3);
    omega2 = y(4);

    % Store equations of motion
    dydt = zeros(4, 1);
    dydt(1) = omega1;
    dydt(2) = (-g * (2 * m1 + m2) * sin(theta1) - m2 * g * sin(theta1 - 2 * theta2) - 2 * sin(theta1 - theta2) * m2 * (omega2^2 * L2 + omega1^2 * L1 * cos(theta1 - theta2))) / (L1 * (2 * m1 + m2 - m2 * cos(2 * theta1 - 2 * theta2)));
    dydt(3) = omega2;
    dydt(4) = (2 * sin(theta1 - theta2) * (omega1^2 * L1 * (m1 + m2) + g * (m1 + m2) * cos(theta1) + omega2^2 * L2 * m2 * cos(theta1 - theta2))) / (L2 * (2 * m1 + m2 - m2 * cos(2 * theta1 - 2 * theta2)));
end

Event function to stop the integration after pendulum flips

function [value, isterminal, direction] = stopEvent(~, y)
    theta2 = y(3);  % Angle of the second pendulum
    value = abs(theta2) - 2*pi;  % Condition for the event
    isterminal = 1;  % Stop the integration
    direction = 0;  % Detect both increasing and decreasing directions
end

Reference Functions for Plotting

% Barrowed from T.G.J. Chandler @UW-Madison Mathematics
function myfigpref
    set(0, 'DefaultAxesFontSize', 20);
    set(0, 'DefaultAxesLineWidth', 2);
    set(0, 'DefaultLineLineWidth', 2);
    set(0, 'DefaultPatchLineWidth', .7);
    set(0, 'DefaultLineMarkerSize', 6);
    grid on;
    box on;
    h = gca;
    h.TickLabelInterpreter='latex';
    h.MinorGridAlpha=0.05;
    h.GridAlpha=0.05;
    h.FontSize=25;
    h.LineWidth=2;
    h = gcf;
    h.Color = [1,1,1];
end

function fig_xytit(xlab, ylab, tit)
    if nargin < 3
        tit = '';
    end
    xlabel(xlab, 'interpreter', 'latex');
    ylabel(ylab, 'interpreter', 'latex');
    title(tit, 'interpreter', 'latex');
end