Mercurial > forge
annotate extra/ocs/src/Mshichmanhodgesmosfet.cc @ 12676:a8f02c1adca6 octave-forge
work around clang bug
author | cdf |
---|---|
date | Mon, 17 Aug 2015 17:02:20 +0000 |
parents | 3ce60a1159f8 |
children |
rev | line source |
---|---|
6667 | 1 /* |
2 | |
3 Copyright (C) 2009 Massimiliano Culpo | |
4 | |
5 This file is part of: | |
6 OCS - A Circuit Simulator for Octave | |
7 | |
8 OCS is free software; you can redistribute it and/or modify | |
9 it under the terms of the GNU General Public License as published by | |
10 the Free Software Foundation. | |
11 | |
12 This program is distributed in the hope that it will be useful, | |
13 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 GNU General Public License for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with this program (see the file LICENSE); if not, | |
19 see <http://www.gnu.org/licenses/>. | |
20 | |
21 author: Massimiliano Culpo <culpo@math.uni-wuppertal.de> | |
22 | |
23 */ | |
24 | |
25 #include <octave/oct.h> | |
26 #include <octave/parse.h> | |
27 #include <octave/str-vec.h> | |
28 #include <string> | |
29 #include <octave/pager.h> | |
30 | |
31 using namespace std; | |
32 | |
33 /* Print parameters */ | |
34 void print_parameters(double rd, double W, double L, double mu0, double Vth, | |
35 double Cox, double Cgs, double Cgd, double Cgb, double Csb, | |
36 double Cdb, double Tshift) | |
37 { | |
38 octave_stdout << "PARAMETER TABLE: Simplified Shichman-Hodges MOS-FET\n\n"; | |
39 octave_stdout << "Name\t\tValue\n"; | |
40 octave_stdout << "rd\t\t" << rd << "\n" ; | |
41 octave_stdout << "W\t\t" << W << "\n" ; | |
42 octave_stdout << "L\t\t" << L << "\n" ; | |
43 octave_stdout << "mu0\t\t" << mu0 << "\n" ; | |
44 octave_stdout << "Vth\t\t" << Vth << "\n" ; | |
45 octave_stdout << "Cox\t\t" << Cox << "\n" ; | |
46 octave_stdout << "Cgs\t\t" << Cgs << "\n" ; | |
47 octave_stdout << "Cgd\t\t" << Cgd << "\n" ; | |
48 octave_stdout << "Cgb\t\t" << Cgb << "\n" ; | |
49 octave_stdout << "Csb\t\t" << Csb << "\n" ; | |
50 octave_stdout << "Cdb\t\t" << Cdb << "\n" ; | |
51 octave_stdout << "Tshift\t\t" << Tshift << "\n" ; | |
52 octave_stdout << "\n\n"; | |
53 } | |
54 | |
55 /* Print computed values */ | |
56 void print_values(double gm, double gd, double ids, double didT, | |
57 double P, double dPdT, double dPdvgs, double dPdvds) | |
58 { | |
59 octave_stdout << "COMPUTED VALUES TABLE: Simplified Shichman-Hodges MOS-FET\n\n"; | |
60 octave_stdout << "Name\t\tValue\n"; | |
61 octave_stdout << "gm\t\t" << gm << "\n" ; | |
62 octave_stdout << "gd\t\t" << gd << "\n" ; | |
63 octave_stdout << "ids\t\t" << ids << "\n" ; | |
64 octave_stdout << "didT\t\t" << didT << "\n" ; | |
65 octave_stdout << "P\t\t" << P << "\n" ; | |
66 octave_stdout << "dPdT\t\t" << dPdT << "\n" ; | |
67 octave_stdout << "dPdvgs\t\t" << dPdvgs << "\n" ; | |
68 octave_stdout << "dPdvds\t\t" << dPdvds << "\n" ; | |
69 octave_stdout << "\n\n"; | |
70 } | |
71 | |
72 /* Set the parameters of the simplified Shichman-Hodges MOS-FET */ | |
73 void set_parameters(ColumnVector parameters, string_vector parameternames, | |
74 double *rd, double* W, double* L, double* mu0, double* Vth, | |
75 double* Cox, double* Cgs, double* Cgd, double* Cgb, double* Csb, | |
76 double* Cdb, double* Tshift) | |
77 { | |
12660 | 78 octave_idx_type nnames = parameternames.numel (); |
6667 | 79 octave_idx_type niter = 0; |
80 //FIXME: it should be better to use Octave_map<string,value> for parameters | |
81 while (niter < nnames) | |
82 { | |
83 if (parameternames[niter] == "rd") | |
84 *rd = parameters(niter); | |
85 else if (parameternames[niter] == "W") | |
86 *W = parameters(niter); | |
87 else if (parameternames[niter] == "L") | |
88 *L = parameters(niter); | |
89 else if (parameternames[niter] == "mu0") | |
90 *mu0 = parameters(niter); | |
91 else if (parameternames[niter] == "Vth") | |
92 *Vth = parameters(niter); | |
93 else if (parameternames[niter] == "Cox") | |
94 *Cox = parameters(niter); | |
95 else if (parameternames[niter] == "Cgs") | |
96 *Cgs = parameters(niter); | |
97 else if (parameternames[niter] == "Cgd") | |
98 *Cgd = parameters(niter); | |
99 else if (parameternames[niter] == "Cgb") | |
100 *Cgb = parameters(niter); | |
101 else if (parameternames[niter] == "Csb") | |
102 *Csb = parameters(niter); | |
103 else if (parameternames[niter] == "Cdb") | |
104 *Cdb = parameters(niter); | |
105 else if (parameternames[niter] == "Tshift") | |
106 *Tshift = parameters(niter); | |
107 else | |
108 warning ((string("Mshichmanhodgesmosfet: unknown parameter").append (parameternames[niter])).c_str ()); | |
109 | |
110 niter++; | |
111 } | |
112 } | |
113 | |
114 /* Compute values for n-mos model*/ | |
115 void nmos(ColumnVector extvar, double mu0, double Cox, double W, | |
116 double L, double Vth, double rd, double Tshift, | |
117 double *gm, double *gd, double *ids, double *didT, | |
118 double *P, double *dPdT, double *dPdvgs, double *dPdvds) | |
119 { | |
120 double vg = extvar(0); // V-gate | |
121 double vs = extvar(1); // V-source | |
122 double vd = extvar(2); // V-drain | |
123 double vb = extvar(3); // V-bulk | |
124 double T = extvar(4); // Temperature | |
125 | |
126 double k = mu0*Cox*pow((T + Tshift)/300.0,-3.0/2.0)*W/L; | |
12676 | 127 double dkdT = mu0*Cox*W*(-3.0/2)*std::pow((T + Tshift)/300.0,-5.0/2.0 )*(1.0/300.0)/L; |
6667 | 128 |
129 double vgs = vg - vs; | |
130 double vds = vd - vs; | |
131 | |
132 if (vgs < Vth) | |
133 { | |
134 *gm = 0; | |
135 *gd = 1/rd; | |
136 *ids = vds*(*gd); | |
137 *didT = 0; | |
138 } | |
139 else if ( ( (vgs-Vth)>= vds ) && (vds>=0)) | |
140 { | |
12676 | 141 *ids = k*((vgs-Vth)*vds - std::pow(vds,2)/2 ) + vds/rd; |
6667 | 142 *gm = k*vds; |
143 *gd = k*(vgs-Vth-vds) + (1/rd); | |
12676 | 144 *didT = dkdT*((vgs-Vth)*vds-(std::pow(vds,2))/2); |
6667 | 145 } |
146 else if (((vgs-Vth)>=(vds))&&(vds<0)) | |
147 { | |
148 *gm = 0; | |
149 *gd = 1/rd; | |
150 *ids = vds*(*gd); | |
151 *didT= 0; | |
152 } | |
153 else // (i.e. if 0 <= vgs-vth <= vds) | |
154 { | |
12676 | 155 *ids = (k/2)*std::pow((vgs-Vth),2) + vds/rd; |
6667 | 156 *gm = k*(vgs-Vth); |
157 *gd = 1/rd; | |
12676 | 158 *didT= (dkdT/(2))*std::pow((vgs-Vth),2); |
6667 | 159 } |
160 | |
161 *P = -(*ids)*vds; | |
162 *dPdT = -(*didT)*vds; | |
163 *dPdvgs = -(*gm)*vds; | |
164 *dPdvds = -((*gd)*vds + (*ids)); | |
165 | |
166 } | |
167 | |
168 /* Compute values for p-mos model*/ | |
169 void pmos(ColumnVector extvar, double mu0, double Cox, double W, | |
170 double L, double Vth, double rd, double Tshift, | |
171 double *gm, double *gd, double *ids, double *didT, | |
172 double *P, double *dPdT, double *dPdvgs, double *dPdvds) | |
173 { | |
174 double vg = extvar(0); // V-gate | |
175 double vs = extvar(1); // V-source | |
176 double vd = extvar(2); // V-drain | |
177 double vb = extvar(3); // V-bulk | |
178 double T = extvar(4); // Temperature | |
179 | |
12676 | 180 double k = - mu0*Cox*std::pow((T + Tshift)/300.0,-3.0/2.0)*W/L; |
181 double dkdT = - mu0*Cox*W*(-3.0/2.0)*std::pow((T + Tshift)/300.0,-5.0/2.0 )*(1.0/300.0)/L; | |
6667 | 182 |
183 double vgs = vg - vs; | |
184 double vds = vd - vs; | |
185 | |
186 if (vgs > Vth) | |
187 { | |
188 *gm = 0; | |
189 *gd = 1/rd; | |
190 *ids = vds*(*gd); | |
191 *didT = 0; | |
192 } | |
193 else if ( ( (vgs-Vth)<= vds ) && (vds<=0)) | |
194 { | |
12676 | 195 *ids = k*((vgs-Vth)*vds - std::pow(vds,2)/2 ) + vds/rd; |
6667 | 196 *gm = k*vds; |
197 *gd = k*(vgs-Vth-vds) + (1/rd); | |
12676 | 198 *didT = dkdT*((vgs-Vth)*vds-(std::pow(vds,2))/2); |
6667 | 199 } |
200 else if (((vgs-Vth)<=(vds))&&(vds>0)) | |
201 { | |
202 *gm = 0; | |
203 *gd = 1/rd; | |
204 *ids = vds*(*gd); | |
205 *didT= 0; | |
206 } | |
207 else // (i.e. if 0 <= vgs-vth <= vds) | |
208 { | |
12676 | 209 *ids = (k/2)*std::pow((vgs-Vth),2) + vds/rd; |
6667 | 210 *gm = k*(vgs-Vth); |
211 *gd = 1/rd; | |
12676 | 212 *didT= (dkdT/(2))*std::pow((vgs-Vth),2); |
6667 | 213 } |
214 | |
215 *P = -(*ids)*vds; | |
216 *dPdT = -(*didT)*vds; | |
217 *dPdvgs = -(*gm)*vds; | |
218 *dPdvds = -((*gd)*vds + (*ids)); | |
219 | |
220 } | |
221 | |
222 DEFUN_DLD(Mshichmanhodgesmosfet,args,nargout, | |
223 "-*- texinfo -*-\n\ | |
224 \n\ | |
9730
4db1fc229c42
help text: functions in oct files are {Loadable Functions}, not {Function Files}. Fixing help texts accordingly
carandraug
parents:
6667
diff
changeset
|
225 @deftypefn{Loadable Function} @\n\ |
6667 | 226 {[@var{a},@var{b},@var{c}]=} Mshichmanhodgesmosfet@\n\ |
227 (@var{string}, @var{parameters}, @var{parameternames}, @\n\ | |
228 @var{extvar},@var{intvar},@var{t})\n\ | |
229 \n\ | |
230 SBN file implementing Schichman-Hodges MOSFETs model.\n\ | |
231 \n\ | |
232 @var{string} is used to select among models. Possible models are:\n\ | |
233 \n\ | |
234 @enumerate\n\ | |
235 @item @var{string} = NMOS (Simplified Shichman-Hodges n-MOSFET)\n\ | |
236 @item @var{string} = PMOS (Simplified Shichman-Hodges p-MOSFET)\n\ | |
237 @end enumerate\n\ | |
238 \n\ | |
239 Parameters for all the above models are:\n\ | |
240 @itemize\n\ | |
241 @item rd -> parasitic resistance between drain and source\n\ | |
242 @item W -> MOSFET width\n\ | |
243 @item L -> channel length\n\ | |
244 @item mu0 -> reference value for mobility\n\ | |
245 @item Vth -> threshold voltage\n\ | |
246 @item Cox -> oxide capacitance\n\ | |
247 @item Cgs -> gate-source capacitance\n\ | |
248 @item Cgd -> gate-drain capacitance\n\ | |
249 @item Cgb -> gate-bulk capacitance\n\ | |
250 @item Csb -> source-bulk capacitance\n\ | |
251 @item Cdb -> drain-bulk capacitance\n\ | |
252 @item Tshift -> shift for reference temperature on MOSFETs\n\ | |
253 @end itemize\n\ | |
254 See the @cite{IFF file format specifications} for details about\n\ | |
255 the output structures.\n\ | |
256 \n\ | |
257 @seealso{prs_iff,asm_initialize_system,asm_build_system}\n\ | |
258 \n\ | |
259 @end deftypefn\n \ | |
260 ") | |
261 { | |
262 | |
263 octave_value_list retval; // Contain returned values | |
264 octave_idx_type nargin = args.length(); | |
265 | |
266 /* Input parameters */ | |
267 string eltype; | |
268 ColumnVector parameters; | |
269 string_vector parameternames; | |
270 ColumnVector extvar; | |
271 ColumnVector intvar(5,0.0); | |
272 double t; | |
273 | |
274 /* Model parameters */ | |
275 double rd; | |
276 double W,L; | |
277 double mu0,Vth,Cox; | |
278 double Cgs,Cgd,Cgb,Csb,Cdb; | |
279 double Tshift; | |
280 | |
281 /* Model variables */ | |
282 double vg; // V-gate | |
283 double vs; // V-source | |
284 double vd; // V-drain | |
285 double vb; // V-bulk | |
286 double T ; // Temperature | |
287 | |
288 double Qgb;// Charges | |
289 double Qgs; | |
290 double Qgd; | |
291 double Qsb; | |
292 double Qdb; | |
293 | |
294 double gm; // Conductances et similia | |
295 double gd; | |
296 double ids; | |
297 double didT; | |
298 double P; | |
299 double dPdT; | |
300 double dPdvgs; | |
301 double dPdvds; | |
302 | |
303 /* Output values */ | |
304 Matrix a(10,10,0.0), b(10,10,0.0); | |
305 ColumnVector c(10,0.0); | |
306 | |
307 /* Check and retrieve input */ | |
308 if (nargin != 6) | |
309 error("Mshichmanhodgesmosfet: wrong number of input parameters.\n"); | |
310 else | |
311 { | |
312 /* Retrieve input parameters */ | |
313 // Type of MOS-FET | |
314 if (args(0).is_string()) | |
315 eltype = args(0).string_value(); | |
316 else | |
317 error("Mshichmanhodgesmosfet: argument #1 is expected to be a string.\n"); | |
318 // Parameters and parameter names | |
319 if (args(1).length() == args(2).length()) | |
320 { | |
321 parameters = args(1).column_vector_value(); | |
322 parameternames = args(2).all_strings(); | |
323 } | |
324 else | |
325 error("Mshichmanhodgesmosfet: parameters and parameternames are expected to have the same length.\n"); | |
326 // External pins | |
327 if (args(3).length() == 5) | |
328 extvar = args(3).column_vector_value(); | |
329 else | |
330 error("Mshichmanhodgesmosfet: five external values expected.\n"); | |
331 // Internal variables | |
332 if (args(4).is_empty()) | |
333 {} | |
334 else if (args(4).length() == 5) | |
335 intvar = args(4).column_vector_value(); | |
336 else | |
337 error("Mshichmanhodgesmosfet: five internal values expected.\n"); | |
338 // Time point | |
339 if (args(5).is_real_scalar()) | |
340 t = args(5).double_value(); | |
341 else | |
342 error("Mshichmanhodgesmosfet: double type value expected as time instant.\n"); | |
343 } | |
344 | |
345 if (!error_state) | |
346 { | |
347 //FIXME: create enum of cases and use switch? | |
348 if (eltype == "NMOS") | |
349 { | |
350 //FIXME: change parameters to a single map or Octave_map | |
351 /* Default n-MOS parameters*/ | |
352 rd = 1e6; | |
353 W = 1; | |
354 L = 1; | |
355 mu0 = 1e-5; | |
356 Vth = .5; | |
357 Cox = 1e-9; | |
358 Cgb = Cox; | |
359 Cgs = .1*Cox; | |
360 Cgd = .1*Cox; | |
361 Csb = .1*Cox; | |
362 Cdb = .1*Cox; | |
363 Tshift = 0; | |
364 | |
365 /* Overwrite parameters */ | |
366 set_parameters(parameters, parameternames, &rd, &W, &L, &mu0, &Vth, &Cox, &Cgs, &Cgd, &Cgb, &Csb, &Cdb, &Tshift); | |
367 //FIXME: debug | |
368 //print_parameters(rd, W, L, mu0, Vth, Cox, Cgs, Cgd, Cgb, Csb, Cdb, Tshift); | |
369 | |
370 /* Compute model conductance and capacitance */ | |
371 nmos(extvar,mu0,Cox,W,L,Vth,rd,Tshift,&gm,&gd,&ids,&didT,&P,&dPdT,&dPdvgs,&dPdvds); | |
372 //FIXME: debug | |
373 //print_values(gm, gd, ids, didT, P, dPdT, dPdvgs, dPdvds); | |
374 | |
375 /* Assemble output values*/ | |
376 vg = extvar(0); // V-gate | |
377 vs = extvar(1); // V-source | |
378 vd = extvar(2); // V-drain | |
379 vb = extvar(3); // V-bulk | |
380 T = extvar(4); // Temperature | |
381 | |
382 Qgb = intvar(0); | |
383 Qgs = intvar(1); | |
384 Qgd = intvar(2); | |
385 Qsb = intvar(3); | |
386 Qdb = intvar(4); | |
387 | |
388 //FIXME: probably a better way to initialize Matrix exist! | |
389 /* Dynamic matrix (constant) */ | |
390 a(0,5) = 1; | |
391 a(0,6) = 1; | |
392 a(0,7) = 1; | |
393 a(1,6) = -1; | |
394 a(1,8) = 1; | |
395 a(2,7) = -1; | |
396 a(2,9) = 1; | |
397 a(3,5) = -1; | |
398 a(3,8) = -1; | |
399 a(3,9) = -1; | |
400 | |
401 /* Algebraic part (non-linear) */ | |
402 b(1,0) = -gm; | |
403 b(1,1) = (gm+gd); | |
404 b(1,2) = -gd; | |
405 b(1,4) = -didT; | |
406 b(2,0) = gm; | |
407 b(2,1) = -(gm+gd); | |
408 b(2,2) = gd; | |
409 b(2,4) = didT; | |
410 b(4,0) = dPdvgs; | |
411 b(4,1) = -(dPdvgs+dPdvds); | |
412 b(4,2) = dPdvds; | |
413 b(4,4) = dPdT; | |
414 | |
415 b(5,0) = Cgb; | |
416 b(5,3) = -Cgb; | |
417 b(6,0) = Cgs; | |
418 b(6,1) = -Cgs; | |
419 b(7,0) = Cgd; | |
420 b(7,2) = -Cgd; | |
421 b(8,1) = Csb; | |
422 b(8,3) = -Csb; | |
423 b(9,2) = Cdb; | |
424 b(9,3) = -Cdb; | |
425 | |
426 b(5,5) = -1; | |
427 b(6,6) = -1; | |
428 b(7,7) = -1; | |
429 b(8,8) = -1; | |
430 b(9,9) = -1; | |
431 | |
432 /* Residual */ | |
433 c(0) = 0; | |
434 c(1) = -ids; | |
435 c(2) = ids; | |
436 c(4) = P; | |
437 c(5) = Cgb*(vg - vb) - Qgb; | |
438 c(6) = Cgs*(vg - vs) - Qgs; | |
439 c(7) = Cgd*(vg - vd) - Qgd; | |
440 c(8) = Csb*(vs - vb) - Qsb; | |
441 c(9) = Cdb*(vd - vb) - Qdb; | |
442 | |
443 /* Return values */ | |
444 retval(0) = octave_value(a); | |
445 retval(1) = octave_value(b); | |
446 retval(2) = octave_value(c); | |
447 | |
448 } | |
449 else if (eltype == "PMOS") | |
450 { | |
451 /* Default p-MOS parameters*/ | |
452 rd = 1e6; | |
453 W = 1; | |
454 L = 1; | |
455 mu0 = 1e-5; | |
456 Vth = -.5; | |
457 Cox = 1e-9; | |
458 Cgb = Cox; | |
459 Cgs = .1*Cox; | |
460 Cgd = .1*Cox; | |
461 Csb = .1*Cox; | |
462 Cdb = .1*Cox; | |
463 Tshift = 0; | |
464 | |
465 /* Overwrite parameters */ | |
466 set_parameters(parameters, parameternames, &rd, &W, &L, &mu0, &Vth, &Cox, &Cgs, &Cgd, &Cgb, &Csb, &Cdb, &Tshift); | |
467 | |
468 /* Compute model conductance and capacitance */ | |
469 pmos(extvar,mu0,Cox,W,L,Vth,rd,Tshift,&gm,&gd,&ids,&didT,&P,&dPdT,&dPdvgs,&dPdvds); | |
470 | |
471 /* Assemble output values*/ | |
472 vg = extvar(0); // V-gate | |
473 vs = extvar(1); // V-source | |
474 vd = extvar(2); // V-drain | |
475 vb = extvar(3); // V-bulk | |
476 T = extvar(4); // Temperature | |
477 | |
478 Qgb = intvar(0); | |
479 Qgs = intvar(1); | |
480 Qgd = intvar(2); | |
481 Qsb = intvar(3); | |
482 Qdb = intvar(4); | |
483 | |
484 /* Dynamic matrix (constant) */ | |
485 a(0,5) = 1; | |
486 a(0,6) = 1; | |
487 a(0,7) = 1; | |
488 a(1,6) = -1; | |
489 a(1,8) = 1; | |
490 a(2,7) = -1; | |
491 a(2,9) = 1; | |
492 a(3,5) = -1; | |
493 a(3,8) = -1; | |
494 a(3,9) = -1; | |
495 | |
496 /* Algebraic part (non-linear) */ | |
497 b(1,0) = -gm; | |
498 b(1,1) = (gm+gd); | |
499 b(1,2) = -gd; | |
500 b(1,4) = -didT; | |
501 b(2,0) = gm; | |
502 b(2,1) = -(gm+gd); | |
503 b(2,2) = gd; | |
504 b(2,4) = didT; | |
505 b(4,0) = dPdvgs; | |
506 b(4,1) = -(dPdvgs+dPdvds); | |
507 b(4,2) = dPdvds; | |
508 b(4,4) = dPdT; | |
509 | |
510 b(5,0) = Cgb; | |
511 b(5,3) = -Cgb; | |
512 b(6,0) = Cgs; | |
513 b(6,1) = -Cgs; | |
514 b(7,0) = Cgd; | |
515 b(7,2) = -Cgd; | |
516 b(8,1) = Csb; | |
517 b(8,3) = -Csb; | |
518 b(9,2) = Cdb; | |
519 b(9,3) = -Cdb; | |
520 | |
521 b(5,5) = -1; | |
522 b(6,6) = -1; | |
523 b(7,7) = -1; | |
524 b(8,8) = -1; | |
525 b(9,9) = -1; | |
526 | |
527 /* Residual */ | |
528 c(0) = 0; | |
529 c(1) = -ids; | |
530 c(2) = ids; | |
531 c(4) = P; | |
532 c(5) = Cgb*(vg - vb) - Qgb; | |
533 c(6) = Cgs*(vg - vs) - Qgs; | |
534 c(7) = Cgd*(vg - vd) - Qgd; | |
535 c(8) = Csb*(vs - vb) - Qsb; | |
536 c(9) = Cdb*(vd - vb) - Qdb; | |
537 | |
538 /* Return values */ | |
539 retval(0) = octave_value(a); | |
540 retval(1) = octave_value(b); | |
541 retval(2) = octave_value(c); | |
542 } | |
543 else | |
544 error("Mshichmanhodgesmosfet: unknown element type.\n"); | |
545 | |
546 } | |
547 | |
12674 | 548 return (retval); |
6667 | 549 } |