Вы ослабляете значение выборки частоты постоянного тока до нуля? Похоже, что вы не ослабляете это вообще в своем примере. Поскольку вы реализуете фильтр верхних частот, вам также необходимо установить значение DC на ноль.
Это объясняет низкочастотные искажения. У вас будет много пульсаций в частотной характеристике на низких частотах, если это значение постоянного тока будет ненулевым из-за большого перехода.
Вот пример в MATLAB / Octave для демонстрации того, что может происходить:
N = 32;
os = 4;
Fs = 1000;
X = [ones(1,4) linspace(1,0,8) zeros(1,3) 1 zeros(1,4) linspace(0,1,8) ones(1,4)];
x = ifftshift(ifft(X));
Xos = fft(x, N*os);
f1 = linspace(-Fs/2, Fs/2-Fs/N, N);
f2 = linspace(-Fs/2, Fs/2-Fs/(N*os), N*os);
hold off;
plot(f2, abs(Xos), '-o');
hold on;
grid on;
plot(f1, abs(X), '-ro');
hold off;
xlabel('Frequency (Hz)');
ylabel('Magnitude');
АЧХ http://www.freeimagehosting.net/uploads/e10109e535.png
Обратите внимание, что в моем коде я создаю пример значения DC, отличного от нуля, с последующим резким изменением на ноль и затем увеличением. Затем я беру IFFT для преобразования во временную область. Затем я выполняю заполненное нулями fft (которое выполняется автоматически MATLAB, когда вы передаете размер fft больше входного сигнала) для этого сигнала во временной области. Заполнение нулями во временной области приводит к интерполяции в частотной области. Используя это, мы можем видеть, как фильтр будет реагировать между выборками фильтра.
Одна из самых важных вещей, которую следует помнить, заключается в том, что даже если вы устанавливаете значения отклика фильтра на заданных частотах путем ослабления выходных сигналов DFT, это ничего не гарантирует для частот, возникающих между точками выборки. Это означает, что чем более резкими будут ваши изменения, тем больше будет скачков и колебаний между выборками.
Теперь, чтобы ответить на ваш вопрос о том, как должна выполняться эта фильтрация. Существует несколько способов, но одним из самых простых для реализации и понимания является метод проектирования окон. Проблема с вашим текущим дизайном в том, что ширина перехода огромна. В большинстве случаев вам понадобится как можно быстрее переходить с минимально возможными колебаниями.
В следующем коде я создам идеальный фильтр и выведу ответ:
N = 32;
os = 4;
Fs = 1000;
X = [ones(1,8) zeros(1,16) ones(1,8)];
x = ifftshift(ifft(X));
Xos = fft(x, N*os);
f1 = linspace(-Fs/2, Fs/2-Fs/N, N);
f2 = linspace(-Fs/2, Fs/2-Fs/(N*os), N*os);
hold off;
plot(f2, abs(Xos), '-o');
hold on;
grid on;
plot(f1, abs(X), '-ro');
hold off;
xlabel('Frequency (Hz)');
ylabel('Magnitude');
АЧХ http://www.freeimagehosting.net/uploads/c86f5f1700.png
Обратите внимание, что существует много колебаний, вызванных резкими изменениями.
БПФ или дискретное преобразование Фурье является выборочной версией преобразования Фурье. Преобразование Фурье применяется к сигналу в непрерывном диапазоне от бесконечности до бесконечности, тогда как ДПФ применяется к конечному числу выборок. Это в действительности приводит к квадратному оконному отображению (усечению) во временной области при использовании ДПФ, поскольку мы имеем дело только с конечным числом выборок. К сожалению, ДПФ прямоугольной волны является функцией типа sinc (sin (x) / x).
Проблема с резкими переходами в вашем фильтре (быстрый переход от 0 до 1 в одном примере) состоит в том, что он имеет очень длинный отклик во временной области, который усекается квадратным окном. Таким образом, чтобы минимизировать эту проблему, мы можем умножить сигнал во временной области на более постепенное окно. Если мы умножим окно Ханнинга, добавив строку:
x = x .* hanning(1,N).';
после принятия IFFT мы получаем такой ответ:
АЧХ http://www.freeimagehosting.net/uploads/944da9dd93.png
Поэтому я бы порекомендовал попытаться реализовать метод проектирования окон, поскольку он довольно прост (есть лучшие способы, но они усложняются). Поскольку вы внедряете эквалайзер, я предполагаю, что вы хотите иметь возможность изменять затухания на лету, поэтому я бы посоветовал рассчитывать и хранить фильтр в частотной области при каждом изменении параметров, а затем вы можете просто применить его к каждому входному аудиобуферу, взяв fft входного буфера, умножив его на выборки фильтра в частотной области, а затем выполнив ifft, чтобы вернуться во временную область. Это будет намного эффективнее, чем все ветвления, которые вы делаете для каждого образца.