Files
2026-04-22 21:34:18 +02:00

116 lines
3.4 KiB
JavaScript

export class Normalizer {
constructor() {
this.settings = {
none: {},
min_max: { min: 0.0, max: 1000.0 },
z_score: {},
percentile: { low: 1.0, high: 1.0 },
};
}
process(buffer, size, mode) {
if (!buffer || size <= 0) return;
switch (mode) {
case 0: this._applyNone(buffer, size); break;
case 1: this._applyMinMax(buffer, size); break;
case 2: this._applyZScore(buffer, size); break;
case 3: this._applyPercentile(buffer, size); break;
}
}
_applyNone(buffer, size) {
let vMin = Infinity, vMax = -Infinity;
for (let i = 0; i < size; i++) {
if (buffer[i] < vMin) vMin = buffer[i];
if (buffer[i] > vMax) vMax = buffer[i];
}
const range = (vMax - vMin) + 1e-8;
for (let i = 0; i < size; i++) {
buffer[i] = (buffer[i] - vMin) / range;
}
}
_applyMinMax(buffer, size) {
const s = this.settings.min_max;
const range = (s.max - s.min) + 1e-8;
for (let i = 0; i < size; i++) {
let val = (buffer[i] - s.min) / range;
buffer[i] = Math.max(0, Math.min(1, val));
}
}
_applyZScore(buffer, size) {
let sum = 0;
for (let i = 0; i < size; i++) sum += buffer[i];
const mean = sum / size;
let sumSqDiff = 0;
for (let i = 0; i < size; i++) {
const diff = buffer[i] - mean;
sumSqDiff += diff * diff;
}
const stdDev = Math.sqrt(sumSqDiff / size);
if (stdDev < 1e-10) {
for (let i = 0; i < size; i++) buffer[i] = 0.5;
return;
}
for (let i = 0; i < size; i++) {
const z = (buffer[i] - mean) / stdDev;
let norm = (z + 3) / 6;
buffer[i] = Math.max(0, Math.min(1, norm));
}
}
_applyPercentile(buffer, size) {
const s = this.settings.percentile;
let vMin = Infinity, vMax = -Infinity;
for (let i = 0; i < size; i++) {
if (buffer[i] < vMin) vMin = buffer[i];
if (buffer[i] > vMax) vMax = buffer[i];
}
const range = vMax - vMin;
if (range < 1e-10) return;
const binCount = 1024;
const hist = new Int32Array(binCount);
for (let i = 0; i < size; i++) {
const bin = Math.floor(((buffer[i] - vMin) / range) * (binCount - 1));
hist[bin]++;
}
const lowPixelsToCut = size * (s.low / 100);
const highPixelsToCut = size * (s.high / 100);
let cutMin = vMin;
let cutMax = vMax;
let acc = 0;
for (let i = 0; i < binCount; i++) {
acc += hist[i];
if (acc >= lowPixelsToCut) {
cutMin = vMin + (i / binCount) * range;
break;
}
}
acc = 0;
for (let i = binCount - 1; i >= 0; i--) {
acc += hist[i];
if (acc >= highPixelsToCut) {
cutMax = vMin + (i / binCount) * range;
break;
}
}
const newRange = (cutMax - cutMin) + 1e-10;
for (let i = 0; i < size; i++) {
let val = (buffer[i] - cutMin) / newRange;
buffer[i] = Math.max(0, Math.min(1, val));
}
}
}