Gentle Introduction to Brownian Motion

Learn how you would move if you were a particle in a tea

--

Motivation

Have you ever looked at some droplets of dust in your tea, if not poor some water in your glass and just wait to see what happens after to a little dust particle in that water? You will see that the dust starts to behave in a somewhat erratic way, no clear pattern, but why is it moving?

Image of a 2-dimensional Brownian motion

If we are interested about the movement on three axes of a particle in 3 dimensions, then we have the following image.

Image of a 3-dimensional Brownian motion

This type of stochastic motion has many outstanding properties, such as being non-differentiable almost everywhere and at the same time being continuous, as well-being a fractal in a graphical sense.

Animation of a 2-dimensional Brownian motion

Particles bumping

It was seen theoretically that there were some particles bumping to each other, and this same particles were the cause of all the dust movement. The fact that the particles bump into the dust makes it move. Now in water there is not only a handful of particles, but we are talking millions of particles and so on might ask what happens to the trajectory that the dust will follow? These are, my fellow readers, what we call a Brownian motion.

From Randomness there is order

There were a couple of tries before we arrived in a successful mathematical description of a Brownian motion. However, for the most intrigued readers, I would point out to Levy as the one who really contributed to the construction of Brownian motion. Brownian motion is what we call in mathematics a stochastic process and these are meant to model events that are random over time, have in your mind:

  • Financial Markets
  • Dust Moving on Glass
  • You receiving a message

These are all stochastic in nature over time, one of these stochastic processes is what we mentioned previously as Brownian motion and these are stochastic processes which have the following characteristics (let's denote B(t) as the stochastic process that describes Brownian motion):

  • B(0) = 0.
  • For any 0 ≤ t_0 ≤ ⋯ ≤ t_n we have that B(t_i)−B(t_j) is a random variable that is randomly distributed.
  • The distribution of B(t+j)−B(t) is the same as B(t)
  • For s < t we have the increment B(t) — B(s) has the following normal distribution N(0, t-s).
  • The function t → B(t) is continuous with probability 1.

Applications

Finance

In some theoretical contexts there is a place for Brownian motion in the stock market, this of course of interest to some hedge funds as well as to governance.

Physics

Brownian motion describes the movement of a particle in a fluid in a satisfactory way, it is of interest to see how particles behave in a fluid, that studying how Brownian motion evolves overtime.

Code of the Week

Here is a Python code that I have produced with GPT o1 Preview that provides a way for you to generate your own python motions in your local machine.

Python Code for 2-dimensional Brownian Motion

import numpy as np
import matplotlib.pyplot as plt

# Parameters
R = 5.0 # Radius of the circle
N_steps = 10000 # Number of steps in the simulation
delta = 0.1 # Standard deviation of the step size

# Initialize position at the center of the circle
x = [0.0]
y = [0.0]

# Simulate Brownian motion
for _ in range(N_steps):
# Generate random displacements
dx, dy = np.random.normal(0, delta, 2)

# Tentative new position
x_new = x[-1] + dx
y_new = y[-1] + dy

# Check if the new position is inside the circle
r_new = np.sqrt(x_new**2 + y_new**2)
if r_new > R:
# Reflect the particle back into the circle
# Compute the normal vector at the point of exit
r_vec = np.array([x_new, y_new])
r_norm = np.linalg.norm(r_vec)
n = r_vec / r_norm # Unit normal vector

# Original displacement vector
d = np.array([dx, dy])

# Reflect the displacement over the normal vector
d_reflected = d - 2 * np.dot(d, n) * n

# Update the new position with the reflected displacement
x_new = x[-1] + d_reflected[0]
y_new = y[-1] + d_reflected[1]

# Ensure the new position is inside the circle
r_new = np.sqrt(x_new**2 + y_new**2)
if r_new > R:
# If still outside, project onto the circle boundary
x_new = R * x_new / r_new
y_new = R * y_new / r_new

# Append the new position
x.append(x_new)
y.append(y_new)

# Convert lists to arrays for plotting
x = np.array(x)
y = np.array(y)

# Plotting the trajectory
fig, ax = plt.subplots(figsize=(8, 8))
ax.plot(x, y, lw=0.5, color='blue')

# Draw the circle boundary
theta = np.linspace(0, 2 * np.pi, 500)
x_circle = R * np.cos(theta)
y_circle = R * np.sin(theta)
ax.plot(x_circle, y_circle, color='black')

# Set equal aspect ratio
ax.set_aspect('equal', 'box')

# Labels and title
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')
plt.title('Brownian Motion of a Particle Within a Circle')

plt.show()

Python Code for 3-dimensional Brownian Motion

import numpy as np
import matplotlib.pyplot as plt

# Parameters
R = 5.0 # Radius of the cup
H = 10.0 # Height of the cup
N_steps = 10000 # Number of steps in the simulation
delta = 0.1 # Standard deviation of the step size

# Initialize position
x = [0.0]
y = [0.0]
z = [H / 2.0] # Start at half the height of the cup

# Simulate Brownian motion
for _ in range(N_steps):
# Generate random displacements
dx, dy, dz = np.random.normal(0, delta, 3)

# Tentative new position
x_new = x[-1] + dx
y_new = y[-1] + dy
z_new = z[-1] + dz

# Check radial boundary (cup walls)
r_new = np.sqrt(x_new**2 + y_new**2)
if r_new > R:
# Reflect off the wall
x_new = x[-1]
y_new = y[-1]

# Check vertical boundaries (base and open top)
if z_new < 0:
# Reflect off the base
z_new = -z_new
elif z_new > H:
# Reflect off the top edge
z_new = 2 * H - z_new

# Append new position
x.append(x_new)
y.append(y_new)
z.append(z_new)

# Convert lists to arrays for plotting
x = np.array(x)
y = np.array(y)
z = np.array(z)

# Plotting the trajectory
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(10, 7))
ax = fig.add_subplot(111, projection='3d')

# Plot the particle's path
ax.plot(x, y, z, lw=0.5, color='blue')

# Set the axes limits
ax.set_xlim([-R, R])
ax.set_ylim([-R, R])
ax.set_zlim([0, H])

# Plot the cup boundary (cylinder surface)
theta = np.linspace(0, 2 * np.pi, 100)
z_cylinder = np.linspace(0, H, 50)
theta_grid, z_grid = np.meshgrid(theta, z_cylinder)
x_cylinder = R * np.cos(theta_grid)
y_cylinder = R * np.sin(theta_grid)
ax.plot_surface(x_cylinder, y_cylinder, z_grid, alpha=0.1, color='gray')

# Labels and title
ax.set_xlabel('X-axis')
ax.set_ylabel('Y-axis')
ax.set_zlabel('Z-axis')
plt.title('Brownian Motion of a Particle Within a Cup')

plt.show()

Brownian Motion for the Animation in 2-dimensional

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

# Parameters
R = 5.0 # Radius of the circle
N_steps = 1000 # Number of steps in the simulation
delta = 0.1 # Standard deviation of the step size

# Initialize position at the center of the circle
x = [0.0]
y = [0.0]

# Initialize the figure and axis
fig, ax = plt.subplots(figsize=(8, 8))
ax.set_xlim(-R, R)
ax.set_ylim(-R, R)
ax.set_aspect('equal', 'box')

# Draw the circle boundary
theta = np.linspace(0, 2 * np.pi, 500)
x_circle = R * np.cos(theta)
y_circle = R * np.sin(theta)
ax.plot(x_circle, y_circle, color='black')

# Initialize the line and point objects
line, = ax.plot([], [], lw=0.5, color='blue')
point, = ax.plot([], [], 'o', color='red')

# Function to initialize the animation
def init():
line.set_data([], [])
point.set_data([], [])
return line, point

# Lists to store trajectory
x_data = []
y_data = []

# Function to perform animation step
def animate(i):
global x_data, y_data
# Generate random displacements
dx, dy = np.random.normal(0, delta, 2)
# Tentative new position
x_new = x[-1] + dx
y_new = y[-1] + dy
# Check if the new position is inside the circle
r_new = np.sqrt(x_new**2 + y_new**2)
if r_new > R:
# Reflect the particle back into the circle
# Compute the normal vector at the point of exit
r_vec = np.array([x_new, y_new])
r_norm = np.linalg.norm(r_vec)
n = r_vec / r_norm # Unit normal vector
# Original displacement vector
d = np.array([dx, dy])
# Reflect the displacement over the normal vector
d_reflected = d - 2 * np.dot(d, n) * n
# Update the new position with the reflected displacement
x_new = x[-1] + d_reflected[0]
y_new = y[-1] + d_reflected[1]
# Ensure the new position is inside the circle
r_new = np.sqrt(x_new**2 + y_new**2)
if r_new > R:
# If still outside, project onto the circle boundary
x_new = R * x_new / r_new
y_new = R * y_new / r_new
# Append the new position
x.append(x_new)
y.append(y_new)
x_data.append(x_new)
y_data.append(y_new)
# Update the line and point data
line.set_data(x_data, y_data)
point.set_data(x_new, y_new)
return line, point

# Create the animation
ani = FuncAnimation(fig, animate, frames=N_steps, init_func=init, blit=True, interval=10, repeat=False)

# Labels and title
plt.title('Animated Brownian Motion of a Particle Within a Circle')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')

# Display the animation
plt.show()

Thank you for the read and see you next week!

Tiago Verissimo,

Newcastle Upon Tyne, United Kingdom

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Tiago Veríssimo
Tiago Veríssimo

Written by Tiago Veríssimo

Mathematics PhD Student at Newcastle University I write about mathematics in very simple terms and typically use computers to showcase concepts.

No responses yet

Write a response