Sure! Let's walk through your `Signal K` **Derived Data App plugin** function **line by line**, using explanations tailored to your sailing and `Signal K`/`OpenPlotter` setup. ### 🚩 Top-level function ```js module.exports = function (app) { ``` This line exports a module function to `Signal K`, which is how plugins or derived data sources are registered. The function receives `app` (the Signal K application instance), but it’s not used here. ### ⚙️ Metadata and Configuration ```js return { group: 'wind', optionKey: 'trueWind', title: 'True Wind Angle, Direction and Speed', ``` This object is returned to define the **derived data source**: - `group: 'wind'`: The logical group for Signal K derived data. - `optionKey: 'trueWind'`: Used to reference/enable this function in Signal K GUI or config. - `title`: Human-readable title for the app UI. ### 🧮 Inputs to the calculation ```js derivedFrom: [ 'navigation.headingTrue', 'navigation.speedThroughWater', 'environment.wind.speedApparent', 'environment.wind.angleApparent' ], ``` These are the input paths that must be present in your Signal K data for this calculation to work. Your plugin **listens** to changes in these values: - `headingTrue`: Boat's course through water (radians, referenced to true north). - `speedThroughWater`: Boat's STW, through the water, not SOG. - `speedApparent`: Apparent wind speed. - `angleApparent`: Apparent wind angle relative to bow. Typically in radians, 0 = bow, ±π = astern. ### 🧠 The actual computation ```js calculator: function (headTrue, speed, aws, awa) { ``` This is the core **calculation function** that computes *true wind* from the provided inputs: - `headTrue`: Heading (true) in radians. - `speed`: STW. - `aws`: Apparent wind speed. - `awa`: Apparent wind angle (radians, relative to bow). ### 📦 Local variables ```js var angle var speed var dir ``` Prepare storage for calculated: - `angle`: True wind angle relative to bow. - `speed`: True wind speed. - `dir`: True wind direction (absolute, relative to true north). ### ❌ Null check ```js if (headTrue == null || speed == null || aws == null || awa == null) { angle = null speed = null dir = null ``` Stops calculation if any key variables are missing (which would break math). Sets outputs as `null` to avoid propagating errors. ### ➗ Vector math: converting apparent -> true wind ```js } else { var apparentX = Math.cos(awa) * aws var apparentY = Math.sin(awa) * aws ``` Breaks the **apparent wind vector** into: - **X**: forward-aft component - **Y**: side-to-side (port-starboard) component Wind vector is in boat's frame of reference. Continuing: ```js angle = Math.atan2(apparentY, -speed + apparentX) ``` Calculates the **true wind angle relative to the bow**, using vector addition: - We subtract boat speed in negative X direction (`-speed`) to convert apparent to true wind. - `atan2(y, x)` returns angle from the bow from -π to π. ```js speed = Math.sqrt( Math.pow(apparentY, 2) + Math.pow(-speed + apparentX, 2) ) ``` Calculates **true wind speed** using Pythagoras’ theorem (from the true wind vector components). ### ⚠️ Small wind workaround ```js if (aws Math.PI * 2) { dir = dir - Math.PI * 2 } else if (dir < 0) { dir = dir + Math.PI * 2 } ``` Ensures `dir` is within **[0, 2π]** (i.e., a full circle, normalized radians). Prevents wraparound bugs. ### 📤 Return computed values ```js return [ { path: 'environment.wind.directionTrue', value: dir }, { path: 'environment.wind.angleTrueWater', value: angle }, { path: 'environment.wind.speedTrue', value: speed } ] ``` This returns the **derived Signal K paths**: - `directionTrue`: True wind direction (like compass bearing). - `angleTrueWater`: TWA relative to the bow. - `speedTrue`: True wind speed. Signal K will then publish these values automatically for other apps to consume. ## 🔚 Summary This plugin computes **true wind** from: - Boat heading (true) - Boat speed (through water) - Apparent wind (speed and angle) It does so using **basic vector math**, where apparent wind is corrected by boat movement to calculate the real wind's speed and direction over water. ⛵ As a singlehanded sailor using `Signal K`, this lets your onboard system display or log **true wind** even if you only have **apparent wind sensors plus a log and compass**. Would you like a **vector diagram** to visualize what the math is showing you?