node-red-contrib-prib-functions 0.19.2 → 0.21.0
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/.github/workflows/codeql-analysis.yml +3 -3
- package/.github/workflows/npmpublish.yml +6 -6
- package/.vs/VSWorkspaceState.json +7 -0
- package/.vs/node-red-contrib-prib-functions/v17/.wsuo +0 -0
- package/README.md +84 -70
- package/dataAnalysis/arrayAllRowsSwap.js +15 -0
- package/dataAnalysis/arrayCompareToPrecision.js +34 -0
- package/dataAnalysis/arrayDifference.js +14 -0
- package/dataAnalysis/arrayDifferenceSeasonal.js +15 -0
- package/dataAnalysis/arrayDifferenceSeasonalSecondOrder.js +20 -0
- package/dataAnalysis/arrayDifferenceSecondOrder.js +14 -0
- package/dataAnalysis/arrayForEachRange.js +38 -0
- package/dataAnalysis/arrayOverlay.js +13 -0
- package/dataAnalysis/arrayProduct.js +11 -0
- package/dataAnalysis/arrayRandom.js +14 -0
- package/dataAnalysis/arrayReduceRange.js +11 -0
- package/dataAnalysis/arrayScale.js +11 -0
- package/dataAnalysis/arraySum.js +11 -0
- package/dataAnalysis/arraySumSquared.js +11 -0
- package/dataAnalysis/arraySwap.js +11 -0
- package/dataAnalysis/dataAnalysis.html +52 -21
- package/dataAnalysis/dataAnalysis.js +73 -44
- package/dataAnalysis/generateMatrixFunction.js +89 -0
- package/dataAnalysis/generateVectorFunction.js +25 -0
- package/dataAnalysis/pca.js +472 -325
- package/dataAnalysis/svd.js +239 -0
- package/documentation/DataAnalysisRealtime.JPG +0 -0
- package/documentation/monitorSystem.JPG +0 -0
- package/documentation/monitorSystemTest.JPG +0 -0
- package/echart/echart.html +68 -0
- package/echart/echart.js +85 -0
- package/echart/icons/chart-671.png +0 -0
- package/echart/lib/echarts.js +95886 -0
- package/lib/Chart.js +177 -0
- package/lib/Column.js +99 -0
- package/lib/GraphDB.js +14 -0
- package/lib/Table.js +185 -0
- package/lib/objectExtensions.js +361 -0
- package/matrix/matrix.js +95 -56
- package/matrix/matrixNode.html +88 -55
- package/matrix/matrixNode.js +12 -5
- package/monitor/BarGauge.js +8 -0
- package/monitor/Dataset.js +29 -0
- package/monitor/DialGauge.js +109 -0
- package/monitor/DialNeedle.js +36 -0
- package/monitor/Format.js +74 -0
- package/monitor/centerElement.js +14 -0
- package/monitor/compareElements.js +95 -0
- package/monitor/defs.js +23 -0
- package/monitor/extensions.js +906 -0
- package/monitor/functions.js +36 -0
- package/monitor/json2xml.js +103 -0
- package/monitor/monitorSystem.html +199 -0
- package/monitor/monitorSystem.js +322 -0
- package/monitor/svgHTML.js +179 -0
- package/monitor/svgObjects.js +64 -0
- package/package.json +20 -6
- package/test/00-objectExtensions.js +94 -0
- package/test/04-tables.js +33 -0
- package/test/data/.config.nodes.json +608 -0
- package/test/data/.config.nodes.json.backup +608 -0
- package/test/data/.config.runtime.json +4 -0
- package/test/data/.config.runtime.json.backup +3 -0
- package/test/data/.config.users.json +21 -0
- package/test/data/.config.users.json.backup +21 -0
- package/test/data/.flow.json.backup +2820 -2003
- package/test/data/float32vector10.npy +0 -0
- package/test/data/flow.json +2830 -2033
- package/test/data/int2matrix2x3.npy +0 -0
- package/test/data/package-lock.json +158 -0
- package/test/data/package.json +11 -0
- package/test/dataAnalysisExtensions.js +471 -0
- package/test/dataAnalysisPCA.js +54 -0
- package/test/dataAnalysisSVD.js +31 -0
- package/test/euclideanDistance.js +2 -2
- package/test/transformConfluence.js +1 -1
- package/test/transformNumPy.js +132 -0
- package/testing/test.html +1 -1
- package/testing/test.js +78 -53
- package/transform/NumPy.js +303 -0
- package/transform/transform.html +12 -0
- package/transform/transform.js +34 -2
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
name: {value:"",required:false},
|
|
8
8
|
action: {value:"avg",required:true},
|
|
9
9
|
columns:{value:"",required:false},
|
|
10
|
+
lag: {value:1,required:true},
|
|
10
11
|
outputs: {value:(["realtime","realtimePredict"].includes(this.action)?3:2),required:true},
|
|
11
12
|
outliersBase: {value:"avg",required:false},
|
|
12
13
|
outliersStdDevs: {value:"3",required:false},
|
|
13
|
-
term: {value:
|
|
14
|
+
term: {value:10,required:false},
|
|
14
15
|
keyProperty: {value:"msg.topic",required:false},
|
|
15
16
|
dataProperty: {value:"msg.payload",required:false},
|
|
16
17
|
dataProperties: {value:["msg.payload[0]","msg.payload[1]"],required:false}
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
},
|
|
28
29
|
oneditprepare: function() {
|
|
29
30
|
const node=this;
|
|
31
|
+
node.lag??=1
|
|
30
32
|
$("#node-input-keyProperty").change(function() {
|
|
31
33
|
if( [null,""].includes(node.keyProperty) ) {
|
|
32
34
|
$(this).val("msg.topic");
|
|
@@ -45,49 +47,62 @@
|
|
|
45
47
|
}
|
|
46
48
|
});
|
|
47
49
|
$("#node-input-action").change(function() {
|
|
48
|
-
|
|
50
|
+
if(["differenceSeasonal","differenceSeasonalSecondOrder","realtime","realtimePredict"].includes( $(this).val() )) {
|
|
51
|
+
$(".form-row-http-in-lag").show();
|
|
52
|
+
} else {
|
|
53
|
+
$(".form-row-http-in-lag").hide();
|
|
54
|
+
}
|
|
55
|
+
if(["distances","distancesMax","distancesMin"].includes( $(this).val() )) {
|
|
49
56
|
$(".form-row-http-in-columns").show();
|
|
50
|
-
|
|
57
|
+
} else {
|
|
51
58
|
$(".form-row-http-in-columns").hide();
|
|
52
|
-
|
|
59
|
+
}
|
|
53
60
|
if(["movingAvgSimple","movingAvgWeighted","movingAvgExponential","realtime","realtimePredict"].includes( $(this).val() )) {
|
|
54
61
|
$(".form-row-http-in-term").show();
|
|
55
|
-
|
|
62
|
+
} else {
|
|
56
63
|
$(".form-row-http-in-term").hide();
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
}
|
|
65
|
+
if(["movingAvgExponential"].includes( $(this).val() )) {
|
|
59
66
|
$("#node-input-term").attr({min:0,max:1,step:0.1});
|
|
60
67
|
if(node.term<0 || node.term>1) $("#node-input-term").val(0.5);
|
|
61
68
|
$("#node-input-term").change(function() {
|
|
62
69
|
if(node.term<0) $(this).val(0);
|
|
63
70
|
if(node.term>1) $(this).val(1);
|
|
64
71
|
});
|
|
65
|
-
|
|
72
|
+
} else {
|
|
73
|
+
$("#node-input-lag").attr({min:1,max:1000,step:1});
|
|
74
|
+
$("#node-input-lag").change(function() {
|
|
75
|
+
const v=$(this).val();
|
|
76
|
+
if(v<1) $(this).val(1);
|
|
77
|
+
if(v>1000) $(this).val(1000);
|
|
78
|
+
});
|
|
66
79
|
$("#node-input-term").attr({min:1,max:100,step:1});
|
|
67
80
|
$("#node-input-term").change(function() {
|
|
68
|
-
|
|
69
|
-
if(
|
|
81
|
+
const v=$(this).val()
|
|
82
|
+
if(v<1) $(this).val(1);
|
|
83
|
+
if(v>100) $(this).val(100);
|
|
70
84
|
});
|
|
71
|
-
|
|
72
|
-
|
|
85
|
+
}
|
|
86
|
+
if(["realtime","realtimePredict"].includes( $(this).val() )) {
|
|
73
87
|
node.outputs=3;
|
|
74
88
|
$(".form-row-http-in-keyProperty").show();
|
|
75
89
|
$(".form-row-http-in-outliersStdDevs").show();
|
|
76
90
|
$(".form-row-http-in-outliersBase").show();
|
|
77
91
|
$("#node-input-outliersStdDevs").change();
|
|
78
|
-
|
|
92
|
+
} else {
|
|
79
93
|
node.outputs=2;
|
|
80
94
|
$(".form-row-http-in-keyProperty").hide();
|
|
81
95
|
$(".form-row-http-in-outliersStdDevs").hide();
|
|
82
96
|
$(".form-row-http-in-outliersBase").hide();
|
|
83
|
-
|
|
84
|
-
|
|
97
|
+
}
|
|
98
|
+
if(["pearsonR","covariance","corelationship"].includes( $(this).val() )) {
|
|
85
99
|
$(".node-input-dataProperties-container-row").show();
|
|
86
100
|
$(".form-row-http-in-dataProperty").hide();
|
|
87
|
-
|
|
101
|
+
} else {
|
|
88
102
|
$(".node-input-dataProperties-container-row").hide();
|
|
89
103
|
$(".form-row-http-in-dataProperty").show();
|
|
90
|
-
|
|
104
|
+
}
|
|
105
|
+
$("#node-input-lag").change();
|
|
91
106
|
$("#node-input-term").change();
|
|
92
107
|
});
|
|
93
108
|
|
|
@@ -148,6 +163,10 @@
|
|
|
148
163
|
<option value="corelationship">Corelationship</option>
|
|
149
164
|
<option value="deltas">Deltas</option>
|
|
150
165
|
<option value="deltaNormalised">Deltas Normalised</option>
|
|
166
|
+
<option value="difference">Difference</option>
|
|
167
|
+
<option value="differenceSeasonal">Difference Seasonal</option>
|
|
168
|
+
<option value="differenceSeasonalSecondOrder">Difference Seasonal Second Order</option>
|
|
169
|
+
<option value="differenceSecondOrder">Difference Second Order</option>
|
|
151
170
|
<option value="distances">Euclidean Distances</option>
|
|
152
171
|
<option value="distancesMax">Euclidean Distances Max</option>
|
|
153
172
|
<option value="distancesMin">Euclidean Distances Min</option>
|
|
@@ -162,6 +181,7 @@
|
|
|
162
181
|
<option value="movingAvgExponential">Moving Average Exponential (EMA/EWMA)</option>
|
|
163
182
|
<option value="normalize">Normalise</option>
|
|
164
183
|
<option value="pearsonR">Pearson Product Moment Correlation (PPMC)</option>
|
|
184
|
+
<option value="randomise">Randomise</option>
|
|
165
185
|
<option value="range">Range</option>
|
|
166
186
|
<option value="realtime">RealTime Metrics</option>
|
|
167
187
|
<option value="realtimePredict">RealTime Metrics + predicts</option>
|
|
@@ -179,6 +199,11 @@
|
|
|
179
199
|
<label for="node-input-columns"><i class="icon-bookmark"></i> Columns</label>
|
|
180
200
|
<input type="text" id="node-input-columns" placeholder="columns">
|
|
181
201
|
</div>
|
|
202
|
+
|
|
203
|
+
<div class="form-row form-row-http-in-lag hide">
|
|
204
|
+
<label for="node-input-lag"><i class="icon-bookmark"></i> Lag</label>
|
|
205
|
+
<input type="number" id="node-input-lag" placeholder="lag" min="1" max="10000" step="1">
|
|
206
|
+
</div>
|
|
182
207
|
|
|
183
208
|
<div class="form-row form-row-http-in-term hide">
|
|
184
209
|
<label for="node-input-term"><i class="icon-bookmark"></i> Term</label>
|
|
@@ -231,12 +256,18 @@ Data is not persisted so metrics start from zero sample set on node recycle.
|
|
|
231
256
|
<p>
|
|
232
257
|
If real-time stats then a message can send directive instruction in topic:
|
|
233
258
|
<dl>
|
|
234
|
-
<dt>"@predict <key>"
|
|
235
|
-
<dt>"@stats"
|
|
236
|
-
<dt>"@stats reset"
|
|
237
|
-
<dt>"@stats set"
|
|
259
|
+
<dt>"@predict <key>"</dt><dd></dd>Send send predictions to second port for selected key.
|
|
260
|
+
<dt>"@stats"</dt><dd></dd>send all stored metrics and retained datapoints to second port.
|
|
261
|
+
<dt>"@stats reset"</dt><dd>Reset all stats and "@stats reset <key>" will reset a particular data point.</dd>
|
|
262
|
+
<dt>"@stats set"</dt><dd>Set stats with ith msg.payload and "@stats set <a data point>" will set a particular data point with msg.payload.</dd>
|
|
238
263
|
</dl>
|
|
239
264
|
</p>
|
|
265
|
+
<dl>
|
|
266
|
+
<dt>Lag</dt><dd>If greater that 1 generates seasonal difference with degree lag</dd>
|
|
267
|
+
<dt>Term</dt><dd>The depth of moving Average</dd>
|
|
268
|
+
</dl>
|
|
269
|
+
<p>
|
|
270
|
+
</p>
|
|
240
271
|
<p>
|
|
241
272
|
Outliers are not within:
|
|
242
273
|
<ul>
|
|
@@ -2,6 +2,11 @@ const logger = new (require("node-red-contrib-logger"))("Data Analysis");
|
|
|
2
2
|
logger.sendInfo("Copyright 2020 Jaroslav Peter Prib");
|
|
3
3
|
|
|
4
4
|
require("./arrayLast");
|
|
5
|
+
require("./arrayDifference")
|
|
6
|
+
require("./arrayDifferenceSeasonal")
|
|
7
|
+
require("./arrayDifferenceSeasonalSecondOrder")
|
|
8
|
+
require("./arrayDifferenceSecondOrder")
|
|
9
|
+
require("./arrayRandom")
|
|
5
10
|
const ed=require("./euclideanDistance.js");
|
|
6
11
|
require("./forNestedEach");
|
|
7
12
|
|
|
@@ -64,10 +69,10 @@ EMA.prototype.sample=function(value) {
|
|
|
64
69
|
return this;
|
|
65
70
|
}
|
|
66
71
|
|
|
67
|
-
function setDataPoint(value,term,node,
|
|
68
|
-
if(logger.active) logger.send({label:"setDataPoint",value:value,term,
|
|
69
|
-
if(!
|
|
70
|
-
Object.assign(
|
|
72
|
+
function setDataPoint(value,term,node,dataPoint) {
|
|
73
|
+
if(logger.active) logger.send({label:"setDataPoint",value:value,term,dataPoint});
|
|
74
|
+
if(!dataPoint.values) {
|
|
75
|
+
Object.assign(dataPoint,{
|
|
71
76
|
values:[],
|
|
72
77
|
avg:0,
|
|
73
78
|
count:0,
|
|
@@ -78,43 +83,44 @@ function setDataPoint(value,term,node,dp) {
|
|
|
78
83
|
sum:0,
|
|
79
84
|
sumSquared:0,
|
|
80
85
|
sumCubed:0,
|
|
81
|
-
term:term,
|
|
86
|
+
term:term??node.term,
|
|
82
87
|
weightedMovingSum:0,
|
|
83
88
|
exponentialWeightedMoving:[new EMA(0.25),new EMA(0.5),new EMA(0.75)]
|
|
84
89
|
});
|
|
85
|
-
}
|
|
86
|
-
;
|
|
87
|
-
const count=++dp.count,values=dp.values;
|
|
90
|
+
};
|
|
91
|
+
const count=++dataPoint.count,values=dataPoint.values;
|
|
88
92
|
values.push(value);
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
93
|
+
const movingTerm=Math.min(values.length,dataPoint.term)
|
|
94
|
+
dataPoint.isMaxSize=(values.length>dataPoint.maxSize);
|
|
95
|
+
dataPoint.removedMovingValue=(dataPoint.isMaxSize?values[values.length-dataPoint.term]:0);
|
|
96
|
+
dataPoint.removedValue=(dataPoint.isMaxSize?values.shift():0);
|
|
97
|
+
const removedMovingValue=dataPoint.removedMovingValue;
|
|
98
|
+
dataPoint.max=Math.max(dataPoint.max||value,value);
|
|
99
|
+
dataPoint.min=Math.min(dataPoint.min||value,value);
|
|
100
|
+
dataPoint.range=dataPoint.max-dataPoint.min;
|
|
101
|
+
dataPoint.sum+=value;
|
|
102
|
+
dataPoint.sumSquared+=Math.pow(value,2);
|
|
103
|
+
dataPoint.sumCubed+=Math.pow(value,3);
|
|
104
|
+
dataPoint.movingSum+=value-removedMovingValue;
|
|
105
|
+
dataPoint.movingSumSquared+=Math.pow(value,2)-Math.pow(removedMovingValue,2);
|
|
106
|
+
dataPoint.movingSumCubed+=Math.pow(value,3)-Math.pow(removedMovingValue,3);
|
|
107
|
+
dataPoint.avg=dataPoint.sum/count;
|
|
108
|
+
const avg=dataPoint.avg;
|
|
109
|
+
dataPoint.normalised=dataPoint.range ? (value-avg)/dataPoint.range : 0;
|
|
110
|
+
dataPoint.movingAvg=dataPoint.movingSum/movingTerm;
|
|
111
|
+
dataPoint.variance=dataPoint.sumSquared/count - Math.pow(avg,2);
|
|
112
|
+
dataPoint.stdDev=Math.sqrt(dataPoint.variance);
|
|
113
|
+
dataPoint.movingVariance=dataPoint.movingSumSquared/movingTerm - Math.pow(dataPoint.movingAvg,2);
|
|
114
|
+
dataPoint.movingStdDev=Math.sqrt(dataPoint.movingVariance);
|
|
115
|
+
dataPoint.median=functions.median(values);
|
|
116
|
+
dataPoint.standardized=( (value-avg)/dataPoint.stdDev )||0;
|
|
117
|
+
dataPoint.movingStandardized=( (value-dataPoint.movingAvg)/dataPoint.movingStdDev )||0;
|
|
118
|
+
dataPoint.skewness=(dataPoint.sumCubed-3*avg*dataPoint.variance-Math.pow(avg,3))/dataPoint.variance*dataPoint.stdDev;
|
|
119
|
+
dataPoint.movingSkewness=(dataPoint.movingSumCubed-3*dataPoint.movingAvg*dataPoint.movingVariance-Math.pow(dataPoint.movingAvg,3))/dataPoint.movingVariance*dataPoint.stdDev;
|
|
120
|
+
dataPoint.outlier=node.outliersFunction(node,dataPoint,value);
|
|
121
|
+
dataPoint.weightedMovingSum+=count*value;
|
|
122
|
+
dataPoint.weightedMovingAvg=(dataPoint.weightedMovingAvg*2/count)/(count+1);
|
|
123
|
+
dataPoint.exponentialWeightedMoving.forEach(c=>c.sample(value));
|
|
118
124
|
}
|
|
119
125
|
function getColumns(node) {
|
|
120
126
|
if(node.columns) {
|
|
@@ -157,6 +163,10 @@ functions={
|
|
|
157
163
|
},
|
|
158
164
|
distancesMin: (d,term,node)=>ed.minDistances(d,getColumns(node)),
|
|
159
165
|
distancesMax: (d,term,node)=>ed.maxDistances(d,getColumns(node)),
|
|
166
|
+
difference: (d)=>d.difference(),
|
|
167
|
+
differenceSeasonal: (d,term,node)=>d.differenceSeasonal(node.lag),
|
|
168
|
+
differenceSeasonalSecondOrder: (d,term,node)=>d.differenceSeasonalSecondOrder(node.lag),
|
|
169
|
+
differenceSecondOrder: (d)=>d.differenceSecondOrder(),
|
|
160
170
|
max: (d)=> Math.max(...d),
|
|
161
171
|
median:(d)=>{
|
|
162
172
|
const i=Math.floor(d.length/2);
|
|
@@ -214,9 +224,9 @@ functions={
|
|
|
214
224
|
}
|
|
215
225
|
}
|
|
216
226
|
node.samples++;
|
|
217
|
-
for(let
|
|
218
|
-
v=d[i];
|
|
219
|
-
dp=node.dataPoints[i];
|
|
227
|
+
for(let i=0; i<node.dataProperties.length; i++) {
|
|
228
|
+
const v=d[i];
|
|
229
|
+
const dp=node.dataPoints[i];
|
|
220
230
|
dp.sum+=v;
|
|
221
231
|
dp.sumSquared+=v*v;
|
|
222
232
|
for(let j=i+1; j<node.dataProperties.length; j++) {
|
|
@@ -271,10 +281,23 @@ functions={
|
|
|
271
281
|
}
|
|
272
282
|
setDataPoint(d.value,term,node,dp);
|
|
273
283
|
if(dp.delta) {
|
|
274
|
-
|
|
284
|
+
if(dp.values.length>1)
|
|
285
|
+
setDataPoint(d.value-dp.values[dp.values.length-2],term,node,dp.delta);
|
|
275
286
|
} else {
|
|
276
287
|
dp.delta={};
|
|
277
288
|
}
|
|
289
|
+
if(node.lag>1) {
|
|
290
|
+
const vectorSize=dp.values.length
|
|
291
|
+
if(dp.lag) {
|
|
292
|
+
if(node.lag<=vectorSize){
|
|
293
|
+
setDataPoint(d.value-dp.values[vectorSize-node.lag],term,node,dp.lag)
|
|
294
|
+
const values=dp.lag.values
|
|
295
|
+
if(values.length>1) setDataPoint(values[values.length-1]-values[values.length-2],term,node,dp.lag.delta)
|
|
296
|
+
}
|
|
297
|
+
} else {
|
|
298
|
+
dp.lag={delta:{}}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
278
301
|
return dp;
|
|
279
302
|
},
|
|
280
303
|
sampleVariance:(d)=>{
|
|
@@ -301,11 +324,15 @@ module.exports = function (RED) {
|
|
|
301
324
|
function dataAnalysisNode(n) {
|
|
302
325
|
RED.nodes.createNode(this, n);
|
|
303
326
|
const node=Object.assign(this,
|
|
304
|
-
{outliersStdDevs:3,crossNormalisedDeltas:crossNormalisedDeltas.bind(this)},
|
|
327
|
+
{outliersStdDevs:3,crossNormalisedDeltas:crossNormalisedDeltas.bind(this),lag:1,term:3},
|
|
305
328
|
n,
|
|
306
329
|
{maxErrorDisplay:10,dataPoint:{}}
|
|
307
330
|
);
|
|
308
331
|
try{
|
|
332
|
+
node.lag=Number(node.lag)
|
|
333
|
+
if(Number(node.term)==NaN)throw Error("term not a number, value:"+JSON.stringify(node.term))
|
|
334
|
+
node.term=Number(node.term)
|
|
335
|
+
node.maxSize=Math.max(node.term,node.lag)
|
|
309
336
|
if(functions.hasOwnProperty(node.action)) {
|
|
310
337
|
node.actionfunction=functions[node.action];
|
|
311
338
|
} else {
|
|
@@ -313,7 +340,7 @@ module.exports = function (RED) {
|
|
|
313
340
|
}
|
|
314
341
|
switch (node.action) {
|
|
315
342
|
case "realtime":
|
|
316
|
-
|
|
343
|
+
node.outliersStdDevs=Number.parseInt(node.outliersStdDevs,10)||3;
|
|
317
344
|
if(![1,2,3].includes(node.outliersStdDevs)) throw Error("outlier std deviation "+node.outliersStdDevs+" not 1,2 or 3");
|
|
318
345
|
const outliersFunction=(node.outliersBase||"avg")=="median";
|
|
319
346
|
node.log("realtime outliersBase set avg "+outliersFunction);
|
|
@@ -340,6 +367,7 @@ module.exports = function (RED) {
|
|
|
340
367
|
node.getData=eval(node.getDatafunction);
|
|
341
368
|
node.status({fill:"green",shape:"ring",text:"Ready"});
|
|
342
369
|
} catch(ex) {
|
|
370
|
+
if(logger.active) logger.send({label:"initialise error",action:node.action,message:ex.message,stack:ex.stack});
|
|
343
371
|
logger.send({label:"initialise error",node:n});
|
|
344
372
|
node.error(ex);
|
|
345
373
|
node.status({fill:"red",shape:"ring",text:"Invalid setup "+ex.message});
|
|
@@ -379,6 +407,7 @@ module.exports = function (RED) {
|
|
|
379
407
|
throw Error("unknown");
|
|
380
408
|
}
|
|
381
409
|
} catch(ex) {
|
|
410
|
+
if(logger.active) logger.send({label:"error input",action:node.action,message:ex.message,stack:ex.stack});
|
|
382
411
|
node.error(msg.topic+" failed "+ex.message);
|
|
383
412
|
}
|
|
384
413
|
return;
|
|
@@ -395,10 +424,10 @@ module.exports = function (RED) {
|
|
|
395
424
|
break;
|
|
396
425
|
}
|
|
397
426
|
} catch(ex) {
|
|
398
|
-
if(logger.active) logger.send({label:"error input",action:node.action,message:ex.message,stack:ex.stack});
|
|
399
427
|
msg.error=ex.message;
|
|
400
428
|
if(node.maxErrorDisplay) {
|
|
401
429
|
--node.maxErrorDisplay;
|
|
430
|
+
logger.send({label:"error input",action:node.action,message:ex.message,stack:ex.stack});
|
|
402
431
|
if(node.action=="realtime") {
|
|
403
432
|
node.error(node.action+" error: "+ex.message);
|
|
404
433
|
} else {
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
function generatedMatrixFunction(arg1) {
|
|
2
|
+
if(typeof arg1 !=="object") throw Error("no definitional JSON found");
|
|
3
|
+
Object.assign(this,{
|
|
4
|
+
args:[],
|
|
5
|
+
dimensionOrder:["row","column"],
|
|
6
|
+
returnValue:"this",
|
|
7
|
+
debug:false
|
|
8
|
+
},arg1);
|
|
9
|
+
const extendedArgs=[
|
|
10
|
+
this.dimensionOrder[0]+"StartOffset=0",
|
|
11
|
+
this.dimensionOrder[0]+"EndOffset",
|
|
12
|
+
this.dimensionOrder[1]+"StartOffset=0",
|
|
13
|
+
this.dimensionOrder[1]+"EndOffset",
|
|
14
|
+
"returnValue="+this.returnValue,
|
|
15
|
+
"matrixEndOffset=matrix.length-1",
|
|
16
|
+
"rowOffset",
|
|
17
|
+
"columnOffset",
|
|
18
|
+
"rowVectorOffset",
|
|
19
|
+
"columnVectorOffset",
|
|
20
|
+
"elementOffset",
|
|
21
|
+
"element",
|
|
22
|
+
"getElementArray=()=>matrix[rowOffset][columnOffset]",
|
|
23
|
+
"getElementVector=()=>matrix[elementOffset]",
|
|
24
|
+
"setElementArray=(v)=>matrix[rowOffset][columnOffset]=v",
|
|
25
|
+
"setElementVector=(v)=>matrix[elementOffset]=v",
|
|
26
|
+
"getElement=getElementVector",
|
|
27
|
+
"setElement=setElementVector",
|
|
28
|
+
"getMatrix=()=>Object.create(Object.getPrototypeOf(matrix))",
|
|
29
|
+
"arrayFunctions={"+
|
|
30
|
+
"forEachRowColumn:(call)=>{for(rowOffset=0;rowOffset<=rowEndOffset;rowOffset++) call()},"+
|
|
31
|
+
"forEachColumnRow:(call)=>{for(columnOffset=0;columnOffset<=columnEndOffset;columnOffset++) call()}"+
|
|
32
|
+
"}",
|
|
33
|
+
"vectorFunctions={}"
|
|
34
|
+
];
|
|
35
|
+
const functionCode=
|
|
36
|
+
"("+["matrix","rows",
|
|
37
|
+
"columns"
|
|
38
|
+
].concat(this.args,extendedArgs).join()+
|
|
39
|
+
")=>{\n"+
|
|
40
|
+
" const isArray=(matrix!==null&&matrix instanceof Array)\n"+
|
|
41
|
+
" if(isArray){\n"+
|
|
42
|
+
" rows=matrix.length\n"+
|
|
43
|
+
" columns=matrix[0].length\n"+
|
|
44
|
+
" getElement=getElementArray\n"+
|
|
45
|
+
" setElement=setElementArray\n"+
|
|
46
|
+
" }\n"+
|
|
47
|
+
" if(rows<=0) throw Error('rows < 1')\n"+
|
|
48
|
+
" if(columns<=0) throw Error('rows < 1')\n"+
|
|
49
|
+
" if(rowEndOffset==null) rowEndOffset=rows-1\n"+
|
|
50
|
+
" if(columnEndOffset==null) columnEndOffset=columns-1\n"+
|
|
51
|
+
(this.debug?"console.log({matrix:matrix,matrixEndOffset:matrixEndOffset,rowEndOffset:rowEndOffset,columnEndOffset:columnEndOffset,rows:rows,columns:columns})\n":"")+
|
|
52
|
+
" if(isArray){\n"+
|
|
53
|
+
" for("+this.dimensionOrder[0]+"Offset="+this.dimensionOrder[0]+"StartOffset;"+this.dimensionOrder[0]+"Offset<="+this.dimensionOrder[0]+"EndOffset;"+this.dimensionOrder[0]+"Offset++){\n"+
|
|
54
|
+
" const "+this.dimensionOrder[0]+"=matrix["+this.dimensionOrder[0]+"Offset]\n"+
|
|
55
|
+
(this.debug?"console.log({"+this.dimensionOrder[0]+"Offset:"+this.dimensionOrder[0]+"Offset,})\n":"")+"\n"+
|
|
56
|
+
" for("+this.dimensionOrder[1]+"Offset="+this.dimensionOrder[1]+"StartOffset;"+this.dimensionOrder[1]+"Offset<="+this.dimensionOrder[1]+"EndOffset;"+this.dimensionOrder[1]+"Offset++){\n"+
|
|
57
|
+
" const element=matrix["+this.dimensionOrder[1]+"Offset]\n"+
|
|
58
|
+
(this.debug?"console.log({"+this.dimensionOrder[1]+"Offset:"+this.dimensionOrder[1]+"Offset,element:element})\n":"")+
|
|
59
|
+
this.code+"\n"+
|
|
60
|
+
" }\n"+
|
|
61
|
+
" }\n"+
|
|
62
|
+
" } else {\n"+
|
|
63
|
+
" const innerSize="+(this.dimensionOrder[0]=="row"?"columns":"1")+"\n"+
|
|
64
|
+
" const outerSize="+(this.dimensionOrder[0]=="row"?"1":"columns")+"\n"+
|
|
65
|
+
" for("+this.dimensionOrder[0]+"Offset="+this.dimensionOrder[0]+"StartOffset;"+this.dimensionOrder[0]+"Offset<="+this.dimensionOrder[0]+"EndOffset;"+this.dimensionOrder[0]+"Offset++){\n"+
|
|
66
|
+
" const "+this.dimensionOrder[0]+"VectorOffset="+this.dimensionOrder[0]+"Offset*innerSize\n"+
|
|
67
|
+
(debug?"console.log({"+this.dimensionOrder[0]+"Offset:"+this.dimensionOrder[0]+"Offset,})\n":"")+
|
|
68
|
+
" for("+this.dimensionOrder[1]+"Offset="+this.dimensionOrder[1]+"StartOffset;"+this.dimensionOrder[1]+"Offset<="+this.dimensionOrder[1]+"EndOffset;"+this.dimensionOrder[1]+"Offset++){\n"+
|
|
69
|
+
" "+this.dimensionOrder[1]+"VectorOffset="+this.dimensionOrder[1]+"Offset*outerSize\n"+
|
|
70
|
+
" elementOffset=rowVectorOffset +columnOffset\n"+
|
|
71
|
+
" element=matrix[elementOffset];\n"+
|
|
72
|
+
(debug?"console.log({"+this.dimensionOrder[1]+"Offset:"+this.dimensionOrder[1]+"Offset,rowVectorOffset:rowVectorOffset,columnVectorOffset:columnVectorOffset,elementOffset:elementOffset,element:element})\n":"")+
|
|
73
|
+
" "+this.code+"\n"+
|
|
74
|
+
" }\n"+
|
|
75
|
+
" }\n"+
|
|
76
|
+
" }\n"+
|
|
77
|
+
(this.returnValue==undefined?" return this":" return returnValue")+
|
|
78
|
+
"\n}";
|
|
79
|
+
try{
|
|
80
|
+
const evaluatedCode=eval(functionCode);
|
|
81
|
+
return evaluatedCode;
|
|
82
|
+
} catch(ex) {
|
|
83
|
+
console.error("built function: \n"+functionCode)
|
|
84
|
+
console.error("error: "+ex.message)
|
|
85
|
+
console.error(ex.stack)
|
|
86
|
+
throw Error("code failed")
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
module.exports = generatedMatrixFunction;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
function generatedVectorFunction(arg1) {
|
|
2
|
+
if(typeof arg1 !=="object") throw Error("no definitional JSON found");
|
|
3
|
+
Object.assign(this,{
|
|
4
|
+
args:[],
|
|
5
|
+
debug:false,
|
|
6
|
+
returnValue:"this"
|
|
7
|
+
},arg1);
|
|
8
|
+
const extendedArgs=["startOffset=0","endOffset=vector.length-1,returnValue="+this.returnValue]
|
|
9
|
+
const functionCode=
|
|
10
|
+
"("+["vector"].concat(this.args,extendedArgs).join()+")=>{"+
|
|
11
|
+
"for(let index=startOffset;index<=endOffset;index++){\n"+
|
|
12
|
+
this.code+";\n"+
|
|
13
|
+
"}\n"+
|
|
14
|
+
"return returnValue\n}";
|
|
15
|
+
try{
|
|
16
|
+
if(debug==true) console.log(functionCode);
|
|
17
|
+
const evaluatedCode=eval(functionCode);
|
|
18
|
+
return evaluatedCode;
|
|
19
|
+
} catch(ex) {
|
|
20
|
+
console.error("built function: "+functionCode)
|
|
21
|
+
console.error("error: "+ex.message)
|
|
22
|
+
throw Error("code failed")
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
module.exports = generatedVectorFunction;
|