Downwinder: Hudson River Surf Forecast
After many years dragonboating I bought an outrigger canoe and started paddling on the Hudson. Primarily for my own fitness, but I quickly discovered that out in the center of the river, if the conditions were right, you could surf! Joy oh joy! I've seen waves of 2-4 feet out there.
The problem was that it took about an hour to get from my apartment to the boathouse, plus another 20 minutes to set up the canoe, only to find that the wind had shifted and there weren't any waves.
That's where this forecaster came into play -> it's accurate to about 1/4 of a foot. And worse-case scenario I can always just surf the wake of the container ships.
Overview
The "Downwinder" service is a Google Sheet that's backed by a python service that does the following:
- Fetches current and forecast water speed data from the NOAA Tides & Currents API.
- Fetches wind forecast data (speed and direction) from the OpenWeatherMap API.
- Combines these datasets, aligning them by timestamp.
- Calculates the effective wind speed acting on the water surface, considering the direction of water flow.
- Estimates potential wave heights using the Bretschneider's formula, based on the projected wind effect.
- Stores the raw and processed data in a cloud-hosted PostgreSQL database.
- Publishes a user-friendly forecast to a public Google Sheet. It was easy to check on my phone before heading out.
- Posts updates and notable conditions to a dedicated Twitter account (It used to do this before Elon shut down the public Twitter API).
Technical Stack
- Programming Language: Python
- Data Manipulation: Pandas, NumPy
- APIs:
- NOAA Tides & Currents API (water data)
- OpenWeatherMap API (wind data)
- Google Sheets API (publishing forecasts)
- Twitter API (social media updates)
- Database: PostgreSQL (cloud-hosted, will probably self-host at some point)
- Deployment & Orchestration:
- Docker for containerizing the Python application.
- A mac mini sitting on my desk.
- A cron job that runs the service once an hour.
How It Works
The fundamental idea is that waves can form when wind blows over water; if the water has a current then an opposing wind can be gentle and still apply force to the surface. The Hudson River exhibits this phenomenon because it has strong tidal currents.
So what I do here is automate the process of:
- Gathering Data: Regularly fetching wind forecasts (speed and direction) and water current forecasts (speed and direction).
- Aligning Forces: The core challenge is a geometric one: determining how the wind's force aligns with the water's movement over a sufficient distance (fetch) for waves to develop. We need to calculate the component of wind that is directly opposing or running with the current.
- Estimating Wave Formation: Once the effective wind acting on the water is quantified, a mathematical model estimates the potential wave height.
- Publishing Results: The forecast is then made available through a Google Sheet.
Wave Height Estimation: A Tale of Two Formulas
Estimating wave height in a dynamic river environment is not as complex as it seems. My initial approach involved a formula from the paper Wave Forecasting in Shallow Water: A New Set of Growth Curves Depending on Bed Roughness. This seemed promising as it was designed for shallow water. However, it was primarily focused on depths less than 4 meters and fetch distances (the length of water over which wind blows) of around 1 kilometer. These parameters didn't quite match the typical conditions or the shorter fetch distances relevant for quick wave formation on the Hudson.
Interestingly what worked better was the Bretschneider formula, which was developed in 1976 for forecasting waves generated by hurricanes in the open ocean (paper here). With some eyeballing and empirical adjustments that gave me reasonably accurate estimates for the Hudson over fetch distances as short as 50-100 meters.
The key data transformation now was to resolve the wind and water vectors to understand the direct opposition or reinforcement, which then feeds into my adjusted Bretschneider model. We do a little bit of trigonometry to find the effective wind speed in the direction of the water flow and BAM! we have a wave height estimate. Now we know if it's surf time.
Output & Publishing
The processed forecast, including estimated wave heights, is written to a database. A subset of that data is then pushed to the public Google Sheet for easy viewing. Key forecast highlights or alerts used to be sent out via Twitter before the API changes.
You can view the live forecast here: (Hudson River Downwind Forecast Sheet)