Wind Vectors Explained
On this page
Problem statement
Wind is a vector: it has a size and a direction, and it can be written either as speed and direction or as two components, east and north. The two forms carry the same information and behave completely differently in calculations. Components add, average and interpolate like ordinary numbers; speed and direction do not, because direction lives on a circle and speed loses the sign. Most errors with wind data, from averaged directions to arrows that point the wrong way, come from doing arithmetic in the wrong form.
This page explains the two forms and the conventions that connect them, using the hourly winds reported at Tampa International Airport as Hurricane Helene passed to the west on 26β27 September 2024.
Quick answer
Convert reports to components once, and do every calculation on the components:
T["u"] = -T.speed * np.sin(np.radians(T.dir)) # towards the east, m/s
T["v"] = -T.speed * np.cos(np.radians(T.dir)) # towards the north, m/s
print(T[["time", "dir", "speed", "u", "v"]].iloc[::6].round(1).to_string(index=False))
print(f"mean speed {T.speed.mean():.1f} m/s; length of the mean vector {np.hypot(T.u.mean(), T.v.mean()):.1f} m/s")
time dir speed u v
2024-09-26 06:53:00 110.0 4.1 -3.9 1.4
2024-09-26 13:53:00 130.0 6.7 -5.1 4.3
2024-09-26 19:53:00 140.0 11.3 -7.3 8.7
2024-09-27 01:53:00 180.0 17.5 -0.0 17.5
2024-09-27 07:53:00 230.0 7.7 5.9 4.9
mean speed 8.9 m/s; length of the mean vector 6.8 m/s
The direction convention, veering and backing, vector changes
1. The direction convention
Meteorological wind direction is where the wind comes from, measured clockwise from north. A southerly at 180Β° blows towards the north, so its v is positive. The minus signs in the conversion turn "from" into "towards":
south = T.loc[T.dir == 180].iloc[0]
print(f"{south.time:%d %H:%M} UTC: from {south.dir:.0f}Β° at {south.speed} m/s β u = {south.u:+.1f}, v = {south.v:+.1f} (blowing north)")
27 01:53 UTC: from 180Β° at 17.5 m/s β u = -0.0, v = +17.5 (blowing north)
2. Veering and backing
As a storm passes, the wind turns. Turning clockwise, from east through south to west, is veering; anticlockwise is backing. In the Northern Hemisphere a station on the right of a cyclone's track sees the wind veer:
turn = (T.dir.diff() + 180) % 360 - 180
print(f"total turn over {len(T)} hours: {turn.sum():+.0f}Β° (positive = clockwise, veering); "
f"from {T.dir.iloc[0]:.0f}Β° to {T.dir.iloc[-1]:.0f}Β°")
peak = T.loc[T.speed.idxmax()]
print(f"strongest report {peak.speed} m/s from {peak.dir:.0f}Β° at {peak.time:%d %H:%M} UTC")
total turn over 29 hours: +130Β° (positive = clockwise, veering); from 110Β° to 240Β°
strongest report 17.5 m/s from 180Β° at 27 01:53 UTC
3. Changes are vectors too
The change in wind from one hour to the next is the difference of the vectors, not the difference of speeds. A wind that turns without strengthening has changed:
dv = np.hypot(T.u.diff(), T.v.diff())
dspeed = T.speed.diff().abs()
i = dv.idxmax()
print(f"largest hourly change: {dv[i]:.1f} m/s as a vector, {dspeed[i]:.1f} m/s in speed, at {T.time[i]:%d %H:%M} UTC")
largest hourly change: 4.2 m/s as a vector, 3.1 m/s in speed, at 27 01:53 UTC
Back to speed and direction
The data used on this page
NOAA's Integrated Surface Database, routine hourly reports (FM-15) from Tampa International Airport (station 722110-12842) from 06 UTC on 26 September to 12 UTC on 27 September 2024; speeds are converted from tenths of a metre per second.
from pathlib import Path
import numpy as np
import pandas as pd
import requests
Path("data").mkdir(exist_ok=True)
F = Path("data/72211012842.csv")
if not F.exists():
F.write_bytes(requests.get("https://noaa-global-hourly-pds.s3.amazonaws.com/2024/72211012842.csv", timeout=300).content)
d = pd.read_csv(F, usecols=["DATE", "REPORT_TYPE", "WND"], dtype=str)
d = d[d.REPORT_TYPE.str.strip() == "FM-15"]
w = d.WND.str.split(",", expand=True)
T = pd.DataFrame({"time": pd.to_datetime(d.DATE), "dir": pd.to_numeric(w[0].replace("999", np.nan)),
"speed": pd.to_numeric(w[3].replace("9999", np.nan)) / 10})
T = T[(T.time >= "2024-09-26 06:00") & (T.time <= "2024-09-27 12:00")].dropna().reset_index(drop=True)
print(f"{len(T)} hourly reports from Tampa, {T.time.min():%d %H:%M} to {T.time.max():%d %H:%M} UTC")
29 hourly reports from Tampa, 26 06:53 to 27 11:53 UTC
Example 1: back to speed and direction
The components go back to the reported values exactly, the check that the signs are right:
back_dir = np.degrees(np.arctan2(-T.u, -T.v)) % 360
back_speed = np.hypot(T.u, T.v)
print(f"largest round-trip difference: direction {np.abs((back_dir - T.dir + 180) % 360 - 180).max():.1e}Β°, "
f"speed {np.abs(back_speed - T.speed).max():.1e} m/s")
largest round-trip difference: direction 2.8e-14Β°, speed 1.8e-15 m/s
Components are natural for physics and computing
The component form is the natural one for physics and computing. Newton's laws act on vectors, models integrate u and v, and any linear operation, from averaging to interpolation to differencing, works on each component separately. The speed-and-direction form is the natural one for people: it is what a weather vane and an anemometer measure, and what a forecast says. The conversion between them is exact, as long as the conventions are respected: east and north for the components, "from" and clockwise from north for the direction.
Three facts follow. The average wind over a period is the average of the components, and its length is never more than the average speed; the gap measures how much the direction varied. A change in wind is a vector difference, so a wind can change a lot without changing speed. And components belong to a coordinate system: on a rotated or projected grid, u and v follow the grid's axes and must be rotated before they mean east and north.
Calm, oceanographic conventions and height
- Calm: a calm wind has components (0, 0) and no direction.
- Oceanography: currents are named for the direction they flow towards; the same formula without the minus signs.
- Units: knots, m/s and km/h scale both components alike; direction is unaffected.
- Height: wind is quoted at a height, usually 10 m; speeds increase with height and directions veer in the boundary layer.
- Grid-relative components: HRRR and other regional models store
uandvalong their grid.
Internal links
- How to calculate wind speed and direction from u and v β the conversion in code
- Why is my average wind direction wrong? β averaging on the circle
FAQ
What are u and v wind components?
u is the part of the wind blowing towards the east and v the part blowing towards the north, both in metres per second.
Is wind direction where the wind comes from or goes to?
Where it comes from: a southerly wind blows from the south, at 180Β°.
What do veering and backing mean?
Veering is the wind turning clockwise, for example from east to south; backing is turning anticlockwise.
Why use components instead of speed and direction?
Components can be averaged, interpolated and differenced directly; speed and direction cannot.