Появилось у меня желание снова поковыряться с микроконтроллером и сделать что-нибудь полезное. Цель сформировалась почти сразу, так как в квартире меня кое-что напрягало.
Как известно, компьютерный стол – он же обеденный, чтобы смотреть Дробышевского или читать Гиктаймс / Зелёного Кота / etc. одновременно с ужином. Но есть проблема – из кухни я иду обычно с обеими занятыми руками, обратно тоже,
Всякие датчики присутствия и прохода отмёл сразу – не та точность, нет управления по воле хозяина. Решение найдено в звуковом управлении, голосом. Скажу сразу, я не планировал делать рапознавалку речи, она не нужна здесь. Свет, включающийся по хлопку, описан ещё в Радио-80х, но я так не хотел делать. Получилось своеобразное handsfree, когда руки заняты. Подробности — дальше.
Аппаратная часть.
Была в наличии плата с Atmega32 с кварцем и периферией SEM0007M-32A и россыпь электроники.
Нашёлся микрофончик и операционный усилитель. Для выхода – транзистор в sot32 корпусе на плате, там же реле на 7 Ампер. Всё собрано упихано в коробочку для визиток, реле запараллелено с выключателем, микрофон спрятан под розеткой. Схема банальна, я её даже не рисовал. Используется только один аналоговый вход и один дискретный выход МК. Плата SEM избыточна, но пока пусть так будет.
Плата и неприбранные провода. Потом переделал аккуратнее.
Сам выключатель, микрофон не виден под демонтированной розеткой.
Поиски алгоритма.
Цель: датчик должен реагировать на слово, например «свет!» при минимуме кода.
Задача: выявить командное слово на фоне возможного шума, стуков, щелчков этим же выключателем. То есть просто амплитудный анализ не подходит, а спектральный анализ показал, что гармоник в слове слишком много и они конечно изменяются. Поэтому надо было искать простое решение, но с приемлемой помехозащитой. Можно сделать несколько временно-частотных фильтров и сравнение с образцом слова, но заниматься распознаванием ни к чему. Решено анализировать наличие только гласного звука, например звука «Е».
Звук «Е». Видно много гармоник, из-за этого анализ затруднён.
Звук «А». Спектр выглядит чище, есть главная частота.
Программная часть
Для того, чтобы узнать спектральные составляющие сигнала, можно использовать цифровые фильтры. В Интернете есть неплохая программа для построения цифровых КИХ и БИХ фильтров и вычисления их коэффициентов — там наглядно и код на Си генерируется автоматически.
float ACoef[NCoef+1] = {
0.00000347268864059354,
0.00000000000000000000,
-0.00001389075456237415,
0.00000000000000000000,
0.00002083613184356122,
0.00000000000000000000,
-0.00001389075456237415,
0.00000000000000000000,
0.00000347268864059354
};
float BCoef[NCoef+1] = {
1.00000000000000000000,
-7.09708794063733790000,
22.77454294680684300000,
-43.03321836036351300000,
52.29813665034108500000,
-41.84199842886619100000,
21.53121088556695300000,
-6.52398963450972500000,
0.89383378261285684000
};
Микроконтроллер, возможно и справился бы, но с отладкой были бы проблемы – пододвинуть границы фильтра нелегко – это новые коэффициенты рассчитывать.
После некоторых поисков – остановился на одночастотном Фурье-преобразовании онлайн. То есть классическое дискретное Фурье-преобразование, выполняемое по приходу каждого отсчёта сигнала с частотой дискретизации (1600 Гц), прохода по частотам нет, частота одна, поэтому её легко настроить по RS-232 при наладке. В итоге анализ был сделан для частоты 128 Гц.
Вследствие коротких сэмплов (блоков) и прямоугольного окна — разрешение по частоте получается низким, что даёт избирательную чувствительность в диапазоне 114…140 Гц, а это тот П-фильтр, который и хотелось получить.
Сначала надо понять, где
Сигнал нормализуется к среднему. Для определения уровня интенсивности звука абсолютные значения сигнала также усредняются с константой 1/16, для ВЧ-фильтрации от отдельных полуволн сигнала (это аналог RMS, но проще в вычислениях). Превышение этого уровня над порогом является началом голосовой команды, и начинается последовательный анализ 5-ти блоков по 135 отсчётов (84,3 мс).
// Timer 0 output compare interrupt service routine
interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
a = adc_data[0] << 2 ; // считывание с АЦП и умножение на 4 для улучшения точности.
a0 = (a0*63 + a+ 63) >> 6; // экспон. сглаживание для "0". сход до 10% за 150 отсчётов
ae = (int)(a - a0); //
a = ae; // теперь это нормализованное значение к среднему.
ae = abs(ae);
if (ae < 32) { // обнуление ошибки при целочисленном усреднении
ae = 0;
};
d = (int)((15 * (long int) d + ae + 15) >> 4); // средний эксп. уровень // сход до 10% за 35 отсчётов
if (d > 100) { //превышение порога уровнем сигнала
if (snd == 0) { Yz=0; snd++; } // начинается первый блок
PORTB.1 = 1; // зажигается светодиод индикатор превышения порога
};
.....
На рисунке ниже показан сигнал, уровень сигнала, порог срабатывания и 5 блоков.
Защита от помех
На блоки сигнал разбивается для защиты от импульса – щелчка или стука. У импульса, как известно, равномерная АЧХ, то есть в любой частотной полосе будет ненулевой результат и вероятно, выше порога. Но
Частотное преобразование
В каждом блоке выполняется одночастотное Фурье – преобразование для одной частоты f.
Традиционно, для ускорения вычислений функции sin и cos сделаны табличными и масштабированы до -127..+127. График ниже отображает байтовый массив из 48 значений для sin(x).
Индекс
ps
массива si(ps)
вычисляется из аргумента sin(2 * ? * f * t / T), конечно с закольцовкой внутри одного периода. Индекс pc
для cos(2 * ? * f * t / T) просто сдвинут на 12 позиций вперёд в этом же массиве si
. Результат Y — уровень спектральной линии получается как сумма абсолютных значений реальной и мнимой части за время одного блока. По-правильному надо делать сумму квадратов, и корень, но это жуть для 8-разрядного МК.
В том же таймере:
a_si = (long int) (a * si[ps]) >> 4; // a*sin
a_co = (long int) (a * si[pc]) >> 4; // a*cos
Ysi = Ysi + a_si ; //сумма
Yco = Yco + a_co;
Y = (labs(Ysi) + labs(Yco)) >> 7; // деление на 128 для помещения в int и передачи по rs-232.
В конце каждого блока Y сравнивается с порогом, подсчитывается количество блоков с превышением порога – сработавших блоков. После экспериментов выяснилось, что минимальное количество сработавших блоков это 3 из 5-ти.
Пример спектральной интенсивности в блоках при голосовой команде. Команда прошла.
Три и более сработавших блока интерпретируется как верно принятая команда. Сигнал на дискретном выходе МК инвертируется, включая или выключая свет. Так как весь анализ происходит внутри блоков, задержки срабатывания после последнего блока нет.
Время выполнения вычислений примерно 1600 тактов, таймер вызывается каждые 9000 тактов, так что загруженность МК невысока — есть место для дальнейших экспериментов с распознаванием. Или можно делать законченное решение меньших размеров и на слабом МК.
Контроль правильности алгоритмов вёлся посредством обмена по RS-232 необходимыми переменными (лог) с программкой на VBasic. Частота f и пороги хранятся в eeprom.
В итоге: датчик оказался очень удобен, реагирует на слова с «А», например «Вааау», «Тааам», «Лаайт»,«Мяаау», «Yao-Yao». Громкость — обычная для человеческого разговора. Слово «Свеет» упорно отказывается слушать. Щелчки, стуки дверьми, шаги, льющуюся воду игнорирует. Теперь можно ходить с полными руками чашек и тарелок)).
Комментарии (41)
extempl
09.12.2017 08:59Всё-таки учитывая, что Вы именно идёте, то есть, двигаясь, датчик движения с задержкой сработал бы чище и лучше. И не надо так орать!
rustavelli
09.12.2017 12:05ДД точно удобнее, проще и дешевле. Главное на нём таймаут побольше выкрутить — у меня 7 минут.
Affdey Автор
09.12.2017 23:36не-не, есть во-первых день, когда светло. есть ситуации, когда включать не надо. Есть ситуации требующие длительного наличия света. Орать не приходится.
rustavelli
10.12.2017 00:27Даже у самых дешевых ДД есть датчик освещенности.
есть ситуации, когда включать не надо
— это самая большая проблема. Мне пришлось поверх тупого датчика ДД навернуть расписание, чтобы ночью электричество для основного освещения кухни в принципе отключалось. Остается только ночник на 2 диодных ватта, который горит всегда.
Есть ситуации требующие длительного наличия света
— а вот с этим вообще никаких проблем. Нужно лишь шевельнуться хотя бы раз за 7 минут.
Лучший интерфейс — это отсутствие интерфейса. Надо стремиться, чтобы всё само работало, без участия человека.
DEM_dwg
09.12.2017 10:08Я бы добавил ключевое слово обращения к прибору, Киви свет.
rPman
09.12.2017 23:46не на atmega, тут с трудом прокатило детектирование гласной А
DEM_dwg
10.12.2017 07:44Тогда уж как правильно заметили, надоть сервер…
rPman
10.12.2017 21:26даже 40-ватный сервер, работающий на распознавание речи, может съесть больше энергии, чем экономия на постоянном выключении света
ну или сравнимо.
p.s. правда если делать на базе какого-нибудь android, там можно до 10ват догнать потребление, гугл и яндекс работают непокладая рук.vassabi
10.12.2017 23:15это если вы его добавляете к уже существующим. А если он у вас и так не выключался (домашний NAS или просто комп) — то там задача распознавания на энергопотреблении практически не сказывается.
rPman
11.12.2017 00:11Распознавание онлайн кушает процессорные ресурсы.
У меня есть смутное подозрение, что смартфоны в составе держат какой то аппаратный чип для ускорения этих задач, либо умудряются использовать gpu, так как они умудряются ok google отслеживать без нагрузки.
Affdey Автор
09.12.2017 23:57Если вдруг станет много приборов, у них же микрофоны в разных местах будут. и остальные не будут слышать. этого достаточно.
Если понадобится, адресацию приборов можно сделать тоже гласной, последовательный протокол. И ходить с одним микрофоном-клипсой. И говорить «ИАИ», «АИО», короче как R2D2
aamonster
09.12.2017 11:41На будущее: вместо "одночастотного преобразования фурье" в таких приложениях часто используют алгоритм Гёрцеля — меньше работы.
Ну а исходную задачу (точнее, подобную ей для прихожей) я для себя решил иначе: маломощный светильник с PIR-сенсором — достаточно, чтобы войти, не спотыкаясь. А дальше уже можно включить большой свет. В вашем случае, наверно, будет не оптимально, но приемлемо: выключил большой свет (включился дежурный), взял тарелку и пошёл. Зато шуметь не надо (важно, когда не один дома)
Affdey Автор
09.12.2017 23:40Спасибо за Гёрцеля, посмотрю что это.
маломощный светильник (тоже самодельный) с датчиком внешнего света есть и работает, но здесь не тот случай. Выключить большой свет — надо выйти из кухни на 1,5 метра. Потом возвращаться что ли? ))
AllexIn
09.12.2017 13:42Ваша идея отличная, но только как первый этап.
У меня так:
Простой минимальный анализ звука на наличие в нём слов.
Если слова есть — попытка понять, есть ли в нём Ключевая Стартовая Фраза.
Если решаем что может быть есть — отправка на локальный сервер, где крутится полноценная распознавалка.
Если сервер говорит — что там ключевая стартовая фраза.
Проигрывание приветствия и отправка всего остального потока в рантайме.Affdey Автор
09.12.2017 23:43Круто у вас, алгоритмы или описание есть?
Здесь просто незачем…AllexIn
10.12.2017 13:20Да ничего умного.
Просто анализ звука, если тишина — ничего не делаем.
Если звук есть и по длинне подходит — передаем на сервер.
В вышмате я не очень, поэтому до преобразования фурье и прочих вещей не дошел…Affdey Автор
10.12.2017 13:29Это понятно, на сервере что? какой алгоритм на сервере, чей?
vassabi
10.12.2017 15:00а на сервере можно перекидывать в амазон или гугл
AllexIn
10.12.2017 15:04У Яндекса тоже не плохая распознавалка.
Если вас, конечно, не смущает отдавать прослушку вашего дома каким-то левым чувакам.
Affdey Автор
10.12.2017 17:02Слова амазон, гугл и сервер мне ни о чём ни говорят. Под алгоритмом я понимаю статью с тех. описанием, например в научном/математическом журнале. К сожалению это большая редкость.
rPman
10.12.2017 22:00полагаю алгоритмы тут вторичны, в опенсорсе вроде гуляют неплохие, дороже обойдутся обученные нейроные сети
vlivyur
09.12.2017 14:35Когда у меня стояла такая проблема, то я просто свои выключатели заменил на подобные:
(выпуклый, с краёв тонкий и хорошо заметная клавиша), и повернул их на 90° так, чтоб когда ты заходил в помещение, то, проводя плечом по нему по ходу движения, ты включал свет, а выходя — соответственно наоборот. Даже если вы уже установили умный дом и подключили все выключатели к нему и оно само включает/выключает везде свет, поверьте, такой способ установки выключателя самый удобный. Особенно после того, как я вспомнил, как я в детстве прыгал до выключателя пытаясь попасть в верхний его край.AllexIn
09.12.2017 15:32Те, кто делают умный дом как правило сразу и диммирование фигачат. Соответственно такой выключатель уже и не может использоваться.
rustavelli
09.12.2017 17:30если там димер на 220в вкорячен в выключатель, это не особо умный ход )
AllexIn
09.12.2017 17:37Зачем в выключатель диммер засовывать?
Одно из преиущество умного освещения — нет никакой необходимости таскать по всему помещению 220.rustavelli
09.12.2017 17:39я думал вы как раз про вариант димера под лампы накаливания. Некоторые до сих пор их ставят.
AllexIn
09.12.2017 17:43У меня освещене 220 вольт. Но в выключателе у меня 5вольт. И вообще 220 только под крышей к лампе идет.
Affdey Автор
09.12.2017 23:46Я не могу сильно менять электрику в не своей квартире. Выключатель строенный, 3 в 1. в узкую клавишу, которая выше плеча на 12 см, попасть сложно в темноте.
icetinte
09.12.2017 20:54А можете подсказать более подробно про микрофон? С какого расстояния ловит звук? Я хочу похожее подключить к Raspberry Pi и пытаюсь понять какой микрофон нужен мне, чтобы звук улавливался по квартире.
Affdey Автор
09.12.2017 23:32микрофон — это маленький динамик, диаметр 25 мм, они были тетрисах. Ловит хорошо, резкий звук голосом с двух метров. я программно делал пороги, большая чувствительность не нужна.
Affdey Автор
10.12.2017 01:13Напрямую не подойдёт почти никакой, только через усилитель. ОУ стоил 17 рублей.
vassabi
а на телевизор\радио реагирует? не будет мигать на фразу «папа! зачем тут эта штука прикручена!»?
Affdey Автор
Только если разговаривать в непосредственной близости и с эстонским акцентом. длительность должна быть более 250 мс, это растянутая гласная.
MTyrz
(Капризным голосом)
— Ну па-апа-а!..
Misaka10032
Главное в такой ситуации — не быть эпилептиком. А то и скончаться недолго.