Plotting Derivative of data in matlab - matlab

I am pretty new to Matlab and i have some Current Vs times stored under a structure in a matlab file.
What i am trying to plot is current vs time along with the first derivative of it. (di/dt). I used the diff function but the plot seems to be really wierd.
I know it simple but can anyone explain it.
THanks in advance.

Assume you have a structure S,
S.t is the time vector and S.I is the current vector in each time in S.t.
(both should be in the same length N).
Now, if you want to approximate the derivative:
dt = diff(S.t); % dt is the time intervals length, dt is N-1 length.
dI = diff(S.I);
derivative = dI./dt; %derivative is memberwise division of dI by dt
plot(t(1:end-1),derivative); % when you plot both vector should be in the same length:
% t(1:end-1) is the same as t except the last coordinate
I think this should work

Related

Computing the DFT of an arbitrary signal

As part of a course in signal processing at university, we have been asked to write an algorithm in Matlab to calculate the single sided spectrum of our signal using DFT, without using the fft() function built in to matlab. this isn't an assessed part of the course, I'm just interested in getting this "right" for myself. I am currently using the 2018b version of Matlab, should anyone find this useful.
I have built a signal of a 1 KHz and 2KHz sinusoid, phase shifted by 135 degrees (2*pi/3 rad).
then using the equations in 9.1 of Discrete time signal processing (Allan V. Oppenheim) and Euler's formula to simplify the exponent, I produce this code:
%%DFT(currently buggy)
n=0;m=0;
for m=1:DFT_N-1 %DFT_Fmin;DFT_Fmax; %scrolls through DFT m values (K in text.)
for n=1:DFT_N-1;%;(DFT_N-1);%<<redundant code? from Oppenheim eqn. 9.1 % eulers identity, K=m and n=n
X(m)=x(n)*(cos((2*pi*n*m)/DFT_N)-j*sin((2*pi*n*m)/DFT_N));
n=n+1;
end
%m=m+1; %redundant code?
end
This takes x as the input, in this case the signal mentioned earlier, as well as the resolution of the transform, as represented by the DFT_N, which has been initialized to 100. The output of this function, X, should be something in the frequency domain, but plotting X yields a circular plot slightly larger than the unit circle, and with a gap on the left hand edge.
I am struggling to see how I am supposed to convert this to the stem() plots as given by the in-built DFT algorithm.
Many thanks, J.
This is your bug:
replace X(m)=x(n)*(cos.. with X(m)=X(m)+x(n)*(cos..
For a given m, it does not integrate over the variable n, but overwrites X(m) only the last calculation for n = DFT_N-1.
Notice that integrating over n=1:DFT_N-1 omits one harmonic, i.e., the first one, exp(-j*2*pi). Replace
n=1:DFT_N-1 with n=1:DFT_N to include that. I would also replace m=1:DFT_N-1 with m=1:DFT_N for plotting concerns.
Also replace any 2*pi*n*m with 2*pi*(n-1)*(m-1) to get the phase right, since the first entry of X should correspond to zero-frequency, yielding sum_n x(n) * (cos(0) + j sin(0)) = sum_n x(n). If your signal x is real-valued then the zero-frequency component X(1) should be real-valued, angle(X(1))=0.
Last remark, don't forget to shift zero-frequency component to the center of the spectrum for better visibility, X = circshift(X,floor(size(X)/2));
If you are interested in the single-sided spectrum only, than you can just calculate X(m) for m=1:DFT_N/2 since X it is conjugate symmetric around m=DFT_N/2, i.e., X(DFT_N/2+m) = X(DFT_N/2-m)', due to exp(-j*(pi*n+2*pi/DFT_N*m)) = exp(-j*(pi*n-2*pi/DFT_N*m))'.
As a side note, for a given m this program calculates an inner product between the array x and another array of complex exponentials, i.e., exp(-j*2*pi/DFT_N*m*n), for n = 0,1,...,N-1. MATLAB syntax is very convenient for such calculations, and you can avoid this inner loop by the following command
exp(-j*2*pi/DFT_N*m*(0:DFT_N-1)) * x
where x is a column vector. Similarly, you can avoid the first loop too by expanding your complex exponential vector row-wise for every m, i.e., build the matrix exp(-j*2*pi/DFT_N*(0:DFT_N-1)'*(0:DFT_N-1)). Then your DFT is simply
X = exp(-j*2*pi/DFT_N*(0:DFT_N-1)'*(0:DFT_N-1)) * x
For single-sided spectrum, instead use
X = exp(-j*2*pi/DFT_N*(0:floor((DFT_N-1)/2))'*(0:DFT_N-1)) * x

spline interpolation and its (exact) derivatives

Suppose I have the following data and commands:
clc;clear;
t = [0:0.1:1];
t_new = [0:0.01:1];
y = [1,2,1,3,2,2,4,5,6,1,0];
p = interp1(t,y,t_new,'spline');
plot(t,y,'o',t_new,p)
You can see they work quite fine, in the sense interpolating function matches the data points at the nodes fine. But my problem is, I need to compute the exact derivative of y (i.e., p function) w.r.t. time and plot it against the t vector. How can it be done? I shall not use diff commands, because I need to make sure the derivative function has the same length as t vector. Thanks a lot.
Method A: Using the derivative
This method calculates the actual derivative of the polynomial. If you have the curve fitting toolbox you can use:
% calculate the polynominal
pp = interp1(t,y,'spline','pp')
% take the first order derivative of it
pp_der=fnder(pp,1);
% evaluate the derivative at points t (or any other points you wish)
slopes=ppval(pp_der,t);
If you don't have the curve fitting toolbox you can replace the fnderline with:
% piece-wise polynomial
[breaks,coefs,l,k,d] = unmkpp(pp);
% get its derivative
pp_der = mkpp(breaks,repmat(k-1:-1:1,d*l,1).*coefs(:,1:k-1),d);
Source: This mathworks question. Thanks to m7913d for linking it.
Appendix:
Note that
p = interp1(t,y,t_new,'spline');
is a shortcut for
% get the polynomial
pp = interp1(t,y,'spline','pp');
% get the height of the polynomial at query points t_new
p=ppval(pp,t_new);
To get the derivative we obviously need the polynomial and can't just work with the new interpolated points. To avoid interpolating the points twice which can take quite long for a lot of data, you should replace the shortcut with the longer version. So a fully working example that includes your code example would be:
t = [0:0.1:1];
t_new = [0:0.01:1];
y = [1,2,1,3,2,2,4,5,6,1,0];
% fit a polynomial
pp = interp1(t,y,'spline','pp');
% get the height of the polynomial at query points t_new
p=ppval(pp,t_new);
% plot the new interpolated curve
plot(t,y,'o',t_new,p)
% piece-wise polynomial
[breaks,coefs,l,k,d] = unmkpp(pp);
% get its derivative
pp_der = mkpp(breaks,repmat(k-1:-1:1,d*l,1).*coefs(:,1:k-1),d);
% evaluate the derivative at points t (or any other points you wish)
slopes=ppval(pp_der,t);
Method B: Using finite differences
A derivative of a continuous function is at its base just the difference of f(x) to f(x+infinitesimal difference) divided by said infinitesimal difference.
In matlab, eps is the smallest difference possible with a double precision. Therefore after each t_new we add a second point which is eps larger and interpolate y for the new points. Then the difference between each point and it's +eps pair divided by eps gives the derivative.
The problem is that if we work with such small differences the precision of the output derivatives is severely limited, meaning it can only have integer values. Therefore we add values slightly larger than eps to allow for higher precisions.
% how many floating points the derivatives can have
precision = 10;
% add after each t_new a second point with +eps difference
t_eps=[t_new; t_new+eps*precision];
t_eps=t_eps(:).';
% interpolate with those points and get the differences between them
differences = diff(interp1(t,y,t_eps,'spline'));
% delete all differences wich are not between t_new and t_new + eps
differences(2:2:end)=[];
% get the derivatives of each point
slopes = differences./(eps*precision);
You can of course replace t_new with t (or any other time you want to get the differential of) if you want to get the derivatives at the old points.
This method is slightly inferior to method a) in your case, as it is slower and a bit less precise. But maybe it's useful to somebody else who is in a different situation.

DFT of time domain for step function

I have been working on DFT in Matlab recently, here is my code in Matlab. which part of my code has problem, my sampling is wrong??? I'll be grateful if you answer my question:
dt = 0.01; %sampling time interval
Fs = 1/dt; %sampling rate
t = 0:dt:45; %Time vector
t0 = 5; %duration of applied stress
N = length(t); %number of sample points
y_timedomain = heaviside(t)-heaviside(t-t0); %the step function
figure (1)
plot(y_timedomain)
axis([-100,1000,-0.2,1.2]);
y_freqDomain=abs(fft(y_timedomain)); % fft of step funcion, y(t)
z = fftshift(y_freqDomain); % DFT and shift center to zero
figure (2)
plot(linspace(-10,10,length(y_freqDomain)),z)
xlabel('Sample Number')
ylabel('Amplitude')
title('Using the Matlab fft command')
grid
axis([-.3,.3,0,1000]);
meanwhile, I have 2 question about this code:
1- my step function at 0 time, has magnitude of 1/2, but i want my step function at 0 time be 0 instead of 1/2,( such as rectangle shape), but i don't know how to correct it???
2- when we do DFT, should we use "shift FFT" always????
if you give me your advice about this code i will be really thankful.
Heaviside Step Function
MATLAB does define the step function with 1/2 for x=0 (see http://de.mathworks.com/help/symbolic/heaviside.html?refresh=true), if you wish otherwise you could define your own function, maybe like this here?
mystep = #(x) sign(max(x, 0));
fftshift
No you don't have to use fftshift always, that really depends on what exactly you want to do. In principle, the fft is not very suited for signals like the step function (if you want to do some frequency analysis, in that particular case, I recommend to do analytical ft!). There are many side effects (I don't want to go into that field right now) and fftshift is one of the tools to help deal with those. Read the doc (doc fftshift) and learn more about the ft in general.

Fourier Analysis - MATLAB

Good evening guys,
I wanna ask you a question regarding the analysis of a function in the domain of frequencies (Fourier). I have two vectors: one containing 7700 values for pressure, and the other one containing 7700 values (same number) for time.
For example, I call the firt vector "a" and the second one "b". With the command "figure(1),plot(a,b)" I obtain the curve in the domain of time.
How can I do to plot this curve in the domain of frequency, to make Fourier transform?
I've read about the function "fft", but I've not understood very well how it can be used...can anyone help me?
Thanks in advance for your attention!
fft returns spectrum as complex numbers. In order to analyze it you have to use its absolute value or phase. In general, it should look like this (let's assume that t is vector containing time and y is the one with actual signal, N is the number of samples):
fY = fft(y) / (N/2) % scale it to amplitude, typically by N/2
amp_fY = abs(fY)
phs_fY = angle(fY)
Additionally, it would be nice to have FFT with known frequency resolution. For that, you need sampling period/frequency. Let's call that frequency fs:
fs = 1/(t(1) - t(0))
and the vector of frequencies for FFT (F)
should be:
F = (0:fs/N:(N-1)*fs/N)
and finally plots:
plot(F, amp_fY)
% or plot(F, phs_fy) according to what you need
I you can use stem instead of plot to get some other type of chart.
Note that the DC component (the average value) will be doubled on the plot.
Hope it helps

Interpolating timeseries in MATLAB to find the time for a specific value, then looking this time up in another timeseries

I have a timeseries that outputs data (time vs theta) from a Simulink model into the MATLAB workspace. I want to automatically interpolate this data so I can find what time (t1) it would be when theta == 45.
I then need to look up t1 in another time series (time vs velocity) and then output what the velocity would be at that time.
How can I do this? Is there a better way to approach this problem?
EDIT: I can interpolate the first timeseries with a new time vector and finer resolution so it has theta == 45 exactly, but my method is pretty brute force and requires manually looking at the time series first to determine what times I need to interpolate between (else it would take forever) which I'd like to avoid, e.g:
theta2 = resample(theta, 1.68:0.0000001:1.685)
I assume that theta and velocity are timeseries objects.
You can search the time interval [time_start, time_finish] as follows. However, this assumes that you know that there is a sign change in this interval.
t1 = fzero(#(t) theta.resample(t).Data - 45, [time_start, time_finish]);
Then, given t1, you can interpolate the velocity directly.
vel = velocity.resample(t1).Data;
You can use this function from the File Exchange to find the intersection of your timeseries and a straight line at theta = 45:
% assume t and theta exist in the base workspace
theta_45 = 45*ones(size(theta));
[t1,theta1] = intersections(t,theta,t,theta_45); % t1 and theta1 are column vectors of the intersection points
Then take say the first element of t1 and look it up in your second time vector t2 (I assume t2 is monotonically increasing so that should be straightforward) and find the corresponding index idx2. velocity(idx2) is your desired value.