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

Update to SPICE grid modelling #284

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
recommonmark
recommonmark

Binary file added docs/source/Quasi3D/EL_Prediction.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/Quasi3D/HGridPattern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/Quasi3D/Layer_Voltages.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
415 changes: 342 additions & 73 deletions docs/source/Quasi3D/quasi3D.rst

Large diffs are not rendered by default.

804 changes: 804 additions & 0 deletions examples/cpv_grid_spice_example.ipynb

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions examples/cpv_grid_spice_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import numpy as np
from solcore.spice.grid import HGridPattern
from solcore.spice.netlist import generate_netlist, solve_netlist
from solcore.spice.result import (
get_characterisic_curve,
get_electroluminescence,
get_maximum_power_point,
get_node_voltages,
plot_characteristic_curve,
plot_electroluminescence,
plot_surface_voltages
)

if __name__ == "__main__":

# Cell short-circuit current
jsc = 3000.0

# Temperature
temperature = 300.0

# Grid pattern
nx, ny = 120, 120
cell_grid = HGridPattern(10, [4, 4, 4, 4, 4, 4], 3, nx=nx, ny=ny)

# Homogeneous illumination
cell_illumination_map = np.ones(nx * ny).reshape((nx, ny))

# The size of the solar is 3mm x 3mm
cell_size = (0.003, 0.003) # meters

# Define a list of properies that describe each junction in the solar cell.
# NB: currently only one junction is working.
junctions = [
{
"jsc": jsc,
"emitter_sheet_resistance": 100.0,
"j01": 4e-16,
"j02": 2e-7,
"Eg": 1.41,
"n1": 1.0,
"n2": 2.0
}
]

netlist = generate_netlist(
cell_grid,
cell_illumination_map,
cell_size,
junctions,
temperature=300,
show_plots=True
)

print("")
print("This simulation will take a few minutes to run, please wait for results to appear...")
result = solve_netlist(netlist, temperature, -0.1, 1.5, 0.01)

V, I = get_characterisic_curve(result)

plot_characteristic_curve(V, I)

vmax, pmax, maxidx = get_maximum_power_point(result)

voltages = get_node_voltages(result)

plot_surface_voltages(voltages, bias_index=maxidx)

pv_surface_voltages = voltages[:, :, 1, maxidx]
el = get_electroluminescence(pv_surface_voltages, is_metal=cell_grid.is_metal)

plot_electroluminescence(el)
5 changes: 2 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ dependencies = [
"yabox",
"joblib",
"solsesame",
"PySpice",
"pixie-python"
]
dynamic = ["version"]

Expand Down Expand Up @@ -71,9 +73,6 @@ package = 'solcore'
"Build" = ["spin.cmds.meson.build", "spin.cmds.meson.test"]
"Extensions" = ['.spin/cmds.py:codecov', '.spin/cmds.py:install_dependencies']

[tool.pytest.ini_options]
addopts = "--cov=solcore --cov-report=html:htmlcov -p no:warnings -n \"auto\" -v"

[tool.isort]
line_length = 88
multi_line_output = 3
Expand Down
2 changes: 1 addition & 1 deletion solcore/spice/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .spice import solve_circuit, SpiceSolverError
from .pv_module_solver import solve_pv_module
from .quasi_3D_solver import solve_quasi_3D
from .quasi_3D_solver import solve_quasi_3D
141 changes: 141 additions & 0 deletions solcore/spice/grid.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
"""Classes that generate a metalisation pattern for a solar cell.
"""


import numpy as np
import pixie
from PIL import Image, ImageOps
import tempfile
from pathlib import Path


class GridPattern:
"""Representation of a metalisation pattern on the front surface of a solar cell.

Instead of instantiating this class directly, subclass and implement the `draw` method to render a grid pattern.

Discussion
----------
You should use three grayscale pixel values to illustrate the solar cell metalization:
- black (0.0), represents no metalisation
- grey (0.5), represents grid fingers
- white (1.0), represents the bus bar.
"""
def draw(self) -> pixie.Image:
raise NotImplementedError("The draw() method should be implemented by subclasses to draw specific grid patterns.")

def save_as_image(self, path):
image: pixie.Image = self.draw()
image.write_file(path) # This file is seems to be corrupt!
img = Image.open(path) # But, it can be opened by PIL and re-saved.

# The shape of this array will be something like (300, 300, 4)
# because pixie saves colours as RGBA. We need to conver this
# to a gray scale image
img = ImageOps.grayscale(img)
img.save(path)

def as_array(self) -> np.ndarray:
# Write the image to a temporary directory,
# load the image back using PIL and return
# the data as an array.
with tempfile.TemporaryDirectory() as dirname:
path = Path(dirname) / "grid.png" # file name does matter
self.save_as_image(path.as_posix())
img = Image.open(path.as_posix())
return np.asarray(img)

@property
def is_metal(self) -> np.ndarray:
"""Return a bool array where the pattern contains metal.
"""
pattern = self.as_array()
return np.where((pattern / pattern.max()) > 0.2, True, False)


class HGridPattern(GridPattern):
"""A classic H pattern concenrator solar cell pattern.
"""

def __init__(self, bus_px_width, finger_px_widths, offset_px=5, nx=300, ny=300):
self.bus_px_width = bus_px_width
self.finger_px_widths = finger_px_widths
self.offset_px = offset_px
self.nx = nx
self.ny = ny

def draw(self) -> pixie.Image:

bus_px_width = self.bus_px_width
finger_px_widths = self.finger_px_widths
offset_px = self.offset_px
nx = self.nx
ny = self.ny

BUS_PAINT = pixie.Paint(pixie.SOLID_PAINT)
BUS_PAINT.color = pixie.Color(1, 1, 1, 1) # White

FINGER_PAINT = pixie.Paint(pixie.SOLID_PAINT)
FINGER_PAINT.color = pixie.Color(0.5, 0.5, 0.5, 1) # Gray

# Fill the image with black i.e. no metal. We are going
# to draw on top of this canvas using the BUS_PAINT and
# the FINGER_PAINT paints.
self.image = image = pixie.Image(nx, ny)
BLACK = pixie.Color(0, 0, 0, 1)
image.fill(BLACK)


# NB Top-left corner is the (0, 0)
ctx = image.new_context()
ctx.fill_style = BUS_PAINT
ctx.fill_rect(offset_px, offset_px, nx - 2 * offset_px, bus_px_width)
ctx.fill_rect(offset_px , ny - offset_px - bus_px_width, nx - 2 * offset_px, bus_px_width)

# The image now looks like this, with the bus bars drawn
#
# ***************
# ***************
#
#
#
#
# ***************
# ***************
#

ctx = image.new_context()
ctx.stroke_style = FINGER_PAINT
f_origin_y = np.rint(bus_px_width + offset_px)
f_length = np.rint(ny - 2 * offset_px - 2 * bus_px_width)
n = len(finger_px_widths)
w = nx - 2 * offset_px # width of mask
d = w / (2*n) # the half-spacing between fingers
f_x = [offset_px + d] # location of first grid finger
for idx in range(1, n):
f_x.append(f_x[idx-1] + 2*d)

# Round the x locations to the nearest integer, this avoid
# the drawing tool kit from blending the colors
f_x = np.rint(np.array(f_x))


for f_origin_x, f_width in zip(f_x, finger_px_widths):

ctx.stroke_segment(f_origin_x, f_origin_y, f_origin_x, f_origin_y + f_length)

# The image now looks like this, with the n grid fingers drawn, here n = 3
#
# ***************
# ***************
# | | |
# | | |
# | | |
# | | |
# ***************
# ***************
#

return image


Loading
Loading