speedandcurrent 1.7.5 → 1.7.6

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/index.js CHANGED
@@ -120,6 +120,7 @@ module.exports = function (app) {
120
120
  let smoothedGroundSpeed = null;
121
121
  let speedCorrection = null;
122
122
  let residual = null;
123
+ let smoothedResidual = null;
123
124
  let reportFull = null;
124
125
  let table = null;
125
126
 
@@ -422,6 +423,10 @@ module.exports = function (app) {
422
423
  // residual
423
424
  residual = new Polar(app, plugin.id, "residual");
424
425
  residual.setMeta({ displayName: "Residual", plane: "Ground" });
426
+ smoothedResidual = new PolarSmoother(residual, ExponentialSmoother, { tau: 30, timeSpan: 30 }); // id auto-derived: 'residual.smoothed'
427
+ smoothedResidual.setAngleRange('0to2pi');
428
+ // smoothedResidual.xSmoother.reset(0, 0.00000001);
429
+ // smoothedResidual.ySmoother.reset(0, 0.00000001);
425
430
 
426
431
  //#endregion
427
432
 
@@ -438,6 +443,7 @@ module.exports = function (app) {
438
443
  reportFull.addPolar(rawGroundSpeed);
439
444
  reportFull.addPolar(smoothedCurrent);
440
445
  reportFull.addPolar(residual);
446
+ reportFull.addPolar(smoothedResidual);
441
447
  }
442
448
  if (options.updateCorrectionTable) {
443
449
  reportFull.addDelta(smoothedHeading);
@@ -493,6 +499,7 @@ module.exports = function (app) {
493
499
  smoothedGroundSpeed = smoothedGroundSpeed?.terminate();
494
500
  speedCorrection = speedCorrection?.terminate();
495
501
  residual = residual?.terminate();
502
+ smoothedResidual = smoothedResidual?.terminate?.();
496
503
  reportFull = null;
497
504
  table = null;
498
505
  rawHeading = null;
@@ -542,25 +549,39 @@ module.exports = function (app) {
542
549
  speedCorrection.setVectorValue(correction, variance);
543
550
  correctedBoatSpeed.add(speedCorrection);
544
551
  }
545
- // Current estimation and residual also require heading (to rotate into ground frame)
546
- if (rawHeading.ready && rawGroundSpeed.ready) {
552
+ // Current estimation and residual also require heading (to rotate into ground frame).
553
+ // Also handle near-zero SOG where COG is unavailable: treat groundspeed as zero vector.
554
+ const sogHandler = rawGroundSpeed.magnitudeHandler;
555
+ const nearZeroGroundSpeed = !rawGroundSpeed.ready &&
556
+ sogHandler.ready &&
557
+ Number.isFinite(sogHandler.value) &&
558
+ sogHandler.value < 0.3;
559
+ if (rawHeading.ready && (rawGroundSpeed.ready || nearZeroGroundSpeed)) {
547
560
  boatSpeedRefGround.copyFrom(correctedBoatSpeed);
548
561
  boatSpeedRefGround.rotate(rawHeading.value);
549
562
  // Current estimation gated by wellUnderway (smoothers need to settle first)
550
563
  if (wellUnderway) {
551
- rawCurrent.copyFrom(rawGroundSpeed);
564
+ if (rawGroundSpeed.ready) {
565
+ rawCurrent.copyFrom(rawGroundSpeed);
566
+ } else {
567
+ // COG unavailable but SOG is near-zero: boat is stationary, groundspeed treated as zero
568
+ rawCurrent.setVectorValue({ x: 0, y: 0 });
569
+ }
552
570
  rawCurrent.substract(boatSpeedRefGround);
553
571
  smoothedCurrent.sample();
554
572
  }
555
- // Residual: how well correctedBoatSpeed + smoothedCurrent explains groundSpeed
556
- residual.copyFrom(rawGroundSpeed);
557
- residual.substract(boatSpeedRefGround);
558
- residual.substract(smoothedCurrent);
573
+ // Residual requires full groundspeed (both SOG and COG)
574
+ if (rawGroundSpeed.ready) {
575
+ residual.copyFrom(rawGroundSpeed);
576
+ residual.substract(boatSpeedRefGround);
577
+ residual.substract(smoothedCurrent);
578
+ smoothedResidual.sample();
579
+ }
559
580
  }
560
581
  }
561
582
  // Implicit fallback: attitude not ready — correctedBoatSpeed = raw STW, no correction
562
583
 
563
- PolarSmoother.send(app, plugin.id, [smoothedCurrent]);
584
+ PolarSmoother.send(app, plugin.id, [smoothedCurrent, smoothedResidual]);
564
585
 
565
586
  Polar.send(app, plugin.id, [correctedBoatSpeed]);
566
587
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speedandcurrent",
3
- "version": "1.7.5",
3
+ "version": "1.7.6",
4
4
  "description": "A plugin that automatically corrects boat speed and calculates current and leeway using sensor fusion.",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/public/app.js CHANGED
@@ -545,7 +545,7 @@ function renderLiveSections() {
545
545
  );
546
546
  // Estimation — intermediates
547
547
  renderGroupInto('estimation-intermediates',
548
- filterById(state.polarsAll, ['boatSpeedRefGround', 'speedCorrection', 'residual']),
548
+ filterById(state.polarsAll, ['boatSpeedRefGround', 'speedCorrection', 'residual', 'residual.smoothed']),
549
549
  [], []
550
550
  );
551
551
  // Estimation — outputs