diff --git a/calcs/cogMagnetic.js b/calcs/cogMagnetic.js new file mode 100644 index 0000000..32d6017 --- /dev/null +++ b/calcs/cogMagnetic.js @@ -0,0 +1,20 @@ + +module.exports = function(app) { + return { + group: 'navigation', + optionKey: 'courseOverGroundMagnetic', + title: "Magneticcog True + Variation. ", + derivedFrom: [ 'navigation.courseOverGroundTrue', 'navigation.magneticVariation'], + calculator: function(cogTrue, magneticVariation) { + var dir = cogTrue + magneticVariation; + + if ( dir > Math.PI*2 ) { + dir = dir - Math.PI*2; + } else if ( dir < 0 ) { + dir = dir + Math.PI*2; + } + + return [{ path: "navigation.courseOverGroundMagnetic", value: dir}] + } + }; +} diff --git a/calcs/groundWind.js b/calcs/groundWind.js index 3602572..0d614bf 100644 --- a/calcs/groundWind.js +++ b/calcs/groundWind.js @@ -5,14 +5,25 @@ module.exports = function(app, plugin) { group: 'wind', optionKey: 'groundWind', title: "Ground Wind Angle and Speed (based on SOG, AWA and AWS)", - derivedFrom: [ "navigation.speedOverGround", "environment.wind.speedApparent", "environment.wind.angleApparent" ], - calculator: function(sog, aws, awa) { + derivedFrom: [ "navigation.courseOverGround", "navigation.speedOverGround", "environment.wind.speedApparent", "environment.wind.angleApparent" ], + calculator: function(cog, sog, aws, awa) { var apparentX = Math.cos(awa) * aws; var apparentY = Math.sin(awa) * aws; var angle = Math.atan2(apparentY, -sog + apparentX); var speed = Math.sqrt(Math.pow(apparentY, 2) + Math.pow(-sog + apparentX, 2)); - return [{ path: "environment.wind.angleTrueGround", value: angle}, - { path: "environment.wind.speedOverGround", value: speed}] + if ( speed > 100 ) { + console.log("Speed > 100 ", sog, aws, awa, apparentX, apparentY, angle, speed); + } + var dir = cog + angle + + if ( dir > Math.PI*2 ) { + dir = dir - Math.PI*2; + } else if ( dir < 0 ) { + dir = dir + Math.PI*2; + } + return [{ path: "environment.wind.directionGround", value: dir}, + { path: "environment.wind.angleGround", value: angle}, + { path: "environment.wind.speedGround", value: speed}] } }; } diff --git a/calcs/headingMagnetic.js b/calcs/headingMagnetic.js new file mode 100644 index 0000000..0045a65 --- /dev/null +++ b/calcs/headingMagnetic.js @@ -0,0 +1,20 @@ + +module.exports = function(app) { + return { + group: 'navigation', + optionKey: 'magneticHeading', + title: "Magnetic heading based on True + Variation. ", + derivedFrom: [ 'navigation.headingTrue', 'navigation.magneticVariation'], + calculator: function(headTrue, magneticVariation) { + var dir = headTrue + magneticVariation; + + if ( dir > Math.PI*2 ) { + dir = dir - Math.PI*2; + } else if ( dir < 0 ) { + dir = dir + Math.PI*2; + } + + return [{ path: "navigation.headingMagnetic", value: dir}] + } + }; +} diff --git a/calcs/performance.js b/calcs/performance.js new file mode 100644 index 0000000..5fab87d --- /dev/null +++ b/calcs/performance.js @@ -0,0 +1,309 @@ + + +const _ = require('lodash') + +// for the moment, hard code the polar data. + +module.exports = function(app) { + + /** + * find the indexes a below and above the value of b. + */ + function findIndexes (a, v) { + var upper = _.findIndex(a,function(o) { return o > v}); + if ( upper === 0 ) { + return [ upper, upper]; + } else if ( upper === -1) { + return [ a.length-1, a.length-1]; + } + return [ upper-1, upper]; + } + + /** + * find y between yl and yh in the same ratio of x between xl, xh + * simple straight line interpolation. + */ + function interpolate(x, xl, xh, yl, yh) { + var r = 0; + if ( x >= xh ) { + r = yh; + } else if ( x <= xl ) { + r = yl; + } else if ( (xh - xl) < 1.0E-8 ) { + r = yl+(yh-yl)*((x-xl)/1.0E-8); + } else { + r = yl+(yh-yl)*((x-xl)/(xh-xl)); + } + return r; + } + + function msToKnots(v) { + return v*3600/1852.0; + } + + function knotsToMs(v) { + return v*1852.0/3600; + } + function radToDeg(v) { + return v*180.0/Math.PI + } + function degToRad(v) { + return v*Math.PI/180.0; + } + function fixAngle(d) { + if ( d > Math.PI ) d = d - Math.PI; + if ( d < -Math.PI) d = d + Math.PI; + return d; + } + + /** + * Returns polarPerf = { + vmg : 0, + polarVmg: 0; + polarSpeed: 0, + polarSpeedRatio: 1, + polarVmgRatio: 1 + } + Only calcuates polr Vmg ration is targets is defined. + */ + function getPerformance(polarData, tws, twa, stw, targets) { + var polarPerf = { + vmg : 0, + polarVmg: 0, + polarSpeed: 0, + polarSpeedRatio: 1, + polarVmgRatio: 1 + } + if ( !polarData.siunits ) { + tws = msToKnots(tws); + twa = radToDeg(twa); + } + // after here in Deg and Kn + if ( twa < 0) twa = -twa; + var twsi = findIndexes(polarData.tws, tws); + var twai = findIndexes(polarData.twa, twa); + if ( polarData.lookup ) { + // polar data has been pre-interpolated, so simply lookup on the uper end of the range. + // the degree range will + polarPerf.polarSpeed = polarData.stw[twai[1]][twsi[1]]; + } else { + // interpolate a stw low value for a given tws and range + if ( twsi[0] >= polarData.stw[0].length || twsi[1] >= polarData.stw[0].length ) { + console.log("ERROR TWSI===============================================================================") + } + if ( twai[0] >= polarData.stw.length || twai[0] >= polarData.stw.length) { + console.log("ERROR TWAI==============================================================================="); + } + var stwl = interpolate(twa, polarData.twa[twai[0]], polarData.twa[twai[1]], polarData.stw[twai[0]][twsi[0]], polarData.stw[twai[1]][twsi[0]]); + // interpolate a stw high value for a given tws and range + var stwh = interpolate(twa, polarData.twa[twai[0]], polarData.twa[twai[1]], polarData.stw[twai[0]][twsi[1]], polarData.stw[twai[1]][twsi[1]]); + // interpolate a stw final value for a given tws and range using the high an low values for twa. + polarPerf.polarSpeed = interpolate(tws, polarData.tws[twsi[0]], polarData.tws[twsi[1]], stwl, stwh); + } + // after here in SI units. + if (!polarData.siunits) { + twa = degToRad(twa); + polarPerf.polarSpeed = knotsToMs(polarPerf.polarSpeed); + } + if (polarPerf.polarSpeed !== 0) { + polarPerf.polarSpeedRatio = stw/polarPerf.polarSpeed; + } + polarPerf.polarVmg = polarPerf.polarSpeed*Math.cos(twa); + polarPerf.vmg = stw*Math.cos(twa); + if ( targets !== undefined && Math.abs(targets.vmg) > 1.0E-8 ) { + polarPerf.polarVmgRatio = polarPerf.vmg/targets.vmg; + + } + return polarPerf; + } + + function buildFinePolarTable(polar) { + var finePolar = { + lookup: true, + siunits: true, + twsstep : 0.1, // 600 0 - 60Kn + twastep : 1, // 180 0 - 180 deg + tws : [], + twa : [], + stw : [] // 108000 elements + } + console.log("Starting fine polar build"); + for(var twa = 0; twa < polar.twa[polar.twa.length-1]; twa += 1) { + finePolar.twa.push(degToRad(twa)); + finePolar.stw.push([]); + } + for(var tws = 0; tws < polar.tws[polar.tws.length-1]; tws += 0.1) { + finePolar.tws.push(knotsToMs(tws)); + } + for (var ia = 0; ia < finePolar.twa.length; ia++) { + for (var is = 0; is < finePolar.tws.length; is++) { + finePolar.stw[ia][is] = getPerformance(polar,finePolar.tws[is],finePolar.twa[ia],0).polarSpeed; + } + } + //for (var is = 0; is < finePolar.tws.length; is++) { + // for (var ia = 0; ia < finePolar.twa.length; ia++) { + // console.log("FinePolar tws, twa, stw",msToKnots(finePolar.tws[is]),",",radToDeg(finePolar.twa[ia]),",",msToKnots(finePolar.stw[ia][is])); + // } + //} + + console.log("Finished fine polar build, in SI units"); + return finePolar; + } + + /** + * for a given tws, what twa has the maximum vmg upwing or downwind. + * returns targets for twa, stw, vmg. vmg will be -ve downwind. + * var targets = { + vmg: 0, + twa: 0, + stw: 0 + }; + */ + function calcTargetAngleSpeed(polarData,tws, twa) { + // everything in SI here. + var intwa = twa; + if ( twa < 0) twa = -twa; + var twal = 0; twah = Math.PI; + if ( twa < Math.PI/2 ) { + twah = Math.PI/2; + } else { + twal = Math.PI/2; + // downwind scan from 90 - 180 + } + var targets = { + vmg: 0, + twa: 0, + stw: 0 + }; + for(var t = twal; t <= twah; t += Math.PI/180) { + var polarPerf = getPerformance(polarData, tws, t, 0); + var vmg = polarPerf.polarSpeed*Math.cos(t); + if ( Math.abs(vmg) > Math.abs(targets.vmg) ) { + targets.vmg = vmg; + targets.twa = t; + targets.stw = polarPerf.polarSpeed; + } + } + if ( intwa < 0 ) { + targets.twa = -targets.twa; + } + //console.log("Targets tws",msToKnots(tws),"twa:",radToDeg(targets.twa),"psp:",msToKnots(targets.stw),"vmg:",msToKnots(targets.vmg)); + return targets; + } + + // calculates the other track + function calcOtherTrack(polarPerformance, targets, tws, twa, stw, trueHeading, magneticVariation, leeway) { + var otherTrack = { + trackTrue: 0, + trackMagnetic: 0, + headingTrue: 0, + headingMagnetic: 0 + + } + if ( leeway === undefined) { + leeway = 0; + } + // new twa is the target twa, which is always +ve + // We need track through water, not heading, so we must have leeway + if ( twa > 0 ) { + otherTrack.trackTrue = fixAngle(trueHeading-(twa+leeway)-(targets.twa+leeway)); + otherTrack.headingTrue = fixAngle(trueHeading-(twa)-(targets.twa)); + } else { + otherTrack.trackTrue = fixAngle(trueHeading-(twa+leeway)+(targets.twa+leeway)); + otherTrack.headingTrue = fixAngle(trueHeading-(twa)-(targets.twa)); + } + otherTrack.trackMagnetic = otherTrack.trackTrue + magneticVariation; + otherTrack.headingMagnetic = otherTrack.headingTrue + magneticVariation; + return otherTrack; + } + + + var polarPerf = { + group: "performance", + optionKey: 'polarPerformance', + title: "Polar Performance using based on tws, twa, stw, hdt and variation", + derivedFrom: [ "environment.wind.angleTrueWater", "environment.wind.speedTrue", "navigation.speedThroughWater", + 'navigation.headingTrue', 'navigation.magneticVariation' + ], + init: function(options) { + // need to find some way of loading a specif polar file + var polar = require('../polar/pogo1250'); + + if ( polar.twa.length !== polar.stw.length) { + throw("Polar STW does not have enough rows for the TWA array. Expected:"+polar.twa.length+" Found:"+polar.stw.length); + } + for (var i = 0; i < polar.stw.length; i++) { + if ( polar.tws.length !== polar.stw[i].length ) { + throw("Polar STW row "+i+" does not ave enough columns Expected:"+polar.tws.length+" Found:"+polar.stw.length); + } + } + for (var i = 1; i < polar.twa.length; i++) { + if ( polar.twa[i] < polar.twa[i-1] ) { + throw("Polar TWA must be in ascending order and match the columns of stw."); + } + }; + for (var i = 1; i < polar.tws.length; i++) { + if ( polar.tws[i] < polar.tws[i-1] ) { + throw("Polar TWA must be in ascending order and match the rows of stw."); + } + }; + // Optimisatin, + polar = buildFinePolarTable(polar); + polarPerf.polar = polar; + }, + calculator: function(twa, tws, stw, trueHeading, magneticVariation){ + try { + var targets = calcTargetAngleSpeed(polarPerf.polar, tws, twa, stw); + var polarPerformance = getPerformance(polarPerf.polar, tws,twa, stw, targets); + var track = calcOtherTrack(polarPerformance, targets, tws, twa, stw, trueHeading, magneticVariation); + + /*console.log("performance,", + msToKnots(tws).toFixed(2), + ",twa,", + radToDeg(twa).toFixed(2), + ",stw,", + msToKnots(stw).toFixed(2), + ",pstw,", + msToKnots(polarPerformance.polarSpeed).toFixed(2), + ",vmg,", + msToKnots(polarPerformance.vmg).toFixed(2), + ",pvmg,", + msToKnots(polarPerformance.polarVmg).toFixed(2), + ",pvmgr,", + polarPerformance.polarVmgRatio.toFixed(2), + ",tvmg,", + msToKnots(targets.vmg).toFixed(2), + ",ttwa,", + radToDeg(targets.twa).toFixed(2), + ",tstw,", + msToKnots(targets.stw).toFixed(2), + ",trt,", + radToDeg(track.trackTrue).toFixed(2), + ",trm,", + radToDeg(track.trackMagnetic).toFixed(2), + ",tht,", + radToDeg(track.headingTrue).toFixed(2), + ",thm,", + radToDeg(track.headingMagnetic).toFixed(2) + ); */ + return [ + { path: 'performance.polarSpeed', value: polarPerformance.polarSpeed}, // polar speed at this twa + { path: 'performance.polarSpeedRatio', value: polarPerformance.polarSpeedRatio}, // polar speed ratio + { path: 'performance.tackMagnetic', value: track.trackMagnetic}, // other track through water magnetic taking into account leeway + { path: 'performance.tackTrue', value: track.trackTrue}, // other track through water true taking into account leeway + { path: 'performance.headingMagnetic', value: track.headingMagnetic}, // other track heading on boat compass + { path: 'performance.headingTrue', value: track.headingTrue}, // other track heading true + { path: 'performance.targetAngle', value: targets.twa}, // target twa on this track for best vmg + { path: 'performance.targetSpeed', value: targets.stw}, // target speed on at best vmg and angle + { path: 'performance.targetVelocityMadeGood', value: targets.vmg}, // target vmg -ve == downwind + { path: 'performance.velocityMadeGood', value: polarPerformance.vmg}, // current vmg at polar speed + { path: 'performance.polarVelocityMadeGoodRatio', value: polarPerformance.polarVmgRatio} // current vmg vs current polar vmg. + ]; + } catch (e) { + console.log(e); + } + } + }; + + return polarPerf; +} \ No newline at end of file diff --git a/calcs/trueWind.js b/calcs/trueWind.js index 425c506..add99e0 100644 --- a/calcs/trueWind.js +++ b/calcs/trueWind.js @@ -21,7 +21,7 @@ module.exports = function(app) { } return [{ path: "environment.wind.directionTrue", value: dir}, - { path: "environment.wind.angleTrueWater", value: angle}, + { path: "environment.wind.angleTrue", value: angle}, { path: "environment.wind.speedTrue", value: speed}] } }; diff --git a/calcs/vmg.js b/calcs/vmg.js index b4ec8bb..377e626 100644 --- a/calcs/vmg.js +++ b/calcs/vmg.js @@ -9,9 +9,12 @@ module.exports = function(app) { "navigation.speedOverGround" ], calculator: function (bearingTrue, headingTrue, speedOverGround) { - var angle = Math.abs(bearingTrue-headingTrue) + var angle = Math.abs(bearingTrue-headingTrue); + var vmgWaypoint = Math.cos(bearingTrue-headingTrue) * speedOverGround; return [{ path: "navigation.courseGreatCircle.nextPoint.velocityMadeGood", - value: Math.cos(bearingTrue-headingTrue) * speedOverGround}] + value: vmgWaypoint}, + {path: "performance.velocityMadeGoodToWaypoint", + value: vmgWaypoint}] } }; } diff --git a/calcs/windShift.js b/calcs/windShift.js index b0e4177..3845bdf 100644 --- a/calcs/windShift.js +++ b/calcs/windShift.js @@ -33,7 +33,7 @@ module.exports = function(app, plugin) { 'environment.wind.directionChangeAlarm.value') if ( typeof alarm === 'undefined' ) { - console.log("signall-Derived-data: no directionChangeAlarm value") + //console.log("signall-Derived-data: no directionChangeAlarm value") return undefined } diff --git a/index.js b/index.js index 22fa883..b506355 100644 --- a/index.js +++ b/index.js @@ -49,6 +49,11 @@ module.exports = function(app) { if (calculation.ttl === undefined ) { calculation.ttl = 1000; // default to a ttl of 1s. } + + if ( typeof calculation.init === 'function' ) { + // might need to add configuration options here in the future. + calculation.init(); + } unsubscribes.push( Bacon.combineWith( @@ -80,6 +85,9 @@ module.exports = function(app) { "context": "vessels." + app.selfId, "updates": [ { + "source": { + "src": "derived_data" + }, "timestamp": (new Date()).toISOString(), "values": values } diff --git a/polar/README.md b/polar/README.md new file mode 100644 index 0000000..9e21a08 --- /dev/null +++ b/polar/README.md @@ -0,0 +1,22 @@ +Polar files format. + +Name followed by 1..n headers delimiated by a line containing ----------- +Then tab seperated header of tws, first cell ignored. +Followed by tab seperated lines of boat speed, first cell is the wind angle. +All numbers are floats. + +Name +header +header +---------- + -------------- tws ----------------- +| bsp +| +| +t +w +a +| +| +| +| \ No newline at end of file diff --git a/polar/pogo1250.js b/polar/pogo1250.js new file mode 100644 index 0000000..db0e512 --- /dev/null +++ b/polar/pogo1250.js @@ -0,0 +1,31 @@ +module.exports = { + name : "pogo1250", + tws : [0,4,6,8,10,12,14,16,20,25,30,35,40,45,50,55,60], + twa : [0,5,10,15,20,25,32,36,40,45,52,60,70,80,90,100,110,120,130,140,150,160,170,180], + stw : [ +[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], +[0,0.4,0.6,0.8,0.9,1,1,1,1.1,1.1,1.1,1.1,0.1,0.1,0.1,0,0], +[0,0.8,1.2,1.6,1.8,2,2,2.1,2.1,2.2,2.2,2.2,0.5,0.2,0.2,0,0], +[0,1.2,1.8,2.4,2.7,2.9,3,3.1,3.2,3.3,3.3,3.3,1.2,0.5,0.3,0,0], +[0,1.4,2.1,2.7,3.1,3.4,3.5,3.6,3.6,3.7,3.8,3.7,1.7,0.7,0.4,0,0], +[0,1.7,2.5,3.2,3.7,4,4.1,4.3,4.3,4.4,4.5,4.4,2.6,1.1,0.4,0,0], +[0,2.8,4.2,5.4,6.2,6.7,6.9,7.1,7.2,7.4,7.5,7.4,5.6,2.2,0.7,0,0], +[0,3.1,4.7,5.9,6.7,7,7.2,7.4,7.6,7.8,7.9,7.9,6.5,2.6,0.8,0,0], +[0,3.5,5.1,6.3,7,7.3,7.5,7.7,7.9,8.1,8.2,8.3,7.4,2.9,1.2,0,0], +[0,3.8,5.6,6.7,7.3,7.6,7.8,8,8.2,8.4,8.5,8.6,8.2,3,1.3,0,0], +[0,4.2,6,7,7.7,8,8.2,8.3,8.6,8.9,9,9.1,8.9,3.2,1.4,0,0], +[0,4.6,6.3,7.3,8,8.3,8.5,8.7,9,9.3,9.5,9.6,9.6,3.8,1.9,0,0], +[0,4.8,6.6,7.5,8.2,8.6,8.9,9.1,9.5,9.8,10.1,10.4,10.4,4.2,2.1,0,0], +[0,5,6.9,7.9,8.3,8.8,9.2,9.4,9.9,10.4,10.9,11.3,11.3,4.5,2.3,0,0], +[0,5.3,7.1,8.1,8.6,8.9,9.3,9.7,10.4,11.1,11.8,12.5,12.5,5.6,3.1,0.6,0.6], +[0,5.4,7.1,8.2,8.8,9.2,9.5,9.9,10.9,11.9,12.8,14.1,14.1,7.1,4.2,0.7,0.7], +[0,5.3,7,8.1,8.8,9.4,9.8,10.3,11.2,12.7,14.3,15,15,8.3,5.3,1.5,1.5], +[0,5,6.8,7.8,8.6,9.4,10,10.6,11.8,13.2,14.9,15.7,15.7,9.4,6.3,1.6,1.6], +[0,4.5,6.3,7.4,8.3,9,9.8,10.6,12.3,14.4,15.6,16.6,16.6,10.8,7.5,2.5,2.5], +[0,3.8,5.6,6.9,7.8,8.5,9.2,10,12.2,15,16.3,17.6,17.6,13.2,9.7,3.5,2.6], +[0,3.2,4.8,6.1,7.1,7.9,8.6,9.3,10.9,14.4,16.8,18.6,18.6,14.9,11.2,3.7,3.7], +[0,2.7,4.1,5.3,6.4,7.3,8,8.7,10,12.4,15.4,17.9,17.9,15.2,11.6,4.5,3.6], +[0,2.4,3.6,4.8,5.9,6.8,7.6,8.2,9.4,11.4,14.3,16.6,16.6,15.8,12.5,5,4.2], +[0,2.2,3.3,4.4,5.5,6.4,7.2,7.9,9,10.6,12.8,15.4,15.4,15.4,12.3,4.6,3.9] +] +}; diff --git a/polar/polar.txt b/polar/polar.txt new file mode 100644 index 0000000..64519c6 --- /dev/null +++ b/polar/polar.txt @@ -0,0 +1,41 @@ +# this file is an Octave script to visialise Polar data. +# install https://www.gnu.org/software/octave/ and run this script to look at the data. +# You can manipulate the data before dumping out again. + +tws = ["0";"4";"6";"8";"10";"12";"14";"16";"20";"25";"30";"35";"40";"45";"50";"55";"60"]; +twa = [0 5 10 15 20 25 32 36 40 45 52 60 70 80 90 100 110 120 130 140 150 160 170 180]; +twa = twa'; +twa = twa.*pi/180; +twa = [twa; 2*pi.-flipud(twa)]; +stw = [ +0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0; +0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0; +0 0.8 1.1 1.1 1.1 1.2 1.2 1.2 1.2 1.2 1.2 1.2 0.8 0.2 0.2 0 0; +0 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 1.2 0.8 0.5 0.3 0 0; +0 1.3 1.4 1.5 1.5 1.6 1.5 1.5 1.5 1.4 1.2 1.2 1.7 0.7 0.4 0 0; +0 1.7 2.5 3.2 3.7 4.0 4.1 4.3 4.3 4.4 4.5 4.4 2.6 1.1 0.4 0 0; +0 2.8 4.2 5.4 6.2 6.7 6.9 7.1 7.2 7.4 7.5 7.4 5.6 2.2 0.7 0 0; +0 3.1 4.7 5.9 6.7 7.0 7.2 7.4 7.6 7.8 7.9 7.9 6.5 2.6 0.8 0 0; +0 3.5 5.1 6.3 7.0 7.3 7.5 7.7 7.9 8.1 8.2 8.3 7.4 2.9 1.2 0 0; +0 3.8 5.6 6.7 7.3 7.6 7.8 8.0 8.2 8.4 8.5 8.6 8.2 3.0 1.3 0 0; +0 4.2 6.0 7.0 7.7 8.0 8.2 8.3 8.6 8.9 9.0 9.1 8.9 3.2 1.4 0 0; +0 4.6 6.3 7.3 8.0 8.3 8.5 8.7 9.0 9.3 9.5 9.6 9.6 3.8 1.9 0 0; +0 4.8 6.6 7.5 8.2 8.6 8.9 9.1 9.5 9.8 10.1 10.4 10.4 4.2 2.1 0 0; +0 5.0 6.9 7.9 8.3 8.8 9.2 9.4 9.9 10.4 10.9 11.3 11.3 4.5 2.3 0 0; +0 5.3 7.1 8.1 8.6 8.9 9.3 9.7 10.4 11.1 11.8 12.5 12.5 5.6 3.1 0.6 0.6; +0 5.4 7.1 8.2 8.8 9.2 9.5 9.9 10.9 11.9 12.8 14.1 14.1 7.1 4.2 0.7 0.7; +0 5.3 7.0 8.1 8.8 9.4 9.8 10.3 11.2 12.7 14.3 15.0 15.0 8.3 5.3 1.5 1.5; +0 5.0 6.8 7.8 8.6 9.4 10.0 10.6 11.8 13.2 14.9 15.7 15.7 9.4 6.3 1.6 1.6; +0 4.5 6.3 7.4 8.3 9.0 9.8 10.6 12.3 14.4 15.6 16.6 16.6 10.8 7.5 2.5 2.5; +0 3.8 5.6 6.9 7.8 8.5 9.2 10.0 12.2 15.0 16.3 17.6 17.6 13.2 9.7 3.5 2.6; +0 3.2 4.8 6.1 7.1 7.9 8.6 9.3 10.9 14.4 16.8 18.6 18.6 14.9 11.2 3.7 3.7; +0 2.7 4.1 5.3 6.4 7.3 8.0 8.7 10.0 12.4 15.4 17.9 17.9 15.2 11.6 4.5 3.6; +0 2.4 3.6 4.8 5.9 6.8 7.6 8.2 9.4 11.4 14.3 16.6 16.6 15.8 12.5 5.0 4.2; +0 2.2 3.3 4.4 5.5 6.4 7.2 7.9 9.0 10.6 12.8 15.4 15.4 15.4 12.3 4.6 3.9 ]; + +stw = [ stw; flipud(stw)]; +polar(twa,stw); +legend(tws); +set (gca, "rtick", 2.0:2.0:20, "ttick", 0:10:350); +view(-90,90); +title("Pogot 1250 polar"); \ No newline at end of file diff --git a/polar/testpolar.js b/polar/testpolar.js new file mode 100644 index 0000000..222ae98 --- /dev/null +++ b/polar/testpolar.js @@ -0,0 +1,31 @@ +module.exports = { + name : "testPolar", + tws : [0,2,3,4,5,12,14,16,20,25,30,35,40,45,50,55,60], + twa : [0,5,10,15,20,22,24,25,28,30,52,60,70,80,90,100,110,120,130,140,150,160,170,180], + stw : [ +[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], +[0,0.4,0.6,0.8,0.9,1,1,1,1.1,1.1,1.1,1.1,0.1,0.1,0.1,0,0], +[0,0.8,1.2,1.6,1.8,2,2,2.1,2.1,2.2,2.2,2.2,0.5,0.2,0.2,0,0], +[0,1.2,1.8,2.4,2.7,2.9,3,3.1,3.2,3.3,3.3,3.3,1.2,0.5,0.3,0,0], +[0,1.4,2.1,2.7,3.1,3.4,3.5,3.6,3.6,3.7,3.8,3.7,1.7,0.7,0.4,0,0], +[0,1.7,2.5,3.2,3.7,4,4.1,4.3,4.3,4.4,4.5,4.4,2.6,1.1,0.4,0,0], +[0,2.8,4.2,5.4,6.2,6.7,6.9,7.1,7.2,7.4,7.5,7.4,5.6,2.2,0.7,0,0], +[0,3.1,4.7,5.9,6.7,7,7.2,7.4,7.6,7.8,7.9,7.9,6.5,2.6,0.8,0,0], +[0,3.5,5.1,6.3,7,7.3,7.5,7.7,7.9,8.1,8.2,8.3,7.4,2.9,1.2,0,0], +[0,3.8,5.6,6.7,7.3,7.6,7.8,8,8.2,8.4,8.5,8.6,8.2,3,1.3,0,0], +[0,4.2,6,7,7.7,8,8.2,8.3,8.6,8.9,9,9.1,8.9,3.2,1.4,0,0], +[0,4.6,6.3,7.3,8,8.3,8.5,8.7,9,9.3,9.5,9.6,9.6,3.8,1.9,0,0], +[0,4.8,6.6,7.5,8.2,8.6,8.9,9.1,9.5,9.8,10.1,10.4,10.4,4.2,2.1,0,0], +[0,5,6.9,7.9,8.3,8.8,9.2,9.4,9.9,10.4,10.9,11.3,11.3,4.5,2.3,0,0], +[0,5.3,7.1,8.1,8.6,8.9,9.3,9.7,10.4,11.1,11.8,12.5,12.5,5.6,3.1,0.6,0.6], +[0,5.4,7.1,8.2,8.8,9.2,9.5,9.9,10.9,11.9,12.8,14.1,14.1,7.1,4.2,0.7,0.7], +[0,5.3,7,8.1,8.8,9.4,9.8,10.3,11.2,12.7,14.3,15,15,8.3,5.3,1.5,1.5], +[0,5,6.8,7.8,8.6,9.4,10,10.6,11.8,13.2,14.9,15.7,15.7,9.4,6.3,1.6,1.6], +[0,4.5,6.3,7.4,8.3,9,9.8,10.6,12.3,14.4,15.6,16.6,16.6,10.8,7.5,2.5,2.5], +[0,3.8,5.6,6.9,7.8,8.5,9.2,10,12.2,15,16.3,17.6,17.6,13.2,9.7,3.5,2.6], +[0,3.2,4.8,6.1,7.1,7.9,8.6,9.3,10.9,14.4,16.8,18.6,18.6,14.9,11.2,3.7,3.7], +[0,2.7,4.1,5.3,6.4,7.3,8,8.7,10,12.4,15.4,17.9,17.9,15.2,11.6,4.5,3.6], +[0,2.4,3.6,4.8,5.9,6.8,7.6,8.2,9.4,11.4,14.3,16.6,16.6,15.8,12.5,5,4.2], +[0,2.2,3.3,4.4,5.5,6.4,7.2,7.9,9,10.6,12.8,15.4,15.4,15.4,12.3,4.6,3.9] +] +}; \ No newline at end of file