%% 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');