I would like to define a Matlab function like the one shown in the figure below, but repeating regularly along the t axis.
So far I tried two different codes:
function Borne = borne(p)
pxt = x;
Borne = zeros(size(pxt));
i0 = (pxt <= 0.1);
i1 = (pxt > 0.1 & pxt < 0.3);
i2 = (pxt > 0.3 & pxt < 0.5);
i3 = (pxt > 0.5 & pxt < 0.7);
i4 = (pxt > 0.7 & pxt < 0.9);
i5 = (pxt > 0.9 & pxt < 1.1);
Borne(i0) = 3;
Borne(i1) = -1;
Borne(i2) = 3;
Borne(i3) = -1;
Borne(i4) = 3;
Borne(i5) = -1;
This one works, but I might be obliged to go to time=100 perhaps.
function Borne = borne(p)
x=0:0.2:100;
y=ones(1,length(x));
for i=1:length(x)
if mod(i,2) == 1;
y(i)=3;
else
y(i)=-1;
end
end
Borne=stairs(x,y);
This one doesn't work at all, it gives me a constant function at 147 circa. Also, at the end of the for loop both x and y have length=1, and I don't know why.
Is there a better way to define my function, maybe? If not, how can I improve my codes?
Thank you very much!
You can do it one-shot with the remainder (rem) function and logical indexing:
%// Data
period = 1;
up_start = .1;
up_stop = .4;
up_value = 3;
down_value = -1;
x = linspace(0,10,200); %// x axis
%// Generate function
Borne = zeros(size(x)); %// initiallize
aux = rem(x,period);
ind = (aux>=up_start) & (aux<up_stop); %// index of "up" values
Borne(ind) = up_value;
Borne(~ind) = down_value;
If you want steps at 2, 4, 6 etc. you could use cumsum:
t = (1:14).*0.1;
x(2:4:12) = -4;
x(4:4:14) = 4;
x(1) = 3;
y = cumsum(x);
[t; y] =
1 2 3 4 5 6 7 8 9 10 11 12 13 14
0 1 1 0 0 1 1 0 0 1 1 0 0 1
The way this works is, you first create a vector that is +1 and -1 where you want the step to be. cumsum will take the cumulative sum of this vector, thus altering between 1 and 0.
If you want, you can plot this using stairs.
Update
With your values, this will be:
n = 8; % Don't know the length of t
t = (0:n).*0.1;
x = zeros(1, length(t));
x(2:4:length(t)) = -4;
x(4:4:length(t)) = 4;
x(1) = 3;
y = cumsum(x);
[t; y] =
0.00000 0.10000 0.20000 0.30000 0.40000 0.50000 0.60000 0.70000
3.00000 -1.00000 -1.00000 3.00000 3.00000 -1.00000 -1.00000 3.00000
No complicated code is needed for something like this. You can use the square function, which is part of the Signal Processing toolbox that comes with most distributions of Matlab:
miny = -1; % Minimum amplitude
maxy = 3; % Maximum amplitude
period = 0.4; % Period in Hz, 1/frequency
duty = 0.5; % Duty cycle, percentage of time spent at maxy
offset = 0.1; % Phase offset in sec.
t = 0:0.01:3;
y = 0.5*(maxy-miny)*square(2*pi*(t-offset)/period,duty*100)-miny;
figure;
plot(t,y)
axis([t(1) t(end) miny-0.1*(maxy-miny) maxy+0.1*(maxy-miny)])
Related
I am currently practicing modelling "random walks" and population modelling. I have a working code that works for a 1D random walk, in the future I'd like to add extra dimensions and I think the code I have at the moment would make it more difficult. I need to plot the first two positions before I can start the for loop. Ideally I would like to get rid of that issue and have it start from the first step.
numjumps = 20; %number of steps
R = 0.5; %probability of step to right
more off
prev_position = [0 0]; %first position
x = rand(1); %generate random number 0-1
if x >= R;
step = 1; %take a step to the right
elseif x < R
step = -1; %take a step to the left
end
position = [1 prev_position(2) + step];
close all;
figure;
hold on;
plot([prev_position(1) position(1)], [prev_position(2) position(2)]);
axis([0 numjumps -5 5])
for i = (2:numjumps);
prev_position(i) = position(i-1);
x = rand(1); %generate random number 0-1
if x >= R;
step = 1; %take a step to the right
elseif x < R
step = -1; %take a step to the left
end
position(i) = [prev_position(i) + step]; %add step to position
plot(position);
axis([0 numjumps -5 5])
end
total = sum(position);
mean_position = total/numjumps;
disp(mean_position);
Any help would be greatly appreciated.
You shouldn't use a for loop, just vectorize your code:
numjumps = 20; %number of steps
R = 0.5; %probability of step to right
x = rand (numjumps, 1);
step = 2 * (x >= R) - 1;
position = [0; cumsum(step)];
plot (position)
now it's easy to make it 2D:
numjumps = 200; %number of steps
R = 0.5; %probability of step to right
x = rand (numjumps, 2);
step = 2 * (x >= R) - 1;
position = [0, 0; cumsum(step)];
plot (position(:, 1), position (:, 2))
gives
I'm currently trying to implement the HS-method for optical flow but my u and v always seem to have only zeros in them. I can't seem to figure out my error in here:
vid=VideoReader('outback.AVI');
vid.CurrentTime = 1.5;
alpha=1;
iterations=10;
frame_one = readFrame(vid);
vid.CurrentTime = 1.6;
frame_two = readFrame(vid);
% convert to grayscale
fone_gr = rgb2gray(frame_one);
ftwo_gr = rgb2gray(frame_two);
% construct for each image
sobelx=[-1 -2 -1; 0 0 0; 1 2 1];
sobely=sobelx';
time=[-1 1];
fx_fone=imfilter(fone_gr, sobelx);
fy_fone=imfilter(fone_gr, sobely);
ft_fone=imfilter(fone_gr, time);
fx_ftwo=imfilter(ftwo_gr, sobelx);
fy_ftwo=imfilter(ftwo_gr, sobely);
ft_ftwo=imfilter(ftwo_gr, time);
Ix=double(fx_fone+fx_ftwo);
Iy=double(fy_fone+fy_ftwo);
It=double(ft_fone+ft_ftwo);
% flow-variables (velocity = 0 assumption)
velocity_kernel=[0 1 0; 1 0 1; 0 1 0];
u = double(0);
v = double(0);
% iteratively solve for u and v
for i=1:iterations
neighborhood_average_u=conv2(u, velocity_kernel, 'same');
neighborhood_average_v=conv2(v, velocity_kernel, 'same');
data_term = (Ix .* neighborhood_average_u + Iy .* neighborhood_average_v + It);
smoothness_term = alpha^2 + (Ix).^2 + (Iy).^2;
numerator_u = Ix .* data_term;
numerator_v = Iy .* data_term;
u = neighborhood_average_u - ( numerator_u ./ smoothness_term );
v = neighborhood_average_v - ( numerator_v ./ smoothness_term );
end
u(isnan(u))=0;
v(isnan(v))=0;
figure
imshow(frame_one); hold on;
quiver(u, v, 5, 'color', 'b', 'linewidth', 2);
set(gca, 'YDir', 'reverse');
The only thing I'm not really confident about is the computation of the neighborhood average:
velocity_kernel=[0 1 0; 1 0 1; 0 1 0];
u = double(0);
v = double(0);
[..]
neighborhood_average_u=conv2(u, velocity_kernel, 'same');
neighborhood_average_v=conv2(v, velocity_kernel, 'same');
Wouldn't that always result in a convolution matrix with only zeros?
I thought about changing it to the following, since I need to compute the average velocity using the velocity kernel on each pixel of my images:
velocity_kernel=[0 1 0; 1 0 1; 0 1 0];
u = double(0);
v = double(0);
[..]
neighborhood_average_u=conv2(Ix, velocity_kernel, 'same');
neighborhood_average_v=conv2(Iy, velocity_kernel, 'same');
But I still don't know if that would be the correct way. I followed the instructions on the bottom of this MATLAB page:
http://de.mathworks.com/help/vision/ref/opticalflowhs-class.html
I found this paper with some further explanations and also some matlab code.
They compute the average of u and v as follows:
% initial values
u = 0; v = 0;
% weighted average kernel
kernel = [1/12 1/6 1/12; 1/6 0 1/6; 1/12 1/6 1/12];
for i = 1:iterations
uAvg = conv2( u, kernel 'same' );
vAvg = conv2( v, kernel 'same' );
...
end
I want to speed up my code. I always use vectorization. But in this code I have no idea how to avoid the for-loop. I would really appreciate a hint how to proceed.
thank u so much for your time.
close all
clear
clc
% generating sample data
x = linspace(10,130,33);
y = linspace(20,100,22);
[xx, yy] = ndgrid(x,y);
k = 2*pi/50;
s = [sin(k*xx+k*yy)];
% generating query points
xi = 10:5:130;
yi = 20:5:100;
[xxi, yyi] = ndgrid(xi,yi);
P = [xxi(:), yyi(:)];
% interpolation algorithm
dx = x(2) - x(1);
dy = y(2) - y(1);
x_ = [x(1)-dx x x(end)+dx x(end)+2*dx];
y_ = [y(1)-dy y y(end)+dy y(end)+2*dy];
s_ = [s(1) s(1,:) s(1,end) s(1,end)
s(:,1) s s(:,end) s(:,end)
s(end,1) s(end,:) s(end,end) s(end,end)
s(end,1) s(end,:) s(end,end) s(end,end)];
si = P(:,1)*0;
M = 1/6*[-1 3 -3 1
3 -6 3 0
-3 0 3 0
1 4 1 0];
tic
for nn = 1:numel(P(:,1))
u = mod(P(nn,1)- x_(1), dx)/dx;
jj = floor((P(nn,1) - x_(1))/dx) + 1;
v = mod(P(nn,2)- y_(1), dy)/dy;
ii = floor((P(nn,2) - y_(1))/dy) + 1;
D = [s_(jj-1,ii-1) s_(jj-1,ii) s_(jj-1,ii+1) s_(jj-1,ii+2)
s_(jj,ii-1) s_(jj,ii) s_(jj,ii+1) s_(jj,ii+2)
s_(jj+1,ii-1) s_(jj+1,ii) s_(jj+1,ii+1) s_(jj+1,ii+2)
s_(jj+2,ii-1) s_(jj+2,ii) s_(jj+2,ii+1) s_(jj+2,ii+2)];
U = [u.^3 u.^2 u 1];
V = [v.^3 v.^2 v 1];
si(nn) = U*M*D*M'*V';
end
toc
scatter3(P(:,1), P(:,2), si)
hold on
mesh(xx,yy,s)
This is the full example and is a cubic B-spline surface interpolation algorithm in 2D space.
I have this for loop
for mass = 1:.1:4
theta = 60;
Fw = [0 -9.8*mass 0];
Rw = [ 0.2*cosd(theta) 0.2*sind(theta) 0];
Mw = cross(Rw,Fw);
Fjrf = [30 50 0];
Rjrf = [0.4*cosd(theta) 0.4*sind(theta) 0];
Mjrf = cross(Rjrf,Fjrf);
alpha = 5;
Ialpha = [0 0 alpha*(0.02+mass*0.2^2)];
Ms = Ialpha - Mjrf - Mw;
omega = [0 0 pi];
alphav = [0 0 5];
anorm = ([-cosd(theta) -sind(theta) 0]*(norm(omega))^2);
atang = cross(Rjrf,alphav);
a = anorm + atang;
Fmuscle = norm(mass*a - Fjrf - Fw)
mass
plot(mass,Fmuscle)'
hold on
end
Where in the end the output is just various values of Fmuscle, that correspond to values of mass varrying from 1 to 4 at intervals of .1. I am trying to plot all these values on a graph (mass =x and Fmuscle = y) but I cannot figure out how to generate this.
With the code I have above I simply get an empty graph, even though I get all the right variables.
Thanks!
This what you want?
i = 0; %set initial index
clear x y; %clear these variables
for mass = 1:.1:4
i = i + 1; %increment index
theta = 60;
Fw = [0 -9.8*mass 0];
Rw = [ 0.2*cosd(theta) 0.2*sind(theta) 0];
Mw = cross(Rw,Fw);
Fjrf = [30 50 0];
Rjrf = [0.4*cosd(theta) 0.4*sind(theta) 0];
Mjrf = cross(Rjrf,Fjrf);
alpha = 5;
Ialpha = [0 0 alpha*(0.02+mass*0.2^2)];
Ms = Ialpha - Mjrf - Mw;
omega = [0 0 pi];
alphav = [0 0 5];
anorm = ([-cosd(theta) -sind(theta) 0]*(norm(omega))^2);
atang = cross(Rjrf,alphav);
a = anorm + atang;
Fmuscle = norm(mass*a - Fjrf - Fw);
x(i) = mass; % set the appropriate row of x vector
y(i) = Fmuscle; % same for y
end
plot(x, y);
Good day,
I have code that stretches and rotates a gaussian 2d pdf as such:
mu = [0 0];
Sigma = [1 0; 0 1];
Scale = [3 0; 0 1];
Theta = 10;
Rotate = [cosd(Theta) -sind(Theta); sind(Theta) cosd(Theta)];
Sigma = (Sigma*Scale)*Rotate
x1 = -100:1:100; x2 = -100:1:100;
[X1,X2] = meshgrid(x1,x2);
F = mvnpdf([X1(:) X2(:)],mu,Sigma);
F = reshape(F,length(x2),length(x1));
imshow(F*255)
Unfortunately, when I change Theta to a value other than 0, it says
SIGMA must be a square, symmetric, positive definite matrix. Can I know what's going on
If you consult the article on Wikipedia about the general elliptical version of the Gaussian 2D PDF, it doesn't look like you're rotating it properly. In general, the equation is:
Source: Wikipedia
where:
Usually, A = 1 and we'll adopt that here. The angle theta will rotate the PDF counter-clockwise, and so we can use this raw form of the equation over mvnpdf. Using your definitions and constants, it would become this:
x1 = -100:1:100; x2 = -100:1:100;
[X1,X2] = meshgrid(X1, X2);
sigma1 = 1;
sigma2 = 1;
scale1 = 3;
scale2 = 1;
sigma1 = scale1*sigma1;
sigma2 = scale2*sigma2;
Theta = 10;
a = ((cosd(Theta)^2) / (2*sigma1^2)) + ((sind(Theta)^2) / (2*sigma2^2));
b = -((sind(2*Theta)) / (4*sigma1^2)) + ((sind(2*Theta)) / (4*sigma2^2));
c = ((sind(Theta)^2) / (2*sigma1^2)) + ((cosd(Theta)^2) / (2*sigma2^2));
mu = [0 0];
A = 1;
F = A*exp(-(a*(X1 - mu(1)).^2 + 2*b*(X1 - mu(1)).*(X2 - mu(2)) + c*(X2 - mu(2)).^2));
imshow(F*255);
I see that you are trying to rotate the variances in 2D... You have to hit your sigma matrix with your transform on both sides of it since the "sigma" matrix is essentially a tensor.
mu = [0 0];
Sigma = [1 0; 0 1];
Scale = [10 0;0 1];
Theta = pi/3;
m = makehgtform('zrotate',Theta);
m = m(1:2,1:2);
Sigma = m*(Sigma*Scale)*m.';
x1 = -100:1:100;
x2 = -100:1:100;
[X1,X2] = meshgrid(x1,x2);
F = mvnpdf([X1(:) X2(:)],mu,Sigma);
F = reshape(F,length(x2),length(x1));
imshow(F*255)