You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/index.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -253,6 +253,12 @@ dms = diskmargin(L, 0, w)
253
253
plot(dms)
254
254
```
255
255
256
+
We can also visualize the plane of complex perturbations that are allowed to be simultaneously applied to the system:
257
+
```@example diskmargin
258
+
gainphaseplot(L)
259
+
```
260
+
The green regions are stable perturbations while red regions are unstable. The diskmargin is the largest disk that can be placed entirely inside the green area. The center of the disk is determined by the skew of the diskmargin. The classical gain margin is the length of the green area along the x-axis starting at the point 1, while the classical phase margin is the length of the green area along the unit circle starting a the point 1.
gain || phase ||error("Must plot either gain or phase")
261
262
w = [dm.ω0 for dm in dm]
262
-
layout --> (phase ?2:1, 1)
263
+
layout --> (phase + gain, 1)
263
264
link -->:x
264
265
gma =getfield.(dm, :γmax)
265
266
gmi =getfield.(dm, :γmin)
266
267
# ylims --> (0, min(10, maximum(gma)))
267
268
data = (lower ? [gmi gma] : gma)
268
269
data =max.(0, data)
269
270
replace!(data, 0=>-Inf)
270
-
@seriesbegin
271
-
subplot -->1
272
-
title -->"Gain margin"
273
-
label --> (lower ? ["Lower""Upper"] :"Upper")
274
-
# xguide --> "Frequency"
275
-
xscale -->:log10
276
-
yscale -->:log10
277
-
w, data
278
-
end
279
-
replace!(data, -Inf=>Inf)
280
-
m,i =findmin(data[:, end])
281
-
@seriesbegin
282
-
subplot -->1
283
-
primary :=true
284
-
seriestype :=:scatter
285
-
seriescolor :=:red
286
-
label :=string(round(m, sigdigits=3))
287
-
[w[i]], [m]
288
-
end
289
-
@seriesbegin
290
-
primary :=false
291
-
seriestype :=:hline
292
-
linecolor :=:black
293
-
[1]
294
-
end
295
-
phase ||return
296
-
ϕm =getfield.(dm, :ϕm)
297
-
m,i =findmin(ϕm)
298
-
@seriesbegin
299
-
subplot -->2
300
-
primary :=true
301
-
seriestype :=:scatter
302
-
seriescolor :=:red
303
-
label :=string(round(m, sigdigits=3))
304
-
[w[i]], [m]
271
+
@show gain, phase
272
+
if gain
273
+
@seriesbegin
274
+
# subplot --> 1
275
+
title -->"Gain margin"
276
+
label --> (lower ? ["Lower""Upper"] :"Upper")
277
+
# xguide --> "Frequency"
278
+
xscale -->:log10
279
+
yscale -->:log10
280
+
w, data
281
+
end
282
+
replace!(data, -Inf=>Inf)
283
+
m,i =findmin(data[:, end])
284
+
@seriesbegin
285
+
# subplot --> 1
286
+
primary :=true
287
+
seriestype :=:scatter
288
+
seriescolor :=:red
289
+
label :=string(round(m, sigdigits=3))
290
+
[w[i]], [m]
291
+
end
292
+
@seriesbegin
293
+
primary :=false
294
+
seriestype :=:hline
295
+
linecolor :=:black
296
+
[1]
297
+
end
305
298
end
306
-
@seriesbegin
307
-
subplot -->2
308
-
title -->"Phase margin (deg)"
309
-
xguide -->"Frequency"
310
-
xscale -->:log10
311
-
label -->""
312
-
w, ϕm
299
+
if phase
300
+
ϕm =getfield.(dm, :ϕm)
301
+
m,i =findmin(ϕm)
302
+
@seriesbegin
303
+
subplot --> (phase + gain)
304
+
primary :=true
305
+
seriestype :=:scatter
306
+
seriescolor :=:red
307
+
label :=string(round(m, sigdigits=3))
308
+
[w[i]], [m]
309
+
end
310
+
@seriesbegin
311
+
subplot --> (phase + gain)
312
+
title -->"Phase margin (deg)"
313
+
xguide -->"Frequency"
314
+
xscale -->:log10
315
+
label -->""
316
+
w, ϕm
317
+
end
313
318
end
314
319
end
315
320
@@ -354,6 +359,64 @@ end
354
359
end
355
360
end
356
361
362
+
@userplot GainPhasePlot
363
+
364
+
@recipefunctionf(gp::GainPhasePlot)
365
+
iflength(gp.args) ==3
366
+
P, re, im = gp.args
367
+
elseiflength(gp.args) ==1
368
+
P = gp.args[1]
369
+
re =LinRange(-1.5, 10, 300)
370
+
im =LinRange(-3, 3, 300)
371
+
else
372
+
error("gainphaseplot takes either 1 (sys) or 3 arguments (sys, re, im).")
373
+
end
374
+
375
+
res =map(Iterators.product(re,im)) do (r,i)
376
+
isstable(feedback(P*complex(r,i)))
377
+
end
378
+
colorbar -->false
379
+
aspect_ratio -->1
380
+
@seriesbegin
381
+
color --> [:red, :green]
382
+
seriesalpha -->0.5
383
+
seriestype :=:heatmap
384
+
re, im, res'
385
+
end
386
+
θ =LinRange(0, 2π, 100)
387
+
S =sin.(θ)
388
+
C =cos.(θ)
389
+
framestyle :=:zerolines
390
+
@seriesbegin
391
+
primary :=false
392
+
linestyle :=:dash
393
+
seriescolor :=:black
394
+
C, S
395
+
end
396
+
r = [0, 1.5]
397
+
c = [:red, :orange, :green]
398
+
for (i, θ) =enumerate([30, 45, 60])
399
+
points = r*cis(deg2rad(θ))
400
+
@seriesbegin
401
+
linestyle :=:dash
402
+
linewidth -->2
403
+
xguide -->"Re"
404
+
yguide -->"Im"
405
+
seriescolor --> c[i]
406
+
label -->string(θ)*"°"
407
+
real(points), imag(points)
408
+
end
409
+
end
410
+
end
411
+
412
+
"""
413
+
gainphaseplot(P)
414
+
gainphaseplot(P, re, im)
415
+
416
+
Plot complex perturbantions to the plant `P` and indicate whether or not the closed-loop system is stable. The diskmargin is the largest disk that can be fit inside the green region that only contains stable variations.
0 commit comments