Brief process for pole placement in Matlab:
- Check that the system is actually controllable.
.
nStates = size(A,1);
R = zeros(nStates,0);
for n = 1:nStates
R(:,n) = (A^(n-1))*B;
end
if rank(R) == nStates
disp('Controllable');
else
disp('Not controllable');
end
- Find the open-loop poles. Get their natural frequencies.
.
olPoles = eig(A);
wns = sqrt(sum(abs(olPoles).^2,2));
In your case, the first pole is huge and negative, the other two are purely imaginary. I'm assuming you want to get rid of this oscillation and keep everything else the same. In any event, whatever you choose:
Pick new poles. There's a lot of guidance available online about how to pick "good" poles, so I'm not going to go into any detail here. Like I said, at least to start with, I'd just change (create) damping on the two undamped poles and iterate from there. Whatever you choose, get your closed loop poles by doing the following for each pole:
clPole = - (dampingRatio*wn) +/- 1i*wn*sqrt(1-dampingRatio);
Do this for each pole. If you don't want to change a particular pole, then just set clPole(n) = olPole(n);
.
- Setup the equations to be solved to insert your new poles.
.
syms P1 P2 P3;
syms s;
syms g1 g2 g3;
G = [g1 g2 g3];
desiredPoleEquation = (s-P1)*(s-P2)*(s-P3);
currentPoleEquation = det([s*eye(nStates) - (A - B*G)]);
[desiredCoeffs,desiredSValues] = coeffs(expand(desiredPoleEquation),s);
[currentCoeffs,currentSValues] = coeffs(expand(currentPoleEquation),s);
equationSetup = sym(zeros(nStates+1,2));
controllerGainEquations = sym(zeros(nStates+1,1));
for i = 0:nStates
desiredIndex = find(desiredSValues == s^i);
if ~isempty(desiredIndex)
equationSetup(i+1,1) = desiredCoeffs(desiredIndex);
else
equationSetup(i+1,1) = 0;
end
currentIndex = find(currentSValues == s^i);
if ~isempty(currentIndex)
equationSetup(i+1,2) = currentCoeffs(currentIndex);
else
equationSetup(i+1,2) = 0;
end
controllerGainEquations(i+1) = equationSetup(i+1,1) == equationSetup(i+1,2);
end
The end of the block of code above is controllerGainEquations
, which has a function of P1,P2,...,PN
on the left and g1,g2,...,gN
on the right.
- Solve the equation
controllerGainEquations
for [g1,g2,...,gN]
. The result here will be gains as a function of poles P1,P2,...,PN
.
.
controllerGains = sym(zeros(nStates,1));
controllerGainsStruct = solve(controllerGainEquations,[g1,g2,g3]);
controllerGains(1) = controllerGainsStruct.g1;
controllerGains(2) = controllerGainsStruct.g2;
controllerGains(3) = controllerGainsStruct.g3;
- Almost done - now plug in the values you picked for the poles.
.
controllerSolvedGains = controllerGains;
controllerSolvedGains = subs(controllerSolvedGains,P1,clPoles(1));
controllerSolvedGains = subs(controllerSolvedGains,P2,clPoles(2));
controllerSolvedGains = subs(controllerSolvedGains,P3,clPoles(3));
- Use the gains correctly. Your control signal is now $u = -G*x$, where $x$ is the vector of states. It is not whatever you originally had. You don't add anything to it. It's not anything other than $u = -G*x$.
Finally, a couple notes on the method I've given:
- I wrote this myself because this method will solve for gains with a symbolic state matrix. Pole placement is a method for linear, time-invariant (LTI) systems, so in theory you shouldn't be using a symbolic state matrix, but it's handy for scenarios where you have configurable/variable parameters and want one calculation for gains.
- The gains calculated this way aren't necessarily "robust". Matlab's
place()
command is supposed to create "better" gains.
- Protip - if you're getting huge number fractions as a result, it's because
controllerSolvedGains
is still a symbolic. Use double(controllerSolvedGains)
to get a succinct number to use.
- Finally, this just works to drive the states to zero. If you want to do reference tracking, you should look into integral control, which requires adding a state (integral error) to the system $A$ matrix. That's beyond the scope of what I wrote here.
:EDIT:
Every step I wrote is the long way to do it. If you have a non-symbolic state matrix and you have the Control System toolbox, then you can do each step as follows:
- Check that the system is actually controllable.
.
nStates = size(A,1);
olSys = ss(A,B,C,D);
R = ctrb(olSys);
if rank(R) == nStates
disp('Controllable');
else
disp('Not controllable');
end
Find the open-loop poles. Get their natural frequencies.
[wns, dampingRatios, olPoles] = damp(olSys);
Pick new poles. You have to do this on your own.
4 to 6. Setup, solve, and substitute the closed loop poles to find the gains. All of this is done in one command:
`G = place(A,B,clPoles);`
- Use the gains correctly. This is still up to you to do.