0

I have solar data in the format:

enter image description here

I want to convert the time index to hour angle using the pvlib package. So far my code reads in the input data from a .csv file using pandas and extracts the time data. I need to convert this data (in 30-minute intervals) into hour angles, but I keep getting the error:

TypeError: index is not a valid DatetimeIndex or PeriodIndex

Here is my code so far:

# Import modules
import pandas as pd
import pvlib

# Read in data from .csv file for time and DHI
headers = ["Time","DHI"]
data_file = pd.read_csv("path to csv file",names=headers)
time_data = data_file["Time"]

# Find equation of time for hour angle calc
equation_of_time = pvlib.solarposition.equation_of_time_spencer71(1)

# Find hour angle
hour_angle = pvlib.solarposition.hour_angle(time_data, -89.401230, equation_of_time)
MUD
  • 121
  • 1
  • 13

2 Answers2

3

As the error message states, the issue is that your index is not a DateTimeIndex. To calculate the hour angle we need to know the specific time, hence the need for a DateTimeIndex. Right now you are simply passing in a list of integers, which doesn't have any meaning to the function.

Let's first create a small example:

import pandas as pd
import pvlib

df = pd.DataFrame(data={'time': [0,570,720], 'DHI': [0,50,100]})
df.head()

   time  DHI
0     0    0
1   570   50
2   720  100

# Create a DateTimeIndex:
start_date = pd.Timestamp(2020,7,28).tz_localize('Europe/Copenhagen')
df.index = start_date + pd.to_timedelta(df['time'], unit='min')

Now the DataFrame has looks like this:

                           time  DHI
time                                
2020-07-28 00:00:00+02:00     0    0
2020-07-28 09:30:00+02:00   570   50
2020-07-28 12:00:00+02:00   720  100

Now we can pass the index to the hour angle function as it represents unique time periods:

equation_of_time = pvlib.solarposition.equation_of_time_spencer71(df.index.dayofyear)

# Find hour angle
hour_angle = pvlib.solarposition.hour_angle(df.index, -89.401230, 
                                         equation_of_time)

Note how the start date was localized to a specific time zone. This is necessary unless that you're data is UTC as otherwise the index does not represent unique time periods.

Adam R. Jensen
  • 617
  • 5
  • 12
  • Thank you for taking the time to write such a thorough explanation! This is really helpful! – MUD Jul 28 '21 at 22:59
  • 1
    There is one issue, it won't allow me to add the start date and timestamp: TypeError: unsupported operand type(s) for +: 'Timestamp' and 'float' – MUD Jul 28 '21 at 23:38
  • 1
    @UnaDavies I suggest using pd.to_timedelta like this: `start_date + pd.to_timedelta(df['time'], unit='min')` – kevinsa5 Jul 29 '21 at 01:46
  • 1
    @UnaDavies Yes that was clearly a mistake on my part. As the column represents a time offset it has to be converted to a timedelta as kevinsa5 commented. I have updated the solution. Welcome to pvlib! – Adam R. Jensen Jul 30 '21 at 02:34
  • Based on the day of year and longitude given in the question I would suggest `start_date = pd.Timestamp(2020,1,1).tz_localize('Etc/GMT+6')` Time zone Copenhagen produces the wrong hour angle for that location. – adr Jul 30 '21 at 12:26
3

The answer by @Adam_Jensen is good, but not the simplest. If you look at the code for the hour_angle function, you will see that 2/3 of it is devoted to turning those timestamps back into integers. The rest is so easy you do not need pvlib.

# hour_angle and equation_of_time are defined in the question

LONGITUDE = -89.401230
LOCAL_MERIDIAN =  -90

hour_angle = (LONGITUDE - LOCAL_MERIDIAN) + (time_data - 720 + equation_of_time) / 4

It's always good to understand what's going on under the hood!

adr
  • 1,731
  • 10
  • 18