Search code examples
python-3.xnumpymatplotlibsignal-processing

Plotting discrete piecewise function - signal


I need to plot a discrete signal that is defined by a piecewise function :

if n < 0 , x = (135/56) * (0.9)^n - (1/8)(0.1)^n - (2/7)(0.2)^n  

if 0<=n< 4, x = (135/56) * (0.9)^n + (7/8)(0.1)^n + (5/7)(0.2)^n  

if n>=4 , x = (135/56) * (0.9)^n + (7/8)(0.1)^n + (5/7)(0.2)^n + (0.1)^(-4) + (0.2)^(-4)  

I have searched a lot in web and especially here and I came up with this code , that after many corrections it actually runned in spyder. But the result is definetely not the expected one. Can anyone help me?

import numpy as np
import matplotlib.pyplot as plt
xPoints = []
nPoints = []
q = (135 / 56)
z= -(1/8)
r = -(2/7)
m = 7/8
p = 5 /7
j = np.power(0.1, -3.5)
a = np.power(0.2, -3.5)
for n in range(-5,11):
    if n<0 :
        x = q *np.power(0.9, n) + z* np.power(0.1, n) + r* np.power(0.2, n)
    elif (n>=0 and n<4):
        x =q *np.power(0.9, n) + m* np.power(0.1, n) + p* np.power(0.2, n)
    else:
        x =q *np.power(0.9, n) + m* np.power(0.1, n) + p* np.power(0.2, n)+ j + a
    xPoints.append(x)
    nPoints.append(n)
plt.plot(nPoints, xPoints)
plt.plot.show()

Solution

  • In numpy stepwise functions can be created using where. One of numpy's most magical features is broadcasting, where a function can be called on a complete array of values at once.

    Your example code creates the expected curve, but only adds a point at integer values. To create a smooth curve, np.linspace creates a long array of values (the code below uses 1000 little steps between -5 and 5). (Note that numpy needs the & operator for a logical and of two array expressions. In this particular case you could use n < 4 instead of (n >= 0) & (n < 4) as the case of n < 0 is taken care of earlier.)

    import numpy as np
    import matplotlib.pyplot as plt
    
    q = (135 / 56)
    z = -(1 / 8)
    r = -(2 / 7)
    m = 7 / 8
    p = 5 / 7
    j = np.power(0.1, -3.5)
    a = np.power(0.2, -3.5)
    
    n = np.linspace(-5, 5, 1000)
    x = np.where(n < 0, q * np.power(0.9, n) + z * np.power(0.1, n) + r * np.power(0.2, n),
                 np.where((n >= 0) & (n < 4), q * np.power(0.9, n) + m * np.power(0.1, n) + p * np.power(0.2, n),
                          q * np.power(0.9, n) + m * np.power(0.1, n) + p * np.power(0.2, n) + j + a))
    plt.plot(n, x)
    plt.show()
    

    resulting plot

    If you only want the integer positions, you can use np.arange instead of np.linspace and then create a scatter plot (plt.scatter(n, x)) or maybe a stemplot:

    import numpy as np
    import matplotlib.pyplot as plt
    
    q = (135 / 56)
    z = -(1 / 8)
    r = -(2 / 7)
    m = 7 / 8
    p = 5 / 7
    j = np.power(0.1, -3.5)
    a = np.power(0.2, -3.5)
    
    n = np.arange(-5, 6)
    x = np.where(n < 0, q * np.power(0.9, n) + z * np.power(0.1, n) + r * np.power(0.2, n),
                 np.where((n >= 0) & (n < 4), q * np.power(0.9, n) + m * np.power(0.1, n) + p * np.power(0.2, n),
                          q * np.power(0.9, n) + m * np.power(0.1, n) + p * np.power(0.2, n) + j + a))
    plt.stem(n, x)
    plt.show()
    

    example stem plot