signalk-polar-performance-plugin 0.0.23 → 0.0.26
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 +1 -1
- package/package.json +1 -1
- package/plugin/index.js +59 -31
package/README.md
CHANGED
|
@@ -42,6 +42,7 @@ In the plugin configuration you can toggle the following options:
|
|
|
42
42
|
- Wind angle for maximum speed at this wind speed
|
|
43
43
|
- Fill up the ends of the polar diagram
|
|
44
44
|
- Visualisation of the polar diagram
|
|
45
|
+
- Configurable damping alorithm on inputs
|
|
45
46
|
|
|
46
47
|
### To-do list
|
|
47
48
|
- Improved interpolation
|
|
@@ -52,7 +53,6 @@ In the plugin configuration you can toggle the following options:
|
|
|
52
53
|
-- Save polar info to file
|
|
53
54
|
-- Save new record speed for angle in polar
|
|
54
55
|
-- Determine if we're on a steady course to avoid fake records
|
|
55
|
-
-- Dampening algoritms
|
|
56
56
|
-- Configure the resolution of the polar diagram
|
|
57
57
|
- Support multiple polar diagrams
|
|
58
58
|
- Capture heel in polar diagram
|
package/package.json
CHANGED
package/plugin/index.js
CHANGED
|
@@ -52,18 +52,19 @@ module.exports = function (app) {
|
|
|
52
52
|
},
|
|
53
53
|
dampingTWA: {
|
|
54
54
|
type: 'number',
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
description: 'If data appears erratic or too sensitive, damping may be applied to amke information appear more stable. With damping set to 0, the data is presented in raw form wih no damping applied.',
|
|
56
|
+
title: 'True Wind Angle damping seconds',
|
|
57
|
+
default: 1
|
|
57
58
|
},
|
|
58
59
|
dampingTWS: {
|
|
59
60
|
type: 'number',
|
|
60
|
-
title: 'True Wind Speed damping
|
|
61
|
-
default:
|
|
61
|
+
title: 'True Wind Speed damping seconds',
|
|
62
|
+
default: 1
|
|
62
63
|
},
|
|
63
64
|
dampingBSP: {
|
|
64
65
|
type: 'number',
|
|
65
|
-
title: 'Boat speed damping
|
|
66
|
-
default:
|
|
66
|
+
title: 'Boat speed damping damping',
|
|
67
|
+
default: 1
|
|
67
68
|
},
|
|
68
69
|
csvTable: {
|
|
69
70
|
type: "string",
|
|
@@ -157,11 +158,11 @@ module.exports = function (app) {
|
|
|
157
158
|
deltas.forEach(delta => {
|
|
158
159
|
// app.debug('handleData: %s', JSON.stringify(delta))
|
|
159
160
|
if (delta.path == 'navigation.speedThroughWater') {
|
|
160
|
-
STW = applyDamping (delta.value, 'BSP', options.dampingBSP || 0
|
|
161
|
+
STW = applyDamping (delta.value, 'BSP', options.dampingBSP || 0)
|
|
161
162
|
BSP = STW
|
|
162
163
|
// app.debug('speedThroughWater (STW): %d', STW)
|
|
163
164
|
} else if (delta.path == 'navigation.speedOverGround') {
|
|
164
|
-
SOG = applyDamping (delta.value, 'BSP', options.dampingBSP || 0
|
|
165
|
+
SOG = applyDamping (delta.value, 'BSP', options.dampingBSP || 0)
|
|
165
166
|
BSP = SOG
|
|
166
167
|
// app.debug('speedThroughWater (STW): %d', STW)
|
|
167
168
|
} else if (delta.path == 'navigation.headingTrue') {
|
|
@@ -169,7 +170,7 @@ module.exports = function (app) {
|
|
|
169
170
|
// app.debug('heading (HDG): %d', HDG)
|
|
170
171
|
} else if (delta.path == 'environment.wind.speedTrue') {
|
|
171
172
|
// applyDamping (Xn, unit, a, n)
|
|
172
|
-
TWS = applyDamping (delta.value, 'TWS', options.dampingTWS || 0
|
|
173
|
+
TWS = applyDamping (delta.value, 'TWS', options.dampingTWS || 0)
|
|
173
174
|
// app.debug('environment.wind.speedTrue (TWS): %d applyDamping: %d', delta.value, TWS)
|
|
174
175
|
// app.debug('TWS: %d TWA: %d BSP: %d', msToKts(TWS), radToDeg(TWA)*port, msToKts(BSP))
|
|
175
176
|
sendUpdates(getPerformanceData(TWS, TWA, BSP))
|
|
@@ -179,8 +180,8 @@ module.exports = function (app) {
|
|
|
179
180
|
} else {
|
|
180
181
|
port = 1
|
|
181
182
|
}
|
|
182
|
-
TWA = Math.abs(applyDamping (delta.value, 'TWA', options.dampingTWA || 0
|
|
183
|
-
|
|
183
|
+
TWA = Math.abs(applyDamping (delta.value, 'TWA', options.dampingTWA || 0))
|
|
184
|
+
app.debug('environment.wind.angleTrueWater (TWA): %s applyDamping: %s', radToDeg(delta.value).toFixed(0), radToDeg(TWA).toFixed(0))
|
|
184
185
|
}
|
|
185
186
|
})
|
|
186
187
|
}
|
|
@@ -401,7 +402,7 @@ module.exports = function (app) {
|
|
|
401
402
|
performance.polarSpeedRatio = BSP / performance.polarSpeed
|
|
402
403
|
if (options.VMG == true) {
|
|
403
404
|
performance.velocityMadeGood = Math.abs(BSP * Math.cos(TWA))
|
|
404
|
-
performance.polarVelocityMadeGood = Math.abs(performance.polarSpeed * Math.cos(
|
|
405
|
+
performance.polarVelocityMadeGood = Math.abs(performance.polarSpeed * Math.cos(targetTWA))
|
|
405
406
|
performance.polarVelocityMadeGoodRatio = performance.velocityMadeGood / performance.polarVelocityMadeGood
|
|
406
407
|
}
|
|
407
408
|
} else {
|
|
@@ -545,6 +546,23 @@ module.exports = function (app) {
|
|
|
545
546
|
}
|
|
546
547
|
|
|
547
548
|
// And now fill in some missing ends to avoid doing expensive calculations in the main loop
|
|
549
|
+
if (polar[0].tws > 0) {
|
|
550
|
+
// Add a 0 line to allow interpolation at very low wind speeds
|
|
551
|
+
app.debug('Add a 0 line to allow interpolation at very low wind speeds')
|
|
552
|
+
let Obj = {
|
|
553
|
+
tws: 0.0001,
|
|
554
|
+
'Beat angle': polar[0]['Beat angle'],
|
|
555
|
+
'Beat VMG': polar[0]['Beat VMG'],
|
|
556
|
+
'Run angle': polar[0]['Run angle'],
|
|
557
|
+
'Run VMG': polar[0]['Run VMG'],
|
|
558
|
+
twa: []
|
|
559
|
+
}
|
|
560
|
+
Object.keys(polar[0].twa).forEach(twaObj => {
|
|
561
|
+
Obj.twa.push({twa: twaObj.twa, tbs: 0})
|
|
562
|
+
})
|
|
563
|
+
polar.unshift(Obj)
|
|
564
|
+
}
|
|
565
|
+
|
|
548
566
|
for (let index = 0; index < polar.length; index++) {
|
|
549
567
|
// Sorted on angle, so first is lowest
|
|
550
568
|
let tws = polar[index].tws
|
|
@@ -567,7 +585,7 @@ module.exports = function (app) {
|
|
|
567
585
|
polar[index].twa = topArray.concat(twaArray)
|
|
568
586
|
}
|
|
569
587
|
|
|
570
|
-
for (let index = 0; index < polar.length
|
|
588
|
+
for (let index = 0; index < polar.length; index++) {
|
|
571
589
|
let tws = polar[index].tws
|
|
572
590
|
let twaArray = polar[index].twa
|
|
573
591
|
let highTBS = twaArray[twaArray.length-1].tbs
|
|
@@ -634,25 +652,31 @@ module.exports = function (app) {
|
|
|
634
652
|
data.datasets[index].pointRadius.push(radius)
|
|
635
653
|
}
|
|
636
654
|
}
|
|
655
|
+
// Remove 0 kts line
|
|
656
|
+
data.datasets.shift()
|
|
637
657
|
return data
|
|
638
658
|
}
|
|
639
659
|
|
|
640
|
-
function applyDamping (Xn, unit,
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
660
|
+
function applyDamping (Xn, unit, RC) {
|
|
661
|
+
if (RC == 0) {
|
|
662
|
+
return Xn
|
|
663
|
+
} else {
|
|
664
|
+
if (typeof damping[unit] == 'undefined') {
|
|
665
|
+
// Doesn't exist yet, make obj for unit
|
|
666
|
+
damping[unit] = {Yn: Xn, dt: Date.now()}
|
|
667
|
+
}
|
|
668
|
+
// Calculate a
|
|
669
|
+
let dt = (Date.now() - damping[unit].dt)/1000
|
|
670
|
+
damping[unit].dt = Date.now()
|
|
671
|
+
let a = dt / (RC + dt)
|
|
672
|
+
// Yn = (1-a) * Yn-1 + a * Xn
|
|
673
|
+
let Yn = (1-a) * (damping[unit].Yn || Xn) + a * Xn
|
|
674
|
+
// Remember Yn
|
|
675
|
+
damping[unit].Yn = Yn
|
|
676
|
+
// app.debug('Unit: %s dt: %d a: %d obj: %s', unit, dt, a, JSON.stringify(damping[unit]))
|
|
677
|
+
return Yn
|
|
678
|
+
}
|
|
679
|
+
}
|
|
656
680
|
}
|
|
657
681
|
|
|
658
682
|
plugin.stop = function () {
|
|
@@ -689,7 +713,11 @@ function msToKts(ms) {
|
|
|
689
713
|
}
|
|
690
714
|
|
|
691
715
|
function roundDec (value) {
|
|
692
|
-
value
|
|
693
|
-
|
|
716
|
+
if (typeof value == 'undefined') {
|
|
717
|
+
return undefined
|
|
718
|
+
} else {
|
|
719
|
+
value = Number(value.toFixed(3))
|
|
720
|
+
return value
|
|
721
|
+
}
|
|
694
722
|
}
|
|
695
723
|
|