0

我正在尝试编写一个 Python 脚本,它可以解调 FSK 调制的音频文件并返回音频中​​编码的数据。传输的数据是作为音频通道嵌入视频文件中的 GPS NMEA 字符串。基本上,文本是用 FSK 调制编码的,我正在尝试使用 Python 检索文本。我用来编码数据的设备也可以解码它,所以我已经能够生成正确的输出,但我需要能够使用软件来完成。

我已经阅读了一些背景资料,向自己介绍了信号处理和 FSK,并查看了示例脚本(例如这个minimodem)。

我设法编写了一个成功运行的 Python 脚本,尽管输出不正确。来自编码/解码设备的正确输出有 8,280 个原始二进制(0 和 1)字符,Python 输出有 1,344,786 个。我想我缺少一个符号同步器,但我不确定它是如何工作的。

我现在的问题是:如何将符号同步添加到脚本和/或符号计时?有没有更好的例子或解释如何在 Python 中进行 FSK 解调?我将不胜感激任何反馈或方向。谢谢你。
到目前为止,这是我的脚本:

from scipy.io.wavfile import read
import numpy as np
import wave
import matplotlib.pyplot as plt
import scipy.signal as signal
from scipy.signal import blackman, butter
from scipy.fftpack import fft, rfft, rfftfreq, irfft
import scipy.signal.signaltools as sigtool
import binascii

# Read in data; 'wav' allows getting paramters, 'wav1' is actual signal data
wavfile = 'Sample4_160224_mono.wav'
wavfile1 = open(wavfile, 'r')
wav = wave.open(wavfile, 'r')
wav_1 = read(wavfile1)
params = wav.getparams()
N = params[3]  #Sample size
wav1 = read(wavfile1)
wav2 = wav1[1][0:N]

duration = float(params[3] / params[2])
n_samples = len(wav2)
Fs = params[2]
nyq = 0.5 * Fs  #Nyquist rate
Fbit = (params[2]*params[0]*16)/100
print "Fbit", Fbit

# Windowing function
w = blackman(n_samples)
print "W is", w

# FFT
wfft = rfft(wav2 * w)
wfft_norm = wfft/N
wfft_norm = abs(wfft_norm[range(N/2)])

# Working with frequencies...
freqs = rfftfreq(len(wfft_norm))
index = np.argmax(np.abs(wfft))  #Returns the index of the maximum absolute value of the windowed FFT
freq = freqs[index]  #Returns the frequency from the above index
freq_range = [freq - 0.01, freq + 0.01]
freq_in_Hz = abs(freq * params[2])  #Converts the Hz
freq_range_Hz = [abs(freq_range[0] * params[2]), abs(freq_range[1] * params[2])]

# Differentiator
diff = np.diff(wav2)

# Envelope detector
env = np.abs(sigtool.hilbert(diff))
print "ENV", len(env)
# Low-pass filter
h = signal.firwin(numtaps = 10, cutoff = freq_range[1], nyq = nyq)
filt = signal.lfilter(h, 1, env)

# Signal's mean
mean = np.mean(filt)

#Do some crazy stuff to get binary **maybe wrong**
rx_data = []
sampled_signal = env[Fs/Fbit/2:params[3]+1:]

for bit in sampled_signal:
    if bit > mean:
        rx_data.append(int(1))
    else:
        rx_data.append(int(0))

# Save raw binary output
rx_data1 = ''.join(map(str, (rx_data)))
outfile1 = open('FSK_wav6_output_binary.txt', 'w')
outfile1.write(rx_data1)
outfile1.close()  
4

1 回答 1

1

似乎您使用了多个通道,并且您需要的声音嵌入其中之一。

到目前为止,我在您的脚本中发现了一些问题:

  1. 奈奎斯特率不是你声音的一半。它是可以对原始声波进行采样的速率,应至少是声音采样率的 2 倍。因此,

    nyq = 0.5 * Fs
    

    是错的。

  2. 如果你利用无噪声的声音来解调,那么微分器可以省略。

  3. 对于低通滤波器:

    h = signal.firwin(numtaps = 10, cutoff = freq_range[1], nyq = nyq)
    

    截止频率是您的数据采样率,请阅读内容。

  4. filt是可以提取您想要的特定数据的最终信号。

  5. 如何选择sampled_signal中的点来重新创建原始信号,实际上取决于原始信号率和采样率之间的比率。就像您提供的第一个链接一样,假设数据以 11025 Hz 写入并且采样或记录速率为 44100 Hz,那么您给出的代码:

    sampled_signal = env[Fs/Fbit/2:params[3]+1:]
    

    应该:

    sampled_signal = filt[Fs/Fbit*2:params[3]:Fs/Fbit*4]
    

    其中Fs/Fbit*2是开始,params[3]是结束,Fs/Fbit*4是步长。

来自编码/解码设备的正确输出有 8,280 个原始二进制(0 和 1)字符,Python 输出有 1,344,786 个。

这是正常的,因为不同的采样率,你可以在你的文本中添加一些特殊的字符作为开始符号和结束符号,然后尝试找到它们,然后你可能会找到你需要的正确长度的数据。

于 2017-02-16T19:50:11.790 回答