Green Data, Part 4: Understanding and Calibrating the Data into Operation

Contributed by

13 min read

This blog post is fourth of a 5-part series that explores the use of IoT and Data Science to maximize solar energy by leveraging the MapR Data Platform. Read the previous 3 blog posts here, here, and here.

So my data confirms that I have some weird behavior, but now I want to finish understanding the math of "how can I know what optimum is?" After reading the paper from the NREL (, I realized that I already had the information I needed in order to calculate it.

Essentially, the NREL paper breaks down determining the optimum angle of a single axis tracker to:

R = tan-1(X) + ψ


R is the Optimum Rotation angle of the panels along the axis


With the variables defined as:

θΖ - The Zenith Angle of the sun (or 90 - the sun's altitude)

γS - The Solar Azimuth, or the position of the sun around a circle, 0 degrees being due north, 180 being due south

γα - The Axis Azimuth of the array. This is 180, in that the down slope of my arrays point due south or 180 degrees.

βα - Axis Tilt. This is the angle from the back of the array to the front, when the panels are flat.

And as to the value of ψ, it's dependent on the result of X.

So, being perfectly honest, this function made my head swim. Once I stared at it long enough, I realized I needed four variables. The axis tilt and axis azimuth were easy. These are static for both arrays. Axis tilt is 20 degrees and axis azimuth is 180 degrees.

The sun zenith angle and azimuth are also easy to obtain for any given time, using the Python module I mentioned earlier called Pysolar ( This allows me to provide a date, local time, latitude, and longitude, and it will return the sun's altitude and azimuth.I wondered why I needed to provide longitude, and questioned if it was even needed, and yet again, my colleague Dr. Ted Dunning pointed out that without it, the calculations could be quite a bit off, given our longitudinal placement in a timezone. Thus, providing longitude IS needed for an accurate solar time calculation and accurate sun positions relative to where we are.

So, given that equation, I wrote a Python function that took those 4 variables and returned the optimum rotation along the axis. (Note that the equation wants zenith, not altitude, so I changed that right away in the function by subtracting the altitude from 90 degrees to get the zenith.) All of the Python math module's trigonometry functions expect variables and return results in radians; my function takes all things in degrees, and returns degrees, so I needed to handle that on return.

The result of this math is a simple function:

The initial results seemed promising, and after working out some syntax errors and other minor math flubs, I was ready to test the equation on my panel data.

Testing the Math

Now that I had a function, I could not only implement in my tracking program but also, since I've been collecting data (including the sun azimuth and altitude at the time), actually do some graphing to see how it WOULD have done in the past. Unfortunately, November appears to be the arch nemesis of solar production, so my sampling of days is not verbose. Here are a few examples with discussion on each.

Note, the first query on these examples is to determine the conversion factor from the sensor. We are using rough math here, but the max rotation is 41 degrees, and then I take the max and the min of the sensor readings, average them, and then divide them by my actual angle to get my conversion x factor. I then use that in my query to return the actual angle rather than the sensor reading. This allows me to graph it next to the optimal sun rotation angle returned from the function. Anything returned from the optimal sun function beyond 41 or -41 is just the limitation of the tracker motion: I can't physically move my array past those rotations.

A Side Note: Measuring Angles Correctly

The 41 degrees range is the accurate number for these arrays; however, for a time, I was using 50 to -50 degrees as my rotational range. I obtained 50 degrees by attempting to manually measure (poorly) the array as it was tilted. After I measured it, I realized a couple of things:

  1. The accuracy of my measurement was poor, and I knew it. I didn't have the right tools to measure the angle, and I basically "eyed" it up. This is not defensible.
  2. The rotational angle range should be calculable, especially if I had some more data.

In order to get a more defensible measurement for rotational angle, I reached out to the helpful folks at U.S. Solar Mounts; they stated that the array was designed to have a max surface angle range of -45 degrees to 45 degrees. Surface angle takes into account the axis tilt (20 degrees). When I looked at the NREL paper, they gave a function to determine surface tilt as:

cos-1((rotational angle) (axis tilt))

When I used this function to model out all the potential rotation angles, I realized that to get the 45 degree surface tilt, my ACTUAL rotation angle was very near 41. Thus, this is what I use in my calculations. It's better to use an equation here than a poorly obtained physical measurement.

Now that we know the rotational angle calculations and have the data from the sensors, let's look at a few days to graph the array position as well as where the rotational angle SHOULD be based on the NREL function. For each of these, I include some observations.

North Array, November 2nd (A Pretty Good Solar Day)


  • The tracker did not like the time before 10:00. It should have stayed east but did not; the sun, maybe snow, maybe frost on the sensor, etc., had it facing the wrong way.
  • Due to clouds, etc., the tracking did not track well between 10:00 and 11:00 and between 12:15 and 15:00.
  • The line tracked close, but not exactly with the optical eye. More on that later.
  • I did not have data from the south array on Nov. 2nd.

North Array, November 3rd (A Great Solar Day)


  • As we can see here, when the tracker is tracking (from around 11:40 to around 12:50), the derived optimum (orange) and the actual (produced via optical tracking) are right in line, if perhaps off by a bit. We may be able to say that is due to the optical eye only accounting for azimuth and not angle.

  • More thought given: It's due to me, using min/max to calibrate sensors rather than averages; I will explain later in this blog post!

  • There are parts, though, where the eye goes haywire and looks the wrong way (from around 10:30 to 11:40 and 12:50 to around 13:30).

  • In addition to the "tracking window" goofiness, the eye was really upset in the morning between 8:45 and 9:30-ish. The tracker SHOULD have stayed at 41 degrees here, but frost on the lens or something else caused it to move around.
  • The spikes between 15:00 and 16:00 are me, testing motor control for the first time.

South Array, November 3rd (A Great Solar Day)


  • Once again, morning sun is compromised by a confused tracker until around 10:30.
  • The tracker rights itself at around 10:30, but then tracks poorly until 11:30.
  • At 11:30 to almost 13:00, the tracker is spot-on.
  • 13:00 to 13:45 must have had some clouds that confused things until getting back on for the rest of the day.

Calibrating the Sensors – Averages vs. Min/Max

In the above graphs, even when trackers ARE tracking correctly, there is sometimes a space between the tracker line and the optimal line. After some testing done on Nov. 13, I realized that it comes from poor calibration of the sensors.

Essentially, when the array is all the way west or all the way east, the sensor (for example, on the north array) would use values from 1345.0 (east) to -1308.0 (west). I mentioned this earlier. However, earlier I was taking the MAX or MIN of these values to determine my range. But this is a sensor that takes hundreds of readings per second, and I am only sampling a few times. The min/max readings are not actually indicative of whether the array is full east or full west; min/max are actually outliers. So what I did is: over a couple of days, I took large time blocks that indicate the array is full east or full west and averaged the values in that position. Instead of using the min/max, I've used the derived averages for those time frames.

Example Math for the South Array

Essentially, I graphed it for two days, and then took some of the blocks of full east or full west and found averages; once I did that, I got an angle factor of 29.451. This actually helps both of my array graphs: both are now spot-on (see the following graphs for tracking today, Nov. 13).

Note: The south array is not fully calibrated from a mechanical perspective. I realized I need to set the arm length on the actuator to be exactly halfway when the array is perfectly level. I've done it fairly accurately on the north array, but it's November in Wisconsin, and it's cold. I'd like to spend some time dialing that in with some help, as I need to adjust the arm that holds the panels in place. Right now, it's "close enough" for me, and I will work on that when the days are bit warmer.

Results with Better Sensor Calibration

North Array, November 13th (A Very Sunny Day)


  • This is one of my first days when I let the equation from NREL control one of the arrays.
  • You can see a step approach here: at first it was moved every 10 minutes; I changed that to every 5 minutes (the steps get shorter).
  • There is a little notch right after 8:00 am; that's me, adjusting my angles.
  • The data is tracking perfectly on this array, even though the south array is showing issues with some clouds.
  • As of update (12:30), this array (north, NREL equation) has 9.5 kWh of production vs. 9.21 kWh of production on the south array (optical). Small amounts for sure, but a difference!

South Array, November 13th (A Very Sunny Day)


  • The optical eye tracks more often than every 10 or 5 minutes (possibly every minute?). So the graphs track closer together.
  • Other than that, with the perfect sun, if the tracker starts out correctly, the optical eye does track well, until it doesn't.
  • On both arrays, on Nov. 13th, using the averages for the sensors, rather than the min/max, we do MUCH better in aligning the optimal sun rotation from the function to what the array is doing.
  • We had some clouds go through around 11:00 and persist throughout the afternoon. The tracker went off and never really got back to tracking solidly.

The data looks promising. We will review the results in the next and final blog post of the series.

This blog post was published January 02, 2019.

50,000+ of the smartest have already joined!

Stay ahead of the bleeding edge...get the best of Big Data in your inbox.

Get our latest posts in your inbox

Subscribe Now