pediatric-ai-scribe-v3/public/js/calculators/bp.js
2026-05-08 04:24:18 +02:00

123 lines
5.5 KiB
JavaScript

var bpCache = null;
export function loadBpReferenceData() {
if (bpCache) return Promise.resolve(bpCache);
return fetch('/data/calculators/bp-reference.json', { credentials: 'same-origin' })
.then(function(response) {
if (!response.ok) throw new Error('Failed to load BP reference data');
return response.json();
})
.then(function(data) {
bpCache = data;
return bpCache;
});
}
function normalCDF(z) {
var a1=0.254829592, a2=-0.284496736, a3=1.421413741, a4=-1.453152027, a5=1.061405429, p=0.3275911;
var sign = z < 0 ? -1 : 1;
z = Math.abs(z) / Math.sqrt(2);
var t = 1 / (1 + p * z);
var y = 1 - (((((a5*t+a4)*t)+a3)*t+a2)*t+a1)*t*Math.exp(-z*z);
return 0.5 * (1 + sign * y);
}
export function calcHeightPercentile(reference, age, sex, heightCm) {
var idx = Math.max(0, Math.min(217, Math.round(age * 12) - 24));
var table = reference.heightLms[sex === 'female' ? 'female' : 'male'];
var L = table.L[idx], M = table.M[idx], S = table.S[idx];
var z = (Math.pow(heightCm / M, L) - 1) / (L * S);
return { z: z, percentile: normalCDF(z) * 100 };
}
export function computeBPPercentile(reference, age, sex, heightCm, bpType, bpValue) {
var t1, t2, t3, t4, t5, ta1, ta2, ta3, ta4, ta5, tb1, tb2, tb3, tb4, tb5, w;
if (sex === 'female') {
t1=106.7; t2=140.7; t3=154.0; t4=160.5; t5=168.9;
ta1=5.00; ta2=10.70; ta3=13.16; ta4=14.51; ta5=17.33;
tb1=6.701; tb2=16.438; tb3=46.80; tb4=84.46; tb5=203.608;
w = (age - 10) * (heightCm - 147);
} else {
t1=107.8; t2=140.0; t3=154.5; t4=166.4; t5=179.1;
ta1=5.06; ta2=10.79; ta3=13.22; ta4=14.51; ta5=17.30;
tb1=-15; tb2=8.9; tb3=50.375; tb4=112.684; tb5=250.04;
w = (age - 10) * (heightCm - 150);
}
var x = heightCm, y = age;
var x2a = Math.max(0, x - t1); var x2b = Math.max(0, x - t4); var x2c = Math.max(0, x - t5);
var x2 = Math.pow(x2a,3) - Math.pow(x2b,3)*(t5-t1)/(t5-t4) + Math.pow(x2c,3)*(t4-t1)/(t5-t4);
var x3a = Math.max(0, x - t2);
var x3 = Math.pow(x3a,3) - Math.pow(x2b,3)*(t5-t2)/(t5-t4) + Math.pow(x2c,3)*(t4-t2)/(t5-t4);
var x4a = Math.max(0, x - t3);
var x4 = Math.pow(x4a,3) - Math.pow(x2b,3)*(t5-t3)/(t5-t4) + Math.pow(x2c,3)*(t4-t3)/(t5-t4);
var x2s = x2/100, x3s = x3/100, x4s = x4/100;
var y2a = Math.max(0, y - ta1); var y2b = Math.max(0, y - ta4); var y2c = Math.max(0, y - ta5);
var y2 = Math.pow(y2a,3) - Math.pow(y2b,3)*(ta5-ta1)/(ta5-ta4) + Math.pow(y2c,3)*(ta4-ta1)/(ta5-ta4);
var y3a = Math.max(0, y - ta2);
var y3 = Math.pow(y3a,3) - Math.pow(y2b,3)*(ta5-ta2)/(ta5-ta4) + Math.pow(y2c,3)*(ta4-ta2)/(ta5-ta4);
var y4a = Math.max(0, y - ta3);
var y4 = Math.pow(y4a,3) - Math.pow(y2b,3)*(ta5-ta3)/(ta5-ta4) + Math.pow(y2c,3)*(ta4-ta3)/(ta5-ta4);
var y2s = y2/100, y3s = y3/100, y4s = y4/100;
var w2a = Math.max(0, w - tb1); var w2b = Math.max(0, w - tb4); var w2c = Math.max(0, w - tb5);
var w2 = Math.pow(w2a,3) - Math.pow(w2b,3)*(tb5-tb1)/(tb5-tb4) + Math.pow(w2c,3)*(tb4-tb1)/(tb5-tb4);
var w3a = Math.max(0, w - tb2);
var w3 = Math.pow(w3a,3) - Math.pow(w2b,3)*(tb5-tb2)/(tb5-tb4) + Math.pow(w2c,3)*(tb4-tb2)/(tb5-tb4);
var w4a = Math.max(0, w - tb3);
var w4 = Math.pow(w4a,3) - Math.pow(w2b,3)*(tb5-tb3)/(tb5-tb4) + Math.pow(w2c,3)*(tb4-tb3)/(tb5-tb4);
var w2s = w2/10000, w3s = w3/10000, w4s = w4/10000;
var coeff = reference.coefficients[sex === 'female' ? 'female' : 'male'][bpType === 'sys' ? 'sys' : 'dia'];
var predicted = new Array(99);
for (var i = 0; i < 99; i++) {
predicted[i] = coeff[i][0] + coeff[i][5]*x + coeff[i][6]*x2s + coeff[i][7]*x3s + coeff[i][8]*x4s
+ coeff[i][1]*y + coeff[i][2]*y2s + coeff[i][3]*y3s + coeff[i][4]*y4s
+ coeff[i][9]*w + coeff[i][10]*w2s + coeff[i][11]*w3s + coeff[i][12]*w4s;
}
var minDiff = Infinity, percentile = 50;
for (var j = 0; j < 99; j++) {
var diff = Math.abs(bpValue - predicted[j]);
if (diff < minDiff) { minDiff = diff; percentile = j + 1; }
}
return { percentile: percentile, predicted: predicted };
}
export function classifyBPFromPercentiles(age, sysPctile, diaPctile, sys, dia) {
var sysClass, diaClass;
if (age >= 13) {
if (sys >= 140) sysClass = 'stage2';
else if (sys >= 130) sysClass = 'stage1';
else if (sys >= 120) sysClass = 'elevated';
else sysClass = 'normal';
if (dia >= 90) diaClass = 'stage2';
else if (dia >= 80) diaClass = 'stage1';
else diaClass = 'normal';
} else {
if (sysPctile >= 95 + 12 || sys >= 140) sysClass = 'stage2';
else if (sysPctile >= 95 || sys >= 130) sysClass = 'stage1';
else if (sysPctile >= 90 || sys >= 120) sysClass = 'elevated';
else sysClass = 'normal';
if (diaPctile >= 95 + 12 || dia >= 90) diaClass = 'stage2';
else if (diaPctile >= 95 || dia >= 80) diaClass = 'stage1';
else if (diaPctile >= 90) diaClass = 'elevated';
else diaClass = 'normal';
}
var levels = { normal: 0, elevated: 1, stage1: 2, stage2: 3 };
var overall = levels[sysClass] >= levels[diaClass] ? sysClass : diaClass;
return { sysClass: sysClass, diaClass: diaClass, classification: overall };
}
export function calculateBPAssessment(reference, age, sex, heightCm, sys, dia) {
var height = calcHeightPercentile(reference, age, sex, heightCm);
var systolic = computeBPPercentile(reference, age, sex, heightCm, 'sys', sys);
var diastolic = computeBPPercentile(reference, age, sex, heightCm, 'dia', dia);
var classification = classifyBPFromPercentiles(age, systolic.percentile, diastolic.percentile, sys, dia);
return { height: height, systolic: systolic, diastolic: diastolic, classification: classification };
}