Skip to content
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

Just making sure I'm not barking up the wrong tree ... #137

Open
abooda1981 opened this issue Nov 22, 2020 · 4 comments
Open

Just making sure I'm not barking up the wrong tree ... #137

abooda1981 opened this issue Nov 22, 2020 · 4 comments

Comments

@abooda1981
Copy link

Hello all. I've received a lot of help from @mikofski and @adambgnr for which I'm very grateful. I will need to run this kind of calculation for roughly ~ 1 year worth of data, I just wanted to make sure this isn't some weird mistake on my part. My codes below should be more or less self explanatory, but I will also offer some commentary.

FWIW (and I don't think it changes much), I'm using Python in R through the reticulate package and just trying to limit the routines that are actually written in Python. The only reason I'll mention this is you might notice some indexes are strange (eg, 60 elements start with 1 and end with 60 and not 0 and 59).

Here's where I begin, it's a set of irradiances which have been attenuated for each cell in a 60-cell module. Expressed in W/m^2.

#In R
irradiances_shaded_ready_to_use[[100]][[1000]]
          [,1]     [,2]     [,3]     [,4]     [,5]     [,6]
 [1,] 213.9050 175.0628 199.4696 174.6492 187.5090 159.7476
 [2,] 215.7734 230.8677 180.7294 166.6885 168.1310 199.5440
 [3,] 229.3951 217.8146 195.3562 183.8101 155.5469 183.3035
 [4,] 209.5742 227.4405 226.7091 194.7483 198.0606 180.4816
 [5,] 227.2889 206.0805 217.0147 226.6177 177.0109 182.4648
 [6,] 223.5549 221.1798 227.0709 234.8297 201.6358 196.6677
 [7,] 293.7470 293.7470 293.7470 293.7470 293.7470 293.7470
 [8,] 293.7470 293.7470 293.7470 293.7470 293.7470 293.7470
 [9,] 293.7470 293.7470 293.7470 293.7470 293.7470 293.7470
[10,] 293.7470 293.7470 293.7470 293.7470 293.7470 293.7470

Next, two python scripts which I can call from R. The first takes a module and a set of shades, as above, and applies "setSuns" to the module using the shades. The second takes a shaded module and returns a list of currents for each cell.

#This is a python script 
#It takes the shades and feeds them into the module
def shade_the_module_3(module_input, shade_input):
    positions_input = create_cell_pos_df(module_input)
    positions_input_np = positions_input.to_numpy()
    module_input.setSuns(shade_input, positions_input_np)
    return module_input
	
#This second python script returns a list of currents per cell 
def moving_day_shaded_currents(shaded_module):
    moving_day_shaded_currents = []
    for c, cells in enumerate(shaded_module.pvcells):
        moving_day_shaded_currents.append(shaded_module.pvcells[c].Igen)
    return moving_day_shaded_currents 

And the next bit, in R, ties it all together and produces a vector which holds the current generated by each cell.

#Let's now feed the shades into the module and then create a vector of currents 
#This is in R
shaded_module_attempt = shade_the_module_3(hello_module, irradiances_shaded_ready_to_use[[100]][[100]]/1000)

#This is what the output looks like 
#Note that I turned down the "Suns" by a factor of 1000 since 1 Sun = 1 kW/m^2 (or so I assume)

lists_into_vectors(moving_day_shaded_currents(shaded_module_attempt))
 [1] 0.2554633 0.2622693 0.2845493 0.2850022 0.2404546 0.2856346 0.2973223 0.2704208 0.3186892 0.2593214
[11] 0.2775086 0.2617764 0.3432120 0.3058749 0.2701947 0.2773878 0.2477220 0.2855832 0.2741956 0.2759731
[21] 0.3025052 0.2575780 0.3093930 0.2761150 0.2929953 0.3463328 0.3004103 0.3396224 0.3242891 0.3061217
[31] 0.3315860 0.3103403 0.3213330 0.3280117 0.3198549 0.3456261 0.3002707 0.3145019 0.3347570 0.2652785
[41] 0.3070128 0.3 344090 0.3567242 0.3435092 0.2984866 0.3556262 0.2902348 0.3673566 0.3232607 0.3634075
[51] 0.3227195 0.3250759 0.3489095 0.3244169 0.3375843 0.3451603 0.3037446 0.2909852 0.3619698 0.3159507
>  
@mikofski
Copy link
Contributor

Hi @abooda1981 ,

If these are currents in a single PV module in which all cells are in series (as in a standard Si module) then there seems to me to be something fishy going on. AFAIK all currents should be identical at a given module operating point. Without seeing what Python code you are using, it would be difficult to trouble shoot. Sorry.

Also as Kevin commented there are some pvmismatch questions & answers on StackOverflow, you may get a wider audience there.

If I use your irradiance distribution here's what I get:

from pvmismatch import *
import numpy as np

Esun = [213.9050, 175.0628, 199.4696, 174.6492, 187.5090, 159.7476,
    215.7734, 230.8677, 180.7294, 166.6885, 168.1310, 199.5440,
    229.3951, 217.8146, 195.3562, 183.8101, 155.5469, 183.3035,
    209.5742, 227.4405, 226.7091, 194.7483, 198.0606, 180.4816,
    227.2889, 206.0805, 217.0147, 226.6177, 177.0109, 182.4648,
    223.5549, 221.1798, 227.0709, 234.8297, 201.6358, 196.6677,
    293.7470, 293.7470, 293.7470, 293.7470, 293.7470, 293.7470,
    293.7470, 293.7470, 293.7470, 293.7470, 293.7470, 293.7470,
    293.7470, 293.7470, 293.7470, 293.7470, 293.7470, 293.7470,
    293.7470, 293.7470, 293.7470, 293.7470, 293.7470, 293.7470]
Ee = np.array(Esun)/1000.

# a standard 60 cell Si module cell position pattern
STD60 = pvmodule.standard_cellpos_pat(10, [2, 2, 2])

# 1-sun module
pvmod0 = pvmodule.PVmodule(cell_pos=STD60)

# another identical test module
pvmod = pvmodule.PVmodule(cell_pos=STD60)

# set the test module to your irradiance distribution
pvmod.setSuns(Ee)

# check the max power
pvmod.Pmod.max()
# 33.68645804634907 [W]

# check the 1-sun module max power
pvmod0.Pmod.max()
# 200.7958518246065 [W]

# find the indices in the power-voltage curve that correspond to the max power
idx_pmax = np.argmax(pvmod.Pmod)
# 121 

# ditto for 1-sun module
idx_p0max = np.argmax(pvmod0.Pmod)
# 121

# get the module current at that index in the curve
# module with your irradiance distribution
pvmod.Imod(idx_pmax)
# 1.005869089412653 [A]

# 1-sun module
pvmod0.Imod[idx_p0max]
# 5.9072865777167225 [A]

So the current of all cells in the module at the max power point would be 1.006[A].

Here's the IV & power-voltage curves for the 1-sun module
gh137_std60_1sun

And here's the IV & power-voltage curves for the module with your irradiance distribution
gh137

Remember! PVMismatch returns a full trace of the IV curve for cells, modules, and strings. So it's up to the user to select the operating point that they want from the curve. If you want functions that describe the max power point, you should use pvsystem.PVsystem

@abooda1981
Copy link
Author

Thanks @mikofski for your response. Actually, the module contains 10 series-connected groups. Perhaps the following codes might clear things up.

The following is the code I use to draw the PV module pattern. This is from a previous discussion with @adambgnr

# define a function that returns the cell positions in a dataframe
def create_cell_pos_df(pv_mod):
    """Create cell position dataframe of a module"""
    pv_mod_pattern = pvmismatch.pvmodule.standard_cellpos_pat(nrows=10, ncols_per_substr=[2]*3) #define the pattern here
    my_module_copy = pvmismatch.pvmodule.PVmodule(cell_pos=pv_mod_pattern)  #define the module to have that pattern
    #fed_shades = shades  #We will feed this pattern of shades into the function we define
    fed_module = my_module_copy
    cell_positions = pv_mod.cell_pos
    #Simple way to define the number of rows in the module
    #Limit it to integers
    nrows = int(pv_mod.numberCells / sum(pv_mod.subStrCells))
    cell_pos_df = pd.DataFrame(index=['{}'.format(nr)
                                      for nr
                                      in range(nrows)])
    for b, bypass in enumerate(cell_positions):
        for c, col in enumerate(bypass):
            cell_pos_df['{}_{}'.format(b, c)] = [i['idx'] for i in col]
    return cell_pos_df

# make the cell position DataFrame
cell_positions = create_cell_pos_df(pv_mod=fed_module)

The next bit of code is the function which I access in R, which takes a module with the given structure and sets the shading for each sun to be the same as the value of the irradiance (in suns) after it is shaded by the required amount.

def shade_the_module_3(module_input, shade_input):
    positions_input = create_cell_pos_df(module_input)
    positions_input_np = positions_input.to_numpy()
    module_input.setSuns(shade_input, positions_input_np)
    return module_input

Finally, after I have created a module, and shaded it, I want to know what the photo-induced current is at each cell. My assumption--and I could be implementing this incorrectly, I guess--is that if each of the 60 cells has a different level of shading, then they should produce a different current. The following bit of code is what gives the output I reproduced above:

def moving_day_shaded_currents(shaded_module):
    moving_day_shaded_currents = []
    for c, cells in enumerate(shaded_module.pvcells):
        moving_day_shaded_currents.append(shaded_module.pvcells[c].Igen)
    return moving_day_shaded_currents 

I wonder: would it not make more sense for me to take the shading level cell by cell, and then use the PVLIB function for single diodes? In other words, use pvlib.pvsystem.calcparams_cec for each cell and then just vary the irradiance parameter?

Thanks again for your help. I will follow this up with a question on the StackOverflow as you suggest if you still think there's something wrong with this.

@adambgnr
Copy link
Contributor

adambgnr commented Nov 23, 2020

Hi @abooda1981 ,
I think you are doing everything right, except that the "Igen"s are not the droids currents you are looking for.
The Igen you accessed is this Igen in the diode model:

# diode model
#  *-->--*--->---*--Rs->-Icell--+
#  ^     |       |              ^
#  |     |       |              |
# Igen  Idiode  Ishunt         Vcell
#  |     |       |              |
#  |     v       v              v
#  *--<--*---<---*--<-----------=
# from: https://github.com/SunPower/PVMismatch/blob/5c4bc75fe7b1b4eddcaa0df15cf630f8e8676fc5/pvmismatch/pvmismatch_lib/pvcell.py

Is this current what you really want? Not the Icell?
I think @mikofski is right about that the Icell in all cells has to be the same if they are connected in series.
But then again if it is really the Igen what you want, then I guess it should be correct what you got. Just make sure that you don't mix up which Igen values correspond to which cell index.

An other thing about the shading: Please @mikofski correct me if I am wrong, but I think if we set the suns with a 60 long 1 dimensional array, then the cell irradiances will be set in the order of the PV cell indexes (0-59), which can mess up the layout of the shadow on the PV module. I think what @abooda1981 wants is to fill the irradiances like this:

image

Where on the left are the cell irradiances and on the right the cell indexes. (As far as I know, PVMM sets the cell indexes like this by default, please correct me if I'm wrong.) Thus if the irradiance input of @abooda1981 is in such form (the irradiance input array looks like how the shadow looks like in real life) then he/she can use the create_cell_pos_df() function to align the shade to the cell indexes, see here:
#134

@abooda1981
Copy link
Author

Hi @adambgnr , thanks for your input. Without wanting to spoil your Star Wars meme, I'm fairly sure that the Igen is what I want--in a later part of the code, I take all of the cells in a given string and define the current of the string to be the lowest current in that string. I am assuming that this lowest current is the one which is actually contributed to the module. (If this sounds off, please let me know.)

Going back and forth with the PVLIB email list here: I'm wondering if it's more sensible to just PVLIB to calculate the photo-induced current for each cell individually using a single diode equation. For one thing, this would avoid my having to worry about the way cell indexing works in PVMM.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants