import matplotlib.pyplot as pltimport numpy as npimport pyaudio#-----------------------CHUNK = 1024RATE = 44100CHANNELS = 2FORMAT = pyaudio.pafloat32#-----------------------samples = int(CHUNK)t = np.arange(samples) / RATEcon = 0def generate_sine(a: float = 0.5,freq: float = 440.0): global con sine = a * np.sin(2.0 * np.pi * freq * t + con) # get the angle of the wave phase = np.angle(np.fft.fft(sine)) # update ref var to generate subsequent sines # begining where the last ended con = phase[-1] return sinedef play_sine(data): pa = pyaudio.PyAudio() stream = pa.open(format=FORMAT,channels=CHANNELS,rate=RATE,input=False,output=True,frames_per_buffer=CHUNK) stream.write(np.array(data).astype(np.float32).tostring()) stream.close()if __name__ == '__main__': f = 80 chunks = generate_sine(freq=f) for i in range(0,4): chunks = np.concatenate((chunks,generate_sine(freq=f))) #for i in range(0,10): #play_sine(chunks) plt.plot(chunks) plt.show()
演示情节
您可以在链接的图像中看到x = 1024,x = 2048周围存在不连续性,依此类推.
解决方法 你正在生成你的信号a * sin(2πf * t + con)
其中t的范围超过[0 .. CHUNK / RATE).
当您启动下一个块时,t将重置为零.要生成连续波形,您需要修改con以生成与上一个样本相同的结果相位值.
使用FFT不会起作用,因为您生成的信号不是采样窗口的精确倍数,而且您实际上对采样窗口末端的相位感兴趣,而不是开始时的相位.
相反,您只需要在t = t_end处生成函数的相位值,模2π.
即,你可以简单地使用:
con = 2.0 * np.pi * f * CHUNK/RATE + con
但是这个值会增长,如果你将很多块连接在一起,频率很高,可能会导致最终的数值问题.由于正弦函数是周期性的,您只需要将结束阶段标准化为0到2π范围:
con = math.fmod(2.0 * np.pi * f * CHUNK/RATE + con,2.0 * np.pi)
如果将生成函数修改为:
a * sin(2π * (f * t + con))
然后con表示从前一个卡盘向前移动的完整循环的分数,并且可以避免模数除以2π,这可能会略微提高精度.
con = math.modf(f * CHUNK/RATE + con)[0]
尝试更清楚的解释:
注意:此技术仅适用,因为您确切知道前一个块的生成方程,并生成以下块.如果这些条件中的任何一个发生变化,您将需要一种不同的技术来匹配这些块.
使用以下序列的sin()生成上一个块:
2πf₁*0/RATE+con₁,2πf₁*1/RATE+con₁,...,2πf₁*1022/RATE+con₁,2πf₁*1023/RATE+con₁
应该清楚的是,为了平滑过渡到下一个块,该块应该以2πf1* 1024 / RATE con 1的sin()开始.
下一个块以2πf2* 0 / RATE con 2的sin()开始.
因此,如果符合以下条件,我们将顺利过渡:
2πf₂*0/RATE + con₂ = 2πf₁*1024/RATE + con₁
要么
0 + con₂ = 2πf₁*1024/RATE + con₁
要么
con₂ = 2πf₁*1024/RATE + con₁
可以在generate_sine函数中写入:
con = 2.0 * np.pi * f * CHUNK/RATE + con
在我的上述答案中,这是“无处不在”的等式.从那时起,由于sin()函数是2π周期性的,我只是执行模2π约简,以使sin()的参数不受限制地增长,导致数值不准确.
希望能让事情更加清晰.
总结以上是内存溢出为你收集整理的如何在没有相位跳跃的情况下连接正弦波全部内容,希望文章能够帮你解决如何在没有相位跳跃的情况下连接正弦波所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)