Cистема измерения акустики

Un_ka

★★✩✩✩✩✩
13 Июл 2020
247
77
других форумов.
Имеется необходимость измерения спектральных параметров звука с нескольких микрофонов установленных на закрытом канале. В первую очередь интересно замерить задержку во времени прохождения звуковой волны между двумя и более микрофонами с высокой точностью.
При этом измерение необходимо осуществлять достаточно локально, то есть микрофон должен иметь малые размеры приёмника по сравнению с длиной волны.
Диапазон частот 100..2000 Гц (длины волн при нормальных условиях около 3-0.15м).

В качестве микрофонов могут быть использованы следующие микрофоны:
  1. Электронные микрофоны малого диаметра (∅6-10 мм, соотношение диаметра и длины волны в худшем случае 15), пример EM6050;
  2. Микрофоны на технологии MEMS, (∅1 мм, соотношение диаметра и длины волны в худшем случае 150), пример SMD02718C4O4C-38VSM2718AB-N30-B3F;
  3. Цифровые микрофоны на технологии MEMS со в строенным усилителем и АЦП, пример im69d130.
  4. Пьезоэлектрические датчики (Пьезоэлектрические излучатели) (∅26мм, соотношение диаметра и длины волны в худшем случае 5,7), пример
Микрофонам, естественно, нужна обвязка 1 и 2 могут потребоваться отдельные усилители, а 3 достаточно лишь нескольких конденсаторов в обвязке для подключения к микроконтроллеру сбора информации.
В связи с этим возникает вопрос выбора подходящего микрофона.

Подключение электретного микрофона к МК
Согласно https://qna.habr.com/q/669863, для схемы на рисунке 1 требуется резистор 2 кОм для 3,3в и конденсатор неполярный ёмкостью более 1 мкф.
Если методики и рекомендации по расчёту номинала резистора и конденсатора?

Микроконтроллер.
Были испытаны возможности двух разных микроконтроллеров без задействования всего потенциала за счёт использования оптимизация обращения к регистрам.
  1. Atmega2560 в составе Arduino mega (16 МГц);
  2. STM32F401RE в составе STM NUCLEO (84 МГц);
Arduino mega, среда Arduino IDE, соответствующим набором библиотек, частота дискретизации составила 8927 Гц.
C++:
#define LEN_SMPL 3000

int* sample = new int[LEN_SMPL];
int* sample2 = new int[LEN_SMPL];
int n = 0, sm = 0;

unsigned long t1 = 0, t2 = 0;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(2000000);  ///921600
  analogReference(INTERNAL1V1);
}

void loop() {
t1 = micros();
  for (n = 0; n < LEN_SMPL; n++) {
    sample[n] = analogRead(A0);
    sample2[n] = analogRead(A1);
  }
  t2 = micros();
  Serial.println("Time read " + String(t2 - t1));
  t1 = micros();
  /*
  for (n = 0; n < LEN_SMPL; n++) {
    Serial.println(analogRead(A0));
  }

  t2 = micros();

Serial.println( String(t2 - t1));

//Serial.println("Time rw " + String(t2 - t1));
  //delay(10000);

  //   for (n = 0; n < LEN_SMPL; n++) {

  //   sm = analogRead(A0);
  //   Serial.write(sm, sizeof( sm ));
  // }

  // t2 = micros();
  // Serial.println("Time rwrite" + String(t2 - t1));
  // Serial.println("sizeof" + String(sizeof( sm )));
  // delay(10000);
*/
  t1 = micros();
  for (n = 0; n < LEN_SMPL; n++) {
    Serial.print(sample[n]);
    Serial.print(sample2[n]);
  }
  t2 = micros();
  Serial.println("\nTime write " + String(t2 - t1));




  // put your main code here, to run repeatedly:


}
STM32F401RE, среда Mbed, библиотека Mbed v6.17, частота дискретизации составила 82370 Гц.
C++:
/* mbed Microcontroller Library
* Copyright (c) 2019 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*/

#include "mbed.h"
#include "mbed_mem_trace.h"

#include <string>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#defineLEN_SMPL10000
// Blinking rate in milliseconds
#defineBLINKING_RATE5000ms
#definemicrosus_timestamp_t
Timer timer;

AnalogIn ain0(A0);
AnalogIn ain1(A1);
AnalogIn vrefint(ADC_VREF);
AnalogIn tempint(ADC_TEMP);
BufferedSerial pc(USBTX, USBRX,115200);
uint64_t t1 = 0, t2 = 0;
uint16_t* sample0 = new uint16_t[LEN_SMPL];
uint16_t* sample1 = new uint16_t[LEN_SMPL];
int n = 0, sm = 0;
Kernel::Clock::time_point start_time,end_time;

int main()
{
mbed_stats_heap_t heap_stats;
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
// DWT->LAR = 0xC5ACCE55;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
printf("Hello, World!\n");
printf("Vref(f): %f, Vref : %u, Temperature : %u\r\n",
vrefint.read(), vrefint.read_u16(), tempint.read_u16());
// Initialise the digital pin LED1 as an output
DigitalOut led(LED1);

while (true) {

uint32_t start_cycles = DWT->CYCCNT;
start_time = Kernel::Clock::now();
for (n = 0; n < LEN_SMPL; n++) {
sample0[n] = ain0.read_u16();
sample1[n] = ain1.read_u16();
}
end_time = Kernel::Clock::now();
uint32_t end_cycles = DWT->CYCCNT;
auto elapsed_time = end_time - start_time;

ThisThread::sleep_for(100ms);
printf("Time read: %lld milliseconds\n", elapsed_time.count());
// Вычисляем время выполнения в тактах
uint32_t elapsed_cycles = end_cycles - start_cycles;
printf("Time read: %lu CPU cycles\n", elapsed_cycles);

// Если нужно перевести такты в микросекунды:
uint32_t cpu_frequency = SystemCoreClock; // Частота процессора в Гц
float elapsed_time_us = (float)elapsed_cycles / (cpu_frequency / 1000000.0f);
printf("Time read: %f microseconds\n", elapsed_time_us);
printf("cpu_frequency %lu \n", cpu_frequency);
mbed_stats_heap_get(&heap_stats);
printf("Heap size: %lu / %lu bytes max %lu \r\n", heap_stats.current_size, heap_stats.reserved_size, heap_stats.max_size);
t1 = micros();
led = !led;
//ThisThread::sleep_for(BLINKING_RATE);

start_time = Kernel::Clock::now();
for (n = 0; n < LEN_SMPL; n++) {
printf("%d %d\n",sample0[n],sample1[n]);
}
end_time = Kernel::Clock::now();
elapsed_time = end_time - start_time;
printf("\nTime write: %lld microseconds\n", elapsed_time.count());


}
}

У данной реализации считывателя сигнала с микрофонов есть два ограничения, расширение которых является перспективным.
  1. Увеличение частоты дискретизации, за счёт оптимизации считывания сигнала;
  2. Уменьшение времени вывода считанных цифровых значений в com port, либо за счёт повышения скорости передачи у серийного порта, либо за счёт отказа от кодирования чисел в ASCII.
Повышение скорости передачи у серийного порта пробовал, но выше 115200, У STM появляются потери данных.

Сигналы с разных микрофонов, уже пробовал получать и обрабатывать в Matlab, кому нужно могу выложить код скрипта.
Спектры в векторном формате emf для лучшего качества сохранил в pdf.
По итогу есть ряд вопросов:
  1. Какой микрофон лучше использовать для имеющейся задачи?
  2. Если методики и рекомендации по расчёту номинала резистора и конденсатора при подключении электретного микрофона?
  3. Как увеличить частоту дискретизации и стоит ли?
  4. Как увеличить скорость передачи данных на ПК?
Здесь также будут выкладываться новые результаты по мере их появления.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
530
157
В первую очередь интересно замерить задержку во времени прохождения звуковой волны между двумя и более микрофонами с высокой точностью.
Было бы более понятно, если бы вы ограничились пока этим измерением. И привели результаты с выводами, что устроило, что нет. В этом вопросе, может кто и поможет/подскажет.
(Специалистов же по измерению спектральных параметров звука, наверное, лучше искать в другом месте.)
 

poty

★★★★★★✩
19 Фев 2020
3,337
958
методики и рекомендации по расчёту номинала резистора и конденсатора при подключении электретного микрофона?
номинал резистора, обычно, даётся в параметрах микрофона. В любом случае, больше 1-2мА ток редко делают.
Что касается конденсатора, то он нужен для исключения постоянной составляющей, а она как раз тут нужна, для аналогового входа МП. Вариант - подобрать напряжение питания и полностью исключить конденсатор.
 

Un_ka

★★✩✩✩✩✩
13 Июл 2020
247
77
других форумов.
Удалось добиться увеличения скорости передачи данных за счёт отказа от буферизации при отправке данных в serial port.
C++:
#include "mbed.h"
#include "mbed_mem_trace.h"

#include <string>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define LEN_SMPL 10000
// Blinking rate in milliseconds
#define BLINKING_RATE     5000ms
#define micros us_timestamp_t
Timer timer;

AnalogIn   ain0(A0);
AnalogIn   ain1(A1);
AnalogIn   ain2(A2);
AnalogIn   ain3(A3);
AnalogIn   vrefint(ADC_VREF);
AnalogIn   tempint(ADC_TEMP);
//BufferedSerial pc(USBTX, USBRX,115200);
UnbufferedSerial pc(USBTX, USBRX,460800); // 2000000
uint64_t t1 = 0, t2 = 0;
uint16_t* sample0 = new uint16_t[LEN_SMPL];
uint16_t* sample1 = new uint16_t[LEN_SMPL];
uint16_t* sample2 = new uint16_t[LEN_SMPL];
uint16_t* sample3 = new uint16_t[LEN_SMPL];
int n = 0, sm = 0;
Kernel::Clock::time_point start_time,end_time;

int main()
{
    mbed_stats_heap_t heap_stats;
 
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
     // DWT->LAR = 0xC5ACCE55;
      DWT->CYCCNT = 0;
      DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    printf("Hello, World!\n");
    printf("Vref(f): %f, Vref : %u, Temperature : %u\r\n",
                 vrefint.read(), vrefint.read_u16(), tempint.read_u16());
    // Initialise the digital pin LED1 as an output
    DigitalOut led(LED1);

    while (true) {

uint32_t start_cycles = DWT->CYCCNT;
  start_time = Kernel::Clock::now();
  for (n = 0; n < LEN_SMPL; n++) {
    sample0[n] = ain0.read_u16();
    sample1[n] = ain1.read_u16();
    sample2[n] = ain2.read_u16();
    sample3[n] = ain3.read_u16();
  }
end_time = Kernel::Clock::now();
  uint32_t end_cycles = DWT->CYCCNT;
  auto elapsed_time = end_time - start_time;

  ThisThread::sleep_for(100ms);
printf("Time read: %lld milliseconds\n", elapsed_time.count());

  // Вычисляем время выполнения в тактах
    uint32_t elapsed_cycles = end_cycles - start_cycles;
    printf("Time read: %lu CPU cycles\n", elapsed_cycles);

    // Если нужно перевести такты в микросекунды:
    uint32_t cpu_frequency = SystemCoreClock; // Частота процессора в Гц
    float elapsed_time_us = (float)elapsed_cycles / (cpu_frequency / 1000000.0f);
    printf("Time read: %f microseconds\n", elapsed_time_us);
    printf("cpu_frequency %lu \n", cpu_frequency);
    mbed_stats_heap_get(&heap_stats);
printf("Heap size: %lu / %lu bytes max  %lu  \r\n", heap_stats.current_size, heap_stats.reserved_size, heap_stats.max_size);
  t1 = micros();
led = !led;
        //ThisThread::sleep_for(BLINKING_RATE);
     
start_time = Kernel::Clock::now();
  for (n = 0; n < LEN_SMPL; n++) {
    printf("%d %d %d %d\n",sample0[n],sample1[n],sample2[n],sample3[n]);
  }
end_time = Kernel::Clock::now();

elapsed_time = end_time - start_time;
printf("\nTime write: %lld microseconds\n", elapsed_time.count());
    }
}
Также было обнаружено, что при имеющейся конфигурации ПК Matlab может получать данные без потерь до скорости 460800 бод/с (менее 0,5 Мбит/с).

Увеличил количество считываемых каналов до 4.

Сравнение сигналов с пьезодатчиков показало наличие разности фаз между ними.
Пьезодатчики были заключены в корпуса, как показано на рисунке 1.
1740678410174.png
Корпус такой конструкции по задумке должен был уменьшить размеры приёмника давления по сравнению с длиной волны.
Для испытаний использовался удалённый на расстояние более 3 длин волн динамик, на котором воспроизводился синусоидальный сигнал постоянной частоты.
Обработка сигнала в Matlab показала, что на частоте воспроизводимый динамиком 432 Гц, наблюдалась разность фаз между двумя одинаковыми пьезодатчиками подключёнными во второй и третий канал соответственно. Теоретически разность фаз на возбуждаемый частоте между датчиками должна была быть равна фазовой задержке между измерениями, однако такого не происходит.
О фазовой задержке между измерениями
Пусть дискретизация АЦП fadc, имеется n каналов, тогда фазовая задержка между i-ым и j-ым каналами
dfi (f)=(1/fadc)*(i-j)*2*pi*f
При частоте f adc = 82370 Гц, n=4 канала, I=3, j=2, f= 432 Гц:
0,033 радиан.
Имеющиеся разность 0,263 радиан.
1740678396492.png
Что может быть не так?
 

poty

★★★★★★✩
19 Фев 2020
3,337
958
Картинки красивые, только не отражают Вашего эксперимента.
Не очень понятно, с чего Вы взяли, что сигнал буферизуется перед обработкой? Ведь именно это Вы предположили в приведённой формуле? Почему не учтена задержка в передаче данных и обработке? Каковы сдвиги в за счёт акустического расположения? (иначе говоря, где гарантия, что сдвиг не происходит из-за разного расстояния до источника излучения) Каковы сдвиги в электрической обработке (RC-цепочки) в разных каналах?
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,981
637
45
Не лучше ли взять нормальный многоканальный звуковой интерфейс, в котором уж точно не будет задержек при семплировании со входов?
Уверены что разница в измерении не происходит из-за схемотехники?
Уверены что датчики абсолютно одинаковые?
 

Un_ka

★★✩✩✩✩✩
13 Июл 2020
247
77
других форумов.
Не очень понятно, с чего Вы взяли, что сигнал буферизуется перед обработкой?
В приведённом мною коде для STM, я его буферизирую в выборку в 10000 замеров последовательно:
Считывание:
for (n = 0; n < LEN_SMPL; n++) {
    sample0[n] = ain0.read_u16();
    sample1[n] = ain1.read_u16();
    sample2[n] = ain2.read_u16();
    sample3[n] = ain3.read_u16();
  }
Задержка между замерами соседних каналов обусловлена лишь временем выполнения функции read_u16() и равна 1/82370 с.

Затем уже отправляю получившийся сэмпл в serial port:
Отправка:
for (n = 0; n < LEN_SMPL; n++) {

    printf("%d %d %d %d\n",sample0[n],sample1[n],sample2[n],sample3[n]);

  }
Однако в Mbed 6 версии есть две реализации serial с буферизацией и без неё:
Serial:
//BufferedSerial pc(USBTX, USBRX,115200);

UnbufferedSerial pc(USBTX, USBRX,460800); // 2000000
Вторая оказалась лучше.

Каковы сдвиги в за счёт акустического расположения?
Динамик был расположен так, что на датчики приходилось дальнее акустическое поле, то есть расстояние до датчиков составляло более 3 длин волн.
Датчики были обращены к динамику, а расстояние между датчиками(отверстиями в диффузорах составляло 44 мм.

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

В будущем собираюсь повторить испытания препарировав трубу и расположив датчики вдоль трубы: при расположении динамика в торце трубы и воспроизведении не резонансной частоты в ней должны бежать плоские волны.

Каковы сдвиги в электрической обработке (RC-цепочки) в разных каналах?
Так как я подключал пъезодатчики на прямую к МК их не должно быть. Однако, если я буду использовать электретные микрофоны, то резистор и конденсатор каждого микрофона из-за разброса характеристик будут иметь собственную АФЧХ.


многоканальный звуковой интерфейс
Аудиокарты обычно ограничиваются 2 входами. Те, что имеют больше входов идут в категориях с прогреваемыми золотыми кабелями. Буду благодарен, если кто-нибудь подскажет модель аудиокарт с количеством входов 5-10.
Но кроме аудиокарты требуется микрофоны со своим разбросом АФЧХ.


Уверены что датчики абсолютно одинаковые?
Хотя сами датчики (2 и 3 каналы) из одной партии, их расположение в распечатанных на 3D принтере корпусах и момент затяжки может влиять на их АФЧХ.


А зачем это нужно?
Для акустических исследований требуется система измерения с простым и понятным принципом работы и возможностью модернизации.
 

poty

★★★★★★✩
19 Фев 2020
3,337
958
Задержка между замерами соседних каналов обусловлена лишь временем выполнения функции read_u16() и равна 1/82370 с.
Откуда такая информация? Время выполнения преобразования не равно времени выполнения функции. Проверить легко: прочитать два раза из одного порта и определить сдвиг.
расстояние между датчиками ... 44 мм
не очень понимаю про отверстия в диффузорах, но если принять во внимание расстояние 44мм, это будет, при нормальной скорости звука, составлять 137,5мкс задержки, что составляет (при частоте = 432 Гц, период =2314,8мкс) 0,373 радиана.
Так как я подключал пъезодатчики на прямую к МК их не должно быть.
в идеале - согласен, однако нужно учитывать влияние шума, проверка же не в абсолютно беззвуковой камере происходит. В обычной комнате уровень акустического шума может достигать 40дБ, нужно коррелировать с уровнем полезного сигнала.
Аудиокарты обычно ограничиваются 2 входами
Во-первых, можно подключить несколько аудиокарт (особенно, USB), но я против экстенсивного расширения "железа". Для измерений достаточно двух каналов и переключать их между нужными входами (аналоговых мультиплексоров сейчас в интегральном исполнении - куча). По сути, увеличивая количество каналов на одном МП, увеличиваете погрешность определения фазы.
 
  • Лойс +1
Реакции: Un_ka

Un_ka

★★✩✩✩✩✩
13 Июл 2020
247
77
других форумов.
Провёл испытания с трубой длиной 1 м, датчики были присоединены к трубе на одном и том же расстоянии от концов трубы в 0,5м, как показано на рисунке.
Динамик располагался на одном из входов трубы.
1740937040848.png
Замеры и обработка показали всё тоже наличие разности фаз между 2 и 3 каналами к которым были подключены датчики:
1740937127059.png
Посторонних шумов меньше в трубе, да и звук от динамика слабее гаснет соотношение сигнал/шум уже радует.
 

poty

★★★★★★✩
19 Фев 2020
3,337
958

@Un_ka:
1. Переключить со второго канала на третий, с третьего на второй. Посмотреть задержку (исключаем проблемы с микрофонами и их размещением).
2. Прочитать каналы не в том порядке, как сейчас (исключаем попадание в ожидание интервала измерений).
3. Соединить второй и третий каналы вместе и к одному микрофону, посмотреть задержку (исключаем задержку в получении данных).
4. Измерить интервал между измерениями (время перед первым, перед вторым, перед третьим, перед четвертым измерениями).
 
  • Лойс +1
Реакции: Un_ka