]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/math/example/lambert_w_diode_graph.cpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / libs / math / example / lambert_w_diode_graph.cpp
CommitLineData
92f5a8d4
TL
1// Copyright Paul A. Bristow 2016
2// Copyright John Z. Maddock 2016
3
4// Distributed under the Boost Software License, Version 1.0.
5// (See accompanying file LICENSE_1_0.txt or
6// copy at http ://www.boost.org/LICENSE_1_0.txt).
7
8/*! \brief Graph showing use of Lambert W function to compute current
9through a diode-connected transistor with preset series resistance.
10
11\details T. C. Banwell and A. Jayakumar,
12Exact analytical solution of current flow through diode with series resistance,
13Electron Letters, 36(4):291-2 (2000).
14DOI: doi.org/10.1049/el:20000301
15
16The current through a diode connected NPN bipolar junction transistor (BJT)
17type 2N2222 (See https://en.wikipedia.org/wiki/2N2222 and
18https://www.fairchildsemi.com/datasheets/PN/PN2222.pdf Datasheet)
19was measured, for a voltage between 0.3 to 1 volt, see Fig 2 for a log plot, showing a knee visible at about 0.6 V.
20
21The transistor parameter I sat was estimated to be 25 fA and the ideality factor = 1.0.
22The intrinsic emitter resistance re was estimated from the rsat = 0 data to be 0.3 ohm.
23
24The solid curves in Figure 2 are calculated using equation 5 with rsat included with re.
25
26http://www3.imperial.ac.uk/pls/portallive/docs/1/7292572.PDF
27
28*/
29
1e59de90
TL
30#ifndef BOOST_MATH_STANDALONE
31
92f5a8d4
TL
32#include <boost/math/special_functions/lambert_w.hpp>
33using boost::math::lambert_w0;
34#include <boost/math/special_functions.hpp>
35using boost::math::isfinite;
36#include <boost/svg_plot/svg_2d_plot.hpp>
37using namespace boost::svg;
38
39#include <iostream>
40// using std::cout;
41// using std::endl;
42#include <exception>
43#include <stdexcept>
44#include <string>
45#include <array>
46#include <vector>
47#include <utility>
48using std::pair;
49#include <map>
50using std::map;
51#include <set>
52using std::multiset;
53#include <limits>
54using std::numeric_limits;
55#include <cmath> //
56
57/*!
58Compute thermal voltage as a function of temperature,
59about 25 mV at room temperature.
60https://en.wikipedia.org/wiki/Boltzmann_constant#Role_in_semiconductor_physics:_the_thermal_voltage
61
62\param temperature Temperature (degrees Celsius).
63*/
64const double v_thermal(double temperature)
65{
1e59de90
TL
66 constexpr const double boltzmann_k = 1.38e-23; // joules/kelvin.
67 constexpr double charge_q = 1.6021766208e-19; // Charge of an electron (columb).
92f5a8d4
TL
68 double temp = +273; // Degrees C to K.
69 return boltzmann_k * temp / charge_q;
70} // v_thermal
71
72 /*!
73 Banwell & Jayakumar, equation 2, page 291.
74 */
75double i(double isat, double vd, double vt, double nu)
76{
77 double i = isat * (exp(vd / (nu * vt)) - 1);
78 return i;
79} //
80
81 /*!
82 Banwell & Jayakumar, Equation 4, page 291.
83 i current flow = isat
84 v voltage source.
85 isat reverse saturation current in equation 4.
86 (might implement equation 4 instead of simpler equation 5?).
87 vd voltage drop = v - i* rs (equation 1).
88 vt thermal voltage, 0.0257025 = 25 mV.
89 nu junction ideality factor (default = unity), also known as the emission coefficient.
90 re intrinsic emitter resistance, estimated to be 0.3 ohm from low current.
91 rsat reverse saturation current
92
93 \param v Voltage V to compute current I(V).
94 \param vt Thermal voltage, for example 0.0257025 = 25 mV, computed from boltzmann_k * temp / charge_q;
95 \param rsat Resistance in series with the diode.
f67539c2 96 \param re Intrinsic emitter resistance (estimated to be 0.3 ohm from the Rs = 0 data)
92f5a8d4
TL
97 \param isat Reverse saturation current (See equation 2).
98 \param nu Ideality factor (default = unity).
99
100 \returns I amp as function of V volt.
101 */
102
103//[lambert_w_diode_graph_2
104double iv(double v, double vt, double rsat, double re, double isat, double nu = 1.)
105{
106 // V thermal 0.0257025 = 25 mV
107 // was double i = (nu * vt/r) * lambert_w((i0 * r) / (nu * vt)); equ 5.
108
109 rsat = rsat + re;
110 double i = nu * vt / rsat;
111 // std::cout << "nu * vt / rsat = " << i << std::endl; // 0.000103223
112
113 double x = isat * rsat / (nu * vt);
114// std::cout << "isat * rsat / (nu * vt) = " << x << std::endl;
115
116 double eterm = (v + isat * rsat) / (nu * vt);
117 // std::cout << "(v + isat * rsat) / (nu * vt) = " << eterm << std::endl;
118
119 double e = exp(eterm);
120// std::cout << "exp(eterm) = " << e << std::endl;
121
122 double w0 = lambert_w0(x * e);
123// std::cout << "w0 = " << w0 << std::endl;
124 return i * w0 - isat;
125} // double iv
126
127//] [\lambert_w_diode_graph_2]
128
129
130std::array<double, 5> rss = { 0., 2.18, 10., 51., 249 }; // series resistance (ohm).
131std::array<double, 7> vds = { 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9 }; // Diode voltage.
132std::array<double, 7> lni = { -19.65, -15.75, -11.86, -7.97, -4.08, -0.0195, 3.6 }; // ln(current).
133
134int main()
135{
136 try
137 {
138 std::cout << "Lambert W diode current example." << std::endl;
139
140//[lambert_w_diode_graph_1
141 double nu = 1.0; // Assumed ideal.
142 double vt = v_thermal(25); // v thermal, Shockley equation, expect about 25 mV at room temperature.
143 double boltzmann_k = 1.38e-23; // joules/kelvin
144 double temp = 273 + 25;
145 double charge_q = 1.6e-19; // column
146 vt = boltzmann_k * temp / charge_q;
147 std::cout << "V thermal " << vt << std::endl; // V thermal 0.0257025 = 25 mV
148 double rsat = 0.;
149 double isat = 25.e-15; // 25 fA;
150 std::cout << "Isat = " << isat << std::endl;
151 double re = 0.3; // Estimated from slope of straight section of graph (equation 6).
152 double v = 0.9;
153 double icalc = iv(v, vt, 249., re, isat);
154 std::cout << "voltage = " << v << ", current = " << icalc << ", " << log(icalc) << std::endl; // voltage = 0.9, current = 0.00108485, -6.82631
155//] [/lambert_w_diode_graph_1]
156
157 // Plot a few measured data points.
158 std::map<const double, double> zero_data; // Extrapolated from slope of measurements with no external resistor.
159 zero_data[0.3] = -19.65;
160 zero_data[0.4] = -15.75;
161 zero_data[0.5] = -11.86;
162 zero_data[0.6] = -7.97;
163 zero_data[0.7] = -4.08;
164 zero_data[0.8] = -0.0195;
165 zero_data[0.9] = 3.9;
166
167 std::map<const double, double> measured_zero_data; // No external series resistor.
168 measured_zero_data[0.3] = -19.65;
169 measured_zero_data[0.4] = -15.75;
170 measured_zero_data[0.5] = -11.86;
171 measured_zero_data[0.6] = -7.97;
172 measured_zero_data[0.7] = -4.2;
173 measured_zero_data[0.72] = -3.5;
174 measured_zero_data[0.74] = -2.8;
175 measured_zero_data[0.76] = -2.3;
176 measured_zero_data[0.78] = -2.0;
177 // Measured from Fig 2 as raw data not available.
178
179 double step = 0.1;
180 for (int i = 0; i < vds.size(); i++)
181 {
182 zero_data[vds[i]] = lni[i];
183 std::cout << lni[i] << " " << vds[i] << std::endl;
184 }
185 step = 0.01;
186
187 std::map<const double, double> data_2;
188 for (double v = 0.3; v < 1.; v += step)
189 {
190 double current = iv(v, vt, 2., re, isat);
191 data_2[v] = log(current);
192 // std::cout << "v " << v << ", current = " << current << " log current = " << log(current) << std::endl;
193 }
194 std::map<const double, double> data_10;
195 for (double v = 0.3; v < 1.; v += step)
196 {
197 double current = iv(v, vt, 10., re, isat);
198 data_10[v] = log(current);
199 // std::cout << "v " << v << ", current = " << current << " log current = " << log(current) << std::endl;
200 }
201 std::map<const double, double> data_51;
202 for (double v = 0.3; v < 1.; v += step)
203 {
204 double current = iv(v, vt, 51., re, isat);
205 data_51[v] = log(current);
206 // std::cout << "v " << v << ", current = " << current << " log current = " << log(current) << std::endl;
207 }
208 std::map<const double, double> data_249;
209 for (double v = 0.3; v < 1.; v += step)
210 {
211 double current = iv(v, vt, 249., re, isat);
212 data_249[v] = log(current);
213 // std::cout << "v " << v << ", current = " << current << " log current = " << log(current) << std::endl;
214 }
215
216 svg_2d_plot data_plot;
217
218 data_plot.title("Diode current versus voltage")
219 .x_size(400)
220 .y_size(300)
221 .legend_on(true)
222 .legend_lines(true)
223 .x_label("voltage (V)")
224 .y_label("log(current) (A)")
225 //.x_label_on(true)
226 //.y_label_on(true)
227 //.xy_values_on(false)
228 .x_range(0.25, 1.)
229 .y_range(-20., +4.)
230 .x_major_interval(0.1)
231 .y_major_interval(4)
232 .x_major_grid_on(true)
233 .y_major_grid_on(true)
234 //.x_values_on(true)
235 //.y_values_on(true)
236 .y_values_rotation(horizontal)
237 //.plot_window_on(true)
238 .x_values_precision(3)
239 .y_values_precision(3)
240 .coord_precision(4) // Needed to avoid stepping on curves.
241 .copyright_holder("Paul A. Bristow")
242 .copyright_date("2016")
243 //.background_border_color(black);
244 ;
245
246 // &#x2080; = subscript zero.
247 data_plot.plot(zero_data, "I&#x2080;(V)").fill_color(lightgray).shape(none).size(3).line_on(true).line_width(0.5);
248 data_plot.plot(measured_zero_data, "Rs=0 &#x3A9;").fill_color(lightgray).shape(square).size(3).line_on(true).line_width(0.5);
249 data_plot.plot(data_2, "Rs=2 &#x3A9;").line_color(blue).shape(none).line_on(true).bezier_on(false).line_width(1);
250 data_plot.plot(data_10, "Rs=10 &#x3A9;").line_color(purple).shape(none).line_on(true).bezier_on(false).line_width(1);
251 data_plot.plot(data_51, "Rs=51 &#x3A9;").line_color(green).shape(none).line_on(true).line_width(1);
252 data_plot.plot(data_249, "Rs=249 &#x3A9;").line_color(red).shape(none).line_on(true).line_width(1);
253 data_plot.write("./diode_iv_plot");
254
255 // bezier_on(true);
256 }
257 catch (std::exception& ex)
258 {
259 std::cout << ex.what() << std::endl;
260 }
261
262
263} // int main()
264
265 /*
266
267 //[lambert_w_output_1
268 Output:
269 Lambert W diode current example.
270 V thermal 0.0257025
271 Isat = 2.5e-14
272 voltage = 0.9, current = 0.00108485, -6.82631
273 -19.65 0.3
274 -15.75 0.4
275 -11.86 0.5
276 -7.97 0.6
277 -4.08 0.7
278 -0.0195 0.8
279 3.6 0.9
280
281 //] [/lambert_w_output_1]
282 */
1e59de90 283#endif // BOOST_MATH_STANDALONE