fix: correct intensity calculations and add ISPTP input mode
Background
This MR fixes two bugs in intensity calculations and adds ISPTP as a new input mode.
Note: ISPPA is computed as the pulse-time-average intensity via Monte Carlo integration over [0, PD] with ramp shaping applied within the pulse (IEC 62359-compliant). ISPPA legitimately decreases when a pulse ramp is used.
Bug 1: Inter-train off-time not zeroed unless a ramp shape was configured
Symptom: ISPTA and average acoustic power were overestimated when a pulse train duty cycle < 100% was used without a pulse train ramp shape configured.
Why it happened: In isptaPampl() the entire body was wrapped in if (state.pulseTrainRampShape). If no train ramp was configured, the off-time zeroing never ran and the signal was treated as continuously on throughout the pulse train repetition window.
Fix: Move the off-time zeroing outside the pulseTrainRampShape guard in all three workers (pressureSignals.js, averageAcousticPowerMonteCarlo.js, dutyCycle.js). Only ramp application remains conditional.
Bug 2: In-situ ISPPA popup showed MI description
Symptom: The help popup on the in-situ ISPPA column header displayed the MI description text.
Fix: Replace the hardcoded MI string with {{ isppaMessage }} in CalculatorResults.vue.
New feature: ISPTP input mode
Added ISPTP (spatial-peak temporal-peak intensity) as a dropdown option alongside Pressure Amplitude, ISPPA, MI, and Non-derated MI.
-
Definition: ISPTP =
pampl² / (2Z)— peak instantaneous intensity, independent of pulse ramp shape -
Back-calculation: analytical (
pampl = sqrt(ISPTP × 2Z) / 10in MPa), no worker call needed -
Display:
isptpis updated fromppp_mpawhenever a worker result arrives - Unlike ISPPA, ISPTP does not decrease when a pulse ramp is applied
Implementation note: The ISPPA back-calculation in handlePamplCalculation previously called calculateISP() (Monte Carlo) on each pampl job to obtain the current ramp-inclusive ISPPA as a baseline. This is replaced by Isppa_old — the module-level variable already set at the end of every isppa job — with pampl²/(2Z) as a cold-start fallback. This avoids a redundant Monte Carlo call without loss of accuracy.
Notes for future consideration
Duty cycle and ramp consistency: The pulse-level duty cycle display uses ⟨ramp(t)⟩ (amplitude average), while ISPPA uses ⟨ramp²(t)⟩ (power average). These differ when a pulse ramp is applied, so ISPTA ≠ ISPPA × DC in that case. A future fix could remove ramp weighting from the duty cycle display (show PD/PRI only) and let ISPPA carry the ramp reduction — making the relationship consistent.
ISPPA field clarity: The displayed ISPPA is the pulse-time-average including ramp (IEC 62359). Users who expect a ramp-independent peak value should use the new ISPTP field instead.
Test plan
-
Enable pulse train mode with PTD < PTRI and no train ramp: ISPTA should correctly reflect the train duty cycle -
Set a pulse ramp, note the displayed ISPPA, switch to ISPPA input mode and re-enter that value: pressure amplitude should be unchanged -
Enter a target ISPPA, then change PRI or PTD: ppp_mpa should stay constant, ISPTA should change proportionally -
Select ISPTP input mode, enter a value: ppp_mpa should update correctly, ISPPA should be lower when a pulse ramp is applied -
Check in-situ ISPPA popup: should show ISPPA description, not MI -
Run npm test— updated expectations inpressureSignals.spec.jsshould pass