Sparse Matrix as field in a Chapel object - sparse-matrix

Following up on this question I now have a class Graph that includes a sparse matrix. Defined like
class Graph {
var vdom: domain(2),
SD: sparse subdomain(vdom),
A: [SD] real;
proc init(A: []) {
this.vdom = {A.domain.dim(1), A.domain.dim(2)};
for ij in A.domain {
this.SD += ij;
}
}
producing the error
chingon-base-test.chpl:30: error: halt reached - Sparse domain/array index out of bounds: (1, 2) (expected to be within {1..0, 1..0}
It appears SD is not getting redefined. What is the correct pattern? In the previous post, we talked about dense arrays, this is for sparse.
I am calling it via
var nv: int = 8,
D: domain(2) = {1..nv, 1..nv},
SD: sparse subdomain(D),
A: [SD] real;
SD += (1,2); A[1,2] = 1;
SD += (1,3); A[1,3] = 1;
SD += (1,4); A[1,4] = 1;
SD += (2,4); A[2,4] = 1;
SD += (3,4); A[3,4] = 1;
SD += (4,5); A[4,5] = 1;
SD += (5,6); A[5,6] = 1;
SD += (6,7); A[6,7] = 1;
SD += (6,8); A[6,8] = 1;
SD += (7,8); A[7,8] = 1;
g = new Graph(A);
writeln(g.A);

You should set the value of the vdom field during Phase 1 of initialization rather than relying on setting it during the default phase (Phase 2). Phase 1 handles the initial value of all fields, so if you don't set vdom explicitly, it will be {1..0, 1..0} when we make the initial value of the SD and A fields, which is why you are getting that error message.
proc init(A: []) {
this.vdom = {A.domain.dim(1), A.domain.dim(2)};
this.complete(); // insert this line here
for ij in A.domain {
this.SD += ij;
}
}
Edit: with executing your sample call line and my fix, I get the following as output:
0.0 0.0 0.0
0.0
0.0
0.0
0.0
0.0 0.0
0.0

Related

FT of a nonlinear term using FFTW3 and q = 0

I am trying to apply an integration algorithm for PDEs called Exponential Time Differencing using C language and the library FFTW3. Without going too much into details, I need to calculate the FT of a nonlinear term which is the derivative of a function squared:
The way I do it is the following:
1) Define lattice size
int Nx = 500;
double dx = 0.2;
2) Calculate wavevectors
for ( i = 0; i < Nx/2+1; i++ ) {
qx[i] = 2.0*i*pi/(Nx*dx);
}
3) Execute FFTW3 plan to obtain FT of h from initial conditions (IC not shown in the code)
plan_forward = fftw_plan_dft_r2c_1d (Nx,dh,dhft,FFTW_ESTIMATE); //dh -> dhft
fftw_execute (plan_forward);
4) Calculate the FT of derivative of h
for ( i = 0; i < Nx/2+1; i++ ) {
// dxhft[i][0] are the real parts and dxhft[i][1] are the imaginary
dxhft[i][0] = -qx[i] * dhft[i][1]; // Re[FTdxh] = -q Im[FTh]
dxhft[i][1] = qx[i] * dhft[i][0]; // Im[FTdxh] = q Re[FTh]
}
5) Set the Nyquist element to 0 (as explained e.g. here)
dxhft[Nx/2][0] = 0.0;
dxhft[Nx/2][1] = 0.0;
6) Transform the derivative in real space using inverse Fourier Transform
plan_backward = fftw_plan_dft_c2r_1d (Nx,dxhft,dxh,FFTW_ESTIMATE); //dxhft -> dxh
fftw_execute (plan_backward);
7) Normalise the derivative by Nx and calculate the nonlinear term
for ( i = 0; i < Nx; i++ ) {
dxh[i] = dxh[i] / (double) (Nx);
Nonl[i] = dxh[i]*dxh[i];
}
8) Transform the nonlinear term
fftw_execute_dft_r2c (plan_forward,Nonl,Nonlft); // Nonl -> Nonlft
Ok. Now, I have reasons to believe that the FT of the nonlinear term for q=0, that is the elements Nonlft[0][0] and Nonlft[0][1], is wrong. But I don't understand what I am missing in the code. Can anyone give me some insight on the problem?

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.

Summation giving random wrong numbers

I'm trying to implement an easy backpropagation algorithm for an exam (I'm a beginner programmer).
I've got a set of arrays and I generate random weights to start the algorithm.
I implemented the activation function following the math formula:
formula
(where x index are for inputs and y index is for hidden neuron input)
My problem is that I get some summation results with very high exponential values that are incompatible with what I'd expect to be.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define INPUT_NEURONS 4
#define HIDDEN_NEURONS 7
#define OUTPUT_NEURONS 3
#define MAX_SAMPLES 150
#define LEARNING_RATE 0.1
#define RAND_WEIGHT ((double)rand()/(RAND_MAX+1))
double IHweight[INPUT_NEURONS][HIDDEN_NEURONS]; /* in->hid weight */
double HOweight[HIDDEN_NEURONS][OUTPUT_NEURONS]; /* hid->out weight */
//activation
double inputs[MAX_SAMPLES][INPUT_NEURONS];
double hidden[HIDDEN_NEURONS];
double target[MAX_SAMPLES][OUTPUT_NEURONS];
double actual[OUTPUT_NEURONS];
//errors
double errO[OUTPUT_NEURONS];
double errH[HIDDEN_NEURONS];
double Error = 0.0;
int sample = 0;
typedef struct {
double sepal_lenght;
double sepal_width;
double petal_lenght;
double petal_width;
double output[OUTPUT_NEURONS];
} IRIS;
IRIS samples[MAX_SAMPLES] = {
{ 5.1, 3.5, 1.4, 0.2, 0.0, 0.0, 1.0 },
{ 4.9, 3.0, 1.4, 0.2, 0.0, 0.0, 1.0 },
{ 4.7, 3.2, 1.3, 0.2, 0.0, 0.0, 1.0 },
{...},
};
double sigmoid(double val) {
return (1.0 / (1.0 + exp(-val)));
}
double dsigmoid(double val) {
return (val * (1.0 - val));
}
void assignRandomWeights() {
int hid, inp, out;
printf("Initializing weights...\n\n");
for (inp = 0; inp < INPUT_NEURONS; inp++) {
for (hid = 0; hid < HIDDEN_NEURONS; hid++) {
IHweight[inp][hid] = RAND_WEIGHT;
printf("Weights : input %d -> hidden %d: %f\n",
inp, hid, IHweight[inp][hid]);
}
}
for (hid = 0; hid < HIDDEN_NEURONS; hid++) {
for (out = 0; out < OUTPUT_NEURONS; out++) {
HOweight[hid][out] = RAND_WEIGHT;
printf("hidden %d -> output %d: %f\n",
hid, out, HOweight[hid][out]);
}
}
system("pause");
}
void activation() {
int hid, inp, out;
double sumH[HIDDEN_NEURONS] ;
double sumO[OUTPUT_NEURONS];
for (hid = 0; hid < HIDDEN_NEURONS; hid++) {
for (inp = 0; inp < INPUT_NEURONS; inp++) {
sumH[hid] += (inputs[sample][inp] * IHweight[inp][hid]);
printf("\n%d Input %d = %.1f Weight = %f sumH = %g",
sample, inp, inputs[sample][inp], IHweight[inp][hid], sumH[hid]);
}
hidden[hid] = sigmoid(sumH[hid]);
printf("\nHidden neuron %d activation = %f", hid, hidden[hid]);
}
for (out = 0; out < OUTPUT_NEURONS; out++) {
for (hid = 0; hid < HIDDEN_NEURONS; hid++) {
sumO[out] += (hidden[hid] * HOweight[hid][out]);
printf("\n%d Hidden %d = %f Weight = %f sumO = %g",
sample, hid, hidden[hid], HOweight[hid][out], sumO[out]);
}
actual[out] = sigmoid(sumO[out]);
printf("\nOutput neuron %d activation = %f", out, actual[out]);
}
}
main () {
srand(time(NULL));
assignRandomWeights();
for (int epoch = 0; epoch < 1; epoch++) {
for (int i = 0; i < 1; i++) {
sample = rand() % MAX_SAMPLES;
inputs[sample][0] = samples[sample].sepal_lenght;
inputs[sample][1] = samples[sample].sepal_width;
inputs[sample][2] = samples[sample].petal_lenght;
inputs[sample][3] = samples[sample].petal_width;
target[sample][0] = samples[sample].output[0];
target[sample][1] = samples[sample].output[1];
target[sample][2] = samples[sample].output[2];
activation();
}
}
}
I'm using a lot of printf() to check my results and i get
...
41 Input 0 = 4.5 Weight = 0.321014 sumH = 1.31886e+267
41 Input 1 = 2.3 Weight = 0.772369 sumH = 1.31886e+267
41 Input 2 = 1.3 Weight = 0.526123 sumH = 1.31886e+267
41 Input 3 = 0.3 Weight = 0.271881 sumH = 1.31886e+267
Hidden neuron 6 activation = 1.000000
...
41 Hidden 0 = 0.974952 Weight = 0.343445 sumO = 1.24176e+267
41 Hidden 1 = 0.917789 Weight = 0.288361 sumO = 1.24176e+267
41 Hidden 2 = 0.999188 Weight = 0.972168 sumO = 1.24176e+267
41 Hidden 3 = 0.989726 Weight = 0.082642 sumO = 1.24176e+267
41 Hidden 4 = 0.979063 Weight = 0.531799 sumO = 1.24176e+267
41 Hidden 5 = 0.972474 Weight = 0.552521 sumO = 1.24176e+267
41 Hidden 6 = 1.000000 Weight = 0.707153 sumO = 1.24176e+267
Output neuron 1 activation = 1.000000
The assignRandomweights() and sigmoid() functions are ok as far as i can tell, the problem is in activation().
Please help me understand why this happens and how to solve it.
Your problem is in these lines
double sumH[HIDDEN_NEURONS];
double sumO[OUTPUT_NEURONS];
You don't initialise them before use. Technically the program behaviour is undefined. Your friendly compiler appears to be setting uninitialised variables to large values. (Other platforms such as Itanium will trap a "Not a Thing").
A simple remedy is to use double sumH[HIDDEN_NEURONS] = {0}; etc. which will set every element to zero.
check this line:
double sumH[HIDDEN_NEURONS] ;
and this line:
sumH[hid] += (inputs[sample][inp] * IHweight[inp][hid]);
you have declared the sumH[] without setting to zero every member of it, so, it starts from an arbitrary value as there is no definition of sumH[hid]
you can use:
for(unsigned int i=0; i<HIDDEN_NEURONS; i++) sumH[i] = 0;
before any use of it (if you don't like malloc() or ZeroMemory()), for example...

Grainy looking sphere in my ray tracer

I am trying to write a simple ray tracer. The final image should like this: I have read stuff about it and below is what I am doing:
create an empty image (to fill each pixel, via ray tracing)
for each pixel [for each row, each column]
create the equation of the ray emanating from our pixel
trace() ray:
if ray intersects SPHERE
compute local shading (including shadow determination)
return color;
Now, the scene data is like: It sets a gray sphere of radius 1 at (0,0,-3). It sets a white light source at the origin.
2
amb: 0.3 0.3 0.3
sphere
pos: 0.0 0.0 -3.0
rad: 1
dif: 0.3 0.3 0.3
spe: 0.5 0.5 0.5
shi: 1
light
pos: 0 0 0
col: 1 1 1
Mine looks very weird :
//check ray intersection with the sphere
boolean intersectsWithSphere(struct point rayPosition, struct point rayDirection, Sphere sp,float* t){
//float a = (rayDirection.x * rayDirection.x) + (rayDirection.y * rayDirection.y) +(rayDirection.z * rayDirection.z);
// value for a is 1 since rayDirection vector is normalized
double radius = sp.radius;
double xc = sp.position[0];
double yc =sp.position[1];
double zc =sp.position[2];
double xo = rayPosition.x;
double yo = rayPosition.y;
double zo = rayPosition.z;
double xd = rayDirection.x;
double yd = rayDirection.y;
double zd = rayDirection.z;
double b = 2 * ((xd*(xo-xc))+(yd*(yo-yc))+(zd*(zo-zc)));
double c = (xo-xc)*(xo-xc) + (yo-yc)*(yo-yc) + (zo-zc)*(zo-zc) - (radius * radius);
float D = b*b + (-4.0f)*c;
//ray does not intersect the sphere
if(D < 0 ){
return false;
}
D = sqrt(D);
float t0 = (-b - D)/2 ;
float t1 = (-b + D)/2;
//printf("D=%f",D);
//printf(" t0=%f",t0);
//printf(" t1=%f\n",t1);
if((t0 > 0) && (t1 > 0)){
*t = min(t0,t1);
return true;
}
else {
*t = 0;
return false;
}
}
Below is the trace() function:
unsigned char* trace(struct point rayPosition, struct point rayDirection, Sphere * totalspheres) {
struct point tempRayPosition = rayPosition;
struct point tempRayDirection = rayDirection;
float f=0;
float tnear = INFINITY;
boolean sphereIntersectionFound = false;
int sphereIndex = -1;
for(int i=0; i < num_spheres ; i++){
float t = INFINITY;
if(intersectsWithSphere(tempRayPosition,tempRayDirection,totalspheres[i],&t)){
if(t < tnear){
tnear = t;
sphereIntersectionFound = true;
sphereIndex = i;
}
}
}
if(sphereIndex < 0){
//printf("No interesection found\n");
mycolor[0] = 1;
mycolor[1] = 1;
mycolor[2] = 1;
return mycolor;
}
else {
Sphere sp = totalspheres[sphereIndex];
//intersection point
hitPoint[0].x = tempRayPosition.x + tempRayDirection.x * tnear;
hitPoint[0].y = tempRayPosition.y + tempRayDirection.y * tnear;
hitPoint[0].z = tempRayPosition.z + tempRayDirection.z * tnear;
//normal at the intersection point
normalAtHitPoint[0].x = (hitPoint[0].x - totalspheres[sphereIndex].position[0])/ totalspheres[sphereIndex].radius;
normalAtHitPoint[0].y = (hitPoint[0].y - totalspheres[sphereIndex].position[1])/ totalspheres[sphereIndex].radius;
normalAtHitPoint[0].z = (hitPoint[0].z - totalspheres[sphereIndex].position[2])/ totalspheres[sphereIndex].radius;
normalizedNormalAtHitPoint[0] = normalize(normalAtHitPoint[0]);
for(int j=0; j < num_lights ; j++) {
for(int k=0; k < num_spheres ; k++){
shadowRay[0].x = lights[j].position[0] - hitPoint[0].x;
shadowRay[0].y = lights[j].position[1] - hitPoint[0].y;
shadowRay[0].z = lights[j].position[2] - hitPoint[0].z;
normalizedShadowRay[0] = normalize(shadowRay[0]);
//R = 2 * ( N dot L) * N - L
reflectionRay[0].x = - 2 * dot(normalizedShadowRay[0],normalizedNormalAtHitPoint[0]) * normalizedNormalAtHitPoint[0].x +normalizedShadowRay[0].x;
reflectionRay[0].y = - 2 * dot(normalizedShadowRay[0],normalizedNormalAtHitPoint[0]) * normalizedNormalAtHitPoint[0].y +normalizedShadowRay[0].y;
reflectionRay[0].z = - 2 * dot(normalizedShadowRay[0],normalizedNormalAtHitPoint[0]) * normalizedNormalAtHitPoint[0].z +normalizedShadowRay[0].z;
normalizeReflectionRay[0] = normalize(reflectionRay[0]);
struct point temp;
temp.x = hitPoint[0].x + (shadowRay[0].x * 0.0001 );
temp.y = hitPoint[0].y + (shadowRay[0].y * 0.0001);
temp.z = hitPoint[0].z + (shadowRay[0].z * 0.0001);
struct point ntemp = normalize(temp);
float f=0;
struct point tempHitPoint;
tempHitPoint.x = hitPoint[0].x + 0.001;
tempHitPoint.y = hitPoint[0].y + 0.001;
tempHitPoint.z = hitPoint[0].z + 0.001;
if(intersectsWithSphere(hitPoint[0],ntemp,totalspheres[k],&f)){
// if(intersectsWithSphere(tempHitPoint,ntemp,totalspheres[k],&f)){
printf("In shadow\n");
float r = lights[j].color[0];
float g = lights[j].color[1];
float b = lights[j].color[2];
mycolor[0] = ambient_light[0] + r;
mycolor[1] = ambient_light[1] + g;
mycolor[2] = ambient_light[2] + b;
return mycolor;
} else {
// point is not is shadow , use Phong shading to determine the color of the point.
//I = lightColor * (kd * (L dot N) + ks * (R dot V) ^ sh)
//(for each color channel separately; note that if L dot N < 0, you should clamp L dot N to zero; same for R dot V)
float x = dot(normalizedShadowRay[0],normalizedNormalAtHitPoint[0]);
if(x < 0)
x = 0;
V[0].x = - rayDirection.x;
V[0].x = - rayDirection.y;
V[0].x = - rayDirection.z;
normalizedV[0] = normalize(V[0]);
float y = dot(normalizeReflectionRay[0],normalizedV[0]);
if(y < 0)
y = 0;
float ar = totalspheres[sphereIndex].color_diffuse[0] * x;
float br = totalspheres[sphereIndex].color_specular[0] * pow(y,totalspheres[sphereIndex].shininess);
float r = lights[j].color[0] * (ar+br);
//----------------------------------------------------------------------------------
float bg = totalspheres[sphereIndex].color_specular[1] * pow(y,totalspheres[sphereIndex].shininess);
float ag = totalspheres[sphereIndex].color_diffuse[1] * x;
float g = lights[j].color[1] * (ag+bg);
//----------------------------------------------------------------------------------
float bb = totalspheres[sphereIndex].color_specular[2] * pow(y,totalspheres[sphereIndex].shininess);
float ab = totalspheres[sphereIndex].color_diffuse[2] * x;
float b = lights[j].color[2] * (ab+bb);
mycolor[0] = r + ambient_light[0];
mycolor[1] = g + ambient_light[1];
mycolor[2] = b+ ambient_light[2];
return mycolor;
}
}
}
}
}
The code calling trace() looks like :
void draw_scene()
{
//Aspect Ratio
double a = WIDTH / HEIGHT;
double angel = tan(M_PI * 0.5 * fov/ 180);
ray[0].x = 0.0;
ray[0].y = 0.0;
ray[0].z = 0.0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
unsigned int x,y;
float sx, sy;
for(x=0;x < WIDTH;x++)
{
glPointSize(2.0);
glBegin(GL_POINTS);
for(y=0;y < HEIGHT;y++)
{
sx = (((x + 0.5) / WIDTH) * 2.0 ) - 1;
sy = (((y + 0.5) / HEIGHT) * 2.0 ) - 1;;
sx = sx * angel * a;
sy = sy * angel;
//set ray direction
ray[1].x = sx;
ray[1].y = sy;
ray[1].z = -1;
normalizedRayDirection[0] = normalize(ray[1]);
unsigned char* color = trace(ray[0],normalizedRayDirection[0],spheres);
unsigned char x1 = color[0] * 255;
unsigned char y1 = color[1] * 255;
unsigned char z1 = color[2] * 255;
plot_pixel(x,y,x1 %256,y1%256,z1%256);
}
glEnd();
glFlush();
}
}
There could be many, many problems with the code/understanding.
I haven't taken the time to understand all your code, and I'm definitely not a graphics expert, but I believe the problem you have is called "surface acne". In this case it's probably happening because your shadow rays are intersecting with the object itself. What I did in my code to fix this is add epsilon * hitPoint.normal to the shadow ray origin. This effectively moves the ray away from your object a bit, so they don't intersect.
The value I'm using for epsilon is the square root of 1.19209290 * 10^-7, as that is the square root of a constant called EPSILON that is defined in the particular language I'm using.
What possible reason do you have for doing this (in the non-shadow branch of trace (...)):
V[0].x = - rayDirection.x;
V[0].x = - rayDirection.y;
V[0].x = - rayDirection.z;
You might as well comment out the first two computations since you write the results of each to the same component. I think you probably meant to do this instead:
V[0].x = - rayDirection.x;
V[0].y = - rayDirection.y;
V[0].z = - rayDirection.z;
That said, you should also avoid using GL_POINT primitives to cover a 2x2 pixel quad. Point primitives are not guaranteed to be square, and OpenGL implementations are not required to support any size other than 1.0. In practice, most support 1.0 - ~64.0 but glDrawPixels (...) is a much better way of writing 2x2 pixels, since it skips primitive assembly and the above mentioned limitations. You are using immediate mode in this example anyway, so glRasterPos (...) and glDrawPixels (...) are still a valid approach.
It seems you are implementing the formula here, but you deviate at the end from the direction the article takes.
First the article warns that D & b can be very close in value, so that -b + D gets you a very limited number. They suggest an alternative.
Also, you are testing that both t0 & t1 > 0. This doesn't have to be true for you to hit the sphere, you could be inside of it (though you obviously should not be in your test scene).
Finally, I would add a test at the beginning to confirm that the direction vector is normalized. I've messed that up more than once in my renderers.

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