Здравствуй, Сообщество!

Появилось у меня желание снова поковыряться с микроконтроллером и сделать что-нибудь полезное. Цель сформировалась почти сразу, так как в квартире меня кое-что напрягало.

Как известно, компьютерный стол – он же обеденный, чтобы смотреть Дробышевского или читать Гиктаймс / Зелёного Кота / etc. одновременно с ужином. Но есть проблема – из кухни я иду обычно с обеими занятыми руками, обратно тоже, ведь чашки копятся по 3 шт. Включать и выключать свет на кухне (выключатель тройной – кухня/ванна/туалет) приходится плечом, носом, мизинцем. То есть неудобно никак, а переставить ниже нельзя. Возникла задача управлять как-то дистанционно.

Всякие датчики присутствия и прохода отмёл сразу – не та точность, нет управления по воле хозяина. Решение найдено в звуковом управлении, голосом. Скажу сразу, я не планировал делать рапознавалку речи, она не нужна здесь. Свет, включающийся по хлопку, описан ещё в Радио-80х, но я так не хотел делать. Получилось своеобразное handsfree, когда руки заняты. Подробности — дальше.

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


Была в наличии плата с Atmega32 с кварцем и периферией SEM0007M-32A и россыпь электроники.

image

Нашёлся микрофончик и операционный усилитель. Для выхода – транзистор в sot32 корпусе на плате, там же реле на 7 Ампер. Всё собрано упихано в коробочку для визиток, реле запараллелено с выключателем, микрофон спрятан под розеткой. Схема банальна, я её даже не рисовал. Используется только один аналоговый вход и один дискретный выход МК. Плата SEM избыточна, но пока пусть так будет.

image
Плата и неприбранные провода. Потом переделал аккуратнее.

image
Сам выключатель, микрофон не виден под демонтированной розеткой.

Поиски алгоритма.


Цель: датчик должен реагировать на слово, например «свет!» при минимуме кода.
Задача: выявить командное слово на фоне возможного шума, стуков, щелчков этим же выключателем. То есть просто амплитудный анализ не подходит, а спектральный анализ показал, что гармоник в слове слишком много и они конечно изменяются. Поэтому надо было искать простое решение, но с приемлемой помехозащитой. Можно сделать несколько временно-частотных фильтров и сравнение с образцом слова, но заниматься распознаванием ни к чему. Решено анализировать наличие только гласного звука, например звука «Е».

image
Звук «Е». Видно много гармоник, из-за этого анализ затруднён.

image
Звук «А». Спектр выглядит чище, есть главная частота.

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


Для того, чтобы узнать спектральные составляющие сигнала, можно использовать цифровые фильтры. В Интернете есть неплохая программа для построения цифровых КИХ и БИХ фильтров и вычисления их коэффициентов — там наглядно и код на Си генерируется автоматически.

Но я от цифровых фильтров отказался
Для приемлемой фильтрации (4 и более порядка) получались много коэффициентов, да ещё и float. Примерно вот так, плюс все расчёты фильтра во float:

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/64. Код приведён ниже.

Сигнал нормализуется к среднему. Для определения уровня интенсивности звука абсолютные значения сигнала также усредняются с константой 1/16, для ВЧ-фильтрации от отдельных полуволн сигнала (это аналог RMS, но проще в вычислениях). Превышение этого уровня над порогом является началом голосовой команды, и начинается последовательный анализ 5-ти блоков по 135 отсчётов (84,3 мс).

Часть кода таймера для обработки сигнала. Частота таймера 1600 Гц
// 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 блоков.

image

Защита от помех


На блоки сигнал разбивается для защиты от импульса – щелчка или стука. У импульса, как известно, равномерная АЧХ, то есть в любой частотной полосе будет ненулевой результат и вероятно, выше порога. Но волос длин, да ум импульс короток. То есть в следующем блоке импульса уже не будет, значит и уровень в частотной полосе будет ниже порога. Одновременно с этим преимуществом, короткие блоки дают низкое разрешение по частоте. Поэтому некоторые частотные отличия в сигнале всё равно попадают в выбранную частотную линию.

Частотное преобразование


В каждом блоке выполняется одночастотное Фурье – преобразование для одной частоты f.

Традиционно, для ускорения вычислений функции sin и cos сделаны табличными и масштабированы до -127..+127. График ниже отображает байтовый массив из 48 значений для sin(x).

image

Индекс 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-ти.

image
Пример спектральной интенсивности в блоках при голосовой команде. Команда прошла.

Три и более сработавших блока интерпретируется как верно принятая команда. Сигнал на дискретном выходе МК инвертируется, включая или выключая свет. Так как весь анализ происходит внутри блоков, задержки срабатывания после последнего блока нет.

Время выполнения вычислений примерно 1600 тактов, таймер вызывается каждые 9000 тактов, так что загруженность МК невысока — есть место для дальнейших экспериментов с распознаванием. Или можно делать законченное решение меньших размеров и на слабом МК.

Контроль правильности алгоритмов вёлся посредством обмена по RS-232 необходимыми переменными (лог) с программкой на VBasic. Частота f и пороги хранятся в eeprom.

В итоге: датчик оказался очень удобен, реагирует на слова с «А», например «Вааау», «Тааам», «Лаайт»,«Мяаау», «Yao-Yao». Громкость — обычная для человеческого разговора. Слово «Свеет» упорно отказывается слушать. Щелчки, стуки дверьми, шаги, льющуюся воду игнорирует. Теперь можно ходить с полными руками чашек и тарелок)).

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


  1. vassabi
    09.12.2017 00:12

    а на телевизор\радио реагирует? не будет мигать на фразу «папа! зачем тут эта штука прикручена!»?


    1. Affdey Автор
      09.12.2017 23:34

      Только если разговаривать в непосредственной близости и с эстонским акцентом. длительность должна быть более 250 мс, это растянутая гласная.


      1. MTyrz
        10.12.2017 19:00
        +1

        (Капризным голосом)
        — Ну па-апа-а!..


    1. Misaka10032
      09.12.2017 23:37

      Главное в такой ситуации — не быть эпилептиком. А то и скончаться недолго.


  1. x893
    09.12.2017 04:48

    Ноги наверняка свободны — можно их научить ВКЛ/ВЫКЛ делать.


    1. Affdey Автор
      10.12.2017 00:08

      Выключатель на уровне уха. Если я научусь с полной чашкой кофе и бутербродами в руках делать это ногами — напишу в спортивный паблик))


  1. extempl
    09.12.2017 08:59

    Всё-таки учитывая, что Вы именно идёте, то есть, двигаясь, датчик движения с задержкой сработал бы чище и лучше. И не надо так орать!


    1. rustavelli
      09.12.2017 12:05

      ДД точно удобнее, проще и дешевле. Главное на нём таймаут побольше выкрутить — у меня 7 минут.


      1. Affdey Автор
        09.12.2017 23:36

        не-не, есть во-первых день, когда светло. есть ситуации, когда включать не надо. Есть ситуации требующие длительного наличия света. Орать не приходится.


        1. rustavelli
          10.12.2017 00:27

          Даже у самых дешевых ДД есть датчик освещенности.

          есть ситуации, когда включать не надо
          — это самая большая проблема. Мне пришлось поверх тупого датчика ДД навернуть расписание, чтобы ночью электричество для основного освещения кухни в принципе отключалось. Остается только ночник на 2 диодных ватта, который горит всегда.
          Есть ситуации требующие длительного наличия света
          — а вот с этим вообще никаких проблем. Нужно лишь шевельнуться хотя бы раз за 7 минут.

          Лучший интерфейс — это отсутствие интерфейса. Надо стремиться, чтобы всё само работало, без участия человека.


  1. DEM_dwg
    09.12.2017 10:08

    Я бы добавил ключевое слово обращения к прибору, Киви свет.


    1. rPman
      09.12.2017 23:46

      не на atmega, тут с трудом прокатило детектирование гласной А


      1. DEM_dwg
        10.12.2017 07:44

        Тогда уж как правильно заметили, надоть сервер…


        1. rPman
          10.12.2017 21:26

          даже 40-ватный сервер, работающий на распознавание речи, может съесть больше энергии, чем экономия на постоянном выключении света

          ну или сравнимо.

          p.s. правда если делать на базе какого-нибудь android, там можно до 10ват догнать потребление, гугл и яндекс работают непокладая рук.


          1. vassabi
            10.12.2017 23:15

            это если вы его добавляете к уже существующим. А если он у вас и так не выключался (домашний NAS или просто комп) — то там задача распознавания на энергопотреблении практически не сказывается.


            1. rPman
              11.12.2017 00:11

              Распознавание онлайн кушает процессорные ресурсы.

              У меня есть смутное подозрение, что смартфоны в составе держат какой то аппаратный чип для ускорения этих задач, либо умудряются использовать gpu, так как они умудряются ok google отслеживать без нагрузки.


    1. Affdey Автор
      09.12.2017 23:57

      Если вдруг станет много приборов, у них же микрофоны в разных местах будут. и остальные не будут слышать. этого достаточно.
      Если понадобится, адресацию приборов можно сделать тоже гласной, последовательный протокол. И ходить с одним микрофоном-клипсой. И говорить «ИАИ», «АИО», короче как R2D2


  1. aamonster
    09.12.2017 11:41

    На будущее: вместо "одночастотного преобразования фурье" в таких приложениях часто используют алгоритм Гёрцеля — меньше работы.


    Ну а исходную задачу (точнее, подобную ей для прихожей) я для себя решил иначе: маломощный светильник с PIR-сенсором — достаточно, чтобы войти, не спотыкаясь. А дальше уже можно включить большой свет. В вашем случае, наверно, будет не оптимально, но приемлемо: выключил большой свет (включился дежурный), взял тарелку и пошёл. Зато шуметь не надо (важно, когда не один дома)


    1. Affdey Автор
      09.12.2017 23:40

      Спасибо за Гёрцеля, посмотрю что это.
      маломощный светильник (тоже самодельный) с датчиком внешнего света есть и работает, но здесь не тот случай. Выключить большой свет — надо выйти из кухни на 1,5 метра. Потом возвращаться что ли? ))


  1. AllexIn
    09.12.2017 13:42

    Ваша идея отличная, но только как первый этап.
    У меня так:
    Простой минимальный анализ звука на наличие в нём слов.
    Если слова есть — попытка понять, есть ли в нём Ключевая Стартовая Фраза.
    Если решаем что может быть есть — отправка на локальный сервер, где крутится полноценная распознавалка.
    Если сервер говорит — что там ключевая стартовая фраза.
    Проигрывание приветствия и отправка всего остального потока в рантайме.


    1. Affdey Автор
      09.12.2017 23:43

      Круто у вас, алгоритмы или описание есть?
      Здесь просто незачем…


      1. AllexIn
        10.12.2017 13:20

        Да ничего умного.
        Просто анализ звука, если тишина — ничего не делаем.
        Если звук есть и по длинне подходит — передаем на сервер.
        В вышмате я не очень, поэтому до преобразования фурье и прочих вещей не дошел…


        1. Affdey Автор
          10.12.2017 13:29

          Это понятно, на сервере что? какой алгоритм на сервере, чей?


          1. vassabi
            10.12.2017 15:00

            а на сервере можно перекидывать в амазон или гугл


            1. AllexIn
              10.12.2017 15:04

              У Яндекса тоже не плохая распознавалка.
              Если вас, конечно, не смущает отдавать прослушку вашего дома каким-то левым чувакам.


            1. Affdey Автор
              10.12.2017 17:02

              Слова амазон, гугл и сервер мне ни о чём ни говорят. Под алгоритмом я понимаю статью с тех. описанием, например в научном/математическом журнале. К сожалению это большая редкость.


              1. rPman
                10.12.2017 22:00

                полагаю алгоритмы тут вторичны, в опенсорсе вроде гуляют неплохие, дороже обойдутся обученные нейроные сети


          1. AllexIn
            10.12.2017 15:00

            Самописный сервер на базе Sphinx. Вообще, есть готовые решения в инете, но они устарели и не поддерживаются. Пришлось свой маленький велосипедик сделать.


            1. AllexIn
              10.12.2017 15:21
              +1

              Я наверно на днях напишу коротенькую статейку на тему этого сервера и выложу его на гитхаб


  1. vlivyur
    09.12.2017 14:35

    Когда у меня стояла такая проблема, то я просто свои выключатели заменил на подобные:

    (выпуклый, с краёв тонкий и хорошо заметная клавиша), и повернул их на 90° так, чтоб когда ты заходил в помещение, то, проводя плечом по нему по ходу движения, ты включал свет, а выходя — соответственно наоборот. Даже если вы уже установили умный дом и подключили все выключатели к нему и оно само включает/выключает везде свет, поверьте, такой способ установки выключателя самый удобный. Особенно после того, как я вспомнил, как я в детстве прыгал до выключателя пытаясь попасть в верхний его край.


    1. AllexIn
      09.12.2017 15:32

      Те, кто делают умный дом как правило сразу и диммирование фигачат. Соответственно такой выключатель уже и не может использоваться.


      1. rustavelli
        09.12.2017 17:30

        если там димер на 220в вкорячен в выключатель, это не особо умный ход )


        1. AllexIn
          09.12.2017 17:37

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


          1. rustavelli
            09.12.2017 17:39

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


            1. AllexIn
              09.12.2017 17:43

              У меня освещене 220 вольт. Но в выключателе у меня 5вольт. И вообще 220 только под крышей к лампе идет.


    1. Affdey Автор
      09.12.2017 23:46

      Я не могу сильно менять электрику в не своей квартире. Выключатель строенный, 3 в 1. в узкую клавишу, которая выше плеча на 12 см, попасть сложно в темноте.


  1. icetinte
    09.12.2017 20:54

    А можете подсказать более подробно про микрофон? С какого расстояния ловит звук? Я хочу похожее подключить к Raspberry Pi и пытаюсь понять какой микрофон нужен мне, чтобы звук улавливался по квартире.


    1. Affdey Автор
      09.12.2017 23:32

      микрофон — это маленький динамик, диаметр 25 мм, они были тетрисах. Ловит хорошо, резкий звук голосом с двух метров. я программно делал пороги, большая чувствительность не нужна.


    1. Affdey Автор
      10.12.2017 01:13

      Напрямую не подойдёт почти никакой, только через усилитель. ОУ стоил 17 рублей.


  1. gears
    09.12.2017 23:51

    По ссылке на программу построения цифровых фильтров пишет что:
    «You do not have permission to access this page or file
    Data files must be stored on the same site they are linked from.»


    1. Affdey Автор
      09.12.2017 23:51

      Ссылку подправил, спасибо.