使用 linspace 了解 Python 中的正弦波生成

信息处理 Python 音调产生
2022-01-28 11:36:59

我试图以每 160us(微秒)采样一次 12.8 MHz 正弦波(78.125 ns)信号。由于 160us 是基周期 78.125ns(x2048) 的倍数,我希望得到一个固定幅度的样本,但我看到的是另一个周期性正弦波。我不明白为什么?

我怀疑量化误差,但不应该产生均匀的噪声而不是产生周期性的正弦波。

    import numpy as np
    from matplotlib import pyplot as plt

    fig2 = plt.figure()
    ax2 = fig2.add_subplot(1, 1, 1)

    capture_size1 = 2048
    timestep1 = 160e-6
    freq1 = 12.8e6
    time1 = np.linspace(0, capture_size1 * timestep1, capture_size1)
    w1 = np.sin(time1 * 2 * np.pi * freq1)
    ax2.plot(time1, w1, '.')

    plt.show()

Edit1 : 1. 12.8 MHZ 故意采样不足

  1. 在 capture_size1 = 2048 的情况下添加绘图的屏幕截图,正弦波的适当幅度为 [+1, -1]

在此处输入图像描述

Edit2:我尝试通过使用 Decimal 来提高精度,我发现它的行为符合预期。我期望一条直线,因为采样点是周期的精确倍数。 使用以下 python 代码生成的实际与预期图

from decimal import Decimal
from math import pi as mpi
from math import sin as msin
import numpy as np
from matplotlib import pyplot as plt

fig2 = plt.figure()
ax2 = fig2.add_subplot(1, 1, 1)

capture_size1 = 2048
timestep1 = 160e-6
freq1 = 12.8e6
time1 = np.linspace(0, capture_size1 * timestep1, capture_size1)
w1 = np.sin(time1 * 2 * np.pi * freq1)
ax2.plot(time1, w1, '.')

capture_size3 = Decimal(2048 * 16)
timestep3 = Decimal(160e-6)
freq3 = Decimal(12.8e6)
time3 = [Decimal(i) * timestep3 for i in range(capture_size1)]
w3 = [msin(Decimal(i) * timestep3 * Decimal(2) * Decimal(mpi) * freq3) for i in range(capture_size1)]
ax2.plot(time3, w3, '.')

plt.legend(["Actual", "Expected"])
plt.show()

Edit3:感谢@jithin 的评论,我进一步做了一些分析。看起来这是 linspace 的问题。我尝试通过乘法来生成时间间隔,如下面的代码所示,并删除了使用 linspace 的原始图(这是至关重要的),所以现在我可以看到其他人建议的 1e-9 范围内的值。那么 linspace 确实存在问题吗?

from decimal import Decimal
from math import pi as mpi
from math import sin as msin
import numpy as np
from matplotlib import pyplot as plt

fig2 = plt.figure()
ax2 = fig2.add_subplot(1, 1, 1)

capture_size1 = 2048
# timestep1 = 160e-6
# freq1 = 12.8e6
# time1 = np.linspace(0, capture_size1 * timestep1, capture_size1)
# w1 = np.sin(time1 * 2 * np.pi * freq1)
# ax2.plot(time1, w1, '.')

capture_size2 = 2048
timestep2 = 160e-6
freq2 = 12.8e6
time2 = [i * timestep2 for i in range(capture_size2)]
w2 = [np.sin(i * timestep2 * 2 * np.pi * freq2) for i in range(capture_size2)]
ax2.plot(time2, w2, '.')

capture_size3 = Decimal(2048)
timestep3 = Decimal(160e-6)
freq3 = Decimal(12.8e6)
time3 = [Decimal(i) * timestep3 for i in range(capture_size1)]
w3 = [msin(Decimal(i) * timestep3 * Decimal(2) * Decimal(mpi) * freq3) for i in range(capture_size1)]
ax2.plot(time3, w3, '.')

plt.legend(["multiply", "Decimal"], fontsize='xx-large')
plt.show()

上述python代码的图像如下 在此处输入图像描述

2个回答

更改以下行:

time1 = np.linspace(0, capture_size1 * timestep1, capture_size1)

到以下:

time1 = np.linspace(0, capture_size1 * timestep1, capture_size1, endpoint=false )

你会看到正确的结果。您的原始时间实例不是您想要的,因为 Python 将在 0 和 2048*Ts 之间创建 2048 个等距点。你想要的是等距的 2048 个点,从 0 到 160usec 开始。

如果您不想使用 'endpoint=false' ,也可以使用以下行:

time1 = np.linspace(0, (capture_size1-1) * timestep1, capture_size1)

在您当前的采样周期,这意味着您每 2048 个周期采集 1 个正弦样本。会有混叠,但您不必为此烦恼,因为您希望看到离散时间的固定幅度。基本上,您希望发生混叠。160μsec

为了在没有混叠的情况下对该信号进行采样,您需要至少为

Fs=212.8MHz=25600000Hz,这意味着您需要对每个1Fs=0,0390625μs.

这意味着您当前的采样率太低了,实际上是除以1600,0390625=4096显示您需要增加多少采样率。

更新: np.sin函数就像任何 sin 函数一样只能产生正弦波(除非参数为 0 或接近它,在这种情况下,可能由于数值舍入错误,您可以获得一条直线)。请注意,np.sin接受角度作为参数,因此freq1将被视为角度。