-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Kimber Dynamic Soiling model #669
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
@mikofski @cwhanse regarding soiling rate, the authors arrived at a range of .1% - .3% a day, using a sample of 46 projects. Given that, I'm wondering if there is a better way than simply splitting the difference and assuming a static value of .2% in the model. The random and localized nature of this loss factor in particular presents a challenge. It seems we can either assume static values for the 3 parameters based on the averages provided by Kimber, or derive them from historical weather data (which might not always be available). Thoughts? I'd like to help write this method, but want to agree on a defensible approach. |
Hi @tahentx, But there are other soiling models, so maybe we should provide a few others as well:
|
@tahentx, here's an idea, could you make these parameters arguments? def soiling_kimber(rainfall_timeseries, soiling_rate_daily=0.0015, grace_period=14,
rain_threshold=30, locale='rural', scheduled_cleaning_dates=None):
"""
Kimber model reference. If soiling rate is None, and locale is set,
then defaults are used. See ref.
"""
return soiling This way user could override default. BTW: Thanks for taking this on! |
@tahentx I mostly agree with @mikofski. One primary purpose of pvlib is to provide model implementation that is faithful to the literature. In this case, a function that implement's Kimber's model (and only Kimber's model) is the first step. Where I disagree is the suggestion to assign defaults to parameters. Where the paper recommends a parameter value, that value should be provided as the default. I didn't see that Kimber's paper provides values for any of the three parameters (in fact I didn't see an equation for the soiling loss percent in terms of soiling rate, cleaning threshold and grace period). If this is the case, I'd leave it to the user to assign appropriate values. |
Sorry I must have linked to the wrong paper, or maybe the Kimber model was internal only to SunPower. If there's no reference to the soiling loss equation, then I'm in favor of closing this in lieu of another soiling model. |
@cwhanse AFAIK that is the right paper, but perhaps it's not an equation, it's just an algorithm: import pandas as pd
import datetime
def soiling_kimber_mitchell(rainfall_timeseries, threshold=6, soiling_rate=0.0015,
grace_period=14, max_soiling=0.3, manual_wash_dates=None):
"""
Parameters
----------
rainfall_timeseries : pandas.DataFrame
a timeseries of rainfall in millimeters
threshold : float, default 6[mm]
the amount of rain in millimeters [mm] required to clean the panels
soiling_rate: float, default 0.15%
daily soiling rate, enter as fraction, not percent
grace_period: int, default 14-days
The time after a rainfall event when it's assumed the ground is damp, and
so it's assumed there is no soiling. Change to smaller value for dry climate
max_soiling: float, default 30%
maximum soiling, soiling will accumulate until this value
manual_wash_dates: sequence or None, default None
A list or tuple of dates when the panels were manually cleaned. Note there
is no grace period after a manual cleaning, so soiling begins to accumulate
immediately after a manual cleaning, sorry :(
Returns
-------
soiling : timeseries
the daily soiling
"""
# manual wash dates
if manual_wash_dates is None:
manual_wash_dates = []
# resample rainfall as days by summing intermediate times
rainfall = pd.resample(rainfall_timeseries, freq="D").sum()
# soiling
soiling = np.zeros_like(rainfall)
# rainfall events that clean the panels
rain_events = rainfall > thresh
# loop over days
for today in rainfall.index:
# did rain exceed threshold?
rain_exceed_thresh = rainfall[today] > threshold
# if yes, then set soiling to zero
if rain_exceed_thresh:
soiling[today] = 0
continue
# start day of grace period
start_day = today - grace_period
# rainfall event during grace period?
rain_in_grace_period = any( rain_events [ start_day : today ] )
# if rain exceeded threshold during grace period,
# assume ground is still damp, so no or v. low soiling
if rain_in_grace_period:
soiling[today] = 0
continue
# is this a manual wash date?
if today in manual_wash_dates:
soiling[today] = 0
continue
# so, it didn't rain enough to clean, it hasn't rained enough recently,
# and we didn't manually clean panels, so soil them by adding daily
# soiling rate to soiling from previous day
total_soil = soiling[today - datetime.timedelta(days=1)] + soiling_rate
# check if soiling has reached the maximum
soiling[today] = max_soiling if (total_soil >= max_soiling) else total_soil
soiling = np.interp(rainfall_timeseries.index, rainfall.index, soiling)
return pd.DataFrame(rainfall_timeseries.index, soiling) WARNING: this is hacky bad psuedocode, needs to be rewritten by someone smart :) |
related to #61 and #668.
Kimber dynamic soiling model has 3 parameters:
The text was updated successfully, but these errors were encountered: