Low pass filtering not working as expected - matlab

The following Matlab script is for filtering a signal consisting of a 50 Hz and 120 Hz sine. I am calculating the frequnecy in rad/s as Fp= (2*PI * 30)/1000=0.184.
I have kept fp=0.184 and fst=0.185, as I want to filter out both 50 hz and 120 Hz.
But when I am plotting the FFT of the output of the filter, what I am getting is a sine at 50 Hz. Why this 50Hz sine is coming even after filtering?
Ideally there should not be any peak in the plot.
Before filtering
after filtering
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sample time
L = 1000; % Length of signal
t =(0:L-1)*T; % Time vector
x = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t); % Sum of a 50 Hz sinusoid and a 120 Hz sinusoid %
y = x + 2*randn(size(t)); % Sinusoids plus noise
y = x ;
plot(Fs*t(1:50),y(1:50));title('Signal');xlabel('time (milliseconds)')
%pause;
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(y,NFFT)/L; f = Fs/2*linspace(0,1,NFFT/2+1);
% Plot single-sided amplitude spectrum.
plot(f,2*abs(Y(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of y(t)');xlabel('Frequency(Hz)');ylabel('|Y(f)|')
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Now let us see Low Pass Filtering of this signal
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Fp= (2*pi * 30)/1000; %=0.184 %only frequncies less than 30Hz will be passed
d=fdesign.lowpass('Fp,Fst,Ap,Ast',0.184,0.185,2,60);
designmethods(d);
Hd = design(d,'equiripple'); fvtool(Hd);
Filterd_Output = filter(Hd,y);
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Filtered_Freq = fft(Filterd_Output,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
% Plot single-sided amplitude spectrum.
plot(f,2*abs(Filtered_Freq(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of Low Pass Filtered_Output')
xlabel('Frequency (Hz)');ylabel('|Filtered_Freq_Amplitude|')
Update
As suggested I compared the original spectrum with the filterd one. This explains me a lot. But is there any way so that I can reduce this spike at 50 Hz further?

You incorrectly specify the normalized frequencies for the filter. Matlab assumes the frequency to be in [0, 1], not in [0, pi].
Replace
d=fdesign.lowpass('Fp,Fst,Ap,Ast',0.184,0.185,2,60);
with
d=fdesign.lowpass('Fp,Fst,Ap,Ast', 2*30/Fs, 2*35/Fs,2,60);
or alternatively
d=fdesign.lowpass('Fp,Fst,Ap,Ast', 30, 35,2,60, Fs);
and it should work as expected.

Related

Findpeaks in Spectrum Matalb

I am trying to find peaks in spectrum but I need to extract only peak of base frequency and its harmonics, red rectangular. How to exclude anything before base frequency and only include base frequency and its 3 harmonics. I use this code but it does not help. Any idea?
pks = findpeaks(q);
findpeaks(q,'MinPeakDistance',99)
%findpeaks(q,'MinPeakHeight',0.0004)
xlim([0.1 500])
When using:
Fs = 1000;
t = 0:0.001:1-0.001; % 250-Hz sine wave modulated at 100 Hz
x = [1+cos(2*pi*100*t)].*cos(2*pi*250*t);
%envspectrum(x,Fs)
[ES,F]=envspectrum(x,Fs);
%%
findpeaks(ES,F)
% Now for only > 99 Hz (choose the freq you fancy)
idx = F >= 99; % greater than 99 Hz
findpeaks(ES(idx),F(idx)) % idx only select those F > 99
% Good? Keep the values of amplitud and location (in frequencies) of the ES
[pks,loc] = findpeaks(ES(idx),F(idx));
% If you just want to have the first 5 peaks (or the n? you choose):
% Select only 3 first.
if length(pks) > 3 % Check you didnt get less peaks
pks = pks(1:3);
loc = loc(1:3);
end
% To plot the peaks in the envelope
plot(F(idx),ES(idx),loc,pks,'r*')
I get this:
And this as result:
EDITED to adapt to new code with an example. We are applying on the envelope spectrum of a signal - [ES,F] = envspectrum(sig,Fs);-, so we know the signal and its frequency sampling (fs).
Still being the same process. You can just compute the values in findpeaks() for only those samples of your signal which are higher than 250 Hz. For that purpose, you define a logical array for the frequencies values you want to:
idx = F >= 250; % 250 Hz
And apply this logical index to the envelop spectrum of your signal and frequencies where you want to apply the function findpeaks():
[pks,loc] = findpeaks(ES(idx),F(idx));
Example:
% Let's create a signal with fs = 2500 Hz
% This is just to create an example, don't worry about these lines
fs = 2500;
f0 = 25;
n = 8;
d = 0.02;
p = 0.12;
t = 0:1/fs:1-1/fs;
z = [1 0.5 0.2 0.1 0.05]*sin(2*pi*f0*[1 2 3 4 5]'.*t)/5;
% z: our signal
% t: time array of the signal (to plot)
% How does the signal look?
plot(t,z)
% Calculating the envelope signal and its spectrum
[ES,F]=envspectrum(z,fs);
% Plot the envelop if you want:
envspectrum(z,fs)
% ES: Envelope spectrum of the signal
% F: array of frequencies used for the spectrum (half our fs for Nyquist Theorem)
% Find the peaks of the envelope spectrum
% Let's see how it is for all the envelope
findpeaks(ES,F)
% Now for only > 250 Hz (choose the freq you fancy)
idx = F >= 250; % greater than 250 Hz
findpeaks(ES(idx),F(idx)) % idx only select those F > 250
% Good? Keep the values of amplitud and location (in frequencies) of the ES
% Use 'NPeaks' input to tell function to select only 5 first peaks it can find.
[pks,loc] = findpeaks(ES(idx),F(idx), 'NPeaks', 5);
% To plot the peaks in the envelope
plot(F(idx),ES(idx),loc,pks,'r*')
% Note in this example the first peak (in 250 Hz) is not selected
% because is not a local maximum when we narrow the envelope.
% If the function select false peaks somehow, you can use
%'MinPeakHeight' to specify an absolute amplitude, 'MinPeakProminence '
%for a relative amplitude or 'Threshold' inputs for a better fit.
https://uk.mathworks.com/matlabcentral/answers/768537-use-findpeaks-on-specific-frequency-range
https://uk.mathworks.com/help/signal/ref/findpeaks.html#responsive_offcanvas

Scaling amplitudes by two for the FFT in MATLAB

I just read the example of Mablab tutorial, trying to studying the FFT function.
Can anyone tell me that for the final step, why P1(2:end-1) = 2*P1(2:end-1). In my opinion, it is not necessary to multiply by 2.
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sampling period
L = 1000; % Length of signal
t = (0:L-1)*T; % Time vector
%--------
S = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t);
%---------
X = S + 2*randn(size(t));
%---------
plot(1000*t(1:50),X(1:50))
title('Signal Corrupted with Zero-Mean Random Noise')
xlabel('t (milliseconds)')
ylabel('X(t)')
Y = fft(X);
P2 = abs(Y/L);
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);
f = Fs*(0:(L/2))/L;
plot(f,P1)
title('Single-Sided Amplitude Spectrum of X(t)')
xlabel('f (Hz)')
ylabel('|P1(f)|')
Y = fft(S);
P2 = abs(Y/L);
P1 = P2(1:L/2+1);
P1(2:end-1) = 2*P1(2:end-1);
plot(f,P1)
title('Single-Sided Amplitude Spectrum of S(t)')
xlabel('f (Hz)')
ylabel('|P1(f)|')
Matlab sample
The reason for the multiplication by 2 is that the spectrum returned by fft is symmetric about the DC component. Since they are showing the single-sided amplitude spectrum, the amplitude of each point is going to be doubled to account for the contributions of data on the other side of the spectrum. For example, the single-sided amplitude of pi/4 is the amplitude at pi/4 plus the amplitude at -pi/4.
The first sample is skipped since it is the DC point and therefore shared between the two sides of the spectrum.
So for example, if we look at the fft of their example signal with a 50Hz sinusoid of amplitude 0.7 and a 120Hz sinusoid of amplitude 1.
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sampling period
L = 1000; % Length of signal
t = (0:L-1)*T; % Time vector
S = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t);
% Compute the FFT
Y = fft(S);
% Compute the amplitudes
amplitude = abs(Y / L);
% Figure out the corresponding frequencies
f = Fs/L*[0:(L/2-1),-L/2:-1]
% Plot the result
plot(f, amplitude)
When we plot this, you'll see that it's symmetric and the original input amplitude is only realized by combining the amplitudes from both sides of the spectrum.
A slightly more explicit version of what they have done would be to be the following which sums the two halves of the spectrum
P1(2:end-1) = P1(2:end-1) + P2((L/2+2):end);
But since by definition the spectrum is symmetric, the opt to simply multiply by 2.

Designing a narrow bandpass filter in MATLAB

I'm working on signal filtering in MATLAB. I wrote a signal with 3 different frequencies:
Fs = 8000; %// Sampling frequency
T = 1/Fs; %// Sample time
L = 16000; %// Length of signal
t = (0:L-1)*T; %// Time vector
y = 40*sin(2*pi*50*t) + 500*sin(2*pi*51*t) + 500*sin(2*pi*49*t);
Now I want to extract the 50Hz signal by bandpass window filtering using a Hanning window. Here is my code to design the filter:
function Hd = HannFilter1
Fs = 8000; %// Sampling Frequency
N = 4096; %// Order
Fc1 = 49.5; %// First Cutoff Frequency
Fc2 = 50.5; %// Second Cutoff Frequency
flag = 'scale'; %// Sampling Flag
win = hann(N+1);
b = fir1(N, [Fc1 Fc2]/(Fs/2), 'bandpass', win, flag);
Hd = dfilt.dffir(b);
After that, I do filtering using filter like this:
yfilter = filter(Hd.Numerator,1,y);
NFFT = 2^nextpow2(L);
Y = fft(yfilter,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
figure;
subplot(2,1,1);
plot(yfilter);
subplot(2,1,2);
plot(f,2*abs(Y(1:NFFT/2+1)))
Why is this filter unable to extract the 50Hz signal?
I'm doing something wrong in this simulation?
How can I filter out the 50Hz signal?
what is the best sample rate for 50Hz signal? and very important question! in real world, like balancing system, the main signal is about 20Hz and environment is very too noisy and filtering by my solution does not give a correct answer. in this case,how can i use or choose the best filtering algorithm?
if my sample rate be 8000Hz and I can buffered only 20000 samples, how can Designing a narrow bandpass filter?
So, I Solve problem by decrease sample rate and increase sample data by this code: ( as Matt was Said )
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sample time
L = 60000; % Length of signal
t = (0:L-1)*T; % Time vector
for j=1:20
r1 = 5 + (1000-5).*rand(1,1);
r2 = 5 + (1000-5).*rand(1,1);
y = 10*sin(2*pi*14.8*t) + r1*sin(2*pi*14.2*t) + r2*sin(2*pi*15.5*t) + 1.1*rand(size(t));
yfilter = filter(Hd.Numerator,1,y);
max(yfilter(40000:50000))
end
my filter is KAISER ( FIR Badpass filter ) :
Fs = 1000; % Sampling Frequency
Fstop1 = 14.2; % First Stopband Frequency
Fpass1 = 14.6; % First Passband Frequency
Fpass2 = 15; % Second Passband Frequency
Fstop2 = 15.2; % Second Stopband Frequency
Dstop1 = 1e-06; % First Stopband Attenuation
Dpass = 0.057501127785; % Passband Ripple
Dstop2 = 1e-06; % Second Stopband Attenuation
flag = 'scale'; % Sampling Flag
% Calculate the order from the parameters using KAISERORD.
[N,Wn,BETA,TYPE] = kaiserord([Fstop1 Fpass1 Fpass2 Fstop2]/(Fs/2), [0 ...
1 0], [Dstop1 Dpass Dstop2]);
% Calculate the coefficients using the FIR1 function.
b = fir1(N, Wn, TYPE, kaiser(N+1, BETA), flag);
Hd = dfilt.dffir(b);
and filter amplitude for 20 iteration and random noise signal is :
max(yfilter(40000:50000))
10.01
10.02
10.01
10.00
10.01
10.03
10.01
10.02
....
that is a great result for me, and filtered signal is :
but there is some problem :
1- my sample data length is 60000 bytes, in other hand by sampling rate at 1000Hz, I wait for 60 Seconds for gathering data, and that is too long time!!!
when i decrease sample data length to about 3000 samples, filtered result is so bad because of number of filter's coefficients is about 4097.
how can i filter my signal when it's length is 3000 samples and my filter's coefficients is about 4097 bytes? when i decrease filter's coefficients , filtered signal result is so noisy.
2- what is the best sample rate fo 15 Hz signal?
thanks.

Fourier transform and FFT for an arbitrary plot using MATLAB

I have a simple problem but since I have not used MATLAB Fourier Transform tools I need some help. I have a plot obtained from n excel file. The plot is in time domain. Time range for the plot is 0 to 50 ps. And I have data for the y component of the plot every 0.5 fs. Basically the plot contains 100000 data printed every 0.5fs. Now I want to get the Fourier transform of this plot. What should i do? The following is a simple format for my excel file that includes the data I needed to have the time-domain plot.
0 116.0080214
0.0005 116.051128
0.001 116.0939229
0.0015 116.1362197
0.002 116.1776665
0.0025 116.2178118
0.003 116.256182
.
.
.
.
50.0 123.000
The first column is time in ps. Thank you so much in advance for you helps. Best, HRJ
I have adapted this page for the solution.
Fs = 100000/50; % Sampling frequency (in 1/ps)
T = 1/Fs; % Sample time (in ps)
L = 100000; % Length of signal
t = (0:L-1)*T; % Time vector; your first column should replace this
% Sum of a 50 1/ps sinusoid and a 120 1/ps sinusoid
% Your second column would replace y
x = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t);
y = x + 2*randn(size(t)); % Sinusoids plus noise
NFFT = 2^nextpow2(L); % Next power of 2 from length of y
Y = fft(y,NFFT)/L;
f = Fs/2*linspace(0,1,NFFT/2+1);
close all
subplot(2,1,1)
% Plot your original signal
plot(Fs*t(1:100),y(1:100))
title('Signal Corrupted with Noise')
xlabel('time (fs)')
% Plot single-sided amplitude spectrum.
subplot(2,1,2)
plot(f,2*abs(Y(1:NFFT/2+1)))
title('Single-Sided Amplitude Spectrum of y(t)')
xlabel('Frequency (1/ps)')
ylabel('|Y(f)|')

Arguments in Plot function

The following Matlab scrip (taken from MATLAB help for fft) runs perfectly fine
Fs = 1000; % Sampling frequency
T = 1/Fs; % Sample time
L = 1000; % Length of signal
t = (0:L-1)*T; % Time vector
% Sum of a 50 Hz sinusoid and a 120 Hz sinusoid
x = 0.7*sin(2*pi*50*t) + sin(2*pi*120*t);
y = x + 2*randn(size(t)); % Sinusoids plus noise
plot(Fs*t(1:50),y(1:50))
title('Signal Corrupted with Zero-Mean Random Noise')
xlabel('time (milliseconds)')
But I am unable to understand why we needed Fs*t in plot(). Why I am making it dimension less?
Your vector t is defined in terms of samples, i.e. t(10) is the value taken as the 10th sample.
If you want to plot the signal vs. time, you will have to multiply the sampling instance with the sampling time, i.e. time = FS*t .
If you don't scale, you eventually plot the signal vs. the sampling instances. Then, however, the label "time(ms)" is not correct.