1
+ % BuildingExample - Computes Secure set-based estimation
2
+ % for the three-story building structure in the following paper
3
+ % Muhammad Umar B. Niazi, Michelle S. Chong, Amr Alanwar, Karl Johansson "Secure Set-Based State Estimation for Multi-Sensor Linear Systems under Adversarial Attacks"
4
+ %
5
+ %
6
+ %
7
+ % Author: Amr Alanwar
8
+ % Written: 27-ِApril-2023
9
+ % Last update:
10
+ % Last revision:---
11
+
12
+ % ------------- BEGIN CODE --------------
13
+
14
+
15
+ clear all
16
+ close all
17
+
18
+ N= 9 ;
19
+ rng(5 )
20
+
21
+ % system parameters
22
+ M = diag([478350 478350 517790 ]);
23
+ D = 1e5 * [7.7626 - 3.7304 0.6514 ;
24
+ - 3.7304 5.8284 - 2.0266 ;
25
+ 0.6514 - 2.0266 2.4458 ];
26
+ S = 1e8 * [4.3651 - 2.3730 0.4144 ;
27
+ - 2.3730 3.1347 - 1.2892 ;
28
+ 0.4144 - 1.2892 0.9358 ];
29
+ G = [478350 478350 517790 ]' ;
30
+ H = [1 - 1 0 ; 0 1 - 1 ; 0 0 1 ];
31
+ % continuous time matrices
32
+ A_c = [zeros(3 ) eye(3 ); - M \ S - M \ D ];
33
+ B1_c = [zeros(3 ,1 ); M \ G ]; % process noise w = B1_c * n, n(t)\in\mathbb{R}
34
+ B2_c = [zeros(3 ); M \ H ]; % control input B2_c * u
35
+ % discretization
36
+ delta = 1e-3 ; % sample time
37
+ A_d = expm(A_c * delta );
38
+ B1_d = A_c \(A_d - eye(6 ))*B1_c ; % process noise w(k) = B1_d * n(k)
39
+ B2_d = A_c \(A_d - eye(6 ))*B2_c ; % control input B2_d * u(k)
40
+ % output matrices
41
+ q= 3 ;
42
+ C = cell(1 ,q );
43
+ C{1 } = [1 - 1 0 0 0 0 ; 1 0 - 1 0 0 0 ; 0 0 0 1 0 0 ];
44
+ C{2 } = [-1 1 0 0 0 0 ; 0 1 - 1 0 0 0 ; 0 0 0 0 1 0 ];
45
+ C{3 } = [-1 0 1 0 0 0 ; 0 - 1 1 0 0 0 ; 0 0 0 0 0 1 ];
46
+
47
+
48
+
49
+ Ts = 1 ;
50
+ A_true = A_d ;
51
+ B_true = B2_d ;
52
+ Z_u = zonotope( [0 ;0;0], diag([10 ,10 ,10 ]) );
53
+
54
+
55
+ % define bounds on v(k) using zonotopes
56
+ Z_v_meas = cell(1 ,q );
57
+ g_v_meas = cell(1 ,q );
58
+ g_v_meas{1 } = 1.0 ;
59
+ g_v_meas{2 } = 1.0 ;
60
+ g_v_meas{3 } = 1.0 ;
61
+ Z_v_meas{1 } = zonotope(zeros(3 ,1 ),diag([g_v_meas{1 },g_v_meas{1 },g_v_meas{1 }]));
62
+ Z_v_meas{2 } = zonotope(zeros(3 ,1 ),diag([g_v_meas{2 },g_v_meas{2 },g_v_meas{2 }]));
63
+ Z_v_meas{3 } = zonotope(zeros(3 ,1 ),diag([g_v_meas{3 },g_v_meas{3 },g_v_meas{3 }]));
64
+ c_w = 500 ;% was 0.02
65
+ Z_w = zonotope( zeros(1 ,1 ), diag(c_w * ones(1 ,1 )) );
66
+
67
+ % intialize
68
+ x = zeros(6 ,N + 1 );
69
+ t = zeros(1 ,N + 1 );
70
+ w = zeros(1 ,N );
71
+ u = zeros(3 ,N );
72
+
73
+
74
+ for idx = 1 : length(C )
75
+ C_z_v = C{idx };
76
+ [p_idx ,~ ] = size(C_z_v );
77
+ C_sizes{idx } = p_idx ;
78
+ end
79
+ SAVEMOVIE = false ;
80
+ if SAVEMOVIE
81
+ vidObj = VideoWriter(' video/SSBE.avi' );
82
+ vidObj.FrameRate= 1 ;
83
+ open(vidObj );
84
+ end
85
+
86
+
87
+ fig = figure(' Renderer' , ' painters' , ' Position' , [10 10 900 900 ]);
88
+ clf ;
89
+ bd = 25 ;
90
+ % xlim([-bd bd]);
91
+ % ylim([-bd bd]);
92
+ grid on
93
+ hold on
94
+
95
+ % Initial constrained zonotope
96
+ Z = conZonotope([1 2 2 2 6 2 8 ;1 2 2 0 5 0 6 ;1 2 2 0 5 0 6 ;1 2 2 0 5 0 6 ;1 2 2 0 5 0 6 ;1 2 2 0 5 0 6 ],[],[]);
97
+ measUpdateGrp{1 }=Z ;
98
+ Linwid = 2 ;
99
+ Blacklinwid = 3 ;
100
+ plottingDim = [1 ,2 ];
101
+ h_measSet{2 } = plotCZono(measUpdateGrp{1 },plottingDim ,' black' ,' +' ,' LineWidth' ,Linwid );
102
+ legend(' measSet1' );
103
+
104
+ indexAtt = 1 ;
105
+
106
+ upperBoundsArr = [];
107
+ lowerBoundsArr = [];
108
+ trueStateArr = [];
109
+
110
+
111
+ for k = 1 : N
112
+
113
+ %% Simulate true system
114
+ disp(" Timestep: " + t(k ) )
115
+
116
+
117
+ % randPointExtreme
118
+ u(: ,k ) = randPoint(Z_u );
119
+ u_zon = zonotope(u(: ,k ),[]);
120
+
121
+ timeUpdateGrp= {};
122
+ for j= 1 : length(measUpdateGrp )
123
+ % time update each set separately
124
+ timeUpdateGrp{j } = [A_true , B_true ]*(cartProd(measUpdateGrp{j },u_zon )) + B1_d * Z_w ;
125
+ end
126
+
127
+ % index of the attacked sensor
128
+ indexAtt = mod(indexAtt ,3 )+1 ;
129
+
130
+ w(: ,k ) = randPoint(Z_w );
131
+ x(: ,k + 1 ) = A_true * x(: ,k ) + B_true * u(: ,k ) + B1_d * w(: ,k );
132
+ for i = 1 : q
133
+ % v{i}(k) = randPoint(Z_v_meas{i});
134
+ y{i }(: ,k ) = C{i }*x(: ,k ) + randPoint(Z_v_meas{i });
135
+ if i == indexAtt
136
+ y{i }(: ,k )= y{i }(: ,k )+3 + rand ;
137
+ end
138
+ end
139
+
140
+ % obtain measurement set
141
+ for j= 1 : q
142
+ measSet{j } = measurement_zonotope(y{j }(: ,k ), C{j }, Z_v_meas{j });
143
+ end
144
+
145
+
146
+
147
+
148
+ pause(0.01 );
149
+
150
+ index= 1 ;
151
+ measUpdateGrp= {};
152
+ doneAllFlag= 0 ;
153
+
154
+
155
+
156
+ % intersect between measurement and time update sets
157
+ pairs = {[1 2 ],[1 3 ],[2 3 ]};
158
+ for ii= 1 : length(pairs )
159
+ if (isIntersecting(measSet{pairs{ii }(1 )},measSet{pairs{ii }(2 )}))
160
+ measSetpair= conZonotope(measSet{pairs{ii }(1 )})&conZonotope(measSet{pairs{ii }(2 )});
161
+ for j= 1 : length(timeUpdateGrp )
162
+ if (isIntersecting(measSetpair ,timeUpdateGrp{j }))
163
+
164
+
165
+ measUpdateGrp{index }=measSetpair & timeUpdateGrp{j };
166
+ index = index + 1 ;
167
+
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ % convert to intervals for plotting upper and lower bounds
174
+ intMeas = interval(measUpdateGrp{1 });
175
+ upperBounds = intMeas .sup ;
176
+ lowerBounds = intMeas .inf ;
177
+ for j= 2 : length(measUpdateGrp )
178
+ intMeas = interval(measUpdateGrp{j });
179
+ upperBounds = max(upperBounds ,intMeas .sup );
180
+ lowerBounds = min(lowerBounds ,intMeas .inf );
181
+ end
182
+
183
+ upperBoundsArr = [ upperBoundsArr ,upperBounds ];
184
+ lowerBoundsArr = [ lowerBoundsArr ,lowerBounds ];
185
+ trueStateArr = [trueStateArr , x(: ,k )];
186
+ clf ;
187
+
188
+
189
+ bd = 25 ;
190
+ % xlim([-bd bd]);
191
+ % ylim([-bd bd]);
192
+ grid on
193
+ hold on
194
+ box on
195
+
196
+
197
+ hpoint = plot(x(plottingDim(1 ),k ),x(plottingDim(2 ),k ),' x' ,' LineWidth' ,Blacklinwid + 1 );
198
+ for jj= 1 : 3
199
+ if jj == indexAtt
200
+ hMeasSetAttacked= plotZono(measSet{jj },plottingDim ,' red' ,' *' ,' LineWidth' ,Linwid );
201
+ else
202
+ hMeasSet= plotZono(measSet{jj },plottingDim ,' blue' ,' +' ,' LineWidth' ,Linwid );
203
+ end
204
+ end
205
+
206
+ for jj= 1 : length(timeUpdateGrp )
207
+ hTimeUpdate= plotCZono(timeUpdateGrp{jj },plottingDim ,' green' ,' +' ,' LineWidth' ,Linwid );
208
+ end
209
+ for jj= 1 : length(measUpdateGrp )
210
+ hMeasUpdate= plotCZono(measUpdateGrp{jj },plottingDim ,' black' ,' +' ,' LineWidth' ,Blacklinwid );
211
+ end
212
+
213
+
214
+
215
+ if indexAtt == 3
216
+ safeIndexStrA = ' 1' ;
217
+ safeIndexStrB = ' 2' ;
218
+ elseif indexAtt == 2
219
+ safeIndexStrA = ' 1' ;
220
+ safeIndexStrB = ' 3' ;
221
+ elseif indexAtt == 1
222
+ safeIndexStrA = ' 2' ;
223
+ safeIndexStrB = ' 3' ;
224
+ end
225
+
226
+
227
+ Yattstr = strcat(' Attacked $\mathcal{Y}_k^{\mathsf{J}_' , num2str(indexAtt ) ,' }$' );
228
+ YsafeStr = strcat(' Safe $\mathcal{Y}_k^{\mathsf{J}_' ,safeIndexStrA ,' }$' ,' $\mathcal{Y}_k^{\mathsf{J}_' ,safeIndexStrB ,' }$' );
229
+ legend([hpoint ,hMeasSet ,hMeasSetAttacked ,hTimeUpdate ,hMeasUpdate ],...
230
+ ' True state $x(k)$' ,YsafeStr ,Yattstr ,' Time update $\hat{\mathcal{X}}_{k|k-1}$' ,' Meas. update $\hat{\mathcal{X}}_{k}$' ,' Location' ,' northwest' ,' Interpreter' ,' latex' );
231
+
232
+ xlabelstr= strcat(' $x_' , num2str(plottingDim(1 )) ,' (k)$' );
233
+ xlabel(xlabelstr ,' Interpreter' ,' latex' );
234
+ ylabelstr= strcat(' $x_' , num2str(plottingDim(2 )) ,' (k)$' );
235
+ ylabel(ylabelstr ,' Interpreter' ,' latex' );
236
+ warOrig = warning ; warning(' off' ,' all' );
237
+ warning(warOrig );
238
+ ax = gca ;
239
+ ax.FontSize = 26 ;
240
+ % set(gcf, 'Position', [50, 50, 800, 400])
241
+ ax = gca ;
242
+ outerpos = ax .OuterPosition ;
243
+ ti = ax .TightInset ;
244
+ left = outerpos(1 ) + ti(1 );
245
+ bottom = outerpos(2 ) + ti(2 );
246
+ ax_width = outerpos(3 ) - ti(1 ) - ti(3 );
247
+ ax_height = outerpos(4 ) - ti(2 ) - ti(4 );
248
+ ax.Position = [left bottom ax_width ax_height ];
249
+ yticks(-4 : 2 : 4 );
250
+ xticks(-4 : 2 : 4 );
251
+ ylim([-4 4 ])
252
+ xlim([-4 4 ])
253
+ if SAVEMOVIE
254
+ for i = 1 : 5
255
+ f = getframe(fig );
256
+ writeVideo(vidObj ,f );
257
+ end
258
+ end
259
+ t(k + 1 ) = t(k ) + Ts ;
260
+
261
+ end
262
+
263
+ % plotting upper and lower bounds
264
+ for iter = 1 : 6
265
+ fig = figure(' Renderer' , ' painters' , ' Position' , [10 10 900 900 ]);
266
+ clf ;
267
+ bd = 25 ;
268
+ dims = iter ;
269
+
270
+ meanValues = (upperBoundsArr(dims ,: ) + lowerBoundsArr(dims ,: ))/2 ;
271
+
272
+ errHand = errorbar(1 : N ,meanValues ,abs(meanValues - lowerBoundsArr(dims ,: )),abs(upperBoundsArr(dims ,: )-meanValues )," LineStyle" ," none" ,' LineWidth' ,Linwid ,' Color' ,' black' );
273
+ hold on
274
+ trueHand= plot(1 : N ,trueStateArr(dims ,: ),' x' ,' LineWidth' ,Blacklinwid + 1 ,' Color' ,' blue' );
275
+
276
+ xlabel(' Time Step' )
277
+ ylabel(strcat(' $x_' ,string(dims ),' (k)$' ),' Interpreter' ,' latex' )
278
+
279
+ legend([errHand ,trueHand ],' State interval' ,' True state $x(k)$' ,' Interpreter' ,' latex' )
280
+
281
+ xlim([0 ,N + 1 ])
282
+ warOrig = warning ; warning(' off' ,' all' );
283
+ warning(warOrig );
284
+ ax = gca ;
285
+ ax.FontSize = 22 ;
286
+ % set(gcf, 'Position', [50, 50, 800, 400])
287
+ ax = gca ;
288
+ outerpos = ax .OuterPosition ;
289
+ ti = ax .TightInset ;
290
+ left = outerpos(1 ) + ti(1 );
291
+ bottom = outerpos(2 ) + ti(2 );
292
+ ax_width = outerpos(3 ) - ti(1 ) - ti(3 )-0.02 ;
293
+ ax_height = outerpos(4 ) - ti(2 ) - ti(4 );
294
+ ax.Position = [left bottom ax_width ax_height ];
295
+ xticks(0 : 1 : 11 );
296
+ ylim([-1.5 2 ])
297
+ end
298
+
299
+ if SAVEMOVIE
300
+ close(vidObj );
301
+ end
0 commit comments