如何使用rtlsdr作为源为特定频率制作带通滤波器?

2024-05-15 07:39:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我对python和rtlsdr的世界还很陌生,但我有一个项目,我正在使用树莓Pi,当听到无线电信号时,它基本上会触发警告灯

在高层次上,我的项目是使用一个2米无线电频段的外部天线连接到插入Raspberry Pi的RTL-SDR加密狗。我有一个标准的继电器连接到GPIO引脚,当它“听到”信号时打开灯

我真的不在乎99%的输入信号。我只想知道什么时候有147.3MHz的载波,让GPIO打开灯。就这样。不多也不少。这当然可以简单地做到?我已经读过scipy.signal.butter带通滤波器,但是我不能让它在这个频率下工作

下面是我的代码,我欢迎任何改进建议,但理想情况下,我正在寻找一种方法,让程序识别中心频率为147.3MHz的峰值,然后调用我的“warning_lights.py”脚本

import RPi.GPIO as GPIO
from rtlsdr import *
from scipy import signal
import peakdetect
import datetime
import sys
import subprocess

def restart():
    import subprocess
    import time
    time.sleep(120)
    command = "/usr/bin/sudo /sbin/shutdown -r now"
    process = subprocess.Popen(command.split(), stdout=subprocess.PIPE)
    output = process.communicate()[0]
    print (output)


# configure SDR device and settings
sdr = RtlSdr()
sdr.sample_rate = 2.4e6     # Hz
sdr.center_freq = 147.3e6   # Hz
sdr.gain = 'auto'           # Possible values are 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 
num_samples = 1024*1024
procs = []


while True:
    try:
        samples = sdr.read_samples(num_samples)
        power, psd_freq = psd(samples, NFFT=1024, Fs=sdr.sample_rate/1e6, 
        Fc=sdr.center_freq/1e6)
        power_db = 10*np.log10(power)

        maxima, minima = peakdetect.peakdetect(power_db, psd_freq, delta=1)
    
        for mx in maxima:
            if mx[0] == 147.3:     #checking that peak was on 147.3 MHz
                if mx[1] > (-15):  #checking dBm of signal
                    try:
                        while proc.poll() is None:
                            proc.terminate()
                    except:
                        print("Warning lights not on. Turning them on.")
                    finally:
                        print(mx[1])
                        proc = subprocess.Popen([sys.executable, '/home/pi/scripts/warning_lights.py'])
                        procs.append(proc)
    except:
        restart()

Tags: importsignalgpio信号procsubprocesspowersamples
1条回答
网友
1楼 · 发布于 2024-05-15 07:39:04

当你调到147.3MHz时,你从SDR中得到的不是实际的无线电信号,因为它出现在输入端。SDR将射频信号的频率降低到较低的频率,以便于处理和数字化。结果,以147.3MHz为中心的原始信号部分向下移动到0Hz,进入所谓的“基带”。特定带宽(在您的情况下为2.4MHz)之外的所有内容都会被过滤掉。因此,如果有一个148.3MHz的纯正弦波信号,例如,这将在SDR的输出中显示为1MHz的正弦波。想象一个频谱图来可视化这一点非常有帮助: Wikipedia article on baseband

因此,如果有一个以147.3MHz为中心的无线电信号,你不会在SDR的输出中看到147.3MHz,而是在0Hz(由于SDR电路的频率并不完全准确,所以有一个轻微的偏移)。正如您所提到的,使用scipy应该很容易进行过滤

还有一个可能是问题。大多数SDR在调谐到的频率上产生一个小的频率峰值(称为“直流尖峰”)。在我的RTL-SDR中,我发现增益较低时就是这种情况。解决这一问题的方法是将频率调到您感兴趣的信号带宽之外(类似147.5MHz的频率可以工作),然后补偿处理过程中的这种偏移

因此,应该采取的措施是:

# configure SDR device and settings
sdr = RtlSdr()
offset_freq = 200e3         # Hz
sdr.sample_rate = 2.4e6     # Hz
sdr.center_freq = 147.3e6 - offset_freq   # Hz
sdr.gain = 'auto'           # Possible values are 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 
num_samples = 1024*1024
procs = []


while True:
    try:
        samples = sdr.read_samples(num_samples)
        power, psd_freq = psd(samples, NFFT=1024, Fs=sdr.sample_rate/1e6, 
        Fc=sdr.center_freq/1e6)
        power_db = 10*np.log10(power)

        maxima, minima = peakdetect.peakdetect(power_db, psd_freq, delta=1)

        for mx in maxima:
            if mx[0] == offset_freq:     #checking that peak was on 147.3 MHz
                if mx[1] > (-15):  #checking dBm of signal
                    try:
                        while proc.poll() is None:
                            proc.terminate()
                    except:
                        print("Warning lights not on. Turning them on.")
                    finally:
                        print(mx[1])
                        proc = subprocess.Popen([sys.executable, 
'/home/pi/scripts/warning_lights.py'])
                        procs.append(proc)
    except:
        restart()

这在图中没有说明,但是你也可以从载波下面的任何频率得到信号中的负频率

相关问题 更多 >