Note
Go to the end to download the full example code.
The Frenet-Serret frame of a circular helix#
A helix has constant curvature and torsion – both confirmed here against their closed forms – and the moving tangent/normal/binormal frame is visualized in 2D projection alongside an ellipse (whose curvature varies).
import numpy as np
from mathematicskit.geometry import frenet_serret_frame
from mathematicskit.geometry.utils.curves_library import ellipse, helix
from mathematicskit.geometry.visualizers.plots import plot_curve_frame
Helix: constant curvature and torsion#
a, b = 3.0, 2.0
t = np.linspace(0.0, 4.0 * np.pi, 1000)
result = frenet_serret_frame(helix(a, b), t)
expected_curvature = a / (a**2 + b**2)
expected_torsion = b / (a**2 + b**2)
print(f"curvature: mean={np.mean(result.curvature):.6f}, closed form={expected_curvature:.6f}")
print(f"torsion: mean={np.mean(result.torsion):.6f}, closed form={expected_torsion:.6f}")
print(f"total arc length: {result.arc_length[-1]:.4f}")
curvature: mean=0.230419, closed form=0.230769
torsion: mean=0.153480, closed form=0.153846
total arc length: 45.3079
An ellipse: curvature varies around the curve#
ellipse_result = frenet_serret_frame(ellipse(3.0, 1.0), np.linspace(0.0, 2.0 * np.pi, 200, endpoint=False))
print(f"\nellipse curvature range: [{ellipse_result.curvature.min():.4f}, {ellipse_result.curvature.max():.4f}]")
plot_curve_frame(ellipse_result)

ellipse curvature range: [0.1111, 3.0000]
<Axes: title={'center': 'Frenet-Serret frame (red=tangent, green=normal)'}>
Total running time of the script: (0 minutes 0.023 seconds)