You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

144 lines
6.1 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import numpy as np
import rtlsdr
import matplotlib.pyplot as plt
from scipy.signal import welch, windows, freqz
# -------------------------- RTL-SDR Configuration -------------------------------------------
sdr = rtlsdr.RtlSdr() # Inicializar el dispositivo RTL-SDR
sample_rate = 2.4e6 # Tasa de muestreo en muestras por segundo (3MHz)
# The maximum sample rate is 3.2 MS/s (mega samples per second).
# However, the RTL-SDR is unstable at this rate and may drop samples.
# The maximum sample rate that does not drop samples is 2.56 MS/s.
# Configurar parámetros
# Rafael Micro R820T/2/R860 24 1766 MHz (Can be improved to ~13 - 1864 MHz with experimental drivers)
# Experimentalmente capta desde 12MHz
sdr.sample_rate = sample_rate # Tasa de muestreo en muestras por segundo
sdr.center_freq = 99.9e6 # Frecuencia central en Hz (99.9 MHz)
sdr.gain = 42 # Ganancia del receptor
output_file = "fm999.bin" # Nombre del archivo de salida con las muestras capturadas
block_size = 1024 * 1024 # Tamaño de cada bloque de muestras (tasa de muestreo * duracion de la muestra)
samples_buffer = [] # Buffer para almacenar las muestras
# ------------------------ Captura y procesamiento de muestras en bloques ---------------------------------
num_blocks = 1 # Capturar 1 bloques de muestras
for _ in range(num_blocks):
samples = sdr.read_samples(block_size) # Capturar bloque de muestras
np.save(output_file, samples, allow_pickle=False) # Guardar las muestras en el archivo binario
samples_buffer.extend(samples) # Agregar las muestras al buffer
# Mantener el buffer dentro del tamaño deseado
if len(samples_buffer) > block_size * num_blocks:
samples_buffer = samples_buffer[-block_size * num_blocks:]
sdr.close() # Cerrar el dispositivo RTL-SDR
signal_energy = np.sum(np.abs(samples_buffer)**2) / len(samples_buffer) # Calcular la energía de la señal
threshold = 1e-8 # Umbral de energía de la señal
information_present = signal_energy > threshold # Verificar si hay información en las muestras
if information_present:
print("Se detectó información en las muestras.")
else:
print("No se detectó información en las muestras.")
# -------------------------------------- Procesamiento para generar el espectro de potencia con Welch ---------------------------------------------------------
# Parámetros de Welch
m = 256 # Tamaño de cada segmento de datos
k = 128 # Superposición entre segmentos
ventana = np.bartlett(m) # Ventana de Bartlett
# Cálculo del espectro de potencia mediante Welch
N = len(samples_buffer)
S = int(np.floor((N-m) / (m-k))) + 1 # Número total de segmentos
Pxx_segments = np.zeros((S, m)) # Inicializar arreglo para almacenar los espectros de potencia de cada segmento
# Calcular el espectro de potencia para cada segmento
for i in range(S-1):
start = i* (m-k) +1
end = start + m
segment = samples_buffer[start:end] * ventana
Pxx_segments[i, :] = np.abs(np.fft.fft(segment))**2 / (np.sum(ventana**2) * sample_rate)
PSD = np.mean(Pxx_segments, axis=0) # Promediar los espectros de potencia de todos los segmentos
frecuencias_welch = np.fft.fftfreq(m, d=1/sample_rate) # Frecuencias correspondientes a los segmentos de datos
# -------------------------------------- Ploteos ---------------------------------------------------------
# Muestras capturadas
plt.plot(samples_buffer)
plt.xlabel('Muestras')
plt.ylabel('Amplitud')
plt.title('Muestras capturadas')
plt.show()
# Muestras capturadas
plt.plot(np.abs(samples_buffer))
plt.xlabel('Muestras')
plt.ylabel('Amplitud')
plt.title('Muestras capturadas absolutas')
plt.show()
# Transformada de Fourier y frecuencias correspondiente de las muestras en el dominio de la frecuencia
fft_result = np.fft.fft(samples_buffer)
magnitud_fft = np.abs(fft_result)
frecuencias = np.fft.fftfreq(len(samples_buffer), d=1/sample_rate)
# Grafica de la transformada de Fourier
plt.figure(figsize=(10, 6))
plt.plot(frecuencias, magnitud_fft)
plt.title('Transformada de Fourier')
plt.xlabel('Frecuencia (Hz)')
plt.ylabel('Magnitud')
plt.show()
# Espectro de frecuencia
frequencies, spectrum = plt.psd(samples_buffer, NFFT=1024, Fs=sample_rate, scale_by_freq=True)
plt.xlabel('Frecuencia (Hz)')
plt.ylabel('Densidad espectral de potencia')
plt.title('Espectro de frecuencia')
plt.show()
# Calcular la respuesta en frecuencia
w, h = freqz(np.sqrt(PSD), worN=8000) # Utilizar la raíz cuadrada para obtener la magnitud
w_normalized = w / np.pi # Convertir la frecuencia a radianes por segundo normalizada por pi
magnitude_db = 20 * np.log10(np.abs(h)) # Calcular la magnitud en decibelios
# Graficar la respuesta en magnitud
plt.figure(figsize=(10, 6))
plt.plot(w_normalized, magnitude_db)
plt.title('Estimación de la Respuesta en Magnitud')
plt.xlabel('Frecuencia Normalizada (xπ rad/muestras)')
plt.ylabel('Magnitud (dB)')
plt.grid(True)
plt.show()
# Calcular las frecuencias normalizadas en unidades de omega/pi
frecuencias_normalizadas = frecuencias_welch / np.pi
# Graficar el espectro de potencia promedio en función de omega/pi
plt.figure(figsize=(10, 6))
plt.semilogy(frecuencias_normalizadas, PSD)
plt.text(0.5, 0.9, "Ventaneo con Bartlett", horizontalalignment='center', verticalalignment='center', transform=plt.gca().transAxes, bbox=dict(facecolor='white', alpha=0.8))
plt.title('Espectro de Potencia usando Welch')
plt.xlabel('Frecuencia Normalizada (ω/π)')
plt.ylabel('Densidad espectral de potencia')
plt.grid(True)
plt.show()