01.4 專案:螺線族探索#
本節目標#
- 完成本章第一個完整專案:以螺旋線 \(\gamma(t) = (a\cos t,\ a\sin t,\ bt)\) 為對象,從定義、計算、驗證到視覺化走一遍完整流程。
- 用 SymPy 符號推導並驗證經典結果:
- 用 matplotlib 的 3D 繪圖可視化螺旋線,並觀察改變 \(a\) (半徑)與 \(b\) (螺距)對形狀與曲率的影響。
- 探索螺線族的極限情形:當 \(b\to 0\) 退化為平面圓、當 \(a\to 0\) 退化為直線;並對「一般/圓柱螺線」的曲率極限情形做反思。
回顧:螺旋線是什麼#
圓柱螺旋線是「繞著圓柱面等速爬升」的軌跡,公式為
- \(a\) :圓柱半徑。
- \(b\) :每轉一弧度爬升的高度,螺距 \(=2\pi b\) 。
- \(b>0\) 右旋、 \(b<0\) 左旋、 \(b=0\) 退化為平面圓。
它是一條以等速率行進的曲線(01.1 節我們算過 \(\|\gamma'\|=\sqrt{a^2+b^2}\) 為常數),也是自然界最普遍的空間曲線:DNA 雙股、螺旋樓梯、彈簧、斜坡上的盤山公路。
專案 Step 1:符號推導曲率與撓率#
import sympy as sp
t = sp.symbols('t', real=True)
a, b = sp.symbols('a b', positive=True)
gamma = sp.Matrix([a*sp.cos(t), a*sp.sin(t), b*t])
v = gamma.diff(t) # γ'
w = v.diff(t) # γ''
j = w.diff(t) # γ'''
speed2 = sp.simplify(v.dot(v)) # ||γ'||^2 = a^2+b^2
cross_w = v.cross(w)
cross2 = sp.simplify(cross_w.dot(cross_w)) # ||γ'×γ''||^2
kappa = sp.simplify(sp.sqrt(cross2) / speed2**sp.Rational(3, 2))
det3 = sp.simplify(v.dot(w.cross(j)))
torsion = sp.simplify(det3 / cross2)
print("κ =", kappa) # sqrt(a**2/(a**2 + b**2)**2) → a/(a**2 + b**2)
print("τ =", torsion) # a**2*b/(a**2*(a**2 + b**2)) → b/(a**2 + b**2)
kappa = sp.simplify(kappa.rewrite(sp.sqrt)) # 若有根號殘留,再化簡一次
print("κ 化簡 =", sp.simplify(kappa)) # a/(a**2 + b**2)
print("τ 化簡 =", torsion) # b/(a**2 + b**2)
預期輸出:
κ = a/(a**2 + b**2)
τ = b/(a**2 + b**2)
數學驗證: \(v = (-a\sin t, a\cos t, b)\) , \(\|v\|^2 = a^2+b^2\) 為常數; \(w = (-a\cos t, -a\sin t, 0)\) ; \(v\times w = (ab\sin t, -ab\cos t, a^2)\) ,其範數平方為 \(a^2(b^2+a^2)\) ,故
兩者都是常數——螺旋線每個點的彎曲與扭轉程度都相同,這是它被稱為「最均勻的空間曲線」的原因。
專案 Step 2:封装成可重用的模組#
def frenet_analysis(g, t):
v, w, j = g.diff(t), g.diff(t, 2), g.diff(t, 3)
v_dot_v = sp.simplify(v.dot(v))
cross = v.cross(w)
cross2 = sp.simplify(cross.dot(cross))
kappa = sp.simplify(sp.sqrt(cross2) / v_dot_v**sp.Rational(3, 2))
tau = sp.simplify(v.dot(w.cross(j)) / cross2)
return kappa, tau
# 驗證數值:a=2, b=1
k_val, tau_val = frenet_analysis(gamma, t)
print("a=2, b=1 → κ =", k_val.subs({a: 2, b: 1})) # 2/5
print("a=2, b=1 → τ =", tau_val.subs({a: 2, b: 1})) # 1/5
print(float(k_val.subs({a: 2, b: 1}))) # 0.4
專案 Step 3:3D 視覺化#
import numpy as np
import matplotlib.pyplot as plt
def plot_helix(a_val, b_val, T=np.pi*8, n=1000, ax=None, color='steelblue'):
tt = np.linspace(0, T, n)
x, y, z = a_val*np.cos(tt), a_val*np.sin(tt), b_val*tt
if ax is None:
fig = plt.figure(figsize=(7, 7))
ax = fig.add_subplot(projection='3d')
ax.plot(x, y, z, color=color, lw=1.5)
ax.set_xlabel('x'); ax.set_ylabel('y'); ax.set_zlabel('z')
ax.set_title(f'helix a={a_val}, b={b_val}, κ={a_val/(a_val**2+b_val**2):.3f}')
return ax
plot_helix(1, 0.3)
plt.show()
你會看到一條沿 z 軸纏繞的彈簧。標題同時顯示理論曲率值,把公式和形狀綁在一起。
專案 Step 4:改變 \(a\) 、 \(b\) 的效應#
fig = plt.figure(figsize=(15, 5))
params = [(1.0, 0.3), (2.0, 0.3), (1.0, 1.0), (1.0, 0.05)]
for i, (av, bv) in enumerate(params, 1):
ax = fig.add_subplot(1, 4, i, projection='3d')
plot_helix(av, bv, ax=ax, color=plt.cm.viridis(i/4))
print(f"a={av}, b={bv}: κ={av/(av**2+bv**2):.3f}, τ={bv/(av**2+bv**2):.3f}")
plt.tight_layout(); plt.show()
觀察規律(用公式預測,再用圖驗證):
- **加大 \(a\) **(半徑變粗):曲率 \(\kappa = a/(a^2+b^2)\) 先增後減,在 \(a=b\) 時達最大值 \(1/(2b)\) ——圓柱不是越粗彎得越急。
- **加大 \(b\) **(螺距變長): \(\kappa\) 單調減小而 \(\tau\) 單調先增後減( \(\tau\) 在 \(b=a\) 處最大)。曲線越「斜」,彎越平緩、扭越劇烈。
- \(\kappa^2+\tau^2 = \dfrac{a^2+b^2}{(a^2+b^2)^2} = \dfrac{1}{a^2+b^2} = \dfrac{1}{\|\gamma'\|^2}\) ,即速率越大,空間總彎度越小。
用 SymPy 一次驗證這些極值:
kappa_expr = a/(a**2 + b**2)
tau_expr = b/(a**2 + b**2)
# 對 b 微分找極值
print(sp.solve(sp.diff(tau_expr, b), b)) # [a] —— τ 在 b=a 時最大
# κ + τ 的平方和
print(sp.simplify(kappa_expr**2 + tau_expr**2)) # 1/(a**2+b**2)
專案 Step 5:極限情形的探索與反思#
退化為平面圓( \(b\to 0\) )
print(sp.limit(kappa_expr, b, 0)) # 1/a —— 正是半徑 a 的圓的曲率
print(sp.limit(tau_expr, b, 0)) # 0 —— 平面曲線無撓率
當 \(b\to 0\) ,螺旋線壓扁成半徑 \(a\) 的平面圓:曲率回到 \(1/a\) ,撓率歸零。所有數學都平滑退回二維世界——這是個好的一致性檢查。
退化為直線( \(a\to 0\) )
print(sp.limit(kappa_expr, a, 0)) # 0 —— 直線曲率為零
print(sp.limit(tau_expr, a, 0)) # 0 —— 直線也無撓率
當 \(a\to 0\) ,螺旋縮成一條沿 z 軸的直線 \((0,0,bt)\) ,曲率與撓率都消失。直線是空間中「最快抵達」的曲線,卻沒有任何幾何戲劇性。
反思 1: \(\kappa\) 與 \(\tau\) 是什麼的坐標?
對螺旋線有 \(\tau/\kappa = b/a\) 恆定。Lancret 定理告訴我們:撓率與曲率之比為常數的曲線恰是一般螺旋線(繞某固定軸的螺旋線)。也就是說,比值 \(\tau/\kappa\) 像指紋一樣刻畫了「螺旋性」。你可以把 (κ, τ) 想成曲線空間的「極坐標」——任何常數對應一條螺旋線,變動的函數對應更狂野的曲線。
反思 2:圓柱螺線 vs. 一般(廣義)螺線
- 圓柱螺線:曲率、撓率都為常數,是我們本節的主角。
- 一般(廣義/Lancret)螺線:只要 \(\tau/\kappa\) 為常數即可,例如畫在圓錐面上的對數螺線投影(concho-spiral)。這類曲線對應的物理是「以固定傾角沿曲面爬升」。
# 廣義螺旋線的例子:圓錐螺線
cone = sp.Matrix([t*sp.cos(t), t*sp.sin(t), t])
kc, tc = frenet_analysis(cone, t)
ratio = sp.simplify(tc/kc)
print("τ/κ =", ratio) # 應為常數 → 支持其為廣義螺旋線
如果輸出是常數,就驗證了 Lancret 定理在這個例子上的適用。
反思 3:為什麼螺旋線無所不在?
在許多約束下(等速率、貼著圓柱面、能量最省),最自然的解就是螺旋線。曲率與撓率是常數,意味著受力模式恆定——這也許就是 DNA、彈簧、海螺殼都選擇螺線形式的幾何原因。當你改 \(a, b\) 時,其實是在一維的「形狀調音」上滑動,而 (κ, τ) 就是那兩個旋鈕。
動手實驗#
實驗 1:數值驗證 \((\kappa,\tau)\) 表
import sympy as sp
t = sp.symbols('t', real=True)
a, b = sp.symbols('a b', positive=True)
gamma = sp.Matrix([a*sp.cos(t), a*sp.sin(t), b*t])
v, w, j = gamma.diff(t), gamma.diff(t, 2), gamma.diff(t, 3)
cross = v.cross(w)
kappa = sp.simplify(sp.sqrt(cross.dot(cross)) / sp.sqrt(v.dot(v))**3)
tau = sp.simplify(v.dot(w.cross(j)) / cross.dot(cross))
expr = sp.lambdify((a, b), (kappa, tau), 'numpy')
theo = lambda av, bv: (av/(av**2+bv**2), bv/(av**2+bv**2))
for av, bv in [(1, 1), (2, 1), (1, 3), (3, 3)]:
print(f"(a,b)=({av},{bv}): num={expr(av,bv)}, theo={theo(av,bv)}, "
f"match={expr(av,bv) == theo(av,bv)}")
實驗 2:用 sp.plot3d_parametric_line 快速可視化
sp.plot3d_parametric_line(a*sp.cos(t), a*sp.sin(t), b*t,
(t, 0, 8*sp.pi), params={a: (1, 0, 3), b: (1, -3, 3)},
use_cm=True)
拖動滑桿即可動態觀察 \(a, b\) 效應,比多張靜態圖更直觀。
實驗 3: \(\kappa\) 最大時的形狀
固定 \(b=1\) ,掃 \(a\in(0, 3]\) ,畫 \(\kappa(a)\) 曲線。你會看到單峰、峰值在 \(a=1\) (即 \(a=b\) )。畫 \(a=1,b=1\) 的 3D 圖——這個「最彎的螺旋線」長什麼樣?你有什麼直覺性猜想嗎?
實驗 4(挑戰):重建曲線
給 \(\kappa = a/(a^2+b^2)\) 、 \(\tau = b/(a^2+b^2)\) 常數對,用 Frenet–Serret ODE(01.2 節)數值求解(scipy.integrate.solve_ivp + 標準正交矩陣演化),重建出的曲線是否為螺旋線(允許剛體旋轉/平移差別)?這是微分幾何基本定理(曲線版)的動手驗證。
小結與練習#
本節重點
- 螺旋線 \(\gamma(t)=(a\cos t,a\sin t,bt)\) 的曲率與撓率都是常數: \(\kappa = a/(a^2+b^2)\) 、 \(\tau = b/(a^2+b^2)\) 。
- \((\kappa,\tau)\) 是形狀的兩個「旋鈕」: \(b\to 0\) 退化為平面圓( \(\kappa\to 1/a, \tau\to 0\) ), \(a\to 0\) 退化為直線(兩者皆 0)。
- \(\tau/\kappa = b/a\) 恆定;由 Lancret 定理,這正是「螺旋性」的代數特徵。
- 完整工作流:SymPy 符號推導 → 公式驗證 →
lambdify數值 → matplotlib 3D 視覺化 → 極限與反思。
練習
- 證明: \(\kappa^2+\tau^2 = 1/(a^2+b^2)\) ,並解釋它與「速率」 \(\sqrt{a^2+b^2}\) 的關係(提示:Frenet 公式三式平方相加)。
- 對數螺旋線的圓柱投影:考慮 \(\gamma(t) = (e^{ct}\cos t, e^{ct}\sin t, bt)\) ,計算 \(\kappa, \tau\) ,觀察它們是否仍為常數;若不是, \(c=0\) 時呢?
- 求使螺旋線「曲率與撓率相等」( \(\kappa=\tau\) )的 \(a, b\) 關係,並畫出此情形的 3D 圖。
- 用 SymPy 證明螺旋線上任意兩點間的弦長與弧長之比在兩點靠近時趨近 1,並對比直線與一般曲線的行為。
- 反思寫作:選一個自然界中的螺旋物件(DNA、貝殼、藤蔓),根據它的形狀估算 \(a, b\) 及對應的 \(\kappa, \tau\) ,並討論「為什麼自然界選了這組參數」。這是開放題,重點是把幾何量連結到物理/生物約束。