Physics 001 — Introduction to Physics
Aug 1, 2026Physics is the discipline that tries to explain everything — from why an apple falls to why the universe exists — using the smallest possible number of ideas. That's the whole game. Compress reality into elegant rules, then use those rules to predict things you've never seen.
It sounds ambitious. It is. But it works surprisingly well.
What physics is not
Physics is not a collection of formulas to memorize. If you've ever been handed a sheet of equations before an exam and felt nothing, that's not physics — that's the corpse of physics. The formulas are the output of understanding, not the understanding itself.
Physics is also not just "hard science for serious people." It's the reason your phone has GPS, your microwave heats food, and your MRI can see inside your bones. Extremely practical stuff, dressed up in math.
The game: models and reality
Here's how physics actually works: you observe something, build a model that explains it, and then test the model against new observations. If it survives, great. If it doesn't, you fix it or throw it out.
A model is a simplified description of reality that captures the parts you care about and ignores the parts you don't. It's never complete — reality is always more complicated than the description. The art is in choosing what to ignore.
Take a ball falling from a building. The simplest model says: the ball accelerates downward at a constant rate, and nothing else matters. That model predicts when it hits the ground, and for a dense object dropped from a reasonable height, it's right enough to be useful. Good enough for almost everything.
Now drop a feather from the same building. The same model predicts the same fall time. The feather disagrees. Air resistance, which we ignored, turns out to dominate the feather's motion. The model didn't break — we just applied it outside its domain.
So you add air resistance to the model. Now it works for feathers. But it breaks for objects moving at 10% the speed of light, where relativistic effects kick in. You add relativity. It breaks again near a black hole. You add general relativity. And so on.
This is the actual structure of physics: a stack of models, each valid within some range of conditions, each a refinement of the one before. Newton's mechanics was the best model of motion for two centuries. Then Einstein came along and showed it was an approximation. Newton's equations still work perfectly for building bridges and launching rockets. They just fail when things move near the speed of light.
That's fine. A model doesn't have to be perfect. It has to be useful.
Units: the part everyone underestimates
Before you can measure anything, you need to agree on what your numbers mean. That's what units are for.
The international standard is the SI system (Système International d'Unités). Seven base units cover everything in classical physics:
| Quantity | Unit | Symbol |
|---|---|---|
| Length | metre | m |
| Mass | kilogram | kg |
| Time | second | s |
| Electric current | ampere | A |
| Temperature | kelvin | K |
| Amount of substance | mole | mol |
| Luminous intensity | candela | cd |
Every other unit — newtons, joules, watts, volts — is a combination of these seven.
Units are not bureaucratic nonsense. They are load-bearing. In 1999, NASA lost a $327 million Mars orbiter because one engineering team delivered thruster data in pound-force seconds and the navigation software expected newton-seconds. Nobody caught it. The spacecraft entered the Martian atmosphere at the wrong angle and burned up.
The difference between a pound-force and a newton is a factor of 4.45. Small enough to miss in a report, large enough to destroy a spacecraft. Run this to see what that error looks like in practice:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image as PILImage
import io, base64
BG = '#ffffff'; MID = '#aaaaaa'; GRN = '#00a846'
RED = '#e03535'; MARS = '#c1440e'; ATMO = '#e8956d'
FPS = 16; N = FPS * 7; RES = 1200
def b4(t, a, b, c, d):
return (1-t)**3*a + 3*(1-t)**2*t*b + 3*(1-t)*t**2*c + t**3*d
def resample(x, y, n):
"""Even arc-length spacing — constant visual speed, no pauses."""
dx, dy = np.diff(x), np.diff(y)
cum = np.concatenate([[0], np.cumsum(np.sqrt(dx**2 + dy**2))])
s = np.linspace(0, cum[-1], n)
return np.interp(s, cum, x), np.interp(s, cum, y)
tv = np.linspace(0, 1, RES)
# Approach: p3=(2.5,0), p2=(2.5,1.5) → end tangent (0,-1).
# Clockwise orbit tangent at θ=0 is also (0,-1). No kink.
ax_raw = b4(tv, 4.8, 4.5, 2.5, 2.5)
ay_raw = b4(tv, 4.8, 2.0, 1.5, 0.0)
# Green orbit: clockwise ~1.7 revs from (2.5,0)
th = np.linspace(0, -10.8, RES)
ox_raw, oy_raw = 2.5*np.cos(th), 2.5*np.sin(th)
# Red dip: starts at (2.5,0) going (0,-1) same as green,
# p1 keeps direction, then curves inward toward Mars.
rx_raw = b4(tv, 2.5, 2.5, 1.4, 0.55)
ry_raw = b4(tv, 0.0, -1.0, -1.35, -1.53)
in_a = np.sqrt(rx_raw**2 + ry_raw**2) < 1.7
imp_i = np.where(in_a)[0][0] if np.any(in_a) else RES-1
rd_x, rd_y = rx_raw[:imp_i+1], ry_raw[:imp_i+1]
IMP_X, IMP_Y = rx_raw[imp_i], ry_raw[imp_i]
# Frame budgets per segment (these define visual speed via resample)
T_APP = 0.26; T_RED = 0.45; T_FLASH = 0.56
N_APP = int(T_APP * N) # frames in approach
N_ORB = N - N_APP # frames in orbit
N_RDF = int((T_RED-T_APP) * N) # frames in red dip
# Resample each segment to its frame budget → constant speed within segment
app_x, app_y = resample(ax_raw, ay_raw, N_APP + 1)
orb_x, orb_y = resample(ox_raw, oy_raw, N_ORB + 1)
dip_x, dip_y = resample(rd_x, rd_y, N_RDF + 1)
# Concatenate full paths — endpoint shared to guarantee C0 continuity
full_gx = np.concatenate([app_x, orb_x[1:]]) # N+1 pts
full_gy = np.concatenate([app_y, orb_y[1:]])
full_rx = np.concatenate([app_x, dip_x[1:]]) # N_APP+N_RDF+1 pts
full_ry = np.concatenate([app_y, dip_y[1:]])
N_RED_END = len(full_rx) - 1 # frame index when red hits atmosphere
TRAIL = 70
frames = []
for fi in range(N):
fig, ax = plt.subplots(figsize=(7.8, 7.8), facecolor=BG, dpi=150)
ax.set_facecolor(BG); ax.set_aspect('equal'); ax.axis('off')
ax.set_xlim(-4.0, 5.5); ax.set_ylim(-4.2, 5.5)
fig.subplots_adjust(left=0.01, right=0.99, top=0.99, bottom=0.01)
# static scene
ax.add_patch(plt.Circle((0,0), 2.5, fill=False, edgecolor=MID, lw=0.9, ls=':', zorder=2))
ax.add_patch(plt.Circle((0,0), 1.7, color=ATMO, alpha=0.18, zorder=3))
ax.add_patch(plt.Circle((0,0), 1.7, fill=False, edgecolor=ATMO, lw=1, ls='--', zorder=3))
ax.add_patch(plt.Circle((0,0), 1.4, color=MARS, zorder=4))
ax.text(0, 0, 'MARS', ha='center', va='center',
fontsize=9, fontweight='bold', color='white', zorder=8)
ax.text(2.6, 0.3, 'target orbit', fontsize=7, color=MID, style='italic')
ax.text(0.05, 1.78, 'atmosphere', fontsize=6.5, color=ATMO, style='italic')
ax.text(-2.6, -3.3, 'correct units\n→ enters orbit',
fontsize=8, color=GRN, fontweight='bold', ha='center', linespacing=1.4)
ax.text( 2.9, -3.3, 'wrong units\n→ hits atmosphere',
fontsize=8, color=RED, fontweight='bold', ha='center', linespacing=1.4)
ax.text(0.5, -3.85, 'Mars Climate Orbiter, 1999 — $327 million',
ha='center', fontsize=7, color=MID, style='italic')
# ── GREEN: index fi directly into full_gx ───────────────────
ig = min(fi, len(full_gx) - 1)
if fi > N_APP: # faint approach ghost
ax.plot(full_gx[:N_APP+1], full_gy[:N_APP+1],
color=GRN, lw=0.8, alpha=0.18, zorder=4)
t0g = max(0, ig - TRAIL)
ax.plot(full_gx[t0g:ig+1], full_gy[t0g:ig+1], color=GRN, lw=2.2, zorder=5)
ax.plot(full_gx[ig], full_gy[ig], 'o', color=GRN, ms=7, zorder=7)
# ── RED: index fi into full_rx until impact, then explosion ─
f_now = fi / N
if fi <= N_RED_END:
ir = min(fi, len(full_rx) - 1)
if fi > N_APP:
ax.plot(full_rx[:N_APP+1], full_ry[:N_APP+1],
color=RED, lw=0.8, alpha=0.18, ls='--', zorder=4)
t0r = max(0, ir - TRAIL)
ax.plot(full_rx[t0r:ir+1], full_ry[t0r:ir+1], color=RED, lw=2.2, ls='--', zorder=5)
ax.plot(full_rx[ir], full_ry[ir], 'o', color=RED, ms=7, zorder=7)
else:
ax.plot(full_rx[:N_APP+1], full_ry[:N_APP+1],
color=RED, lw=0.8, alpha=0.15, ls='--', zorder=4)
ax.plot(full_rx[N_APP:], full_ry[N_APP:],
color=RED, lw=1.8, ls='--', alpha=0.5, zorder=5)
age = min(1.0, (f_now - T_RED) / (T_FLASH - T_RED))
a_fl = max(0.0, 1.0 - age * 1.2)
if a_fl > 0:
r_e = age * 0.6
for ang in np.linspace(0, 2*np.pi, 8, endpoint=False):
ax.plot([IMP_X, IMP_X + r_e*np.cos(ang)],
[IMP_Y, IMP_Y + r_e*np.sin(ang)],
color='#ff6000', lw=2.5, alpha=a_fl, zorder=9)
ax.plot(IMP_X, IMP_Y, '*', color='#ffdd00',
ms=max(3, 19*(1-age)), zorder=10, alpha=a_fl)
ax.plot(IMP_X, IMP_Y, 'x', color=RED, ms=11, mew=2.5, zorder=9,
alpha=min(1.0, age * 2.5))
buf = io.BytesIO()
fig.savefig(buf, format='png', dpi=90, facecolor=BG,
bbox_inches='tight', pad_inches=0.02)
buf.seek(0)
raw = PILImage.open(buf).convert('RGB')
frames.append(raw.quantize(colors=256, dither=0))
plt.close(fig)
gif_buf = io.BytesIO()
frames[0].save(gif_buf, format='GIF', save_all=True,
append_images=frames[1:], loop=0, duration=int(1000/FPS))
gif_buf.seek(0)
print('PLOT_GIF:' + base64.b64encode(gif_buf.read()).decode())
The green trajectory reaches orbit. The red one — same spacecraft, same thruster, same burn duration, wrong unit — goes straight into the atmosphere. $327 million. Gone.
Always carry your units.
Orders of magnitude
One of the most useful skills in physics is being comfortable with very large and very small numbers. The universe doesn't care about human-scale intuitions — it operates from the diameter of a proton (10⁻¹⁵ m) to the radius of the observable universe (10²⁶ m). That's 41 orders of magnitude.
The tool for navigating this is the power of ten. Instead of thinking "0.000000000000001 metres," you think "10⁻¹⁵ metres." Differences in scale become differences in exponent — much easier to reason about.
Run this to see where things sit on the scale of the universe:
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import numpy as np
import io, base64
BG = '#ffffff'
FG = '#333333'
MID = '#888888'
GRN = '#00a846'
DARK = '#111111'
objects = [
(-15, "proton"),
(-10, "atom"),
(-8, "DNA strand"),
(-5, "red blood cell"),
(-3, "ant"),
(0, "human"),
(3, "mountain"),
(7, "Earth radius"),
(11, "Earth–Sun distance"),
(16, "light-year"),
(21, "Milky Way"),
(26, "observable universe"),
]
fig, ax = plt.subplots(figsize=(10, 5), facecolor=BG)
ax.set_facecolor(BG)
ax.set_xlim(-17, 28)
ax.set_ylim(-1.2, 1.2)
ax.axis('off')
fig.subplots_adjust(left=0.02, right=0.98, top=0.88, bottom=0.12)
ax.axhline(0, color=DARK, linewidth=1.5, zorder=1)
for exp in range(-16, 27, 1):
major = (exp % 4 == 0)
ax.plot([exp, exp], [-0.08 if major else -0.04, 0.08 if major else 0.04],
color=MID, linewidth=1.2 if major else 0.5, zorder=2)
if major:
label = f'$10^{{{exp}}}$'
ax.text(exp, -0.18, label, ha='center', va='top', fontsize=10,
color=MID)
ax.text(5.5, -0.42, 'metres (m)', ha='center', va='top',
fontsize=10, color=MID, style='italic')
for i, (exp, label) in enumerate(objects):
above = i % 2 == 0
y_dot = 0
y_line = 0.55 if above else -0.55
y_text = 0.62 if above else -0.62
ax.plot([exp, exp], [y_dot, y_line * 0.85], color=GRN, linewidth=0.9,
linestyle='--', alpha=0.5, zorder=3)
ax.plot(exp, 0, 'o', color=GRN, markersize=6, zorder=4)
ax.text(exp, y_text, label, ha='center',
va='bottom' if above else 'top',
fontsize=8.5, color=FG, fontweight='500')
ax.text(5.5, 1.1, 'scale of the universe (metres, log₁₀)',
ha='center', va='top', fontsize=11, color=DARK, fontweight='bold')
buf = io.BytesIO()
fig.savefig(buf, format='png', dpi=130, facecolor=BG)
buf.seek(0)
print('PLOT:' + base64.b64encode(buf.read()).decode())
Notice that a human (10⁰) sits almost exactly in the middle of the scale between a proton and the observable universe. That's not meaningful — it's a coincidence — but it's a fun one.
Precision and significant figures
A number without context is useless. If I tell you a bridge is "100 metres long," I might mean anywhere from 95 to 105 metres. Or I might mean exactly 100.000 metres. Those are very different claims.
Significant figures encode how much you actually know. The number 1.47 has three significant figures — you're confident to the hundredths place. The number 1.470 has four — you measured one decimal further. The trailing zero matters.
Three rules govern how precision propagates through calculations:
Physics is full of approximations. The skill is knowing which ones are acceptable and which ones will blow up your spacecraft.
So far, no formulas. That's intentional.
Physics is about compressing reality into the smallest number of useful ideas. Before any formula is worth anything, you need the ideas underneath it: that what we call "laws" are really just models — approximations that work within some range and break outside it. That numbers are meaningless without units attached, and units are load-bearing enough to destroy a $327 million spacecraft when someone gets them wrong. That scale matters — the universe spans 41 orders of magnitude, and the tools you use at one end are useless at the other. And that precision isn't decoration: reporting more digits than you measured is not accuracy, it's fiction.
These four things — models, units, scale, and precision — show up in every calculation you'll ever do. Get comfortable with them now and the formulas, when they arrive, will make sense instead of just existing.
Next up: Physics 002 — Kinematics. Things start moving.
What could be better? (criticism is free, ego is not)