在Python

时间:2016-03-02 22:21:56

标签: python audio modulation

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

我已经做了一些背景阅读,介绍自己的信号处理和FSK,我已经看过示例脚本(例如this oneminimodem)。

我设法编写了一个成功运行的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()  

1 个答案:

答案 0 :(得分:1)

似乎你使用多个频道,你需要的声音嵌入其中一个。

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

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

    nyq = 0.5 * Fs
    

    错了。

  2. 如果您利用无噪音进行解调,则可以省略 Differentiator

  3. 对于低通滤波器:

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

    cutoff 频率是您的数据采样率,请阅读this

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

  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 是步骤长度。

  6.   

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

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