moving(sliding) window average to create base line in Matlab - matlab

I need to compute the moving window average with a window size of 20 samples.That window should move throughout the data. Example: For the first 20 samples it will calculate the average and the window moves from 0 to and 20 to 21 and calculate the average from 1 to 21 samples and further it should move on.
I have written a code which 'x' variable is loaded with .dat file and a for loop has been written to calculate mean. The code as follows
clear all;
close all;
x= load ('cpp1500.dat');
for i=1:length(x)
s(i)=sum(x(1:i));
r(i)=s(i)./i;
end
plot(x,'R')
hold on;
plot(r)
Please suggest me a method to calculate the moving window average.
Graphs of samples v/s sensor data

In your code you seem to have mixed up some of the indexing. To answer the question (this is not the recommended version, for that refer to the version further below)
clear all;
close all;
x= load ('cpp1500.dat');
wndSize = 20;
for i=1:length(x) - wndSize
s(i)=sum(x(i:i + wndSize));
end
r = s ./ wndSize
plot(x,'R')
hold on;
plot(r)
Matlab usually punishes looping over arrays with high runtimes. You want to perform a 1d-filtering with a box filter of size 20 where Matlab happens to have efficiently implemented functions. This should do the trick:
windowSize = 20;
b = (1/windowSize)*ones(1,windowSize);
a = 1;
r = filter( b, a, x )
Beware that the implementation of filter is slightly different regarding the handling of elements from x that are close than windowSize to the ends of the array. However, it yields a usable sliding average.
See also: https://de.mathworks.com/help/matlab/ref/filter.html?requestedDomain=www.mathworks.com

That's very easy to do. You would just use the index of your for loop to help you compute that for you. Instead of going from 1 to i, you would go from i to i + 19. You will need to make sure that your for loop doesn't go beyond the bounds of the signal though, so you will need to iterate up to length(x) - 19. You also need to divide your signal by 20 before you go to the next window:
clear all;
close all;
x = load ('cpp1500.dat');
for i = 1 : length(x) - 19 % Change
s(i) = sum(x(i : i + 19)); % Change
r(i) = s(i) / 20; % Change
end
plot(x,'R');
hold on;
plot(r)
However, if I can recommend something, don't use a loop here. Use filter and specify the right side coefficients as all 1s while the left coefficient is 20. You also have to be cognizant that there will be a delay because it starts immediately filtering the signal before you have collected 20 samples to get a moving average. Therefore you will need to remove the first 19 samples from the output after you're done:
clear all;
close all;
x = load ('cpp1500.dat');
r = filter(ones(20, 1), 20, x(:));
r = r(20 : end);
plot(x, 'R');
hold on;
plot(r);
Note that I have no idea what structure your loaded vector is, so I've ensured that it's a column vector.

If you R2016a or later, you can use the movmean function to do this.
r = movmean(x, [0 19]);
will take a 20-point moving average starting at the current point and using 19 points to the left. There are other options for the function, depending on how you want to align the window, handle endpoints, tec.

Related

How to reduce for loops in a moving window based operation?

How to reduce for loops in a moving window based operation? I'm using a 15x15 window across two images and performing multiplication to get average value per pixel.
[ma,na]=size(g);
z= (win1 -1)/2;%centre of window
ini=z+1;
for i= ini :(ma-z)
for j= ini:(na-z)
for a= (i-z):(i+z)
for b=(j-z):(j+z)
W(pp,qq)= g(a, b);%window on image
Es(pp,qq)=edg(a,b);%window on edge
qq=qq+1;
end
qq=1;
pp=pp+1;
end
pp=1;
E(i,j)=sum(sum(W.*Es))/sum(sum(Es));
end
end
I might have gotten lost in your loops and i can't exactly read the formula (it's a bit fuzzy) but i think this is what you want:
g = rand(5); %sample img1
edg = rand(5); %sample img2
windowsize = 3; %set this to 15 for real images
A = g.*edg; % multiply each element beforehand, corresponds to mu*sigma in formula
B = movsum(movsum(A,windowsize,2),windowsize,1); % get moving window sum of A, corresponds to numerator in formula
C = movsum(movsum(edg,windowsize,2),windowsize,1); % get moving window sum of edg, corresponds to denominator in formula
E = B./C; %hopefully what you wanted
Ps: You need 2016a or newer to run this

Numerically integrating in Matlab. Why does increasing divisions cause less accurate output?

I am currently working on a problem in Matlab where I am given a distributed loaded beam and then numerically integrate (using the composite trapezoidal rule) to find the shear force and bending moment. From there I find the maximum moment value and the position at which this occurs. Then I differentiate twice to again find the shear force and distributed load.
I am using the analytically integrated functions in order to check and make sure that each of my numerical integrations and differentiations are calculated correctly. My issue is that when I use only 13 points to perform the calculations (x = 0:12;) my values are as close as I have gotten them to the results from the analytical values. (This number comes from the beam being 12 ft and the divisions are 1 ft each). When I increase the number of divisions in order to increase the accuracy of my numerical integration the values get further away from the analytical values. I would like to figure out what could have caused this and thus far have been unsuccessful.
My code:
clear; clc;
% n=100;
% x = linspace(0,12,n+1); %dx (100 divisions)
x=0:12; %dx (12 divisions)
w = 12.5.*x; %distributed load
%//Integrated Shear
V(1)=300;
for i = 2: length(w)
weight = [.5 ones(1,i-2) .5];
V(i)=300-sum(weight.*w(1:i));
end
figure(1); clf;
plot(x,V,'--');
legend('Numerical Shear');
xlabel('Position (ft)'); ylabel('Shear Force (lb)');
%//Integrated Moment
Mactual = 300.*x - ((25/12).*(x.^3)); %analytically integrated M
M(1)=0;
for i = 2: length(V)
weight = [.5 ones(1,i-2) .5];
M(i)=sum(weight.*V(1:i));
end
figure(2); clf;
plot(x,M,'--'); hold on;
plot(x,Mactual); hold off;
legend('Numerical Moment' , 'Analytical Moment');
xlabel('Position (ft)'); ylabel('Bending Moment (lbf)');
%//Max Moment and Position at Max Moment
[maxMValue, indexAtMaxM] = max(M);
xValueAtMaxMValue = x(indexAtMaxM(1));
dispM = [ 'Maximum bending moment: ' , num2str(maxMValue) , ' lbf'];
disp(dispM);
dispX = [ 'Position at maximum bending moment: ' , num2str(xValueAtMaxMValue) , ' ft' ];
disp(dispX)
%//Derived Shear
dM(1)=300;
for i = 1:length(x)-1
dM(i+1) = (M(i+1)-M(i));
end
figure(3); clf;
plot(x,dM,'--'); hold on;
Vactual = 300 - 6.25.*(x.^2); %analytically integrated shear
plot(x,Vactual); hold off;
legend('Numerical Shear' , 'Analytical Shear');
xlabel('Position (ft)'); ylabel('Shear Force (lb)');
%//Derived Load
dV(1)=0;
for i = 1:length(x)-1
dV(i+1) = -(V(i+1)-V(i));
end
figure(4); clf;
plot(x,dV,'--'); hold on;
plot (x,w); hold off;
legend('Numerical Load' , 'Analytical Load');
xlabel('Position (ft)'); ylabel('Distributed Load (lb/ft)');
In the code above the 2nd and 3rd lines are commented out to show the output with only 12 divisions. If you uncomment those two lines and comment out the 4th line the output shows values with 100 divisions.
Quick Note: The analytical values are plotted against the integrated moment, derived shear, and derived distributed load as a comparison. Consider the analytical values (Mactual and Vactual) as the correct output values.
Any input which could help lead me to a way to solve this issue would be greatly appreciated.
To get the correct integral value, you will need to multiply the function value sums with dx=12/n or identically dx=x(2)-x(1) if n is different from 12.
(11/28) You can also simplify the trapezoidal integration loops as
V(1)=300
M(1)=0
for i=2:n
V(i) = V(i-1) - 0.5*dx*(w(i-1)+w(i))
M(i) = M(i-1) + 0.5*dx*(V(i-1)+V(i))
end
thus avoiding reconstruction of the weights and computation of the sums in each step. This reduces this part of the algorithm from O(n^2) to O(n).

Swinging spring ODE system in Matlab - How do I make a position vector follow the path?

I'm very new to Matlab.
I have a script using ode45 and arrow.m to show the motion of a swinging spring with a mass on Matlab as it moves through 3-D space. The program is almost doing what I want it to. Right now the density of the diamonds is showing the speed of the spring in effect (except for when ode45 takes it personal favorite number samples) and the velocity is almost accurately accounted for with the step size of the function (at least with the speed that my computer is running the code). What I want to do with this is have the position vector that I commented out in the code only show up at the instantaneous position of the mass, that is the endpoint of the curve, and not at every point that the diamonds show up at. I've looked around for help, but everything I try seems to cause errors. If somebody could point me in the right direction it would be much appreciated. Please try running the program and you will see what I mean, also play around with the parameters of the function.
function elasticPendulum(totalTime)
time=1;
totalTime=20
X=1
Vx=0
Y=0
Vy=0
Z=1.1
Vz=0
w=3;
g=9;
l=1;
while (time<totalTime)
tspan=[0,time];
x0=[X,Vx,Y,Vy,Z,Vz];
[t,x]=ode45(#F,tspan,x0);
plot3(x(:,1),x(:,3),x(:,5),'dk'), axis([-2 2 -2 2 -10 2]);
grid on;
o=[0, 0, 0];
Xeq=[0, 0, -(g/(w^2)+l)];
arrow(o,Xeq,'Length',5);
%{
Xt=[x(:,1) x(:,3) x(:,5)]
arrow(o,Xt,'Length',5);
%}
time=time+.1*(((x(2))^2+(x(4))^2+(x(6))^2)^(1/2))
pause(.1);
end
function xprime=F(t,x)
r=sqrt(x(1)^2+x(3)^2+x(5)^2);
xprime=[x(2);-w*(r-l)/r*x(1);x(4);-w*(r-l)/r*x(3);x(6);-w*(r-l)/r*x(5)-g];
end
end
I think that you can accomplish what you want simply by setting Xt to this so that only the last vector is plotted on each iteration:
Xt = [x(end,1) x(end,3) x(end,5)];
Also, you mention that things are working "except for when ode45 takes it personal favorite number samples." You can can tell ode45 to use fixed step output simply by changing tspan:
tspan = 0:dt:time;
where dt = 1/time (or you could use linspace). This is not the same thing as using a fixed step solver – read my answer to this question to maybe gain some understanding on this.
I don't think that you're updating your animation properly. You update time, but not the initial conditions. Therefore, you integrate over the same path on each iteration of the while loop. Is there a reason that you're adjusting the end time on each iteration? Are you trying to find the oscillation period or something?
Also, your method of animation is rather crude/inefficient. You should read about the output options that can be set via odeset for Matlab's ODE solvers. In particular 'OutputFcn'. You might even be able to use and/or look at the code for some of the built in output functions – for example, type edit odeplot or edit odephas3 in your command window. Here is a simple output function I created for your case:
function elasticPendulum
totalTime = 20;
stepsPerSec = 10;
X = 1; Vx = 0;
Y = 0; Vy = 0;
Z = 1.1; Vz = 0;
w = 3; g = 9; l = 1;
opts = odeset('OutputFcn',#(t,x,flag)arrowplot(t,x,flag,w,l,g));
tspan = linspace(0,totalTime,totalTime*stepsPerSec);
x0 = [X,Vx,Y,Vy,Z,Vz];
ode45(#(t,x)F(t,x,w,l,g),tspan,x0,opts);
function xprime=F(t,x,w,l,g) %#ok<INUSL>
r=sqrt(x(1)^2+x(3)^2+x(5)^2);
xprime=[x(2);-w*(r-l)/r*x(1);x(4);-w*(r-l)/r*x(3);x(6);-w*(r-l)/r*x(5)-g];
function status=arrowplot(t,x,flag,w,l,g) %#ok<INUSL>
persistent h; % Handle for moving arrow
status = 0;
o = [0, 0, 0];
switch flag
case 'init'
axis([-2 2 -2 2 -10 2]); grid on; hold on;
Xeq = [0, 0, -(g/(w^2)+l)];
arrow(o,Xeq,'Length',5);
plot3(x(1,:),x(3,:),x(5,:),'dk'); % Initial position
Xt = [x(1,end) x(3,end) x(5,end)];
h = arrow(o,Xt,'Length',5); % Initial arrow, get handle
case 'done'
hold off; status = 1;
otherwise
plot3(x(1,:),x(3,:),x(5,:),'dk'); % Plot new positions
Xt = [x(1,end) x(3,end) x(5,end)];
arrow(h,'Start',o,'Stop',Xt,'Length',5); % Update arrow
pause(0.1);
end
The call to plot3 on every iteration (the otherwise case in arrowplot) is still inefficient as it adds new high level plot objects, taking up more memory. The better/faster way is to get a handle from the first call to plot3 and use set and get to add the new data points. See the code for odeplot and odephas3 for how you might do this (it's a bit advanced).
Note how I also pass parameters via anonymous functions rather than by creating sub-functions. This is a bit of a matter of style.

Select a random patch from an image using matlab

I have a gray image of size 400 x 600 . And i want to select randomly from this image, a patch of size 50 x 50.
By the way, i tried to write a code for this, and it worked fine. But according to my code below, there is another solution ? In other words, is there another code which can be more sexy than my own code ?
clear all;
close all;
clc;
image=imread('my_image.jpg');
image_gray=rgb2gray(image);
[n m]= size(image_gray); % 400 x600
L=50;
x=round(rand(1)*n); % generate a random integer between 1 and 400
y=round(rand(1)*m); % generate a random integer between 1 and 600
%verify if x is > than 400-50 , because if x is equal to 380 for example, so x+50 become %equal to 430, it exceeds the matrix dimension of image...
if(x<=n-L)
a=x:x+(L-1);
else
a=x-(L-1):x;
end
if(y<=m-L)
b=y:y+(L-1);
else
b=y-(L-1):y;
end
crop=image_gray(a,b);
figure(1);
imshow(crop);
This is as "sexy" as it gets. Satisfaction guaranteed ;-)
% Data
img=imread('my_image.jpg');
image_gray=rgb2gray(img);
[n m]= size(image_gray);
L = 50;
% Crop
crop = image_gray(randi(n-L+1)+(0:L-1),randi(m-L+1)+(0:L-1));
If using a Matlab version that doesn't support randi, substitute last line by
crop = image_gray(ceil(rand*(n-L+1))+(0:L-1),ceil(rand*(m-L+1))+(0:L-1));
Comments to your code:
You shouldn't use image as a variable name. It overrides a function.
You should change round(rand(1)*n) to ceil(rand(1)*n). Or use randi(n).
Instead of randi(n), use randi(n-L+1). That way you avoid the ifs.
For anyone struggling to get this code to work for RGB images, when you compute the size you'll want to add an extra variable for the third dimension. i.e.
% Data
img=imread('my_image.jpg');
% Not making anything gray anymore
[n, m, ~]= size(img);
L = 50;
% Crop - add a : in order to get 3 or more dimensions at the end
crop = img(randi(n-L+1)+(0:L-1),randi(m-L+1)+(0:L-1), :);
Super simple but not necessarily obvious at first.

How to create sliding window over signal on matlab

I have a sequence of data. So I want to plot that data inside the sliding windows due to windows length.
Help me please.
Actually data is from mean and variance of frames. So I want to plot that mean and variance inside the sliding windows. Also I can't create sliding windows on Matlab.
My approach would be,
a = randi(100,[1,50]); % My sequence
win_width = 10; %Sliding window width
slide_incr = 1; %Slide for each iteration
numstps = (length(a)-win_width)/slide_incr; %Number of windows
for i = 1:numstps
mean_win(i) = mean(a(i:i+win_width)); %Calculation for each window
end
plot(mean_win)
there may be better ways of doing it..
This is how I've always done it (adapted from code for 2 sliding windows). You can calculate the mean and variance however you'd like.
T = 25; % Window Size
K = size(data,1) - T; % Number of repetitions
for i = 1:K
window = data(i:i+T-1,:);
% Mean and Variance Calculations here
% Plotting here
% call 'drawnow' for incremental plotting (animation)
end
So if I understand you correctly you want to change the x-axis limits of the plot. Use xlim for that, for example:
a=1:10;
plot(a)
xmin = 5;
xmax = 7.6;
xlim([xmin xmax])
or if you want a window of a constant size you can xlim([xmin xmin+window]) etc...