PullMonkey Blog

05 Feb

ECE231 - Spring 2009 - Programming Assignment 1


This is a step-by-step tutorial for this assignment and an explanation of the basics of how it works for those that are having a difficult time understanding or just are stuck somewhere. To view the assignment click here.

Part A

1. Create a structure (called point) that includes a time and y value (both doubles).

This is very simple using the typedef struct and listing your variables.

1
2
3
4
5
6
7

typedef struct
{
  double time;
  double y;
} point;

2. Create a main program that has an array of 40 points (or structures), keeps track of the number of values in the array and has variables for each of the values needed to calculate above.

In the main program we will need an array of points p, an integer with the total number of points values, and 4 double variables, one for each of the functions (I used vert_shift, amp, freq, and phase_shift).

Then you will need to call each function and for testing I printed each value out to make sure everything was coming in right. It is short, simple, and to the point like all programming should be. Your main should look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

int main()
{
  point p[40];          // array of points
  int values = 0;       // total number of values in the points array
  double vert_shift=0;  // vertical shift
  double amp=0;         // amplitude
  double freq=0;        // frequency
  double phase_shift=0; // phase shift

  values = read_data(p);
  cout << "Values: " << endl;
  for(lcv=0; lcv < values; lcv++)
    cout << "  " <<  p[lcv].time << "  " << p[lcv].y << endl;
  cout << "nTotal Number of values = " << values << endl;
  vert_shift = vertical(p, values);
  cout << "nVertical shift = " << vert_shift << endl;
  amp = amplitude(p, values);
  cout << "nAmplitude = " << amp << endl;
  freq = frequency(p, values);
  cout << "nFrequency = " << freq << endl;
  phase_shift = pshift(p, values);
  cout << "nPhase Shift = " << phase_shift << endl;
  return 0;
}

3. The main program should then call the read_data function. This function will have one argument (the array of points - or structures - which will be passed as a pointer to the function) and will return the number of values in the array. It should read the data from the data file using a pointer and the arrow (->) operator.

First, we are going to be reading from a file in this function so we are going to need to include the fstream library.

1
2
3

#inlcude <fstream> // reading from file

Next, we need to create the prototype for this function called read_data. This will go above the main. The read_data function will need the array of points and will return the total number of points as an integer. So it should look like this:

1
2
3

int read_data(point *);

Now below the main we can create our function and lets call the array of points a. In this function we will need 2 more variables, an integer (total) for counting the number of points that we read from the file and an ifstream variable (f) for opening and closing the file.

First, we need to try to open the file using f.open("sp09prog1.txt"). Next, we need to test to make sure the file was opened and that we can read from it and if not then print out error message and exit. If the file was opened then we need to read in the values into the point array and count the number of points using the total integer variable. We do this until we read the end of the file and we find out if we are at the end of the file with f.eof(). Finally, we will want to return the total. It should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

int read_data(point *a)
{
  ifstream f;  // file streaming variable
  int total=0; // counts the total number of points in file

  f.open("sp09prog1.txt");

  if(f.fail())
  {
    cout << "ERROR: File could not be opened" << endl;
    exit(1);
  }

  while(!f.eof())
  {
    f >> a->time >> a->y;
    total++;
    a++;
  }
  return total - 1;
}

Notice that we return total - 1. This is because we increment total and then we find out it is the end of the file. So we incremented one too many times so we need to subtract 1 before returning it.

4. Main should then call the vertical function to calculate the vertical shift. This function has two arguments (the array of points - passed as a pointer - and the number of values in the array). It will calculate the vertical shift by finding the average of the maximum and minimum y-values. You will need to search through the array of points to find these max and min values.
5. Next, main will call the amplitude function to calculate the amplitude. This function has two arguments (the array of points - passed as a pointer - and the number of values in the array; you must also use the arrow operator in this function) and will return the amplitude. To find the amplitude, you need to calculate half the difference between the maximum and minimum values of the y-values (you will need to search through the array for the maximum and minimum values again).

The functions are both almost identical. The only difference is the equation at the end so we will do them at the same time.

First, we will create the prototypes. Both functions take the array of points and the integer total number of points and they both return a double. So the prototypes should look like this:

1
2
3
4

double vertical(point *, int );
double amplitude(point *, int );

So lets call the point array p and the integer total.

To find the max and min values we need to create 2 double variables (max and min) and an integer (lcv) that we will use for the loop.

Next we will need to set both max and min to the first y element in the array of points. Then we will have a loop and start from 0 to total. Each time we run through this loop we need to do 3 things:

  • 1. Test if max is less than the current y value? If yes then set max to the current y
  • 2. Test if min is greater than the current y value? If yes then set min to the current y
  • 3. Increment a to the next position in the array. Because we are using a pointer to the array we can do this easily by doing a++

Next we will just return the result of the equation as a double. So your functions should look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

double vertical(point *a, int total)
{   
  double min; // minimum y value found in array
  double max; // maximum y value found in array
  int lcv;    // loop control variable
  max = min = a->y;
  for(lcv=0; lcv < total; lcv++) 
  {
    if(max < a->y)
      max = a->y;
    if(min > a->y)
      min = a->y;
    a++;
  }
  return (max + min) / 2.0;
}
double amplitude(point *a, int total)
{
  double min; // minimum y value found in array
  double max; // maximum y value found in array
  int lcv;    // loop control variable
  max = min = a->y;
  for(lcv=0; lcv < total; lcv++)
  {
    if(max < a->y)
      max = a->y;
    if(min > a->y)
      min = a->y;
    a++;
  }
  return (max - min) / 2.0;
}

6. The next function called by main is the frequency function that has two arguments (the array of points - passed as a pointer - and the number of values in the array; again using the arrow operator to access values) and will return the frequency. To calculate the frequency, find the period which is time difference between the maximum and minimum y-values and multiply by 2. Then, divide to calculate the frequency. Please note that you are using the difference between time values, not the y values, to perform the overall computation.
7. Finally, main will call the pshift function that contains two arguments (the array of points - passed as a pointer - and the number of values in the array; again using the arrow operator to access values) and will return the phase shift or horizontal shift. This shift can be found by finding the average of the time values where the maximum and minimum y-values occur; then subtracting it from half the period (see step 6 to find the period).

The functions for steps 6 and 7 are both almost identical expect for the equation at the end so we will do these both at the same time.

For the frequency function we will need to use the absolute value function in the cmath library. To include this you will need to do this at the top of your file.

1
2
3

#include <cmath>

Like the functions in step 4 and 5 they need to have the array of points and the integer total number of points and they both return a double. So the prototypes should look like this:

1
2
3
4

double frequency(point *, int );
double pshift(point *, int );

So lets call the point array p and the integer total.

To find the max and min values we need to create 2 pointers to point variables (max and min) and an integer (lcv) that we will use for the loop.

Next we will need to set both max and min pointers to the same address as a points which is the first position in the array of points. Then we will have a loop and start from 0 to total. Each time we run through this loop we need to do 3 things:

  • 1. Test if max->y is less than the current a->y value? If yes then set max to the current a address.
  • 2. Test if min->y is greater than the current a->y value? If yes then set min to the current a address.
  • 3. Increment a to the next position in the array. Because we are using a pointer to the array we can do this easily by doing a++

Next we will just return the result of the equation as a double. So your functions should look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

double frequency(point *a, int total)
{
  point *min; // minimum y value location found in array
  point *max; // maximum y value location found in array
  int lcv;    // loop control variable
  max = min = a;
  for(lcv=0; lcv < total; lcv++)
  {
    if(max->y < a->y)
      max = a;
    if(min->y > a->y)
      min = a;
    a++;
  } 
  return abs(PI / (max->time - min->time));
} 
double pshift(point *a, int total)
{
  point *min; // minimum y value location found in array
  point *max; // maximum y value location found in array
  int lcv;    // loop control variable
  max = min = a;
  for(lcv=0; lcv < total; lcv++)
  {
    if(max->y < a->y)
      max = a;
    if(min->y > a->y)
      min = a;
    a++;
  }
  a -= total;
  return (2 * PI / frequency(a, total)) / 2 - (max->time + min->time) / 2.0;
}

Notice how in the pshift function after the loop we do a -= total. This is because a is currently pointing the last element in the array and if we want to call frequency and pass the address of the first element in the array of points then we need to set a back to the first element.

Also notice that the frequency function uses a variable called PI. This is the value of pi so at the top above the main you will need to define it as a constant. You can do this one of 2 ways:

1
2
3
4
5

#define PI 3.14159
or 
const double PI=3.14159;

Either way will work but I prefer to use the #define since it uses less memory and only takes more processing when you compile the program not in running it.

Outcome

Using the text file provided this is what I got when I ran the program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46

[scnaegle@egor ece231]$ ./a.out 
Values: 
  1.5708  -4
  1.6791  -3.3551
  1.7875  -2.7403
  1.8958  -2.1845
  2.0041  -1.7135
  2.1125  -1.3495
  2.2208  -1.1094
  2.3291  -1.0044
  2.4374  -1.0395
  2.5458  -1.2131
  2.6541  -1.5169
  2.7624  -1.9369
  2.8708  -2.4533
  2.9791  -3.0421
  3.0874  -3.6756
  3.1958  -4.3244
  3.3041  -4.9579
  3.4124  -5.5467
  3.5208  -6.0631
  3.6291  -6.4831
  3.7374  -6.7869


  3.8457  -6.9605
  3.9541  -6.9956
  4.0624  -6.8906
  4.1707  -6.6505
  4.2791  -6.2865
  4.3874  -5.8155
  4.4957  -5.2597
  4.6041  -4.6449
  4.7124  -4

Total Number of values = 30

Vertical shift = -4

Amplitude = 2.9956

Frequency = 1.93329

Phase Shift = -1.5166

Part B

Using MATLAB, you need to plot the original data using the data file sp09prog1.txt. To do this, load the file into MATLAB, then assign the first column to be the x values and the second column to be the y values. You can then use the plot command to plot these (you should only plot the points - not any connecting lines).

This is easy. Use the load() function to read in data from the file into a matrix.

1
2
3

table = load('sp09prog1.txt')

Then we need to get the data into arrays of time and y. To do this use matrixvairable(row,column). Use a colon (:) to get everything in either the row or column. In this case we will want all rows in the first column for time and all rows and second column for y.

1
2
3
4

time = table(: , 1)
y = table(: , 2)

Then plot the data using the plot() function. For this you will need to pass 3 things (x values, y values, and symbol). Our x values is the array time and our y values is array y.

1
2
3

plot(time, y, 'o')

Then, using the values you found in the C++ program for each of the four variables, create a cosine curve that can be plotted over the data. You will need to create a matrix of x-values that run from 1 to 2π with an increment of π/100. Then, create a matrix of y values using the cosine equation: where vs is the vertical shift, ps is the phase shift, amp is the amplitude and freq is the frequency. Plot these x and y values using a red line.

This is just the same as the first part only we need to find the x and y values using equations. But first lets set all the values we will need for our calculations which we can get from Part A of the program.

1
2
3
4
5
6
7

vs = -4
amp = 2.9956
freq = 1.93329
ps = -1.5166
PI = 3.14159

Next we will have to create the array x with all the x values. In this case we are going to go from 0 to 2pi and step by pi/100. To do this we have a colon (:) between each argument like this:

1
2
3

x = 0 : PI / 100 : 2 * PI

Now, to create the array y with all the y values we use the equation we were given.

1
2
3

y = vs + amp * (cos(freq * x - ps))

Now, all we need to do is plot it on the graph. However, we want to plot the new equation on the same plot as the last one. To do this we need to use the command hold on. We also want the new graph to look different so lets make it a full line 4px wide and the color be dark red. Like this:

1
2
3
4

hold on
plot(x, y, '', 'LineWidth', 4, 'Color', [.6 0 0])

Now run it and see if your two line match up at all.


Sorry, comments for this entry are closed at this time.