pvlib / pvlib-python

A set of documented functions for simulating the performance of photovoltaic energy systems.
https://pvlib-python.readthedocs.io
BSD 3-Clause "New" or "Revised" License
1.16k stars 980 forks source link

PVsyst inverter #1002

Open mikofski opened 4 years ago

mikofski commented 4 years ago

mimic pvsyst I would like to mimic pvsyst so as to be bankable

a pvsyst inverter Inverter model: efficiency says:

Set of 3 efficiency profiles: this is a more accurate definition: we define an efficiency profile as above for 3 different input voltages. At each step, the simulation will perform a quadratic interpolation between these 3 curves, as function of the real input voltage.

Sandia grid inverter model Any idea how the Sandia inverter model compares?

Other pvsyst inverters There are 4 options single curve, Euro per weighted efficiency, etc..

See also grid inverter-efficiency curve

cwhanse commented 4 years ago

I agree, pvlib.inverter.pvsyst would be a good addition. In the case of PVsyst option 3, input consisting of three efficiency curves at 3 input voltages, these data are typical for an inverter datasheet. Perhaps we can start there, since I don't know how PVsyst builds the curves from CEC efficiency and threshold power (option 4).

The Sandia inverter model assumes that the efficiency curves evolve linearly as the input DC voltage changes; as @Peque has pointed out, a given device might not follow that linear behavior. An interpolation would be more general.

Peque commented 4 years ago

Would it be interesting to support reading .ond files directly from pvlib? For what I know, it is a non-standard and not documented format used by PVSyst to import/export module data, so probably no... :joy: but maybe I am wrong (?).

btaute commented 4 years ago

The ability to read in .OND files (inverters) and .PAN files (modules) would be a big help for people trying to transition to pvlib from PVSyst.

cwhanse commented 4 years ago

I think @frivollier has shared some tools to read OND and PAN files. I would support adding capabilities to pvlib, either directly or by importing from @frivollier 's project if there's intention to maintain that project.

mikofski commented 4 years ago

CanadianSolar CASSYS is another source of code to parse and model inverters:

frivollier commented 4 years ago

Despite some good intentions I won’t be maintaining or updating this project to read PAN files but I could help anyone that want to take it over.

Fred

On Tue, Jul 14, 2020 at 3:15 PM Cliff Hansen notifications@github.com wrote:

I think @frivollier https://github.com/frivollier has shared some tools https://github.com/frivollier/pvsyst_tools to read OND and PAN files. I would support adding capabilities to pvlib, either directly or by importing from @frivollier https://github.com/frivollier 's project if there's intention to maintain that project.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/pvlib/pvlib-python/issues/1002#issuecomment-658363265, or unsubscribe https://github.com/notifications/unsubscribe-auth/AALHKPXBNGXK6JPUQJ5CFGTR3SVGZANCNFSM4OZDEGPA .

-- Frederic

kandersolar commented 2 years ago

In https://github.com/pvlib/pvlib-python/issues/1199#issuecomment-801431990 @cwhanse said:

That would be a nice addition to pvlib. But, to my knowledge the inverter model in Pvsyst is not fully documented. The Pvsyst license prohibits reverse engineering the software. Without reference to complete and open documentation, I don't think we can add inverter.pvsyst and claim that it's the model in Pvsyst.

Just curious, is that still the case? Do we expect to ever be able to address this feature request?

cwhanse commented 2 years ago

Just curious, is that still the case?

AFAIK, yes.

mikofski commented 2 years ago

Should we just close this issue? AFAIK pvsyst just interpolates between the curves to get the efficiency. I don't know how it compares to Sandia grid inverter model, but I think it can't be bad to have a function that just does that. I also think the ability to read PAN and OND files would be very helpful. And measurements from the CEC solar equipment lists too while we're at it.

def interp_inverter_eff(eff_curves, pdc_timeseries, vdc_timeseries, voltages, method="quadratic"):
    """
    interpolate inverter efficiency given 3 voltages

    Parameters
    ----------
    eff_curves : numpy.ndarray or pandas.DataFrame
        table of efficiencies with indices or first column as the DC power monotonically
        increasing and each consecutive column at a different monotonically increasing
        voltage corresponding to the ``voltages`` parameter
    pdc_timeseries : numpy.ndarray, pandas.Series, or pandas.DataFrame
    vdc_timeseries : numpy.ndarray, pandas.Series, or pandas.DataFrame 
    voltages : numeric
        a sequence or scalar of the corresponding nominal voltages, must be
        monotonically increasing and length must be same as columns in ``eff_curves``
    method : str
        how to interpolate the efficiency if given 3 voltages

    returns
    -------
    efficiency : numpy.ndarray or pandas.Series
    """
    eff_curves = pd.DataFrame(eff_curves, index_col=0)
    f = scipy.interpolate.interp1d(x=eff_curves.index, y=eff_curves)
    eff = f(pdc_timeseries)
    try:
        num_volts = len(voltages)
    except TypeError: 
        num_volts = 1
    else:
        if num_volts > 1:
            g = scipy.interpolate.interp1d(x=voltages, y=eff.T, kind=method)
            eff = g(vdc_timeseries)

    return eff
cwhanse commented 2 years ago

OK with me to close, or to keep the issue open. It would be nice to have the Pvsyst inverter model in pvlib, the real blocker is the lack of documentation.

mikofski commented 2 years ago

I'm not sure if the above function works, as you say, there's no docs - which according to the pvlib ethos means it doesn't go in - soo... how about a gallery example or we start a contrib folder?

cwhanse commented 2 years ago

The interpolation is simple enough that I'm ok adding it with the docstring being the reference, if you are persuaded that there's demand for it. It would fill a gap between the Sandia/adriesse models (which require fitting) and the PVWatts model (a single parameter), in that this interpolation could work from the data in the CEC listing or from digitized datasheet curves.

adriesse commented 2 years ago

Does anyone else see the irony here? The opening line is:

I would like to mimic pvsyst so as to be bankable

And:

It would be nice to have the Pvsyst inverter model in pvlib, the real blocker is the lack of documentation.

Please let the banks know!

adriesse commented 2 years ago

If you have some data and are tempted to use interpolation, I suggest you also give the fitting routine for the ADR inverter model a try. It is located here.

This model is well-documented, and being based on the summation of physically explained losses it is pretty much constrained to produce physically correct efficiency curves. If there is enough demand I can move it to pvlib.

adriesse commented 2 years ago

Maybe we could join forces and publish a paper with a title like "Bankability assessment of inverter simulation models" in a publication that bankers read.

frivollier commented 2 years ago

There might be details of the PVSYST inverter model in the CASSYS documentation. https://github.com/CanadianSolar/CASSYS/tree/master/Documents%20and%20Help

On Sat, Apr 9, 2022 at 3:39 AM Anton Driesse @.***> wrote:

Does anyone else see the irony here? The opening line is:

I would like to mimic pvsyst so as to be bankable

And:

It would be nice to have the Pvsyst inverter model in pvlib, the real blocker is the lack of documentation.

Please let the banks know!

— Reply to this email directly, view it on GitHub https://github.com/pvlib/pvlib-python/issues/1002#issuecomment-1093779207, or unsubscribe https://github.com/notifications/unsubscribe-auth/AALHKPXJQJCH73SN5FOYRWLVEEX35ANCNFSM4OZDEGPA . You are receiving this because you were mentioned.Message ID: @.***>

-- Frederic

cwhanse commented 2 years ago

We could implement the interpolation model described in CASSYS documentation, call it the CASSYS model, and point to the comparison with Pvsyst which shows the two models' results are close.

mikofski commented 2 years ago

Good idea, starts here.

adriesse commented 2 years ago

There are some graphs in these publications illustrating what can go wrong with generic numeric interpolation:

https://www.researchgate.net/project/PV-System-Simulation-Software-Validation

kurt-rhee commented 1 year ago

I found this thread while trying to mimic PVSyst's inverter efficiency model. I wrote a small script to try to emulate:

Notes:

image Figure 1: Inverter Curve Shape from quadratic interpolation

image Figure 2: Inverter Curve Shape from quadratic interpolation when 0, 0 point is added

image Figure 3: Cassys Source Code I am not the best C sharp programmer, but my understanding is that:

itsLowEff[0] = DC Power (point from inverter defined curve) itsLowEff[1] = Efficiency at DC Power DCPwrIn = DC Power from data (interpolant)

itsPresentEfficiencies[0] = Array of Low Voltage, Med Voltage and High Voltage from inverter defined curve itsPresentEfficiencies[1] = Array of interpolated efficiencies from linear interpolation

image Figure 4: PVSyst parameters for inverter efficiency

Emulation Script

import numpy as np
import pandas as pd
import plotly.graph_objects as go

# --- Efficiency Curves from OND ---
LowVoltage = 962
LowVoltageEffCurve = pd.DataFrame({
    'Power': [225, 447, 891, 1336, 2227, 3345, 4468],
    'Efficiency': [97.68, 98.47, 98.79, 98.83, 98.79, 98.66, 98.47]
})

MidVoltage = 1144
MidVoltageEffCurve = pd.DataFrame({
    'Power': [227, 449, 893, 1338, 2230, 3350, 4477],
    'Efficiency': [96.77, 98.01, 98.53, 98.63, 98.64, 98.52, 98.27]
})

HighVoltage = 1193
HighVoltageEffCurve = pd.DataFrame({
    'Power': [228, 449, 893, 1339, 2231, 3351, 4479],
    'Efficiency': [96.55, 97.95, 98.49, 98.57, 98.59, 98.47, 98.23]
})

VoltageLevels = [0, LowVoltage, MidVoltage, HighVoltage]

# --- Read in performance data ---
df = pd.read_csv('inverter.csv')
df['DC Power at MPP (kW)'] = df['DC Power at MPP (W)'] / 1000

# --- Do Interpolations ---
xs = []
ys = []
for i, row in df.iterrows():
    x = row['DC Power at MPP (kW)']
    v = row['DC Voltage at MPP (V)']

    # --- given power, predict efficiency ---
    LowVoltageCoeff = np.polynomial.polynomial.polyfit(
        LowVoltageEffCurve['Power'], LowVoltageEffCurve['Efficiency'], deg=1
    )
    MedVoltageCoeff = np.polynomial.polynomial.polyfit(
        MidVoltageEffCurve['Power'], MidVoltageEffCurve['Efficiency'], deg=1
    )
    HighVoltageCoeff = np.polynomial.polynomial.polyfit(
        HighVoltageEffCurve['Power'], HighVoltageEffCurve['Efficiency'], deg=1
    )

    LowVoltageEfficiency = (LowVoltageCoeff[1] * x) + LowVoltageCoeff[0]
    MidVoltageEfficiency = (MedVoltageCoeff[1] * x) + MedVoltageCoeff[0]
    HighVoltageEfficiency = (HighVoltageCoeff[1] * x) + HighVoltageCoeff[0]
    EfficiencyLevels = [0, LowVoltageEfficiency, MidVoltageEfficiency, HighVoltageEfficiency]

    QuadFitCoeff = np.polynomial.polynomial.polyfit(
        VoltageLevels,
        EfficiencyLevels,
        deg=2
    )

    y = (
        (QuadFitCoeff[2] * (v ** 2)) +
        (QuadFitCoeff[1] * v) +
        (QuadFitCoeff[0])
    )

    xs.append(x)
    ys.append(y)

fig = go.Figure()
fig.add_scatter(
    x=xs,
    y=ys,
    mode='markers'
)
fig.show(renderer='browser')
kurt-rhee commented 1 year ago

I also tried modifying @mikofski 's code to go line by line, it gives the correct curve orientation, but I had to add some new points at 0 for the scipy functions to complete the interpolation. This may give the curve a more linear shape [Figure 1]

image Figure 1

import numpy as np
import pandas as pd
import scipy
import plotly.graph_objects as go

eff_curves = {
    'power': [0, 227, 449, 893, 1338, 2230, 3350, 4477],
    'v1': [0, 97.68, 98.47, 98.79, 98.83, 98.79, 98.66, 98.47],
    'v2': [0, 96.77, 98.01, 98.53, 98.63, 98.64, 98.52, 98.27],
    'v3': [0, 96.55, 97.95, 98.49, 98.57, 98.59, 98.47, 98.23]
}
eff_curves = pd.DataFrame(eff_curves)
eff_curves = eff_curves.set_index('power')

voltages = [0, 962, 1144, 1193]

df = pd.read_csv('inverter.csv')
df['DC Power at MPP (kW)'] = df['DC Power at MPP (W)'] / 1000

f1 = scipy.interpolate.interp1d(x=eff_curves.index, y=eff_curves['v1'])
f2 = scipy.interpolate.interp1d(x=eff_curves.index, y=eff_curves['v2'])
f3 = scipy.interpolate.interp1d(x=eff_curves.index, y=eff_curves['v3'])

xs = []
ys = []
for i, row in df.iterrows():
    x = row['DC Power at MPP (kW)']
    v = row['DC Voltage at MPP (V)']
    eff1 = f1(x)
    eff2 = f2(x)
    eff3 = f3(x)
    try:
        num_volts = len(voltages)
    except TypeError:
        num_volts = 1
    else:
        if num_volts > 1:
            g = scipy.interpolate.interp1d(x=voltages, y=[0, eff1, eff2, eff3], kind='quadratic')
            y = g(v)
    xs.append(x)
    ys.append(y)

fig = go.Figure()
fig.add_scatter(
    x=xs,
    y=ys,
    mode='markers'
)
fig.show(renderer='browser')
kurt-rhee commented 1 year ago

Playing around with this a little bit more, here are pictures of different types of linear interpolations and their resulting quadratic interpolations:

None give the expected output, so there must be something else that I am missing.

  1. Linear Interpolation, not including 0,0 image image

  2. Linear Interpolation, including 0,0 image image

  3. Piecewise Linear Interpolation, not including 0, 0 image image

  4. Piecewise Linear Interpolation, including 0, 0 image image

kandersolar commented 1 year ago

I have written the code below to linearly interpolate using all available points, and therefore the resulting interpolation is not piecewise. This was done to match the Cassys implementation.

I interpret the PVsyst description to be "piecewise interpolation". I don't think a linear least-squares fit to all points in each curve is what is meant; it wouldn't be my first interpretation for the word "interpolation", and it doesn't make sense to fit straight lines to the full efficiency curves anyway. The CASSYS implementation is also "piecewise" in the linear Pdc interpolation:

https://github.com/CanadianSolar/CASSYS/blob/b5487bb4e9e77174c805d64e3c960c46d357b7e2/CASSYS%20Engine/Interpolate.cs#L38

I haven't run any code myself but @mikofski's code in https://github.com/pvlib/pvlib-python/issues/1002#issuecomment-1089095634 looks right to me: linear interpolation (not least-squares fit) to get low/medium/high efficiencies for the given Pdc, then quadratic interpolation between those three efficiencies for the given Vdc. Maybe adding (0,0) is needed if the curves in the OND files don't include it already.

I wasn't sure why the efficiency curved was divided by input power.

I can't make sense of that either. Strange.

kurt-rhee commented 1 year ago

I agree, least squares would be throwing away good data points.