/
tunnel_junctions.py
executable file
·210 lines (153 loc) · 7.02 KB
/
tunnel_junctions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
import numpy as np
from solcore.constants import kb, q
def resistive_tunnel_junction(junction, options):
""" Calculates the IV curve of a tunnel junction when it is modelled as a simple resistor. The minimum resistance of the junction is always 1e-16.
:param junction: A junction object.
:param options: Solver options.
:return: None.
"""
def iv(v):
return v / junction.R
def vi(j):
return j * junction.R
junction.voltage = options.internal_voltages
junction.current = iv(junction.voltage)
junction.iv = iv
junction.vi = vi
def parametric_tunnel_junction(junction, options):
""" Calculates the IV curve of a tunnel junction when it is modelled using a set of empirical parameters, such as peak curent and voltage, valley current and voltage, etc. The total current of the tunnel junction is summ of 3 components: the tunnel current, the excess current and the difussion current.
:param junction: A junction object.
:param options: Solver options.
:return: None.
"""
T = options.T
junction.voltage = options.internal_voltages
try:
# First we calculate the tunnel current
jp = junction.j_peak
vp = junction.v_peak
def tunnel_current(v):
return jp * v / vp * np.exp(1 - v / vp)
junction.tunnel_current = tunnel_current
# Now we calculate the excess current due to carrier tunnelling by way of states within the forbidden gap
jva = junction.j_valley
vv = junction.v_valley
pref = junction.prefactor
def excess_current(v):
return jva * np.exp(pref * (v - vv))
junction.excess_current = excess_current
# Finally we calculate the diffusion current
j01 = junction.j01
def diffusion_current(v):
return j01 * np.exp(q * v / kb / T)
junction.diffusion_current = diffusion_current
except AttributeError:
raise
# And we put everything together in an IV curve function
def iv(v):
return junction.tunnel_current(v) + junction.excess_current(v) + junction.diffusion_current(v)
junction.current = iv(junction.voltage)
# Also, we calculate the inverse, needed for the calculation of the IV curve in MJ solar cells
MJ_current = np.where(junction.voltage <= junction.v_peak, junction.current,
np.maximum(iv(junction.v_peak), junction.current))
# And the corresponding function doing that
if junction.pn:
def vi(j):
return np.interp(-j, MJ_current, -junction.voltage)
else:
def vi(j):
return np.interp(j, MJ_current, junction.voltage)
junction.iv = iv
junction.vi = vi
def external_tunnel_junction(junction, options):
""" Calculates the IV curve of a tunnel junction when it is modelled with external data. The external voltage and current must be defined with the input parameters external_voltage and external_current, respectively. It assumes that the interesting part of the curve is in the 1st quadrant (V>0 and I>0).
:param junction: A junction object.
:param options: Solver options.
:return: None.
"""
try:
# We put everything together in an IV curve function using the external data
def iv(v):
return np.interp(v, junction.external_voltage, junction.external_current)
except AttributeError:
raise
# Also, we calculate the inverse, needed for the calculation of the IV curve in MJ solar cells
MJ_current = np.zeros_like(junction.external_current)
MJ_current[0] = junction.external_current[0]
for i in range(len(junction.external_current) - 1):
MJ_current[i + 1] = max(MJ_current[i], junction.current[i + 1])
# And the corresponding function doing that
def vi(j):
return np.interp(j, MJ_current, junction.external_voltage)
junction.voltage = options.internal_voltages
junction.current = iv(junction.voltage)
junction.iv = iv
junction.vi = vi
def example_resistive_tunnel_junction(show=True):
from solcore.structure import TunnelJunction
from solcore.solar_cell_solver import default_options
import matplotlib.pyplot as plt
# Parametric tunnel example
my_tunnel = TunnelJunction(R=0.05)
resistive_tunnel_junction(my_tunnel, default_options)
if show:
v = my_tunnel.voltage
plt.plot(v, my_tunnel.current, 'k', linewidth=2, label='Total')
plt.legend(fontsize=12)
plt.ylim(0, 1.5)
plt.xlim(0, 1)
plt.ylabel('Current Density(A/$m^2$)', fontsize=12)
plt.xlabel('Voltage(V)', fontsize=12)
plt.tick_params(labelsize=12)
plt.tight_layout()
plt.show()
return my_tunnel
def example_parametric_tunnel_junction(show=True):
from solcore.structure import TunnelJunction
from solcore.solar_cell_solver import default_options
import matplotlib.pyplot as plt
# Parametric tunnel example
my_tunnel = TunnelJunction(v_peak=0.1, j_peak=1, v_valley=0.5, j_valley=0.1, prefactor=10, j01=1e-11)
parametric_tunnel_junction(my_tunnel, default_options)
if show:
v = my_tunnel.voltage
plt.plot(v, my_tunnel.tunnel_current(v), 'r--', label='Tunnel')
plt.plot(v, my_tunnel.excess_current(v), 'g--', label='Excess')
plt.plot(v, my_tunnel.diffusion_current(v), 'b--', label='Diffusion')
plt.plot(v, my_tunnel.current, 'k', linewidth=2, label='Total')
plt.legend(fontsize=12)
plt.ylim(0, 1.5)
plt.xlim(0, 1)
plt.ylabel('Current Density(A/$m^2$)', fontsize=12)
plt.xlabel('Voltage(V)', fontsize=12)
plt.tick_params(labelsize=12)
plt.tight_layout()
plt.show()
return my_tunnel
if __name__ == '__main__':
import matplotlib.pyplot as plt
from solcore.structure import TunnelJunction
from solcore.solar_cell_solver import default_options
# tunnel = example_parametric_tunnel_junction(False)
# example_resistive_tunnel_junction()
tunnel = TunnelJunction(v_peak=0.2, j_peak=7.5e4, v_valley=1, j_valley=40000, prefactor=5, j01=1e-23, kind='parametric')
parametric_tunnel_junction(tunnel, default_options)
v = tunnel.voltage
I = np.linspace(0, 105000, 100)
plt.plot(v, tunnel.tunnel_current(v), 'r--', label='Tunnel')
plt.plot(v, tunnel.excess_current(v), 'g--', label='Excess')
plt.plot(v, tunnel.diffusion_current(v), 'b--', label='Diffusion')
plt.plot(v, tunnel.current, 'k', linewidth=3, color='DimGray', label='Total')
# plt.plot(v, MJ_current, 'k-o', linewidth=2, label='MJ current')
# plt.plot(tunnel.vi(I), I, '--', color='grey', linewidth=2, label='MJ current')
plt.plot((0.2, 0.9), (100, 10), 'ko')
plt.annotate('V$_P$, J$_P$', xy=(0.2, 110), fontsize=12)
plt.annotate('V$_V$, J$_V$', xy=(0.6, 10), fontsize=12)
plt.legend(fontsize=12, frameon=False)
plt.ylim(0, 105000)
plt.xlim(0, 2)
plt.ylabel('Current Density(A/$m^2$)', fontsize=12)
plt.xlabel('Voltage(V)', fontsize=12)
plt.tick_params(labelsize=12)
plt.tight_layout()
plt.show()