pvlib-python icon indicating copy to clipboard operation
pvlib-python copied to clipboard

PVsyst inverter

Open mikofski opened this issue 4 years ago • 19 comments

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

mikofski avatar Jul 14 '20 03:07 mikofski

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.

cwhanse avatar Jul 14 '20 17:07 cwhanse

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 (?).

Peque avatar Jul 14 '20 18:07 Peque

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.

btaute avatar Jul 14 '20 19:07 btaute

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.

cwhanse avatar Jul 14 '20 19:07 cwhanse

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

mikofski avatar Jul 14 '20 20:07 mikofski

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 [email protected] 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

frivollier avatar Jul 14 '20 23:07 frivollier

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?

kandersolar avatar Apr 05 '22 14:04 kandersolar

Just curious, is that still the case?

AFAIK, yes.

cwhanse avatar Apr 05 '22 14:04 cwhanse

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

mikofski avatar Apr 05 '22 17:04 mikofski

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.

cwhanse avatar Apr 05 '22 17:04 cwhanse

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?

mikofski avatar Apr 05 '22 18:04 mikofski

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.

cwhanse avatar Apr 05 '22 18:04 cwhanse

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 avatar Apr 09 '22 07:04 adriesse

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 avatar Apr 09 '22 08:04 adriesse

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.

adriesse avatar Apr 09 '22 08:04 adriesse

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

frivollier avatar Apr 09 '22 13:04 frivollier

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.

cwhanse avatar Apr 10 '22 19:04 cwhanse

Good idea, starts here.

mikofski avatar Apr 11 '22 06:04 mikofski

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

adriesse avatar Apr 11 '22 07:04 adriesse

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

Notes:

  • I wrote the script to calculate the final efficiency in a looping fashion so that I could step through individual values.
  • I am not sure if PVSyst is linearly interpolating the efficiency vs power curves at each respective voltage using all available points in the curve or if it is generating a piecewise linear interpolation. 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.
  • The quadratic interpolation gives an upside down curve if a point is not added for efficiency=0 at voltage=0 [Figure 1], a curve with those points added to the interpolation is in [Figure 2] though this makes the curve much too square. I noticed in the Cassys source code [Figure 3] that the efficiency curve at a given power is divided by the input power, which is not done in the python code below. I wasn't sure why the efficiency curved was divided by input power.
  • I have hardcoded some values from an SMA Sunny Central 4400 Inverter [Figure 3].

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 avatar Mar 03 '23 05:03 kurt-rhee

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 avatar Mar 03 '23 05:03 kurt-rhee

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

kurt-rhee avatar Mar 03 '23 18:03 kurt-rhee

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.

kandersolar avatar Mar 03 '23 20:03 kandersolar

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

kurt-rhee avatar Mar 04 '23 00:03 kurt-rhee