0
# Clear Sky Models
1
2
Calculate clear sky irradiance using multiple models including Ineichen, Bird, Haurwitz, and simplified SOLIS. Clear sky models provide baseline irradiance estimates for system modeling, clear sky detection, and performance analysis.
3
4
## Capabilities
5
6
### Ineichen Clear Sky Model
7
8
The most commonly used clear sky model, recommended by the IEA Task 12 and WMO.
9
10
```python { .api }
11
def ineichen(apparent_zenith, airmass_absolute, linke_turbidity,
12
altitude=0, dni_extra=1366.1):
13
"""
14
Calculate clear sky irradiance using Ineichen model.
15
16
Parameters:
17
- apparent_zenith: numeric, apparent solar zenith angle in degrees
18
- airmass_absolute: numeric, absolute airmass
19
- linke_turbidity: numeric, Linke turbidity factor
20
- altitude: numeric, altitude above sea level in meters
21
- dni_extra: numeric, extraterrestrial direct normal irradiance (W/m^2)
22
23
Returns:
24
OrderedDict with keys:
25
- ghi: global horizontal irradiance (W/m^2)
26
- dni: direct normal irradiance (W/m^2)
27
- dhi: diffuse horizontal irradiance (W/m^2)
28
"""
29
```
30
31
### Bird Clear Sky Model
32
33
Physically-based clear sky model with detailed atmospheric parameter inputs.
34
35
```python { .api }
36
def bird(zenith, airmass_relative, aod380, aod500, precipitable_water,
37
ozone=0.3, pressure=101325.0, dni_extra=1366.1,
38
asymmetry=0.85, albedo=0.2):
39
"""
40
Calculate clear sky irradiance using Bird model.
41
42
Parameters:
43
- zenith: numeric, solar zenith angle in degrees
44
- airmass_relative: numeric, relative airmass
45
- aod380: numeric, aerosol optical depth at 380 nm
46
- aod500: numeric, aerosol optical depth at 500 nm
47
- precipitable_water: numeric, precipitable water in cm
48
- ozone: numeric, ozone in atm-cm
49
- pressure: numeric, atmospheric pressure in pascals
50
- dni_extra: numeric, extraterrestrial direct normal irradiance (W/m^2)
51
- asymmetry: numeric, aerosol asymmetry parameter
52
- albedo: numeric, ground albedo
53
54
Returns:
55
OrderedDict with keys:
56
- ghi: global horizontal irradiance (W/m^2)
57
- dni: direct normal irradiance (W/m^2)
58
- dhi: diffuse horizontal irradiance (W/m^2)
59
"""
60
```
61
62
### Haurwitz Clear Sky Model
63
64
Simple empirical clear sky model requiring only solar zenith angle.
65
66
```python { .api }
67
def haurwitz(apparent_zenith):
68
"""
69
Calculate clear sky GHI using Haurwitz model.
70
71
Parameters:
72
- apparent_zenith: numeric, apparent solar zenith angle in degrees
73
74
Returns:
75
numeric, global horizontal irradiance (W/m^2)
76
"""
77
```
78
79
### Simplified SOLIS Clear Sky Model
80
81
Simplified version of the SOLIS clear sky model.
82
83
```python { .api }
84
def simplified_solis(apparent_elevation, aod700=0.1, precipitable_water=1.0,
85
pressure=101325.0, dni_extra=1366.1):
86
"""
87
Calculate clear sky irradiance using simplified SOLIS model.
88
89
Parameters:
90
- apparent_elevation: numeric, apparent solar elevation angle in degrees
91
- aod700: numeric, aerosol optical depth at 700 nm
92
- precipitable_water: numeric, precipitable water in cm
93
- pressure: numeric, atmospheric pressure in pascals
94
- dni_extra: numeric, extraterrestrial direct normal irradiance (W/m^2)
95
96
Returns:
97
OrderedDict with keys:
98
- ghi: global horizontal irradiance (W/m^2)
99
- dni: direct normal irradiance (W/m^2)
100
- dhi: diffuse horizontal irradiance (W/m^2)
101
"""
102
```
103
104
### Linke Turbidity Lookup
105
106
Look up Linke turbidity values from monthly climatology database.
107
108
```python { .api }
109
def lookup_linke_turbidity(time, latitude, longitude, filepath=None,
110
interp_turbidity=True):
111
"""
112
Look up Linke turbidity values from climatology database.
113
114
Parameters:
115
- time: pandas.DatetimeIndex, times for lookup
116
- latitude: float, decimal degrees north
117
- longitude: float, decimal degrees east
118
- filepath: str, path to Linke turbidity file
119
- interp_turbidity: bool, interpolate turbidity values
120
121
Returns:
122
pandas.Series, Linke turbidity values
123
"""
124
```
125
126
### Clear Sky Detection
127
128
Detect clear sky conditions from measured irradiance data.
129
130
```python { .api }
131
def detect_clearsky(measured, clearsky, times=None, infer_limits=False,
132
window_length=10, mean_diff=75, max_diff=75,
133
lower_line_length=-5, upper_line_length=10,
134
var_diff=0.005, slope_dev=8, max_iterations=20,
135
return_components=False):
136
"""
137
Detect clear sky conditions from measured vs. clear sky irradiance.
138
139
Parameters:
140
- measured: pandas.Series or DataFrame, measured irradiance
141
- clearsky: pandas.Series or DataFrame, clear sky irradiance
142
- times: pandas.DatetimeIndex, timestamps
143
- infer_limits: bool, infer detection limits from data
144
- window_length: int, window length for moving statistics
145
- mean_diff: numeric, mean difference threshold
146
- max_diff: numeric, maximum difference threshold
147
- lower_line_length: numeric, lower line length parameter
148
- upper_line_length: numeric, upper line length parameter
149
- var_diff: numeric, variance difference threshold
150
- slope_dev: numeric, slope deviation threshold
151
- max_iterations: int, maximum number of iterations
152
- return_components: bool, return intermediate results
153
154
Returns:
155
pandas.Series or tuple, clear sky mask and optional components
156
"""
157
```
158
159
## Usage Examples
160
161
### Basic Ineichen Clear Sky Calculation
162
163
```python
164
import pvlib
165
from pvlib import clearsky, solarposition, atmosphere
166
import pandas as pd
167
168
# Location and time
169
lat, lon = 40.0583, -74.4057 # Princeton, NJ
170
times = pd.date_range('2023-06-21', periods=24, freq='H', tz='US/Eastern')
171
172
# Solar position
173
solar_pos = solarposition.get_solarposition(times, lat, lon)
174
175
# Atmospheric parameters
176
airmass = atmosphere.get_relative_airmass(solar_pos['zenith'])
177
airmass_abs = atmosphere.get_absolute_airmass(airmass)
178
179
# Look up Linke turbidity (or use typical value)
180
linke_turbidity = 3.0 # Typical value for mid-latitudes
181
182
# Calculate clear sky irradiance
183
clear_sky = clearsky.ineichen(
184
apparent_zenith=solar_pos['apparent_zenith'],
185
airmass_absolute=airmass_abs,
186
linke_turbidity=linke_turbidity
187
)
188
189
print("Time, GHI, DNI, DHI")
190
for i in range(8, 16): # Show daytime hours
191
time_str = times[i].strftime('%H:%M')
192
ghi = clear_sky['ghi'].iloc[i]
193
dni = clear_sky['dni'].iloc[i]
194
dhi = clear_sky['dhi'].iloc[i]
195
print(f"{time_str}, {ghi:.0f}, {dni:.0f}, {dhi:.0f}")
196
```
197
198
### Bird Clear Sky Model with Detailed Atmospheric Parameters
199
200
```python
201
import pvlib
202
from pvlib import clearsky, solarposition, atmosphere
203
import pandas as pd
204
205
# Location and conditions
206
lat, lon = 35.05, -106.54 # Albuquerque, NM (high altitude, dry)
207
times = pd.date_range('2023-06-21 12:00', periods=1, tz='US/Mountain')
208
209
# Solar position
210
solar_pos = solarposition.get_solarposition(times, lat, lon, altitude=1619)
211
zenith = solar_pos['zenith'].iloc[0]
212
213
# Atmospheric parameters for high altitude, dry location
214
airmass_rel = atmosphere.get_relative_airmass(zenith)
215
aod380 = 0.1 # Low aerosol loading
216
aod500 = 0.05
217
precipitable_water = 0.8 # Low water vapor
218
ozone = 0.25 # Typical ozone
219
pressure = atmosphere.alt2pres(1619) # Pressure at altitude
220
221
# Calculate clear sky irradiance
222
clear_sky = clearsky.bird(
223
zenith=zenith,
224
airmass_relative=airmass_rel,
225
aod380=aod380,
226
aod500=aod500,
227
precipitable_water=precipitable_water,
228
ozone=ozone,
229
pressure=pressure
230
)
231
232
print(f"Bird clear sky model results:")
233
print(f"GHI: {clear_sky['ghi']:.0f} W/m²")
234
print(f"DNI: {clear_sky['dni']:.0f} W/m²")
235
print(f"DHI: {clear_sky['dhi']:.0f} W/m²")
236
```
237
238
### Comparing Clear Sky Models
239
240
```python
241
import pvlib
242
from pvlib import clearsky, solarposition, atmosphere
243
import pandas as pd
244
import matplotlib.pyplot as plt
245
246
# Location and time
247
lat, lon = 40.0583, -74.4057
248
times = pd.date_range('2023-06-21 06:00', '2023-06-21 18:00',
249
freq='H', tz='US/Eastern')
250
251
# Solar position and atmospheric parameters
252
solar_pos = solarposition.get_solarposition(times, lat, lon)
253
airmass_rel = atmosphere.get_relative_airmass(solar_pos['zenith'])
254
airmass_abs = atmosphere.get_absolute_airmass(airmass_rel)
255
256
# Model comparisons
257
results = {}
258
259
# Ineichen model
260
results['Ineichen'] = clearsky.ineichen(
261
solar_pos['apparent_zenith'], airmass_abs, linke_turbidity=3.0
262
)
263
264
# Haurwitz model (GHI only)
265
results['Haurwitz'] = {'ghi': clearsky.haurwitz(solar_pos['apparent_zenith'])}
266
267
# Simplified SOLIS model
268
results['SOLIS'] = clearsky.simplified_solis(
269
solar_pos['apparent_elevation'],
270
aod700=0.1,
271
precipitable_water=1.5
272
)
273
274
# Print comparison at solar noon
275
noon_idx = 12
276
print("Clear sky model comparison at solar noon:")
277
print(f"{'Model':<10} {'GHI':<6} {'DNI':<6} {'DHI':<6}")
278
for model_name, data in results.items():
279
ghi = data['ghi'].iloc[noon_idx] if hasattr(data['ghi'], 'iloc') else data['ghi'][noon_idx]
280
dni = data.get('dni', [0]*len(times))
281
dhi = data.get('dhi', [0]*len(times))
282
if hasattr(dni, 'iloc'):
283
dni_val = dni.iloc[noon_idx]
284
dhi_val = dhi.iloc[noon_idx]
285
else:
286
dni_val = dni[noon_idx]
287
dhi_val = dhi[noon_idx]
288
print(f"{model_name:<10} {ghi:<6.0f} {dni_val:<6.0f} {dhi_val:<6.0f}")
289
```
290
291
### Clear Sky Detection
292
293
```python
294
import pvlib
295
from pvlib import clearsky, solarposition, atmosphere
296
import pandas as pd
297
import numpy as np
298
299
# Generate synthetic clear sky and measured data
300
lat, lon = 40.0583, -74.4057
301
times = pd.date_range('2023-06-21', periods=24, freq='H', tz='US/Eastern')
302
303
# Solar position and clear sky
304
solar_pos = solarposition.get_solarposition(times, lat, lon)
305
airmass_abs = atmosphere.get_absolute_airmass(
306
atmosphere.get_relative_airmass(solar_pos['zenith'])
307
)
308
clear_sky = clearsky.ineichen(
309
solar_pos['apparent_zenith'], airmass_abs, linke_turbidity=3.0
310
)
311
312
# Create synthetic measured data with some cloudy periods
313
np.random.seed(42)
314
measured_ghi = clear_sky['ghi'].copy()
315
# Add some clouds (reduce irradiance) for certain hours
316
cloudy_hours = [9, 10, 14, 15]
317
for hour in cloudy_hours:
318
measured_ghi.iloc[hour] *= 0.3 + 0.4 * np.random.random()
319
320
# Detect clear sky periods
321
clear_mask = clearsky.detect_clearsky(
322
measured=measured_ghi,
323
clearsky=clear_sky['ghi'],
324
times=times
325
)
326
327
print("Clear sky detection results:")
328
print("Hour, Measured GHI, Clear Sky GHI, Clear Sky?")
329
for i in range(8, 17): # Daytime hours
330
hour = times[i].hour
331
measured = measured_ghi.iloc[i]
332
clear = clear_sky['ghi'].iloc[i]
333
is_clear = clear_mask.iloc[i]
334
print(f"{hour:2d}:00, {measured:6.0f}, {clear:6.0f}, {is_clear}")
335
```
336
337
### Location-Specific Linke Turbidity
338
339
```python
340
import pvlib
341
from pvlib import clearsky
342
import pandas as pd
343
344
# Multiple locations with different turbidity characteristics
345
locations = [
346
{'name': 'Rural', 'lat': 45.0, 'lon': -100.0}, # Clean rural
347
{'name': 'Urban', 'lat': 40.7, 'lon': -74.0}, # Urban pollution
348
{'name': 'Desert', 'lat': 25.0, 'lon': 55.0}, # Desert dust
349
]
350
351
times = pd.date_range('2023-01-01', '2023-12-31', freq='MS')
352
353
print("Monthly Linke turbidity values:")
354
print(f"{'Month':<10}", end='')
355
for loc in locations:
356
print(f"{loc['name']:<8}", end='')
357
print()
358
359
for i, time in enumerate(times):
360
print(f"{time.strftime('%b'):<10}", end='')
361
for loc in locations:
362
try:
363
lt = clearsky.lookup_linke_turbidity(
364
pd.DatetimeIndex([time]),
365
loc['lat'],
366
loc['lon']
367
)
368
print(f"{lt.iloc[0]:<8.2f}", end='')
369
except:
370
print(f"{'N/A':<8}", end='')
371
print()
372
```