3D / 4D Matrix manipulation - arrays

I often struggle with slow Matlab processing due to high numbers of for loops.
Maybe you can help me with this example, which would help me in other cases as well: Is it possible to completely transfer it to matrices?
R = [1 2 3; 1 2 3; 1 2 3];
u1 = 200; u2 = 300; v1 = 100; v2 = 222; w1 = 123; w2 = 312;
px = 20; py = 30; pz = 25;
a = 20; b = 30; c = 25;
Ellipse = zeros(500,600,500)
for i=u1:u2
for j=v1:v2
for k=w1:w2
x=[i-px;j-py;k-pz];
x=R*x;
if (x(1)/a)^2+(x(2)/b)^2+(x(3)/c)^2<1
Ellipse(i,j,k)=1;
end
end
end
end

Here's one approach that runs about 2 orders of magnitude faster
R = [1 2 3; 1 2 3; 1 2 3];
u1 = 200; u2 = 300; v1 = 100; v2 = 222; w1 = 123; w2 = 312;
px = 20; py = 30; pz = 25;
a = 20; b = 30; c = 25;
Ellipse = zeros(500,600,500);
% Create mesh of points to process
vx = (u1:u2) - px;
vy = (v1:v2) - py;
vz = (w1:w2) - pz;
[X,Y,Z] = meshgrid(vx, vy, vz);
% Compute R*x
V = [X(:)'; Y(:)'; Z(:)'];
V = R * V;
% Divide by ellipse axes
M = diag([1/a, 1/b, 1/c]);
V = M * V;
% Determine if norm criteria is met
index = norm(V') < 1;
Ellipse(X(index), Y(index), Z(index)) = 1;
Agree with #Dan, a smaller working example would make it easier to test.

If you are doing more than simple mathematical operations matrices can be tricky.
Here you can (should) reduce the size of Ellipse because you are not using most of its entries.
All you need is (101,123,190) and things will be much faster, especially the way you are accessing the matrix entries, remember MATLAB will eventually store the matrix as just an array.

#dpmcmlxxvi Thank you very much for the answer. At first, sorry for the large example. I used your answer with some modification as norm(XY) did not work for me.(smaller example and valueas adapted to run properly)
R = [1 2 3; 1 2 3; 1 2 3];
u1 = 50; u2 = 90; v1 = 20; v2 = 50; w1 = 30; w2 = 60;
px = 60; py = 25; pz = 50;
a = 10; b = 20; c = 15;
Ellipse = zeros(100,200,100);
% Create mesh of points to process
vx = (u1:u2) - px;
vy = (v1:v2) - py;
vz = (w1:w2) - pz;
[X,Y,Z] = meshgrid(vx, vy, vz);
% Compute R*x
V = [X(:)'; Y(:)'; Z(:)'];
V = R * V;
% Divide by ellipse axes
M = diag([1/a, 1/b, 1/c]);
V = M * V;
% Apply criteria
Vsq = V.*V;
crit = Vsq(1,:)+Vsq(2,:)+Vsq(3,:);
% Look for indices in the meshgrid fullfilling criteria
xe = X(find(crit<1));
ye = Y(find(crit<1));
ze = Z(find(crit<1));
xi = ceil(abs(xe+px));
yi = ceil(abs(ye+py));
zi = ceil(abs(ze+pz));
% Set values at correpsonding indices to 1
linind = sub2ind(size(Ellipse),xi,yi,zi);
Ellipse(linind) = 1;
It works fine and all for loops have been removed.

Related

I want to implement a while loop in python but I have this error

I'm trying to optimise a gradient descent of a function using a while loop but the loop doesn't stop. How can I make it works please.
def GradDescent(y, la, nbiter,tau,f,epsilon):
x = y;
crit= np.zeros(nbiter);
xprev = 0
iter = 0
while norm(x-xprev)/norm(x) > epsilon:
xprev = x
x = x - tau*(x - y + la * gradTVeps(x,epsilon))
crit[iter] = 1/2 * (norm(x-y)**2) + la * J(x,epsilon);
iter = 1
return x,crit
nbiter = 10;
epsilon = np.logspace(-5, 0,num=5);
laTVTeq = 0.01;
SNRTVep = 0*np.ones(len(epsilon));
for i in range(0,len(epsilon)):
tau = 1.8/(1 + laTVTeq *4/epsilon[i]);
[xdenoised,crit] = GradDescent( y,laTVTeq, nbiter,tau,f,epsilon[i])
SNRTVep[i] = snr(x0,xdenoised)

How to fix this error Index in position 2 exceeds array bounds in MATLAB?

I have a problem with this line of code bloop(rj,cj) = J1(i,j). I tried it a lot and changed the numbers, but the error remains.
The Error is Index in position 2 exceeds array bounds
bloop(rj,cj) = J1(i,j).
I hope someone has a solution to this problem.
clc
clear
close all
J = imread('logo.jpg'); %discolored image
J1 = im2double(J); %convert image to bouble precise
[r,c] = size(J1); %find size of image
rc = r*c; %151874
%find A inverse
x = [17;121;171];
xT = x';
xxT = x*xT;
inv = pinv(xxT); %find inverse for singular or badly scaled
y = [17;122;114];
yxT = y*xT;
Ainv = yxT*inv;
B = Ainv;
%find color correction
%reshape matrix to 3xn
i = 0;
j = 0;
bloop=zeros(3,50625);
for rj = 1:3 %row
i = i+1;
for cj = 1:50625 %cols
j = j+1;
bloop(rj,cj) = J1(i,j);
end
end
[w,t] = size(bloop);
bloop(:,:)
%I(r,c) = BJ(r,c)color correction equation
I = B*bloop;
Your j doesn't get reset to zero for each rj/i. Move the j = 0 inside the i loop.
clc
clear
close all
J = imread('logo.jpg'); %discolored image
J1 = im2double(J); %convert image to bouble precise
[r,c] = size(J1); %find size of image
rc = r*c; %151874
%find A inverse
x = [17;121;171];
xT = x';
xxT = x*xT;
inv = pinv(xxT); %find inverse for singular or badly scaled
y = [17;122;114];
yxT = y*xT;
Ainv = yxT*inv;
B = Ainv;
%find color correction
%reshape matrix to 3xn
i = 0;
bloop=zeros(3,50625);
for rj = 1:3 %row
i = i+1;
j = 0;
for cj = 1:50625 %cols
j = j + 1;
bloop(rj,cj) = J1(i,j);
end
end
[w,t] = size(bloop);
bloop(:,:)
%I(r,c) = BJ(r,c)color correction equation
I = B*bloop;

Ray Tracing calculation in C

I'm new to ray tracing and trying to program one in C. But My program keep on showing a dot (around 1-3 pixel) of the sphere in the wrong places and now I'm confused. This feels like a very stupid question, but I'm confused about exactly how big is 1 radius of a sphere? What I mean by that is if the radius is 1, the circle is 2 pixels?
I know all the calculations and I triple checked if I had any errors in my codes. but just incase, here is part of my codes:
Directions:
//size: 1024x768, view point (512 384 1), screen (0 0 0) to (1024 768 0)
ray[0] = x - start_x;
ray[1] = y - start_y;
ray[2] = 0 - start_z;
//normalize
double length;
length = (sqrt((ray[0]*ray[0]) + (ray[1]*ray[1]) + (ray[2]*ray[2])));
ray[0] = ray[0]/length;
ray[1] = ray[1]/length;
ray[2] = ray[2]/length;
Intersection:
temp = top; //my struct with sphere data, _x, _y, _z, _r, _red, _green, _blue
//x and y is the current pixel value
while (temp != NULL) {
x_diff = start_x - temp->_x + 0.0;
y_diff = start_y - temp->_y + 0.0;
z_diff = start_z - temp->_z + 0.0;
//a = 1 because my direction is a normalized
b = 2.0 * ((rayVector[0] * x_diff) + (rayVector[1] * y_diff) + (rayVector[2] * z_diff));
c = (x_diff * x_diff * 1.0) + (y_diff * y_diff) + (z_diff * z_diff) - (temp->_r * temp->_r);
check = (b * b) - (4.0 * c);
if (check < 0) { //0
pixels[width][height][0] = 0.0;
pixels[width][height][1] = 0.0;
pixels[width][height][2] = 0.0;
}
else if (check == 0) { //1
r1 = (b * -1.0) /2.0;
if (r1 < nearest_z) {
nearest_z = r1;
pixels[width][height][0] = temp->_red;
pixels[width][height][1] = temp->_green;
pixels[width][height][2] = temp->_blue;
}
}
else { //2
r1 = ((b * -1.0) + sqrt(check))/2.0;
r2 = ((b * -1.0) - sqrt(check))/2.0;
if ((r1 < r2) && (r1 < nearest_z)) {
nearest_z = r1;
pixels[width][height][0] = 255.0;
pixels[width][height][1] = 0;
pixels[width][height][2] = 0;
}
else if ((r2 < r1) && (r2 < nearest_z)) {
nearest_z = r2;
pixels[width][height][0] = temp->_red;
pixels[width][height][1] = temp->_green;
pixels[width][height][2] = temp->_blue;
}
}
temp = temp->next;
}
I haven't done any lightings yet since the flat colouring it doesn't work. I'm new to openGL so expect me to miss some common functions in the codes. Thanks in advance.
Edit:
I only have one sphere currently, but my output looks like: img1
I was expecting a bigger circle? Also, I had a printf for each intersection (if there is) and when I manually plot in a paper, it is a 4x5 pixel square. But there are 4 dots in the output.
Edit 2: I change the size of the sphere to: x = 512 y = 384 z = -21 r = 30, it gave me this:
img2
Again, I only have one sphere and there are 4 in the image. Also, there are holds between the lines?
If I change the z value to -20, now my output is all white (colour of sphere).
I use glDrawPixels(1024,768,GL_RGB,GL_FLOAT,pixels); to draw
I had a RBG output file, everything seems to be in the right place. but when I draw on the program, it is off.

How to display the true range of my parameters on a contour plot in MATLAB?

I want to display the values of a function Z = Z(x,y) in the range (x_min, x_max) and (y_min, y_max) using the contourf function in Matlab 2015a. Here is my code:
N = 20;
x_min = 20;
x_max = 40;
y_min = 40;
y_max = 80;
x = linspace(x_min, x_max, N);
y = linspace(y_min, y_max, N);
[X,Y] = meshgrid(y,x);
Z = X.*Y;
for i = 1:N
for j = 1:N
Z(i, j) = 10*i+j;
end
end
contourf(Z);
colorbar
And this is the plot I get:
How can I show the true range of x and y (20<=x=<40 and 40<=y=<80)?
A look at the fantastic MATLAB documentation reveals that you can supply three arguments to contourf, namely the X, Y, and Z values.
N = 20;
x_min = 20;
x_max = 40;
y_min = 40;
y_max = 80;
x = linspace(x_min, x_max, N);
y = linspace(y_min, y_max, N);
[X,Y] = meshgrid(y,x);
Z = X.*Y;
for i = 1:N
for j = 1:N
Z(i, j) = 10*i+j;
end
end
contourf(X,Y,Z);
colorbar
This will give you properly labelled tick marks:

PI control algorithm manually implemented in matlab

I'm trying to implement a simple script performing a PI control for a cruise control application, but I'm founding some problems with the integral part. Here is my code:
function [] = PI_cruisecontrol()
clc; close all;
t0 = 0; tfinal = 50; dt = 0.001; % time parameters
r = 10; % reference of 10 m/s
m = 1000; % mass
b = 50; % friction coeff. (depends on v)
yp = zeros(tfinal/dt,1); t = yp; % initialize speed and time array
Ki = 40; % integrarl constant
Kp = 800; % proportional constant
int = 0; % itinialize int error
% CONTROL LOOP (Forward-Euler integrator is used to solve the ODE)
for i=t0+2:tfinal/dt
err = r-yp(i-1); % update error
int = int+err; % integral term
u = (Kp*err)+(Ki*int*dt); % action of control
yp(i) = yp(i-1)+((-b*yp(i)/m) + (u/m))*dt; % solve ode for speed
t(i) = t(i)+dt*i; % log the time
end
% Results
figure(1)
plot(t,yp)
title ('Step Response')
xlabel('Time (seconds)')
ylabel('Amplitud')
axis([0 20 0 12])
hold on
reference = ones(tfinal/dt,1)*10;
plot(t,reference,':')
end
And this is how it should be, using predefinided matlab functions:
function [] = PI_cruisecontrol2()
m = 1000;
b = 50;
r = 10;
s = tf('s');
P_cruise = 1/(m*s + b);
Kp = 800;
Ki = 40;
C = pid(Kp,Ki);
T = feedback(C*P_cruise,1);
t = 0:0.1:20;
step(r*T,t)
axis([0 20 0 12])
end
What am I doing wrong in my code?
Thanks!
I managed to fix the problem, working with float variables instead of arrays. Moreover, I added the derivative term (although for this first order problem was not necessary)
Here I left the code:
function [] = aFortran_PI()
clc; close all;
r = 10; % reference of 10 m/s
m = 1000; % mass
b = 50; % friction coeff. (depends on v)
yp = 0; % init response
Kp = 800; % proportional constant
Ki = 40; % proportional constant
Kd = 0; % derivative term is not necessary in this problem
previous_error = 0;
integral = 0;
dt = 0.001;
% CONTROL LOOP
for i=1:20000
error = r-yp; % update error
integral = integral + error*dt; % integral term
derivative = (error-previous_error)/dt; % derivative term
u = Kp*error+Ki*integral+Kd*derivative; % action of control
yp = yp+(-b*yp/m + u/m)*dt % solve ode for velocity
end
end

Resources