Отслеживание ориентации головы путем сплавления данных, полученных от IMU, и затем управление направлением прихода источника звука путем применения связанных с головой передаточных функций (HRTF).
В типичной настройке виртуальной реальности IMU-датчик крепится к наушникам пользователя или VR-гарнитуре так, чтобы воспринимаемое положение источника звука было относительно визуального сигнала, не зависящего от движений головы. Например, если звук воспринимается как поступающий от монитора, он остается таким, даже если пользователь поворачивает голову в сторону.
Ардуино-Уно
Invensense MPU-9250
Сначала подключите MPU-9250 Invensense к плате Arduino. Дополнительные сведения см. в разделе Оценка ориентации с помощью слияния и MPU-9250 инерционных датчиков.
Создание arduino объект.
a = arduino;
Создайте объект датчика Invensense MPU-9250.
imu = mpu9250(a);
Создайте и установите частоту дискретизации фильтра Калмана.
Fs = imu.SampleRate;
imufilt = imufilter('SampleRate',Fs);Когда звук перемещается из точки пространства в уши, его можно локализовать на основе межауральных различий во времени и уровнях (ITD и ILD). Эти зависящие от частоты ITD и ILD могут быть измерены и представлены в виде пары импульсных откликов для любой заданной высоты источника и азимута. Набор данных ARI HRTF содержит 1550 пар импульсных откликов, которые охватывают азимуты более 360 градусов и отметки от -30 до 80 градусов. Эти импульсные характеристики используются для фильтрации источника звука так, чтобы он воспринимался как поступающий из положения, определяемого ориентацией датчика. Если датчик прикреплен к устройству на голове пользователя, звук воспринимается как поступающий из одного фиксированного места, несмотря на движения головы.
Сначала загрузите набор данных HRTF.
ARIDataset = load('ReferenceHRTF.mat');Затем получите соответствующие данные HRTF из набора данных и поместите их в полезный формат для нашей обработки.
hrtfData = double(ARIDataset.hrtfData); hrtfData = permute(hrtfData,[2,3,1]);
Получение связанных исходных позиций. Углы должны находиться в том же диапазоне, что и у датчика. Преобразуйте азимуты из [0,360] в [-180,180].
sourcePosition = ARIDataset.sourcePosition(:,[1,2]); sourcePosition(:,1) = sourcePosition(:,1) - 180;
Загрузить амбисоническую запись вертолета. Сохранить только первый канал, который соответствует всенаправленной записи. Выполните повторную выборку до 48 кГц для совместимости с набором данных HRTF.
[heli,originalSampleRate] = audioread('Heli_16ch_ACN_SN3D.wav'); heli = 12*heli(:,1); % keep only one channel sampleRate = 48e3; heli = resample(heli,sampleRate,originalSampleRate);
Загрузка аудиоданных в SignalSource объект. Установите SamplesPerFrame кому 0.1 секунд.
sigsrc = dsp.SignalSource(heli, ... 'SamplesPerFrame',sampleRate/10, ... 'SignalEndAction','Cyclic repetition');
Создание audioDeviceWriter с той же частотой дискретизации, что и звуковой сигнал.
deviceWriter = audioDeviceWriter('SampleRate',sampleRate);Создайте пару фильтров FIR для выполнения бинауральной фильтрации HRTF.
FIR = cell(1,2);
FIR{1} = dsp.FIRFilter('NumeratorSource','Input port');
FIR{2} = dsp.FIRFilter('NumeratorSource','Input port');Создайте объект для визуализации ориентации датчика IMU в реальном времени. Вызовите фильтр IMU один раз и просмотрите начальную ориентацию.
orientationScope = HelperOrientationViewer; data = read(imu); qimu = imufilt(data.Acceleration,data.AngularVelocity); orientationScope(qimu);

Выполните цикл обработки в течение 30 секунд. Этот цикл выполняет следующие шаги:
Считывание данных с датчика IMU.
Чтобы оценить ориентацию датчика, запалите данные датчика IMU. Визуализация текущей ориентации.
Преобразуйте ориентацию из представления кватерниона в шаг и рыскание в углах Эйлера.
Использовать interpolateHRTF для получения пары HRTF в требуемом положении.
Считывание кадра звука из источника сигнала.
Примените HRTF к монозаписи и воспроизведите стереосигнал. Это лучше всего возможно с помощью наушников.
imuOverruns = 0; audioUnderruns = 0; audioFiltered = zeros(sigsrc.SamplesPerFrame,2); tic while toc < 30 % Read from the IMU sensor. [data,overrun] = read(imu); if overrun > 0 imuOverruns = imuOverruns + overrun; end % Fuse IMU sensor data to estimate the orientation of the sensor. qimu = imufilt(data.Acceleration,data.AngularVelocity); orientationScope(qimu); % Convert the orientation from a quaternion representation to pitch and yaw in Euler angles. ypr = eulerd(qimu,'zyx','frame'); yaw = ypr(end,1); pitch = ypr(end,2); desiredPosition = [yaw,pitch]; % Obtain a pair of HRTFs at the desired position. interpolatedIR = squeeze(interpolateHRTF(hrtfData,sourcePosition,desiredPosition)); % Read audio from file audioIn = sigsrc(); % Apply HRTFs audioFiltered(:,1) = FIR{1}(audioIn, interpolatedIR(1,:)); % Left audioFiltered(:,2) = FIR{2}(audioIn, interpolatedIR(2,:)); % Right audioUnderruns = audioUnderruns + deviceWriter(squeeze(audioFiltered)); end

Освободить ресурсы, включая звуковое устройство.
release(sigsrc) release(deviceWriter) clear imu a