Solar power is a free and clean alternative to traditional fossil fuels.

However, nowadays, solar cells' efficiency is not as high as we would like. Therefore, selecting the ideal conditions for its installation is critical in obtaining the maximum amount of energy out of it.

We want to predict the power output for a particular array of solar power generators, knowing some environmental conditions.

- Application type.
- Data set.
- Neural network.
- Training strategy.
- Model selection.
- Testing analysis.
- Model deployment.

This example is solved with Neural Designer. You can use the free trial to understand how the solution is achieved step by step.

The variable to be predicted is continuous (energy production). Therefore, this is an approximation project.

The primary goal here is to model energy production as a function of environmental variables.

The first step is to prepare the data set, which is the source of information for the approximation problem. It is composed of:

- Data source.
- Variables.
- Instances.

The file solarpowergeneration.csv contains the data for this example. Here the number of variables (columns) is 10, and the number of instances (rows) is 2920.

We have the following variables for this analysis:

**distance-to-solar-noon**, in radians.**temperature**, daily average temperature, in degrees Celsius.**wind-direction**, daily average wind direction, in degrees (0-360).**wind-speed**, daily average wind speed, in meters per second.**sky-cover**, in a five-step scale, from 0 to 4, being 0 totally clear and 4 completely covered.**visibility**, in kilometers.**humidity**, in percentage.**average-wind-speed-(period)**, average wind speed during the 3-hour period de measure was taken in, in meters per second.**average-pressure-(period)**, average barometric pressure during the 3-hour period de measure was taken in, in mercury inches.**power-generated**, in jules for each 3-hour period.

Our target variable will be the last one, power-generated.

The instances are divided into training, selection, and testing subsets. They represent 60%, 20% and 20% of the original instances, respectively, and are split at random.

Calculating the data distributions helps us check for the correctness of the available information and detect anomalies. The following chart shows the histogram for the power-generated variable:

It is also interesting to look for dependencies between a single input and single target variables. To do that, we can plot an inputs-targets correlations chart.

In this case, the highest correlation is with the distance to solar noon (the closer to solar noon, the more power is generated by the solar plant).

Next, we plot a scatter chart for the most significant correlations for our target variable.

The second step is to build a neural network that represents the approximation function. For approximation problems, it is usually composed by:

- Scaling layer.
- Perceptron layers.
- Unscaling layer.

The neural network has 9 inputs (distance to solar noon, temperature, wind direction, wind speed, sky cover, visibility, humidity, average wind speed (period) and average pressure (period)) and 1 output (power generated).

The scaling layer contains the statistics of the inputs. We use the automatic setting for this layer to accommodate the best scaling technique for our data.

We use 2 perceptron layers here:

- The first perceptron layer has 9 inputs, 3 neurons, and a hyperbolic tangent activation function.
- The second perceptron layer has 3 inputs, 1 neuron, and a linear activation function.

The unscaling layer contains the statistics of the outputs. We use the automatic method as before.

The next graph represents the neural network for this example.

The fourth step is to select an appropriate training strategy. It is composed of two parameters:

- Loss index.
- Optimization algorithm.

The loss index defines what the neural network will learn. It is composed of an error term and a regularization term.

The error term chosen is the normalized squared error. It divides the squared error between the outputs from the neural network and the targets in the data set by its normalization coefficient. If the normalized squared error has a value of 1, then the neural network is predicting the data 'in the mean', while a value of zero means a perfect prediction of the data. This error term does not have any parameters to set.

The regularization term is the L2 regularization. It is applied to control the complexity of the neural network by reducing the value of the parameters. We use a weak weight for this regularization term.

The optimization algorithm is in charge of searching for the neural network parameters that minimize the loss index. Here we chose the quasi-Newton method as optimization algorithm.

The following chart shows how the training (blue) and selection (orange) errors decrease with the epochs during the training process.
The final values are **training error = 0.121 NSE** and **selection error = 0.122 NSE**, respectively.

The objective of model selection is to find the network architecture with the best generalization properties. That is, we want to improve the final selection error obtained before (0.122 NSE).

The best selection error is achieved by using a model with the most appropriate complexity to produce a good data fit. Order selection algorithms are responsible for find the optimal number of perceptrons in the neural network.

The following chart shows the results of the incremental order algorithm. The blue line plots the final training error as a function of the number of neurons. The orange line plots the final selection error as a function of the number of neurons.

As we can see, the final training error continuously decreases with the number of neurons.
However, the final selection error takes a minimum value at some point.
Here, the optimal number of neurons is 8, corresponding to a selection error of **0.089 NSE**.

The following figure shows the optimal network architecture for this application.

The purpose of the testing analysis is to validate the generalization capabilities of the neural network. We use the testing instances in the data set, which have never been used before.

A standard testing method in approximation applications is to perform a linear regression analysis between the predicted and the real pollutant level values.

For a perfect fit, the correlation coefficient R2 would be 1.
As we have **R2 = 0.951**, the neural network predicts the testing data quite well.

In the model deployment phase, the neural network is used to predict outputs for inputs that it has never seen.

We can calculate the neural network outputs for a given set of inputs:

- distance-to-solar-noon: 0.503 radians.
- temperature: 58.468ºC.
- wind-direction: 24.953º.
- wind-speed: 10.097 m/s.
- sky-cover: 1.988 over 4.
- visibility: 9.558 km.
- humidity: 73.524%.
- average-wind-speed-(period): 10.136 m/s.
- average-pressure-(period): 30.062 mercury inches.
- power-generated: 3012.461 Jules per 3-hour period.

Directional outputs plot the neural network outputs through some reference points.

The next list shows the reference point for the plots.

- distance-to-solar-noon: 0.503 radians.
- temperature: 58.468ºC.
- wind-direction: 24.953º.
- wind-speed: 10.097 m/s.
- sky-cover: 1.988 over 4.
- visibility: 9.558 km.
- humidity: 73.524%.
- average-wind-speed-(period): 10.136 m/s.
- average-pressure-(period): 30.062 mercury inches.

We can see here how the distance to solar noon affects the power generated:

The mathematical expression represented by the predictive model is displayed next:

scaled_distance-to-solar-noon = distance-to-solar-noon*(1+1)/(1.141360044-(0.05040090159))-0.05040090159*(1+1)/(1.141360044-0.05040090159)-1; scaled_temperature = temperature*(1+1)/(78-(42))-42*(1+1)/(78-42)-1; scaled_wind-direction = wind-direction*(1+1)/(36-(1))-1*(1+1)/(36-1)-1; scaled_wind-speed = wind-speed*(1+1)/(26.60000038-(1.100000024))-1.100000024*(1+1)/(26.60000038-1.100000024)-1; scaled_sky-cover = sky-cover*(1+1)/(4-(0))-0*(1+1)/(4-0)-1; scaled_visibility = visibility*(1+1)/(10-(0))-0*(1+1)/(10-0)-1; scaled_humidity = humidity*(1+1)/(100-(14))-14*(1+1)/(100-14)-1; scaled_average-wind-speed-(period) = average-wind-speed-(period)*(1+1)/(40-(0))-0*(1+1)/(40-0)-1; scaled_average-pressure-(period) = average-pressure-(period)*(1+1)/(30.53000069-(29.47999954))-29.47999954*(1+1)/(30.53000069-29.47999954)-1; perceptron_layer_0_output_0 = tanh[ -0.176941 + (scaled_distance-to-solar-noon*0.899353)+ (scaled_temperature*-0.620422)+ (scaled_wind-direction*0.136902)+ (scaled_wind-speed*0.836426)+ (scaled_sky-cover*0.12677)+ (scaled_visibility*0.177673)+ (scaled_humidity*0.99292)+ (scaled_average-wind-speed-(period)*0.443054)+ (scaled_average-pressure-(period)*-0.994507) ]; perceptron_layer_0_output_1 = tanh[ -0.290833 + (scaled_distance-to-solar-noon*-0.221985)+ (scaled_temperature*-0.513855)+ (scaled_wind-direction*-0.931396)+ (scaled_wind-speed*0.848389)+ (scaled_sky-cover*0.985168)+ (scaled_visibility*-0.0263062)+ (scaled_humidity*0.330078)+ (scaled_average-wind-speed-(period)*-0.260864)+ (scaled_average-pressure-(period)*-0.255554) ]; perceptron_layer_0_output_2 = tanh[ 0.400513 + (scaled_distance-to-solar-noon*-0.969666)+ (scaled_temperature*0.269836)+ (scaled_wind-direction*-0.749023)+ (scaled_wind-speed*-0.764648)+ (scaled_sky-cover*0.419434)+ (scaled_visibility*0.692505)+ (scaled_humidity*-0.314514)+ (scaled_average-wind-speed-(period)*0.405884)+ (scaled_average-pressure-(period)*0.739563) ]; perceptron_layer_0_output_3 = tanh[ 0.624329 + (scaled_distance-to-solar-noon*0.475281)+ (scaled_temperature*-0.607056)+ (scaled_wind-direction*0.260742)+ (scaled_wind-speed*-0.190369)+ (scaled_sky-cover*0.662354)+ (scaled_visibility*0.73761)+ (scaled_humidity*0.216064)+ (scaled_average-wind-speed-(period)*0.854614)+ (scaled_average-pressure-(period)*0.157959) ]; perceptron_layer_0_output_4 = tanh[ 0.019043 + (scaled_distance-to-solar-noon*0.269653)+ (scaled_temperature*-0.166748)+ (scaled_wind-direction*0.554626)+ (scaled_wind-speed*-0.171143)+ (scaled_sky-cover*-0.333191)+ (scaled_visibility*0.243896)+ (scaled_humidity*0.0197754)+ (scaled_average-wind-speed-(period)*-0.169983)+ (scaled_average-pressure-(period)*-0.991638) ]; perceptron_layer_0_output_5 = tanh[ -0.243835 + (scaled_distance-to-solar-noon*0.578796)+ (scaled_temperature*0.753418)+ (scaled_wind-direction*-0.0349121)+ (scaled_wind-speed*0.94281)+ (scaled_sky-cover*-0.286865)+ (scaled_visibility*0.665833)+ (scaled_humidity*-0.105347)+ (scaled_average-wind-speed-(period)*-0.686279)+ (scaled_average-pressure-(period)*0.641052) ]; perceptron_layer_0_output_6 = tanh[ -0.579224 + (scaled_distance-to-solar-noon*0.20166)+ (scaled_temperature*-0.9953)+ (scaled_wind-direction*0.804138)+ (scaled_wind-speed*-0.209045)+ (scaled_sky-cover*-0.3573)+ (scaled_visibility*0.747437)+ (scaled_humidity*-0.83667)+ (scaled_average-wind-speed-(period)*0.595459)+ (scaled_average-pressure-(period)*-0.350708) ]; perceptron_layer_0_output_7 = tanh[ 0.880127 + (scaled_distance-to-solar-noon*-0.731995)+ (scaled_temperature*0.578369)+ (scaled_wind-direction*-0.372803)+ (scaled_wind-speed*0.102295)+ (scaled_sky-cover*-0.872192)+ (scaled_visibility*-0.247559)+ (scaled_humidity*0.613586)+ (scaled_average-wind-speed-(period)*-0.691589)+ (scaled_average-pressure-(period)*-0.0609741) ]; perceptron_layer_1_output_0 = [ -0.747375 + (perceptron_layer_0_output_0*0.643494)+ (perceptron_layer_0_output_1*0.631348)+ (perceptron_layer_0_output_2*0.720947)+ (perceptron_layer_0_output_3*-0.310059)+ (perceptron_layer_0_output_4*-0.123047)+ (perceptron_layer_0_output_5*0.611084)+ (perceptron_layer_0_output_6*-0.208069)+ (perceptron_layer_0_output_7*-0.706238) ]; unscaling_layer_output_0 = perceptron_layer_1_output_0*(36580-0)/(1+1)+0+1*(36580-0)/(1+1);

You can watch the step-by-step tutorial video below to help you complete this Machine Learning example for free using the powerful machine learning software, Neural Designer.