Отслеживайте ориентацию головы путем сплавления данных, полученных от БИНС, и затем управляйте направлением прибытия источника звука путем применения связанных с головой передаточных функций (HRTF).
При типичной настройке виртуальной реальности датчик БИНС крепится к наушникам или VR-гарнитуре пользователя так, чтобы воспринимаемое положение источника звука было относительно визуальной подсказки, независимой от движений головы. Например, если звук воспринимается как исходящий от монитора, он остается таким, даже если пользователь поворачивает голову в сторону.
Arduino
Функции Invensense MPU-9250
Сначала подключите MPU-9250 Invensense к плате Arduino. Для получения дополнительной информации см. «Оценка ориентации с помощью синтеза инерционного датчика и MPU-9250».
Создайте arduino
объект.
a = arduino;
Создайте объект датчика MPU-9250 Invensense.
imu = mpu9250(a);
Создайте и установите частоту дискретизации фильтра Калмана.
Fs = imu.SampleRate;
imufilt = imufilter('SampleRate',Fs);
Когда звук перемещается от точки в пространстве к ушам, можно локализовать его на основе интеравральных различий во времени и уровне (ITD и ILD). Эти частотно-зависимые ITD и ILD могут быть измерены и представлены в виде пары импульсных характеристик для любого заданного повышения и азимута источника. Набор данных HRTF ARI содержит 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);
Создайте пару конечных импульсных характеристик для выполнения бинауральной фильтрации HRTF.
FIR = cell(1,2); FIR{1} = dsp.FIRFilter('NumeratorSource','Input port'); FIR{2} = dsp.FIRFilter('NumeratorSource','Input port');
Создайте объект, чтобы выполнить визуализацию в реальном времени для ориентации датчика IMU. Один раз вызовите фильтр БИНС и отобразите начальную ориентацию.
orientationScope = HelperOrientationViewer; data = read(imu); qimu = imufilt(data.Acceleration,data.AngularVelocity); orientationScope(qimu);
Выполните цикл обработки в течение 30 секунд. Этот цикл выполняет следующие шаги:
Считайте данные с датчика БИНС.
Для оценки ориентации датчика используйте данные БИНС. Визуализация текущей ориентации.
Преобразуйте ориентацию из представления кватерниона в тангаж и рыскание в углах Эйлера.
Использование 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