Caribou SDR spectrum analyzer #18

Open
opened 2026-10-05 05:58:58 +02:00 by adam · 1 comment
Owner

'''
import sys
import time
import numpy as np
import serial.tools.list_ports
from SoapySDR import Device, SOAPY_SDR_RX, SOAPY_SDR_CF32

Add SoapySDR library path

sys.path.insert(0, "/home/pi/SoapySDR/build/swig/python/python3/")

Scanner parameters

START_FREQ = 100e6 # Start frequency: 100 MHz
STOP_FREQ = 6e9 # Stop frequency: 6 GHz
STEP_SIZE = 10e6 # Frequency step size: 10 MHz
SAMPLE_RATE = 2e6 # Sample rate: 2 Msps
GAIN = 30 # SDR gain in dB
NUM_SAMPLES = 1024 # Number of samples for RSSI calculation

def select_serial_device():
"""List available serial ports and allow the user to select one."""
ports = list(serial.tools.list_ports.comports())
if not ports:
print("No serial ports detected. Please connect a USB serial device.")
sys.exit(1)

print("Available serial ports:")
for i, port in enumerate(ports):
    print(f"[{i}] {port.device} - {port.description}")

while True:
    try:
        choice = int(input("Select the serial port [number]: "))
        if 0 <= choice < len(ports):
            return ports[choice].device
        else:
            print("Invalid choice. Please select a valid number.")
    except ValueError:
        print("Please enter a number.")

def main():
try:
# Select and open the serial port
serial_device = select_serial_device()
ser = serial.Serial(serial_device, 9600)
print(f"Serial port {serial_device} opened at 9600 baud.")

    # Initialize SDR device
    sdr = Device({"driver": "Cariboulite", "channel": "HiF"})
    
    # Configure SDR settings
    sdr.setSampleRate(SOAPY_SDR_RX, 0, SAMPLE_RATE)
    sdr.setGain(SOAPY_SDR_RX, 0, GAIN)

    # Setup RX stream
    rx_stream = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32)
    sdr.activateStream(rx_stream)

    # Allocate buffer for samples
    buffer = np.zeros(NUM_SAMPLES, dtype=np.complex64)

    # Scan frequencies
    for freq in np.arange(START_FREQ, STOP_FREQ, STEP_SIZE):
        # Set the center frequency
        sdr.setFrequency(SOAPY_SDR_RX, 0, freq)

        # Allow time for frequency stabilization
        time.sleep(0.1)

        # Read samples
        sr = sdr.readStream(rx_stream, [buffer], len(buffer))
        if sr.ret == len(buffer):
            # Calculate RSSI (Received Signal Strength Indicator)
            rssi = 10 * np.log10(np.mean(np.abs(buffer) ** 2))
            # Output frequency and RSSI to serial
            output = f"Frequency: {freq / 1e6:.2f} MHz, RSSI: {rssi:.2f} dB\n"
            ser.write(output.encode('utf-8'))
            print(output.strip())  # Also print to console
        else:
            print(f"Error reading samples at {freq / 1e6:.2f} MHz: {sr.ret}")

    # Deactivate and close stream
    sdr.deactivateStream(rx_stream)
    sdr.closeStream(rx_stream)
    print("Scanning complete.")

except Exception as e:
    print(f"An error occurred: {e}")
finally:
    # Ensure resources are cleaned up
    if 'rx_stream' in locals():
        sdr.deactivateStream(rx_stream)
        sdr.closeStream(rx_stream)
    if 'ser' in locals() and ser.is_open:
        ser.close()
        print("Serial port closed.")

if name == "main":
main()

‘’’

''' import sys import time import numpy as np import serial.tools.list_ports from SoapySDR import Device, SOAPY_SDR_RX, SOAPY_SDR_CF32 # Add SoapySDR library path sys.path.insert(0, "/home/pi/SoapySDR/build/swig/python/python3/") # Scanner parameters START_FREQ = 100e6 # Start frequency: 100 MHz STOP_FREQ = 6e9 # Stop frequency: 6 GHz STEP_SIZE = 10e6 # Frequency step size: 10 MHz SAMPLE_RATE = 2e6 # Sample rate: 2 Msps GAIN = 30 # SDR gain in dB NUM_SAMPLES = 1024 # Number of samples for RSSI calculation def select_serial_device(): """List available serial ports and allow the user to select one.""" ports = list(serial.tools.list_ports.comports()) if not ports: print("No serial ports detected. Please connect a USB serial device.") sys.exit(1) print("Available serial ports:") for i, port in enumerate(ports): print(f"[{i}] {port.device} - {port.description}") while True: try: choice = int(input("Select the serial port [number]: ")) if 0 <= choice < len(ports): return ports[choice].device else: print("Invalid choice. Please select a valid number.") except ValueError: print("Please enter a number.") def main(): try: # Select and open the serial port serial_device = select_serial_device() ser = serial.Serial(serial_device, 9600) print(f"Serial port {serial_device} opened at 9600 baud.") # Initialize SDR device sdr = Device({"driver": "Cariboulite", "channel": "HiF"}) # Configure SDR settings sdr.setSampleRate(SOAPY_SDR_RX, 0, SAMPLE_RATE) sdr.setGain(SOAPY_SDR_RX, 0, GAIN) # Setup RX stream rx_stream = sdr.setupStream(SOAPY_SDR_RX, SOAPY_SDR_CF32) sdr.activateStream(rx_stream) # Allocate buffer for samples buffer = np.zeros(NUM_SAMPLES, dtype=np.complex64) # Scan frequencies for freq in np.arange(START_FREQ, STOP_FREQ, STEP_SIZE): # Set the center frequency sdr.setFrequency(SOAPY_SDR_RX, 0, freq) # Allow time for frequency stabilization time.sleep(0.1) # Read samples sr = sdr.readStream(rx_stream, [buffer], len(buffer)) if sr.ret == len(buffer): # Calculate RSSI (Received Signal Strength Indicator) rssi = 10 * np.log10(np.mean(np.abs(buffer) ** 2)) # Output frequency and RSSI to serial output = f"Frequency: {freq / 1e6:.2f} MHz, RSSI: {rssi:.2f} dB\n" ser.write(output.encode('utf-8')) print(output.strip()) # Also print to console else: print(f"Error reading samples at {freq / 1e6:.2f} MHz: {sr.ret}") # Deactivate and close stream sdr.deactivateStream(rx_stream) sdr.closeStream(rx_stream) print("Scanning complete.") except Exception as e: print(f"An error occurred: {e}") finally: # Ensure resources are cleaned up if 'rx_stream' in locals(): sdr.deactivateStream(rx_stream) sdr.closeStream(rx_stream) if 'ser' in locals() and ser.is_open: ser.close() print("Serial port closed.") if __name__ == "__main__": main() ‘’’ <!-- github-sync-id:2760638566 -->
Author
Owner

I don’t think cariboulite has gotten to the point of being a ready to use state yet. There will likely be more development on the software side.

My setup is based on a freshly installed 64bit bullseye desktop version on a pi 4 (I wanted to make sure everything works properly before switching over to a headless setup).
Before you run the official install.sh, you can add “dtparam=i2c_vc=on” to /boot/config.txt to avoid error during environment check at the end of the install script. Apparently, not all functions rely on i2c_vc to be on.

Once everything is ready, you can run the install script “./install.sh” in the cariboulite folder you pulled through git. It’s under the started and installation section on the code page. The installation script should install SoapySDRUtil and SoapySDRServer for you before compiling the drivers for cariboulite device. However, I found that SoapySDRServer never got installed properly for me so I had to compile it myself. At this point, you can use “cariboulite_test_app” and “cariboulite_util” in the cariboulite/build folder to manually interact with cariboulite.

sudo ./cariboulite_test_app

#You should also be able to see cariboulite devices (HiF and S1G) using SoapySDRUtil
#the case of the letters are important
sudo SoapySDRUtil --find
I believe you can use the source code pulled by the script or just follow the instructions from pothosware/SoapyRemote git page as following:

git clone https://github.com/pothosware/SoapyRemote.git
cd SoapyRemote
mkdir build
cd build
cmake ..
make
sudo make install
Once SoapyRemote (SoapySDRServer) is compiled and installed properly, you can use SoapySDRServer to connect to it remotely using native SDR software like cubicsdr (I’ve yet to get sdrpp install properly on my pi, gqrx also has issue connecting to Soapy).

#To launch server manually (binding port is 55132)
sudo SoapySDRServer --bind

#Or enable the server so it starts when system boots
sudo systemctl enable SoapySDRServer
sudo systemctl start SoaypySDRServer #only for the first time, subsequent reboots do not need manual server start
After the server is started, you will be able to connect using cubicsdr using ip:55132. I was able to get cubicsdr, openwebrx and gqrx to see both radios on caribou using 0.0.0.0 on local host. However, gqrx seemed to have issue staying connected with SoapyRemote and cubicsdr and openwebrx are both showing poor signal strength using antennas (a 70cm/2m hand held antenna, a multi band discone and a rubber duckie) that produce adequate to good signal strength on local radio stations (~100MHz) for the RTL SDR dongle on the same pi setup, so I’m guess either I’m still missing something or the driver still needs some work. I don’t know enough to tell for sure.

This is how far I’ve gotten recently, and I hope this helps to get you started. I hope I has not made too much mistakes in write this as well.

I don’t think cariboulite has gotten to the point of being a ready to use state yet. There will likely be more development on the software side. My setup is based on a freshly installed 64bit bullseye desktop version on a pi 4 (I wanted to make sure everything works properly before switching over to a headless setup). Before you run the official install.sh, you can add “dtparam=i2c_vc=on” to /boot/config.txt to avoid error during environment check at the end of the install script. Apparently, not all functions rely on i2c_vc to be on. Once everything is ready, you can run the install script “./install.sh” in the cariboulite folder you pulled through git. It’s under the started and installation section on the code page. The installation script should install SoapySDRUtil and SoapySDRServer for you before compiling the drivers for cariboulite device. However, I found that SoapySDRServer never got installed properly for me so I had to compile it myself. At this point, you can use “cariboulite_test_app” and “cariboulite_util” in the cariboulite/build folder to manually interact with cariboulite. sudo ./cariboulite_test_app #You should also be able to see cariboulite devices (HiF and S1G) using SoapySDRUtil #the case of the letters are important sudo SoapySDRUtil --find I believe you can use the source code pulled by the script or just follow the instructions from pothosware/SoapyRemote git page as following: git clone https://github.com/pothosware/SoapyRemote.git cd SoapyRemote mkdir build cd build cmake .. make sudo make install Once SoapyRemote (SoapySDRServer) is compiled and installed properly, you can use SoapySDRServer to connect to it remotely using native SDR software like cubicsdr (I’ve yet to get sdrpp install properly on my pi, gqrx also has issue connecting to Soapy). #To launch server manually (binding port is 55132) sudo SoapySDRServer --bind #Or enable the server so it starts when system boots sudo systemctl enable SoapySDRServer sudo systemctl start SoaypySDRServer #only for the first time, subsequent reboots do not need manual server start After the server is started, you will be able to connect using cubicsdr using ip:55132. I was able to get cubicsdr, openwebrx and gqrx to see both radios on caribou using 0.0.0.0 on local host. However, gqrx seemed to have issue staying connected with SoapyRemote and cubicsdr and openwebrx are both showing poor signal strength using antennas (a 70cm/2m hand held antenna, a multi band discone and a rubber duckie) that produce adequate to good signal strength on local radio stations (~100MHz) for the RTL SDR dongle on the same pi setup, so I’m guess either I’m still missing something or the driver still needs some work. I don’t know enough to tell for sure. This is how far I’ve gotten recently, and I hope this helps to get you started. I hope I has not made too much mistakes in write this as well. <!-- github-comment-id:2564596126 -->
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/LoraSA#18