Перейти к содержанию

10. Анализ записанного сигнала в C++

Цель раздела

Показать, как офлайн-анализ IQ-файла реализуется на C++ и почему такой подход важен для высокопроизводительных DSP-приложений.

1. Зачем в курсе C++

Хотя для первого анализа удобнее MATLAB и Python, C++ остаётся важным инженерным инструментом, потому что позволяет:

  • обрабатывать большие файлы;
  • создавать быстрые утилиты;
  • готовить код для интеграции в реальные проекты;
  • строить высокопроизводительные инструменты анализа и управления.

Дальше C++ может стать основой сервисных приложений, серверных компонентов и DSP-утилит.

2. Задачи этапа

В первом блоке C++ используется в облегчённом режиме. Студент должен:

  • прочитать IQ-файл;
  • сформировать комплексный массив;
  • выполнить базовый спектральный анализ;
  • оценить частоту основного тона;
  • понять архитектуру простой консольной DSP-утилиты.

3. Что должна делать программа

Минимальная программа должна:

  1. Открыть файл.
  2. Прочитать чередующиеся данные I/Q.
  3. Преобразовать их в комплексный массив.
  4. Выполнить FFT или эквивалентный спектральный анализ.
  5. Найти максимум спектра.
  6. Вывести оценку частоты пика.

4. Что можно использовать

На первом этапе возможны два подхода.

Вариант 1. Учебный

Реализовать простое ДПФ/FFT вручную или в упрощённом виде.

Вариант 2. Практический

Использовать внешнюю библиотеку:

  • FFTW
  • Intel IPP
  • KissFFT
  • другую подходящую библиотеку FFT

Для первого блока допустим упрощённый демонстрационный вариант.

5. Пример общей структуры программы

#include <iostream>
#include <fstream>
#include <vector>
#include <complex>
#include <cstdint>

int main() {
    const char* filename = "tone_capture_iq.bin";
    std::ifstream file(filename, std::ios::binary);

    if (!file) {
        std::cerr << "Cannot open file\n";
        return 1;
    }

    std::vector<int16_t> raw;
    int16_t value;
    while (file.read(reinterpret_cast<char*>(&value), sizeof(value))) {
        raw.push_back(value);
    }

    if (raw.size() < 2) {
        std::cerr << "Not enough data\n";
        return 1;
    }

    std::vector<std::complex<double>> x;
    x.reserve(raw.size() / 2);

    for (size_t k = 0; k + 1 < raw.size(); k += 2) {
        double i = static_cast<double>(raw[k]);
        double q = static_cast<double>(raw[k + 1]);
        x.emplace_back(i, q);
    }

    std::cout << "Loaded complex samples: " << x.size() << "\n";

    // Здесь можно добавить FFT и поиск пика

    return 0;
}

5a. Версия курса: законченная утилита с ДПФ

blocks/block_01_intro_sdr/cpp/iq_reader_example.cpp дополняет эту структуру учебным вариантом: простое ДПФ по 4096 отсчётам и поиск пика с учётом отрицательных частот. На том же тестовом тоне 200 кГц, что и на странице 09:

g++ -std=c++17 -O2 -o iq_reader_example blocks/block_01_intro_sdr/cpp/iq_reader_example.cpp
./iq_reader_example capture.ci16 2400000
Loaded complex samples: 65536
DFT length: 4096, bin width: 585.938 Hz
Peak offset from the tuning frequency: 199805 Hz

Ответ совпадает с Python-скриптом до бина. Простому ДПФ нужно 4096 × 4096 ≈ 16,8 млн комплексных умножений, здесь это заняло около 2,7 с; FFT нужно около 4096 × log2(4096) / 2 ≈ 25 000 бабочек. Этот разрыв: причина, по которой любой реальный инструмент использует библиотеку FFT и по которой курс строит в аппаратуре именно FFT, а не ДПФ (Лабораторная 8.14).

6. Что должен понять студент

На этом этапе важно не столько написать идеальную DSP-библиотеку, сколько понять:

  • как устроен формат хранения IQ;
  • как строится конвейер обработки на C++;
  • как комплексные данные представлены в памяти;
  • почему C++ полезен для задач, где важна производительность;
  • как офлайн-анализ можно оформить в самостоятельную утилиту.

7. Какие результаты нужны в первом блоке

Достаточно получить:

  • успешное чтение файла;
  • формирование комплексного сигнала;
  • базовое вычисление спектра;
  • оценку частоты основного пика;
  • вывод параметров в консоль.

8. Практическая ценность этапа

Даже простая программа на C++ важна: она показывает студенту переход от учебного анализа к прикладной разработке.

Так в реальных проектах появляются:

  • анализаторы записей;
  • сервисные утилиты;
  • автономные DSP-модули;
  • серверные компоненты SDR-систем.

9. Что включить в отчёт

Рекомендуется включить:

  • краткое описание структуры программы;
  • фрагмент кода чтения IQ-файла;
  • способ вычисления спектра;
  • оценённую частоту пика;
  • вывод о применимости C++ для обработки сигналов.

10. Выводы

После этого этапа студент должен:

  • понимать, как читать IQ-данные на C++;
  • видеть роль C++ в высокопроизводительной обработке сигналов;
  • понимать, как из учебного анализа вырастает настоящая инженерная утилита.