Учитывая довольно динамичный характер помех в вашей выборке, стационарные фильтры не будут давать очень удовлетворительных результатов.Чтобы повысить производительность, вам нужно будет динамически регулировать параметры фильтрации на основе оценок помех.
К счастью, в этом случае помехи довольно сильные и имеют довольно регулярный характер, что облегчает оценку.Это видно из сигнала spectrogram
.Для следующих выводов мы будем предполагать, что выборки wavfile были сохранены в массиве x
и что частота дискретизации составляет fs
(что составляет 8000 Гц в предоставленной выборке).
[Sx,f,t] = spectrogram(x, triang(1024), 1023, [], fs, 'onesided');
Учитывая, что помехи сильны, получение частоты помехи может быть выполнено путем определения максимальной частоты в каждом временном интервале:
frequency = zeros(size(Sx,2),1);
for k = 1:size(Sx,2)
[pks,loc] = findpeaks(Sx(:,k));
frequency(k) = fs * (loc(1)-1);
end
Видя, что помехи являются периодическими, мы можем использовать дискретное преобразование Фурье для разложения этого сигнала:
M = 32*fs;
Ff = fft(frequency, M);
plot(fs*[0:M-1]/M, 20*log10(abs(Ff));
axis(0, 2);
xlabel('frequency (Hz)');
ylabel('amplitude (dB)');
Использование первых двух гармоник в качестве приближениямы можем смоделировать частоту интерференционного сигнала как:
T = 1.0/fs
t = [0:length(x)-1]*T
freq = 750.0127340203496
+ 249.99913423501602*cos(2*pi*0.25*t - 1.5702946346796276)
+ 250.23974282864816*cos(2*pi*0.5 *t - 1.5701043282285363);
. На этом этапе нам будет достаточно создать узкополосный фильтр с центральной частотой (который будет динамически изменяться по мере обновления коэффициентов фильтра).дается этой частотной моделью.Отметим, однако, что постоянный пересчет и обновление коэффициента фильтра является довольно дорогостоящим процессом, и, учитывая, что помехи являются сильными, можно добиться большего, зафиксировав фазу помехи.Это может быть сделано путем соотнесения небольших блоков исходного сигнала с синусом и косинусом на желаемой частоте.Затем мы можем слегка настроить фазу, чтобы выровнять синус / косинус с исходным сигналом.
% Compute the phase of the sine/cosine to correlate the signal with
delta_phi = 2*pi*freq/fs;
phi = cumsum(delta_phi);
% We scale the phase adjustments with a triangular window to try to reduce
% phase discontinuities. I've chosen a window of ~200 samples somewhat arbitrarily,
% but it is large enough to cover 8 cycles of the interference around its lowest
% frequency sections (so we can get a better estimate by averaging out other signal
% contributions over multiple interference cycles), and is small enough to capture
% local phase variations.
step = 50;
L = 200;
win = triang(L);
win = win/sum(win);
for i = 0:floor((length(x)-(L-step))/step)
% The phase tweak to align the sine/cosine isn't linear, so we run a few
% iterations to let it converge to a phase locked to the original signal
for iter = 0:1
xseg = x[(i*step+1):(i*step+L+1)];
phiseg = phi[(i*step+1):(i*step+L+1)];
r1 = sum(xseg .* cos(phiseg));
r2 = sum(xseg .* sin(phiseg));
theta = atan2(r2, r1);
delta_phi[(i*step+1):(i*step+L+1)] = delta_phi[(i*step+1):(i*step+L+1)] - theta*win;
phi = cumsum(delta_phi);
end
end
Наконец, нам нужно оценить амплитуду помехи.Здесь мы выбираем выполнение оценки в течение начальных 0,15 секунд, когда перед началом речи есть небольшая пауза, чтобы оценка не была смещена по амплитуде речи:
tmax = 0.15;
nmax = floor(tmax * fs);
amp = sqrt(2*mean(x[1:nmax].^2));
% this should give us amp ~ 0.250996990794946
Эти параметры затем позволяют нам достаточноточно восстановить помехи и, соответственно, устранить помехи из исходного сигнала путем прямого вычитания:
y = amp * cos(phi)
x = x-y
Прослушивая полученный результат, вы можетезаметить оставшийся слабый свистящий шум, но ничто по сравнению с первоначальным вмешательствомОчевидно, что это довольно идеальный случай, когда параметры интерференции настолько легко оценить, что результаты выглядят слишком хорошими, чтобы быть правдой.Вы не можете получить ту же производительность с большим количеством случайных помех.
Примечание : скрипт Python, используемый для этой обработки (и соответствующий вывод файла .wav), можно найти здесь .