signalk-polar-performance-plugin 0.0.20 → 0.0.22

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/plugin/index.js +43 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "signalk-polar-performance-plugin",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
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
@@ -1,3 +1,4 @@
1
+ const halfPi = Math.PI / 2
1
2
  var sourceAddress
2
3
 
3
4
  module.exports = function (app) {
@@ -36,6 +37,10 @@ module.exports = function (app) {
36
37
  type: 'boolean',
37
38
  title: 'Enable calculation of Optimum Wind Angle (difference between TWA and beat/run angle (depends on beat/run angle)'
38
39
  },
40
+ VMG: {
41
+ type: 'boolean',
42
+ title: 'Enable calculation of VMG, polarVMG and polar VMG ratio'
43
+ },
39
44
  useSOG: {
40
45
  type: 'boolean',
41
46
  title: 'Use speed over ground (SOG) as boat speed.'
@@ -46,7 +51,7 @@ module.exports = function (app) {
46
51
  },
47
52
  csvTable: {
48
53
  type: "string",
49
- title: "Enter csv with polar in http://jieter.github.io/orc-data/site/ style."
54
+ title: "Copy/paste the csv content of the polar in http://jieter.github.io/orc-data/site/ style."
50
55
  }
51
56
  }
52
57
  }
@@ -83,7 +88,6 @@ module.exports = function (app) {
83
88
 
84
89
  // Global variables
85
90
  var BSP, STW, TWA, targetTWA, TWS, HDG, port // Angles in rad, speed in m/s
86
- var halfPi = Math.PI / 2
87
91
 
88
92
  // Subscribe to paths
89
93
  let localSubscription = {
@@ -206,6 +210,11 @@ module.exports = function (app) {
206
210
  if (typeof perfObj.polarSpeed != 'undefined') {
207
211
  values.push({path: 'performance.polarSpeed', value: roundDec(perfObj.polarSpeed)})
208
212
  values.push({path: 'performance.polarSpeedRatio', value: roundDec(perfObj.polarSpeedRatio)})
213
+ if (options.VMG == true) {
214
+ values.push({path: 'performance.velocityMadeGood', value: roundDec(perfObj.velocityMadeGood)})
215
+ values.push({path: 'performance.polarVelocityMadeGood', value: roundDec(perfObj.polarVelocityMadeGood)})
216
+ values.push({path: 'performance.polarVelocityMadeGoodRatio', value: roundDec(perfObj.polarVelocityMadeGoodRatio)})
217
+ }
209
218
  }
210
219
  if (typeof perfObj.maxSpeed != 'undefined') {
211
220
  values.push({path: 'performance.maxSpeed', value: roundDec(perfObj.maxSpeed)})
@@ -369,11 +378,21 @@ module.exports = function (app) {
369
378
  }
370
379
  // Calculate polar performance ratio
371
380
  if (typeof performance.polarSpeed != 'undefined') {
372
- performance.polarSpeedRatio = (1 / performance.polarSpeed) * BSP
381
+ performance.polarSpeedRatio = BSP / performance.polarSpeed
382
+ if (options.VMG == true) {
383
+ performance.velocityMadeGood = Math.abs(BSP * Math.cos(TWA))
384
+ performance.polarVelocityMadeGood = Math.abs(performance.polarSpeed * Math.cos(TWA))
385
+ performance.polarVelocityMadeGoodRatio = performance.velocityMadeGood / performance.polarVelocityMadeGood
386
+ }
373
387
  } else {
374
388
  // No value would create stale values
375
389
  performance.polarSpeed = 0
376
390
  performance.polarSpeedRatio = 0
391
+ if (options.VMG == true) {
392
+ performance.velocityMadeGood = 0
393
+ performance.polarVelocityMadeGood = 0
394
+ performance.polarRatioVelocityMadeGood = 0
395
+ }
377
396
  }
378
397
  return performance
379
398
  }
@@ -394,6 +413,7 @@ module.exports = function (app) {
394
413
  if (row[0] == 'twa/tws') {
395
414
  // The row with TWS columns
396
415
  // Create empty TWS objects in polar object
416
+ app.debug('First row with TWS columns')
397
417
  polar = []
398
418
  for (let index = 1; index < row.length; index++) {
399
419
 
@@ -401,20 +421,23 @@ module.exports = function (app) {
401
421
  polar.push(twsObj)
402
422
  }
403
423
  app.debug('polar: %s', JSON.stringify(polar))
404
- } else if (row[0] == '0') {
424
+ } else if (row.filter(i => i === '0').length > 1) {
405
425
  app.debug('beat and run angles are included')
406
- } else if (row.includes('0')) {
407
426
  // Beat / Run angle
408
427
  let angle = degToRad(Number(row[0]))
409
428
  let angleName
410
429
  let VMGName
430
+ app.debug('angle < halfPi %d < %d', angle, halfPi)
411
431
  if (angle < halfPi) {
412
432
  angleName = 'Beat angle'
413
433
  VMGName = 'Beat VMG'
434
+ app.debug('cvsToPolar: row includes Beat angle: %s', row.join(';'))
414
435
  } else {
415
436
  angleName = 'Run angle'
416
437
  VMGName = 'Run VMG'
438
+ app.debug('cvsToPolar: row includes Run angle: %s', row.join(';'))
417
439
  }
440
+
418
441
  for (let index = 0; index < row.length-1; index++) {
419
442
  if (row[index+1] != 0) {
420
443
  polar[index][angleName] = angle
@@ -465,16 +488,19 @@ module.exports = function (app) {
465
488
  })
466
489
 
467
490
  // Find the beat/run angle if not set yet.
468
- if (typeof polar[0].beatAngle == 'undefined') {
469
- for (let index = 0; index < polar.length-1; index++) {
470
- let tws = polar[index].tws
491
+ for (let index = 0; index < polar.length; index++) {
492
+ let tws = polar[index].tws
493
+ app.debug('Beat angle for TWS %s is %s', msToKts(tws).toFixed(0), polar[index]['Beat angle'])
494
+ // app.debug(polar[index]['Beat angle'])
495
+ if (typeof polar[index]['Beat angle'] == 'undefined') {
496
+ app.debug('Finding beat angle for TWS %s')
471
497
  let beatVMG = 0
472
498
  let beatElement = 0
473
499
  let runVMG = 0
474
500
  let runElement = 0
475
501
 
476
502
  let twaArray = polar[index].twa
477
- for (let element = 0; element < twaArray.length-1; element++) {
503
+ for (let element = 0; element < twaArray.length; element++) {
478
504
  let Obj = twaArray[element]
479
505
  if (Obj.twa < halfPi) {
480
506
  // Beat
@@ -488,8 +514,8 @@ module.exports = function (app) {
488
514
  }
489
515
  }
490
516
  }
491
- app.debug('beatVMG for %d is %d (angel %d)', tws, twaArray[beatElement].vmg, twaArray[beatElement].twa)
492
- app.debug(' runVMG for %d is %d (angel %d)', tws, twaArray[runElement].vmg, twaArray[runElement].twa)
517
+ app.debug('beatVMG for %s is %s (angle %s)', msToKts(tws).toFixed(0), msToKts(twaArray[beatElement].vmg).toFixed(2), radToDeg(twaArray[beatElement].twa).toFixed(1))
518
+ app.debug('runVMG for %s is %s (angle %s)', msToKts(tws).toFixed(0), msToKts(twaArray[runElement].vmg).toFixed(2), radToDeg(twaArray[runElement].twa).toFixed(1))
493
519
  polar[index]['Beat angle'] = twaArray[beatElement].twa
494
520
  polar[index]['Beat VMG'] = twaArray[beatElement].vmg
495
521
  polar[index]['Run angle'] = twaArray[runElement].twa
@@ -499,18 +525,19 @@ module.exports = function (app) {
499
525
  }
500
526
 
501
527
  // And now fill in some missing ends to avoid doing expensive calculations in the main loop
502
- for (let index = 0; index < polar.length-1; index++) {
528
+ for (let index = 0; index < polar.length; index++) {
503
529
  // Sorted on angle, so first is lowest
504
530
  let tws = polar[index].tws
505
531
  let twaArray = polar[index].twa
506
532
  let lowTBS = twaArray[0].tbs
507
533
  let lowTWA = twaArray[0].twa
508
534
 
509
- app.debug('Padding polar for %s from 0 to first given angle (%d deg, %d kts)', msToKts(tws).toFixed(0), radToDeg(lowTWA), msToKts(lowTBS))
535
+ // app.debug('Padding polar for %s from 0 to first given angle (%d deg, %d kts)', msToKts(tws).toFixed(0), radToDeg(lowTWA), msToKts(lowTBS))
510
536
 
511
537
  // Now put some extra values at the beginning
512
538
  var topArray = []
513
539
  for (let angle = 0; angle < lowTWA; angle = angle + degToRad(5)) {
540
+ app.debug('Padding for angle %d (< lowTWA)', radToDeg(angle).toFixed(1), radToDeg(lowTWA).toFixed(1))
514
541
  let tbs = (angle / lowTWA) * Math.pow(Math.cos((-1*lowTWA + angle)*2),2) * lowTBS
515
542
  if (tbs < 0 ) { tbs = 0 }
516
543
  let Obj = {'twa': angle, 'tbs': tbs}
@@ -546,7 +573,7 @@ module.exports = function (app) {
546
573
  function getChartData () {
547
574
  var backgroundColor = []
548
575
  var borderColor = []
549
- for (let c = 0; c < 8; c++) {
576
+ for (let c = 0; c < 20; c++) {
550
577
  let r = 0 + (c*10)
551
578
  let g = 130 + (c*20 % 100)
552
579
  let b = 80 + (c*30 % 120)
@@ -565,7 +592,7 @@ module.exports = function (app) {
565
592
  for (let angle = 0; angle <= 180; angle += 5) {
566
593
  data.labels.push(angle)
567
594
  }
568
- for (let index = 0; index < polar.length -1; index++) {
595
+ for (let index = 0; index < polar.length; index++) {
569
596
  // Add x axis label TWS
570
597
  let tws = msToKts(polar[index].tws).toFixed(0)
571
598
  let twaArray = polar[index].twa
@@ -583,7 +610,7 @@ module.exports = function (app) {
583
610
  if (twaObj.twa == polar[index]['Beat angle'] || twaObj.twa == polar[index]['Run angle']) {
584
611
  radius = 5
585
612
  }
586
- data.datasets[index].data.push({x: Math.round(radToDeg(twaObj.twa)), y: Number(msToKts(twaObj.tbs).toFixed(2))})
613
+ data.datasets[index].data.push({x: Number(radToDeg(twaObj.twa).toFixed(1)), y: Number(msToKts(twaObj.tbs).toFixed(2))})
587
614
  data.datasets[index].pointRadius.push(radius)
588
615
  }
589
616
  }