1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Anuncie Aqui
    Anuncie aqui você Também: fdantas@4each.com.br

Optimizing this function to reduce dead band when reading a pressure transducer that has...

Discussão em 'Angular' iniciado por Lenny Cunningham, Julho 15, 2025.

  1. When reading a pressure transducer, I'm currently using the following code to apply the "device under test data" from the calibration report. This significantly improves any dead band across the whole scope; vs just using the entire pressure range. What I'm looking to understand is there a better way to optimize this vs a for loop with javascript? Is there a better way to determine which range segment of calibration data the output voltage is with in?

    The application is using a web worker to read the values from the transducer every 250ms, pushes them into an array with a set length, to be averaged every 1000ms and then returned to application and plotted to a graph.

    Current code to process readings (code works, just looking for input & feedback):

    /**
    * Example device under test calibration data
    * 4-20ma 0-10,000psi Transducer
    * Column 0: Voltage in volts
    * Column 1: Pressure in psi
    */
    const CALIBRATION_DATA = [
    [4.01, 0.0],
    [7.20, 2000.1],
    [10.41, 4000.0],
    [13.62, 6000.2],
    [16.81, 8000.4],
    [20.02, 9999.0],
    ];

    let activeSegmentIndex = 0;

    function getPsi(volts: number, CALIBRATION_DATA: number[][]): number {
    let lower = CALIBRATION_DATA[activeSegmentIndex];
    let upper = CALIBRATION_DATA[activeSegmentIndex + 1];

    if (!(volts >= lower[0] && volts <= upper[0])) {
    for (let i = 0; i < CALIBRATION_DATA.length - 1; i++) {
    if (volts >= CALIBRATION_DATA[0] && volts <= CALIBRATION_DATA[i + 1][0]) {
    // Found the segment for the current voltage
    activeSegmentIndex = i;
    lower = CALIBRATION_DATA;
    upper = CALIBRATION_DATA[i + 1];
    break;
    }
    }
    }


    Most common formula using entire pressure range but introduces dead band.

    • P=PR∗(Vr−VL)/(Vu−VL)
    • P = Pressure
    • PR = Pressure Range (Transducer lowestValue to HighestValue i.e 0-10k)
    • Vr = Volts reading
    • VL = Volts lower limit
    • Vu = Volts upper limit

    And for sake of entirety here is the entire WebWorker

    /// <reference lib="webworker" />

    import { DoWork, runWorker } from 'observable-webworker';
    import { fromFetch } from 'rxjs/fetch';
    import { Observable, of } from "rxjs";
    import { catchError, delay, map, repeat, scan, switchMap, tap } from "rxjs/operators";
    import { WebRelayStateModel } from '@dis/webrelay';
    import { PreferencesStateModel } from '../../pattern/state/preferences/preferences.state';


    export class WebRelayWorker implements DoWork<any, any> {
    public work(input$: Observable<PreferencesStateModel>) {
    return input$.pipe(
    switchMap(input => {
    const { webRelayIp, pollInterval, observedInput, inputs } = input;
    const webRelayState$ = getRelayState(webRelayIp, pollInterval);
    let webRelayState: WebRelayStateModel;
    return webRelayState$.pipe(
    tap(_webRelayState => webRelayState = _webRelayState),

    // Map the web relay state to the input being monitored;
    map((webRelayState: WebRelayStateModel) => Number(webRelayState[`analogInput${observedInput + 1}`])),
    // tap(console.log),

    // Calculate to psi apply offset and drop any negative numbers
    map(value => getPsi(value, inputs[observedInput].dutData)),

    // Calculate offset from zeroing data
    map(value => value - Number(inputs[observedInput].offset)),
    //tap(console.log),

    map(value => value > 0 ? value : 0),
    //tap(console.log),

    // Buffer the amount of readings that is set in preferences
    scan((acc, curr) => {
    acc.push(curr);
    if (acc.length > Number(inputs[observedInput].bufferArrayLength)) {
    acc.shift();
    }
    return acc;
    }, []),
    // tap(console.log),
    // Avervage the collected readings into current pressure;
    map(arr => Number((arr.reduce((acc, current) => acc + current, 0) / arr.length).toFixed(0))),
    // tap(console.log),
    // Return the web relay state and the calculated value
    map(value => [webRelayState, value]),
    )
    })
    )
    }
    }

    runWorker(WebRelayWorker);

    /**
    * Example device under test calibration data
    * Column 0: Voltage in volts
    * Column 1: Pressure in psi
    */
    const CALIBRATION_DATA = [
    [4.01, 0.0],
    [7.20, 2000.1],
    [10.41, 4000.0],
    [13.62, 6000.2],
    [16.81, 8000.4],
    [20.02, 9999.0],
    ];

    let activeSegmentIndex = 0;

    function getPsi(volts: number, CALIBRATION_DATA: number[][]): number {
    let lower = CALIBRATION_DATA[activeSegmentIndex];
    let upper = CALIBRATION_DATA[activeSegmentIndex + 1];

    if (!(volts >= lower[0] && volts <= upper[0])) {
    for (let i = 0; i < CALIBRATION_DATA.length - 1; i++) {
    if (volts >= CALIBRATION_DATA[0] && volts <= CALIBRATION_DATA[i + 1][0]) {
    // Found the segment for the current voltage
    activeSegmentIndex = i;
    lower = CALIBRATION_DATA;
    upper = CALIBRATION_DATA[i + 1];
    break;
    }
    }
    }

    // Calculate slope and offset for the segment
    const slope = (upper[1] - lower[1]) / (upper[0] - lower[0]);
    const offset = lower[1] - (slope * lower[0]);
    const calculatedValue = volts * slope + offset;
    return Number(calculatedValue.toFixed(0));
    }

    function getRelayState(webRelayIp: string, pollInterval: number, simulateData?: boolean) {
    const webRelayUrl = `${webRelayIp}/state.json`;
    return fromFetch(webRelayUrl)
    .pipe(
    switchMap(response => {
    if (response.ok) {
    // OK return data
    return response.json();
    } else {
    // Server is returning a status requiring the client to try something else.
    return of({ error: true, message: `Error ${response.status}` });
    }
    }),
    catchError(err => {
    // Network or other error, handle appropriately
    console.error(err);
    return of({ error: true, message: err.message })
    }),
    delay(pollInterval),
    repeat(),
    );
    }

    Continue reading...

Compartilhe esta Página