5. Visualising complex functions

5.1. One-dimensional functions

Consider a “normal” plot of \(\sin(t)\):

[1]:
import sympy
sympy.init_printing()

%matplotlib inline
[2]:
t = sympy.Symbol('t')
[3]:
sympy.plot(sympy.sin(t))
../../_images/1_Dynamics_3_Linear_systems_Visualising_complex_functions_5_0.png
[3]:
<sympy.plotting.plot.Plot at 0x10f372470>

This allows us to see exactly what the of \(\sin(t)\) is for every value of \(t\). To do this, we need two dimensions: one for the value of \(t\) and one for \(\sin(t)\).

If we want to plot a function of two variables we start needing three dimensions. The following plot shows a “fake” 3d plot. It’s fake because in fact there are only two dimensions available on your computer screen. So we’re already in a bit of trouble when trying to visualise the relationships represented by higher dimensional functions.

[4]:
x, y = sympy.symbols('x, y')
[5]:
f2 = sympy.sin(x) + sympy.cos(y)
[6]:
sympy.plotting.plot3d(f2)
../../_images/1_Dynamics_3_Linear_systems_Visualising_complex_functions_10_0.png
[6]:
<sympy.plotting.plot.Plot at 0x1113c2320>

We can make up for some of this lack by using colors to represent another axis.

[7]:
import numpy
import matplotlib.pyplot as plt
[8]:
f2numeric = sympy.lambdify((x, y), f2, 'numpy')
[9]:
xx, yy = numpy.mgrid[-10:10:0.1, -10:10:0.1]
[10]:
zz = f2numeric(xx, yy)
[11]:
plt.pcolor(xx, yy, zz)
[11]:
<matplotlib.collections.PolyCollection at 0x111922550>
../../_images/1_Dynamics_3_Linear_systems_Visualising_complex_functions_16_1.png

For transfer functions, we have an even bigger challenge, because we have two input variables (the real and imaginary part of \(s\)) and two output variables (the real and imaginary part of \(G(s)\)). One solution to the problem is to use colors for \(\angle G(s)\) and brightness for \(|G(s)|\). This is known as domain colouring and is supplied by mpmath.cplot.

[12]:
try:
    import mpmath
except:
    from sympy import mpmath
[13]:
s = sympy.Symbol('s')

G = 1/(s**2 + s + 1)
Gnumeric = sympy.lambdify(s, G)
mpmath.cplot(Gnumeric)
../../_images/1_Dynamics_3_Linear_systems_Visualising_complex_functions_19_0.png

We can get a smoother result by plotting with more points

[14]:
mpmath.cplot(Gnumeric, points=10000)
../../_images/1_Dynamics_3_Linear_systems_Visualising_complex_functions_21_0.png

The roots of the denominator appear as two bright regions.

Another solution is to plot the image of \(G(s)\) as \(s\) goes through a particular path. We will speak more of this when we cover the frequency domain, but have a look at this example. We generate values of \(s\) in a circle of diameter 1 (radius 0.5) around the origin, then plot \(G(s)\) for all these \(s\) values. This is known as the image of \(G(s)\) for these values of \(s\).

[15]:
theta = numpy.linspace(0, 2*numpy.pi)  # angles around the circle
s = 0.5*(numpy.cos(theta) + numpy.sin(theta)*1j) # The circle with radius 0.5
Gs = Gnumeric(s)
[16]:
plt.plot(s.real, s.imag)
plt.plot(Gs.real, Gs.imag)
plt.axis('equal');
../../_images/1_Dynamics_3_Linear_systems_Visualising_complex_functions_25_0.png
[ ]: