signalk-polar-performance-plugin 0.0.5 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # Polar performance plugin
2
2
  Generate performance information based on a polar diagram.
3
3
 
4
+
5
+ ## MFD configuration
6
+
7
+ ### B&G
8
+ To make use of the performance data and get e.g. lay lines you need to set:
9
+ - Settings -> Chart -> Laylines -> Targets... -> True wind angle to 'Actual'
10
+ - SailSteer screen -> Long press tile to add 'Performance -> Target TWA -> decollapse, choose SignalK'
11
+ Now the Target TWA is coming from SignalK and the laylines will be drawn based on it's value.
12
+
4
13
  ## Data correctness
5
14
  It's assumed data is already corrected when it's read by this plugin. This can be sometimes be done by the sensor, sometimes upon entry into SignalK using the [calibration plugin](https://www.npmjs.com/package/@signalk/calibration).
6
15
 
@@ -19,7 +28,7 @@ The polar diagram can be configured through CSV notation as used on [ORC sailboa
19
28
  In the plugin configuration you can toggle the following options:
20
29
  - Enable calculation of beat/upwind and run/gybe/downwind angle
21
30
  - Enable calculation of beat/upwind and run/gybe/downwind VMG
22
- - Enable calculation of Optimal Wind Angle (difference between TWA and beat/run angle (depends on beat/run angle)
31
+ - Enable calculation of Optimum Wind Angle (difference between TWA and beat/run angle (depends on beat/run angle)
23
32
 
24
33
  ## Calculated performance data
25
34
  ### Currently supported
@@ -32,10 +41,10 @@ In the plugin configuration you can toggle the following options:
32
41
  - Polar Boat Speed (performance.polarSpeed)
33
42
  - Polar Speed Ratio (performance.polarSpeedRatio)
34
43
  - Plugin option to use SOG as boat speed
44
+ - Wind angle for maximum speed at this wind speed
35
45
 
36
46
  ### To-do list
37
47
  - Fill up the ends of the polar diagram
38
- - Wind angle for maximum speed at this wind speed
39
48
  - Improved interpolation
40
49
  - Make moment to do calculation smarter/configurable
41
50
  - Create polar from live data
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signalk-polar-performance-plugin",
3
- "version": "0.0.5",
3
+ "version": "0.0.8",
4
4
  "description": "A plugin that calculates performance information based on a (CSV) polar diagram.",
5
5
  "main": "plugin/index.js",
6
6
  "scripts": {
package/plugin/index.js CHANGED
@@ -24,14 +24,18 @@ module.exports = function (app) {
24
24
  type: 'boolean',
25
25
  title: 'Enable calculation of beat/upwind and run/gybe/downwind VMG'
26
26
  },
27
- optimalWindAngle: {
27
+ optimumWindAngle: {
28
28
  type: 'boolean',
29
- title: 'Enable calculation of Optimal Wind Angle (difference between TWA and beat/run angle (depends on beat/run angle)'
29
+ title: 'Enable calculation of Optimum Wind Angle (difference between TWA and beat/run angle (depends on beat/run angle)'
30
30
  },
31
31
  useSOG: {
32
32
  type: 'boolean',
33
33
  title: 'Use speed over ground (SOG) as boat speed.'
34
34
  },
35
+ maxSpeed: {
36
+ type: 'boolean',
37
+ title: 'Enable writing of maximum speed angle and boat speed for a given TWS'
38
+ },
35
39
  csvTable: {
36
40
  type: "string",
37
41
  title: "Enter csv with polar in http://jieter.github.io/orc-data/site/ style."
@@ -116,7 +120,7 @@ module.exports = function (app) {
116
120
  } else if (delta.path == 'environment.wind.speedTrue') {
117
121
  TWS = delta.value
118
122
  // app.debug('environment.wind.speedTrue (TWS): %d', TWS)
119
- app.debug('TWS: %d TWA: %d BSP: %d', TWS, TWA, BSP)
123
+ app.debug('TWS: %d TWA: %d BSP: %d', msToKts(TWS), radToDeg(TWA)*port, msToKts(BSP))
120
124
  sendUpdates(getPerformanceData(TWS, TWA, BSP))
121
125
  } else if (delta.path == 'environment.wind.angleTrueWater') {
122
126
  if (delta.value < 0) {
@@ -125,7 +129,6 @@ module.exports = function (app) {
125
129
  port = 1
126
130
  }
127
131
  TWA = Math.abs(delta.value)
128
- // app.debug('environment.wind.angleTrueWater (TWA): %d', TWA)
129
132
  }
130
133
  })
131
134
  }
@@ -139,6 +142,8 @@ module.exports = function (app) {
139
142
  }
140
143
  if (typeof perfObj.beatVMG != 'undefined') {
141
144
  values.push({path: 'performance.beatAngleVelocityMadeGood', value: roundDec(perfObj.beatVMG)})
145
+ values.push({path: 'performance.targetVelocityMadeGood', value: roundDec(perfObj.beatVMG)})
146
+ metas.push({path: 'performance.targetVelocityMadeGood', value: {"units": "rad"}})
142
147
  }
143
148
  if (typeof perfObj.runAngle != 'undefined') {
144
149
  values.push({path: 'performance.gybeAngle', value: roundDec(perfObj.runAngle)})
@@ -146,10 +151,12 @@ module.exports = function (app) {
146
151
  }
147
152
  if (typeof perfObj.runVMG != 'undefined') {
148
153
  values.push({path: 'performance.gybeAngleVelocityMadeGood', value: roundDec(perfObj.runVMG)})
154
+ values.push({path: 'performance.targetVelocityMadeGood', value: roundDec(perfObj.runVMG)})
155
+ metas.push({path: 'performance.targetVelocityMadeGood', value: {"units": "rad"}})
149
156
  }
150
- if (typeof perfObj.optimalWindAngle != 'undefined') {
151
- values.push({path: 'performance.optimalWindAngle', value: roundDec(perfObj.optimalWindAngle)})
152
- metas.push({path: 'performance.optimalWindAngle', value: {"units": "rad"}})
157
+ if (typeof perfObj.optimumWindAngle != 'undefined') {
158
+ values.push({path: 'performance.optimumWindAngle', value: roundDec(perfObj.optimumWindAngle)})
159
+ metas.push({path: 'performance.optimumWindAngle', value: {"units": "rad"}})
153
160
  }
154
161
  if (typeof perfObj.targetSpeed != 'undefined') {
155
162
  values.push({path: 'performance.targetSpeed', value: roundDec(perfObj.targetSpeed)})
@@ -158,6 +165,12 @@ module.exports = function (app) {
158
165
  values.push({path: 'performance.polarSpeed', value: roundDec(perfObj.polarSpeed)})
159
166
  values.push({path: 'performance.polarSpeedRatio', value: roundDec(perfObj.polarSpeedRatio)})
160
167
  }
168
+ if (typeof perfObj.maxSpeed != 'undefined') {
169
+ values.push({path: 'performance.maxSpeed', value: roundDec(perfObj.maxSpeed)})
170
+ metas.push({path: 'performance.maxSpeed', value: {"units": "m/s"}})
171
+ values.push({path: 'performance.maxSpeedAngle', value: roundDec(perfObj.maxSpeedAngle)})
172
+ metas.push({path: 'performance.maxSpeedAngle', value: {"units": "rad"}})
173
+ }
161
174
 
162
175
  app.debug('sendUpdates: %s', JSON.stringify(values))
163
176
  app.handleMessage(plugin.id, {
@@ -191,9 +204,9 @@ module.exports = function (app) {
191
204
  let beatUpper = polar[indexTWS+1]['Beat angle']
192
205
  performance.beatAngle = beatLower + ((beatUpper - beatLower) * twsGapRatio)
193
206
  }
194
- // Calculate optimal wind angle
195
- if (options.optimalWindAngle == true) {
196
- performance.optimalWindAngle = performance.beatAngle - TWA * port
207
+ // Calculate optimum wind angle (B&G thing)
208
+ if (options.optimumWindAngle == true) {
209
+ performance.optimumWindAngle = (TWA - performance.beatAngle) * port
197
210
  }
198
211
  // Calculate beat VMG
199
212
  if (options.beatVMG == true) {
@@ -210,9 +223,9 @@ module.exports = function (app) {
210
223
  //app.debug('runLower: %s runUpper: %s', runLower, runUpper)
211
224
  performance.runAngle = runLower + ((runUpper - runLower) * twsGapRatio)
212
225
  }
213
- if (options.optimalWindAngle == true) {
214
- // Calculate optimal wind angle
215
- performance.optimalWindAngle = performance.runAngle - TWA * port
226
+ if (options.optimumWindAngle == true) {
227
+ // Calculate optimum wind angle
228
+ performance.optimumWindAngle = (performance.runAngle - TWA) * port * -1
216
229
  }
217
230
  if (options.beatVMG == true) {
218
231
  // Calculate run VMG
@@ -246,17 +259,25 @@ module.exports = function (app) {
246
259
  // Calculate upper tws boat speed
247
260
  let upperTBS = upperTWAlower.tbs + ((upperTWAupper.tbs - upperTWAlower.tbs) * twaGapRatio)
248
261
 
249
- // Calculate target boat speed
262
+ // Calculate polar performance
250
263
  performance.polarSpeed = lowerTBS + ((upperTBS - lowerTBS) * twsGapRatio)
251
264
  // app.debug('lowerTBS: %d TBS: %d upperTBS: %d', lowerTBS, performance.polarSpeed, upperTBS)
252
265
 
253
- // Calculate polar performance
266
+ // Calculate polar performance ratio
254
267
  performance.polarSpeedRatio = (1 / performance.polarSpeed) * BSP
255
-
268
+ break
256
269
  }
257
270
  }
258
-
259
- // Calculate polar performance ratio
271
+ if (options.maxSpeed == true) {
272
+ let lowerMax = polar[indexTWS]['Max speed']
273
+ let upperMax = polar[indexTWS+1]['Max speed']
274
+ let maxSpeed = lowerMax + ((upperMax - lowerMax) * twsGapRatio)
275
+ performance.maxSpeed = maxSpeed
276
+ let lowerMaxAngle = polar[indexTWS]['Max speed angle']
277
+ let upperMaxAngle = polar[indexTWS+1]['Max speed angle']
278
+ let maxSpeedAngle = lowerMaxAngle + ((upperMaxAngle - lowerMaxAngle) * twsGapRatio)
279
+ performance.maxSpeedAngle = maxSpeedAngle
280
+ }
260
281
  } else {
261
282
  // app.debug('%d not >= %d && <= %d', TWS, lower, upper)
262
283
  }
@@ -305,17 +326,16 @@ module.exports = function (app) {
305
326
  if (row[index] != 0) {
306
327
  polar[index-1][angleName] = degToRad(angle)
307
328
  polar[index-1][VMGName] = roundDec(Number((row[index]) * Math.abs(Math.cos(angle))))
308
- app.debug('polar[index-1]: %s', polar[index-1])
309
329
  if (typeof polar[index-1]['twa'] == 'undefined') {
310
330
  polar[index-1]['twa'] = []
311
331
  }
312
- app.debug('polar[index-1]: %s', polar[index-1])
313
- app.debug('Adding TargetBoatSpeed')
314
- let Obj = {"twa": degToRad(angle), "tbs": ktsToMs(Number(row[index]))}
315
- app.debug('Obj: %s', JSON.stringify(Obj))
332
+ let tbs = ktsToMs(Number(row[index]))
333
+ let Obj = {"twa": degToRad(angle), "tbs": tbs}
316
334
  polar[index-1]['twa'] = polar[index-1]['twa'].concat(Obj)
317
- app.debug('polar[index-1]["twa"]: %s', polar[index-1]['twa'])
318
- app.debug('polar: %s', JSON.stringify(polar))
335
+ if (typeof polar[index-1]['Max speed'] == 'undefined' || tbs > polar[index-1]['Max speed']) {
336
+ polar[index-1]['Max speed'] = tbs
337
+ polar[index-1]['Max speed angle'] = degToRad(angle)
338
+ }
319
339
  }
320
340
  }
321
341
  } else {
@@ -325,9 +345,13 @@ module.exports = function (app) {
325
345
  if (typeof polar[index-1].twa == 'undefined') {
326
346
  polar[index-1].twa = []
327
347
  }
328
- let Obj = {"twa": angle, "tbs": ktsToMs(Number(row[index]))}
348
+ let tbs = ktsToMs(Number(row[index]))
349
+ let Obj = {"twa": angle, "tbs": tbs}
329
350
  polar[index-1]['twa'] = polar[index-1]['twa'].concat(Obj)
330
- app.debug('polar: %s', JSON.stringify(polar))
351
+ if (tbs > polar[index-1]['Max speed']) {
352
+ polar[index-1]['Max speed'] = tbs
353
+ polar[index-1]['Max speed angle'] = angle
354
+ }
331
355
  }
332
356
  }
333
357
  })
@@ -377,7 +401,7 @@ function ktsToMs(knots) {
377
401
  return knots / 1.94384
378
402
  }
379
403
 
380
- function MsToKts(ms) {
404
+ function msToKts(ms) {
381
405
  return ms * 1.94384
382
406
  }
383
407