Giter Club home page Giter Club logo

pvmismatch's People

Contributors

adambgnr avatar ahoffmanspwr avatar bmeyers avatar chetan201 avatar kandersolar avatar mikofski avatar nzweibaum avatar rayhickey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pvmismatch's Issues

don't keep copies of identical objects (eg cells)

observed: large systems take up too much system memory

proposed: don't make separate copies of objects until absolutely necessary.

instead of making copies and tracking all objects as individuals, just reference the same copy of identical objects. for example: when making a module, rather than copying the cell 96 or 128 times, just reference the same cell until there are differences. Ditto for modules - if all the modules in a string are identical, just reference the same module rather than making cheap copies until needed. in other words only create as many objects, the minimum, as needed to describe the characteristics and condition of the system.

issues:

  • requires caching of the references somewhere. for example: the cells that reference the cell object could be cached in the modules in a cached_cells field as a dictionary. Instead, an easier way is to just keep the lists the same, and put the reference you want in there. see my 1st comment below
  • requires tracking of cell changes in object (eg cell) characteristics like temperature, shunt and series resistance, etc.

also profiling to demonstrate this is an improvement over current methods is required.

update GITHUB_OAUTH_TOKEN in .travis.yml

This token GITHUB_OAUTH_TOKEN is probably no good anymore for uploading Python wheels and source distros to GitHub anymore. You'll have to generate a new one, or ask @cedricleroy to do it and either add it directly to the travis build settings as a secret environment variable, or use their CLI to create a secure encrypted token that you add to .travis.yml - read their docs.

See the build log from travis where it tried to deploy to GitHub:

Logged in as Mark Mikofski
Deploying to repo: SunPower/PVMismatch
Current tag is: v3.2.1
POST https://api.github.com/repos/SunPower/PVMismatch/releases: 404 - Not Found
See: https://developer.github.com/v3/repos/releases/#create-a-release (Octokit::NotFound)


For PyPI, I don't know what the hell is wrong with it. It's possible that because it couldn't deploy to GitHub, and it tries that first, it just quit, and if that had succeeded it would have worked? Regardless, I already deployed it to PyPI this time. And for next time, you should have your own PyPI account, and so you can change the pypi username and password in travis.

remove local versions of pvconst, to make sure that different pvconst can be used

PVMismatch can use different PVconstants for strings and modules, which in certain situations can provide a system where each string has its own pvconstants or systems can share PVconstants as previously as well. Therefore PVMismatch CAN have modules and strings with different temperatures and cell properties through some very clever use of pvconstants in pvmismatch. See the example below where we create a system with 2 strings, ie one east facing and one west facing that have different properties, in this case only temperature is different.

Unfortunately, this granularity of control is limited to strings and above, but I think it can easily be extended to modules, and the extremely few places where it’s broken can be patched. There are a few cases where a larger component, eg: a PVstring exerts its own version of PVconstants on its constituents, but in all of those cases, there are like 4, the property used is not actually a module property, eg: number of points, etc, or the way it’s used doesn’t affect the calculation. Nevertheless, delegation to the constituent should be the paradigm everywhere.

Why does it work? Because each component - modules and strings – have their own PVconstants object that contains cell parameters and cell temperatures. Originally my intention was that all of the components in a system model would share a single PVconstants object, however, you can create a system with two strings each which uses its own PVconstants object as in the example below. Or in a more complex example, you could create a string made of modules that each have different PVconstants objects, then combine strings together to make the system.

Remember that modules and strings can share PVconstants objects so you only need to create as many as needed.

EG:

pvconst_lowtemp ---- >|pvmod1|
                     |pvmod2|
                      |pvmod3|
                             |
pvconst_normaltemp - >|pvmod4|
                      |pvmod5|---- >|pvstr1 |
                      |pvmod6|              |
                      |pvmod7|              |
                             |              |
pvconst_hitemp ----- >|pvmod8|              |
                                            |---- >|pvsys
pvconst_hiRsh ------ >|pvmod9 |             |
                      |pvmod10|             |
                      |pvmod11|             |
                      |pvmod12|             |
                      |pvmod13|---- >|pvstr2|
                      |pvmod14|
                      |pvmod15|
                      |pvmod16|

Here’s an example:

# import pvmismatch packages
from pvmismatch import *

# low temp string
pvconst_0C = pvconstants.PVconstants(Tcell=(0+273.15))  # a low temperature set of constants
pvstr_0C = pvstring.PVstring(pvconst=pvconst_0C)  # string with low temperature modules

# high temp string
# a high temperature set of constants
pvconst_100C = pvconstants.PVconstants(Tcell=(100+273.15))
pvstr_100C = pvstring.PVstring(pvconst=pvconst_100C)  # string with high temperature modules

# system with 1 low temp string and 1 high temp string
pvsys = pvsystem.PVsystem(pvstrs=[pvstr_0C, pvstr_100C])

# low temp system
pvsys_0C = pvsystem.PVsystem(pvconst=pvconstants.PVconstants(
    Tcell=(0+273.15)),numberStrs=2
)
# high temp system
pvsys_100C = pvsystem.PVsystem(pvconst=pvconstants.PVconstants(
    Tcell=(100+273.15)),numberStrs=2
)

refactor pvcell.PVcell.__setattr__ or constructor to only set Icell, Vcell, and Pcell only once

The pcell.PVcell() constructor sets Icell, Vcell, and Pcell to None which calls the __setattr__() overload which calls calcCells() and sets Icell, Vcell, and Pcell again!

The constructor calls to self.__setattr__(key, value) look like this:

setting attribute Rs to 0.004267236774264931
setting attribute Rsh to 10.01226369025448
setting attribute Isat1_T0 to 2.28618816125344e-11
setting attribute Isat2 to 1.117455042372326e-06
setting attribute Isc0_T0 to 6.3056
setting attribute aRBD to 0.0001036748445065697
setting attribute bRBD to 0.0
setting attribute VRBD to -5.527260068445654
setting attribute nRBD to 3.284628553041425
setting attribute Eg to 1.1
setting attribute alpha_Isc to 0.0003551
setting attribute Tcell to 298.15
setting attribute Ee to 1.0
setting attribute pvconst to <PVconstants(npts=101)>
setting attribute Icell to None
setting attribute Vcell to None
setting attribute Pcell to None

Since __setattr__() checks to see if pvconst attribute exists, therefore it doesn't calculate Icell, Vcell, and Pcell until the end, but then it sets them again, calling calcCells() again and again and again.

I think just move the pvconst setting in the constructor to the last position, or maybe add an _calc_now flag might be more explicit. something like:

_calc_now = False
def __init__(self, Rs=RS, Rsh=RSH, Isat1_T0=ISAT1_T0, Isat2=ISAT2,
             Isc0_T0=ISC0_T0, aRBD=ARBD, bRBD=BRBD, VRBD=VRBD_,
             nRBD=NRBD, Eg=EG, alpha_Isc=ALPHA_ISC,
             Tcell=TCELL, Ee=1., pvconst=PVconstants()):
    # user inputs
    self.Rs = Rs  #: [ohm] series resistance
    self.Rsh = Rsh  #: [ohm] shunt resistance
    self.Isat1_T0 = Isat1_T0  #: [A] diode one sat. current at T0
    self.Isat2 = Isat2  #: [A] diode two saturation current
    self.Isc0_T0 = Isc0_T0  #: [A] short circuit current at T0
    self.aRBD = aRBD  #: reverse breakdown coefficient 1
    self.bRBD = bRBD  #: reverse breakdown coefficient 2
    self.VRBD = VRBD  #: [V] reverse breakdown voltage
    self.nRBD = nRBD  #: reverse breakdown exponent
    self.Eg = Eg  #: [eV] band gap of cSi
    self.alpha_Isc = alpha_Isc  #: [1/K] short circuit temp. coeff.
    self.Tcell = Tcell  #: [K] cell temperature
    self.Ee = Ee  #: [suns] incident effective irradiance on cell
    self.pvconst = pvconst  #: configuration constants
    self.Icell = None  #: cell currents on IV curve [A]
    self.Vcell = None  #: cell voltages on IV curve [V]
    self.Pcell = None  #: cell power on IV curve [W]
    # set calculation flag
    self._calc_now = True  # overwrites the class attribute

def __setattr__(self, key, value):
    try:
        value = np.float64(value)
    except (TypeError, ValueError):
        pass
    super(PVcell, self).__setattr__(key, value)
    # after all attributes have been initialized, recalculate IV curve
    # every time __setattr__() is called
    if self._calc_now:
        Icell, Vcell, Pcell = self.calcCell()
        super(PVcell, self).__setattr__('Icell', Icell)
        super(PVcell, self).__setattr__('Vcell', Vcell)
        super(PVcell, self).__setattr__('Pcell', Pcell)

I think this is kinda relevant to #48, or at least the last bit where it says, "all calculations should wait until all new parameters are set," but I thought that was already mentioned in another issue. Maybe the other issue was #15? Anyway, the reason why I think this is relevant to that part of the issue is because if you need to delay calculation of the cell, then just set pvc._calc_now = False and it won't self update until you set it to True again.

But this issue isn't directly related to #48 which is more about creating a single update method that copies cells, modules or strings as needed when updating irradiance, cell-temperature, or any parameter, instead of having methods for each parameter, eg setsuns() and settemps() which are nearly identical and repeated in pvmodules and pvstrings. See the TODO in the code.

This is easy to do in the PVcell.update() method:

def update(self, **kwargs):
    """
    Update user-defined constants.
    """
    # TODO: use __dict__.update()
    # self.__dict__.update(kwargs)
    # TODO: check for floats and update IV curve
    # * __setattr__ already checks for floats
    # turn off calculation flag until all attributes are updated to save time
    self._calc_now = False
    for k, v in kwargs.iteritems():
        setattr(self, k, v)
    self._calc_now = True  # recalculate

package data is not installed

need to move everything down one level to include package data.

IE: currently

PVMismatch
|
* pvmismatch/
|
* pvmismatch_tk/
|
* pvmismatch_json/
|
* docs/
|
* setup.py

proposed

PVMismatch
|
* pvmismatch/
|  |
|  * pvmismatch_lib/
|  |
|  * pvmismatch_tk/
|  |
|  * pvmismatch_json/
|  |
|  * docs/
|
* setup.py

System setSuns TypeError

When using the system setSuns method to set the Ee on a whole panel, the Ee must be a sequence, not a float as in the documentation. Example in documentation is given as Ee={3: {8: 0.23, 7: 0.45}}. Must use Ee={3: {8: [0.23], 7: [0.45]}} or Ee={3: {8: (0.23,), 7: (0.45,)}} to allow for list unpacking (or "splat").

make flexible breakdown model

From issue #25:

Another even better option would be to allow any expression to be used as the breakdown current, and implement this as an object that the user can pass to the PVcell class instead of specifying the parameters aRBD, bRBD, nRBD and VRBD.

Currently user can only specify breakdown parameters and use the model in pvcell.PVcell(). Remove these parameters and instead specify some user specified object that has a boilerplate implementation, ie: it returns the Irbd when called or when its Irbd() method is called.

Decide on any implementation appropriate.

Class example:

class my_rbd_class():
    def Irbd(self, Vd):
        return self.Isc0_T0*(self.a_rbd*(Vd/self.Rsh/self.Isc0_T0) +
            self.b_rbd*(Vd/self.Rsh/self.Isc0_T0)^2)*(1-Vd/self.Vrbd)^-self.nRBD

Lambda example:

my_rbd_lambda = lambda Vd: Isc*(a_rbd*(Vd/Rsh/Isc) +
    b_rbd*(Vd/Rsh/Isc)^2)*(1-Vd/Vrbd)^-nRBD

Function example:

def my_rbd_func(Vd):
    return self.Isc0_T0*(self.a_rbd*(Vd/self.Rsh/self.Isc0_T0) +
        self.b_rbd*(Vd/self.Rsh/self.Isc0_T0)^2)*(1-Vd/self.Vrbd)^-self.nRBD

Diode behavior in PVstring

PVstring model doesn't allow for a module's diodes to be completely activated. See email sent to Mark M. on 4/28/13.

PVconst behavior

If building a PVsystem from PVcell, PVmodule, and PVstring instances, there is an option for the user to set pvconst each time. If the user does not set the kwarg, the instance of that class defaults to the default PVConstant() instance. This is confusing. For instance, if it set npts=1001 in my creation of my PVcell object, and then pass that object to my PVmodule instantiation and then my PVsystem instantiation, I would expect npts to propogate, but it does not.

split pvconst into pvcell and configs to facilitate individual cell props

this is related to #11. If pvconstant is split into a pvcell class and a config class then modules, strings and the system can have any number of combinations of cells, but there are a few properties that are just configuration properties for the entire model, those should go into a new configs object, that is common to all objects. Details to follow

Setting module size for traditional SPWR modules

You used to be able to quickly set the module size from a PVsystem instance (numberCells=128, etc.), and you used to be able to quickly see what size module made up a system with pvsystem.numberCells. I'm assuming these were removed to allow for the new Tetris configurations, but they were really convenient.

Also, am I understanding the new method correctly that to create a system of 128-cell modules, I first need to import standard_cellpos_pat from pvmismatch_lib.pvmodule and pass standard_cellpos_pat(16, [2, 4, 2]) to the cell_pos arguement in PVmodule, and then pass that PVmodule instance to PVsystem? If I am missing the fast way to do this, please let me know, but this is pretty burdensome relative to the old method.

Temperature dependence of Voc and Vmp are wrong

Problem:
A plot of Voc vs. cell temperature shows decreasing below about zero degrees.
voc-vs-t-is-wrong

Should look like this
voc-correct

Possibly the lack of temperature dependence of Isat2 is the culprit?

Proposed:
Use cubic temperature dependence for Isat2 same as for Isat1.

addressed in #64

two diode tests failing

As mentioned in #54, test_two_diode.py where failing because of changes to SymPy.

Traceback (most recent call last):
  File "pvmismatch\contrib\gen_coeffs\tests\test_two_diode.py", line 63, in test_didv_dpdv_frsh
    fdidv_expected = np.float(didv_simple.evalf(subs=expected_data))
  File "python27\lib\site-packages\sympy\core\expr.py", line 239, in __float__
    raise TypeError("can't convert expression to float")
TypeError: can't convert expression to float

Single cell parameter update method

There should be a single method that allow for updates to any current and future cell parameters at the system, string, and module level. The method should allow for Ee, Tcell, and other parameters to be passed as nested dictionaries, and all calculations should wait until all new parameters are set. For example, if a particular cell is getting its irradiance, temperature, and shunt resistance values changed, the cell IV curves should only be updated after all three parameters have been set.

create pvmod attr for pvcell

  • set to None, only used if in a module, used to tell module I'm updated
  • ditto for modules to strings and strings to systems

should it be possible to create standard module using crossties

If you make a cell position pattern that mimics a standard serpentine module the simulation fails.

>>> std72 = [
 [[{'circuit': 'series', 'idx': 0},
   {'circuit': 'series', 'idx': 1},
   {'circuit': 'series', 'idx': 2},
   {'circuit': 'series', 'idx': 3},
   {'circuit': 'series', 'idx': 4},
   {'circuit': 'series', 'idx': 5},
   {'circuit': 'series', 'idx': 6},
   {'circuit': 'series', 'idx': 7},
   {'circuit': 'series', 'idx': 8},
   {'circuit': 'series', 'idx': 9},
   {'circuit': 'series', 'idx': 10},
   {'circuit': 'parallel', 'idx': 11}],
  [{'circuit': 'parallel', 'idx': 23},
   {'circuit': 'series', 'idx': 22},
   {'circuit': 'series', 'idx': 21},
   {'circuit': 'series', 'idx': 20},
   {'circuit': 'series', 'idx': 19},
   {'circuit': 'series', 'idx': 18},
   {'circuit': 'series', 'idx': 17},
   {'circuit': 'series', 'idx': 16},
   {'circuit': 'series', 'idx': 15},
   {'circuit': 'series', 'idx': 14},
   {'circuit': 'series', 'idx': 13},
   {'circuit': 'series', 'idx': 12}]],
 [[{'circuit': 'series', 'idx': 24},
   {'circuit': 'series', 'idx': 25},
   {'circuit': 'series', 'idx': 26},
   {'circuit': 'series', 'idx': 27},
   {'circuit': 'series', 'idx': 28},
   {'circuit': 'series', 'idx': 29},
   {'circuit': 'series', 'idx': 30},
   {'circuit': 'series', 'idx': 31},
   {'circuit': 'series', 'idx': 32},
   {'circuit': 'series', 'idx': 33},
   {'circuit': 'series', 'idx': 34},
   {'circuit': 'parallel', 'idx': 35}],
  [{'circuit': 'parallel', 'idx': 47},
   {'circuit': 'series', 'idx': 46},
   {'circuit': 'series', 'idx': 45},
   {'circuit': 'series', 'idx': 44},
   {'circuit': 'series', 'idx': 43},
   {'circuit': 'series', 'idx': 42},
   {'circuit': 'series', 'idx': 41},
   {'circuit': 'series', 'idx': 40},
   {'circuit': 'series', 'idx': 39},
   {'circuit': 'series', 'idx': 38},
   {'circuit': 'series', 'idx': 37},
   {'circuit': 'series', 'idx': 36}]],
 [[{'circuit': 'series', 'idx': 48},
   {'circuit': 'series', 'idx': 49},
   {'circuit': 'series', 'idx': 50},
   {'circuit': 'series', 'idx': 51},
   {'circuit': 'series', 'idx': 52},
   {'circuit': 'series', 'idx': 53},
   {'circuit': 'series', 'idx': 54},
   {'circuit': 'series', 'idx': 55},
   {'circuit': 'series', 'idx': 56},
   {'circuit': 'series', 'idx': 57},
   {'circuit': 'series', 'idx': 58},
   {'circuit': 'parallel', 'idx': 59}],
  [{'circuit': 'parallel', 'idx': 71},
   {'circuit': 'series', 'idx': 70},
   {'circuit': 'series', 'idx': 69},
   {'circuit': 'series', 'idx': 68},
   {'circuit': 'series', 'idx': 67},
   {'circuit': 'series', 'idx': 66},
   {'circuit': 'series', 'idx': 65},
   {'circuit': 'series', 'idx': 64},
   {'circuit': 'series', 'idx': 63},
   {'circuit': 'series', 'idx': 62},
   {'circuit': 'series', 'idx': 61},
   {'circuit': 'series', 'idx': 60}]]
]
>>> pvsys = pvsystem.PVsystem(numberMods=8, numberStrs=2, pvmods=pvmodule.PVmodule(std72))
---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-29-5843f6d31c33> in <module>()
----> 1 pvsys2 = pvsystem.PVsystem(numberMods=8, numberStrs=2, pvmods=pvmodule.PVmodule(std72a))

C:\Users\mmikofski\Documents\Projects\PVMismatch\pvmismatch\pvmismatch_lib\pvmodule.pyc in __init__(self, cell_pos, pvcells, pvconst, Vbypass, cellArea)
    131         self.subStrCells = [len(_) for _ in self.cell_pos]  #: cells per substr
    132         # initialize members so PyLint doesn't get upset
--> 133         self.Imod, self.Vmod, self.Pmod, self.Vsubstr = self.calcMod()
    134
    135     # TODO: use __getattr__ to check for updates to pvcells

C:\Users\mmikofski\Documents\Projects\PVMismatch\pvmismatch\pvmismatch_lib\pvmodule.pyc in calcMod(self)
    257                             # TODO: use pvmismatch exceptions
    258                             raise Exception(
--> 259                                 "First row and last rows must be crosstied."
    260                             )
    261                         elif len(idxs) > 1:

Exception: First row and last rows must be crosstied.

make sure Vmax for all strings is greater than Vmp of system

observed: if some strings have lower Vmax than others, then linear extrapolation using the last 2 points in the string with the lower Vmax is used which is arbitrary. This is especially an issue if the practical operating point of the system (ie: Vmp) is at a voltage greater than Vmax of any of the strings. Then the current of the low Vmax strings is arbitrarily determined by the linear extrapolation and the uncertainty is unknown.

proposed: Set Vmax for all of the strings to be Voc at STC.

use cheap copies with setsuns

observed: calling setsuns(Ee=x.x) takes a very long time if the pv system is very large, even if all of the objects in the system are identical.

proposed: check cell temperatures, and use cheap copies to duplicate cells that are identical, rather than calculating them individually, the same way that pv modules, strings and systems are created.

The previous proposal (crossed out above) was a great idea, but if issue #35 is implemented, then this proposal isn't relevant. And moreover if calling setsuns(Ee=<scalar>) then using the tips and tricks: the better/faster way is to make a new system.

new proposal: Assuming issue #35 is implemented, then it now becomes setsuns() methods job to create cells (using cheap copies of course) as needed.

** example**:

  1. create a system with Ee=<scalar> - the entire system is represented by one cell, one module and one string, with a cached_<obj> dictionary in system, string and module mapping which cells, modules and strings point to the cached references. EG: cached_strings = [0, 0, 0, 0, 0, 0] for 6 strings that all point to the reference zero, cached_modules = [0, 0, 0, 0, 0, ...] for a string of modules that all point to the reference of module zero, and `cached_cells = [0, 0, 0, 0, ...] for modules cells that all point to the reference of cell zero. For ease, if the cached list is a scalar, then we can assume that all of that objects items point to that reference. This is covered in detail in #35. (see comments in #35, caches are NOT necessary)
  2. change irradiance with setsuns(Ee={0, {0, {'cells': (0, 1, 2), 'Ee': (0.34, 0.45, 0.56)}}} - setsuns job is to figure out which cells need to be created now, so in this example we need 3 new cells,
    1. so use cheap copies to create 3 new cells from the previous cell, for examples, see PVsystem, PVstring or PVmodule and
    2. update the system, string and module cells directly, same as before caches (#35) to point to the new references.EG_: cached_strings = [1, 0, 0, 0, 0, 0] since now there are two string references, one new string and five old, cached_modules = [1, 0, 0, 0, 0, ...] for the new string with the new shaded module, and `cached_cells = [1, 2, 3, 0, ...] for the new module with the 3 new shaded cells. The entire system is now represented by 4 cells, 2 modules and 2 strings. (see comments in #35, caches are NOT necessary)
  3. As a further improvement, setsuns could also check if there are any duplicate cells (or modules or strings) either in the setsuns call or already existing in the system.
    1. For example if all 3 cells in the previous example are set to 0.5 suns then we only need one new cell, and the system is represented by 2 cells, 2 modules and 2 strings.
    2. Another example is if we further modify the previous example and add another cell with 0.56 irradiance, instead of creating another new cell, just point it to the duplicated that was previously created.

cache last X calculations, and be smarter about checking cache before recalculating

This is definitely relevant to #48 and is a spinoff of @bmeyers original cache idea in the rejected PR #42 , and a continuation of the accepted PR #43, that closed the relevant issues #34 and #35 about copies, and of course the ability to delay calculation #59.

The idea is simple, every time you make a calculation in __setattr__ or in calcCells():

  1. check the cache for a similar cell, it's hash should be identical
  2. if the cell doesn't exist yet, then calculate it and store the cell in a cache, like @bmeyers does in #42 except just store the entire PVcell, no need to serialize it (the cell) right now

The cache should be in pvconstants and should probably have a limit of 100 or 1000 cells. Any strategy can be used to determine which cells to keep in the cache, for example, a count could be kept of how many times each cell was called, and then the least popular cells are culled as needed.

This cache could be repeated for modules and strings as well.

sample code:

from pvmismatch import *

# pvconstants
pvconst = pvconstants.PVconstants()
# monkey patch for example
pvconst.cache = {'pvcells': {}, 'pvmods': {}, 'pvstrs': {}}
pvconst.cache_maxsize = 100

PARAMS = ['Rs', 'Rsh', 'Isat1_T0', 'Isat2_T0', 'Isc0_T0', 'aRBD', 'bRBD', 'VRBD', 'nRBD', 'Eg', 'alpha_Isc', 'Tcell', 'Ee']

def hash_cell(cell, params=PARAMS):
    """cell params is a dictionary with cell params"""
    cell_params = vars(cell)
    cell_hash = str()
    for k in params:
        cell_hash += hex(hash(cell_params[k]))[2:]  # omit '0x'
    return '0x%s' % cell_hash

This works! Generate two different PVcells that are identical, but have different memory locations, and the calculated hash is the same.

>>> pvc = pvcell.PVcell()
>>> cell_hash = hash_cell(pvc)
'0x22f50b4c78e2706476d29247d00a1c997714032461851a3c0257edda00dc9c779a6b50b10061000d96c02215ef60x10df5081cebee80591bad56da435c033333333333334011802e8b2dc60be864cccccccccc012a1'
>>> pvconst.cache['pvcells'][cell_hash ] = pvc  # cache cell for future
>>> id(pvc)
1880798536480  # different
>>> hash(pvc)
117549908530  # different

>>> pvsys = pvsystem.PVsystem()
>>> new_cell_hash = hash_cell(pvsys.pvstrs[0].pvmods[0].pvcells[0])
'0x22f50b4c78e2706476d29247d00a1c997714032461851a3c0257edda00dc9c779a6b50b10061000d96c02215ef60x10df5081cebee80591bad56da435c033333333333334011802e8b2dc60be864cccccccccc012a1'
>>> new_cell_hash in pvconst.cache['pvcells']
True
>>> id(pvsys.pvstrs[0].pvmods[0].pvcells[0])
1880798601344  # different
hash(pvsys.pvstrs[0].pvmods[0].pvcells[0])
117549912584  # different

then in PVmodules

# in #48 update method
def update(self, cell_dicts):
    for pvc, params in cell_dicts.item():
        cell_params = vars(self.pvcells[pvc])
        cell_params.pop('Icell')
        cell_params.pop('Vcell')
        cell_params.pop('Pcell')
        cell_params.pop('pvconst')
        cell_params.pop('_calc_now')
        cell_params.update(params)
        cell_hash = pvconstants.hash_cell(cell_params)
        if cell_hash in self.pvconst.cache['pvcells']:
            # use cache
             self.pvcells[pvc] = self.pvconst.cache['pvcells'][cell_hash]
        else:
            # make a new cell
            self.pvcells[pvc] = pvcell.PVcell(**params, pvconst=self.pvconst)
            self.pvconst.cache['pvcells'][cell_hash] = self.pvcells[pvc]           

Zener reverse breakdown is not modelled only avalance breakdown

Current method is to use avalanche breakdown

Irbd = a_rbd*(Vd/Rsh)*(1-Vd/Vrbd)^-nRBD

The proposed method is to add a quadratic term to soften the shoulder of the breakdown like a Zener diode. It's a hybrid approach that should be easy to implement in PVMismatch.

Zener breakdown
zener_breakdown

Irbd = Isc*(a_rbd*(Vd/Rsh/Isc) + b_rbd*(Vd/Rsh/Isc)^2)*(1-Vd/Vrbd)^-nRBD

New 2nd order term: b_rbd*(Vd/Rsh/Isc)^2

Another even better option would be to allow any expression to be used as the breakdown current, and implement this as an object that the user can pass to the PVcell class instead of specifying the parameters aRBD, bRBD, nRBD and VRBD.

The plot below shows the measured and simulated breakdown response.

Tetris breakdown plot

Equation rendering by Online LaTeX Equation Editor API
CodeCogs - An Open Source Scientific Library

tips and tricks section

There are a few tricks that aren't obvious, so should there be a tips section of the docs?

For example, it is usually faster to create a new PVsystem then change every single cell in the system to a new irradiance.

>>> %%timeit
...     pvm = pvmodule.PVmodule(pvcells=pvcell.PVcell(Ee=0.88))
...     pvsys = pvsystem.PVsystem(pvmods=pvm)
# 1 loop, best of 3: 486 ms per loop

>>> %timeit pvsys.setSuns(0.75)
# 1 loop, best of 3: 1.38 s per loop

For example if you are trying to do a full day simulation of a shadow passing over the array, then to set the ambient effective irradiance on the cells at each timestep, you should call pvsys = pvsystem.PVsystem() at each timestep instead of pvsys.setSuns().

multi-thread calcMod

  • add multi-threading to calcMod to decrease runtime
  • benchmark accuracy/consistency with old code
  • benchmark speed vs unthreaded

Inconsistency in applying setSuns to entire objects (modules, strings, array)

Setting all modules in all strings and all modules in a given string to a single effective irradiance value works as indicated by the docstring:

Ee=0.91  # set all modules in all strings to 0.91 suns
Ee={12: 0.77}  # set all modules in string with index 12 to 0.77 suns

However, to set all cells in a single module to one irradiance value, you need to wrap the irradiance in a list: Ee={3: {8: [0.23], 7: [0.45]}}. This is inconsistent with the array and string methods, and it is not reflected in the documentation, which states that the correct form is: Ee={3: {8: 0.23, 7: 0.45}}.

In the current implementation, if one is building a autovivicated dictionary for Ee, you need to do the following for an array, string, and module, respectively:

self.Ee = Ee_shade
self.Ee[strng] = Ee_shade
self.Ee[strng][mod] = [Ee_shade]

As a reference, here's what I do to set the values for individual cells:

self.Ee[strng][mod]['cells'] = []
self.Ee[strng][mod]['Ee'] = []
self.Ee[strng][mod]['cells'].append(self.cell_pattern[ind])
self.Ee[strng][mod]['Ee'].append(Ee_shade)

or

self.Ee[strng][mod]['Ee'].append(m * a + 1)

Where,

a = cell_box.intersection(poly).area
m = Ee_shade - 1

PVModule IV curve has no knees

Hi!

I am simulating shading on a STD72 module to test microinverter MPPT tracking. I am passing the PVmodule.setSuns function a np.ndarray with values between 0.2 and 1.0 as a shade passes over the module. However, the IV curve produced does not seem to have the "knees" that we would expect.

I am attaching an mp4 file of the animation, as well as the Python script I am using. I apologize for how poorly structured and commented it is. It is a work in progress (scaffolding!).

Any help or insight would be greatly appreciated!

panel_animation.zip

dynamic_shading.zip

use lookup table for 2-diode parameters (a la SAM)

related to #50 and #51

At PVSC Janine Freeman introduced a great idea to nearly eliminate errors from diode-analog cell models, which was to use a lookup table.

Since we already have the pvmismatch.contrib.gen_coeffs methods, all we need is to loop over it so it creates an IEC-61853 table but for Isat1, Isat2, Rs and Rsh instead of Imp, Vmp, Isc, and Voc.

Then we would have to add the interpolation methods into pvmismatch.pvcell or at least the option to.

create a contrib folder for examples of cell position patterns

let's not put hard coded examples of instances of pvmodules into pvmismatch. instead lets create a parallel package called contrib inside the top package, pvmismatch and parallel to pvmismatch_lib that contains contributed code that isn't part of the main toolbox but is still useful enough to be included.

System setSun: passing multiple values to single module

Passing multiple values to a single module causes only the first value to be applied to the first cell, and nothing else. Would expect an error or for the second value to apply to the second cell of the module

Example:

In [24]: sys1.setSuns({3: {8: [0.23, 0.5]}})

In [25]: sys1.pvstrs[3].pvmods[8].Ee

array([[ 0.23, 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. , 1. ,
1. , 1. , 1. , 1. , 1. , 1. ]])

update method for pvmod, pvstring and pvsystem

  • new method that calls calcmod(), calcString() and calcSystem() and updates attributes
  • optionally could also set parameters, drilling down, just like SetSuns() does now.
  • optionally could have delayed recalculation, if setting many parameters.

Allow user to use connection matrix

Allow the user to define a system-level, inter-module topology through an arbitrary connection indicator matrix. Allow for:

  • PCT
  • TCT
  • Honeycomb
  • Bridge-Link

See, for example:

[1] C. A. Ramos-Paja, J. D. Bastidas, A. J. Saavedra-Montes, F. Guinjoan-Gispert, and M. Goez, “Mathematical model of total cross-tied photovoltaic arrays in mismatching conditions,” 2012 IEEE 4th Colomb. Work. Circuits Syst. CWCAS 2012 - Conf. Proc., 2012.
[2] S. Malathy and R. Ramaprabha, “Comprehensive analysis on the role of array size and configuration on energy yield of photovoltaic systems under shaded conditions,” Renew. Sustain. Energy Rev., vol. 49, pp. 672–679, 2015.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.