I have a really weird question.
Let's assume i have an oscillogram like the one shown below.
(source: engineeringvista.com)
I need to -somehow- capture the points that compose the signal and afterwards try to make a Fourier analysis and plot the harmonics of the signal.
Do you think such an operation could be done in matlab or any other software?
This forum is not a Give Me the Code service!!!...
Having said that, here is precisely what you requested, with the code profusely commented and plotting the image processing steps :).....
%% Processing
% Reading Image
X0=imread('Pentode 10kHz.gif');
X1=512*(X0([21:219],[15:263]));
imshow(512*(1-X1));
X2=X1;
% Removing Division Dotted Lines and Axis
X2(5:5:end,:)=[];
X2(:,5:5:end)=[];
imshow(512*(1-X2));
%% Evaluating
% Obtain Maximums per Points
[~,i0]=max(X2);
% Setting the Proper Scaling
[lx,lt]=size(X2);
xmax=8*2; %2V per division, 8 divisions
tmax=10*20e-6; % 20us per division, 10 divisions
% Applying Time Scaling
t0=(1:lt)'/lt*tmax; % 200us total
% Remove Spurious Points
t0=t0(i0>1);
% Applying Volt Scaling
x0=xmax/2-i0(i0>1)'/lx*xmax;
%% Signal
plot(t0,x0)
xlabel('Time [s]');
ylabel('Volts [V]')
%% Fourier Transform
ln=length(x0);
h=fftshift(fft(x0))/1000; % f in kHz
h0=abs(h);p0=phase(h);
fmax=1/tmax*ln/2/1000; % F in kHz
f1=(0:(ln/2+1))'/ln*fmax;
h1=[h0(ln/2);2*h0(ln/2:end)];
plot(f1,h1)
axis([0 100 0 1])
xlabel('Frequency [kHz]')
ylabel('Spectral Magnitude [x/kHz]')
Check finally the Fourier Transform. Note the proper scales, and the single point around 10kHz, which is the correct value. Note that, because having only two periods of the signal, the FT is not the best method for confirming the frequency and yes, the period in this case is.
Greetings.............
Related
This is the kind of plot i imagined myself.
https://de.mathworks.com/help/matlab/ref/waterfall.html
Ok, i don't want to explain too much, how my code works. It would take too much time. Just try the second code yourself. Take any small wav-file you can find. When you compile the code, you can see three frequency bands and see that many spectrums are plotted every 30ms. If you have a specifically question concerning my code, how it works, ask me in the comments.
I want every spectrum, at least from one frequency band, to plot it in a 3-dimensional plot. In short, what are the coordinates of the first spectrum and the 2nd, the 3rd, the 4th and so on.
My time segment on which is a fft applied, is 30 ms long. The first point on the x-axis is 30 ms, the next one 60ms and the next one 90ms and so on. What is the y-coordinate from the 30ms? This would be on the frequency axis or the y-axis. The z-axis would be the magnitude out of a frequency component at some point in time (or at a given sliding window frame). How can i do that? How do i write that? I am having big trouble with this matter. And since every explanation is in another language, it makes it much more harder for me.
As you may know, i have an audiofile (music) on which i compute a STFT. I want to visualise it. See the following explanation in my code. Read the comments!
My first idea to do this way, was using the function "mesh" or something similar.
Here is my mesh-code:
X=1:10;
Y=1:15;
Z = [];
% Here i would define the number of time segments
% See the next following code, to understand, what i mean.
for i = 1:length(X)
% Here in this line, i want to compute my short fft
%
% number of frequencies
for j = 1: length(Y)
Z(j,i) = 1.0/(i*j);
end
end
mesh(X,Y,Z)
This code plots me a mesh, i just wanted to know for myself, how this works. Anyway please be aware, that i am quite sure that i do not know, how the function "mesh" works to the fullest, but i think, i understood most of it.
Another thing i need to mention is, that i am defining frequency bands in my next following code. I did this, because i noticed, i have very high amplitudes in a range from 1 - 1000Hz, which is why, i defined 3 frequency bands. It is not necessary to plot all of them, but i want to visualise at least one. Not visualising the whole frequency range from the audio signal, but only the specificially chosen band.
%% MATLAB
%_________________________________________
[y,fs]=audioread('dontstopmenow.wav');
% audioread = Read WAV-file
% y = Vector, which contains audio signal
% fs = Sample Rate
% 'dontstopmenow' = WAV-file
%_________________________________________
%PARAMETER FOR STFT
%_________________________________________
t_seg=0.03; % Length of segment in ms
fftlen = 4096; %FFT-Points
%Defining the length of my frequency bands
f_LOW= 1:200; % contain lower frequencies
f_MEDIUM= 201:600; % contain medium frequencies
f_HIGH= 601:1000; % contain higher frequencies
%_______________________________________________________
segl =floor(t_seg*fs);
% Length of segment, on which we use the fft
% "floor" rounds off the result
windowshift=segl/2;
% size of window which goes to the next segment
window=hann(segl);
%hann function
window=window.';
% From a row vector to a column vector
si=1;
%Start index
ei=segl;
%End index
N= length(y)/windowshift - 1;
% Number of time segements in audio signal
f1=figure;
% New window
f=0:1:fftlen-1;
f=f/(fftlen-1)*fs;
% frequency vector
Ya=zeros(1,fftlen);
%Plotting time segments!
for m= 1:1:N
y_a = y(si:ei);
y_a= y_a.*window;
Ya=fft(y_a, fftlen);
Ya=abs(Ya(1:end/2));
%One-sided-spectrum
drawnow; %Updates graphical objects
figure(f1);
plot(f(1:end/2), 20*log10(Ya));
%STFT __ plots the whole audio signal after a stft, every 30ms
%% L,M,H - Bands
subplot(3,1,1)
y_low = Ya(f_LOW);
plot(f_LOW,y_low);
ylim([-20 60]);
title('Spektrum (LOW)');
xlabel('f(Hz)');
ylabel('dB');
grid on
subplot(3,1,2)
y_medium = Ya(f_MEDIUM);
plot(f_MEDIUM,y_medium);
ylim([-20 30]);
title('Spektrum (MEDIUM)');
xlabel('f(Hz)');
ylabel('dB');
grid on
subplot(3,1,3)
y_high = Ya(f_HIGH);
plot(f_HIGH,y_high);
ylim([-20 30]);
title('Spektrum (HIGH)');
xlabel('f(Hz)');
ylabel('dB');
grid on;
si=si+windowshift;
% start index updated
ei=ei+windowshift;
% end index updated
end
Here's the list of statements you could add to your code to generate the waterfall plot:
Let's store all STFT outputs in a matrix named Yb. Firstly, allocate the memory by adding this line before the for-loop.
Yb = NaN(N, fftlen/2);
Next, in the for-loop, save the fft result for each segment. This can be done by adding the following line after you have finished the computation of Ya (just before drawnow).
Yb(m,:) = Ya;
Now you're ready to generate the waterfall plot. This can be done by adding the following code after the end of the for-loop.
figure;
waterfall(f(f_LOW), (1:N)*windowshift/fs, Yb(:,f_LOW));
xlabel('Frequency (Hz)');
ylabel('Time (s)');
Hope this achieves what you want.
Following is not related to the main question: I also have the following suggestions to improve some other aspects of your code:
(1) The computation of the frequency grid f has a small scaling error. It should be:
f=f/fftlen*fs;
(2) Depending on the WAV file you use, your code may get fractional values in windowshift and N, but both of them need to be integers. So, use appropriate rounding methods while computing them. I'd suggest the following:
windowshift = round(segl/2);
N = floor(length(y)/windowshift);
(3) In the for-loop, you plot the whole fft only to overwrite that with the subplots immediately. That line should be removed.
I try to understand a result I get on with Matlab FFT and especially with the function fftshift
I first calculate the FFT of a simple signal (y = cos (2 * pi * f_signal * t) and the inverse transform to try to find the original signal.
I compare the results with and without the "zero padding" by adding 100 points higher at the starting signal before performing the FFT.
here is the code:
% Frequency input signal and time vector
f_signal=10;
nb_points = 100;
f_sampling=nb_points*f_signal;
step_time=1/f_sampling;
t=linspace(0,1/f_signal,nb_points);
%% Original signal with 100 points
y=cos(2*pi*f_signal*t);
%% Adding 100 more points for y
n_zero_padding=100;
y_f=padarray(y,[0 n_zero_padding],'post');
% Plot Input Signal
figure(1);
plot(y);
title('Input Signal');
% Perform Forward FFT
z=real(fft(y_f));
% Center FFT
z_centered=fftshift(z);
figure(2);
plot(z_centered);
title('FFT centrered with zero padding');
% Without centering
figure(3);
plot(z);
title('FFT with zero padding');
% Perform Inverse FFT
z_inv=ifft(z);
figure(4);
plot(z_inv);
title('Inverse FFT with zero padding');
% Inverse FFT with centered spectrum
z_inv_centered=ifft(z_centered);
figure(5);
plot(z_inv_centered);
title('Inverse FFT centered with zero padding');
I do not understand the result on Figure 5 (inverse transform of a shifted spectrum with fftshift)
here is the first spectrum obtained (not shifted) (Figure (3)):
here is the first shifted spectrum with fftshift (Figure (2)):
and the inverse FT of the shifted spectrum above (Figure (5)):
I do not understand the latter figure. If I take the theory, the fact of shifting the spectrum with fftshift leads to the obtaining of two Dirac centered around f_sampling / 2, more precisely on f_sampling / 2-f_signal and f_sampling / 2 + f_signal.
So I have the sum of these two Dirac and I do Inverse FFT of this sum: so I should get for Inverse FFT 2 cosine with frequencies very closed: it seems like I get on the figure (5 ) the product of two cosine signals but I do not see where is my misinterpretation ...
If someone could explain this result?
Thank you in advance
Because the spectrum of a real signal are symmetric about the origin, we prefer to see the spectrum like this, i.e., the zero frequency in the center. However, when computing the spectrum by FFT, what in the center are is the high frequency, thus, fftshift() is used to shift the zero spectrum to the center.
Since the fftshift() is used for visual matter, you can not perform ifft() on the shifted spectrum directly. On the other hand, the shifted spectrum is the modulated version of the original signal, and you obtain the modulated signal in Fig.5.
I am trying to reproduce the changes on a ~30 femtosecond laser pulse. I create and display this pulse in time just fine. Also, the fft of this pulse apperas fine on matlab (central frequency and width are very fine). But when I backtransform the transformed one using the ifft() function, the pulse is moved in time (posssibly due to phase change?? I don't know) and also the peak maxima are different.. What could be the cause of this? I am using ifft the wrong way?
The code I am using is this :
atto=1e-18;
c = 299792458;
femto=1e-15;
lamda0=800e-9;
f_0=c/lamda0;
omega0=2*pi*c/lamda0;
T=2*pi/omega0;
a=2*log(2)/((36.32*femto)^2);
Fs=3/atto; %samplying rate
t=-200*femto:1/Fs:200*femto;
Efield=exp(-a.*(t-T).^2).*exp(1j.*omega0.*(t-T));
nfft=2^nextpow2(length(Efield));
Efieldfft=fft(Efield,nfft);
f=(0:nfft-1)*Fs/nfft;
omega=2*pi*f;
figure(1)
plot(t,Efield)
xlabel('s [fs]')
ylabel('Amplitude')
figure(2)
plot(omega,abs(Efieldfft))
xlim([2e15 2.8e15])
xlabel('omega [rad]')
ylabel('Amplitude')
figure(3)
plot(f,abs(Efieldfft))
xlim([3.3e14 4.1e14])
xlabel('frequency [Hz]')
ylabel('Power')
test=ifft(Efieldfft,length(t));
figure(4)
plot(t,test)
xlabel('s[fs]')
ylabel('amplitude')
That's because you are modifying the length of the FFT compared with the length of your time axis. To see this, replace
nfft=2^nextpow2(length(Efield));
by
nfft=length(Efield);
You'll find that figures 1 and 4 are now equal, up to numerical precision errors.
I'm trying to make a fft from a transient time measurement but it seems that peaks are located at different locations than the measured FRF? The program (PULSE) I'm using have given me an averaged FRF and the transient signal is the last measurement of this series.
The fft of the transient acceleration signal is made by the following code:
% loading data:
[DataST, InfoST, errmsgST]=readuff('.\steel_tight_bolt_acc_center.uff');
dt=1.52588e-05; % sampling time
Fs=1/dt/2.56; % sampling frequency
NFFT = 2^nextpow2(length(DataST{1,5}.x)); % Next power of 2 from length signal
f = Fs*linspace(0,1,NFFT/2+1); % frequency
figure
subplot(2,1,1)
plot(DataST{1,7}.x,abs(DataST{1,7}.measData)) % FRF data from PULSE
title(DataST{1,7}.d1)
subplot(2,1,2)
L=length(DataST{1,5}.x); % length of signal
a=DataST{1,5}.measData; % Transient data measured [m/s^2]
A=2*abs(fft(a/L)); % calculating the fft
plot(f,A(1:(length(A))/2+1))
ylabel('2*|fft(Y)/N|')
title('FFT')
But by the resulting plot it seems that the peaks are located at different locations?
Can anyone explain what I'm doing wrong? Thanks!
I was trying to plot STFT using plot3 in MATLAB but failed. Can somebody guide me how to do that? My MWE is given below:
%% STFT Computataion
clear; clc; clf;
%% Get input and calculate frame size and overlap/shift
[Y,Fs]=wavread('D_NEHU_F0001_MN_10001');
frame_size=round(20*Fs/1000); % calculate frame size for 20ms
frame_shift=round(10*Fs/1000); % calculate frame shift for 10ms
%% Plot the input signal in time domain
t=1/Fs:1/Fs:(length(Y)/Fs);
subplot(2,1,1)
plot(t,Y);
title('Speech signal in time domain');
ylabel('Magnitude of samples');
xlabel('time in seconds');
%% Calculation of STFT
%NoOfFrames=floor((length(Y)/frame_shift)-1);
NoOfFrames=length(Y)-frame_size;
j=1;
%for i=1:frame_shift:(length(Y)-frame_size)
for i=1:frame_shift:((length(Y)-frame_size))%+frame_shift)
sp_frame=Y(i:(i+frame_size)).*hamming(frame_size+1);
sp_frame_dft=abs(fft(sp_frame)); % Compute STFT
sp_frame_array(:,j)=sp_frame_dft;
j=j+1;
end
%% Plot the STFT in 3D
[rows,cols]=size(sp_frame_array);
F=linspace(1/Fs,Fs/2000,cols);
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Z=1:frame_size+1;
subplot(2,1,2)
%mesh(sp_frame_array);
%surf(sp_frame_array,'EdgeColor','none');
plot3(T,F,sp_frame_array);
I am not sure what your question exactly is about, but I guess the problem is, with the provided code, that you do not get a plot similar to the one you'd get, say, with surf.
Furthermore, I am also not quite sure why you would want to use plot3, maybe to get the labels on the time and frequency right ? you could do that all the same with surf:
surf(T, F, sp_frame_array,'EdgeColor','none');
As a matter of fact, the reason why your plot3 does not give the same figure is because the arguments of plot3 must be three matrices of the same size (check it on help plot3). Your code should actually be broken on Matlab, which it's not, according to my test. Well, once again Matlab allowing people to mess around without warnings (go Python! :D)... Anyway, try to set the matrices more like the following:
F=linspace(1/Fs,Fs/2000, rows); % note: has to be rows, not cols here!
Fmat = F(:) * ones(1,cols); % or use repmat
T=1/Fs:(frame_shift*Fs/1000):(cols*(frame_shift*Fs/1000));
Tmat = ones(rows,1) * T(:)';
plot3(Tmat,Fmat,sp_frame_array);
While this will normally produce something more in line with what I would expect in drawing a spectrogram, I'd still make some remarks:
your F vector should go up to Fs, because of the way you filled sp_frame_dft in. More specifically, it should go from 0Hz to Fs - Fs/rows:
F = linspace(0,Fs*(1-1/rows)/1000,rows); % in kHz
you would probably like to draw the amplitudes in dBs:
plot3(Tmat,Fmat,db(sp_frame_array));
plot3 draws one line per column of the provided matrices. That means potentially lots of lines to draw! As #atul-ingle asked, are you sure this is what you want? Maybe waterfall would provide a better rendering at a lower cost?
waterfall(T,F,db(sp_frame_array));
Well, you'll get the lines for the rows, instead of the columns, so you might need to transpose if the latter is what you want.
You might also prefer to visualise only the first half of the matrix (because the frequencies higher than Fs/2 are only mirrors of the other half of the matrix).
Hope that helps!