2%% Example: UBO sliding-window change-point detection (open network)
4% Service demand changes from D=0.3 to D=0.6 at t=100.
5% A sliding window of size W
is used to estimate demands online.
7% Copyright (c) 2012-2026, Imperial College London
11model = Network(
'model');
13node{1} = Delay(model,
'Delay');
14node{2} = Queue(model,
'Queue1', SchedStrategy.FCFS);
15node{3} = Source(model,
'Source');
16node{4} = Sink(model,
'Sink');
18jobclass{1} = OpenClass(model,
'Class1', 0);
19jobclass{2} = OpenClass(model,
'Class2', 0);
21node{1}.setService(
jobclass{1}, Exp.fitMean(1.0));
22node{1}.setService(
jobclass{2}, Exp.fitMean(1.0));
23node{2}.setService(
jobclass{1}, Exp(NaN));
24node{2}.setService(
jobclass{2}, Exp(NaN));
25node{3}.setArrival(
jobclass{1}, Exp(1.0));
26node{3}.setArrival(
jobclass{2}, Exp(0.5));
28P = model.initRoutingMatrix;
29P{1,1} = [0,1,0,0; 0,0,0,1; 1,0,0,0; 0,0,0,0];
30P{2,2} = [0,1,0,0; 0,0,0,1; 1,0,0,0; 0,0,0,0];
33%% Generate data with change point
34% Class 1 demand changes: D1=0.1 -> 0.3
35% Class 2 demand stays: D2=0.2
38D1_before = 0.1; D1_after = 0.3;
40lambda1 = 1.0; lambda2 = 0.5;
44arvr1_samples = lambda1*ones(n,1) + randn(n,1)*noise;
45arvr2_samples = lambda2*ones(n,1) + randn(n,1)*noise;
47util_samples = zeros(n,1);
48respt1_samples = zeros(n,1);
49respt2_samples = zeros(n,1);
56 U = lambda1*d1 + lambda2*D2 + randn(1)*noise;
57 U = max(0.01, min(0.95, U));
59 respt1_samples(t) = d1 / (1 - U) + randn(1)*noise*0.1;
60 respt2_samples(t) = D2 / (1 - U) + randn(1)*noise*0.1;
63%% Sliding-window estimation
65est1 = zeros(n - W + 1, 1);
66est2 = zeros(n - W + 1, 1);
71 node{2}.setService(jobclass{1}, Exp(NaN));
72 node{2}.setService(jobclass{2}, Exp(NaN));
75 estoptions = ParamEstimator.defaultOptions;
76 estoptions.method = 'ubo
';
77 se = ParamEstimator(model, estoptions);
79 se.addSamples(SampledMetric(MetricType.ArvR, ts(idx), arvr1_samples(idx), node{2}, jobclass{1}));
80 se.addSamples(SampledMetric(MetricType.ArvR, ts(idx), arvr2_samples(idx), node{2}, jobclass{2}));
81 se.addSamples(SampledMetric(MetricType.RespT, ts(idx), respt1_samples(idx), node{2}, jobclass{1}));
82 se.addSamples(SampledMetric(MetricType.RespT, ts(idx), respt2_samples(idx), node{2}, jobclass{2}));
83 se.addSamples(SampledMetric(MetricType.Util, ts(idx), util_samples(idx), node{2}));
85 estVal = se.estimateAt(node{2});
86 est1(t - W + 1) = estVal(1);
87 est2(t - W + 1) = estVal(2);
91fprintf(1, '\n=== UBO Change-Point Detection (2-
class) ===\n
');
92fprintf(1, 'Class 1: D=%.1f (t<=100), D=%.1f (t>100)\n
', D1_before, D1_after);
93fprintf(1, 'Class 2: D=%.1f (constant)\n
', D2);
94fprintf(1, 'Window size: %d\n\n
', W);
96checkpoints = [W, 50, 80, 100, 110, 120, 130, 150, 180, 200];
97fprintf(1, '%6s %8s %8s %8s %8s\n
', 't
', 'Est D1
', 'True D1
', 'Est D2
', 'True D2
');
98fprintf(1, '%6s %8s %8s %8s %8s\n
', '------
', '--------
', '--------
', '--------
', '--------
');
99for i = 1:length(checkpoints)
102 e1 = est1(t - W + 1);
103 e2 = est2(t - W + 1);
109 fprintf(1, '%6d %8.4f %8.4f %8.4f %8.4f\n
', t, e1, trueD1, e2, D2);
117plot(tAxis, est1,
'b-',
'LineWidth', 1.5); hold on;
118yline(D1_before,
'r--',
'LineWidth', 1);
119yline(D1_after,
'r--',
'LineWidth', 1);
120xline(changeT,
'k:',
'Change point',
'LineWidth', 1);
121ylabel(
'Demand'); title(
'Class 1 (changes D=0.1 -> D=0.3)');
125plot(tAxis, est2,
'b-',
'LineWidth', 1.5); hold on;
126yline(D2,
'r--',
'LineWidth', 1);
127xline(changeT,
'k:',
'Change point',
'LineWidth', 1);
128xlabel(
'Time'); ylabel(
'Demand'); title(
'Class 2 (constant D=0.2)');