MATLAB: How to make Narrow Bandpass filter

bandpassfilter

I have a signal, that has a bunch of noise and sine signals in it, 4 sine signals too be exact, and 4 noise signals.
i have pin pointed the frequencies of these sine signals to be 159.0574, 359.3519, 459.4992, 709.8674.
The signal and its spektrum looks like this:
I need to filter out all the noise, so i tried too use bandpass, using each sine frequency :
f1 = bandpass(signalas, [floor(virsunes(1)) ceil(virsunes(1))], Fd);
f2 = bandpass(signalas, [floor(virsunes(2)) ceil(virsunes(2))], Fd);
f3 = bandpass(signalas, [floor(virsunes(3)) ceil(virsunes(3))], Fd);
f4 = bandpass(signalas, [floor(virsunes(4)) ceil(virsunes(4))], Fd);
virsunes is just an array of those frequencies.
When i combined the filtered signals, i got this:
A lot of the noise has stuck around because it's too close too the sine signal. How to make a bandpass filter more narrow, for it too filter all the noise?
I attached the signal file "G4_12.dot".

Best Answer

hello
seems I have already seen similar post somewhere... a buddy of yours ?
you did not mentionned the sampling frequency , but 24 kHz seemed correct
here my little contribution :
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%





% options
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% spectrogram dB scale
spectrogram_dB_scale = 60; % dB range scale (means , the lowest displayed level is XX dB below the max level)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% load signal
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% test data
Fs = 24000;
% t = 0:1/Fs:10-1/Fs;
fid = fopen('G4_12.dat','r')
[signal,samples] = fscanf(fid, '%12f');
fclose(fid);
% decimate
decim = 12;
signal = decimate(signal,decim);
Fs = Fs/decim;
samples = length(signal);
time =(1:samples)/Fs;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% FFT parameters
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
n_max = fix(log2(samples));
NFFT = 2^(n_max-1); % 2^n with n chosen so that NFFT is below length of signal (even after decimation) by factor > 2 so some averaging is doable
% NFFT = 2048/4; % 2^n with n chosen so that NFFT is below length of signal (even after decimation) by factor > 2 so some averaging is doable
NOVERLAP = round(0.95*NFFT);
w = hanning(NFFT); % Hanning window / Use the HANN function to get a Hanning window which has the first and last zero-weighted samples.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%



% display : averaged FFT spectrum before filter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[sensor_spectrum, freq] = pwelch(signal,w,NOVERLAP,NFFT,Fs,'power');
sensor_spectrum_dB = 10*log10(sensor_spectrum);% convert to dB scale (ref = 1)

% sensor_spectrum_dB = sensor_spectrum_dB-min(sensor_spectrum_dB); % y axis shift so dB values are positive (min value = 0)
%% findpeaks
% df = Fs/NFFT;
% MAXW = 10*df;
% MPD = 20;
% MPP = 20;
% [peaks,loc,W,P] = findpeaks(sensor_spectrum_dB,'MinPeakDistance',MPD,'MaxPeakWidth',MAXW,'MinPeakProminence',MPP);
% freq_peaks = freq(loc);
freq_peaks = [159.0574, 359.3519, 459.4992, 709.8674];
peaks = interp1(freq,sensor_spectrum_dB,freq_peaks,'linear');
figure(1),plot(freq,sensor_spectrum_dB,'b',freq_peaks,peaks,'*r');grid
title(['Averaged FFT Spectrum / Fs = ' num2str(Fs) ' Hz / Delta f = ' num2str(freq(2)-freq(1)) ' Hz ']);
xlabel('Frequency (Hz)');ylabel(' dB')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% display 2 : time / frequency analysis : spectrogram demo
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[sg,fsg,tsg] = specgram(signal,NFFT,Fs,hanning(NFFT),NOVERLAP);
% FFT normalisation and conversion amplitude from linear to dB (peak)
sg_dBpeak = 20*log10(abs(sg))+20*log10(2/length(fsg)); % NB : X=fft(x.*hanning(N))*4/N; % hanning only
% scalingf the dB range :
min_disp_dB = round(max(max(sg_dBpeak))) - spectrogram_dB_scale;
sg_dBpeak(sg_dBpeak<min_disp_dB) = min_disp_dB;
% plots spectrogram
figure(2);
imagesc(tsg,fsg,sg_dBpeak);colormap('jet');
axis('xy');colorbar('vert');grid
title(['Spectrogram / Fs = ' num2str(Fs) ' Hz / Delta f = ' num2str(fsg(2)-fsg(1)) ' Hz ']);
xlabel('Time (s)');ylabel('Frequency (Hz)');
% keep only signal content extracted by bandpass filters
fc = freq_peaks; % Hz

bandwith = 8; % Hz
f_low = fc-0.5*bandwith;
f_high = fc+0.5*bandwith;
N = 4;
signal_filtered = zeros(size(signal));
for ci = 1:length(fc)
[b,a] = butter(N,2/Fs*[f_low(ci) f_high(ci)]);
% add filtered signal to total final signal
tmp = filtfilt(b,a,signal);
signal_filtered = signal_filtered + tmp;
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% display : averaged FFT spectrum before / after notch filter
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[sensor_spectrum_filtered, freq] = pwelch(signal_filtered,w,NOVERLAP,NFFT,Fs,'power');
sensor_spectrum_filtered_dB = 10*log10(sensor_spectrum_filtered);% convert to dB scale (ref = 1)
figure(4),plot(freq,sensor_spectrum_dB,'b',freq,sensor_spectrum_filtered_dB,'r');grid
title(['Averaged FFT Spectrum / Fs = ' num2str(Fs) ' Hz / Delta f = ' num2str(freq(2)-freq(1)) ' Hz ']);
legend('before filter','after filter');
xlabel('Frequency (Hz)');ylabel(' dB')
figure(5),plot(time,signal_filtered,'b');grid
title('Filtered signal');
xlabel('Time (s)');ylabel(' amplitude')
Related Question