Tutorial 5
Click the badges above to run this tutorial interactively in your browser without installing anything!
- Binder: Free cloud-based Jupyter environment
- Colab: Google's free Jupyter notebook environment
Topics Covered
This tutorial covers the following topics using Python and SymPy:
- Navigation problems: adding velocity vectors given as compass headings
- Work and torque: the dot product in engineering
- Directional derivatives and the gradient
- Tangent planes, normal lines and unit normals
- Divergence and curl and their physical meaning
Introduction
Headings are measured clockwise from North. A velocity of speed at compass heading
hdg therefore has components
SymPy's atan2(E, N) inverts this and returns a bearing that we shift into
.
import sympy as sy
from sympy.abc import x, y, z, t, r
from sympy import sqrt, sin, cos, tan, pi, atan, atan2, acos, exp, ln, Matrix, simplify
sy.init_printing(use_latex=True)
def velocity(speed, hdg):
"""Velocity vector (East, North) for a given speed and compass heading in degrees."""
return Matrix([speed*sin(hdg*pi/180), speed*cos(hdg*pi/180)])
def gradient(f, vars=(x, y, z)):
return Matrix([sy.diff(f, v) for v in vars])
def divergence(F, vars=(x, y, z)):
return sum(sy.diff(F[i], vars[i]) for i in range(len(vars)))
def curl(F):
return Matrix([sy.diff(F[2], y) - sy.diff(F[1], z),
sy.diff(F[0], z) - sy.diff(F[2], x),
sy.diff(F[1], x) - sy.diff(F[0], y)])
Question 1
A boat heads for Dunes Beach. Part (a) gives the heading ; in part (b) a wind of knot at acts while the skipper keeps the same heading.
boat = velocity(2.4, 250) # intended course, 2.4 knots
wind = velocity(0.8, 200) # wind acting on the boat
display([sy.N(v, 4) for v in boat]) # [-2.255, -0.821] (East, North)
display([sy.N(v, 4) for v in wind]) # [-0.274, -0.752]
res = boat + wind
display([sy.N(v, 4) for v in res]) # [-2.529, -1.573]
speed = sqrt(res.dot(res))
display(speed, sy.N(speed, 4)) # 2.978 knots
hdg = atan2(res[0], res[1]) * 180/pi # compass heading, may be negative
display(sy.N(hdg, 6), sy.N(hdg + 360, 6)) # -121.88 ... 238.12 degrees
a. The intended heading is .
c. The altered speed is knots at a heading of .
Question 2
Work done by a constant force, .
a. of work to pull a sled with a force.
theta = acos(12000/(150*200))
display(sy.N(theta*180/pi, 6)) # 66.42 degrees
b. moving an object from the origin to .
F = Matrix([5, 0]); d = Matrix([1, 1])
display(F.dot(d)) # 5 J
c. A 1000 lb force on a sail moves a boat 1 mile.
W = 1000 * 5280 * cos(60*pi/180)
display(W) # 2640000 ft.lb
The downloadable solution PDF writes , the vertical field. The displacement is purely horizontal, so the correct field is and the work is the -component alone: .
Question 3
A bolt is tightened with a force at to a wrench.
tau = 0.3 * 20 * sin(60*pi/180)
display(tau, sy.N(tau, 4)) # 5.196 N.m
The magnitude of the torque is (about ). The two pictures in part (b) have the same magnitude but opposite direction — one tightens the bolt, the other loosens it.
Torque is measured in , so the magnitude rounds to (not joules).
Question 4
a. Is there a direction in which the rate of change of at equals ?
T = 2*x*y - y*z
grad_T = gradient(T)
display(grad_T) # <2y, 2x - z, -y>
g = grad_T.subs({x: 1, y: -1, z: 1})
display(g) # <-2, 1, 1>
display(sqrt(g.dot(g)), sy.N(-sqrt(g.dot(g)), 6)) # sqrt(6), -2.449
The directional derivative lies in . Since is outside that interval, no such direction exists.
b. For the paraboloid at , write the surface as .
f = x**2 + y**2 - 2*z
grad_f = gradient(f)
display(grad_f) # <2x, 2y, -2>
n = grad_f.subs({x: 1, y: 3, z: 5})
display(n) # <2, 6, -2>
# tangent plane: n . (X - P) = 0
plane = n[0]*(x - 1) + n[1]*(y - 3) + n[2]*(z - 5)
display(simplify(plane)) # 2x + 6y - 2z - 10
display(simplify(plane/2)) # x + 3y - z - 5
# unit normal vector
display(n / sqrt(n.dot(n))) # <1, 3, -1>/sqrt(11)
So , , the tangent plane is , the unit normal is , and the normal line is .
The gradient of is , so the -component of is the constant , not .
c.i. at .
f = 2*x**2 + y**2 - z**2 + 3
g = gradient(f).subs({x: 1, y: 2, z: 3})
display(g) # <4, 4, -6>
display(simplify(g[0]*(x-1) + g[1]*(y-2) + g[2]*(z-3))) # 4x + 4y - 6z + 6
Tangent plane ; normal line .
c.ii. at .
f = x**2 + y**2 + z**2 - 30
g = gradient(f).subs({x: 1, y: -2, z: 5})
display(g) # <2, -4, 10>
display(simplify(g[0]*(x-1) + g[1]*(y+2) + g[2]*(z-5))) # 2x - 4y + 10z - 60
Tangent plane ; normal line .
Question 5
a. Divergence of
display(simplify(divergence(Matrix([x/y, 2*x - 3*y]), (x, y)))) # 1/y - 3
The divergence is a scalar, so it describes whether the field is expanding (positive) or compressing (negative) at a point.
b. Curl of
display(curl(Matrix([x, -y, z]))) # <0, 0, 0>
The curl is the zero vector, so this field is irrotational.
Question 6
A force is applied perpendicular to a spanner.
tau = 2.5 * 0.15 * sin(pi/2) # 15 cm = 0.15 m
display(tau, tau*100) # 0.375 N.m = 37.5e-2 N.m
The torque is , acting anticlockwise.
The spanner is , which is what gives the quoted answer .
Extra Learning Resources
Key Concepts to Master
- Relative velocity: add the vectors tip-to-tail, then convert back to speed and heading
- Work:
- Torque: , in
- Gradient: points in the direction of steepest increase, with magnitude equal to that maximum rate
- Divergence vs curl: divergence is a scalar (source/sink), curl is a vector (rotation)
SymPy Resources
- SymPy trigonometric functions —
atan2,acos,sin,cos - SymPy Matrices —
dot,cross,subs - SymPy
subs— substituting the evaluation point into a gradient
Common Pitfalls
- Compass headings run clockwise from North, so the East component uses and the North component uses — the opposite of the usual maths convention
atan2(E, N)returns angles in ; add if you want a bearing- A directional derivative can never exceed in magnitude
- Torque uses (cross product) while work uses (dot product)