我可以使用以下方法从RTL-SDR捕获信号:
from rtlsdr import *
i = 0
signals = []
sdr = RtlSdr()
sdr.sample_rate = 2.8e6
sdr.center_freq = 434.42e6
sdr.gain = 25
while True:
samples = sdr.read_samples(1024*1024)
decibel = 10*log10(var(samples))
if decibel >= -10:
signals.append(samples)
i += 1
if i == 2:
break
如果我使用Matplotlib和Seaborn绘制信号,它们看起来像这样:
现在,我需要的是使所有峰值的坐标高于某个功率水平,例如-20。
我找到了一个相当有前途的各种Python options列表。但是,所有这些示例都使用了一个简单的Numpy数组,不同的算法可以很容易地使用它。
这是最好的尝试(因为我的猜测是我从RTL-SDR获得一个复杂的信号,并且必须将其“转换”为具有实际值的数组?):
import numpy as np
import peakutils.peak
real_sig = np.real(signals[0])
indexes = peakutils.peak.indexes(real_sig, thres=-20.0/max(real_sig), min_dist=1)
print("Peaks are: %s" % (indexes))
在上面的脚本中添加了这几行,我确实得到了一些输出,但是,首先,对于功率级-20以上的五个峰值,有太多的值。其次,在给定的上下文中,这些值没有多大意义。
那么,我需要改变什么来获得有意义的结果,例如“峰值1是433.22 MHz”?
理想情况下,我应该得到像Peak 1: X = 433.22, Y = -18.0
这样的坐标,但我想我知道如何获得正确的X值后我就能弄明白。
答案 0 :(得分:1)
您缺少几个步骤。
首先需要:从长度为N的RTL-SDR中选择一段复杂的IQ数据(您可能需要将原始IQ样本从无符号8位转换为有符号浮点数),窗口(von Hann或汉明等),通过长度为N的FFT将其转换为频域,将FFT结果转换为对数幅度,并按频率标记FFT对数幅度结果箱(例如阵列元素),大致为
frequency(i) = sdr.center_freq + i * sdr.sample_rate / N
对于0到N / 2的区间
frequency(i) = sdr.center_freq - (N - i) * sdr.sample_rate / N
用于箱子N / 2到N-1
然后,您可以沿着该对数幅度数组搜索峰值,并将频率标签应用于找到的峰值。
补充:您无法直接从RTL-SDR获取频域信息(如频率峰值)。你想要的峰值不在那里。 RTL-SDR输出原始复数/ IQ时域采样,而不是频域数据。所以首先你需要查阅,研究和理解两者之间的区别。那么您可能会理解为什么需要FFT(或DFT,或Goertzels,或小波等)来进行转换。
答案 1 :(得分:1)
类似于:
获取你的signals
y值相对幂数组。
sort([x for x in signals > -20])
sort[:i]
为我的拳峰。
对于频率范围:
frequency_peaks = [ frequencyspectrum[a] for a in signals[:i]]
但实际上你应该使用Fourrier变换和分组(@ hotpaw2'答案):
numpy.fft
可以解决问题:
https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.fft.html
另见:
https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem
为背景理论。
答案 2 :(得分:0)
我现在尝试了以下代码(灵感来自hotpaw2和我在Google上发现的答案):
from numpy.fft import fft, fftshift
window = np.hamming(sdr.sample_rate/1e6+1)
plt.figure()
A = fft(window, 2048) / 25.5 # what do these values mean?
mag = np.abs(fftshift(A))
freq = np.linspace(sdr.center_freq/1e6-(sdr.sample_rate/1e6)/2, sdr.center_freq/1e6+(sdr.sample_rate/1e6)/2, len(A))
response = 20 * np.log10(mag)
#response = np.clip(response, -100, 100)
plt.plot(freq, response)
plt.title("Frequency response of Hamming window")
plt.ylabel("Magnitude [dB]")
plt.xlabel("Normalized frequency [cycles per sample]")
plt.axis("tight")
plt.show()
来源:https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.hamming.html
这导致以下(绝对无用的)信号图: 我需要在原始帖子中使用类似PSD的情节,然后我可以在其中检测到峰值。
有人可以向我解释为什么我应该做所有这些汉明/ FFT的东西吗?
我想要的只是表示我的信号(由RTL-SDR接收),peakutils.peak.indexes()方法接受并返回正确的峰值。
答案 3 :(得分:0)
我相信我已经开始明白你们所有人想要告诉我的事了......
目标仍然是重现如下图表(使用Matplotlib的plt.psd()方法创建): 现在,我已经能够提出三个不同的代码段,每个代码段都让我非常接近,但没有一个是完美的:
# Scipy version 1
from scipy.signal import welch
sample_freq, power = welch(signal[0], sdr.sample_rate, window="hamming")
plt.figure(figsize=(9.84, 3.94))
plt.semilogy(sample_freq, power)
plt.xlabel("Frequency (MHz)")
plt.ylabel("Relative power (dB)")
plt.show()
以上情况产生以下情节: 虽然这个数字看起来并不太糟糕,但我完全不知道为什么中心峰的一部分缺失,以及连接图的两端的奇怪线来自何处。另外,我无法弄清楚如何显示功率电平和频率的正确值。
我的下一次尝试:
# Scipy version 2
from scipy.fftpack import fft, fftfreq
window = np.hamming(len(signal[0]))
sig_fft = fft(signal[0])
power = 20*np.log10(np.abs(sig_fft)*window)
sample_freq = fftfreq(signal[0].size, sdr.sample_rate/signal[0].size)
plt.figure(figsize=(9.84, 3.94))
plt.plot(sample_freq, power)
plt.xlabel("Frequency (MHz)")
plt.ylabel("Relative power (dB)")
plt.show()
这让我得到以下结果: 显然,我再次走上正轨,但我不知道如何在该版本的代码中应用汉明窗口(显然,我做错了)。就像之前的尝试一样,我无法弄清楚如何在x轴上显示正确的频率。
我的最后一次尝试使用的是Numpy而不是Scipy:
# Numpy version
window = np.hamming(len(signal[0]))
sig_fft = np.fft.fft(signal[0])
sample_freq = np.fft.fftfreq(signal[0].size, sdr.sample_rate/signal[0].size)
power = 20*np.log10(np.abs(sig_fft))
plt.figure(figsize=(9.84, 3.94))
plt.plot(sample_freq, power)
plt.xlabel("Frequency (MHz)")
plt.ylabel("Relative power (dB)")
plt.show()
结果是: 我会说这个可能最接近我想要的(如果没有错误应用的汉明窗口,Scipy版本2会看起来相同),如果它不是所有的噪音。再一次,不知道如何应用汉明窗来摆脱噪音。
我的问题是: