@@ -80,6 +80,9 @@ def _polysqr(pol):
8080# idea for the frequency data solution copied/adapted from
8181# https://github.com/alchemyst/Skogestad-Python/blob/master/BODE.py
8282# Rene van Paassen <rene.vanpaassen@gmail.com>
83+ #
84+ # RvP, July 8, 2014, corrected to exclude phase=0 crossing for the gain
85+ # margin polynomial
8386def stability_margins (sysdata , deg = True , returnall = False , epsw = 1e-10 ):
8487 """Calculate gain, phase and stability margins and associated
8588 crossover frequencies.
@@ -147,7 +150,19 @@ def stability_margins(sysdata, deg=True, returnall=False, epsw=1e-10):
147150 # test imaginary part of tf == 0, for phase crossover/gain margins
148151 test_w_180 = np .polyadd (np .polymul (inum , rden ), np .polymul (rnum , - iden ))
149152 w_180 = np .roots (test_w_180 )
150- w_180 = np .real (w_180 [(np .imag (w_180 ) == 0 ) * (w_180 > epsw )])
153+
154+ # first remove imaginary and negative frequencies, epsw removes the
155+ # "0" frequency for type-2 systems
156+ w_180 = np .real (w_180 [(np .imag (w_180 ) == 0 ) * (w_180 >= epsw )])
157+
158+ # evaluate response at remaining frequencies, to test for phase 180 vs 0
159+ resp_w_180 = np .real (np .polyval (sys .num [0 ][0 ], 1.j * w_180 ) /
160+ np .polyval (sys .den [0 ][0 ], 1.j * w_180 ))
161+
162+ # only keep frequencies where the negative real axis is crossed
163+ w_180 = w_180 [(resp_w_180 < 0.0 )]
164+
165+ # and sort
151166 w_180 .sort ()
152167
153168 # test magnitude is 1 for gain crossover/phase margins
@@ -203,14 +218,14 @@ def dstab(w):
203218 SM = np .abs (sys .evalfr (wstab )[0 ][0 ]+ 1 )
204219
205220 if returnall :
206- return GM , PM , SM , wc , w_180 , wstab
221+ return GM , PM , SM , w_180 , wc , wstab
207222 else :
208223 return (
209224 (GM .shape [0 ] or None ) and GM [0 ],
210225 (PM .shape [0 ] or None ) and PM [0 ],
211226 (SM .shape [0 ] or None ) and SM [0 ],
212- (wc .shape [0 ] or None ) and wc [0 ],
213227 (w_180 .shape [0 ] or None ) and w_180 [0 ],
228+ (wc .shape [0 ] or None ) and wc [0 ],
214229 (wstab .shape [0 ] or None ) and wstab [0 ])
215230
216231
0 commit comments