257 lines
8.8 KiB
Matlab
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

%% Lesson 10, extra -- Chaos!
% Based on work for PH429: Chaos & Nonlinear Dynamics. The following was
% translated from the original NumPy/Matplotlib code. See Strogatz' Nonlinear
% Dynamics and Chaos (the source for much of this information) if you want to
% know more!
close all; clear; clc;
% Simple systems of nonlinear differential equations (also iterated nonlinear
% maps) often exhibit surprisingly complex behavior. Lorenz's "strange
% attractor," discovered in 1963, was an example of this: he discovered that an
% exceedingly simplified (and entirely deterministic!) model of the weather was
% still able to produce unpredictable fluctuations in temperature, wind speed,
% etc. -- the system exponentially amplified miniscule parameter changes, so
% every decimal place mattered. Further work with analog computers and the
% then-emerging digital computers led to the field we now call chaos theory.
% Chaos has much to do with fractal geometry, so we'll start by generating a
% few fractals. Because... why not?
%% The Chaos Game & Sierpinski Triangles
% The game is simple:
% 1. Place three vertices in the plane, corresponding to the vertices of an
% equilateral triangle.
% 2. Randomly choose a point P(0).
% 3. Each turn, choose a random vertex, and plot a point P(n) halfway between
% that vertex and point P(n - 1).
% Let's see what happens.
n1 = 5e5; % points
vertices = [0, 0; .5, .5*sqrt(3); 1, 0];
r = .5; % fraction of the way between points and vertices (here halfway)
% point coordinates
points = zeros(n1, 2);
choices = randi([1 3], n1, 1);
% randomly choose the first point somewhere in the plane
points(1, :) = 100*randn(1, 2);
% choose the rest
% note: the loop here is actually necessary, like it was in G-S -- each
% iteration depends upon the previous one.
for i = 2:n1
choice = choices(i);
vertex = vertices(choice, :);
last_point = points(i - 1, :);
points(i, :) = last_point + r*(vertex - last_point);
end
% plot the thing
figure;
scatter(points(:, 1), points(:, 2), 1);
xlim([-.1 1.1]);
ylim([-.2 1]);
xticks([]);
yticks([]);
pbaspect([1 1 1]); % make the plot box square
title('The Sierpinski Triangle, by Chance', 'Interpreter', 'latex');
% A rather important property of fractals is their fractional dimension -- this
% triangle, for example, is not quite two-dimensional but is clearly more than
% one-dimensional. So how do we measure this dimension?
% One simple measure, known as self-similarity dimension, is relatively easy to
% find for the Sierpinski triangle. The idea is we simply examine how many
% smaller versions of a given shape could fit into that shape, and what size
% they would be in relation. For example, a square with scale 1 can be made up
% of 4 smaller squares scaled by 1/2, or 9 smaller squares with scale 1/3:
% ----------------- -----------------
% | | | | |
% | | | 1/2 | 1/2 |
% | | | | |
% | 1 | = |-------|-------|
% | | | | |
% | | | 1/2 | 1/2 |
% | | | | |
% ----------------- -----------------
% A square thus has self-similarity dimension log₂4 = log₃9 = 2 (as one might
% expect). The Sierpinski triangle is composed of 3 copies of itself scaled by
% 1/2, and thus has self-similarity dimension log₂3 ≈ 1.585.
% I wonder if we could have MATLAB calculate these...
%% Iterated Maps
% One way to create chaotic behavior is to iterate a nonlinear map: e.g., plot
% the set {x, sin(x), sin(sin(x)), sin(sin(sin(x))), ...}. The values will
% generally hop unpredictably around, but will often stay closer to some values
% than others...
% The following plot is a visual representation of these iterations, called a
% cobweb. Cobwebs are often used to qualitatively analyze nonlinear maps. The
% idea is, since the output of the map will be fed back into the input, we plot
% a point on the map's curve, translate horizontally to the line y = x, then
% translate vertically back to the map and repeat. This gives a visual
% representation of plugging the output back into the input.
% When you see this, think about which points on the map will "attract" the
% cobweb, which will "repel" it, and how one might go about making that
% distinction.
n2 = 10;
map = @(x) 2*sin(x);
% create the map curve and the center line
x = linspace(0, pi, 100).';
y_map = map(x);
y_line = x;
% create the cobweb
map_pts = zeros(2*n2 + 1, 2);
map_pts(1, :) = [.2, 0];
for i = 1:n2
last_pt = map_pts(2*i - 1, :);
mapped = [last_pt(1), map(last_pt(1))];
on_the_line = [mapped(2), mapped(2)];
map_pts(2*i, :) = mapped;
map_pts(2*i + 1, :) = on_the_line;
end
% plot it
figure;
hold on;
plot(x, y_map, 'b');
plot(x, y_line, 'k');
plot(map_pts(:, 1), map_pts(:, 2), 'r');
start = map_pts(1, :);
scatter(start(1), start(2), 'r');
text(start(1) + .03, start(2) + .03, 'Start Point');
xlim([0 pi]);
xticks([0 pi/2 pi]);
ylim([0 2.1]);
xticklabels({'0', '\pi/2', '\pi'});
title('Cobweb of \(2 \sin x\)', 'Interpreter', 'latex');
%% Orbit Diagrams
% The above example was... not too crazy. The map x → α sin x *can* exhibit
% more complex behavior, but it requires α to be greater than π (so that we can
% escape the [0, π] interval). The map will first stay close to two points,
% then a few, then... altogether too many. This is usually plotted with what is
% called an orbit diagram, showing roughly how much time the map spends at
% certain values for a given α.
map_alpha = @(alpha, x) alpha.*sin(x);
n3 = 6e2; % iterations to go through
frames = 9e2; % run this many parallel alpha computations
toss = 2e2; % delete this many points from the start
min_alpha = 2.2;
max_alpha = 3.1;
alphas = linspace(min_alpha, max_alpha, frames);
% at least we can run the frames in parallel...
values = zeros(n3, frames);
values(1, :) = pi/4; % the first input each time
for i = 2:n3
values(i, :) = map_alpha(alphas, values(i - 1, :));
end
% plot this crazy thing
values = values((toss + 1):end, :);
figure;
scatter(alphas.', values, 1, [.7 0 0], 'MarkerEdgeAlpha', .3);
title('Orbit of \(\alpha \sin x\)', 'Interpreter', 'latex');
xlabel('\alpha');
ylabel('map value');
%% The Phase Plane
% In continuous time, we have differential equations rather than iterated maps.
% One way to analyze higher-order equations is using the so-called phase plane,
% which is a plot of our state variable and its derivative. The idea is that a
% second-order differential equation really acts like a system in two
% dimensions, and is best analyzed directly as such.
% We'll analyze the motion of an damped pendulum, which has the governing
% equation d²θ/dt² + b dθ/dt + (g/L) sin θ = 0. For simplicity (it won't change
% the qualitative behavior), we'll let g/L = 1. Then (the phase plane bit)
% we break this into two differential equations,
% * dθ/dt = ω and
% * dω/dt = -(sin θ + bω),
% and make a plot of the *vector* (dθ/dt, dω/dt) in θ-ω space. We can easily
% plot the vector field with `quiver`, and MATLAB's `streamline` is rather
% effective at plotting either single trajectories or a whole suite of possible
% solutions.
b = .2;
min_theta = -3*pi;
max_theta = 3*pi;
min_omega = -3*pi;
max_omega = 3*pi;
theta_range = linspace(min_theta, max_theta, 300);
omega_range = linspace(min_omega, max_omega, 200);
[theta, omega] = meshgrid(theta_range, omega_range);
theta_dot = omega;
omega_dot = -(sin(theta) + b*omega);
% to cut down on the # of points we plot
d = 10;
[sparse_x, sparse_y] = ...
meshgrid(d:d:length(theta_range), d:d:length(omega_range));
sparse = sub2ind(size(theta), sparse_y(:), sparse_x(:));
% plot this thing
figure;
hold on;
quiver(theta(sparse), omega(sparse), ...
theta_dot(sparse), omega_dot(sparse), 'm');
streamline(theta, omega, theta_dot, omega_dot, ...
theta(sparse_y, [1 end]), omega(sparse_y, [1 end]));
xlim([min_theta max_theta]);
xticks(linspace(min_theta, max_theta, 7));
ylim([min_omega max_omega]);
xlabel('pendulum angle');
ylabel('angular velocity');
title('Behavior of a Damped Pendulum', 'Interpreter', 'latex');
%% Strange Attractors
% I won't go into detail here -- suffice it to say the behavior of this system
% would be quite opaque without numerical integration. Fortunately, we have
% just that! Lorenz managed to prove analytically that this system had no
% closed cycles and yet all its trajectories eventually stayed within a bounded
% region of space, but beyond that... well, we'll see.
sigma = 10;
r = 28;
b = 8/3;
x_dot = @(x, y, z) sigma*(y - x);
y_dot = @(x, y, z) r*x - y - x.*z;
z_dot = @(x, y, z) x.*y - b*z;
[x, y, z] = meshgrid(linspace(-50, 50, 100));
u = x_dot(x, y, z);
v = y_dot(x, y, z);
w = z_dot(x, y, z);
figure;
hold on;
streamline(x, y, z, u, v, w, 0, 1, 0, [.1 2e4]);
scatter3(0, 1, 0);
view(3);
grid on;
text(0, 0, -2, 'Start Point');
xlabel('x');
ylabel('y');
zlabel('z');
title("Lorenz's Strange Attractor", 'Interpreter', 'latex');