-
Notifications
You must be signed in to change notification settings - Fork 2
/
DataLeech.m
139 lines (116 loc) · 5.2 KB
/
DataLeech.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
%--------------------------------------------------------------------------------------------------
% Copyright (c) Institute of Control Systems, Hamburg University of Technology.All rights reserved.
% Licensed under the GPLv3. See LICENSE in the project root for license information.
% Author(s): Christian Hespe
%--------------------------------------------------------------------------------------------------
classdef DataLeech < handle
%DATALEECH Class that helps with repeatedly sampling data.
% This class can be used to sample data from a collection of agents
% at each sampling time. This is required, as the agents only save
% the data of the current timestep, not their historic position and
% velocities.
properties(GetAccess = public, SetAccess = private)
data % Data that was saved from the agents
t % List of time instances, at whcih the sampling occured
end
properties(GetAccess = public, SetAccess = immutable)
targets % Target properties of the host
steps % Number of timesteps that can be saved by this instance
end
properties(GetAccess = private, SetAccess = private)
k % Internal counter for the number of saved datapoints
end
properties(GetAccess = private, SetAccess = immutable)
host % Object that the data gets saved from
end
methods
function obj = DataLeech(host, steps, varargin)
%DATALEECH Construct an instance of this class
% The host is the object that the data should be saved from,
% steps is the number of timesteps that can be saved and
% after those two, you need to provide a list of properties
% to save.
if nargin <= 2
error('You need to name at least one target property')
end
obj.k = 1;
obj.t = zeros(steps, 1);
obj.host = host;
obj.steps = steps;
obj.targets = {};
obj.data = struct;
% Assemble a list of public properties that the host has
clazz = metaclass(host);
pubmask = strcmp({clazz.PropertyList.GetAccess}, 'public');
pubprobs = {clazz.PropertyList(pubmask).Name};
% Build a datastorage from the provided list of properties
for field = varargin
name = field{:};
if any(strcmp(pubprobs, name))
obj.targets = [obj.targets, field];
else
warning("The host does not have a property called '%s'. This variable will be ignored.", name)
end
end
end
function save(obj, t)
%SAVE Saves one set of data from the host
if obj.k > obj.steps
error('The target number of steps was exceeded')
end
% Initialize all variables
if obj.k == 1
for field = obj.targets
name = field{:};
val = [obj.host.(name)];
obj.data.(name) = zeros([obj.steps, size(val)]);
end
end
% Save data for each desired property
for field = obj.targets
name = field{:};
val = [obj.host.(name)];
obj.data.(name)(obj.k,:) = val(:);
end
% Update time instance
obj.t(obj.k) = t;
obj.k = obj.k + 1;
end
function [t, data] = get(obj)
%GET Export saved data
t = obj.t;
data = obj.data;
end
function [t, sampled] = resample(obj, dT, method)
%RESAMPLE Resamples the saved data onto a time grid with
%constant stepsize dT.
% Depending on the simulation, the number of timesteps can be
% very large and the difference between two timesteps can be
% non uniform. In these cases, it is benifical to resample
% the data onto a uniform grid.
if nargin <= 2
method = 'zoh';
end
% Build timeseries object for each property
tsin = tscollection(obj.t);
for field = obj.targets
name = field{:};
list = obj.data.(name);
list = permute(list, [2:length(size(list)), 1]);
ts = timeseries(list, obj.t, 'Name', name);
tsin = addts(tsin, ts);
end
% Resample with zero order hold behaviour onto uniform grid
tsout = resample(tsin, 0:dT:max(obj.t), method);
% Export resampled data as a structure
t = tsout.Time;
sampled = struct;
for field = obj.targets
name = field{:};
val = tsout.(name).Data;
dims = length(size(val));
sampled.(name) = permute(val, [dims, 1:(dims-1)]);
end
end
end
end