各位大神,請問如何用matlab證明人耳對聲音的相位不敏感?

matlab的使用,信號處理


提供一個思路:可以設計一個相頻特性比較崎嶇的全通濾波器,把語音濾波後再聽,看看跟原來一不一樣。

全通濾波器的相頻特徵能不能設計得比較崎嶇,我已經記不得了,需要去複習數字信號處理了……


實驗成功!

先來講一下全通濾波器的原理。最簡單的全通濾波器,只有一個極點和一個零點,極點和零點的輻角相同,模互為倒數。可以驗證此濾波器在單位圓上的幅度響應為常數。

但這種一階全通濾波器的極點和零點不構成共軛複數對,它的係數就也是複數。為了得到實係數濾波器,就要在極點和零點的共軛位置再增設一對極點和零點,如下圖所示。

這種實係數二階全通濾波器,幅度響應為常數,相位響應在 0 到 pi 角頻率上會降低 2pi。極、零點越靠近單位圓,相位響應的變化就越偏離線性。

如果把多個這樣的二階全通濾波器級聯起來,就可以得到一個幅度響應為常數、相位響應非常崎嶇的全通濾波器。把一段語音通過這個濾波器再播放出來,就可以知道相位對聽覺的影響了。

如圖,我隨機生成了 10 個靠近單位圓的零極點對,搭建了一個 20 階全通濾波器。可以看到幅度響應的確為常數(那點波動是純數值誤差,可忽略),但相位響應十分崎嶇。

右上角的圖是清華電子系 2008 年夏季小學期 Matlab 課用過的男聲「電燈比油燈進步多了」的波形,右下角是濾波後的結果。二者看起來區別就不大,播放濾波後的結果,聽起來更是與原始聲音毫無區別。於是可以證明人耳對相位不敏感。

實驗用的代碼如下,你也可以換用任何一段聲音。

N = 10; % 零極點對數
pole_phi = rand(N,1) * pi; % 隨機生成極點輻角(都在 z 平面上半部分)
pole_r = 0.9 + 0.09 * rand(N,1); % 隨機生成極點的模,儘可能靠近單位圓
pole = pole_r .* exp(1i * pole_phi); % 算出極點的值
pole = [pole; conj(pole)]; % 讓極點組成共軛對
zero = 1 ./ pole; % 算出零點的值

b = poly(zero); a = poly(pole); % 由零極點算出濾波器係數
b = b / sum(b); a = a / sum(a); % 歸一化,讓濾波器的增益為 1

[x, fs] = audioread("diandeng.wav"); % 讀取聲音波形,舊版本 Matlab 用 wavread
y = filter(b, a, x); % 對聲音進行濾波
sound(y, fs); % 播放濾波後的聲音

% 下面全是畫圖

% 1. 零極點圖
subplot(2, 3, [1 4]);
zplane(zero, pole);
title("Zero-Pole Plot");

% 2. 幅頻、相頻響應圖
n = 1024; m = n / 2 + 1; % FFT 點數
H = fft(b, n) ./ fft(a, n); % 傳輸函數
H = H(1:m); % 由對稱性,只保留一半

subplot 232;
plot(linspace(0, 1, m), abs(H)); % 畫幅頻響應
xlabel("omega / pi");
ylabel("Gain");
title("Amplitude Response");

subplot 235;
plot(linspace(0, 1, m), angle(H) / pi); % 畫相頻響應
xlabel("omega / pi");
ylabel("Phase shift / pi");
title("Phase Response");

% 3. 聲音波形圖
t = (0:length(x) - 1) / fs; % 時間軸

subplot 233;
plot(t, x); % 畫濾波前的聲音
xlabel("Time / s");
set(gca, "YLim", [-1 1]);
title("Original Waveform");

subplot 236;
plot(t, y); % 畫濾波後的聲音
xlabel("Time / s");
set(gca, "YLim", [-1 1]);
title("Filtered Waveform");


寫一下吧,沒有自己跑過,不是真正的代碼,你可以當作類matlab格式的偽代碼吧。

%x是語音信號

X = fft(x) %求頻譜

Mag = abs(X) % 計算振幅

phi = angle(X) % 計算相位

delta_phi = rand(n,1) ; %隨便你怎麼改啦

phi_changed = mod(phi+delta_phi+pi,-2*pi) + pi; %改過之後的相位還在-pi 和 pi之間

ft = (Mag.* exp(1i*phi_changed)); %改變相位後的頻譜

x_out = real(ifft(ft)); 生成改變或相位的語音信號。

%播放

player = audioDeviceWriter("SampleRate",fs);

player(x);

player(x_out);

%---------------------分割線------------------------

做個廣告,有語音信號處理的問題的話歡迎加入QQ群:485186545


以前上課時考慮過交換兩段語音的相位,不知道如何正確處理。提供一個有趣的實現現象。

如果簡單粗暴交換兩個同等長度語音片段的相位譜的話(幅度譜不變),語音內容(文本)會交換。

可能的方法:設計一個調節相位的全通濾波器,將語音通過濾波器,再聽聽語音。

——————————————————————————————————————————

更新: 找到2014年我在水木上提的問題「語音對相位不敏感是什麼意思」, 正好當時貼了我的一些測試代碼和測試音頻(知乎上傳不了),雖然最終也沒搞清應該如何測試(因為沒人真正做過類似實驗),我想到過全通濾波器,但是沒設計過物理可用的全通濾波器,所以也沒做實驗。僅供參考。 (分幀處理後拼在一起現在感覺還是很不合理的)

根據feb29的提示,我重新做了一下實驗,先對語音分幀,然後每幀把相位隨機化,結果能聽出雜訊感,但是能分辨出語音內容。

貼出我的測試代碼和測試語音,matlab下運行

clear all; close all; clc;

[x,sr]=wavread("thu8k.wav"); %sr為採樣頻率

x = (x(:,1)+x(:,2))/2; % 左右聲道

s=length(x);

% figure; plot((1:s)/sr,x); xlabel("時間/s");

% title("清華大學");

%% 下面這段把語音分為兩段,然後交換兩段的相位,結果似乎說明相位比幅度更重要

% x1 = x(1:s/2); x2 = x(s/2+1:end);

% sound(x1,sr);

% sound(x2,sr);

% X1 = fft(x1); X2 = fft(x2);

% Y1 = abs(X1).*exp(1i*angle(X2)); y1 = real(ifft(Y1));

% Y2 = abs(X2).*exp(1i*angle(X1)); y2 = real(ifft(Y2));

% sound(y1,sr);

% sound(y2,sr);

%% 這段是先分幀,對給個短時幀把相位隨機化,結果有雜訊感,但是能分辨出語音內容,幀長到1s左右還能夠勉強聽清內容。 更長分幀則語音聽著更像雜訊了

for j = 1:10

N = 160*j; % 20*j ms

frame_num = ceil(s/N);

xx = [x; zeros(N*frame_num-s, 1)];

for i = 1:frame_num

Xi = fft( xx( (i-1)*N+1: i*N));

ang = (2*rand(size(Xi))-1)*pi; % 隨機相位(-pi, pi)

ang = [ang(1:N/2); 0; -ang(N/2:-1:2)]; %保證相位奇對稱

XXi = abs(Xi).*exp(1i*ang);

xx( (i-1)*N+1: i*N) = real( ifft( XXi));

end

% sound(x);

sound(xx);

end


sound(speech,fs);

sound(-speech,fs);

耳朵聽起來完全是一樣的。


對聲音(語音)和圖片來說,將A的相位和B的頻譜組合,得到的結果總是和A比較接近。或者說,聲音和圖片的信息更多的在相位中。

pepper = rgb2gray(imread("pepper.bmp"));
pepper = imresize(pepper,[512 512]);
lena = rgb2gray(imread("lenna.bmp"));
lena = imresize(lena, [512 512]);

PEPPER = fft2(pepper);
LENA = fft2(lena);

R1 = abs(PEPPER).*exp(1i*angle(LENA));
R2 = abs(LENA).*exp(1i*angle(PEPPER));
r1 = abs(ifft2(R1));
r2 = abs(ifft2(R2));

imshow([lena pepper;r1 r2]);
%%
[data, Fs] = audioread("1.mp3");
s = (1:Fs*3);
y1 = data(round(size(data,1)/2)+s,1);
y2 = data(round(size(data,1)/3)+Fs+s,1);

Y1 = fft(y1);
Y2 = fft(y2);

N1 = abs(Y1).*exp(1i*angle(Y2));
N2 = abs(Y2).*exp(1i*angle(Y1));

n1 = abs(ifft(N1));
n2 = abs(ifft(N2));

sound(y1,Fs);
pause(4);
sound(y2,Fs);
pause(4);
sound(n1,Fs);
pause(4);
sound(n2,Fs);

圖片是lena和pepper。聲音是在桌面上發現的配樂詩朗誦《腹瀉與電梯》。這裡可以下載到。腹瀉與電梯-NGA - Edison重口味電台 - 電台節目 - 網易雲音樂


可以對一段音頻信號做全反相,然後讓matlab播放出來再聽聽,跟未做處理前的效果對比。從最小

二乘的角度而言全反相應該是對信號相位改變最大的方式了吧,如果這種情況下人還不能分辨出差

別的話,那就說明人對聲音相位真的不敏感。


這大概是個偽命題。

樓主先告訴我,什麼是相位?然後告訴我,什麼叫對相位不敏感?

我想樓主想說的可能是:我們耳朵能察覺聲音頻率的變化(音高),能感知幅度的起伏(響度),但我們感覺不出相位的變化???

我所理解的,首先必須明確相位不是一個絕對量,而是因為比較才出來的相對量,所以他其實是相位差,它有兩種:空間相差和時間相差。

空間相差和時間相差由波速聯繫起來。

樓主如果想說,兩段音頻信號,初始相位(兩段信號有時間上的相差)不一致,聽到的為什麼感覺相同?

這個我能回答,因為人的感知系統本質上也是一個分析器,分析的是一段一段的時間信號,初始相差對信號分析結果沒有任何意義。

所以,這裡的關鍵是,不敏感是什麼意思?


推薦閱讀:

請通俗易懂地解釋一下guidata()的用法?以及他是如何幫助參數在GUI間傳遞的?
Matlab畫圖增加右邊坐標軸的刻度,與左邊一樣,如何處理?
請問怎麼用matlab 畫一個傾斜的橢球?
「MatLab 模擬結論在工業界認可度低」是否屬實?
matlab計算速度?

TAG:MATLAB | 數字信號處理 |