Array data loss after return from function

Pages: 12
@TheIdeasMan
Perhaps I am reading this wrong:
With the invariants & math formulae, it seems to me that a formula needs to go in a class rather than a public struct, because one can't change 1 variable by it self without invalidating all the rest, so the member functions should be responsible for maintaining the object in a valid state at all times.


In this case, the purpose is to allow the user to change Vci, Vr, Vco, Pr, area, and possibly Vavg in order to witness the effects their change have on the Weibull PDF distribution and power performance curve. Changing these variables does not invalidate anything, it just allows for data output variation. However, I still have to implement a GUI of some sort. I just figured I would validate the calculations and code structure before taking it to that step. I have a feeling I will have to experiment with Qt some more before I can produce an efficient GUI. For right now, I'm exporting the data to a text file and graphing it with Excel. That being said, it would be nice to interface the program with Excel, but that is yet another complicated matter.

As far as the conditions: (pertaining to wind turbines)
Vci = the wind velocity which produces usable power (cut-in)
Vr = the wind velocity which yields the rated generator power (Pr)
Vco = the maximum wind velocity which produces usable power (cut-out). Usually a limitation set by design engineers due to structural and safety limitations.

Vavg = mean wind velocity from a sample of experimental wind velocities

CF = Capacity factor for the wind turbine (probability of output)

PDF = Probability Distribution Function (probability of wind velocities using the sample of experimental wind velocities)

In order to product CF, gamma and incomplete gamma functions are used. Probability is determined using a Weibull PDF.

The data, currently, is arbitrary and used for experimentation to show the effect of changing variables on the CF and power performance curve.

I hope that helps :).

@everyone
I'm still honing out the code and will post it as soon as I have finished the next revision.
Here is the latest revision. Please feel free to offer more suggestions. Thanks again for everyone's input.

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
// File:		WindTurbineMain.cpp
// Modified:	10/10/2013

#define _USE_MATH_DEFINES
#include <cmath>
#include <iostream>
#include <fstream>
#include "parameters.h"
#include "functions.h"

using namespace std;

int main()
{
	parameters param;

	/* Define values for variables here or leave commented to use default
	param.vci = 0;
	param.vr = 7.0;
	param.vco = 20.0;
	param.vavg = 7.0;
	param.area = 10.869;
	param.airD = 1.2;
	param.pr = 2.1;
	param.inc = 0.5;

	param.k = 2.0;
	param.c = 2 * param.vavg / sqrt(M_PI);
	param.a = 3.0 / param.k + 1.0;
	*/

	param.populate();
	
	output(param);
}


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
// File:		parameters.h
// Modified:	10/10/2013

#ifndef parameters_H
#define parameters_H

class parameters
{
public:
	parameters();
	~parameters();

	int arrSize;
	double k;			// Weibull PDF shape parameter
	double c;			// Weibull PDF scale parameter
	double a;			// Gamma function complex variable
	double vci;			// Cut-in velocity
	double vr;			// Rated velocity
	double vco;			// Cut-out velocity
	double vavg;		// Average velocity
	double area;		// Turbine blade area
	double airD;		// Air density
	double pr;			// Rated power
	double inc;			// Velocity iteration increment
	double CapFactor;	// Capacity factor
	double pavg;		// Average power

	double *dataV;		// Pointer to velocity data array
	double *dataPDF;	// Pointer to Weibull PDF data array
	double *dataPower;	// Pointer to power output data array

	void populate();
	
private:
	void arrCreate();		
	double pGen(double V);
	double fV(double V);
	double CF();
	double incGamma(double a, double x);
};

#endif 


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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// File:		parameters.cpp
// Modified:	10/10/2013

#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif

#include "parameters.h"
#include <iostream>
#include <iomanip>
#include <cmath>

// Class parameters constructor
// Variable initiated to arbitrary numbers
parameters::parameters() : dataV(nullptr), dataPDF(nullptr), dataPower(nullptr)
	{
		vci = 0;					// Cut-in velocity in m/s
		vr = 7.0;					// Rated velocity in m/s
		vco = 20.0;					// Cut-out velocity in m/s
		vavg = 7.0;					// Average velocity in m/s
		area = 10.869;				// Turbine blade area in m^2
		airD = 1.2;					// Air density in kg/m^3
		pr = 2.1;					// Rated power in kW
		inc = 0.5;					// Velocity iteration increment
		CapFactor = 0;				// Capacity factor 
		pavg = 0;					// Average power in kW
		arrSize = 0;				// Initialize data array size
		k = 2.0;					// Weibull PDF shape parameter
		c = 0;						// Weibull PDF scale parameter
		a = 0;						// Gamma function complex variable (aka "z")
	}

// Create and populate data arrays for Velicity, PDF, and Power
void parameters::populate()
{
	// Create data arrays
	arrCreate();
	
	// Define Weibull PDF scale parameter
	c = 2 * vavg / sqrt(M_PI);
	// Define gamma function complex variable
	a = 3.0 / k + 1.0;
	
	int index = 0;

	for (double V = 0; V <= vco; V += inc)
	{
		
		if (index > arrSize)
		{
			std::cout << "Array overflow" << std::endl;
			break;
		}
		// Power output is 0 for wind velicity less than cut-in velocity
		else if (V < vci)
		{
			dataPower[index] = 0;
		}
		// Write power output value to data array
		else
		{
			dataPower[index] = pGen(V);
		}
		// Write velocity data to data array
		dataV[index] = V;
		// Write probability to data array
		dataPDF[index] = fV(V);
		index++;
	}
}

// Create data arrays to store final calcualtion results
void parameters::arrCreate()
	{
		arrSize = vco / inc + 1;
		dataV = new double[arrSize];
		dataPower = new double[arrSize];
		dataPDF = new double[arrSize];
	}

// Function for producting the probability of each velocity magnitude
double parameters::fV(double V)
{
	return k / c * pow(V / c, k - 1.0) * exp( - pow(V / c, k) );
}

// Function for calculating the capacity factor
double parameters::CF()
{
	return pow(vr, -3.0) * incGamma(a, vr) - incGamma(a, vci) + exp( - pow(vco / c, k) ) - exp( - pow(vr / c, k) );
}

// Function for approximating the result of the incomplete gamma function
// Used for integral approximation
double parameters::incGamma(double a, double x) // Consider using recursion
{
	double gammaSum = 0;
	for(int n = 0; n <= 100; n++)
	{
		double denom = 1;
		for(int nInc = 0; nInc <= n; nInc++)
		{
			denom *= (a + nInc);
		}

		gammaSum += ( pow(x, n) / denom );
	}

	return gammaSum * pow(x, a) * exp(-x);
}

// Function for calculating power output
double parameters::pGen(double V)
{
	return pr * pow(V, 3) / pow(vr, 3);
}

// Class parameters destructor
parameters::~parameters()
	{
		delete [] dataV;
		delete [] dataPower;
		delete [] dataPDF;
	}


1
2
3
4
5
6
7
8
9
// File :		functions.h
// Modified:	10/10/2013

#ifndef FUNCTIONS_H
#define FUNCTIONS_H

void output(parameters &param);

#endif 


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
47
48
// File:		functions.cpp
// Modified:	10/10/2013

#include "parameters.h"
#include "functions.h"
#include <iostream>
#include <fstream>

using namespace std;

void output(parameters &param)
{
	cout << "Index\tVelocity\tProbability\tPower\n";
	for (int i = 0; i <= param.arrSize; i++)
	{
		cout << i << '\t';
		cout << fixed << param.dataV[i] << '\t';
		cout << fixed << param.dataPDF[i] << '\t';
		cout << fixed << param.dataPower[i] << endl;
	}

	cout << "Press enter to continue...";
	cin.get();

	ofstream data;
	data.open("Program Data.txt");
	if (data.is_open())
	{
		cout << "Writing to file...";
		data << __DATE__ << ", " << __TIME__ << "\n\n";
		data << "Index\tVelocity\tProbability\tPower\n";
		for (int i = 0; i < param.arrSize; i++)
		{
			data << i << '\t';
			data << fixed << param.dataV[i] << '\t';
			data << fixed << param.dataPDF[i] << '\t';
			data << fixed << param.dataPower[i] << endl;
		}

		data << endl << "End of file...";
	}
	else
	{
		cout << "Could not open file.";
		cin.get();
	}
	data.close();
}
Last edited on
@fatirishman53

I will have to see if I have any time to re-write your code, but the main things I would be looking at are:

Don't have public data members.

With, the initialiser list in your constructors, use it to initialise all the data members, not just some of them. You can have default values in the declaration of a constructor by assigning values in the parameter list, which means that the member variable is initialised to that value when that argument is not supplied.

Variable names, even though they are commented, I would still be tempted to name them like VelocityCutIn rather than vci for example. But that might be debatable.

Move the data storage arrays out of the class - even if it is only to main(). Change them to vectors - which use new internally, thus avoid memory management issues.

Don't use doubles in for loop conditions. They are not exact and might cause the loop to more or less times than you might expect. It is easy to calculate how many times a loop has to run: (EndValue - StartValue) / IncrementValue

Avoid using <= in an end condition, this runs 101 times: for (int a = 0; a <= 100; ++a) {} And can cause over runs in whatever container you use. The loop ends when the end condition becomes false.

Don't use magic numbers in your code (like 100 above), use const variables instead:

1
2
const int SIZE = 100;
for (int a = 0; a < SIZE; ++a) {}


With the functions.cpp file, it deals with member data, but is complicated by the fact that your data container (or Collection) is also in the class. I would have a member function that takes an output file as an argument, and just prints out the data for the 1 object. Put the for loop that goes through the container of all the objects (the Collection) in the same place as the Collection, and access your output function from there. Whether that be in main() or in another class is up to you.

The other way is to have an interface that gets the data from your object, and use them to print out the data, but I am not a fan of creating an interface for the sake of having external functions. That might create more debate, but there you go.

It is good that you have put comments describing your functions, now just need some to describe what the purpose of the class is. Include a link to a wiki page or some other descriptive document in the comments

Finally, but perhaps more importantly, there is the issue of validating your input data. What are the valid ranges for input? Do some have to be positive? What are the max & min values? Are there any other constraints or values that might lead to problems? What is an acceptable precision - does it matter if two values are close together? Are there any that can't be zero (or very close to)? These things are sometimes called preconditions. This validation could take place in a constructor, maybe via the constructor calling a private validation function. But IMO this might be better done before you create the object, so as to not create an invalid object. An advanced topic is the idea that constructors should provide some sort of no throw guarantee.

Hope this helps. :+)

EDIT: I forgot to mention namespaces - put all your stuff in it's own namespace, and don't have using namespace std;

And const for class functions and arguments / parameters wherever & whenever possible.
Last edited on
Please forgive me if my understanding is not up to par:

WRT data members:
What data members did I not initialize? The variables need to be public so that the user can change their values. Perhaps create local variables in main() and send them to a member function to set member values?

WRT variable names:
I understand your point, but they are what they are to coincide with the variable names used in my resource materials.

WRT vector use:
I haven't used vectors much and was toying with their usage last night. It would be nice to not have to worry about the size of the array.

WRT condition statements:
How are these different, other than being able to determine the value of "a" just by looking at the termination value?
for(int a = 0; a <= 99; a++) {} condition statement range: real{0 to 99} : yields 100 iterations
for(int a = 0; a < 100; a++) {} condition statement range: real{0 to 99.99...} : yields 100 iterations
for(int a = 1; a <= 100; a++) {} condition statement range: real{1 to 100} : yields 100 iterations

WRT function.cpp
Output file as an arguement is a great idea!

I'm not quite understanding this:
With the functions.cpp file, it deals with member data, but is complicated by the fact that your data container (or Collection) is also in the class


Is this to increase modularity?
Put the for loop that goes through the container of all the objects (the Collection) in the same place as the Collection, and access your output function from there. Whether that be in main() or in another class is up to you.

If I'm understanding correctly, you would replace function.h/.cpp with another object which holds and outputs the final results. Is that correct?

WRT const:
I was just about to implement const values :). That is another item I have only recently read about.

WRT validating input data:
Currently, the code is only at its very beginning. For right now, its purpose is to show the effect of certain variable changes on the output. Later, it will evolve to include more specific calculations (i.e. actual sample data using real wind turbine specifications, and/or further calculations). For now, the varible values are arbitrary. Though, there may be some conditions that cause a function to be "undefined". I will have to look into that.

WRT namespaces:
My knowledge here is very limited. I will have to look into that further.
...don't have using namespace std;
--> Why? If the std namespace is the only one needed, shouldn't time and effort be saved by using it?

Thanks again for your input!!
Please forgive me if my understanding is not up to par:


No worries, it's all about learning - I am stoked you are willing to learn :+)

WRT data members:
What data members did I not initialize? The variables need to be public so that the user can change their values. Perhaps create local variables in main() and send them to a member function to set member values?


Initialisation is slightly different from assignment. The initialisation list, initialised 3 member variables, then the rest were by assignment. To quote Scott Meyers :

Scott Meyers wrote:
The rules of C++ stipulate that data members of an object are initialized before the body of the constructor is entered.


That is before the opening brace of the constructor. This applies to non built in types (ie class objects) which have their constructors called in the initialisation even if you don't have anything in the initialiser list. So when you do assignment inside the body of the constructor, all of the previous effort was wasted. For built in types like int or double, they are not guaranteed to be initialised at all. So it's best to initialise everything with the initialiser list, and it's good practice to do it in the same order that members appear in the class declaration.

Having public member variables is a really bad idea: Would you display all your bank account details & balances on the internet AND let ANYONE change them whenever they wanted? Instead, it is better to make them all private, and provide an interface (public functions) to allow access to only those that need it. Don't be tempted to have get / set functions for each member though. If you do need to change values after the object has been created, then consider having one function to change them all at once. However changing 1 variable at a time to see the effects could be a valid use of set functions.

WRT variable names:
I understand your point, but they are what they are to coincide with the variable names used in my resource materials.


That's fine. I am always mentioning this because in my mind it relates to better understanding especially for others. I did exactly the same thing in one of my projects - named the variables as close as possible as to what was in the documentation. But I wonder for example: a = 0.5 * b * h; versus TriArea = 0.5 *Base * Height;. To me the latter is pretty Idiot proof, sometimes you might amaze yourself how a runtime error can occur because of insufficient variable naming.

WRT vector use:
I haven't used vectors much and was toying with their usage last night. It would be nice to not have to worry about the size of the array.


Yes, and more importantly the memory management - you don't have to do it with any of the STL containers!!

WRT condition statements:
How are these different, other than being able to determine the value of "a" just by looking at the termination value?


The standard idiom for doing something n times is:

for (int a = 0;a < n; ++a) {}

If you use the <= it will do it n +1 times. This is a problem when dealing with arrays, or any container which returns a size value, or uses a subscript operator [] because you will go past the end, and get a seg fault.

WRT function.cpp
Output file as an arguement is a great idea!
If I'm understanding correctly, you would replace function.h/.cpp with another object which holds and outputs the final results. Is that correct?


With that section, the idea was to have the class for just the data object. I am saying put a collection of the data objects elsewhere - in main() if you like, or in a class of it's own. So, if you had points, create a point class, but imagine it is only 1 point. Then put the collection of the points elsewhere. If it's in a class of it's own, then that class would have facilities to retrieve individual items, or do things like sort all of them or apply some function to them all. These would probably make use of the STL algorithms and functions to do this.

...don't have using namespace std;
--> Why? If the std namespace is the only one needed, shouldn't time and effort be saved by using it?


What happens is that you bring in the entire std namespace (The whole of the STL!!) into the global namespace, thereby polluting it. It will cause you naming conflicts one day. Did you know that there is std::distance, std::left, std::right, just to name a few. If you had a function or variable name the same as these -> big problems. Look them up see what they do. This whole thing creates a drama that we were trying avoid by having the concept of a namespace!

So what to do instead? You can either put std:: before each std thing - sounds like a pain, but you get used to it. This has the advantage of no editing required when you send someone a function snippet. Or you can do this after the includes:

1
2
3
4
5
6
7
using std::cout;
using std::cin;
using std::endl;

using std::string;
using std::vector;
// etc 


Sometimes a mixture is worthwhile -do std::find if that only appears a few times in a file.

It is also a good idea to keep you own stuff out of the global namespace. Put you class declaration, and the definition of it's functions into a namespace declaration. Use the scope resolution operator to refer to things in your namespace. For example MyNS::MyClass::MyFunction. You can also use the using statement to make an alias for things: using MyNamespace = mns;

Jeepers - I just saw your post at the top of this page.

Perhaps I am reading this wrong:


If you have set functions, ensure that the result is re-calculated somewhere. This might be a good reason to have the answer as a function instead of a variable. I keep thinking about geometry objects, where things are dependent on each other: A circular arc defined by 3 points - you can't just move one of the points without invalidating the other info. This why I mentioned having private member data.

Vavg = mean wind velocity from a sample of experimental wind velocities


If you program was going to manage this data as well (I understand it might not need to), then that implies a WindVelocity class, A class to hold a collection of that data, with functions to calc the average or other stats as necessary.

Some other things I do:

Name my classes with a leading C as in CWindVelocity. I am not the only one: Qt uses Q, KDE uses K

I like CamelCase for names.

Name member variables with a leading m_ as in m_Radius This helps avoid the need for this->Radius in operator overloading.

Name any pointer variable with a leading p as in pMyVariable. Probably shouldn't be using pointers these days, unless they are smart pointers.

Any way hope you are having fun. I am: I finally have a job after much lollygagging about, now have to pack the car & drive to Darwin. I am in Melbourne, so that is a casual ~4,000km drive. Hopefully I won't be too discombobulated at the other end!!
Last edited on
@TheIdeasMan
On the subject of learning, I have opened a question about the next book to buy for further learning. Here is the post, if you (or anyone else following this thread) would like to contribute:

http://www.cplusplus.com/forum/general/113260/

BTW, how do you post a link?
Here is the next revision:

WindTurbineMain.cpp
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
#include <iostream>
#include <fstream>
#include "parameters.h"
#include "output.h"

int main()
{
	// Define vectors to store calculation data
	std::vector<double> dataV;
	std::vector<double> dataPDF;
	std::vector<double> dataPower;

	// Create parameter data class
	parameters param;

	// Set initial parameters
	param.velocityCutIn = 0;
	param.velocityRated = 7.0;
	param.velocityCutOut = 20.0;
	param.velocityAvg = 7.0;
	param.bladeArea = 10.869;
	param.airDensity = 1.2;
	param.powerRated = 2.1;
	param.dataIncrement = 0.5;
	param.shapeFactor = 2.0;

	// Create data container and ouput procedure class
	output dataOut;

	// Input file to write to
	dataOut.outFile = "New Data2.txt";
	// Populate output data containers
	param.populate(dataV, dataPDF, dataPower);
	// Output data to file
	dataOut.dataUI(dataV, dataPDF, dataPower);
}


parameters.h
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
47
48
49
50
51
52
53
54
55
56
57
58
#ifndef parameters_H
#define parameters_H

#include <vector>

class parameters
{
public:
	parameters();
	~parameters();

	double velocityCutIn;
	double velocityRated;
	double velocityCutOut;
	double velocityAvg;
	double bladeArea;
	double airDensity;
	double powerRated;
	double dataIncrement;
	double powerAvg;
	double shapeFactor;

	void populate(
		std::vector<double> &dataV,
		std::vector<double> &dataPDF,
		std::vector<double> &dataPower);

private:
	double _vci;		// Cut-in velocity
	double _vr;			// Rated velocity
	double _vco;		// Cut-out velocity
	double _vavg;		// Average velocity
	double _area;		// Turbine blade area
	double _airD;		// Air density
	double _pr;			// Rated power
	double _inc;		// Velocity iteration increment
	double _CF;			// Capacity factor
	double _pavg;		// Average power
	double _k;			// Weibull PDF shape parameter
	double _c;			// Weibull PDF scale parameter
	double _a;			// Gamma function complex variable

	std::vector<double> _dataV;
	std::vector<double> _dataPDF;
	std::vector<double> _dataPower;

	void _processInputs();
	void _processData(
        std::vector<double> &dataV,
		std::vector<double> &dataPDF,
		std::vector<double> &dataPower);
	double _pGen(const double V);
	double _fV(const double V);
	double _CapFactor();
	double _incGamma(const double a, const double x);
};

#endif 


parameters.cpp
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#ifndef _USE_MATH_DEFINES
#define _USE_MATH_DEFINES
#endif

#include "parameters.h"
#include <iostream>
#include <iomanip>
#include <cmath>
#include <vector>

// Class parameters constructor
// Variable initiated to arbitrary numbers
parameters::parameters() :
		_vci(0),
		_vr(7.0),
		_vco(20.0),
		_vavg(7.0),
		_area(10.869),
		_airD(1.2),
		_pr(2.1),
		_inc(0.5),
		_CF(0),
		_pavg(0),
		_k(2.0),
		_c(0),
		_a(0)
{}

// Create and populate data arrays for Velicity, PDF, and Power
void parameters::populate(
    std::vector<double> &dataV,
    std::vector<double> &dataPDF,
    std::vector<double> &dataPower)
{
	_processInputs();
	_processData(dataV, dataPDF, dataPower);
}

void parameters::_processInputs()
{
	_vci = velocityCutIn;
	_vr = velocityRated;
	_vco = velocityCutOut;
	_vavg = velocityAvg;
	_area = bladeArea;
	_airD = airDensity;
	_pr = powerRated;
	_inc = dataIncrement;
	_pavg = powerAvg;
	_k = shapeFactor;
}

// Change to write to output class
void parameters::_processData(
    std::vector<double> &dataV,
    std::vector<double> &dataPDF,
    std::vector<double> &dataPower)
{
	// Define Weibull PDF scale parameter
	_c = 2 * _vavg / sqrt(M_PI);
	// Define gamma function complex variable
	_a = 3.0 / _k + 1.0;

	int index = 0;

	const int iterate = (int)(_vco / _inc) + 1;
	double V = 0;

	for (int i = 0; i < iterate; i++)
	{
		if (V < _vci)
		{
			// Power output is 0 for wind velicity less than cut-in velocity
			_dataPower.push_back(0);
		}
		else // Write power output value to data vector
		{
			_dataPower.push_back( _pGen(V) );
		}

		// Write velocity data to data vector
		_dataV.push_back(V);
		// Write probability to data vector
		_dataPDF.push_back( _fV(V) );

		V += _inc;
	}

	dataV = _dataV;
	dataPDF = _dataPDF;
	dataPower = _dataPower;
}

// Function for producting the probability of each velocity magnitude
double parameters::_fV(const double V)
{
	return _k / _c * pow(V / _c, _k - 1.0) * exp( - pow(V / _c, _k) );
}

// Function for calculating the capacity factor
double parameters::_CapFactor()
{
	return pow(_vr, -3.0) * 
		_incGamma(_a, _vr) - _incGamma(_a, _vci) + 
		exp( - pow(_vco / _c, _k) ) - exp( - pow(_vr / _c, _k) );
}

// Function for approximating the result of the incomplete gamma function
// Used for integral approximation
double parameters::_incGamma(const double a, const double x) // Consider using recursion
{
	double gammaSum = 0;
	for(int n = 0; n <= 100; n++)
	{
		double denom = 1;
		for(int nInc = 0; nInc <= n; nInc++)
		{
			denom *= (a + nInc);
		}

		gammaSum += ( pow(x, n) / denom );
	}

	return gammaSum * pow(x, a) * exp(-x);
}

// Function for calculating power output
double parameters::_pGen(const double V)
{
	return _pr * pow(V, 3) / pow(_vr, 3);
}

// Class parameters destructor
parameters::~parameters() {}


output.h
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
#ifndef OUTPUT_H
#define OUTPUT_H

#include <vector>
#include <string>

class output
{
public:
	output();
	~output();
	std::string outFile;
	void toFile(
        const std::vector<double> &dataV,
        const std::vector<double> &dataPDF,
        const std::vector<double> &dataPower);
	void toConsole(
		const std::vector<double> &dataV,
        const std::vector<double> &dataPDF,
        const std::vector<double> &dataPower);
	void dataUI(
		const std::vector<double> &dataV,
        const std::vector<double> &dataPDF,
        const std::vector<double> &dataPower);

private:
	std::vector<double> _dataV;
	std::vector<double> _dataPDF;
	std::vector<double> _dataPower;

	void _processOutput(
        const std::vector<double> &dataV,
        const std::vector<double> &dataPDF,
        const std::vector<double> &dataPower);

	int _invalid();
};

#endif 
output.cpp
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "output.h"
#include "parameters.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <cstring>

using std::cout;
using std::cin;
using std::endl;
using std::fixed;

// Class constructor
output::output() {}

// Copy user vectors to private vectors
void output::_processOutput(
    const std::vector<double> &dataV,
    const std::vector<double> &dataPDF,
    const std::vector<double> &dataPower)
{
    _dataV = dataV;
    _dataPDF = dataPDF;
    _dataPower = dataPower;
}

void output::dataUI(
	const std::vector<double> &dataV,
    const std::vector<double> &dataPDF,
    const std::vector<double> &dataPower)
{
	int choice = 0;

	while (choice != 99)
	{
		cout << endl;
		cout << "Choose an option:" << endl;
		cout << "1.  Print data to screen" << endl;
		cout << "2.  Print data to file" << endl;
		cout << "3.  Exit" << endl;
		cout << "Choice: ";
		cin >> choice;

		if(cin.fail())
		{
			cin.clear();
			cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
			choice = _invalid();
		}
		else
		{
			switch (choice)
			{
			case 1:
				toConsole(dataV, dataPDF, dataPower);
				break;
			case 2:
				cin.clear();
				cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
				toFile(dataV, dataPDF, dataPower);
				break;
			case 3:
				choice = 99;
				break;
			default:
				choice = _invalid();
			}
		}
	}
}

void output::toConsole(
	const std::vector<double> &dataV,
    const std::vector<double> &dataPDF,
    const std::vector<double> &dataPower)
{
	_processOutput(dataV, dataPDF, dataPower);

	// Output data to console
	const size_t dataSize = dataV.size();
	
	cout << "Index\tVelocity\tProbability\tPower\n";
	for (size_t i = 0; i < dataSize; i++)
	{
		cout << i << '\t';
		cout << fixed << _dataV[i] << '\t';
		cout << fixed << _dataPDF[i] << '\t';
		cout << fixed << _dataPower[i] << endl;
	}

	cout << "Press enter to continue...";
	cin.get();
	cout << endl << endl;
}

// Split function to show data and output to file
// Make conversion public and rest private
void output::toFile(
    const std::vector<double> &dataV,
    const std::vector<double> &dataPDF,
    const std::vector<double> &dataPower)
{
	_processOutput(dataV, dataPDF, dataPower);

	const size_t dataSize = dataV.size();
	std::ofstream data;

	// Convert file name string to char array
	char *cstr = new char[outFile.size() + 1];
	cstr[outFile.size()] = 0;
	memcpy(cstr, outFile.c_str(), outFile.size());

	// Open file and output file data
	data.open(cstr);
	if (data.is_open())
	{
		cout << endl << "Writing to file: " << cstr << endl;
		cout << "Press enter to continue...";
		cin.get();
		data << __DATE__ << ", " << __TIME__ << "\n\n";
		data << "Index\tVelocity\tProbability\tPower\n";
		for (size_t i = 0; i < dataSize; i++)
		{
			data << i << '\t';
			data << fixed << _dataV[i] << '\t';
			data << fixed << _dataPDF[i] << '\t';
			data << fixed << _dataPower[i] << endl;
		}
		data << endl << "End of file...";
	}
	else
	{
		cout << "Could not open file.";
		cin.get();
	}
	data.close();

	cout << endl << endl;

	delete [] cstr;
}

int output::_invalid()
{
	cout << endl;
	cout << "Invalid entry.  Try again..." << endl << endl;

	return 0;
}

// Class destructor
output::~output() {}
Sorry for the long delay, I have moved across country, the car gearbox is discombobulated, and I have been working flat out at the new job.

With your code, still some problems here.

You now have private member variables, but you still have the public ones and have written code to copy between them, and you send the vectors between classes. Also the concept of the Turbine Parameters could have only the parameters and the functions that operate on them and nothing else.

I wonder whether you understand these two concepts:

1. Class Interface;
2. Overloaded functions, including constructors.

A Class interface is the class functions with which the user interacts with the data. So for your turbine class, this is the overloaded constructors (with arguments - initialises data), and the public functions which calculate using the turbine parameters.

C++ allows overloading of functions. That is you can have functions with the same name, but they differ in the number & type of the arguments, and whether the function is const or not. In my code below, I provide 2 constructors: a default which uses the default values, and another which uses the arguments provided.

So you have an output class, The std::vectors should only exist in this class, they should not be part of the Turbine parameters class. You could have a struct which has Wind Velocity, and variables to hold the answers to the calculation functions, then have a std::vector of this struct. IMO you should call your calculation functions in the Turbine parameters class with Wind Velocity as an argument, in order to populate the struct. Also a loop to call the calculation functions with different Wind Velocities, to populate the vector. Then it is a matter of printing out the contents of the vector.

Could also have a std::list of the turbine vectors, so you can process any number of different turbine types.

When one uses a constructor with an initialisation list and an empty body, just put it in the header file, don't bother with putting an empty function in the .cpp file.

Here is my Turbine class, sorry I didn't have time to do more. Hopefully this is basically all you need for this class. Could add a m_Name string, with a get function, so you can print it out in your table. The calculation functions don't take any arguments, you would need to alter this so that they do - Velocity etc.

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#ifndef CTURBINE_H
#define CTURBINE_H

namespace WindTurbine {

class CTurbine
{
    private:
        double m_VelocityCutIn;    //!< Member variable "m_velocityCutIn"
        double m_VelocityRated;    //!< Member variable "m_velocityRated"
        double m_VelocityCutOut;   //!< Member variable "m_velocityCutOut"
        double m_VelocityAvg;      //!< Member variable "m_velocityAvg"
        double m_BladeArea;        //!< Member variable "m_BladeArea"
        double m_AirDensity;       //!< Member variable "m_AirDensity"
        double m_PowerRated;       //!< Member variable "m_PowerRated"
        double m_PowerAvg;         //!< Member variable "m_PowerAvg"
        double m_ShapeFactor;      //!< Member variable "m_ShapeFactor"
        double m_WeibullPDFShape;  //!< Member variable "Weibull Probability Distribution Function shape parameter"
        double m_WeibullPDFScale;  //!< Member variable "Weibull PDF scale parameter"
        double m_GammaFComplex;     //!< Member variable "Gamma function complex"

    public:
        /** Default constructor uses set values*/
        CTurbine():
            m_VelocityCutIn(0.0),
            m_VelocityRated (7.0),
            m_VelocityCutOut (20.0),
            m_VelocityAvg (7.0),
            m_BladeArea (10.869),
            m_AirDensity (1.2),
            m_PowerRated (2.1),
            m_PowerAvg (0.0),
            m_ShapeFactor (0.0), // could be 1.0?
            m_WeibullPDFShape (0.0),
            m_WeibullPDFScale (0.0),
            m_GammaFComplex (0.0)
            {}
            // Constructor uses args for the values
            CTurbine (double VelocityCutIn,
                double VelocityRated,
                double VelocityCutOut,
                double VelocityAvg,
                double BladeArea,
                double AirDensity,
                double PowerRated,
                double PowerAvg,
                double ShapeFactor,
                double WeibullPDFShape,
                double WeibullPDFScale,
                double GammaFComplex) :

            m_VelocityCutIn(VelocityCutIn),
            m_VelocityRated (VelocityRated),
            m_VelocityCutOut (VelocityCutOut),
            m_VelocityAvg (VelocityAvg),
            m_BladeArea (BladeArea),
            m_AirDensity (AirDensity),
            m_PowerRated (PowerRated),
            m_PowerAvg (PowerAvg),
            m_ShapeFactor (ShapeFactor),
            m_WeibullPDFShape (WeibullPDFShape),
            m_WeibullPDFScale (WeibullPDFScale),
            m_GammaFComplex (GammaFComplex)
            {}


        double CalcWeibullPDFShape();
        double CalcWeibullPDFScale();
        double CalcGammaFComplex();
};

} // end WindTurbine Namespace

#endif // CTURBINE_H



EDIT: Fixed some errors
Last edited on
No worries. I've been tied up with sick kids, work, and preparing for grad school anyway.

1. Class Interface;
2. Overloaded functions, including constructors.

My understanding of these concepts is very limited, especially class interfaces.

So you have an output class, The std::vectors should only exist in this class, they should not be part of the Turbine parameters class.

So the calculations should be stored directly in the output class vectors? I figured that keeping the production of data separate from how the data is displayed or further utilized would allow for the greatest ease of program evolution.

You could have a struct which has Wind Velocity, and variables to hold the answers to the calculation functions, then have a std::vector of this struct.

So linked lists contained by vectors? I'm pretty sure I'm not understanding this correctly, or if I am, the reason for doing this. Would this struct be utilized by the user (main) or the "parameters" class?

IMO you should call your calculation functions in the Turbine parameters class with Wind Velocity as an argument, in order to populate the struct. Also a loop to call the calculation functions with different Wind Velocities, to populate the vector. Then it is a matter of printing out the contents of the vector.

Assuming you are referring to the velocityCutIn, velocityCutOut, velocityRated, and velocityAvg, being able to ouput immediately comparable data is a great idea. Adjusting the wind velocity range (or loop range) would only serve to produce a longer or shorter set of data.

Please forgive me if I'm not understanding your suggestions correctly.

EDIT: I'm playing with the code some more and was wondering: were you suggesting that I create the struct in the main function or within the parameters class?

If you are suggesting creating the struct within the parameters class, wouldn't it make more sense to just use class members? Perhaps it would just serve as another way to group variables?

If you are suggesting creating the struct in the main function, how would I structure the class to accept a reference to the struct?
Last edited on
Gidday,

It seems that life is continuing for all of us :+)

A class interface is just some public functions to allow one to interact with the private member data. In your case, it is the constructors & your calculation functions.

So the calculations should be stored directly in the output class vectors? I figured that keeping the production of data separate from how the data is displayed or further utilized would allow for the greatest ease of program evolution.


I was thinking that the parameters class is just that - the parameters only. The results of the calcs could go in a class of their own, if you wanted an additional class for output, that is fine - but you would then need to provide interface functions to get access to the data.

With the output / storing of the answers, rather than have 3 separate vectors, make a struct that holds the wind velocity and the 3 answers. The struct is easier than a class for this, because the access is public by default, and it will be a member variable. Then have a vector of these structs, to make a table showing results for each wind velocity. Then make a std::list of these vectors, so you can have multiple turbines. With STL containers, they can hold any type of object, including another STL container.

Assuming you are referring to the velocityCutIn, velocityCutOut, velocityRated, and velocityAvg, being able to ouput immediately comparable data is a great idea. Adjusting the wind velocity range (or loop range) would only serve to produce a longer or shorter set of data.


Those variables are parameters of the turbine, I meant the actual wind velocity blowing through the turbine - which has nothing to do with the turbine parameters (it is external to the turbine). However it could be an argument to a calculation function.

With the use of the main function, I like to have minimal code in there - the classes should do all the work. Could use it to create some objects and go from there.

I might have 2 days off this weekend - will have a go at writing the whole thing.

Regards, and hope this helps a bit :+)
Thanks for the suggestions! I'll see if I can mold this code some more and relay the results.

Just a quick question: How can I created the parameters constructor to allow the user to optionally use a pre-defined complex variable and/or scale factor. As is, the constructor will automatically calculate both of these variables based off other defined variables. If, in the future, an alternative method for calculating scale factor or complex variable is used for comparison, it would be nice to allow the user to define it by other means. Should I just create another constructor that includes these variables within the argument list?
Yes, sounds all right.

Cheers
Regarding std::list :

If I initialize a list within a constructor, how can I initialize it to contain more than one vector?

For instance:
1
2
3
4
5
someConstructor(std::vector<structType> mVector1,
    std::vector<structType> myVector2) : 
    
    listName(????)
{}
The list is for storing the output data - there is no real need to initialise it with anything, can just put data into it. Use push_back

http://www.cplusplus.com/reference/list/list/push_back/


Are you aware of the reference section on this site? There is a link at the top left of this page - it shows a lot of the details about STL, with examples. There are also articles, and a tutorial. Some things that are not shown for C++11 can be found on
http://en.cppreference.com/w/


I mentioned std::list because it is pretty simple, if we just want to put stuff in it, then print it out. If we wanted to do a lot of sorting or finding, then some of the other containers might be better. But it would only make a difference if we had a LOT of data. However it is a good idea to always write efficient code, so it might be worthwhile investigating some of the other containers: std::map, std::multimap, std::set, std::multisetset, std::unordered_set etc.

I have some free time today & tmrw, so will have a go at writing the whole thing.
Last edited on
Are you aware of the reference section on this site?

Yes, and it has be a great source of information. However, sometimes implementation is a bit more complicated than the examples given.

Here are the latest changes: (includes and pre-processing code left out)
parameters.h
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
class parameters
{
public:
	struct velocityResult
	{
		// struct constructor
		velocityResult() :
			velocity(0),
			probability(0),
			power(0)
		{}

		double velocity;
		double probability;
		double power;
	};

	parameters() :
		_vci(0),
		_vr(0),
		_vco(0),
		_vavg(0),
		_area(0),
		_airD(0),
		_pr(0),
		_inc(0),
		_pavg(0),
		_CF(0),
		_k(0),
		_c(0),
		_a(0)
	{}

	parameters(std::string turbineName,
		double velocityCutIn,
		double velocityRated,
		double velocityCutOut,
		double velocityAvg,
		double bladeArea,
		double airDensity,
		double powerRated,
		double dataIncrement,
		double shapeFactor) :
		
		name(turbineName),
		_vci(velocityCutIn),
		_vr(velocityRated),
		_vco(velocityCutOut),
		_vavg(velocityAvg),
		_area(bladeArea),
		_airD(airDensity),
		_pr(powerRated),
		_inc(dataIncrement),
		_pavg(0),						// Calculation method undecided
		capacityFactor(0),
		_CF(0),
		_k(shapeFactor),
		_c(_scaleFactor()),
		_a(_complexVariable())
	{
		_CF = _CapFactor();
		capacityFactor = _CF;
		_processData();
	}

	~parameters() {};

	std::string name;
	std::vector<velocityResult> velocityData;
	double capacityFactor;

	// Public function for approximating the incomplete gamma function result
	// Used for data comparison and debugging
	double incGamma(const double a, const double x);

private:
	double _vci;		// Cut-in velocity
	double _vr;			// Rated velocity
	double _vco;		// Cut-out velocity
	double _vavg;		// Average velocity
	double _area;		// Turbine blade area
	double _airD;		// Air density
	double _pr;			// Rated power
	double _inc;		// Velocity iteration increment
	double _CF;			// Capacity factor
	double _pavg;		// Average power
	double _k;			// Weibull PDF shape parameter
	double _c;			// Weibull PDF scale parameter
	double _a;			// Gamma function complex variable

	double _scaleFactor();
	double _complexVariable();
	void _processInputs();
	void _processData();
	double _pGen(const double V);
	double _fV(const double V);
	double _CapFactor();
	double _incGamma(const double a, const double x);

};


parameters.cpp
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
// Functions essentially unchanged

void parameters::_processData()
{

	int index = 0;

	const int iterate = (int)(_vco / _inc) + 1;

	double V = 0;

	for (int i = 0; i < iterate; i++)
	{
		velocityResult newVelocity;

		// Write velocity magnitude to struct
		newVelocity.velocity = V;

		if (V < _vci)
		{
			// Power output is 0 for wind velicity less than cut-in velocity
			newVelocity.power = 0;
		}
		else // Write power output value to struct
		{
			newVelocity.power = _pGen(V);
		}

		// Write velocity probability to struct
		newVelocity.probability = _fV(V);

		// Write velocityResult to _velocityData vector
		velocityData.push_back(newVelocity);
		
		// Increment velocity by user-defined increment value
		V += _inc;
	}
}


output.h
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
class output : public parameters
{
public:

	output() {};
	output(std::string fileName, parameters &mTurbine);

	output(std::vector<velocityResult> velocityData1) : 
		_velocitySet(1, velocityData1)
	{}

	output(std::vector<velocityResult> velocityData1,
		std::vector<velocityResult> velocityData2) :
	_velocitySet(2, (velocityData1, velocityData2))
	{}

	~output() {};

private:
	std::string _outFile;
	std::string _turbineName;
	std::vector<velocityResult> _velocityData;

	void _dataUI();
	void _toConsole();
	void _toFile();

	int _invalid();

	std::list<std::vector<velocityResult>> _velocitySet;
};


ouput.cpp

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
output::output(std::string fileName, parameters &mTurbine) :
	_outFile(fileName),
	_turbineName(mTurbine.name),
	_velocityData(mTurbine.velocityData)
{
	_dataUI();
}

void output::_dataUI()
{
	int choice = 0;

	while (choice != 99)
	{
		cout << endl;
		cout << "Choose an option:" << endl;
		cout << "1.  Print data to screen" << endl;
		cout << "2.  Print data to file" << endl;
		cout << "3.  Exit" << endl;
		cout << "Choice: ";
		cin >> choice;

		if(cin.fail())
		{
			cin.clear();
			cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
			choice = _invalid();
		}
		else
		{
			cout << endl << endl;
			switch (choice)
			{
			case 1:
				_toConsole();
				break;
			case 2:
				cin.clear();
				cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
				_toFile();
				break;
			case 3:
				choice = 99;
				break;
			default:
				choice = _invalid();
			}
		}
	}
}

void output::_toConsole()
{
	// Output data to console
	const size_t dataSize = _velocityData.size();
	
	cout << "Turbine : " << _turbineName << endl << endl;
	cout << "Velocity\tProbability\tPower\n";
	for (size_t i = 0; i < dataSize; i++)
	{
		cout << fixed << _velocityData[i].velocity << '\t';
		cout << fixed << _velocityData[i].probability << '\t';
		cout << fixed << _velocityData[i].power << endl;
	}

	cout << "Press enter to continue...";
	cin.get();
	cout << endl << endl;
}


void output::_toFile()
{

	const size_t dataSize = _velocityData.size();
	std::ofstream data;

	// Convert file name string to char array
	char *cstr = new char[_outFile.size() + 1];
	cstr[_outFile.size()] = 0;
	memcpy(cstr, _outFile.c_str(), _outFile.size());

	// Open file and output file data
	data.open(cstr);
	if (data.is_open())
	{
		cout << endl << "Writing to file: " << cstr << endl;
		cout << "Press enter to continue...";
		cin.get();
		data << __DATE__ << ", " << __TIME__ << "\n\n";
		data << "Turbine : " << _turbineName << endl << endl;
		data << "Velocity\tProbability\tPower\n";
		for (size_t i = 0; i < dataSize; i++)
		{
			data << fixed << _velocityData[i].velocity << '\t';
			data << fixed << _velocityData[i].probability << '\t';
			data << fixed << _velocityData[i].power << endl;
		}
		data << endl << "End of file...";
	}
	else
	{
		cout << "Could not open file.";
		cin.get();
	}
	data.close();

	cout << endl << endl;

	delete [] cstr;
}

int output::_invalid()
{
	cout << endl;
	cout << "Invalid entry.  Try again..." << endl << endl;

	return 0;
}


WindTurbineMain.cpp
1
2
3
4
5
6
7
8
int main()
{
	// Create parameters::WindTurbine structure
	std::string name = "Example";
	parameters param(name, 0.0, 7.0, 20.0, 7.0, 10.869, 1.2, 2.1, 0.5, 2.0);

	output dataOut("NewFile.txt", param);
}


I know you had suggested placing the calculation results within the output (or separate) class, but storing and passing the results via the parameters class just seemed to be the best way of keeping calculation and output processes separate. However, I'm certainly open to your thoughts.
Topic archived. No new replies allowed.
Pages: 12