""" Lab024A. Первый приём реальных IQ-сэмплов с Pluto+. Схема: антенна 40–860 МГц -> RX1 Передатчики TX1 и TX2 не используются. """ from pathlib import Path import json import adi import matplotlib.pyplot as plt import numpy as np # --------------------------------------------------------------------- # Параметры приёмника # --------------------------------------------------------------------- PLUTO_URI = "ip:192.168.2.1" CENTER_FREQUENCY_HZ = 100_000_000 SAMPLE_RATE_HZ = 2_400_000 RX_BANDWIDTH_HZ = 2_000_000 RX_BUFFER_SIZE = 262_144 OUTPUT_DIRECTORY = Path("data/raw") IQ_FILE_PATH = OUTPUT_DIRECTORY / "lab024a_pluto_rx_100mhz.npy" METADATA_FILE_PATH = OUTPUT_DIRECTORY / "lab024a_pluto_rx_100mhz.json" SPECTRUM_FILE_PATH = OUTPUT_DIRECTORY / "lab024a_pluto_rx_100mhz_spectrum.png" def calculate_spectrum( samples: np.ndarray, sample_rate_hz: float, center_frequency_hz: float, ) -> tuple[np.ndarray, np.ndarray]: """ Рассчитывает спектр принятого комплексного IQ-сигнала. Возвращает: frequencies_hz — абсолютные радиочастоты; power_db — относительная мощность спектра в дБ. """ sample_count = len(samples) window = np.hanning(sample_count) windowed_samples = samples * window spectrum = np.fft.fftshift(np.fft.fft(windowed_samples)) power = np.abs(spectrum) ** 2 power_db = 10.0 * np.log10(power + 1e-12) power_db -= np.max(power_db) baseband_frequencies_hz = np.fft.fftshift( np.fft.fftfreq(sample_count, d=1.0 / sample_rate_hz) ) absolute_frequencies_hz = ( center_frequency_hz + baseband_frequencies_hz ) return absolute_frequencies_hz, power_db def main() -> None: OUTPUT_DIRECTORY.mkdir(parents=True, exist_ok=True) print("Подключение к Pluto+...") sdr = adi.Pluto(uri=PLUTO_URI) # Используем только первый приёмный канал RX1. sdr.rx_enabled_channels = [0] sdr.sample_rate = SAMPLE_RATE_HZ sdr.rx_lo = CENTER_FREQUENCY_HZ sdr.rx_rf_bandwidth = RX_BANDWIDTH_HZ # Автоматическая регулировка усиления. sdr.gain_control_mode_chan0 = "slow_attack" sdr.rx_buffer_size = RX_BUFFER_SIZE print() print("Параметры приёмника:") print(f" URI: {PLUTO_URI}") print(f" Центральная частота: {sdr.rx_lo / 1e6:.3f} МГц") print(f" Частота дискретизации: {sdr.sample_rate / 1e6:.3f} Мвыб/с") print(f" Полоса RX: {sdr.rx_rf_bandwidth / 1e6:.3f} МГц") print(f" Режим усиления: {sdr.gain_control_mode_chan0}") print(f" Размер буфера: {sdr.rx_buffer_size} отсчётов") print() print("Получение IQ-сэмплов...") # Первый буфер после перенастройки иногда содержит переходный процесс. _ = sdr.rx() # Второй буфер сохраняем и анализируем. samples = np.asarray(sdr.rx(), dtype=np.complex64) print("IQ-сэмплы получены.") np.save(IQ_FILE_PATH, samples) mean_value = np.mean(samples) rms_value = np.sqrt(np.mean(np.abs(samples) ** 2)) peak_value = np.max(np.abs(samples)) metadata = { "pluto_uri": PLUTO_URI, "center_frequency_hz": int(sdr.rx_lo), "sample_rate_hz": int(sdr.sample_rate), "rx_bandwidth_hz": int(sdr.rx_rf_bandwidth), "gain_control_mode": sdr.gain_control_mode_chan0, "sample_count": int(len(samples)), "sample_dtype": str(samples.dtype), "mean_i": float(np.real(mean_value)), "mean_q": float(np.imag(mean_value)), "rms": float(rms_value), "peak": float(peak_value), } with METADATA_FILE_PATH.open("w", encoding="utf-8") as metadata_file: json.dump(metadata, metadata_file, ensure_ascii=False, indent=4) frequencies_hz, power_db = calculate_spectrum( samples=samples, sample_rate_hz=float(sdr.sample_rate), center_frequency_hz=float(sdr.rx_lo), ) plt.figure(figsize=(12, 6)) plt.plot(frequencies_hz / 1e6, power_db) plt.title("Lab024A. Спектр сигнала, принятого Pluto+") plt.xlabel("Частота, МГц") plt.ylabel("Относительная мощность, дБ") plt.grid(True) plt.ylim(-100, 5) plt.tight_layout() plt.savefig(SPECTRUM_FILE_PATH, dpi=150) plt.show() print() print("Статистика:") print(f" Количество сэмплов: {len(samples)}") print(f" Тип данных: {samples.dtype}") print(f" Среднее I: {np.real(mean_value):.3f}") print(f" Среднее Q: {np.imag(mean_value):.3f}") print(f" RMS: {rms_value:.3f}") print(f" Пиковая амплитуда: {peak_value:.3f}") print() print("Созданы файлы:") print(f" IQ: {IQ_FILE_PATH}") print(f" Метаданные:{METADATA_FILE_PATH}") print(f" Спектр: {SPECTRUM_FILE_PATH}") print() print("Lab024A выполнена успешно.") if __name__ == "__main__": main()