Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trapezoidal wave in Python

How do I generate a trapezoidal wave in Python?

I looked into the modules such as SciPy and NumPy, but in vain. Is there a module such as the scipy.signal.gaussian which returns an array of values representing the Gaussian function wave?

Enter image description here

I generated this using the trapezoidal kernel of Astropy, Trapezoid1DKernel(30,slope=1.0) . I want to implement this in Python without using Astropy.

like image 364
Dragon Avatar asked Mar 08 '23 20:03

Dragon


2 Answers

While the width and the slope are sufficient to define a triangular signal, you would need a third parameter for a trapezoidal signal: the amplitude.

Using those three parameters, you can easily adjust the scipy.signal.sawtooth function to give you a trapeziodal shape by truncating and offsetting the triangular shaped function.

from scipy import signal
import matplotlib.pyplot as plt
import numpy as np


def trapzoid_signal(t, width=2., slope=1., amp=1., offs=0):
    a = slope*width*signal.sawtooth(2*np.pi*t/width, width=0.5)/4.
    a[a>amp/2.] = amp/2.
    a[a<-amp/2.] = -amp/2.
    return a + amp/2. + offs

t = np.linspace(0, 6, 501)
plt.plot(t,trapzoid_signal(t, width=2, slope=2, amp=1.), label="width=2, slope=2, amp=1")
plt.plot(t,trapzoid_signal(t, width=4, slope=1, amp=0.6), label="width=4, slope=1, amp=0.6")

plt.legend( loc=(0.25,1.015))
plt.show()

enter image description here

Note that you may also like to define a phase, depeding on the use case.

In order to define a single pulse, you might want to modify the function a bit and supply an array which ranges over [0,width].

from scipy import signal
import matplotlib.pyplot as plt
import numpy as np

def trapzoid_signal(t, width=2., slope=1., amp=1., offs=0):
    a = slope*width*signal.sawtooth(2*np.pi*t/width, width=0.5)/4.
    a += slope*width/4.
    a[a>amp] = amp
    return a + offs

for w,s,a in zip([2,5], [2,1], [1,0.6]):
    t = np.linspace(0, w, 501)
    l = "width={}, slope={}, amp={}".format(w,s,a)
    plt.plot(t,trapzoid_signal(t, width=w, slope=s, amp=a), label=l)

plt.legend( loc="upper right")
plt.show()

enter image description here

like image 55
ImportanceOfBeingErnest Avatar answered Mar 20 '23 03:03

ImportanceOfBeingErnest


From the SciPy website it looks like this isn't included (they currently have sawtooth and square, but not trapezoid). As a generalised version of the C example the following will do what you want,

import numpy as np
import matplotlib.pyplot as plt

def trapezoidalWave(xin, width=1., slope=1.):
    x = xin%(4*width)
    if (x <= width):
        # Ascending line
        return x*slope;
    elif (x <= 2.*width):
        # Top horizontal line
        return width*slope
    elif (x <= 3.*width):
        # Descending line
        return 3.*width*slope - x*slope
    elif (x <= 4*width):
        # Bottom horizontal line
        return 0.


x = np.linspace(0.,20,1000)
for i in x:
    plt.plot(i, trapezoidalWave(i), 'k.')
    plt.plot(i, trapezoidalWave(i, 1.5, 2.), 'r.')
plt.show()

which looks like,

Enter image description here

This can be done more elegantly with Heaviside functions which allow you to use NumPy arrays,

import numpy as np
import matplotlib.pyplot as plt

def H(x):
    return 0.5 * (np.sign(x) + 1)

def trapWave(xin, width=1., slope=1.):
    x = xin%(4*width)
    y = ((H(x)-H(x-width))*x*slope +
         (H(x-width)-H(x-2.*width))*width*slope +
         (H(x-2.*width)-H(x-3.*width))*(3.*width*slope - x*slope))
    return y

x = np.linspace(0.,20,1000)
plt.plot(x, trapWave(x))
plt.plot(x, trapWave(x, 1.5, 2.))
plt.show()

For this example, the Heaviside version is about 20 times faster!

like image 37
Ed Smith Avatar answered Mar 20 '23 05:03

Ed Smith