1function sampleNodeState = sample(self, node, numSamples, markActivePassive)
2% TRANNODESTATE = SAMPLE(NODE, NUMSAMPLES, MARKACTIVEPASSIVE)
3% Returns a sample path simulation trace showing state evolution at a node
5% @brief Generates a stochastic simulation sample path with phase information at a node
7% This method runs a discrete-
event stochastic simulation and records the sequence
8% of states visited at a specified station along with timing information. The sample
9% path includes detailed phase information from the service distributions, capturing
10% all internal phases experienced during service.
12% The SSA solver uses the Next Reaction Method (NRM)
for efficient stochastic
13% sampling when possible, or general serial CTMC simulation otherwise.
15% @param self SolverSSA instance
16% @param node Queue or node object (or node index as integer) to sample
17% @param numSamples (optional) Number of events to simulate (
default: solver
's samples option)
18% Use more samples for longer traces and better statistics.
19% @param markActivePassive (optional) Boolean flag to distinguish active vs passive events
20% - false (default): Mixed event list
21% - true: Separate 'active
' and 'passive
' event arrays per time
23% @return sampleNodeState Structure containing the sample path with fields:
24% - sampleNodeState.handle: Reference to the sampled node
25% - sampleNodeState.t: Vector of event times (increasing sequence)
26% - sampleNodeState.state: Matrix of states at event times
27% Shape: [num_events x (num_classes + phase_dimension)]
28% - sampleNodeState.event: Cell array of event information at each time
29% - sampleNodeState.isaggregate: Boolean false (phase-detailed sample)
30% - sampleNodeState.nodeIndex: Index of the sampled node
31% - sampleNodeState.numSamples: Number of events generated
33% @note Phase information allows detailed analysis of service behavior including
34% time spent in each phase of phase-type distributions. For simpler class-only
35% analysis, use sampleAggr() instead.
36% Supported by CTMC and SSA solvers.
38% @warning Simulation-based trace - results are stochastic and depend on random seed.
39% Set seed option in solver constructor for reproducibility:
40% solver = SolverSSA(model, 'seed
', 12345);
42% @see sampleAggr - Returns sample path aggregated over phases (simpler output)
43% @see sample_sys - Returns system-wide sample path for all stations
47% model = Network('M_M_1
');
48% % ... model setup ...
49% solver = SolverSSA(model, 'samples
', 5000, 'seed
', 54321);
50% queue1 = model.nodes{1};
52% % Generate sample path with 1000 events
53% S = solver.sample(queue1, 1000);
55% % Access and plot sample path
59% % Plot number of jobs of class 1 vs time
61% plot(times, states(:,1));
63% ylabel('Number of Jobs (Class 1)
');
64% title('Sample Path at Queue
');
66% % Mark active/passive events if needed
67% S_marked = solver.sample(queue1, 1000, true);
70if GlobalConstants.DummyMode
71 sampleNodeState = NaN;
75options = self.getOptions;
78 markActivePassive = false;
81if nargin>=3 %exist('numSamples
','var
')
82 options.samples = numSamples;
84 numSamples = options.samples;
87 case {'default
','serial
'}
88 options.method = 'serial
'; % nrm does not support tran*
89 [~, tranSystemState, tranSync] = self.runAnalyzer(options);
92 isf = sn.nodeToStateful(node.index);
93 sampleNodeState = struct();
94 sampleNodeState.handle = node;
95 sampleNodeState.t = tranSystemState{1};
96 sampleNodeState.state = tranSystemState{1+isf};
99 sampleNodeState.event = {};
100 for e = 1:length(event)
101 for a=1:length(sn.sync{event(e)}.active)
102 sampleNodeState.event{end+1} = sn.sync{event(e)}.active{a};
103 sampleNodeState.event{end}.t = sampleNodeState.t(e);
105 for p=1:length(sn.sync{event(e)}.passive)
106 sampleNodeState.event{end+1} = sn.sync{event(e)}.passive{p};
107 sampleNodeState.event{end}.t = sampleNodeState.t(e);
110 sampleNodeState.isaggregate = false;
113 line_error(mfilename,'sample
is not available in SolverSSA with the chosen method.
');
115%sampleNodeState.t = [0; sampleNodeState.t(2:end)];
118 apevent = cell(1,length(sampleNodeState.t)-1);
119 for ti = 1:length(apevent)
120 apevent{ti} = struct('active
',[],'passive
',[]);
122 for e=1:length(sampleNodeState.event)
123 ti = find(sampleNodeState.event{e}.t == sampleNodeState.t);
124 if ~isempty(ti) && ti<length(sampleNodeState.t)
125 switch sampleNodeState.event{e}.event
127 apevent{ti}.passive = sampleNodeState.event{e};
129 apevent{ti}.active = sampleNodeState.event{e};
133 sampleNodeState.event = apevent';