清除生成的正弦波伪影以实现平滑的频率转换

Cleaning generated Sinewave artifacts for smooth frequency transitions

我是一名 python 初学者,作为一个学习项目,我正在使用 Wraase SC2-120 方法制作 SSTV 编码器。

SSTV 对于那些不知道的人来说是一种通过无线电将图像作为声音发送并在接收端解码回图像的技术。 Wraase SC2-120 是众多编码类型中的一种,但它是支持颜色的更简单的编码类型之一。

我已经能够创建一个获取图像并将其转换为数组的系统。然后获取该数组并为编码器所需的亮度和色度创建所需的值。

然后我使用这个块为该方法创建一个介于 1500hz - 2300hz 之间的值。

 def ChrominanceAsHertz(value=0.0):
    value = 800 * value
    value -= value % 128 # Test. Results were promising but too much noise
    value += 1500
    return int(value)

您可以忽略取模运算。这只是我为了“乐趣”和实验而玩弄数据的方式。

然后我清理音频以避免在同一个数组中有太多相同的值,并将它们的持续时间加在一起以获得更清晰的声音

cleanTone = []
cleanDuration = []

for i in range(len(hertzData)-1):
    # If the next tone is not the same
    # Add it to the cleantone array
    # with it's initial duration
    if hertzData[i] != hertzData[i+1]:
        cleanTone.append(hertzData[i])
        cleanDuration.append(durationData[i])
    # else add the duration of the current hertz to the clean duration array
    else:
        # the current duration is the last inserted duration
        currentDur = cleanDuration[len(cleanDuration)-1]
        # Add the new duration to the current duration
        currentDur += durationData[i]
        cleanDuration[len(cleanDuration)-1] = currentDur

我的数组处理需要一些工作,但这不是我现在来这里的原因。

结果是一个数组,其中没有相同的连续值,并且该音调的持续时间仍然正确。

然后我使用这个块创建一个正弦波阵列

audio = []
for i in range(len(cleanTone)):   
    sineAudio = AudioGen.SineWave(cleanTone[i], cleanDuration[i]) 
    for sine in sineAudio:
        audio.append(sine)

正弦函数为

   def SineWave( freq=440, durationMS = 500, sample_rate = 44100.0 ):
    num_samples = durationMS * (sample_rate / 1000)
    audio = []
    for i in range(int(num_samples)):
        audio.insert(i, np.sin(2 * np.pi * freq * (i / sample_rate)))
    return audio

它按预期工作。它创建了我想要的频率和持续时间的正弦波。

问题是当我创建 .wav 文件然后使用 wave 创建的正弦波没有平滑过渡。

我的意思的特写截图。 Sinusoidal wave artifacts

由于上述方法产生的这些伪影,音频文件具有这些巨大的尖叫声和裂缝,看看它如何采用单一频率和持续时间,而不管最后一个音调在哪里结束并开始一个新的音调。

我试图解决这些问题的方法是重构 SineWave 方法以接收整个数组并一个接一个地连续创建正弦波,希望获得干净的声音,但它仍然做了同样的事情.

我还尝试“平滑”生成的音频数组,然后使用来自 的简单过滤操作。

 0.7 * audio[1:-1] + 0.15 * ( audio[2:] + audio[:-2] )

但结果还是不令人满意,瑕疵仍然存在。

我也开始研究傅里叶变换,主要是 FFT(快速傅里叶变换),但我对它们还不是很熟悉,还不知道我到底想做什么和编码。

要使 SSTV 正常工作,频率的变化有时必须非常快。准确地说是快 0.3 毫秒,所以我有点不知道如何在不丢失太多数据的情况下实现这一点。

长话短说;博士 我的正弦波函数在音调变化之间产生伪影,导致划痕和不需要的爆裂声。如何不这样做?

你需要从一个 wave-snippet 转移到下一个是阶段。您必须从上一阶段结束的阶段开始下一波。

def SineWave( freq=440, durationMS = 500, phase = 0, sample_rate = 44100.0):
    num_samples = int(durationMS * (sample_rate / 1000))
    audio = []

    for i in range(num_samples):
        audio.insert(i, np.sin(2 * np.pi * freq * (i / sample_rate) + phase))

    phase = (phase + 2 * np.pi * freq * (num_samples / sample_rate)) % (2 * np.pi)
    return audio, phase

在你的主循环中,从一个波片段到下一个波片段:

audio = []
phase = 0

for i in range(len(cleanTone)):   
    sineAudio, phase = AudioGen.SineWave(cleanTone[i], cleanDuration[i], phase)
    for sine in sineAudio:
        audio.append(sine)