Javascript Maths Node Red Thermistor Function - javascript

have node-red running with arduino analogue output through serial to pi, where I'm collecting thermistor data as a msg payload on change.
Trying to turn the Arduino signal into a Temperature - it's the most common 10K enamelised thermistor that adafruit sell. So quite useful code.
The issue is that I am a total noob at JS.
Here's my code so far - using a function node - and trying to replicate the steinhart equation (https://learn.adafruit.com/thermistor/using-a-thermistor)
var input = { payload: msg.payload };
var R0 = 10000;
var R = R0 / ((1023 / input)-1);
var T0 = 273 + 25;
var B = 3950;
var T = 1 / ( (1/T0) + (1/B) * Math.log(R/R0) );
return T;

i am not sure whether will msg.payload will return number in an actual datatype "Number" meaning or a string that will be a numeric, but something like this should take care of any anomalies when trying to divide strings
var numInput = Number(msg.payload);
var R0 = 10000;
var R = R0 / ((1023 / input)-1);
var T0 = 273 + 25;
var B = 3950;
var T = 1 / ( (1/T0) + (1/B) * Math.log(R/R0) );
return T;
EDIT: this should fix the errors:
var numInput = Number(msg.payload);
var R0 = 10000;
var R = R0 / ((1023 / numInput)-1);
var T0 = 273 + 25;
var B = 3950;
var T = 1 / ( (1/T0) + (1/B) * Math.log(R/R0) );
msg.payload = T;
return msg;

Related

Google Sheets NORMDIST( x, mean, standard deviation, cumulative T/F) to JavaScript

Google Sheets has the NORMDIST( x, mean, standard deviation, cumulative T/F) function. I have not been able to find something equivalent in JavaScript. The examples I've found do not allow for all the variables that are in the Google function or I don't have the understanding to implement them.
I am trying to write a reiterative JavaScript function to replace a set of reiterative Google Sheets calculations and need something like this;
x = NORMDIST(x,0,1, TRUE);
y = NORMDIST(x,0,1, FALSE);
At a high-level, there's two things that the NORMDIST function can do: calculate the Normal Distribution's PDF when false is supplied as the last parameter and CDF when true is supplied.
The PDF part is easy: just follow the formula given on Wikipedia for Normal Distribution.
The CDF part is less trivial as it's a non-elementary integral. Your best shot is to find some open-source implementation and translate it into JS. (Preferably a non-iterative one.) It won't be 100% exact due to roundoff errors, but it can get you extremely close. I found one here.
Here's what I came up with:
function _getNDistPDF(x, mean, stdev)
{
const sqrt2PI = Math.SQRT2 * Math.sqrt(Math.PI);
let frac = (x - mean) / stdev;
return Math.exp(-.5 * frac * frac) / (sqrt2PI * stdev);
}
// Adapted from https://people.sc.fsu.edu/~jburkardt/c_src/asa066/alnorm.c
function _getNDistCDF(x, mean, stdev)
{
const a1 = 5.75885480458;
const a2 = 2.62433121679;
const a3 = 5.92885724438;
const b1 = -29.8213557807;
const b2 = 48.6959930692;
const c1 = -0.000000038052;
const c2 = 0.000398064794;
const c3 = -0.151679116635;
const c4 = 4.8385912808;
const c5 = 0.742380924027;
const c6 = 3.99019417011;
const con = 1.28;
const d1 = 1.00000615302;
const d2 = 1.98615381364;
const d3 = 5.29330324926;
const d4 = -15.1508972451;
const d5 = 30.789933034;
const ltone = 7.0;
const p = 0.398942280444;
const q = 0.39990348504;
const r = 0.398942280385;
const utzero = 18.66;
let up = false;
let value;
let y;
// For non-standard NDist
let z = (x - mean) / stdev;
if (z < 0)
{
up = true;
z = -z;
}
if (ltone < z && (!up || utzero < z))
{
value = !up * 1;
return value;
}
y = 0.5 * z * z;
if (z <= con)
{
value = 0.5 - z * (p - q * y
/ (y + a1 + b1
/ (y + a2 + b2
/ (y + a3))));
}
else
{
value = r * Math.exp(-y)
/ (z + c1 + d1
/ (z + c2 + d2
/ (z + c3 + d3
/ (z + c4 + d4
/ (z + c5 + d5
/ (z + c6))))));
}
if (!up)
value = 1 - value;
return value;
}
function NDistJS(x, mean, stdev, cumulative)
{
return cumulative
? _getNDistCDF(x, mean, stdev)
: _getNDistPDF(x, mean, stdev);
}
This gives you a function NDistJS that takes the exact same parameters as NORMDIST.
The PDF is 100% accurate to the Sheets formula.
The CDF is 99.9999992% accurate to the Sheets formula for (x=1, m=0, s=1).

dividing number with decimals evenly

I need some help with dividing a number(currency) by a divisor so I end up with even parts, and any cents left over needs to be divided also.
So for an example 500/9 = 55.55555555555556, that's 55.55 with 0.05 left over to be divined among the first 5 results.
I would like to end up with
55.56
55.56
55.56
55.56
55.56
55.55
55.55
55.55
55.55
This is a similar solution that i found divide number with decimals javascript
but this one adds the change to the last result.
var mathjunk = 500/9;
var formattedtotal = Math.floor(mathjunk*100)/100;
var realtotal = formattedtotal * 9;
var modulus = 500 - realtotal;
var diff = modulus / 5;
var first5 = formattedtotal+diff;
alert("first 5 get $"+first5+", everyone else gets $"+formattedtotal)
this is more of a math question than a programming one.. https://jsfiddle.net/ttz0jsgr/
take a look
function distribute(money, piles){
var m = money * 100,
n = m % piles,
v = Math.floor( m / piles ) / 100,
w = Math.floor( m / piles + 1 ) / 100;
for(var i=0, out = new Array(piles); i < piles; ++i){
out[i] = i<n? w: v;
}
return out;
}
var arr = distribute(500, 9);
var sum = arr.reduce((a,b) => a+b);

Javascript - strange math output

This is my JavaScript:
function straava() {
var input = document.getElementById('input').value
var r1 = document.getElementById('r1').value
var r2 = document.getElementById('r2').value
document.getElementById("output").innerHTML = r2 / (r1 + r2) * input;
}
Given values:
input = 5
r1 = 1000
r2 = 1000
The expected output is 2.5, but this function produces 0.0004999500049995. Why is that?
Your variables are strings. So here is what happens:
"1000" / ("1000" + "1000") * "5";
"1000" / "10001000" * "5";
// 0.0004999500049995
The + (addition) operator concatenates strings instead of adding them, hence the incorrect result.
Convert your "numbers" to Number; using parseInt / parseFloat functions, the (unary) + operator or Number function:
var input = parseInt(document.getElementById('input').value, 10);
var r1 = parseInt(document.getElementById('r1').value, 10);
var r2 = parseInt(document.getElementById('r2').value, 10);
You're not parsing the values to numbers, so it does the calculations on the strings. This happens because getting element values, through the use of .value, will return type string.
function straava() {
var input = parseInt(document.getElementById('input').value);
var r1 = parseInt(document.getElementById('r1').value);
var r2 = parseInt(document.getElementById('r2').value);
document.getElementById("output").innerHTML = r2 / (r1 + r2) * input;
}
Below is an example of the different outputs, using both strings and ints.
function straava(p1, p2, p3) {
var input = p1 //document.getElementById('input').value
var r1 = p2 //document.getElementById('r1').value
var r2 = p3 //document.getElementById('r2').value
return (r2 / (r1 + r2) * input);
}
document.getElementById('output1').innerHTML = straava('5','1000','1000');
document.getElementById('output2').innerHTML = straava(5,1000,1000);
Using strings as parameters: <span id="output1"></span><br/>
Using integers as parameters: <span id="output2"></span>

Polyline Length

I get line length by this functions.
google.maps.LatLng.prototype.kmTo = function(a){
var e = Math, ra = e.PI/180;
var b = this.lat() * ra, c = a.lat() * ra, d = b - c;
var g = this.lng() * ra - a.lng() * ra;
var f = 2 * e.asin(e.sqrt(e.pow(e.sin(d/2), 2) + e.cos(b) * e.cos
(c) * e.pow(e.sin(g/2), 2)));
return f * 6378.137;
}
google.maps.Polyline.prototype.inKm = function(n){
var a = this.getPath(n), len = a.getLength(), dist = 0;
for (var i=0; i < len-1; i++) {
dist += a.getAt(i).kmTo(a.getAt(i+1));
}
return dist;
}
And use :
alert('Line Length: '+ poly1.inKm() +'');
Everything working. But i have a small problem.
Its shows me: >> Line Length: 8.854502612255438km <<
Digits is to long i want it show me only 8.8 how can i do it?
Sorry for my english!
Try something like:
Math.floor(x * 10) / 10
Where x is the number you are trying to show (8.854502612255438).
Instead of floor (which will turn 88.5 to 88) you may want to try round (which will turn 88.5 to 89).
Edit - ah no, that won't work will it because your number is a string with 'km' at the end (did not spot that)...
so... try using parseFloat like this:
Math.floor(parseFloat(x, 10) * 10) / 10
You would have to add 'km' to the end of the string your self, so the full thing becomes:
alert('Line Length: '+ (Math.floor(parseFloat(poly1.inKm(), 10) * 10) / 10) +'km');

Cumulative distribution function in Javascript

I am searching for a way to calculate the Cumulative distribution function in Javascript. Are there classes which have implemented this? Do you have an idea to get this to work? It does not need to be 100% percent accurate but I need a good idea of the value.
http://en.wikipedia.org/wiki/Cumulative_distribution_function
I was able to write my own function with the help of Is there an easily available implementation of erf() for Python? and the knowledge from wikipedia.
The calculation is not 100% correct as it is just a approximation.
function normalcdf(mean, sigma, to)
{
var z = (to-mean)/Math.sqrt(2*sigma*sigma);
var t = 1/(1+0.3275911*Math.abs(z));
var a1 = 0.254829592;
var a2 = -0.284496736;
var a3 = 1.421413741;
var a4 = -1.453152027;
var a5 = 1.061405429;
var erf = 1-(((((a5*t + a4)*t) + a3)*t + a2)*t + a1)*t*Math.exp(-z*z);
var sign = 1;
if(z < 0)
{
sign = -1;
}
return (1/2)*(1+sign*erf);
}
normalcdf(30, 25, 1.4241); //-> 0.12651187738346226
//wolframalpha.com 0.12651200000000000
The math.js library provides an erf function. Based on a definition found at Wolfram Alpha , the cdfNormalfunction can be implemented like this in Javascript:
const mathjs = require('mathjs')
function cdfNormal (x, mean, standardDeviation) {
return (1 - mathjs.erf((mean - x ) / (Math.sqrt(2) * standardDeviation))) / 2
}
In the node.js console:
> console.log(cdfNormal(5, 30, 25))
> 0.15865525393145707 // Equal to Wolfram Alpha's result at: https://sandbox.open.wolframcloud.com/app/objects/4935c1cb-c245-4d8d-9668-4d353ad714ec#sidebar=compute
This formula will give the correct normal CDF unlike the currently accepted answer
function ncdf(x, mean, std) {
var x = (x - mean) / std
var t = 1 / (1 + .2315419 * Math.abs(x))
var d =.3989423 * Math.exp( -x * x / 2)
var prob = d * t * (.3193815 + t * ( -.3565638 + t * (1.781478 + t * (-1.821256 + t * 1.330274))))
if( x > 0 ) prob = 1 - prob
return prob
}
This answer comes from math.ucla.edu
Due to some needs in the past, i put together an implementation of distribution function in javascript. my library is available at github. You can take a look at https://github.com/chen0040/js-stats
it provides javascript implementation of CDF and inverse CDF for Normal distribution, Student's T distribution, F distribution and Chi-Square Distribution
To use the js lib for obtaining CDF and inverse CDF:
jsstats = require('js-stats');
//====================NORMAL DISTRIBUTION====================//
var mu = 0.0; // mean
var sd = 1.0; // standard deviation
var normal_distribution = new jsstats.NormalDistribution(mu, sd);
var X = 10.0; // point estimate value
var p = normal_distribution.cumulativeProbability(X); // cumulative probability
var p = 0.7; // cumulative probability
var X = normal_distribution.invCumulativeProbability(p); // point estimate value
//====================T DISTRIBUTION====================//
var df = 10; // degrees of freedom for t-distribution
var t_distribution = new jsstats.TDistribution(df);
var t_df = 10.0; // point estimate or test statistic
var p = t_distribution.cumulativeProbability(t_df); // cumulative probability
var p = 0.7;
var t_df = t_distribution.invCumulativeProbability(p); // point estimate or test statistic
//====================F DISTRIBUTION====================//
var df1 = 10; // degrees of freedom for f-distribution
var df2 = 20; // degrees of freedom for f-distribution
var f_distribution = new jsstats.FDistribution(df1, df2);
var F = 10.0; // point estimate or test statistic
var p = f_distribution.cumulativeProbability(F); // cumulative probability
//====================Chi Square DISTRIBUTION====================//
var df = 10; // degrees of freedom for cs-distribution
var cs_distribution = new jsstats.ChiSquareDistribution(df);
var X = 10.0; // point estimate or test statistic
var p = cs_distribution.cumulativeProbability(X); // cumulative probability
This is a brute force implementation, but accurate to more digits of precision. The approximation above is accurate within 10^-7. My implementation runs slower (700 nano-sec) but is accurate within 10^-14. normal(25,30,1.4241) === 0.00022322110257305683, vs wolfram's 0.000223221102572082.
It takes the power series of the standard normal pdf, i.e. the bell-curve, and then integrates the series.
I originally wrote this in C, so I concede some of the optimizations might seem silly in Javascript.
function normal(x, mu, sigma) {
return stdNormal((x-mu)/sigma);
}
function stdNormal(z) {
var j, k, kMax, m, values, total, subtotal, item, z2, z4, a, b;
// Power series is not stable at these extreme tail scenarios
if (z < -6) { return 0; }
if (z > 6) { return 1; }
m = 1; // m(k) == (2**k)/factorial(k)
b = z; // b(k) == z ** (2*k + 1)
z2 = z * z; // cache of z squared
z4 = z2 * z2; // cache of z to the 4th
values = [];
// Compute the power series in groups of two terms.
// This reduces floating point errors because the series
// alternates between positive and negative.
for (k=0; k<100; k+=2) {
a = 2*k + 1;
item = b / (a*m);
item *= (1 - (a*z2)/((a+1)*(a+2)));
values.push(item);
m *= (4*(k+1)*(k+2));
b *= z4;
}
// Add the smallest terms to the total first that
// way we minimize the floating point errors.
total = 0;
for (k=49; k>=0; k--) {
total += values[k];
}
// Multiply total by 1/sqrt(2*PI)
// Then add 0.5 so that stdNormal(0) === 0.5
return 0.5 + 0.3989422804014327 * total;
}
You can also take a look here, it's a scientific calculator implemented in javascript, it includes erf and its author claims no copyright on the implementation.

Categories