Cool. That looks useful. If you start using Symbols the results get more complicated but with this change:
from sympy import symbols
from sympy.matrices import Matrix
from sympy.core.symbol import Symbol
from sympy.polys.polytools import Poly
from sympy.solvers.solvers import solve
def place(A, B, p):
K_symbols = symbols('k0:{0}'.format(A.rows))
K = Matrix([[ k for k in K_symbols]])
closed_coeffs = Matrix((A - B * K).berkowitz()[2])
desired_poly = Poly([1],Symbol('lambda'))
for pole in p:
desired_poly = desired_poly * Poly([1, -pole],Symbol('lambda'))
desired_coeffs = Matrix(desired_poly.all_coeffs())
return K.subs(solve(closed_coeffs - desired_coeffs, K_symbols))
if __name__ == "__main__":
from sympy.abc import a, b, c, d
A = Matrix([[0, 0, a], [a, 0, a], [a, 0, 0]])
B = Matrix([0, 0, a])
p = [b, c, d]
print place(A, B, p)
You get some interesting symbolic functions for the gains:
moorepants@moorepants-UL30A:Desktop$ python pole_placement.py
Matrix([[(a*(a**2 + b*c + b*d + c*d) + b*c*d)/a**3, -b*c*d/a**3, -(b + c + d)/a]])
The symbolic form, for simple systems, can be very powerful for seeing how the gains are a function of the system (A, B) and the desired poles.