Я программировал мультимедийные системы для автомобилей. Это были проигрыватели музыки на основе микроконтроллеров. И между делом у меня появилась мечта сделать сонар из музыкальной колонки.

Постановка задачи
Собрать прототип акустического сонара. Соединить микроконтроллер STM32, аудиокодек WM8731 и SD карту в один прототип. Сделать прошивку на Audio Loop Back. Микроконтроллер соединить с аудиокодеком по I2S и I2C. Прошивка рассчитывает зондирующий ЛЧМ импульс и отправляет его на спикер. Тем временем микрофон в фоновом режиме записывает излученный импульс и эхо от него. Затем прошивка вычисляет свертку зондирующего импульса с принятым эхо сигналом. Результат свёртки записывается на SD карту в виде отдельного файла. Поэкспериментировать с разными зондирующими импульсами. В идеале каждый зондирующий импульс должен быть уникальным.

Теория

Как известно скорость звука это 331 метр/с. Если умножить скорость звука на TOF и поделить на два, то получится расстояние до предмета.

Dist = V_{sound} \frac{TOF}{2} ;   \frac{[m] }{[s]} \frac{[s]}{2}=[m]  \qquad   \qquad (1)

Учитывая скорость звука 331 метр/с получаем, что разрешение по дальности dx косвенно зависит от частоты дискретизации звука

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

\delta R =\frac{V_{sound} \tau_{и}}{2 } \quad \quad \quad (2) \quad\quad\\ BW\cong  1/\tau_{и} \quad \quad (3) \quad\quad\\  \delta R =\frac{V_{sound}}{2 \cdot  BW} \quad \quad \quad (4) \\

Например, для ЛЧМ c параметрами Fstart=500 Hz Fend=5kHz и скорости звука 331 м/c разрешение равно 3см.

Аппаратная часть

В прошлом тексте я использовал два смартфона для сбора данных. Первый проигрывал огромный wav файл с зондирующими ЛЧМ импульсами, второй смартфон просто записывал всё вокруг рядом. Такой подход затруднял понять, где именно на двух звуковых дорожках эхо от конкретного импульса. Поэтому я решил написать одну прошивку для одного прототипа, чтобы специально собирать сонарные данные.

В качестве отладочной платы я выбрал PCB DevEBox_V3_0. Эта учебная плата хороша тем, что на ней есть SD карта, подключенная по интерфейсу SDIO. Надо собрать прототип согласно вот этой подсказке.

На микроконтроллер STM32F407VG я загрузил прошивку аналогового LoopBack проигрывателя. Это такая прошивка, которая может одновременно воспроизводить и записывать WAV файл. Про её разработку у меня есть отдельный текст.

Зондирующие импульсы я проигрывал 8 Watt-ными компьютерными колонками. Модель Defender 2.0 Speaker System Aurora S8 (SN 2293315072403158). Колонки питались от USB-A порта. Эхо записывал петличным микрофоном.

Программная часть

При записи эхо сигнала надо реализовать непрерывную запись звуковой дорожки длительностью 1-2 секунды. Данные надо непрерывно записывать в SD карту и уже затем считать свёртку по каждому смещению. У меня уже был текст про то как делать аудио LoopBack. Называется Full Duplex I2S на STM32. Надо посылать реальные сонарные сигналы и записывать эхо от них. Далее на PC пропустить записанный сигнал через программный консольный коррелятор, опорный сигнал которого равен излучаемому зондирующему сигналу. Получится свертка, показывающая расстояния до целей. Коррелятором выступает обыкновенный FIR фильтр высокого порядка. Всё просто.

Подготовка зондирующего импульса

У меня написана отдельная консольная утилита для синтезирования ЛЧМ импульсов. Называется sonar.exe. Утилита при запуске разворачивает на экране интерфейс командной строки и можно текстовыми командами сконфигурировать параметры зондирующего импульса.

CLI команда

Пояснение

dds_set_chirp 1 10 000 450 10 000 0.05

Присвоить первому DDS настройки для ЛЧМ сигнала F1=450 Hz; F2=10kHz; Duration: 50ms

ddssfr 1 48 000

Задать частоту дискретизации 48kHz для первого DDS

wavsf 2 48000

Задать частоту дискретизации 48kHz для второго WAV файла

wav_duration 2 2

Задать длительность 2 секунды для второго WAV файла

wav_gen1ch_from_dds 2 out.wav 1

Сгенерировать WAV файл out.wav на основе настроек из первого DDS

wav_shift_right out.wav 0.25

Сдвинуть вправо сигнал из WAV файла на 0.25 секунд

Можно вводить CLI команды вручную, а можно набрать их автоматически одним кликом на bat файл. Данный скрипт синтезирует желаемый цифровой ЛЧМ импульс, который начинается от 450 Hz и заканчивается 10kHz. Имеет ширину 50ms.

cls
set batdir=%~dp0
echo batdir=%batdir%
cd %batdir%

set wav_num=2

set options=
set options=%options%; ddp 1 0.05
set options=%options%; dds_set_chirp 1 10000 450 10000 0.05
set options=%options%; ddssfr 1 48000
set options=%options%; wavsf %wav_num% 48000
set options=%options%; wav_duration %wav_num% 2
set options=%options%; wav_gen1ch_from_dds %wav_num% out.wav 1 
set options=%options%; ll FileAPI debug
set options=%options%; wav_shift_right out.wav 0.25 

%batdir%sonar.exe %options%

В прошивке зондирующий ЛЧМ импульс рассчитывается вот этой функцией. По сути подготовка импульса сводится к формуле вычисления одного семпла calc_chirp_sample


/*
  cur_time_s - up time in s
  signal_diration_s - signal duration
  f_2_hz - maximum value of signal frequency.
  f_1_hz - initial signal frequency
  des_amplitude - signal amplitude
  phase_rad -  initial phase.
 */
float calc_chirp_sample(float cur_time_s,
                        float f_2_hz,
                        float f_1_hz,
                        float phase_rad,
                        float amplitude,
                        float signal_diration_s) {
    float amplitude_scaled = 0.0f;
    float b = 0.0f;
    if(0.0f < signal_diration_s) {
        float bandwith_hz = f_2_hz - f_1_hz;
        b = bandwith_hz / signal_diration_s;

        float argument_rad = phase_rad;
        argument_rad += M_2PI * (f_1_hz * cur_time_s + (b * cur_time_s * cur_time_s) / 2.0f);

        if(signal_diration_s < cur_time_s) {
            amplitude = 0.0f;
        }

        float cos_arg = (M_2PI * cur_time_s) / signal_diration_s;
        float hamming_window = 0.46f - 0.46f * cosf(cos_arg);
        amplitude_scaled = amplitude * sinf(argument_rad) * hamming_window;
    }
    return amplitude_scaled;
}

Лог синтеза импульса

Импульс помещается в wav файл длительностью 1.1 секунды с определенным в скрипте отступом от начала файла с частотой дискретизации 48kHz.

На слух этот импульс напоминает лопающиеся мыльные пузыри. В частотной области спектр ЛЧМ сигнала — это прямоугольник со сглаженными краями.

ЛЧМ сигнал хорош тем, что у него очень ярко выраженная автокорреляционная функция. Вы можете построить ее при помощи всё той же утилиты sonar.exe. Данный скрипт позволяет экспериментировать с АКФ различных ЛЧМ сигналов.

 АКФ различных ЛЧМ сигналов
cls
set batdir=%~dp0
echo batdir=%batdir%
cd %batdir%

set options=

set wav_num=2
set sonar_num=0

set ampletide=10000
set freq1=400
set freq2=9000
set chip_dur_s=0.05 

set options=
set options=%options%; ddp 1 0.05 
set options=%options%; dds_set_chirp 1 %ampletide% %freq1% %freq2% %chip_dur_s%
set options=%options%; ddssfr 1 48000 
set options=%options%; wavsf %wav_num% 48000 
set options=%options%; wav_duration %wav_num% 2 
set options=%options%; ll WAV info 
set options=%options%; ll FileAPI info 
set options=%options%; wav_generate_signal %wav_num% 1 
set options=%options%; wav_shift_right2 %wav_num% 0.5 
set options=%options%; sonar_config %sonar_num%  %chip_dur_s% %freq1% %freq2% 
set options=%options%; sonar_chirp_correlation %sonar_num% CHIRP_400_9000_dt50_A1000.wav 
set options=%options%; sonar_plot_convolution %sonar_num% 3 7 


%batdir%sonar.exe %options%

График АКФ рисуется отдельным Python скриптом.

Я выбрал, что в качестве зондирующего импульса у меня в экспериментах будет ЛЧМ сигнал длительностью 30ms, амплитудой 30 000 PCM, начальной частотой 1kHz, конечной частотой 10kHz. У такого сигнала хорошая автокорреляционная функция.

Если записывать на микрофон этот импульс, то получается вот такой принятый сигнал.

Иной раз эхосигнал можно увидеть даже на графике сигнала записи.

Однако есть более точный способ определить момент времени прихода эхо. Это и есть корреляция записи с опорным зондирующими сигналом.

Корреляция реальных записанных эхо сигналов.

Вот я прямо в комнате записал 24 эхо сигнала на зондирующий импульс. Затем вычислил корреляцию и построил на одном графике в виде точек с прозрачностью 10%. Можно наблюдать локальные максимумы корреляции.

Далее я попробовал испытать сонар на импровизированном полигоне.


Результат корреляции удобнее анализировать в логарифмическом масштабе. Так проще зарегистрировать локальные максимумы свертки записи эхосигнала с опорных сигналом в FIR фильтре (корреляторе). Вот эту запись я выполнил во дворе.

Некоторые измерения приблизительно соответствуют расстоянию до забора.

Зондирующий импульс в виде модулированного кодом Баркера BPSK сигнала

В качестве зондирующих импульсов можно еще применить модулированые кодом Баркера BPSK пакеты. Вот так выглядит BPSK пакет модулированный Баркер кодом длинной 13 чипов: 1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1. Тут несущая частота 2kHz, на один чип 6 периодов несущей. Длинна импульса 39ms.

На слух этот сигнал похож на квакание лягушки. Коды Баркера хороши тем, что что при автокорреляции боковые лепестки имеют минимальную высоту.

автокорреляция кода Баркера
автокорреляция кода Баркера

Корреляция импульса с реальной записью эха показала, как будто бы эхо от деревьев на расстоянии 24,5 метров.

BPSK импульс методично каждый раз отражался именно от берёзы за забором. При этом сам забор не так выразительно выглядит как в случае с ЛЧМ.

В чем трудность разработки акустического сонара?

1) Получение корреляции это очень затратная с вычислительной точки зрения операция. Для обработки 1,1 секунды на 48kHz, STM32F407VG микроконтроллер на 168 МHz вычислят корреляцию с 30ms опорным сигналом 13 минут! Это, по сути, пропустить 52800 семплов через FIR фильтр порядка 1440. Это очень долго. Ситуацию можно улучшить, если отправить wav запись эхо сигнала на одноплатный компьютер или делать обработку на FPGA. Дело бы улучшил микроконтроллер с аппаратными корреляторами. Еще можно ускорить вычисления пожертвовав энергетикой излучаемого сигнала. Чем короче длительность ЛЧМ импульса, тем меньше надо делать вычислений, так как порядок коррелятора прямо пропорционален длительности зондирующего импульса. Однако короткие ЛЧМ импульсы не позволяют чтобы то ни было обнаружить. Чем короче ЛЧМ импульс, тем менее он эффективен. На коротком ЛЧМ импульсе даже не видно локальных максимумов как таковых. Трудно выделить локальные максимумы на графике свертки.

2) На малых расстояниях зондирующие импульсы на основе кодов Баркера нет так эффективны. Их боковые лепестки перебивают все отражения от близких целей. Для регистрации на малых расстояниях лучше выбрать ЛЧМ импульсы.

3) По факту звуковые отражения приходят только от строго перпендикулярных поверхностей (забор, листья, стены). Всё остальное сонар не видит.

Что можно улучшить?

Логическим развитием акустических сонаров было бы создание FPGA SoC, который бы отправлял попарно отличные зондирующие импульсы с периодом 0,1 - 0,2 сек и многочисленными аппаратными корреляторами в реальном времени вычислял бы свертки, показывая результат на графическом экране. Однако это сделать весьма трудно, так как надо привлекать FPGA технологии.

Итоги

Мне удалось построить прототип сонара из микроконтроллера, аудиокодека и SD карты. Разработана прошивка для микроконтроллерного прибора, который может одновременно воспроизводить и записывать звук. Удалось научиться синтезировать WAV файлы с различными зондирующими импульсами внутри: ЛЧМ сигналы, кодированные BPSK пакеты.

Написана утилита sonar.exe для вычисления корреляций конкретных записей на входе c опорным сигналом. Проведены эксперименты по измерению дальности до окружающих предметов получившимся сонаром, показавшие концептуальную работоспособность прототипа.

Вот так просто и незатейливо можно отлаживать радиолокационные алгоритмы буквально из подручных материалов на примере привычного нам всем акустического диапазона. Всё это открывает дорогу для дальнейших исследований в области радиолокации и гидроакустики.

Словарь

Акроним

Расшифровка

ЦОС

Цифровая обработка сигналов

ЛЧМ

Линейная частотная модуляция

DDS

direct digital synthesis

TOF

Time-of-Flight

FIR

finite impulse response

Ссылки

Название

URL

Сонар из Диктофона

https://habr.com/ru/articles/868672/

Обработка звука в реальном времени (или Full Duplex I2S на STM32)

https://habr.com/ru/articles/1058052/

Аналитика по сонару

https://docs.google.com/spreadsheets/d/1twizxcenUCPF2iNNpEq3qrrdMX3we23pn7XMsVpdRhA/edit

Проигрыватель WAV файлов на STM32

https://habr.com/ru/articles/1051842/

Диктофон на микроконтроллере (WM8731 + I2S + STM32 + SDIO + FAT16)

https://habr.com/ru/articles/1054896/

STM32F4XX M STM32F407VGT6

https://stm32-base.org/boards/STM32F407VGT6-STM32F4XX‑M

Принципы работы сонаров и подводная акустика: как, зачем и почему @akuzmin

https://habr.com/ru/articles/191594/

Разрешающая способность по дальности

https://www.radartutorial.eu/01.basics/rb18.ru.html

Модуль подводного ультразвукового дальномера. Часть третья @MShekunov

https://habr.com/ru/articles/497654/

Модуль подводного ультразвукового дальномера @MShekunov

https://habr.com/ru/articles/440222/

Как работают эхолоты

https://buydeeper.ru/kak‑rabotajut‑jeholoti

#18 Audio codec — Floating point hardware

https://www.youtube.com/watch?v=mTAcDftyYBs

Утилита генератор wav файла с ЛЧМ и приложение консольный сонар

https://github.com/aabzel/Artifacts/tree/main/sonar

Чип AudioСodec(а) WM8731 (или (ADC/DAC)*2 из iPod(а))

https://habr.com/ru/articles/703588/

Вопросы

1) Существуют ли в продаже готовые учебные электронные платы с SD картой, STM32F4 микроконтроллером, микросхемой простого аудиокодека и графическим экраном?
2) Можно ли радарные сигналы хранить в WAV файле?
5) Существует ли отдельный специальный бинарный формат данных для хранения свёрток сигналов? Формат для хранения результата коррелляции.
6) Существует ли утилита для сравнения двух wav файлов? Чтобы находить в двух WAV файлах одинаковые участки звука.
7) Какие параметры ЛЧМ сигнала следует выбрать для сонара в воздушной среде?
8) Раз уж в ЛЧМ важна именно частота зондирующего сигнала, то можно ли использовать однобитные зондирующие импульсы? Например, чтобы излучать их не аудиокодеком, а пьезокерамическим звуко‑излучателем от GPIO или формировать отправкой битового потока по SPI в режиме DMA.
9) Существуют ли в продаже микроконтроллеры с аппаратными корреляторами глубиной 2000+ семплов по 16-бит каждый? Это бы очень пригодилось для цифровой связи, радиолокации, дефектоскопов, УЗИ, сонаров и прочих ЦОС приложений.

Комментарии (6)


  1. MShekunov
    31.07.2026 04:49

    7. Обычно, база ЛЧМ - это около 30% центральной частоты. Например, центральная - 10кГц, тогда ваш сигнал от 8.5 до 11.5кГц. Но я говорю про гидроакустику, и это не железное правило, а скорее особенность излучателей, которые достаточно узкополосные. Думаю, вам тоже следует придерживаться этих ограничений, потому что ваш излучатель на 1 и 10 кГц будет иметь разную диаграмму направленности.

    8. Если генерить сигнал для пьезика на высокой частоте - то так и надо делать, дёргать пином драйвер пьезика. А уже потом электрически драйвер согласовывать с излучателем.

    9. Мы используем H7 серию. Но честных и чистых 16 бит там не добьётесь. Да и не надо. 14 бит дают приемлемый динамический диапазон. Ддя ваших экспериментов этого процика - за глаза. Для обычных сонаров нам хватает L412, который при хорошей оптимизации тянет ЛЧМ реалтайм.

    P.S. когда приводите значения скорости звука, уточняйте, пожалуйста, для какой среды эти значения.


    1. aabzel Автор
      31.07.2026 04:49

      Обычно, база ЛЧМ - это около 30% центральной частоты. Например, центральная - 10кГц, тогда ваш сигнал от 8.5 до 11.5кГц. 

      А какую указать длительность CHIRP импульса?


    1. aabzel Автор
      31.07.2026 04:49

      Обычно, база ЛЧМ - это около 30% центральной частоты. Например, центральная - 10кГц, тогда ваш сигнал от 8.5 до 11.5кГц. 

      Я попробовал и такие настройки ЛЧМ-импульса.
      Результат примерно то же что и прежде. Хорошо видно забор


      1. aabzel Автор
        31.07.2026 04:49

        Тот же ЛЧМ только без окна Хэмминга. Радиоголограмма выглядит выразительнее.


  1. Dozer88
    31.07.2026 04:49

    У меня как-то были похожие мысли. Если взять длинный код (например, коды Голда), постоянно его передавать и принимать (может даже без несущей частоты), то можно в любой момент времени увидеть все отраженные сигналы. В STM32G431 (наверняка и в других) есть аппаратный свёрточный фильтр

    А еще, если использовать несколько излучателей/приемников, можно управлять направлением луча, сканируя пространство


    1. MShekunov
      31.07.2026 04:49

      длинные коды очень плохо себя ведут при эффекте Допплера. И чем длиннее код, тех хуже корреляция при том же допплеровском сдвиге. Нужно делать множество корреляторов для каждого частотного сдвига.