1function [PercRT, PercTable] = getPerctRespT(self, percentiles,
jobclass)
2% [PERCRT, PERCTABLE] = GETPERCTRESPT(SELF, PERCENTILES, JOBCLASS)
3% Extract response time percentiles from CDF or solver-specific results
6% self - NetworkSolver instance
7% percentiles - Array of percentile values (e.g., [0.90, 0.95, 0.99] or [90, 95, 99])
8%
jobclass - (optional) specific job
class to retrieve percentiles
for
11% PercRT - Struct array with fields for each class:
13% .percentiles - percentile levels (as percentages)
14% .values - percentile values (response times)
15% .method - extraction method (
'cdf' or solver-specific)
16% PercTable - Formatted table for display
18% This method provides a generic interface for extracting response time
19% percentiles. Solvers that compute CDFs via getCdfRespT can use this
20% method to extract percentile values. Solvers may override this method
21% to provide more efficient or accurate percentile computation.
23% Copyright (c) 2012-2026, Imperial College London
26% Normalize percentiles to [0, 1] range
27if any(percentiles > 1)
28 percentiles = percentiles / 100;
33% Determine which
classes to
return
41 classIdx = find(strcmp(sn.classnames,
jobclass));
43 line_error(mfilename,
'Job class "%s" not found in model.',
jobclass);
47 % Class index provided
52% Try to get CDF
for percentile extraction
54 RD = self.getCdfRespT();
56 line_error(mfilename, [
'Unable to compute percentiles. getCdfRespT not available for this solver.\n', ...
57 'Error: %s'], ME.message);
60% Build PercRT
struct array by extracting from CDF
66 % CDF structure may vary by solver,
try common patterns
69 % Pattern 1:
RD is a
struct with .C field (common in CTMC, Fluid, MAM)
70 if isfield(
RD, 'C') && r <= length(
RD.C)
72 % Pattern 2:
RD is a
struct with .CDF field
73 elseif isfield(
RD, 'CDF') && r <= length(
RD.CDF)
75 % Pattern 3:
RD is a cell array
76 elseif iscell(
RD) && r <= length(
RD)
81 line_warning(mfilename,
'No CDF data available for class %d.', r);
85 % Extract time and probability arrays from CDF structure
87 if isfield(cdfData,
't') && isfield(cdfData,
'p')
90 elseif isfield(cdfData, 'x') && isfield(cdfData, 'f')
92 probs = cumsum(cdfData.f(:)); % Convert PDF to CDF
94 line_warning(mfilename, 'Unrecognized CDF structure for class %d.', r);
97 elseif size(cdfData, 2) >= 2
98 % Matrix format: [time, prob]
99 times = cdfData(:, 1);
100 probs = cdfData(:, 2);
102 line_warning(mfilename, 'Unable to parse CDF data for class %d.', r);
106 % Ensure CDF
is monotonic and normalized
107 [probs, sortIdx] = sort(probs);
108 times = times(sortIdx);
111 [probs, uniqueIdx] = unique(probs);
112 times = times(uniqueIdx);
114 % Interpolate to find response times at requested percentiles
115 if length(times) > 1 && length(probs) > 1
116 percValues = interp1(probs, times, percentiles, 'linear', 'extrap');
118 % Ensure non-negative response times
119 percValues = max(percValues, 0);
121 PercRT(idx).class = sn.classnames{r};
122 PercRT(idx).percentiles = percentiles; % Keep in fractional form [0,1]
123 PercRT(idx).values = percValues;
124 PercRT(idx).method =
'cdf';
126 line_warning(mfilename,
'Insufficient CDF data points for class %d.', r);
130% Build PercTable
for display
136 for idx = 1:length(PercRT)
137 nPercentiles = length(PercRT(idx).percentiles);
138 for p = 1:nPercentiles
139 JobClass{end+1,1} = PercRT(idx).class;
140 Percentile(end+1,1) = PercRT(idx).percentiles(p);
141 ResponseTime(end+1,1) = PercRT(idx).values(p);
145 JobClass = label(JobClass);
146 PercTable = Table(JobClass, Percentile, ResponseTime);