Findpeaks in Spectrum Matalb - matlab

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

Related

Morlet wavelet transformation function returns nonsensical plot

I have written a matlab function (Version 7.10.0.499 (R2010a)) to evaluate incoming FT signal and calculate the morlet wavelet for the signal. I have a similar program, but I needed to make it more readable and closer to mathematical lingo. The output plot is supposed to be a 2D plot with colour showing the intensity of the frequencies. My plot seems to have all frequencies the same per time. The program does make an fft per row of time for each frequency, so I suppose another way to look at it is that the same line repeats itself per step in my for loop. The issue is I have checked with the original program, which does return the correct plot, and I cannot locate any difference beyond what I named the values and how I organized the code.
function[msg] = mile01_wlt(FT_y, f_mn, f_mx, K, N, F_s)
%{
Fucntion to perform a full wlt of a morlet wavelett.
optimization of the number of frequencies to be included.
FT_y satisfies the FT(x) of 1 envelope and is our ft signal.
f min and max enter into the analysis and are decided from
the f-image for optimal values.
While performing the transformation there are different scalings
on the resulting "intensity".
Plot is made with a 2D array and a colour code for intensity.
version 05.05.2016
%}
%--------------------------------------------------------------%
%{
tableofcontents:
1: determining nr. of analysis f, prints and readies f's to be used.
2: ensuring correct orientation of FT_y
3:defining arrays
4: declaring waveletdiagram and storage of frequencies
5: for-loop over all frequencies:
6: reducing file to manageable size by truncating time.
7: marking plot to highlight ("randproblemer")
8: plotting waveletdiagram
%}
%--------------------------------------------------------------%
%1: determining nr. of analysis f, prints and readies f's to be used.
DF = floor( log(f_mx/f_mn) / log(1+( 1/(8*K) ) ) ) + 1;% f-spectre analysed
nr_f_analysed = DF %output to commandline
f_step = (f_mx/f_mn)^(1/(DF-1)); % multiplicative step for new f_a
f_a = f_mn; %[Hz] frequency of analysis
T = N/F_s; %[s] total time sampled
C = 2.0; % factor to scale Psi
%--------------------------------------------------------------%
%2: ensuring correct orientation of FT_y
siz = size(FT_y);
if (siz(2)>siz(1))
FT_y = transpose(FT_y);
end;
%--------------------------------------------------------------%
%3:defining arrays
t = linspace(0, T*(N-1)/N, N); %[s] timespan
f = linspace(0, F_s*(N-1)/N, N); %[Hz] f-specter
%--------------------------------------------------------------%
%4: declaring waveletdiagram and storage of frequencies
WLd = zeros(DF,N); % matrix of DF rows and N columns for storing our wlt
f_store = zeros(1,DF); % horizontal array for storing DF frequencies
%--------------------------------------------------------------%
%5: for-loop over all frequencies:
for jj = 1:DF
o = (K/f_a)*(K/f_a); %factor sigma
Psi = exp(- 0*(f-f_a).*(f-f_a)); % FT(\psi) for 1 envelope
Psi = Psi - exp(-K*K)*exp(- o*(f.*f)); % correctional element
Psi = C*Psi; %factor. not set in stone
%next step fits 1 row in the WLd (3 alternatives)
%WLd(jj,:) = abs(ifft(Psi.*transpose(FT_y)));
WLd(jj,:) = sqrt(abs(ifft(Psi.*transpose(FT_y))));
%WLd(jj,:) = sqrt(abs(ifft(Psi.*FT_y))); %for different array sizes
%and emphasizes weaker parts.
%prep for next round
f_store (jj) = f_a; % storing used frequencies
f_a = f_a*f_step; % determines the next step
end;
%--------------------------------------------------------------%
%6: reducing file to manageable size by truncating time.
P = floor( (K*F_s) / (24*f_mx) );%24 not set in stone
using_every_P_point = P %printout to cmdline for monitoring
N_P = floor(N/P);
points_in_time = N_P %printout to cmdline for monitoring
% truncating WLd and time
WLd2 = zeros(DF,N_P);
for jj = 1:DF
for ii = 1:N_P
WLd2(jj,ii) = WLd(jj,ii*P);
end
end
t_P = zeros(1,N_P);
for ii = 1:N_P % set outside the initial loop to reduce redundancy
t_P(ii) = t(ii*P);
end
%--------------------------------------------------------------%
%7: marking plot to highlight boundary value problems
maxval = max(WLd2);%setting an intensity
mxv = max(maxval);
% marks in wl matrix
for jj= 1:DF
m = floor( K*F_s / (P*pi*f_store(jj)) ); %finding edges of envelope
WLd2(jj,m) = mxv/2; % lower limit
WLd2(jj,N_P-m) = mxv/2;% upper limit
end
%--------------------------------------------------------------%
%8: plotting waveletdiagram
figure;
imagesc(t_P, log10(f_store), WLd2, 'Ydata', [1 size(WLd2,1)]);
set(gca, 'Ydir', 'normal');
xlabel('Time [s]');
ylabel('log10(frequency [Hz])');
%title('wavelet power spectrum'); % for non-sqrt inensities
title('sqrt(wavelet power spectrum)'); %when calculating using sqrt
colorbar('location', 'southoutside');
msg = 'done.';
There are no error message, so I am uncertain what exactly I am doing wrong.
Hope I followed all the guidelines. Otherwise, I apologize.
edit:
my calling program:
% establishing parameters
N = 2^(16); % | number of points to sample
F_s = 3.2e6; % Hz | samplings frequency
T_t = N/F_s; % s | length in seconds of sample time
f_c = 2.0e5; % Hz | carrying wave frequency
f_m = 8./T_t; % Hz | modulating wave frequency
w_c = 2pif_c; % Hz | angular frequency("omega") of carrying wave
w_m = 2pif_m; % Hz | angular frequency("omega") of modulating wave
% establishing parameter arrays
t = linspace(0, T_t, N);
% function variables
T_h = 2*f_m.*t; % dimless | 1/2 of the period for square signal
% combined carry and modulated wave
% y(t) eq. 1):
y_t = 0.5.*cos(w_c.*t).*(1+cos(w_m.*t));
% y(t) eq. 2):
% y_t = 0.5.*cos(w_c.*t)+0.25*cos((w_c+w_m).*t)+0.25*cos((w_c-w_m).*t);
%square wave
sq_t = cos(w_c.*t).*(1 - mod(floor(t./T_h), 2)); % sq(t)
% the following can be exchanged between sq(t) and y(t)
plot(t, y_t)
% plot(t, sq_t)
xlabel('time [s]');
ylabel('signal amplitude');
title('plot of harmonically modulated signal with carrying wave');
% title('plot of square modulated signal with carrying wave');
figure()
hold on
% Fourier transform and plot of freq-image
FT_y = mile01_fftplot(y_t, N, F_s);
% FT_sq = mile01_fftplot(sq_t, N, F_s);
% Morlet wavelet transform and plot of WLdiagram
%determining K, check t-image
K_h = 57*4; % approximation based on 1/4 of an envelope, harmonious
%determining f min and max, from f-image
f_m = 1.995e5; % minimum frequency. chosen to showcase all relevant f
f_M = 2.005e5; % maximum frequency. chosen to showcase all relevant f
%calling wlt function.
name = 'mile'
msg = mile01_wlt(FT_y, f_m, f_M, K_h, N, F_s)
siz = size(FT_y);
if (siz(2)>siz(1))
FT_y = transpose(FT_y);
end;
name = 'arnt'
msg = arnt_wltransf(FT_y, f_m, f_M, K_h, N, F_s)
The time image has a constant frequency, but the amplitude oscillates resempling a gaussian curve. My code returns a sharply segmented image over time, where each point in time holds only 1 frequency. It should reflect a change in intensity across the spectra over time.
hope that helps and thanks!
I found the error. There is a 0 rather than an o in the first instance of Psi. Thinking I'll maybe rename the value as sig or something. besides this the code works. sorry for the trouble there

Get Exact Frequency From Digital Signal

I studies on Digital Signal Filtering and I have a file includes some signal data. I wrote Matlab Program to get 23 to 27 Hz from original signal. but filtered signal is different. my desire filter is bandpass but my code work like low pass filter.
this is my code :
clc;
clear all;
load('SignalFile.mat');
%number of sample
SampleNumber = 60000;
%create hamming window
hamm = hamming((SampleNumber))'; %'
% there is 4 data in SignalFile.mat
for pl=1:4
% get name of data in signalFile.mat
data = eval(['mydata' num2str(pl)]);
[n,c] = size(data);
nk=SampleNumber;
% there is 2 signal in each data. but main signal exists on data(1:nk,1);
% nk is Sample Number.
mydata = data(1:nk,1) ;
encodedata = data(1:nk,2);
% Sample Rate my this file equal to data length / 4 ->> ~ 39000 sample
% per second.
fs = floor(n/4); % Sampling rate [Hz]
noSamples = nk; % Number of samples
f = 0 : fs/noSamples : fs - fs/noSamples; % Frequency vector
figure;
subplot(2,2,1);
plot(mydata);
x_fft = abs(fft(mydata));
subplot(2,2,2);
plot(f,x_fft);
xlim([1 100]);
centerf = 25; % 25 Hz Center
bw=2; %Bandwisth
fc=pi*centerf; %Center Frequency
L = nk; %sample number;
%Compute Filter
hsuup=(-(L-1)/2:(L-1)/2);
hideal1=hamm.*(2*(fc+bw)*(sin(2*(fc+bw)*hsuup/fs)./(2*(2*fc+bw)*hsuup/fs)));
hideal2=hamm.*(2*(fc-bw)*(sin(2*(fc-bw)*hsuup/fs)./(2*(2*fc+bw)*hsuup/fs)));
h_bpf=(hideal1-hideal2);
% transform mydata to Ferequency Domain
comp_sig_fft=fft(mydata)'; %'
% transform Filter Windows to Ferequency Domain
h_bpf_fft=fft(h_bpf);
% Filter Signal
s_fft=comp_sig_fft.*h_bpf_fft;
%
band_passed_signal=real(ifft(s_fft));
subplot(2,2,3);
plot(band_passed_signal);
x_fft = abs(fft(band_passed_signal));
subplot(2,2,4);
plot(f,x_fft);
xlim([1 100]);
end
is there any idea?
best regards.
my datafile uploaded here :
http://wikisend.com/download/574638/SignalFile.mat
result Images :
https://www.imageupload.co.uk/image/ZLzM
if you look at image, you can find under 20hz signal exists in filtered signal yet.

Synthesize PSD in MatLab

I want to recover a time signals from a given power spectral density, assuming a normal distribution of the original signal:
PSD; % [(m/s)^2/Hz] given spectrum
T = 60; % [s] length of original signal
dt = 0.005; % [s] time step of original signal
N = T/dt; % [-] number of samples
NFFT = 2^nextpow2(N); % [-] number of bins for FFT
fs = 1/dt; % [Hz] sampling frequency
ASD = sqrt(PSD); % [(m/s)/sqrt(Hz)] get amplitude spectrum
omega = 2*pi*rand(NFFT/2,1); % [rad] generate phase vector
Z = ASD.*exp(1i*omega); % create complex amplitude vector
Z = [0;Z;flipud(conj(Z))]; % extend to satisfy symmetry
Y = real(ifft(Z)); % inverse FFT
[PSDY,f] = pwelch(Y,[],[],NFFT,fs); % generate PSD from Y to compare
The results show a power spectrum several orders of magnitude lower than the original, but the shape matches very good. I guess there is something wrong with the units or there might be a scaling factor missing. I'm not sure about the units of the time signal after ifft, since the amplitude has [(m/s)/sqrt(Hz)].
I believe there are two problems here.
First, I think that the PSD as you define it (or rather, as you use it) is in the wrong units.
When you define the signal as
Z = ASD.*exp(1i*omega);
then ASD should be in m/s and not in (m/s)/Hz.
So you should do something like that:
ASD = sqrt(PSD*fs/2)
Now, since PSD is in (m/s)^2/Hz, ASD is in units of m/s.
Next, the ifft should be normalised. That is, you should define the Y as
Y = ifft(Z)*sqrt(NFFT);
One more thing, I am not sure if this is on purpose, but the following line
[PSDY,f] = pwelch(Y,[],[],NFFT,fs);
results in Y being divided into 8 parts (with length <NFFT) with 50% overlap. Each part is zero padded to length of NFFT.
A better practice would be to use something like
[PSDY,f] = pwelch(Y,L,L/2,L,fs);
for some L or
[PSDY,f] = pwelch(Y,NFFT,[],NFFT,fs);
if you insist. To find out more, go to http://www.mathworks.com/help/signal/ref/pwelch.html
In conclusion, this is your (modified) code:
PSD = 5; % [(m/s)^2/Hz] given spectrum
T = 60; % [s] length of original signal
dt = 0.005; % [s] time step of original signal
N = T/dt; % [-] number of samples
NFFT = 2^nextpow2(N); % [-] number of bins for FFT
fs = 1/dt; % [Hz] sampling frequency
ASD = sqrt(PSD*fs/2); % [(m/s)] get amplitude spectrum
omega = 2*pi*rand(NFFT/2,1); % [rad] generate phase vector
Z = ASD.*exp(1i*omega); % create complex amplitude vector
Z = [0;Z;flipud(conj(Z))]; % extend to satisfy symmetry
Y = ifft(Z)*sqrt(NFFT); % inverse FFT
[PSDY,f] = pwelch(Y,256,128,256,fs); % generate PSD from Y to compare
which results in
where the blue line is the estimate PSD.

Low pass filtering not working as expected

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.

Matlab fft function

The code below is from the Matlab 2011a help about fft function.
I think there is a problem here : why do they multiply t(1:50) by Fs, and then say it's time in millisecond ? Certainly, it happens to be true in this very particular case, but change the value of Fs to, say, 2000, and it won't work anymore, obviously because of this factor of 2. Right ? Quite misleading, isn't it ? What do I miss ?
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)')
Clearer with this :
fs = 2000; % Sampling frequency
T = 1 / fs; % Sample time
L = 1000; % Length of signal
t2 = (0:L-1)*T; % Time vector
f = 50; % signal frequency
s2 = sin(2*pi*f*t2);
figure, plot(fs*t2(1:50),s2(1:50)); % NOT good
figure, plot(t2(1:50),s2(1:50)); % good
You don't miss anything. This is a typical bad practice of not having units as comments for each line. For example,
Fs=1000; % in [Hz]
T=1/Fs; % [sec]
L = 1000; % Length of signal
t = (0:L-1)*T; % Time vector
then, the time vector has units of 1/1000 seconds, or milliseconds... (each element is 1 ms).
In the other case Fs=2000 %[Hz], which makes the time vector to have units of 1/2000 seconds...