Pole Zero Maps
The Pole Zerp Map functions and classes allow users to create and animate Pole Zero Maps. The class supports both discrete-time and continuous-time systems
Static Examples
Example: Pzmap_Static_Example1
from manim import *
from controltheorylib import *
class Static_example1(Scene):
def construct(self):
# Define transfer function
pzmap = PoleZeroMap("(s+1)/((s+2)*(s**2+s+10))")
# Add title
pzmap.title(r"H(s)=\frac{s+1}{(s+2)(s^2+s+10)}", use_math_tex=True)
# Add statically to the scene
self.add(pzmap)
Example: Pzmap_Static_Example2
from manim import *
from controltheorylib import *
import sympy as sp
class Pzmap_Static_Example2(Scene):
def construct(self):
s = sp.symbols('s')
# Define transfer function, adjust ranges + increase size of markers to 0.18
pzmap = PoleZeroMap(((s-2)/((s+3)*(s-10)*(s+13)*(s**2+5*s+8))),
x_range=[-15,13,4], y_range=[-2,2,1], markers_size=0.18)
# Add stability regions, don't show unstable region,
# change label of stable region to "ROC" (Region of convergence). Increase fill opacity
pzmap.add_stability_regions(show_unstable=False,stable_label="ROC", fill_opacity=0.3)
# Add statically to the scene
self.add(pzmap)
Example: Pzmap_Static_Example3
from manim import *
from controltheorylib import *
import sympy as sp
class Pzmap_Static_Example3(Scene):
def construct(self):
s = sp.symbols('s') # define symbolic variable
system = 1/(s**2+0.2*s+1) # symbolic expression
system = ("1/(s**2+0.2*s+1)") # string
system = ([1],[1,0.2,1]) # Coefficients
# Define transfer function: use z to denote discrete-time system
pzmap = PoleZeroMap("(z**2+2*z+1)/(z**2+0.25)")
# Add title showing the system at hand
pzmap.title(r"H(z)=\frac{z^2+2z+1}{z^2+\frac{1}{4}}", use_math_tex=True,)
pzmap.add_stability_regions(unstable_label=r"\begin{cases} |z| > 1 \\ \text{unstable} \end{cases}",
use_mathtex=True, stable_label="")
# Add statically to the scene
self.add(pzmap)
Animation examples
Example: Pzmap_Animation
from manim import *
from controltheorylib import *
class Pzmap_Animation(Scene):
def construct(self):
# Define continuous-time system transfer function, turn dashed axis lines false (just straight lines)
pzmap = PoleZeroMap(("(s-1)/(s+2)"), dashed_axis=False, x_range=[-3,3,1], y_range=[-3,3,1])
pzmap.title(r"G(s)=\frac{s-1}{s+2}", use_math_tex=True, font_size=25)
# Animate all plot components individually
# Fade in the surrounding box
self.play(FadeIn(pzmap.surrbox))
self.wait(0.5) # wait 0.5 sec before animating the nex plot component
# Animate ticks and their labels
self.play(Create(pzmap.y_ticks), Create(pzmap.x_ticks), run_time=0.8)
self.wait(0.5)
self.play(Write(pzmap.y_tick_labels), Write(pzmap.x_tick_labels), run_time=0.8)
self.wait(0.5)
# Create non-dashed axis lines and their labels
self.play(Create(pzmap.y_axis), Create(pzmap.x_axis))
self.wait(0.5)
self.play(Write(pzmap.axis_labels), Write(pzmap.title_text), run_time=0.8)
self.wait(0.5)
# Animate the pole and zero markers
self.play(Create(pzmap.zeros), Create(pzmap.poles))
self.wait(2.5)
Example: Stabilityregions
from manim import *
from controltheorylib import *
config.background_color = "#3d3d3d"
class Stabilityregions(Scene):
def construct(self):
# Define continuous-time system transfer function, turn dashed axis lines false (just straight lines)
pzmap = PoleZeroMap(("(s-10)/(s*(s**2+6*s+5))"))
pzmap.title(r"G(s)=\frac{s-100}{s(s^2+6s+5)}", use_math_tex=True, font_size=25)
# Add stability regions, set add_directly to false
# Such that it does not get added when we FadeIn all the plot components,
# This way we can animate it seperatly.
pzmap.add_stability_regions()
# Instead of using pzmap, we use pzmap.basecomponents such that we can
# animate the poles and zeros later
self.play(FadeIn(pzmap.basecomponents))
self.wait(2)
# Fade in stable region
self.play(FadeIn(pzmap.stable_region), Write(pzmap.text_stable))
self.wait(1)
# Fade in unstable region
self.play(FadeIn(pzmap.unstable_region), Write(pzmap.text_unstable))
self.wait(1)
# Add poles and zeros
self.play(GrowFromCenter(pzmap.zeros), GrowFromCenter(pzmap.poles), run_time=2)
self.wait(2)
Example: Transform
from manim import *
from controltheorylib import *
config.background_color = "#3d3d3d"
class Transform(Scene):
def construct(self):
pzmap1 = PoleZeroMap(("(z-2)*(z+1)/(z**2+0.1*z+3)"), x_range=[-2,3,1], y_range=[-2,2,1])
pzmap2 = PoleZeroMap(("(z-2)*(z+1)/(z**2+0.1*z+0.25)"), x_range=[-2,3,1], y_range=[-2,2,1])
pzmap1.add_stability_regions()
pzmap1.title(r"H_1(z)=\frac{(z-2)(z+1)}{z^2+0.1z+3}", use_math_tex=True, font_size=25)
pzmap2.title(r"H_2(z)=\frac{(z-2)(z+1)}{z^2+0.1z+0.25}", use_math_tex=True, font_size=25)
# Add first pzmap statically to the scene
self.add(pzmap1)
self.wait(2)
# Transform first title into the other
#self.play(ReplacementTransform(pzmap1.title_text, pzmap2.title_text))
self.play(FadeOut(pzmap1.title_text))
self.play(FadeIn(pzmap2.title_text))
self.wait(1.5)
self.play(ReplacementTransform(pzmap1.zeros, pzmap2.zeros), ReplacementTransform(pzmap1.poles, pzmap2.poles))
self.wait(2)