I tried to deconvolute a measured spectrum (Sm) with the pure spectrum (S0) to get the apodization and instrument line shape. Here are the files: Sm and S0
However, I found that the result of my ifft of Sm and S0 are similar. It should give me Gaussian line shape, but I got triangular. What is my mistake and how to solve it?
Thank you in advance.
close all
clear all
clc
sm=load('n2o_gaussian.txt'); %loading spectrum with gaussian ILS
s0=load('n2o_noapodization.txt'); %loading pure spectrum
v=s0(:,1); %wavenumber of pure spectrum
s0_y=s0(:,2); %y component of S0
L=length(v); %length of data
n=2^(nextpow2(L)*2); %number of the next power of two data for FFT
vm=sm(:,1); %wavenumber of measured spectrum
v0=2217.241; %v0 is peak location
vv0=v*ones(1,length(v0))-ones(length(v),1)*v0; %vv0 is wavenumber difference
sm_interpl=interp1( vm, sm, v, 'spline',0); %fit the measured spectrum to match the grid
%pure spectrum
sm_interpl_y=sm_interpl(:,2); %y component of Sm
%y-deconvolution of Sm with S0
s0_y_ift=ifft(s0_y,n,'symmetric'); %inverse FFT of pure spectrum, the symmetric option
enforces imaginary part should be zero in DFT
s0_y_ift=fftshift(s0_y_ift);
sm_interpl_ift=ifft(sm_interpl_y,n,'symmetric'); %inverse FFT of measured spectrum, without
symmetric, half of amplitude will lost
sm_interpl_ift=fftshift(sm_interpl_ift);
apo_y=(sm_interpl_ift)./(s0_y_ift); %get the apodization function from division of sm
and s0
ILS_y=fft(apo_y,n); %get the ILS
ILS_y2=fftshift(ILS_y);
%normalize the area of ILS
area=trapz(f,ILS_y2);
ILS_y2_normalized=ILS_y2./area;
%showing spectra and spline result
figure (1)
plot (sm(:,1),sm(:,2),'o');
hold on;
plot (sm_interpl(:,1),sm_interpl(:,2));
hold on
plot (s0(:,1),s0(:,2));
legend('Measured spectrum','fitted spectrum','pure spectrum')
hold on;
%showing interferogram results
figure (2)
plot(real(sm_interpl_ift))
hold on
plot(real(s0_y_ift))
legend('interferogram of Sm','interferogram of S0')
hold on
%showing apodization function
figure (3)
plot(real(apo_y))
legend('apodization function')
hold on
%showing retrieved ILS
figure (4);
plot(f,real(ILS_y2_normalized));
xlim([-0.0001 0.0001]);
legend('ILS');
hold on;
Related
As a data basis, I have measured data the volts were recorded.
Matlab will now be used to perform an FFT.
I have the following questions:
- What unit do I have on the ordinate axis after the FFT? Also volts?
- How is scaled correctly? By hiding the negative frequencies (Nyquist), I would actually have to double the amplitude, right?
- Do I have to multiply all values of the FFT again with 20 * log10 (FFT) to represent the ordinate in db?
Thank you so much for your support!
Frank
Matlab example:
load('TimeDomain.mat')%loading of the time domain signal
L=2500; %length of the signal
Fs=500000;%sampling frequency
N=2^nextpow2(L);%scale factor
t=(0:L-1)*10^-3;%time domain array
f=linspace(0,Fs/2,length(t));%frequency domain array
FFT=abs(fft(Timedomain,N));
figure(1)
plot(f,FFT(1:2500))
Yes, after the FFT, the unit of the ordinate axis will still be volts.
You can scale it by dividing by the number of samples of your signal, then you can indeed multiplying by two (except the first and last elements that represents respectively the frequency 0 and Fs/2) if you want to plot all the spectrum in the positive side.
Then if you want to plot in dB, you can use the function mag2db which applies the formula that you said.
I found some weirdnesses in your code, so I suggest some fixes. My Timedomain signal is a 100 kHz sine at 1 V.
Fs = 500000; % sampling frequency
L = 2500; % length of the signal
t = (0:L-1)/Fs; % time domain array
f = linspace(0, Fs/2, L/2+1); % frequency domain array
Timedomain = cos(2*pi*100000*t); % Input signal
FFT = abs(fft(Timedomain)/L);
FFT(2:L/2) = 2*FFT(2:L/2);
%% Plots
subplot(2,1,1);
plot(f, FFT(1:L/2+1)); xlabel('Frequency (Hz)'); ylabel('Tension (V)');
subplot(2,1,2);
plot(f, mag2db(FFT(1:L/2+1))); xlabel('Frequency (Hz)'); ylabel('Tension (dBV)');
This returns:
I need to calculate convolution of functions:
f(x)=1 when -1< x <2, 0 otherwise
g(x)=sgn(x)*dirac(abs(x)-1)
I've got this code:
Fs=1;
t=-10:1/Fs:10;
d=dirac(abs(t)-1);
s=sign(t);
x=d.*s;
x2=1*(t>-1 & t<2);
spl=conv(x,x2,'same');
disp(spl);
But what I get is a lot of NaN values.
Where is my mistake? What should I change?
The following is a way of estimating the solution in discrete-time domain. This requires a couple of changes to your code:
Increase the sample rate Fs to preserve more bandwidth. I used 100x below.
Replace Dirac delta function by Kronecker delta to enable discrete-time modeling.
The modified code and the results are as follows:
Fs=100; % use higher sampling rate
t=-10:1/Fs:10;
d=(abs(t)-1)==0; % use kronecker delta function for discrete-time simulation
s=sign(t);
x=d.*s;
x2=1*(t>-1 & t<2);
spl=conv(x,x2,'same');
% plots to visualize the results
figure;
subplot(3,1,1);
plot(t, x2);
ylabel('f(x)');
subplot(3,1,2);
plot(t, x);
ylabel('g(x)');
subplot(3,1,3);
plot(t, spl);
xlabel('Time');
ylabel('convolution');
Try this code:
Fs=1;
t=-10:1/Fs:10;
g=t;
g(g~=1)=0; %g function
s=sign(t);
x=g.*s;
f=t;
f(f>-1 & f<2)=1;
f(f~=1)=0; %f function
x2=f;
spl=conv(x,x2,'same');
disp(spl)
I am new in matlab so maybe my question is stupid. I have a two signals rec(t) and sent(t) for which I want to find time delay through phase vs. frequency realtionship obtained from cross spectrum. I obtained cross spectrum through the FFT of the cross corelation between rec(t) and sent(t). Here it is:
time=data(15:length(data),1); %time of measurement - s
sent=data(15:length(data),2); %sent signal - mV
rec=data(15:length(data),3); %recorded signal - mV
samples=length(time); %number of samples
Fs=samples/max(time); %sampling frequency - Hz
dt=max(time)/samples; %time interval - s
freq=(0:samples/2)/samples/dt; %frequency scale for FFT
FFTrec=fft(rec); %FFT of recorded signal
FFTsent=fft(sent); %FFT of sent signal
CorrRecSent=(ifft(FFTrec.*conj(FFTsent))); %cross correlation definition
CS=fft(CorrRecSent); %cross spectrum (CS)
amp=abs(CS); %amplitude of CS
amp1=amp(1:samples/2+1); %amplitude of CS for half of the frequency spectrum
A2=angle(CS);
A1=A2(1:samples/2+1); %phase angle of (CS)
A=unwrap(A1); %unwrapped phase
plot(freq,(A));
xlabel('frequency (Hz)')
ylabel('phase (rad)')
And here is the plot. Is there any command or procedure how can I obtain exact phase angles for given frequencies (marked with black line)? Or how can I find the slope of the drawn orange line? I chose this range of frequencies because my sent signal was 5 kHz, so something around was chosen.
Thanks for help.
In the plot, you are setting freq as your x-axis vector, and A as your y-axis vector.
If you want to know the slope of the orange line, you first need to know the index where 4000Hz and 8000Hz is:
f1 = find(freq==4000);
f2 = find(freq==8000);
Then you can check which is the phase in this two points:
p1 = A(f1);
p2 = A(f2);
Finally the slope will be deltaX / deltaY:
slope = (f2-f1)/(p2-p1);
EDIT:
I stumbled on this explanation to obtain the energy spectrum from an IEEE paper(Open Circuit Fault Diagnosis in 3 phase uncontrolled rectifiers, Rahiminejad, Diduch, Stevenson, Chang).
"A recorded sample of the signal containing a number of samples equivalent to 4T is captured and its FFT is determined using an FFT size equal to the record length (where T is the fundamental period).
Assuming the FFT size is matched to 4 periods of a periodic waveform, every 4th FFT bin will coincide with a harmonic frequency, in particular the center of FFT bin 4k+1 will coincide with the kth harmonic frequency.
The energy of the kth harmonic is calculated as the sum of the squared magnitudes of the 5 consecutive FFT values centred at bin 4k+1. The additional FFT values are included in the harmonic energy calculation so as to reduce the sensitivity of the calculated energy to an error in the frequency estimate which oculd result in the kth harmonic peak shifting away from bin 4k+1."
I do not fully understand the passage above. In my limited understanding, the bold line
refers to the sum of the squared magnitudes of the output of function fft(), i.e. the complex fourier series coefficients.
Can someone please show some light into obtaining the energy spectrum ?
#fpe : I am not sure if ESD performs the same as energy spectrum. BTW, thanks alot for your answer:)
I am trying to plot the energy spectrum of a signal to look at the for example Normalised energy contained first three harmonics, energy ratio of fundamental to 2nd harmonics etc....
Here I have managed to get the Hanning window FFT amplitude-Hz and power-Hz. But, I have no idea how to get energy-Hz for each frequency components.
Any help is much appreciated !
function [f,Xall_Wnd]=fftplotExxx(time,X_input)
Fs = 20000; % Sampling frequency
x = X_input;
% Fast Fourier Transform
L = length (X_input); % Length of FFT
nfft = 2^nextpow2(L); % Next power of 2 from length of signal
%wave = wave.*hamming(length(wave));
x_HammingWnd = x.*hamming(L);
% Take fft, padding with zeros so that length(X)
%is equal to nfft
Xall_Wnd = fft(x_HammingWnd, nfft)/L; %hamming window fft
% FFT is symmetric, throw away second half
% Take the magnitude of fft of x
mx_Wnd = 2*abs(Xall_Wnd(1:nfft/2+1));
% To get Power of x(t) by sqr of magnitude
m2x_Wnd = mx_Wnd.^2;
% I am Not sure how to get energy spectrum
for i=1:L:nfft-L
E(i) = sum(Xall_Wnd(1:nfft/2+1).^2);
end
% Frequency vector
f = Fs/2*linspace(0,1,nfft/2+1);
% Generate the plot, title and labels.
subplot(2,2,1)
plot(time,X_input);
title('Time Domain')
xlabel('Time(s)')
subplot(2,2,2)
plot(f,m2x_Wnd);
title('Power Spectrum of x(t)');
xlabel('Frequency (Hz)');
ylabel('Normalised Power of fft');
subplot(2,2,3)
plot(f,mx_Wnd);
title('Hamming Window_ Spectrum of x(t)');
xlabel('Frequency (Hz)');
ylabel('Normalised Magunitude of fft');
subplot(2,2,4)
plot(f,E);
title('Energy Spectrum of x(t)');
xlabel('Frequency (Hz)');
ylabel('Energy');
end
Generally you can calculate the spectrum in this way:
h = spectrum.welch('hamming',2048,50);
PSD = psd(h,x(t),'nfft',2048,'fs',Fs);
I'm trying to extract the peaks of an audio file. I have the following code to extract the envelope of my amplitude spectrum. However I'm not getting the desired output graph. Can someone tell me what adjustment I need to make to get a proper graph. Here's my code:
[song,FS] = wavread('c scale fast.wav');
P=20000/44100*FS; % length of filter
N=length(song); % length of song
t=0:1/FS:(N-1)/FS; % define time period
% Plot time domain signal
figure(1);
subplot(3,1,1)
plot(t,(3*abs(song)))
title('Wave File')
ylabel('Amplitude')
xlabel('Length (in seconds)')
xlim([0 1.1])
xlim([0 N/FS])
% Gaussian Filter
x = linspace( -1, 1, P); % create a vector of P values between -1 and 1 inclusive
sigma = 0.335; % standard deviation used in Gaussian formula
myFilter = -x .* exp( -(x.^2)/(2*sigma.^2));% compute first derivative, but leave constants out
myFilter = myFilter / sum( abs( myFilter ) ); % normalize
% Plot Gaussian Filter
subplot(3,1,2)
plot(myFilter)
title('Edge Detection Filter')
% fft convolution
myFilter = myFilter(:); % create a column vector
song(length(song)+length(myFilter)-1) = 0; %zero pad song
myFilter(length(song)) = 0; %zero pad myFilter
edges =ifft(fft(song).*fft(myFilter));
tedges=edges(P/2:N+P/2-1); % shift by P/2 so peaks line up w/ edges
tedges=tedges/max(abs(tedges)); % normalize
% Plot song filtered with edge detector
subplot(3,1,3)
plot(1/FS:1/FS:N/FS,tedges)
title('Song Filtered With Edge Detector')
xlabel('Time (s)')
ylabel('Amplitude')
ylim([-1 1.1])
xlim([0 N/FS])
This is the graph i get for the above code and im focusing on the "song filtered with edge detector" plot
And this is the "song filtered with edge detector" plot I NEED to get
You can use a Hilbert transform to get the envelope. Technically, this returns the analytic signal. You get the envelope with the following line:
envelope = abs(hilbert(Song));
What the Hilbert transform does is to take the fft of the input, zeroes out the negative frequencies, and then does an ifft. The real part of the transform is the original signal, the imaginary part is the transformed signal. The absolute value of the real and imaginary part is the envelope, and the argument (angle(hilbert(Song))) is the instantaneous phase.
I assume you want to obtain the envelope of the signal (not of its spectrum as you say). If that is the case, for envelope detection I would use a lowpass filter applied to abs(song) (you can substituye abs by a similar non-linear function). The cutoff frequency of the filter should be (slightly) above the highest frequency of the envelope variations.
You are applying the filter directly to the waveform, and the filter does not seem to be a lowpass filter. Perhaps if you explain your approach we can provide more focused help.
By the way, if your song is much longer than your filter, the zero-padding followed by fft followed by ifft seems to be a slow way of doing the filtering. Why not just use conv?