Оценка направления прибытия в реальном времени с массивом линейных микрофонов

Этот пример показывает, как получить и обработать live многоканальное аудио. Он также представляет простой алгоритм для оценки направления прибытия (DOA) источника звука с использованием нескольких пар микрофонов в линейном массиве.

Выберите и сконфигурируйте источник аудио Выборок

Если доступен многоканальный входной аудиоинтерфейс, измените этот скрипт, чтобы задать sourceChoice на 'live'. В этом режиме пример использует live audio входные сигналы. Пример предполагает, что все входы (два или более) управляются микрофонами, расположенными на линейном массиве. Если массив микрофонов или многоканальная аудиокарта не доступны, установите sourceChoice на 'recorded'. В этом режиме в примере используются предварительно записанные аудио выборки, полученные с помощью линейного массива. Для sourceChoice = 'live', следующий код использует audioDeviceReader получить 4 канала аудиосигнала через Microsoft Kinect™ для Windows ®. Чтобы использовать другую настройку микрофонного массива, убедитесь, что установленный драйвер аудио устройства является одним из обычных типов, поддерживаемых MATLAB, и установите Device свойство audioDeviceReader соответственно. Можно запросить допустимое Device назначения для вашего компьютера вызовом getAudioDevices функция объекта от audioDeviceReader. Обратите внимание, что даже при использовании Microsoft Kinect имя устройства может различаться на разных компьютерах и может не совпадать с именем, используемым в этом примере. Используйте заполнение клавишей Tab, чтобы получить правильное имя на вашем компьютере.

sourceChoice = 'recorded';

Установите длительность live обработки. Установите, сколько выборок на канал для получения и обработки каждой итерации.

endTime = 20;
audioFrameLength = 3200;

Создайте источник.

switch sourceChoice
    case 'live'
        fs = 16000;
        audioInput = audioDeviceReader( ...
            'Device','Microphone Array (Microsoft Kinect USB Audio)', ...
            'SampleRate',fs, ...
            'NumChannels',4, ...
            'OutputDataType','double', ...
            'SamplesPerFrame',audioFrameLength);
    case 'recorded'    
        % This audio file holds a 20-second recording of 4 raw audio
        % channels acquired with a Microsoft Kinect(TM) for Windows(R) in
        % the presence of a noisy source moving in front of the array
        % roughly from -40 to about +40 degrees and then back to the
        % initial position.
        audioFileName = 'AudioArray-16-16-4channels-20secs.wav';
        audioInput = dsp.AudioFileReader( ...
            'OutputDataType','double', ...
            'Filename',audioFileName, ...
            'PlayCount',inf, ...
            'SamplesPerFrame',audioFrameLength);
        fs = audioInput.SampleRate;
end

Задайте геометрию массива

Следующие значения идентифицируют приблизительные линейные координаты 4 встроенных микрофонов Microsoft Kinect™ относительно положения камеры RGB (в данном примере не используется). Для координат 3D используйте [[x1; y1; z1], [x2; y2; z2],..., [xN; yN; zN]]

micPositions = [-0.088, 0.042, 0.078, 0.11];

Формируйте пары микрофонов

Алгоритм, используемый в этом примере, работает с парами микрофонов независимо. Затем он объединяет индивидуума оценки DOA, чтобы предоставить один живой выход DOA. Чем больше доступных пар, тем более устойчивая (но в то же время в вычислительном отношении дорогая) оценка DOA. Максимальное количество доступных пар может быть вычислено следующим nchoosek(length(micPositions),2). В этом случае выбираются 3 пары с наибольшими межмикрофонными расстояниями. Чем больше расстояние между микрофонами, тем более чувствительна оценка DOA. Каждый столбец следующей матрицы описывает выбор пары микрофонов в массиве. Все значения должны быть целыми числами от 1 до length(micPositions).

micPairs = [1 4; 1 3; 1 2];
numPairs = size(micPairs, 1);

Инициализация визуализации DOA

Создайте образец вспомогательного объекта построения графика DOADisplay. Это отображает предполагаемый DOA в прямом эфире со стрелой на полярном графике.

DOAPointer = DOADisplay();

Создайте и сконфигурируйте алгоритмические базовые блоки

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

bufferLength = 64;
preprocessor = PairArrayPreprocessor( ...
    'MicPositions',micPositions, ...
    'MicPairs',micPairs, ...
    'BufferLength',bufferLength);
micSeparations = getPairSeparations(preprocessor);

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

XCorrelator = dsp.Crosscorrelator('Method','Frequency Domain');
interpFactor = 8;
b = interpFactor * fir1((2*interpFactor*8-1),1/interpFactor);
groupDelay = median(grpdelay(b));
interpolator = dsp.FIRInterpolator('InterpolationFactor',interpFactor,'Numerator',b);

Получение и обработка сигналов в цикле

Для каждой итерации следующего цикла while: read audioFrameLength выборки для каждого аудиоканала, обрабатывают данные, чтобы оценить значение DOA и отобразить результат на пользовательской основанной стрелкой полярной визуализации.

tic
for idx = 1:(endTime*fs/audioFrameLength)
    cycleStart = toc;
    % Read a multichannel frame from the audio source
    % The returned array is of size AudioFrameLength x size(micPositions,2)
    multichannelAudioFrame = audioInput();
    
    % Rearrange the acquired sample in 4-D array of size
    % bufferLength x numBuffers x 2 x numPairs where 2 is the number of
    % channels per microphone pair
    bufferedFrame = preprocessor(multichannelAudioFrame);
    
    % First, estimate the DOA for each pair, independently
    
    % Initialize arrays used across available pairs
    numBuffers = size(bufferedFrame, 2);
    delays = zeros(1,numPairs);
    anglesInRadians = zeros(1,numPairs);
    xcDense = zeros((2*bufferLength-1)*interpFactor, numPairs);
    
    % Loop through available pairs
    for kPair = 1:numPairs
        % Estimate inter-microphone delay for each 2-channel buffer 
        delayVector = zeros(numBuffers, 1);
        for kBuffer = 1:numBuffers
            % Cross-correlate pair channels to get a coarse
            % crosscorrelation
            xcCoarse = XCorrelator( ...
                bufferedFrame(:,kBuffer,1,kPair), ...
                bufferedFrame(:,kBuffer,2,kPair));

            % Interpolate to increase spatial resolution
            xcDense = interpolator(flipud(xcCoarse));

            % Extract position of maximum, equal to delay in sample time
            % units, including the group delay of the interpolation filter
            [~,idxloc] = max(xcDense);
            delayVector(kBuffer) = ...
                (idxloc - groupDelay)/interpFactor - bufferLength;
        end

        % Combine DOA estimation across pairs by selecting the median value
        delays(kPair) = median(delayVector);

        % Convert delay into angle using the microsoft pair spatial
        % separations provided
        anglesInRadians(kPair) = HelperDelayToAngle(delays(kPair), fs, ...
            micSeparations(kPair));
    end

    % Combine DOA estimation across pairs by keeping only the median value
    DOAInRadians = median(anglesInRadians);
    
    % Arrow display
    DOAPointer(DOAInRadians)
    
    % Delay cycle execution artificially if using recorded data
    if(strcmp(sourceChoice,'recorded'))
        pause(audioFrameLength/fs - toc + cycleStart)
    end
end

release(audioInput)