Closed-form average count-rate time per IBSI-SUV recommendation (suv_text.txt:820-826): T_ave = (1/lambda) * ln((lambda * T) / (1 - exp(-lambda * T))) with lambda = ln(2) / T_half and T = ActualFrameDuration. Physically: a non-decay-corrected voxel value is the count rate averaged over the frame; T_ave is the time inside the frame at which the *instantaneous* count rate equals that average. As
| 250 | // We use std::expm1(-lambda*T) instead of (1 - exp(-lambda*T)) for |
| 251 | // numerical stability when lambda*T is small. |
| 252 | double ComputeTAveSeconds(double frameDurationSeconds, double halfLifeSeconds) |
| 253 | { |
| 254 | if (frameDurationSeconds <= 0.0 || halfLifeSeconds <= 0.0 |
| 255 | || !std::isfinite(frameDurationSeconds) || !std::isfinite(halfLifeSeconds)) |
| 256 | { |
| 257 | mitkThrowException(mitk::InvalidDICOMPropertyValueException) |
| 258 | << "ComputeTAveSeconds requires positive, finite frame duration and " |
| 259 | "half-life (got T=" << frameDurationSeconds |
| 260 | << " s, T_half=" << halfLifeSeconds << " s)."; |
| 261 | } |
| 262 | const double lambda = std::log(2.0) / halfLifeSeconds; |
| 263 | const double lambdaT = lambda * frameDurationSeconds; |
| 264 | // (1 - exp(-lambdaT)) computed stably as -expm1(-lambdaT). |
| 265 | const double denom = -std::expm1(-lambdaT); |
| 266 | return (1.0 / lambda) * std::log(lambdaT / denom); |
| 267 | } |
| 268 | } |
| 269 | |
| 270 |
no outgoing calls
no test coverage detected