0

我对 python 和 rtlsdr 的世界仍然很陌生,但是我正在使用 Raspberry Pi 进行一个项目,以便在听到无线电信号时基本上触发警告灯。

在高层次上,我的项目是使用连接到插入 Raspberry Pi 的 RTL-SDR 加密狗的 2 米无线电频段的外部天线。我有一个标准继电器连接到 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()
4

1 回答 1

0

当您调谐到 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 在它们调谐到的频率处产生一个小的频率峰值(称为“DC 尖峰”)。在我的 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()

图像中没有说明这一点,但您也可以从低于载波的任何频率获得信号中的负频率。

于 2021-07-25T10:54:19.903 回答