@@ -27,8 +27,10 @@ function CSMakie.pzmap(args...; kwargs...)
2727 fig = Figure ()
2828 CSMakie. pzmap! (fig, args... ; kwargs... )
2929end
30- function CSMakie. pzmap! (fig, systems:: Union{LTISystem, AbstractVector{<:LTISystem}} ;
31- hz= false , kwargs... )
30+ function CSMakie. pzmap! (fig, systems:: Union{LTISystem, AbstractVector{<:LTISystem}} ;
31+ hz= false , grid= true ,
32+ ζ = [0.1 : 0.1 : 0.6 ; 1 / sqrt (2 ); 0.82 ; 0.9 ; 0.96 ],
33+ ωn= Float64[], kwargs... )
3234 systems_vec = systems isa AbstractVector ? systems : [systems]
3335
3436 ax = Axis (fig[1 ,1 ], aspect = DataAspect (),
@@ -50,8 +52,7 @@ function CSMakie.pzmap!(fig, systems::Union{LTISystem, AbstractVector{<:LTISyste
5052 if ! isempty (z)
5153 scatter! (ax, real (z), imag (z),
5254 marker= :circle , markersize= 15 ,
53- color= (:transparent , 0.5 ), strokewidth= 2 ,
54- strokecolor= Cycled (i), label= " Zeros" )
55+ color= Cycled (i), strokewidth= 2 , label= " Zeros" )
5556 end
5657
5758 # Plot poles as x's
@@ -65,11 +66,53 @@ function CSMakie.pzmap!(fig, systems::Union{LTISystem, AbstractVector{<:LTISyste
6566 if isdiscrete (system) && i == 1 # Only draw once
6667 θ = range (0 , 2 π, length= 100 )
6768 circle_scale = scale_factor
68- lines! (ax, circle_scale .* cos .(θ), circle_scale .* sin .(θ),
69+ lines! (ax, circle_scale .* cos .(θ), circle_scale .* sin .(θ),
6970 color= :gray , linestyle= :dash , alpha= 0.5 )
7071 end
7172 end
72-
73+
74+ # Draw damping/frequency grid for continuous-time systems
75+ if grid
76+ has_continuous = any (iscontinuous, systems_vec)
77+ if has_continuous
78+ # Compute extent from all poles for scaling
79+ all_poles = vcat ([poles (s) .* scale_factor for s in systems_vec if iscontinuous (s)]. .. )
80+ if ! isempty (all_poles)
81+ max_extent = maximum (abs .(all_poles))
82+ r_max = max_extent * 1.3
83+
84+ # Auto-compute ωn values if not provided
85+ ωn_vals = isempty (ωn) ? collect (range (0 , r_max, length= 6 )[2 : end ]) : ωn .* scale_factor
86+
87+ # Draw constant ζ lines (rays from origin into left half-plane)
88+ for ζi in ζ
89+ θ_zeta = acos (clamp (ζi, 0 , 1 ))
90+ # Upper ray (positive imaginary)
91+ lines! (ax, [- r_max * cos (θ_zeta), 0 ], [r_max * sin (θ_zeta), 0 ],
92+ color= :gray , linestyle= :dash , alpha= 0.4 , linewidth= 0.5 )
93+ # Lower ray (negative imaginary)
94+ lines! (ax, [- r_max * cos (θ_zeta), 0 ], [- r_max * sin (θ_zeta), 0 ],
95+ color= :gray , linestyle= :dash , alpha= 0.4 , linewidth= 0.5 )
96+ # Label at upper ray endpoint
97+ text! (ax, - r_max * cos (θ_zeta) * 0.95 , r_max * sin (θ_zeta) * 0.95 ,
98+ text = " ζ=$(ζi ≈ 1 / sqrt (2 ) ? " 1/√2" : round (ζi, digits= 2 )) " , fontsize= 8 ,
99+ color= :gray , align= (:right , :bottom ))
100+ end
101+
102+ # Draw constant ωn semicircles (left half-plane only)
103+ θ_arc = range (π/ 2 , 3 π/ 2 , length= 50 )
104+ for ωni in ωn_vals
105+ lines! (ax, ωni .* cos .(θ_arc), ωni .* sin .(θ_arc),
106+ color= :gray , linestyle= :dot , alpha= 0.4 , linewidth= 0.5 )
107+ # Label at top of semicircle
108+ text! (ax, 0 , ωni * 1.02 ,
109+ text = " ωn=$(round (ωni, digits= 1 )) " , fontsize= 8 ,
110+ color= :gray , align= (:left , :bottom ))
111+ end
112+ end
113+ end
114+ end
115+
73116 return fig
74117end
75118
0 commit comments