НЕСТАНДАРТНЫЙ Детектор хлопков (только хлопков)

Kollname
Offline
Зарегистрирован: 18.10.2016

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

Пытался построить устройство на основе програмного фильтра, по следующему алгоритму : при срабатывании детектора, ардуино записывает в массив состоящий из 500 ячеек каждый такт. Таким образом записал 100 хлопков. Получилась очень грязная картина синусоиды. С Очень расплывчатыми периодами подъема и спада синусоиды. 

На других форумах мне посоветовали сделать аппаратный фильтр звука вместе с программным. Но представления о том как это сделать равны 1- 2 %

На других форумах дали несколько вариантов как решить эту проблема, ниже приведу парочку из них:

"Анализатор спектра на ардуино))), ну даже быстрое преобразование фурье для 8 битного контроллера задача не простая.
Можно попробовать реализовать корреляцию сигналов, но это нужно сделать таблицу, в которую ещё нужно заполнить, далее нужно измерять уровень при помощи АЦП и считать, и организовать смещение массива, вобщем-то тоже нужно постараться.

А если взять компаратор, выставить порог срабатывания при котором он будет переключаться, выход компаратора, повесить на счетчик, скажем того же ардуино, но счетчик будет тактироваться внешним сигналом компаратора, задача просто скажем каждые 50мс смотреть чего там насчитал таймер, если настроить так чтобы за 1 хлопок регистрировал от 3 до 7 переключений, и соответственно если это так, регистрировать хлопок.
PS: сам я это не проверял, это просто идея)))"

Вот второй совет: en555 lm358 что то на них похожее если хлопок то сначала его обработает en555 задаст частоту после два операционника они эту частоту фильтруют по продолжительности импульса после когда импульс сформированный кидаем его на лапку контролера и программно описываем задержку после чего опршиваем лапку и смотрим что там происходит если импульс длица значит разговор если нет значит хлопок ну перд микрофоном я бы еще простой частотный фильтр бы применил 

Как видите, в этих советах нет четких последовательностей. 

Буду очень признателен если вы поможите: 

1)  Понять каким образом можно создать аппаратный фильтр (желательно на пальцах) Если не трудно с пояснением принципа работы каждого из элементов. 
2) Сформировать последовательный список задачь , который поможет решить эту проблему.

P.S. Я ЗАИНТЕРЕСОВАН В СОТРУДНИЧЕСТВЕ С ЛЮДЬМИ БОЛЕЕ ЗНАЮЩИМИ ЧЕМ Я( В ЭЛЕКТРОНИКЕ).ГОТОВ ОТБЛАГОДАРИТЬ ДЕНЕЖНО. ТЕХ КТО БУДЕТ СОПРОВОЖДАТЬ МЕНЯ В ЭТОМ ПРОЕКТЕ.

negavoid
Offline
Зарегистрирован: 09.07.2016

Попробуйте всё-таки сначала программно, не заморачиваясь с фильтрами

вот раз: clap_detector.ino

/*
  Clapper project
  Author: Manoj Kunthu
  Update: 2/2/13
*/

/*-----------------------------
    Method Prototypes
  -----------------------------*/

void initialize();
void runDetector();
boolean clapDetected();

int detectClaps(int numClaps);
void indicateClaps();
void readMic();

void printStats();

/*-----------------------------
    Variable Declarations
  -----------------------------*/

int TOTAL_CLAPS_TO_DETECT = 2; // The number of claps detected before output is toggled
int offset = 80;               // The point above average that the clap is detected
int CLAP_TIME = 4000;          // The time allowed between each clap


int sensorValue = 0; //the value read through mic

int toggleOutput = -1;

int SIZE = 3;
int buffer[3];
int loopIteration = 0;
int average = 0;
int total = 0;



//BOARD INPUT MIC
const int inPin0 = A0;

//BOARD OUTPUT SIGNALS
const int clapLed1 = 12, clapLed2 = 11, out = 10, readyPin = 13;

//CLAP STATE CONSTANTS
const int FINAL_DETECTED = 0, LOST_CONTINUITY = 1, CLAP_NOT_DETECTED = 2;

void setup() {
  Serial.begin(9600);

  //direct representation of the light bulb that toggles on/off
  pinMode(out, OUTPUT);

  //once initialize() runs the ready pin turns on
  pinMode(readyPin, OUTPUT);

  //respective clap LEDs, more can be added
  pinMode(clapLed1, OUTPUT);
  pinMode(clapLed2, OUTPUT);
}


void loop() {
  initialize();
  runDetector();
}

/**
  Purpose: Prepares the buffer to recognize ambient noise levels in room.
*/
void initialize()
{
  loopIteration = 0;
  total = 0;
  average = 0;

  digitalWrite(clapLed1, LOW);
  digitalWrite(clapLed2, LOW);
  digitalWrite(out, LOW);

  for (int i = 0; i < SIZE; i++)
  {
    readMic();

    buffer[i] = sensorValue;
    total = total + sensorValue;
    average = (total / (i + 1));

    Serial.print("INIT - AVE: ");
    Serial.print(average);
    Serial.print("    Total: ");
    Serial.print(total);
    Serial.print("    Sensor: ");
    Serial.print(sensorValue);
    Serial.print("    Change: ");
    Serial.println(sensorValue - average);

    delay(50);
  }
  digitalWrite(readyPin, HIGH);
}

/**
  Purpose: Runs the detector algorithm. Developers can change the number of claps by adjusting TOTAL_CLAPS_TO_DETECT variable up at the top.
*/
void runDetector()
{
  while (true)
  {
    int clapState = detectClaps(TOTAL_CLAPS_TO_DETECT);

    if (clapState == FINAL_DETECTED || clapState == LOST_CONTINUITY)
    {
      Serial.println("--done--");
      indicateClap(0);//turn off any clap indicating lights
    }
  }
}

/**
  Purpose:  Detects the number of claps specified. This method is recursive
*/
int detectClaps(int numClaps)
{
  int clapNum = numClaps;

  //Base Case - if clapNum is 0, then all claps have been accounted.
  if (clapNum == 0)
  {
    //the output can now be toggled.
    toggleOutput *= -1;
    indicateClap(clapNum);

    Serial.println("-----  Clap Limit Reached - Output Toggled -----");

    return FINAL_DETECTED;
  }

  //Read from mic and update ambient noise levels.
  readMic();

  total = (total - buffer[loopIteration]) + sensorValue;
  average = (total / SIZE);
  buffer[loopIteration] = sensorValue;

  loopIteration = (loopIteration + 1) % SIZE;

  if (clapDetected())
  {
    Serial.print("detectClaps - Claps:");
    Serial.println(TOTAL_CLAPS_TO_DETECT + 1 - numClaps);

    printStats();
    indicateClap(clapNum);

    delay(100);
    for (int i = 0; i < CLAP_TIME; i++)
    {
      int clapState = detectClaps(clapNum - 1);

      if (clapState == FINAL_DETECTED || clapState == LOST_CONTINUITY)
      {
        return clapState;
      }
    }
    return LOST_CONTINUITY;
  }
  return CLAP_NOT_DETECTED;
}

/**
  Purpose: Turns the LED on appropriately to signal a clap detection.
*/
void indicateClap(int clapNum)
{
  if (clapNum == 0)
  {
    if (toggleOutput == 1)
    {
      digitalWrite(out, HIGH);
    }
    else
    {
      digitalWrite(out, LOW);
    }
    digitalWrite(clapLed1, LOW);
    digitalWrite(clapLed2, LOW);
  }
  else if (clapNum == 1)
  {
    digitalWrite(clapLed1, HIGH);
  }
  else if (clapNum == 2)
  {
    digitalWrite(clapLed2, HIGH);
  }
  delay(110);
}

/**
  Purpose: Prints basic statistics data for more info with sensor readouts and data points.
*/
void printStats()
{
  Serial.print("--- AVE: ");
  Serial.print(average);
  Serial.print("    Total: ");
  Serial.print(total);
  //Serial.print("    iterNum: ");
  //Serial.print(loopIteration);
  Serial.print("    Sensor: ");
  Serial.print(sensorValue);
  Serial.print("    Change: ");
  Serial.println(sensorValue - average); //This is what I used to determine the 'offset' value
}

/**
  Purpose:  A clap is detected when the sensor value is greater than the average plus
      an offset.  The offset might need to be fine tuned for different sound sensors.
*/
boolean clapDetected()
{
  return sensorValue > average + offset;
}

/**
  Purpose: Reads mic input and stores it in a global variable.
*/
void readMic()
{
  sensorValue = analogRead(inPin0);
}

вот два: библиотеки с fft и fht, после которых брать бин частоты клэпа

http://wiki.openmusiclabs.com/wiki/ArduinoFHT

вот три: пример low-pass программного фильтра, можно, разумеется, сделать и high pass и band pass на частоту хлопка

https://bochovj.wordpress.com/2013/07/07/bass-detection-with-arduino/

Kollname
Offline
Зарегистрирован: 18.10.2016

Спасибо, вы считаете, что програмный фильтр может все-таки работать? (на стандартном ардуиновском микрофоне)

negavoid
Offline
Зарегистрирован: 09.07.2016

Если под стандартным вы имеете в виду KY-038 с алиэкспресса ( https://tkkrlab.nl/wiki/Arduino_KY-038_Microphone_sound_sensor_module ), то смело выкидывайте его в ведро, он очень дубовый. Но и с ним сработает, только хлопать надо не далее, чем в 5 см от микрофона.

Kollname
Offline
Зарегистрирован: 18.10.2016
negavoid
Offline
Зарегистрирован: 09.07.2016

Не знаю :), я не звукач; а fft для avr мучил, пробуя вылепить из ардуины vlf sdr, модуль микрофона же подключал для проверки кода.

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

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

Можно попытаться нащупать какой-нибудь эмпирический алгоритм, обладающий приемлемым количеством ошибок срабатывания, но для этого нужны некоторые познания: в первую очередь в акустике, ну и как необходимое (нр не достаточное) условие - в радиоэлектронике и программировании.

Суды по Вашим вопросам, ни первым, ни вторым, ни третьим Вы не обладаете. Тогда чего Вы хотите? Если невозможного - сразу бросьте эту затею. Если чему-то научиться, начните с учебника по акустике. Если чтобы за Вас что-то сделали - это в раздел "Ищу исполнителя". Только, боюсь, в последнем варианте никто за такую задачу не возмется. А если и возмется, вряд ли сделает.

Kollname
Offline
Зарегистрирован: 18.10.2016

У меня конкретная цель  - я её упомянул выше. Согласен, что знаний у меня более чем недостоточно. Но это не мешает мне их накопить (хотя это может занять очень много времени).  Мне всего-лишь нужно знать куда копать.

P.S. Кто знает сколько мс длится хлопок? 

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

Kollname пишет:

P.S. Кто знает сколько мс длится хлопок? 

твой хлопок длится ровно один мой чих.

четыре эха от моего чиха заменяют один мой хлопок.

не хлопай - у меня насморк.

Kollname
Offline
Зарегистрирован: 18.10.2016

Спасибо, очень полезно! 

Боги электроники Помогите!

 

 Как програмно можно создать алгоритм на основе этих частот??

вторая картинка это обычный шум 

первая это хлопок

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

Kollname пишет:

1) сколько по времени длится хлопок?

2) Как (с помощью чего) можно разложить хлопок по частотам?

1. запиши свой хлопок и посмотри в аудиоредакторе длину

2. с помощью того же аудиоредактора.

 

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

Я думаю Ваша задача очень абстрактна. Вы попробуйте хотя бы что то написать, глядишь заработает. Со стандартным микрофоном или с каким то еще попробуйте. А когда устаните хлопать выложите сей скетч сюда, может мы тоже его зальем и похлопаем. Если на Вашем скрине с ютуба по горизонтали миллисекунды то хлопок длится 4 мс.
Я бы написал по такому алгаритму. Слушаем эфир, принимаем значение за фон и фильтруем его. Если идет увеличение смотрим на сколько больше фона, если не значительно (параметр значительности регулируем допустим с подстройки для удобства) то перезаписываем уровень громкости фона и слушаем дальше. Если значительный то засекаем сколько он длится. Если больше чем наш хлопок то значит это не хлопок и слушаем дальше. Если хлопок по времени говорим что хлопок. Но это например может быть и стук и резкий чих уважаемого Клапауция...

Клапауций 823
Клапауций 823 аватар
Offline
Зарегистрирован: 13.01.2017

ну, шо за бред?

кто-то вообще пробовал хлопать в своём жилом помещении чаще, чем два раза в сутки?

ваша собака, жена, тёща, соседка вас на*уй после этого не послали?

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

Logik
Offline
Зарегистрирован: 05.08.2014

Kollname пишет:

Спасибо, очень полезно! 

Боги электроники Помогите!

Хера взываеш среди ночи? Спят усе.

Твоя задача - амплитудная детекция и селекция по длительности. Хлопок по громкости выше чем шум и длится мало. Пиши код и не возропщи нах... 

Kollname
Offline
Зарегистрирован: 18.10.2016

Я так полагаю код который мне скинули работает по тому же принципу. Плохо понимаемый! 

void initialize();
012
void runDetector();
013
boolean clapDetected();
014
 
015
int detectClaps(int numClaps);
016
void indicateClaps();
017
void readMic();
018
 
019
void printStats();
020
 
021
/*-----------------------------
022
    Variable Declarations
023
  -----------------------------*/
024
 
025
int TOTAL_CLAPS_TO_DETECT = 2; // The number of claps detected before output is toggled
026
int offset = 80;               // The point above average that the clap is detected
027
int CLAP_TIME = 4000;          // The time allowed between each clap
028
 
029
 
030
int sensorValue = 0; //the value read through mic
031
 
032
int toggleOutput = -1;
033
 
034
int SIZE = 3;
035
int buffer[3];
036
int loopIteration = 0;
037
int average = 0;
038
int total = 0;
039
 
040
 
041
 
042
//BOARD INPUT MIC
043
const int inPin0 = A0;
044
 
045
//BOARD OUTPUT SIGNALS
046
const int clapLed1 = 12, clapLed2 = 11, out = 10, readyPin = 13;
047
 
048
//CLAP STATE CONSTANTS
049
const int FINAL_DETECTED = 0, LOST_CONTINUITY = 1, CLAP_NOT_DETECTED = 2;
050
 
051
void setup() {
052
  Serial.begin(9600);
053
 
054
  //direct representation of the light bulb that toggles on/off
055
  pinMode(out, OUTPUT);
056
 
057
  //once initialize() runs the ready pin turns on
058
  pinMode(readyPin, OUTPUT);
059
 
060
  //respective clap LEDs, more can be added
061
  pinMode(clapLed1, OUTPUT);
062
  pinMode(clapLed2, OUTPUT);
063
}
064
 
065
 
066
void loop() {
067
  initialize();
068
  runDetector();
069
}
070
 
071
/**
072
  Purpose: Prepares the buffer to recognize ambient noise levels in room.
073
*/
074
void initialize()
075
{
076
  loopIteration = 0;
077
  total = 0;
078
  average = 0;
079
 
080
  digitalWrite(clapLed1, LOW);
081
  digitalWrite(clapLed2, LOW);
082
  digitalWrite(out, LOW);
083
 
084
  for (int i = 0; i < SIZE; i++)
085
  {
086
    readMic();
087
 
088
    buffer[i] = sensorValue;
089
    total = total + sensorValue;
090
    average = (total / (i + 1));
091
 
092
    Serial.print("INIT - AVE: ");
093
    Serial.print(average);
094
    Serial.print("    Total: ");
095
    Serial.print(total);
096
    Serial.print("    Sensor: ");
097
    Serial.print(sensorValue);
098
    Serial.print("    Change: ");
099
    Serial.println(sensorValue - average);
100
 
101
    delay(50);
102
  }
103
  digitalWrite(readyPin, HIGH);
104
}
105
 
106
/**
107
  Purpose: Runs the detector algorithm. Developers can change the number of claps by adjusting TOTAL_CLAPS_TO_DETECT variable up at the top.
108
*/
109
void runDetector()
110
{
111
  while (true)
112
  {
113
    int clapState = detectClaps(TOTAL_CLAPS_TO_DETECT);
114
 
115
    if (clapState == FINAL_DETECTED || clapState == LOST_CONTINUITY)
116
    {
117
      Serial.println("--done--");
118
      indicateClap(0);//turn off any clap indicating lights
119
    }
120
  }
121
}
122
 
123
/**
124
  Purpose:  Detects the number of claps specified. This method is recursive
125
*/
126
int detectClaps(int numClaps)
127
{
128
  int clapNum = numClaps;
129
 
130
  //Base Case - if clapNum is 0, then all claps have been accounted.
131
  if (clapNum == 0)
132
  {
133
    //the output can now be toggled.
134
    toggleOutput *= -1;
135
    indicateClap(clapNum);
136
 
137
    Serial.println("-----  Clap Limit Reached - Output Toggled -----");
138
 
139
    return FINAL_DETECTED;
140
  }
141
 
142
  //Read from mic and update ambient noise levels.
143
  readMic();
144
 
145
  total = (total - buffer[loopIteration]) + sensorValue;
146
  average = (total / SIZE);
147
  buffer[loopIteration] = sensorValue;
148
 
149
  loopIteration = (loopIteration + 1) % SIZE;
150
 
151
  if (clapDetected())
152
  {
153
    Serial.print("detectClaps - Claps:");
154
    Serial.println(TOTAL_CLAPS_TO_DETECT + 1 - numClaps);
155
 
156
    printStats();
157
    indicateClap(clapNum);
158
 
159
    delay(100);
160
    for (int i = 0; i < CLAP_TIME; i++)
161
    {
162
      int clapState = detectClaps(clapNum - 1);
163
 
164
      if (clapState == FINAL_DETECTED || clapState == LOST_CONTINUITY)
165
      {
166
        return clapState;
167
      }
168
    }
169
    return LOST_CONTINUITY;
170
  }
171
  return CLAP_NOT_DETECTED;
172
}
173
 
174
/**
175
  Purpose: Turns the LED on appropriately to signal a clap detection.
176
*/
177
void indicateClap(int clapNum)
178
{
179
  if (clapNum == 0)
180
  {
181
    if (toggleOutput == 1)
182
    {
183
      digitalWrite(out, HIGH);
184
    }
185
    else
186
    {
187
      digitalWrite(out, LOW);
188
    }
189
    digitalWrite(clapLed1, LOW);
190
    digitalWrite(clapLed2, LOW);
191
  }
192
  else if (clapNum == 1)
193
  {
194
    digitalWrite(clapLed1, HIGH);
195
  }
196
  else if (clapNum == 2)
197
  {
198
    digitalWrite(clapLed2, HIGH);
199
  }
200
  delay(110);
201
}
202
 
203
/**
204
  Purpose: Prints basic statistics data for more info with sensor readouts and data points.
205
*/
206
void printStats()
207
{
208
  Serial.print("--- AVE: ");
209
  Serial.print(average);
210
  Serial.print("    Total: ");
211
  Serial.print(total);
212
  //Serial.print("    iterNum: ");
213
  //Serial.print(loopIteration);
214
  Serial.print("    Sensor: ");
215
  Serial.print(sensorValue);
216
  Serial.print("    Change: ");
217
  Serial.println(sensorValue - average); //This is what I used to determine the 'offset' value
218
}
219
 
220
/**
221
  Purpose:  A clap is detected when the sensor value is greater than the average plus
222
      an offset.  The offset might need to be fine tuned for different sound sensors.
223
*/
224
boolean clapDetected()
225
{
226
  return sensorValue > average + offset;
227
}
228
 
229
/**
230
  Purpose: Reads mic input and stores it in a global variable.
231
*/
232
void readMic()
233
{
234
  sensorValue = analogRead(inPin0);
235
}

 

Kollname
Offline
Зарегистрирован: 18.10.2016

Волнует такая проблема. Написал скетч реагирующий на хлопок, но микрофон, который я использую - гавнецо. Исправно работает на расстоянии 50 см. Подскажите пожайлуста, схему усилителя с микрофоном, чтобы можно было расширить возможности детектора до 4-5 метров 

Kollname
Offline
Зарегистрирован: 18.10.2016

Спасибо, что скинул столько полезной информации. Все зашло кроме последнего скетча. Там просит LowPassFilter.c Весь инет прорыл не нашел такой библиотеки

negavoid
Offline
Зарегистрирован: 09.07.2016

Просто надо быть чуть внимательнее :)  http://t-filter.engineerjs.com/

Kollname
Offline
Зарегистрирован: 18.10.2016

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

Обещаю это последняя просьба =)))

negavoid
Offline
Зарегистрирован: 09.07.2016

то, что там наверху, на картинках - это не спектр хлопка ) ну, допустим, попробуйте, реагировать на частоту где-то около 4-5 кГц

Kollname
Offline
Зарегистрирован: 18.10.2016

Ок спасибо =)