How to create sliding window over signal on matlab - 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...

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

Best method of removing flattish areas of a signal in MatLab?

Say I have a signal that looks a bit like this:
that I am processing in MatLab, what functions would I have to use to get rid of the flattish area in the middle? is there any functions that can do that, or do I need to program it in myself? Currently I just have a blank function as I don't know where to start:
function removala = removal(a, b)
end
Is there any quick functions that can remove it or do I just have to search for all values below a threshold and remove them myself? For reference a and b are vectors of amplitude points.
use findpeaks:
% generating signal
x = 1:0.1:10;
y = rand(size(x))*0.5;
y([5,25,84]) = [6,-5.5,7.5];
z = y;
thresh = 0.75; % height threshold
% find peaks
[pks,locs] = findpeaks(z,'MinPeakProminence',thresh);
% remove signal noise between peaks
for ii = 1:length(locs)-1
zz = z(locs(ii)+1:locs(ii+1)-1);
zz(abs(zz) < thresh) = 0;
z(locs(ii)+1:locs(ii+1)-1) = zz;
end
% plot
plot(x,y);
hold on
plot(x,z);
plot(x(locs),pks,'og');
legend('original signal','modified signal','peaks')
You probably want to remove the signal whose absolute power is less than a certain threshold.
So the two input of your function would be the raw signal, and the threshold. The function will output a variable "cleanSignal"
function cleanSignal = removal(rawSignal,threshold)
simplest implementation. remove the data below threshold. If rawSignal is a matrix the resulting variable will be a vector concatenating all the epochs above threshold.
ind = abs(rawSignal)<threshold;
rawSignal(ind) = [];
cleanSignal = rawSignal;
This might not be the behavior that you want, since you want to preserve the original shape of your rawSignal matrix. So you can just "nan" the values below threshold.
ind = abs(rawSignal)<threshold;
rawSignal(ind) = nan;
cleanSignal = rawSignal;
end
Notice that this does not really removes flat signal, but signal which is close to 0.
If you really want to remove flat signal you should use
ind = abs(diff(rawSignal))<threshold;

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.

Positive & Negitive Log10 Scale Y axis in Matlab

Hi i'm having a problem where I have a dataset which ranges between -10^3 to 10^3
I need to be able to plot this as with a log scale but semilogy cannot plot negative values
Say for example my data is:
x = [-3,-2,-1,0,1,2,3];
y = [-1000,-100,-10,1,10,100,1000];
(or in general y=sign(x).*10.^abs(x);)
How can I plot this in MATLAB with a log scale? If possible It would be great if the log scale ticks could be on the Y-axis too
Use your actual data as labels, but scale the plotted data with log10.
% data
x = -3:0.1:3;
y = sign(x).*10.^abs(x);
% scaling function
scale = #(x) sign(x).*log10(abs(x));
N = 7; % number of ticks desired
% picking of adequate values for the labels
TickMask = linspace(1,numel(y),N);
YTickLabels = y(TickMask);
% scale labels and plotdata, remove NaN ->inconsistency, do you really want that?
YTick = scale( YTickLabels );
Y = scale(y);
YTick(isnan(YTick)) = 0;
Y(isnan(Y)) = 0;
% plot
plot(x,Y)
set(gca,'YTick',YTick,'YTickLabels',YTickLabels)
grid on
For N = 7:
For N = 11
How to find a valid value for N?
The following function (thanks to gnovice) will return all possible values you could choose for N:
n = numel(x);
N = find(rem(n./(1:n), 1) == 0) + 1;
about the semilogy-style labels: by adding the following line before the plot:
YTickLabels = cellfun(#(x) ['10^' num2str(x)], num2cell(YTick),'UniformOutput',false)
you could at least achieve something like this:
not beautiful and not generic, but a good point to start for you.
The reason you can't make a logarithmic axis that crosses zero, is that it doesn't make sense!
Since a logarithmic scale is generally displayed as eg. 100 - 10 - 1 - 1/10 - 1/100 - ..., you would need an infinite amount of space to make the axis cross zero.
How about this:
x=logspace(-3,3);
y=sign(x).*10.^abs(x);
loglog(x,y)
#thewaywewalk has already given a beautiful solution to it. The one I'm suggesting is an epsilon improvement on it. If you make two changes
(a) Define a new MATLAB function signia that basically extracts the sign before a number.
function value = signia(x)
if(x>=0)
value = '';
else
value = '-';
end
and (b) make this little change that instead of
YTickLabels = cellfun(#(x) ['10^' num2str(x)], num2cell(YTick),'UniformOutput',false)
you use
YTickLabels = cellfun(#(x) [signia(x) '10^{' num2str(x) '}'], num2cell(YTick),'UniformOutput',false);
(notice the presence of curly braces), you'll get an improvement in the Y ticks display. I got the following.
enter image description here

How to fit a curve by a series of segmented lines in Matlab?

I have a simple loglog curve as above. Is there some function in Matlab which can fit this curve by segmented lines and show the starting and end points of these line segments ? I have checked the curve fitting toolbox in matlab. They seems to do curve fitting by either one line or some functions. I do not want to curve fitting by one line only.
If there is no direct function, any alternative to achieve the same goal is fine with me. My goal is to fit the curve by segmented lines and get locations of the end points of these segments .
First of all, your problem is not called curve fitting. Curve fitting is when you have data, and you find the best function that describes it, in some sense. You, on the other hand, want to create a piecewise linear approximation of your function.
I suggest the following strategy:
Split manually into sections. The section size should depend on the derivative, large derivative -> small section
Sample the function at the nodes between the sections
Find a linear interpolation that passes through the points mentioned above.
Here is an example of a code that does that. You can see that the red line (interpolation) is very close to the original function, despite the small amount of sections. This happens due to the adaptive section size.
function fitLogLog()
x = 2:1000;
y = log(log(x));
%# Find section sizes, by using an inverse of the approximation of the derivative
numOfSections = 20;
indexes = round(linspace(1,numel(y),numOfSections));
derivativeApprox = diff(y(indexes));
inverseDerivative = 1./derivativeApprox;
weightOfSection = inverseDerivative/sum(inverseDerivative);
totalRange = max(x(:))-min(x(:));
sectionSize = weightOfSection.* totalRange;
%# The relevant nodes
xNodes = x(1) + [ 0 cumsum(sectionSize)];
yNodes = log(log(xNodes));
figure;plot(x,y);
hold on;
plot (xNodes,yNodes,'r');
scatter (xNodes,yNodes,'r');
legend('log(log(x))','adaptive linear interpolation');
end
Andrey's adaptive solution provides a more accurate overall fit. If what you want is segments of a fixed length, however, then here is something that should work, using a method that also returns a complete set of all the fitted values. Could be vectorized if speed is needed.
Nsamp = 1000; %number of data samples on x-axis
x = [1:Nsamp]; %this is your x-axis
Nlines = 5; %number of lines to fit
fx = exp(-10*x/Nsamp); %generate something like your current data, f(x)
gx = NaN(size(fx)); %this will hold your fitted lines, g(x)
joins = round(linspace(1, Nsamp, Nlines+1)); %define equally spaced breaks along the x-axis
dx = diff(x(joins)); %x-change
df = diff(fx(joins)); %f(x)-change
m = df./dx; %gradient for each section
for i = 1:Nlines
x1 = joins(i); %start point
x2 = joins(i+1); %end point
gx(x1:x2) = fx(x1) + m(i)*(0:dx(i)); %compute line segment
end
subplot(2,1,1)
h(1,:) = plot(x, fx, 'b', x, gx, 'k', joins, gx(joins), 'ro');
title('Normal Plot')
subplot(2,1,2)
h(2,:) = loglog(x, fx, 'b', x, gx, 'k', joins, gx(joins), 'ro');
title('Log Log Plot')
for ip = 1:2
subplot(2,1,ip)
set(h(ip,:), 'LineWidth', 2)
legend('Data', 'Piecewise Linear', 'Location', 'NorthEastOutside')
legend boxoff
end
This is not an exact answer to this question, but since I arrived here based on a search, I'd like to answer the related question of how to create (not fit) a piecewise linear function that is intended to represent the mean (or median, or some other other function) of interval data in a scatter plot.
First, a related but more sophisticated alternative using regression, which apparently has some MATLAB code listed on the wikipedia page, is Multivariate adaptive regression splines.
The solution here is to just calculate the mean on overlapping intervals to get points
function [x, y] = intervalAggregate(Xdata, Ydata, aggFun, intStep, intOverlap)
% intOverlap in [0, 1); 0 for no overlap of intervals, etc.
% intStep this is the size of the interval being aggregated.
minX = min(Xdata);
maxX = max(Xdata);
minY = min(Ydata);
maxY = max(Ydata);
intInc = intOverlap*intStep; %How far we advance each iteraction.
if intOverlap <= 0
intInc = intStep;
end
nInt = ceil((maxX-minX)/intInc); %Number of aggregations
parfor i = 1:nInt
xStart = minX + (i-1)*intInc;
xEnd = xStart + intStep;
intervalIndices = find((Xdata >= xStart) & (Xdata <= xEnd));
x(i) = aggFun(Xdata(intervalIndices));
y(i) = aggFun(Ydata(intervalIndices));
end
For instance, to calculate the mean over some paired X and Y data I had handy with intervals of length 0.1 having roughly 1/3 overlap with each other (see scatter image):
[x,y] = intervalAggregate(Xdat, Ydat, #mean, 0.1, 0.333)
x =
Columns 1 through 8
0.0552 0.0868 0.1170 0.1475 0.1844 0.2173 0.2498 0.2834
Columns 9 through 15
0.3182 0.3561 0.3875 0.4178 0.4494 0.4671 0.4822
y =
Columns 1 through 8
0.9992 0.9983 0.9971 0.9955 0.9927 0.9905 0.9876 0.9846
Columns 9 through 15
0.9803 0.9750 0.9707 0.9653 0.9598 0.9560 0.9537
We see that as x increases, y tends to decrease slightly. From there, it is easy enough to draw line segments and/or perform some other kind of smoothing.
(Note that I did not attempt to vectorize this solution; a much faster version could be assumed if Xdata is sorted.)