33
33
34
34
def duffing_equation (y , t ):
35
35
"""Non-autonomous system"""
36
+ # y1 is displacement and y2 is velocity
36
37
y1 , y2 = y
38
+ # u is sinusoidal input
37
39
u = 2.5 * np .cos (2 * np .pi * t )
40
+ # dydt is derivative of y1 and y2
38
41
dydt = [y2 , - 0.1 * y2 + y1 - 0.25 * y1 ** 3 + u ]
39
42
return dydt
40
43
@@ -79,20 +82,26 @@ def auto_duffing_equation(y, t):
79
82
# In the phase portraits, it is shown that the system has two stable equilibria.
80
83
# We use one to generate training data and the other to generate test data.
81
84
85
+ # 10 s duration with 0.01 Hz sampling time,
86
+ # so 1000 samples in total for each measurement
82
87
dur = 10
83
88
n_samples = 1000
89
+ t = np .linspace (0 , dur , n_samples )
90
+ # External excitation is the same for each measurement
91
+ u = 2.5 * np .cos (2 * np .pi * t ).reshape (- 1 , 1 )
84
92
93
+ # Small additional white noise
85
94
rng = np .random .default_rng (12345 )
86
- e_train = rng .normal (0 , 0.0004 , n_samples )
95
+ e_train_0 = rng .normal (0 , 0.0004 , n_samples )
87
96
e_test = rng .normal (0 , 0.0004 , n_samples )
88
- t = np .linspace (0 , dur , n_samples )
89
97
98
+ # Solve differential equation to get displacement as y
99
+ # Initial condition at displacement 0.6 and velocity 0.8
90
100
sol = odeint (duffing_equation , [0.6 , 0.8 ], t )
91
- u_train = 2.5 * np .cos (2 * np .pi * t ).reshape (- 1 , 1 )
92
- y_train = sol [:, 0 ] + e_train
101
+ y_train_0 = sol [:, 0 ] + e_train_0
93
102
103
+ # Initial condition at displacement 0.6 and velocity -0.8
94
104
sol = odeint (duffing_equation , [0.6 , - 0.8 ], t )
95
- u_test = 2.5 * np .cos (2 * np .pi * t ).reshape (- 1 , 1 )
96
105
y_test = sol [:, 0 ] + e_test
97
106
98
107
# %%
@@ -111,8 +120,8 @@ def auto_duffing_equation(y, t):
111
120
max_delay = 3
112
121
113
122
narx_model = make_narx (
114
- X = u_train ,
115
- y = y_train ,
123
+ X = u ,
124
+ y = y_train_0 ,
116
125
n_terms_to_select = 5 ,
117
126
max_delay = max_delay ,
118
127
poly_degree = 3 ,
@@ -129,17 +138,19 @@ def plot_prediction(ax, t, y_true, y_pred, title):
129
138
ax .set_ylabel ("y(t)" )
130
139
131
140
132
- narx_model .fit (u_train , y_train )
133
- y_train_osa_pred = narx_model .predict (u_train , y_init = y_train [:max_delay ])
134
- y_test_osa_pred = narx_model .predict (u_test , y_init = y_test [:max_delay ])
141
+ # OSA NARX
142
+ narx_model .fit (u , y_train_0 )
143
+ y_train_0_osa_pred = narx_model .predict (u , y_init = y_train_0 [:max_delay ])
144
+ y_test_osa_pred = narx_model .predict (u , y_init = y_test [:max_delay ])
135
145
136
- narx_model .fit (u_train , y_train , coef_init = "one_step_ahead" )
137
- y_train_msa_pred = narx_model .predict (u_train , y_init = y_train [:max_delay ])
138
- y_test_msa_pred = narx_model .predict (u_test , y_init = y_test [:max_delay ])
146
+ # MSA NARX
147
+ narx_model .fit (u , y_train_0 , coef_init = "one_step_ahead" )
148
+ y_train_0_msa_pred = narx_model .predict (u , y_init = y_train_0 [:max_delay ])
149
+ y_test_msa_pred = narx_model .predict (u , y_init = y_test [:max_delay ])
139
150
140
151
fig , ax = plt .subplots (2 , 2 , figsize = (8 , 6 ))
141
- plot_prediction (ax [0 , 0 ], t , y_train , y_train_osa_pred , "OSA NARX on Train" )
142
- plot_prediction (ax [0 , 1 ], t , y_train , y_train_msa_pred , "MSA NARX on Train" )
152
+ plot_prediction (ax [0 , 0 ], t , y_train_0 , y_train_0_osa_pred , "OSA NARX on Train 0 " )
153
+ plot_prediction (ax [0 , 1 ], t , y_train_0 , y_train_0_msa_pred , "MSA NARX on Train 0 " )
143
154
plot_prediction (ax [1 , 0 ], t , y_test , y_test_osa_pred , "OSA NARX on Test" )
144
155
plot_prediction (ax [1 , 1 ], t , y_test , y_test_msa_pred , "MSA NARX on Test" )
145
156
fig .tight_layout ()
@@ -152,14 +163,21 @@ def plot_prediction(ax, t, y_true, y_pred, title):
152
163
#
153
164
# The plot above shows that the NARX model cannot capture the dynamics at
154
165
# the left equilibrium shown in the phase portraits. To improve the performance, let us
155
- # combine the training and test data for model training to include the dynamics of both
156
- # equilibria. Here, we need to insert (at least max_delay number of) `np.nan` to
157
- # indicate the model that training data
158
- # and test data are from different measurement sessions. The plot shows that the
166
+ # append another measurement session to the training data to include the dynamics of
167
+ # both equilibria. Here, we need to insert (at least max_delay number of) `np.nan` to
168
+ # indicate the model that the original training data and the appended data
169
+ # are from different measurement sessions. The plot shows that the
159
170
# prediction performance of the NARX on test data has been largely improved.
160
171
161
- u_all = np .r_ [u_train , [[np .nan ]] * max_delay , u_test ]
162
- y_all = np .r_ [y_train , [np .nan ] * max_delay , y_test ]
172
+ e_train_1 = rng .normal (0 , 0.0004 , n_samples )
173
+
174
+ # Solve differential equation to get displacement as y
175
+ # Initial condition at displacement 0.5 and velocity -1
176
+ sol = odeint (duffing_equation , [0.5 , - 1 ], t )
177
+ y_train_1 = sol [:, 0 ] + e_train_1
178
+
179
+ u_all = np .r_ [u , [[np .nan ]] * max_delay , u ]
180
+ y_all = np .r_ [y_train_0 , [np .nan ] * max_delay , y_train_1 ]
163
181
narx_model = make_narx (
164
182
X = u_all ,
165
183
y = y_all ,
@@ -170,17 +188,21 @@ def plot_prediction(ax, t, y_true, y_pred, title):
170
188
)
171
189
172
190
narx_model .fit (u_all , y_all )
173
- y_train_osa_pred = narx_model .predict (u_train , y_init = y_train [:max_delay ])
174
- y_test_osa_pred = narx_model .predict (u_test , y_init = y_test [:max_delay ])
191
+ y_train_0_osa_pred = narx_model .predict (u , y_init = y_train_0 [:max_delay ])
192
+ y_train_1_osa_pred = narx_model .predict (u , y_init = y_train_1 [:max_delay ])
193
+ y_test_osa_pred = narx_model .predict (u , y_init = y_test [:max_delay ])
175
194
176
195
narx_model .fit (u_all , y_all , coef_init = "one_step_ahead" )
177
- y_train_msa_pred = narx_model .predict (u_train , y_init = y_train [:max_delay ])
178
- y_test_msa_pred = narx_model .predict (u_test , y_init = y_test [:max_delay ])
179
-
180
- fig , ax = plt .subplots (2 , 2 , figsize = (8 , 6 ))
181
- plot_prediction (ax [0 , 0 ], t , y_train , y_train_osa_pred , "OSA NARX on Train" )
182
- plot_prediction (ax [0 , 1 ], t , y_train , y_train_msa_pred , "MSA NARX on Train" )
183
- plot_prediction (ax [1 , 0 ], t , y_test , y_test_osa_pred , "OSA NARX on Test" )
184
- plot_prediction (ax [1 , 1 ], t , y_test , y_test_msa_pred , "MSA NARX on Test" )
196
+ y_train_0_msa_pred = narx_model .predict (u , y_init = y_train_0 [:max_delay ])
197
+ y_train_1_msa_pred = narx_model .predict (u , y_init = y_train_1 [:max_delay ])
198
+ y_test_msa_pred = narx_model .predict (u , y_init = y_test [:max_delay ])
199
+
200
+ fig , ax = plt .subplots (3 , 2 , figsize = (8 , 9 ))
201
+ plot_prediction (ax [0 , 0 ], t , y_train_0 , y_train_0_osa_pred , "OSA NARX on Train 0" )
202
+ plot_prediction (ax [0 , 1 ], t , y_train_0 , y_train_0_msa_pred , "MSA NARX on Train 0" )
203
+ plot_prediction (ax [1 , 0 ], t , y_train_1 , y_train_1_osa_pred , "OSA NARX on Train 1" )
204
+ plot_prediction (ax [1 , 1 ], t , y_train_1 , y_train_1_msa_pred , "MSA NARX on Train 1" )
205
+ plot_prediction (ax [2 , 0 ], t , y_test , y_test_osa_pred , "OSA NARX on Test" )
206
+ plot_prediction (ax [2 , 1 ], t , y_test , y_test_msa_pred , "MSA NARX on Test" )
185
207
fig .tight_layout ()
186
208
plt .show ()
0 commit comments