Skip to content

Commit 38f6c80

Browse files
committed
added method horner, for evaluating s-response, and added a feedback on
selected point, gain, damping in rlocus plot
1 parent 72e2844 commit 38f6c80

5 files changed

Lines changed: 42 additions & 10 deletions

File tree

src/bdalg.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,9 @@ def append(*sys):
244244
Group models by appending their inputs and outputs
245245
246246
Forms an augmented system model, and appends the inputs and
247-
outputs together. The system type will be the type of the first system
248-
given.
247+
outputs together. The system type will be the type of the first
248+
system given; if you mix state-space systems and gain matrices,
249+
make sure the gain matrices are not first.
249250
250251
Parameters.
251252
-----------

src/matlab.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,13 +1204,13 @@ def damp(sys, doprint=True):
12041204
'''
12051205
wn, damping, poles = sys.damp()
12061206
if doprint:
1207-
print('______Eigenvalue______ Damping___ Frequency_')
1207+
print('_____Eigenvalue______ Damping___ Frequency_')
12081208
for p, d, w in zip(poles, damping, wn) :
12091209
if abs(p.imag) < 1e-12:
1210-
print("%10.4g %10.4g %10.4g" %
1210+
print("%10.4g %10.4g %10.4g" %
12111211
(p.real, 1.0, -p.real))
12121212
else:
1213-
print("%10.4g %10.4gi %10.4g %10.4g" %
1213+
print("%10.4g%+10.4gj %10.4g %10.4g" %
12141214
(p.real, p.imag, d, w))
12151215
return wn, damping, poles
12161216

src/rlocus.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@
5050
import scipy.signal # signal processing toolbox
5151
import pylab # plotting routines
5252
import control.xferfcn as xferfcn
53+
from functools import partial
5354

5455
# Main function: compute a root locus diagram
55-
def root_locus(sys, kvect, xlim=None, ylim=None, plotstr='-', Plot=True):
56+
def root_locus(sys, kvect, xlim=None, ylim=None, plotstr='-', Plot=True,
57+
PrintGain=True):
5658
"""Calculate the root locus by finding the roots of 1+k*TF(s)
5759
where TF is self.num(s)/self.den(s) and each k is an element
5860
of kvect.
@@ -65,7 +67,9 @@ def root_locus(sys, kvect, xlim=None, ylim=None, plotstr='-', Plot=True):
6567
List of gains to use in computing diagram
6668
Plot : boolean (default = True)
6769
If True, plot magnitude and phase
68-
70+
PrintGain: boolean (default = True)
71+
If True, report mouse clicks when close to the root-locus branches,
72+
calculate gain, damping and print
6973
Return values
7074
-------------
7175
rlist : list of computed root locations
@@ -80,6 +84,10 @@ def root_locus(sys, kvect, xlim=None, ylim=None, plotstr='-', Plot=True):
8084

8185
# Create the plot
8286
if (Plot):
87+
f = pylab.figure()
88+
if PrintGain:
89+
cid = f.canvas.mpl_connect(
90+
'button_release_event', partial(_RLFeedbackClicks, sys=sys))
8391
ax = pylab.axes();
8492

8593
# plot open loop poles
@@ -165,3 +173,12 @@ def _RLSortRoots(sys, mymat):
165173
sorted[n,ind] = elem
166174
prevrow = sorted[n,:]
167175
return sorted
176+
177+
def _RLFeedbackClicks(event, sys):
178+
"""Print root-locus gain feedback for clicks on the root-locus plot
179+
"""
180+
s = complex(event.xdata, event.ydata)
181+
K = -1./sys.horner(s)
182+
if abs(K.real) > 1e-8 and abs(K.imag/K.real) < 0.04:
183+
print("Clicked at %10.4g%+10.4gj gain %10.4g damp %10.4g" %
184+
(s.real, s.imag, K.real, -1*s.real/abs(s)))

src/statesp.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,10 +384,16 @@ def evalfr(self, omega):
384384
else:
385385
s = omega * 1.j
386386

387-
fresp = self.C * solve(s * eye(self.states) - self.A,
388-
self.B) + self.D
387+
return self.horner(s)
389388

390-
return array(fresp)
389+
def horner(self, s):
390+
'''Evaluate the systems's transfer function for a complex variable
391+
392+
Returns a matrix of values evaluated at complex variable s.
393+
'''
394+
resp = self.C * solve(s * eye(self.states) - self.A,
395+
self.B) + self.D
396+
return array(resp)
391397

392398
# Method for generating the frequency response of the system
393399
# TODO: add discrete time check

src/xferfcn.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,14 @@ def evalfr(self, omega):
527527
warn("evalfr: frequency evaluation above Nyquist frequency")
528528
else:
529529
s = 1.j * omega
530+
531+
return self.horner(s)
532+
533+
def horner(self, s):
534+
'''Evaluate the systems's transfer function for a complex variable
535+
536+
Returns a matrix of values evaluated at complex variable s.
537+
'''
530538

531539
# Preallocate the output.
532540
out = empty((self.outputs, self.inputs), dtype=complex)

0 commit comments

Comments
 (0)