scipy Python梯形波浪

yzxexxkh  于 2022-12-13  发布在  Python
关注(0)|答案(5)|浏览(185)

如何在Python中生成梯形波?
我研究了Scipy和NumPy等模块,但一无所获。有没有像Scipy.signal.gaussian这样的模块返回代表高斯函数波的值的数组?

我使用Astropy的梯形核生成了这个函数,Trapezoid1DKernel(30,slope=1.0)。我想用Python实现这个函数,而不使用Astropy。

8tntrjer

8tntrjer1#

虽然宽度和斜率足以定义三角形信号,但对于梯形信号,还需要第三个参数:振幅。
使用这三个参数,您可以轻松地调整scipy.signal.sawtooth函数,通过截断和偏移三角形函数来给予梯形。

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()

请注意,您可能还希望根据用例定义一个阶段。
为了定义单个脉冲,您可能需要稍微修改函数并提供一个范围超过[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()

cngwdvgl

cngwdvgl2#

从SciPy网站上看,这似乎不包括在内(他们目前有sawtoothsquare,但没有梯形)。作为the C示例的通用版本,以下内容将满足您的要求:

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()

看起来像是

这可以通过Heaviside函数更好地完成,

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()

对于这个例子,Heaviside版本大约快了20倍!

dba5bblo

dba5bblo3#

下面的示例显示了如何执行此操作以获取点并显示范围。
基于回复的等式:Equation for trapezoidal wave equation

import math
import numpy as np
import matplotlib.pyplot as plt

def get_wave_point(x, a, m, l, c):
    # Equation from: https://stackoverflow.com/questions/11041498/equation-for-trapezoidal-wave-equation
    # a/pi(arcsin(sin((pi/m)x+l))+arccos(cos((pi/m)x+l)))-a/2+c
    # a is the amplitude
    # m is the period
    # l is the horizontal transition
    # c is the vertical transition

    point = a/math.pi*(math.asin(math.sin((math.pi/m)*x+l))+math.acos(math.cos((math.pi/m)*x+l)))-a/2+c
    return point

print('Testing wave')

x = np.linspace(0., 10, 1000)
listofpoints = []
for i in x:
    plt.plot(i, get_wave_point(i, 5, 2, 50, 20), 'k.')
    listofpoints.append(get_wave_point(i, 5, 2, 50, 20))
print('List of points : {} '.format(listofpoints))
plt.show()
7uhlpewt

7uhlpewt4#

所有的功劳都要归功于@ImportanceOfBeingErnest。我正在修改他的代码,这让我很开心。

from scipy import signal
import matplotlib.pyplot as plt
from matplotlib import style
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([32],[1],[0.0322]):
    t = np.linspace(0, w, 34)

    plt.plot(t,trapzoid_signal(t, width=w, slope=s, amp=a))

plt.show()

结果:x1c 0d1x

dauxcl2d

dauxcl2d5#

我将把一个非常晚的帽子扔到这个环中,即,一个只使用numpy的函数,它在所需的位置产生一个(对称的)梯形,带有所有常用的参数。

import numpy as np

def trapezoid(x, center=0, slope=1, width=1, height=1, offset=0):
    """
    For given array x, returns a (symmetric) trapezoid with plateau at y=h (or -h if 
    slope is negative), centered at center value of "x".
    Note: Negative widths and heights just converted to 0

    Parameters
    ----------
    x : array_like
        array of x values at which the trapezoid should be evaluated
    center : float
        x coordinate of the center of the (symmetric) trapezoid
    slope : float
        slope of the sides of the trapezoid
    width : float
        width of the plateau of the trapezoid
    height : float
        (positive) vertical distance between the base and plateau of the trapezoid
    offset : array_like
        vertical shift (either single value or the same shape as x) to add to y before returning

    Returns
    -------
    y : array_like
        y value(s) of trapezoid with above parameters, evaluated at x

    """
    
    # ---------- input checking ----------
    if width < 0: width = 0
    if height < 0: height = 0

    x = np.asarray(x)

    slope_negative = slope < 0
    slope = np.abs(slope)  #  Do all calculations with positive slope, invert at end if necessary

    # ---------- Calculation ----------
    y = np.zeros_like(x)
    mask_left = x - center < -width/2.0
    mask_right = x - center > width/2.0

    y[mask_left] = slope*(x[mask_left] - center + width/2.0)
    y[mask_right] = -slope*(x[mask_right] - center - width/2.0)

    y += height     # Shift plateau up to y=h
    y[y < 0] = 0    # cut off below zero (so that trapezoid flattens off at "offset")

    if slope_negative: y = -y          # invert non-plateau

    return y + offset

它输出类似于

import matplotlib.pyplot as plt
plt.style.use("seaborn-colorblind")

x = np.linspace(-5,5,1000)

for i in range(1,4):
    plt.plot(x,trapezoid(x, center=0, slope=1, width=i, height=i, offset = 0), label=f"width = height = {i}\nslope=1")

plt.plot(x,trapezoid(x, center=0, slope=-1, width=2.5, height=1, offset = 0), label=f"width = height = 1.5,\nslope=-1")
plt.ylim((-2.5,3.5))
plt.legend(frameon=False, loc='lower center', ncol=2)

输出示例:

相关问题