Linearise Nonlinear Model Automatically
[1]:
%matplotlib notebook
from notebook_quick_setup import *
Beginning notebook setup...
Added /home/jhewers/Documents/projects/jdrones/src to path
Imported gymnasium version 0.27.1
pybullet build time: Feb 2 2023 13:13:41
/home/jhewers/.local/lib/python3.10/site-packages/scipy/__init__.py:146: UserWarning: A NumPy version >=1.16.5 and <1.23.0 is required for this version of SciPy (detected version 1.23.5
warnings.warn(f"A NumPy version >={np_minversion} and <{np_maxversion}"
Imported jdrones version unknown
Imported scipy==1.7.3, numpy==1.23.5, pandas==1.3.5
Imported functools, collections and itertools
Imported tqdm (standard and trange)
Imported seaborn==0.11.2, matplotlib==3.5.1
End of notebook setup
[2]:
env = gymnasium.make('NonLinearDynamicModelDroneEnv-v0')
[3]:
utrim = np.ones(4)*np.sqrt((env.model.mass*env.model.g)/(4*env.model.k_T))
xtrim = np.zeros(12)
[4]:
nstates = len(xtrim)
ncontrols = len(utrim)
nv = nstates + ncontrols
stepSize = 0.01
minPertSize = 0.0001
cv = np.concatenate([xtrim, utrim])
pert = np.clip(np.abs(cv) * stepSize, minPertSize, np.inf)
dvar = 2.0 * pert
var = cv
varpert = np.zeros((2 * nv, nv))
for m in range(2 * nv):
for n in range(nv):
varpert[m, n] = var[n]
if m > 1:
ind = np.floor(0.5 * m).astype(int)
if m % 2 == 1:
varpert[m, ind] = var[ind] - pert[ind]
else:
varpert[m, ind] = var[ind] + pert[ind]
# evaluate the Jacobian
f = np.empty((nstates, 2 * nv))
for j in range(2 * nv):
# Calculate the derivative corresponding to the perturbed state.
xp = varpert[j, 0:nstates].T
up = varpert[j, nstates:nv].T
xd = env.calc_dstate(up, State.from_x(xp), env.model)
xd = State(xd).to_x()
# Now the function
for i in range(nstates):
f[i, j] = xd[i]
# calculate the Jacobian using numerical differentiation
J = np.empty((nstates, nv))
for m in range(nstates):
for n in range(nv):
a = f[m, 2 * n]
b = f[m, 2 * n + 1]
c = dvar[n]
J[m, n]= (a - b) / c
sysMatrix = J[0:nstates, 0:nstates]
conMatrix = J[0:nstates, nstates:nv]
[9]:
for row in sysMatrix:
print(tuple(map(functools.partial(round, ndigits=2), row)))
(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0, 9.81, 0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0, -0.0, 0.0, -9.81, 0.0, 0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0, 0.0, -0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
[10]:
for row in conMatrix:
print(tuple(map(functools.partial(round, ndigits=2), row)))
(0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0)
(0.84, 0.84, 0.84, 0.84)
(0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0)
(0.0, 0.0, 0.0, 0.0)
(0.0, -1.17, 0.0, 1.17)
(-1.17, 0.0, 1.17, 0.0)
(5.86, -5.86, 5.86, -5.86)