ピアノの録音で周波数を検出する MATLAB コードを書いています。
キーボードを使用して録音した C スケールのオーディオ ファイルを使用しました (C4 D4 E4 F4 G4 A4 B4 C5)
単純にFFTを実行すると(ウィンドウに侵入せずに)、基本周波数の振幅が大きくなり、完全に問題ありません。
しかし、より正確にするために、次の手順を実行しました。2. ピーク検出アルゴリズムを実装して、ノートの始まりを見つけます。3. 各オンセットを取得して、各音符の FFT を取得するために、それぞれに FFT を実行しました。ただし、上記のオーディオ ファイルに対してこれを行うと、間違った結果が得られます。ハーモニクスの振幅が 1 番目よりも高い場合があります。
clear all;
clear max;
clc;
%% create 5s sample at 10kHz with tone from 1s to 2s
FS = 10000; % 10kHz
N=5*FS;
song = randn(N,2)/10;
song(FS:2*FS,:)=10*repmat(sin(261*pi*2*(0:FS)/FS)',1,2)+song(FS:2*FS,:);
P = 2000;
t=0:1/FS:(N-1)/FS; % define time period
song = sum(song,2);
song=abs(song);
%----------------------Finding the envelope of the signal-----------------%
% Gaussian Filter
x = linspace( -1, 1, P); % create a vector of P values between -1 and 1 inclusive
sigma = 0.335; % standard deviation used in Gaussian formula
myFilter = -x .* exp( -(x.^2)/(2*sigma.^2)); % compute first derivative, but leave constants out
myFilter = myFilter / sum( abs( myFilter ) ); % normalize
% fft convolution
myFilter = myFilter(:); % create a column vector
song(length(song)+length(myFilter)-1) = 0; %zero pad song
myFilter(length(song)) = 0; %zero pad myFilter
edges =ifft(fft(song).*fft(myFilter));
tedges=edges(P:N+P-1); % shift by P/2 so peaks line up w/ edges
tedges=tedges/max(abs(tedges)); % normalize
%---------------------------Onset Detection-------------------------------%
% This section does the peak picking algorithm
max_col = maxtab(:,1);
peaks_det = max_col/FS;
No_of_peaks = length(peaks_det);
%---------------------------Performing FFT--------------------------------
song_seg = song(max_col(1):max_col(2)-1);
L = length(song_seg);
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
seg_fft = fft(song_seg,NFFT);%/L;
f = FS/2*linspace(0,1,NFFT/2+1);
seg_fft2 = 2*abs(seg_fft(1:NFFT/2+1));
L5 = length(song_seg);
fmin = 60;
fmax = 1000;
region_of_interest = fmax>f & f>fmin;
froi = f(region_of_interest);
[p_max,loc] = max(seg_fft2(region_of_interest));
% index into froi to find the frequency of the peaks
p_max;
f_p_max = froi(loc);
[points, locatn] = findpeaks(seg_fft2(region_of_interest));
aboveMax = points > 0.4*p_max;
if any(aboveMax)
peak_points = points(aboveMax)
f_peak = froi(locatn(aboveMax))
end
end
ここで何が間違っているのですか?ここで本当に本当に助けが必要です......
D4 の f0 はまったく検出されていませんが、C4 と E4 の f0 は高調波に比べて振幅が小さいことがわかります。