Figure 2.3:
First element of control constraint set \mathcal {U}_3(x) (shaded) and control law \kappa _3(x) (line) versus x=(\cos (\theta ),\sin (\theta )), \theta \in [-\pi ,\pi ] on the unit circle for a nonlinear system with terminal constraint.
Code for Figure 2.3
Text of the GNU GPL.
main.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 | % Finding the feasible region and optimal solution of the (u, u^3) example.
thmin = -1.1;
thmax = 1.1;
% Need to sample with higher density for this boundary.
theta = linspace(thmin, thmax, 1001);
% Points on unit circle.
x = cos(pi()*theta);
y = sin(pi()*theta);
% Weird curvy branch for numerator = 0.
numcurves = NaN(3, length(theta));
for i = 1:length(theta)
r = roots([3, -3*x(i), -3*x(i)^2, -x(i)^3 + 4*y(i)]);
r(abs(imag(r)) > 1e-6) = NaN();
numcurves(:,i) = real(r);
end
% Nice branch where denominator = 0.
dencurve = -x;
% Need to do some magic to plot the curve properly because it's a multivalued
% function. Loop through the points, finding the next closest one at each step.
% This works because the curve is not self-intersecting and we know one of the
% endpoints. We bring the nice denominator curve along for the ride so that
% the region is easier to plot later on.
[inum, jnum] = find(~isnan(numcurves));
z = [numcurves(sub2ind(size(numcurves), inum, jnum))'; dencurve(jnum); ...
theta(jnum)];
zscale = max(z, [], 2) - min(z, [], 2);
z = bsxfun(@rdivide, z, zscale);
for i = 2:size(z, 2)
dist = [1, 0, 1]*bsxfun(@minus, z(:,i:end), z(:,i - 1)).^2;
[~, inext] = min(dist);
inext = inext + i - 1; % Correct for offset.
if inext ~= i
z(:,[i, inext]) = z(:,[inext, i]);
end
end
z = bsxfun(@times, z, zscale); % Rescale.
ufeas1 = max(z(1:2,:)); % Top piece.
ufeas2 = min(z(1:2,:)); % Bottom piece.
thfeas = z(3,:);
% Now find the minimizer. We use a coarser gridding here.
theta = linspace(thmin, thmax, 241);
urange = linspace(-2, 2, 1001);
[th, u] = meshgrid(theta, urange);
Vplus = cost(u, th, 1);
Vminus = cost(u, th, -1);
[V, firstsign] = min(cat(3, Vplus, Vminus), [], 3);
firstsign = 3 - 2*firstsign;
% Find local minima.
Vmid = V(2:end-1,:); % Slice out edges.
localmin = (Vmid < V(1:end-2,:)) & (Vmid < V(3:end,:));
localmin = [false(size(theta)); localmin; false(size(theta))]; % Add edges back.
ilocal = find(localmin(:));
Vlocal = V(ilocal);
thlocal = th(ilocal);
ulocal = u(ilocal);
% Find the absolute minima. Run fminsearch to refine a bit.
[Vmin, imin] = min(V);
umin = urange(imin);
for i = 1:length(umin)
[umin(i), Vmin(i)] = fminsearch(@(u) cost(u, theta(i), ...
firstsign(imin(i),i)), umin(i));
end
% Find lines of discontinuity.
[upieces, ujumps] = getdiscont(theta, umin, 2);
[Vpieces, Vjumps] = getdiscont(theta, Vmin, 2);
% Make a plot of u.
figure();
hold('on');
ufill = [ufeas1, ufeas2(end:-1:1)];
thfill = [thfeas, thfeas(end:-1:1)];
fill(thfill, ufill, 'r', 'edgecolor', 'r');
plot(thlocal, ulocal, 'sb', upieces(:,1), upieces(:,2), '-g', ...
ujumps(:,1), ujumps(:,2), ':g');
legend('Infeasible', 'Local Optima', 'Global Optima');
xlabel('\theta/\pi');
ylabel('Input');
% Make a plot of V.
figure();
hold('on');
semilogy(thlocal, Vlocal, 'sr', Vpieces(:,1), Vpieces(:,2), '-g', ...
Vjumps(:,1), Vjumps(:,2), ':g');
xlabel('\theta/\pi');
ylabel('Cost');
% Now save data.
feas = [thfeas', ufeas1', ufeas2'];
save('circle.dat', 'upieces', 'ujumps', 'Vpieces', 'Vjumps', 'feas');
|
cost.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 | function V = cost(u, th, firstsign)
% Computes optimal cost with inf if infeasible.
narginchk(3, 3);
x = cos(pi()*th);
y = sin(pi()*th);
% Calculate b.
bnum = 3*u.^3 - 3*x.*u.^2 - 3*x.^2.*u - x.^3 + 4*y;
bden = 12*(u + x);
b = bnum./bden;
% Simulate the system.
useq = {u, -x/2 - u/2 + firstsign*sqrt(b), -x/2 - u/2 - firstsign*sqrt(b)};
V = 0;
for i = 1:4
V = V + x.^2 + y.^2;
if i == 4
break
end
V = V + useq{i}.^2;
x = x + useq{i};
y = y + useq{i}.^3;
end
V = real(V);
V(b < 0) = inf(); % These points are infeasible.
|
getdiscont.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 | function [pieces, jumps] = getdiscont(x, y, N)
% Finds discontinuities in y and adds in NaNs to make a gap.
dy = abs(diff(y));
idiscont = find(dy > mean(dy) + N*std(dy));
% Interpolate x and y, screening out any large jumps.
expand = @(z) [z; z(1:end-1) + 0.5*diff(z), NaN()];
x = expand(x);
xdc1 = x(1,idiscont);
xdc2 = x(1,idiscont + 1);
x(2,idiscont) = NaN();
y = expand(y);
ydc1 = y(1,idiscont);
ydc2 = y(1,idiscont + 1);
y(2,idiscont) = NaN();
% Assemble discontinuities for plotting.
xdc = [xdc1; xdc2; NaN(size(xdc2))];
ydc = [ydc1; ydc2; NaN(size(ydc2))];
% Package everybody up.
pieces = [x(:), y(:)];
jumps = [xdc(:), ydc(:)];
|