Chapter 11: ufunc Trigonometric
1. What are trigonometric ufuncs in NumPy?
NumPy provides six main trigonometric functions as universal functions (ufuncs):
| Function | Computes | Input unit | Output range | Most common use case |
|---|---|---|---|---|
| np.sin | sine | radians | [-1, 1] | oscillations, waves |
| np.cos | cosine | radians | [-1, 1] | phase shifts, projections |
| np.tan | tangent | radians | (-∞, +∞) | slopes, angles |
| np.arcsin | inverse sine (asin) | radians | [-π/2, π/2] | find angle from sine |
| np.arccos | inverse cosine (acos) | radians | [0, π] | find angle from cosine |
| np.arctan | inverse tangent (atan) | radians | (-π/2, π/2) | find angle from tangent |
There are also two-argument versions:
- np.arctan2(y, x) → angle of point (x,y) in correct quadrant (−π, π]
And hyperbolic versions (less common but important):
- np.sinh, np.cosh, np.tanh, np.arcsinh, etc.
2. The single most important rule you must remember
All trigonometric functions in NumPy expect input in radians — not degrees.
This is the #1 source of confusion for beginners.
|
0 1 2 3 4 5 6 7 8 9 10 |
# Wrong (most people forget this) print(np.sin(90)) # sin(90 radians) ≈ 0.893 (not 1!) # Correct print(np.sin(np.pi/2)) # ≈ 1.0 |
Conversion helpers (memorize or bookmark these):
|
0 1 2 3 4 5 6 7 8 9 10 11 |
deg = 45 rad = np.deg2rad(deg) # or deg * np.pi / 180 print(np.sin(rad)) # ≈ 0.707 # Opposite direction print(np.rad2deg(np.pi/3)) # 60.0 |
3. Basic usage examples – all six functions
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 |
angles_rad = np.linspace(0, 2*np.pi, 13) # 0 to 360° in 13 points print("Angles (rad):", angles_rad.round(3)) print("Angles (deg):", np.rad2deg(angles_rad).astype(int)) print("\nsin =", np.sin(angles_rad).round(3)) print("cos =", np.cos(angles_rad).round(3)) print("tan =", np.tan(angles_rad).round(3)) # notice discontinuities |
Inverse functions
|
0 1 2 3 4 5 6 7 8 9 10 |
sine_values = np.array([-1, -0.707, 0, 0.707, 1]) print("arcsin =", np.arcsin(sine_values).round(3)) # -π/2 to π/2 print("arccos =", np.arccos(sine_values).round(3)) # 0 to π print("arctan =", np.arctan(sine_values).round(3)) # -π/2 to π/2 |
Very important: arctan2 (two-argument version)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 |
x = np.array([ 1, -1, -1, 1, 0]) y = np.array([ 0, 0, 1, -1, 1]) angles = np.arctan2(y, x) print("arctan2(y,x) in radians:", angles.round(3)) print("in degrees: ", np.rad2deg(angles).astype(int)) # → [ 0 180 90 -90 90 ] ← correct quadrant! |
4. Realistic visualizations – the best way to build intuition
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
theta = np.linspace(0, 2*np.pi, 300) fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5.5)) # Unit circle ax1.plot(np.cos(theta), np.sin(theta), lw=2, color='teal') ax1.set_aspect('equal') ax1.set_title("Unit circle: cos(θ), sin(θ)", fontsize=13) ax1.set_xlabel("cos(θ)") ax1.set_ylabel("sin(θ)") ax1.axhline(0, color='gray', lw=0.8) ax1.axvline(0, color='gray', lw=0.8) ax1.grid(True, alpha=0.3) # All three functions ax2.plot(theta, np.sin(theta), label="sin", lw=2.2) ax2.plot(theta, np.cos(theta), label="cos", lw=2.2) ax2.plot(theta, np.tan(theta), label="tan", lw=2.2, alpha=0.8) ax2.set_title("sin, cos, tan over one period", fontsize=13) ax2.set_xlabel("θ (radians)") ax2.set_ylabel("Value") ax2.set_ylim(-2, 2) ax2.legend() ax2.grid(True, alpha=0.3) plt.tight_layout() plt.show() |
5. Very common realistic patterns you will use
Pattern 1 – Convert degrees to radians and compute
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
angles_deg = np.array([0, 30, 45, 60, 90, 120, 180, 270, 360]) angles_rad = np.deg2rad(angles_deg) sines = np.sin(angles_rad) cosines = np.cos(angles_rad) for d, s, c in zip(angles_deg, sines, cosines): print(f"{d:3}° → sin = {s:6.3f}, cos = {c:6.3f}") |
Pattern 2 – Generate sine/cosine waves (signal processing)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
t = np.linspace(0, 2, 1000) # time in seconds frequency = 5 # 5 Hz amplitude = 2.5 wave = amplitude * np.sin(2 * np.pi * frequency * t) plt.plot(t, wave, lw=1.8, color='teal') plt.title("5 Hz sine wave") plt.xlabel("Time (s)") plt.ylabel("Amplitude") plt.grid(True, alpha=0.3) plt.show() |
Pattern 3 – Find angles from ratios (arctan2 is critical)
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# Robot arm / game physics – direction to target dx = np.array([3, -4, 0, 5]) dy = np.array([4, 3, 5, 0]) angles_rad = np.arctan2(dy, dx) angles_deg = np.rad2deg(angles_rad) for x, y, deg in zip(dx, dy, angles_deg): print(f"dx={x:2}, dy={y:2} → angle = {deg:6.1f}°") |
Pattern 4 – Phase shift and superposition
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
t = np.linspace(0, 2, 1000) wave1 = np.sin(2 * np.pi * 3 * t) # 3 Hz wave2 = 0.6 * np.sin(2 * np.pi * 5 * t + np.pi/3) # 5 Hz with phase combined = wave1 + wave2 plt.plot(t, wave1, lw=1.2, alpha=0.7, label="3 Hz") plt.plot(t, wave2, lw=1.2, alpha=0.7, label="5 Hz + phase") plt.plot(t, combined, lw=2.5, color='darkblue', label="Superposition") plt.legend() plt.title("Wave superposition") plt.show() |
Summary – Trigonometric ufuncs Quick Reference
| Function | Input unit | Output range | Most common mistake |
|---|---|---|---|
| np.sin | radians | [-1, 1] | giving degrees |
| np.cos | radians | [-1, 1] | same |
| np.tan | radians | (-∞, +∞) | discontinuities at π/2 |
| np.arcsin | [-1,1] | [-π/2, π/2] | domain error outside [-1,1] |
| np.arccos | [-1,1] | [0, π] | domain error |
| np.arctan | any | (-π/2, π/2) | loses quadrant info |
| np.arctan2 | (y,x) | (-π, π] | always use this for angles |
Final teacher advice (very important)
Golden rule #1 All trigonometric functions expect radians — never pass degrees directly. Always convert with np.deg2rad() or np.pi / 180.
Golden rule #2 Use np.arctan2(y, x) instead of np.arctan(y/x) whenever you need the correct angle in the full circle (−180° to 180°).
Golden rule #3 Tan has discontinuities — be careful when plotting or using np.tan near odd multiples of π/2.
Golden rule #4 For signal/wave work always use radians — the 2π period is natural in radians.
Would you like to continue with any of these topics?
- Trigonometric identities and how NumPy handles them
- Phase, amplitude, frequency in signal generation
- Realistic mini-project: simulate sound wave or pendulum motion
- Common floating-point pitfalls with trig functions
- Hyperbolic trig functions (sinh, cosh, tanh)
Just tell me what you want to focus on next! 😊
