在 FFT 之后归一化每个单独的频率
Normalize each individual frequency after FFT
我正在编写一个程序,可以直观地显示构成音频的频率。为此,我有一个滚动 window,我对其执行 FFT(我将 post 代码放在底部)。让我感兴趣的是,我所有的地块在 0hz 侧附近都有高功率,在 10khz 侧附近有低功率:
我想更改图表,而不是显示实际功率,而是显示相对于歌曲其余部分相同频率的功率的功率。例如,我想让它在 0hz 处的最大值与在 10khz 处的最大值相同。这意味着在低频时降低 y 值并在高频时提高它。我将如何着手进行此操作并使其看起来像图表不在向下倾斜?
作为旁注,在算法运行后,我将流式传输音频而不是从音频文件中读取它,这样可以消除在整首歌曲中保持每个频率平均值的可能性。
% Prototype to graph moving window of FFT through an audio file in real time
clear all;
warning('off','MATLAB:colon:nonIntegerIndex'); % Suppress integer operand errors because it's ok to round for the window size
% Read Audio
fs = 44100; % sample frequency (Hz)
full = audioread('O.mp3');
% Remove leading 0's and select range
for i = 1:fs
if full(i) ~= 0
crop = i;
break
end
end
full = full(crop:end);
startTime = 0;
endTime = length(full)/fs;
% Play song
tic
player = audioplayer(full(fs*startTime+1:fs*endTime), fs);
player.play();
initialTime = toc;
% Perform fft and get frequencies (hopefully in realish time with audio)
windowSize = fs/8;
for i = windowSize/2+1+fs*startTime : fs/16 : fs*endTime
beginningChunk = round(i-windowSize/2);
endChunk = round(i+windowSize/2);
x = full(beginningChunk:endChunk);
y = fft(x);
n = length(x); % number of samples in chunk
power = abs(y).^2/n; % power of the DFT
power = power(1:end/2);
f = (0:n-1)*(fs/n); % frequency range
f = f(1:end/2);
while initialTime+i/fs > toc
pause(.0001);
end
figure(1);
plot(f,power);
axis([0 10000 0 5]);
xlabel('Frequency');
ylabel('Power');
end
将功效表示为 z 分数
准备 [t,f]
个基线样本
winrange = windowSize/2+1+fs*startTime : fs/16 : fs*endTime;
for i = winrange
...
% base_pow is [# of time bins,# freq bins]
base_pow(i == winrange,:) = power(1:end/2);
...
end
根据基线数据对每个样本进行标准化
for i = winrange
...
raw_pow = power(1:end/2);
% collapse across 1st dimension of base_pow
norm_pow = (raw_pow - mean(base_pow,1))./std(base_pow,[],1)
...
end
信号流
上述解决方案要求您使用完整示例。一种计算效率更高的方法是在流式传输任何样本之前将某些函数拟合到多个音轨,并使用该曲线进行归一化。
我正在编写一个程序,可以直观地显示构成音频的频率。为此,我有一个滚动 window,我对其执行 FFT(我将 post 代码放在底部)。让我感兴趣的是,我所有的地块在 0hz 侧附近都有高功率,在 10khz 侧附近有低功率:
我想更改图表,而不是显示实际功率,而是显示相对于歌曲其余部分相同频率的功率的功率。例如,我想让它在 0hz 处的最大值与在 10khz 处的最大值相同。这意味着在低频时降低 y 值并在高频时提高它。我将如何着手进行此操作并使其看起来像图表不在向下倾斜?
作为旁注,在算法运行后,我将流式传输音频而不是从音频文件中读取它,这样可以消除在整首歌曲中保持每个频率平均值的可能性。
% Prototype to graph moving window of FFT through an audio file in real time
clear all;
warning('off','MATLAB:colon:nonIntegerIndex'); % Suppress integer operand errors because it's ok to round for the window size
% Read Audio
fs = 44100; % sample frequency (Hz)
full = audioread('O.mp3');
% Remove leading 0's and select range
for i = 1:fs
if full(i) ~= 0
crop = i;
break
end
end
full = full(crop:end);
startTime = 0;
endTime = length(full)/fs;
% Play song
tic
player = audioplayer(full(fs*startTime+1:fs*endTime), fs);
player.play();
initialTime = toc;
% Perform fft and get frequencies (hopefully in realish time with audio)
windowSize = fs/8;
for i = windowSize/2+1+fs*startTime : fs/16 : fs*endTime
beginningChunk = round(i-windowSize/2);
endChunk = round(i+windowSize/2);
x = full(beginningChunk:endChunk);
y = fft(x);
n = length(x); % number of samples in chunk
power = abs(y).^2/n; % power of the DFT
power = power(1:end/2);
f = (0:n-1)*(fs/n); % frequency range
f = f(1:end/2);
while initialTime+i/fs > toc
pause(.0001);
end
figure(1);
plot(f,power);
axis([0 10000 0 5]);
xlabel('Frequency');
ylabel('Power');
end
将功效表示为 z 分数
准备 [t,f]
个基线样本
winrange = windowSize/2+1+fs*startTime : fs/16 : fs*endTime;
for i = winrange
...
% base_pow is [# of time bins,# freq bins]
base_pow(i == winrange,:) = power(1:end/2);
...
end
根据基线数据对每个样本进行标准化
for i = winrange
...
raw_pow = power(1:end/2);
% collapse across 1st dimension of base_pow
norm_pow = (raw_pow - mean(base_pow,1))./std(base_pow,[],1)
...
end
信号流
上述解决方案要求您使用完整示例。一种计算效率更高的方法是在流式传输任何样本之前将某些函数拟合到多个音轨,并使用该曲线进行归一化。