viminfo
[gnucap-felix.git] / apps / d_coil.cc
blobc4afdf97f22229fac53769eba18ec553305c91cf
1 /*$Id: d_coil.cc,v 26.137 2010/04/10 02:37:05 al Exp $ -*- C++ -*-
2 * Copyright (C) 2001 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *------------------------------------------------------------------
22 * inductors
23 * y.x = amps, y.f0 = flux, ev = y.f1 = henrys
24 * q = y history in time
25 * i.x = amps, i.f0 = volts, i.f1 = ohms
26 * m.x = volts, m.c0 = amps, acg = m.c1 = mhos
28 //testing=script 2008.10.09
29 #include "globals.h"
30 #include "e_subckt.h"
31 #include "e_ccsrc.h"
32 #include "e_storag.h"
33 /*--------------------------------------------------------------------------*/
34 namespace {
35 /*--------------------------------------------------------------------------*/
36 class DEV_INDUCTANCE : public STORAGE {
37 protected:
38 explicit DEV_INDUCTANCE(const DEV_INDUCTANCE& p)
39 :STORAGE(p), _c_model(p._c_model) {}
40 public:
41 explicit DEV_INDUCTANCE()
42 :STORAGE(), _c_model(false) {}
43 public: // override virtual
44 char id_letter()const {return 'L';}
45 std::string value_name()const {return "l";}
46 std::string dev_type()const {return "inductor";}
47 int max_nodes()const {return 2;}
48 int min_nodes()const {return 2;}
49 int net_nodes()const {return 2;}
50 int int_nodes()const {return (!_c_model) ? 0 : 1;}
51 int matrix_nodes()const {return net_nodes() + int_nodes();}
53 bool has_inode()const {return _c_model;}
54 bool has_iv_probe()const {return true;}
55 bool use_obsolete_callback_parse()const {return true;}
56 CARD* clone()const {return new DEV_INDUCTANCE(*this);}
57 void expand();
58 void tr_iwant_matrix();
59 void tr_begin();
60 bool do_tr();
61 void tr_load();
62 void tr_unload();
63 double tr_involts()const {return tr_outvolts();}
64 double tr_input()const;
65 double tr_involts_limited()const {return tr_outvolts_limited();}
66 double tr_input_limited()const;
67 double tr_amps()const;
68 double tr_probe_num(const std::string&)const;
69 void ac_iwant_matrix();
70 void ac_begin() {_loss1 = _loss0 = ((!_c_model) ? 0. : 1.); _ev = _y[0].f1;}
71 void do_ac();
72 void ac_load();
73 COMPLEX ac_involts()const {return ac_outvolts();}
74 COMPLEX ac_amps()const;
76 std::string port_name(int i)const {itested();
77 assert(i >= 0);
78 assert(i < 2);
79 static std::string names[] = {"p", "n"};
80 return names[i];
83 bool _c_model;
85 /*--------------------------------------------------------------------------*/
86 class DEV_MUTUAL_L : public DEV_INDUCTANCE {
87 private:
88 std::string _output_label;
89 DEV_INDUCTANCE* _output;
90 std::string _input_label;
91 DEV_INDUCTANCE* _input;
92 double _lm;
93 double _mf0_c0; // matrix parameters, new
94 double _mf1_c0; // matrix parameters, 1 fill ago
95 double _mr0_c0; // matrix parameters, new
96 double _mr1_c0; // matrix parameters, 1 fill ago
97 FPOLY1 _yf1; // iteration parameters, 1 iter ago
98 FPOLY1 _yf[OPT::_keep_time_steps];
99 FPOLY1 _if[OPT::_keep_time_steps];
100 FPOLY1 _yr1; // iteration parameters, 1 iter ago
101 FPOLY1 _yr[OPT::_keep_time_steps];
102 FPOLY1 _ir[OPT::_keep_time_steps];
103 private:
104 explicit DEV_MUTUAL_L(const DEV_MUTUAL_L& p);
105 public:
106 explicit DEV_MUTUAL_L();
107 private: // override virtual
108 char id_letter()const {return 'K';}
109 bool print_type_in_spice()const {return false;}
110 std::string value_name()const {return "k";}
111 std::string dev_type()const {untested(); return "mutual_inductor";}
112 int max_nodes()const {return 2;}
113 int min_nodes()const {return 2;}
114 int matrix_nodes()const {return 2;}
115 int net_nodes()const {return 0;}
116 int num_current_ports()const {return 2;}
117 bool has_iv_probe()const {untested(); return false;}
118 bool use_obsolete_callback_parse()const {return false;}
119 CARD* clone()const {return new DEV_MUTUAL_L(*this);}
120 void expand_first();
121 void expand_last();
122 void precalc_last();
123 void tr_iwant_matrix() {tr_iwant_matrix_passive();}
124 void tr_begin();
125 void dc_advance();
126 void tr_advance();
127 bool do_tr() {_sim->_late_evalq.push_back(this); return true;}
128 bool do_tr_last();
129 void tr_load();
130 TIME_PAIR tr_review() {return TIME_PAIR(NEVER,NEVER);}
131 void tr_unload();
132 double tr_input()const {return tr_involts();}
133 double tr_input_limited()const {untested(); return tr_involts_limited();}
134 double tr_amps()const {untested(); return _loss0 * tr_outvolts();}
135 double tr_probe_num(const std::string&)const;
137 void ac_iwant_matrix() {ac_iwant_matrix_passive();}
138 void ac_load();
139 COMPLEX ac_amps()const {untested(); return _loss0 * ac_outvolts();}
141 void set_port_by_name(std::string& Name, std::string& Value)
142 {untested(); COMPONENT::set_port_by_name(Name,Value);}
143 void set_port_by_index(int Index, std::string& Value)
144 {set_current_port_by_index(Index, Value);}
145 bool node_is_connected(int i)const {
146 switch (i) {
147 case 0: return _output_label != "";
148 case 1: return _input_label != "";
149 default: unreachable(); return false;
153 std::string port_name(int)const {untested();
154 return "";
156 std::string current_port_name(int i)const {untested();
157 assert(i >= 0);
158 assert(i < 2);
159 static std::string names[] = {"l1", "l2"};
160 return names[i];
162 const std::string current_port_value(int i)const {
163 switch (i) {
164 case 0: return _output_label;
165 case 1: return _input_label;
166 default: unreachable(); return COMPONENT::current_port_value(i);
169 void set_current_port_by_index(int i, const std::string& s) {
170 switch (i) {
171 case 0: _output_label = s; break;
172 case 1: _input_label = s; break;
173 default: unreachable(); break;
177 /*--------------------------------------------------------------------------*/
178 /*--------------------------------------------------------------------------*/
179 DEV_MUTUAL_L::DEV_MUTUAL_L()
180 :DEV_INDUCTANCE(),
181 _output_label(),
182 _output(0),
183 _input_label(),
184 _input(0),
185 _lm(NOT_INPUT),
186 _mf0_c0(0.),
187 _mf1_c0(0.),
188 _mr0_c0(0.),
189 _mr1_c0(0.)
191 _c_model = true;
192 assert(_yf[0].x == 0. && _yf[0].f0 == 0. && _yf[0].f1 == 0.);
193 assert(_yf1 == _yf[0]);
194 assert(_yr[0].x == 0. && _yr[0].f0 == 0. && _yr[0].f1 == 0.);
195 assert(_yr1 == _yr[0]);
197 /*--------------------------------------------------------------------------*/
198 DEV_MUTUAL_L::DEV_MUTUAL_L(const DEV_MUTUAL_L& p)
199 :DEV_INDUCTANCE(p),
200 _output_label(p._output_label),
201 _output(p._output),
202 _input_label(p._input_label),
203 _input(p._input),
204 _lm(p._lm),
205 _mf0_c0(0.),
206 _mf1_c0(0.),
207 _mr0_c0(0.),
208 _mr1_c0(0.)
210 _c_model = true;
211 assert(_yf[0].x == 0. && _yf[0].f0 == 0. && _yf[0].f1 == 0.);
212 assert(_yf1 == _yf[0]);
213 assert(_yr[0].x == 0. && _yr[0].f0 == 0. && _yr[0].f1 == 0.);
214 assert(_yr1 == _yr[0]);
216 /*--------------------------------------------------------------------------*/
217 void DEV_INDUCTANCE::expand()
219 STORAGE::expand();
220 if (_sim->is_first_expand()) {
221 if (!_c_model) {
222 _n[IN1].set_to_ground(this);
223 }else{
224 _n[IN1].new_model_node(long_label() + ".i", this);
226 }else{untested();
229 /*--------------------------------------------------------------------------*/
230 void DEV_MUTUAL_L::expand_first()
232 _output = dynamic_cast<DEV_INDUCTANCE*>(find_in_my_scope(_output_label));
233 if (!_output) {
234 throw Exception_Type_Mismatch(long_label(), _output_label, "inductor");
235 }else{
236 _output->_c_model = true;
239 _input = dynamic_cast<DEV_INDUCTANCE*>(find_in_my_scope(_input_label));
240 if (!_input) {
241 throw Exception_Type_Mismatch(long_label(), _input_label, "inductor");
242 }else{
243 _input->_c_model = true;
246 /*--------------------------------------------------------------------------*/
247 void DEV_MUTUAL_L::expand_last()
249 STORAGE::expand(); // skip DEV_INDUCTANCE
250 if (_sim->is_first_expand()) {
251 _n[OUT2] = _input->n_(IN1);
252 _n[OUT1] = _output->n_(IN1);
253 }else{untested();
256 /*--------------------------------------------------------------------------*/
257 void DEV_MUTUAL_L::precalc_last()
259 _output->precalc_last();
260 _input->precalc_last();
262 DEV_INDUCTANCE::precalc_last();
264 double l1 = _output->value();
265 double l2 = _input->value();
266 _lm = value() * sqrt(l1 * l2);
267 trace3(long_label().c_str(), l1, l2, _lm);
269 if (_sim->is_first_expand()) {
270 assert(_y[0].x == 0.);
271 assert(_y[0].f0 == LINEAR);
272 _y[0].f1 = -_lm; // override
273 _yf[0] = _yr[0] = _y[0];
274 }else{
277 /*--------------------------------------------------------------------------*/
278 void DEV_INDUCTANCE::tr_iwant_matrix()
280 if (!_c_model) {
281 tr_iwant_matrix_passive();
282 }else{
283 assert(matrix_nodes() == 3);
285 assert(_n[OUT1].m_() != INVALID_NODE);
286 assert(_n[OUT2].m_() != INVALID_NODE);
287 assert(_n[IN1].m_() != INVALID_NODE);
289 _sim->_aa.iwant(_n[OUT1].m_(),_n[IN1].m_());
290 _sim->_aa.iwant(_n[OUT2].m_(),_n[IN1].m_());
292 _sim->_lu.iwant(_n[OUT1].m_(),_n[IN1].m_());
293 _sim->_lu.iwant(_n[OUT2].m_(),_n[IN1].m_());
296 /*--------------------------------------------------------------------------*/
297 void DEV_INDUCTANCE::tr_begin()
299 STORAGE::tr_begin();
300 _loss1 = _loss0 = ((!_c_model) ? 0. : 1.);
302 /*--------------------------------------------------------------------------*/
303 void DEV_MUTUAL_L::tr_begin()
305 DEV_INDUCTANCE::tr_begin();
306 assert(_y[0].x == 0.);
307 assert(_y[0].f0 == LINEAR);
308 _y[0].f1 = -_lm; // override
309 _y1 = _y[0];
311 for (int i = 0; i < OPT::_keep_time_steps; ++i) {
312 _if[i] = _ir[i] = FPOLY1(0., 0., 0.);
314 _mf1_c0 = _mf0_c0 = _mr1_c0 = _mr0_c0 = 0.;
316 /*--------------------------------------------------------------------------*/
317 void DEV_MUTUAL_L::dc_advance()
319 STORAGE::dc_advance();
321 for (int i = 1; i < OPT::_keep_time_steps; ++i) {
322 _if[i] = _if[0];
323 _ir[i] = _ir[0];
326 /*--------------------------------------------------------------------------*/
327 void DEV_MUTUAL_L::tr_advance()
329 STORAGE::tr_advance();
331 for (int i=OPT::_keep_time_steps-1; i>0; --i) {
332 _yf[i] = _yf[i-1];
333 _yr[i] = _yr[i-1];
334 _if[i] = _if[i-1];
335 _ir[i] = _ir[i-1];
338 /*--------------------------------------------------------------------------*/
339 bool DEV_INDUCTANCE::do_tr()
341 if (using_tr_eval()) {
342 _y[0].x = tr_input_limited(); // _m0.c0 + _m0.c1 * x;
343 tr_eval();
344 if ((!_c_model) && (_y[0].f1 == 0.)) {untested();
345 error(bDANGER, long_label() + ": short circuit, L = 0\n");
346 _y[0].f1 = OPT::shortckt;
347 set_converged(conv_check());
348 }else{
350 }else{
351 _y[0].x = tr_input(); // _m0.c0 + _m0.c1 * x;
352 assert(_y[0].f1 == value());
353 _y[0].f0 = _y[0].x * _y[0].f1;
354 assert(converged());
356 store_values();
357 q_load();
359 // i is really voltage ..
360 // _i[0].x = current, _i[0].f0 = voltage, _i[0].f1 = ohms
361 _i[0] = differentiate(_y, _i, _time, _method_a);
363 if (!_c_model) {
364 _m0.x = NOT_VALID;
365 _m0.c1 = 1 / ((_i[0].c1()==0) ? OPT::shortckt : _i[0].c1());
366 _m0.c0 = -_i[0].c0() * _m0.c1;
367 }else{
368 //_m0 = -CPOLY1(_i[0]);
369 _m0.x = NOT_VALID;
370 _m0.c1 = -_loss0 * _loss0 * _i[0].c1();
371 _m0.c0 = _loss0 * _loss0 * _i[0].c0();
374 return converged();
376 /*--------------------------------------------------------------------------*/
377 bool DEV_MUTUAL_L::do_tr_last()
379 double l1 = _output->_y[0].f1;
380 double l2 = _input->_y[0].f1;
381 _lm = value() * sqrt(l1 * l2);
383 _y[0].x = _n[OUT1].v0() - _n[OUT2].v0(); // really current
384 _y[0].f1 = -_lm;
385 _y[0].f0 = _y[0].x * _y[0].f1; // flux = I * L
386 trace3("", _y[0].x, _y[0].f0, _y[0].f1);
387 store_values();
388 _i[0] = differentiate(_y, _i, _time, _method_a); // really voltage, v = df/dt
389 trace3("", _i[0].x, _i[0].f0, _i[0].f1);
390 _m0.x = NOT_VALID;
391 _m0.c1 = -_loss0 * _loss0 * _i[0].c1();
392 _m0.c0 = -_loss0 * _loss0 * _i[0].c0();
393 trace3("", _m0.x, _m0.c0, _m0.c1);
395 _yf[0].x = _n[OUT1].v0();
396 _yf[0].f1 = -_lm;
397 _yf[0].f0 = _yf[0].x * _yf[0].f1;
398 trace3("", _yf[0].x, _yf[0].f0, _yf[0].f1);
399 assert(_yf[0]==_yf[0]); // store_values();
400 _yf1=_yf[0]; // store_values();
401 _if[0] = differentiate(_yf, _if, _time, _method_a);
402 trace3("", _if[0].x, _if[0].f0, _if[0].f1);
403 _mf0_c0 = -_loss0 * _loss0 * _if[0].c0();
405 _yr[0].x = _n[OUT2].v0();
406 _yr[0].f1 = -_lm;
407 _yr[0].f0 = _yr[0].x * _yr[0].f1;
408 trace3("", _yr[0].x, _yr[0].f0, _yr[0].f1);
409 assert(_yr[0]==_yr[0]); // store_values();
410 _yr1=_yr[0]; // store_values();
411 _ir[0] = differentiate(_yr, _ir, _time, _method_a);
412 trace3("", _ir[0].x, _ir[0].f0, _ir[0].f1);
413 _mr0_c0 = -_loss0 * _loss0 * _ir[0].c0();
415 q_load();
416 return true;
418 /*--------------------------------------------------------------------------*/
419 void DEV_INDUCTANCE::tr_load()
421 if (!_c_model) {
422 tr_load_passive();
423 }else{
424 tr_load_inode();
425 tr_load_diagonal_point(_n[IN1], &_m0.c1, &_m1.c1);
426 tr_load_source_point(_n[IN1], &_m0.c0, &_m1.c0);
429 /*--------------------------------------------------------------------------*/
430 void DEV_MUTUAL_L::tr_load()
432 tr_load_couple();
433 tr_load_source();
434 tr_load_source_point(_n[OUT2], &_mr0_c0, &_mr1_c0);
435 tr_load_source_point(_n[OUT1], &_mf0_c0, &_mf1_c0);
437 /*--------------------------------------------------------------------------*/
438 void DEV_INDUCTANCE::tr_unload()
439 {untested();
440 _loss0 = _m0.c0 = _m0.c1 = 0.;
441 _sim->mark_inc_mode_bad();
442 tr_load();
444 /*--------------------------------------------------------------------------*/
445 void DEV_MUTUAL_L::tr_unload()
446 {untested();
447 tr_unload_couple();
449 /*--------------------------------------------------------------------------*/
450 double DEV_INDUCTANCE::tr_input()const
452 if (!_c_model) {
453 return _m0.c0 + _m0.c1 * tr_involts();
454 }else{
455 return _n[IN1].v0();
458 /*--------------------------------------------------------------------------*/
459 double DEV_INDUCTANCE::tr_input_limited()const
461 if (!_c_model) {
462 return _m0.c0 + _m0.c1 * tr_involts_limited();
463 }else{
464 return _n[IN1].v0();
467 /*--------------------------------------------------------------------------*/
468 double DEV_INDUCTANCE::tr_amps()const
470 if (!_c_model) {
471 return fixzero((_m0.c1 * tr_involts() + _m0.c0), _m0.c0);
472 }else{
473 return _loss0 * _n[IN1].v0();
476 /*--------------------------------------------------------------------------*/
477 void DEV_INDUCTANCE::ac_iwant_matrix()
479 if (!_c_model) {
480 ac_iwant_matrix_passive();
481 }else{
482 assert(matrix_nodes() == 3);
484 assert(_n[OUT1].m_() != INVALID_NODE);
485 assert(_n[OUT2].m_() != INVALID_NODE);
486 assert(_n[IN1].m_() != INVALID_NODE);
488 _sim->_acx.iwant(_n[OUT1].m_(),_n[IN1].m_());
489 _sim->_acx.iwant(_n[OUT2].m_(),_n[IN1].m_());
492 /*--------------------------------------------------------------------------*/
493 void DEV_INDUCTANCE::do_ac()
495 if (using_ac_eval()) {
496 ac_eval();
497 }else{
498 assert(_ev == _y[0].f1);
499 assert(dynamic_cast<DEV_MUTUAL_L*>(this) || has_tr_eval() || _ev == double(value()));
501 if (!_c_model) {
502 if (_ev * _sim->_jomega == 0.) {untested();
503 _acg = 1. / OPT::shortckt;
504 }else{
505 _acg = 1. / (_ev * _sim->_jomega);
507 }else{
508 _acg = -_loss0 * _loss0 * _ev * _sim->_jomega;
511 /*--------------------------------------------------------------------------*/
512 void DEV_INDUCTANCE::ac_load()
514 if (!_c_model) {
515 ac_load_passive();
516 }else{
517 ac_load_inode();
518 ac_load_diagonal_point(_n[IN1], _acg);
521 /*--------------------------------------------------------------------------*/
522 void DEV_MUTUAL_L::ac_load()
524 ac_load_couple();
526 /*--------------------------------------------------------------------------*/
527 COMPLEX DEV_INDUCTANCE::ac_amps()const
529 if (!_c_model) {
530 return (ac_involts() * _acg);
531 }else{
532 return _loss0 * _n[IN1].vac();
535 /*--------------------------------------------------------------------------*/
536 double DEV_INDUCTANCE::tr_probe_num(const std::string& x)const
538 if (Umatch(x, "flux ")) {untested();
539 return _y[0].f0;
540 }else if (Umatch(x, "ind{uctance} |l ")) {untested();
541 return _y[0].f1;
542 }else if (Umatch(x, "dldt ")) {untested();
543 return (_y[0].f1 - _y[1].f1) / _dt;
544 }else if (Umatch(x, "dl ")) {untested();
545 return (_y[0].f1 - _y[1].f1);
546 }else if (Umatch(x, "dfdt ")) {untested();
547 return (_y[0].f0 - _y[1].f0) / _dt;
548 }else if (Umatch(x, "dflux ")) {untested();
549 return (_y[0].f0 - _y[1].f0);
550 }else{
551 return STORAGE::tr_probe_num(x);
554 /*--------------------------------------------------------------------------*/
555 double DEV_MUTUAL_L::tr_probe_num(const std::string& x)const
556 {untested();
557 if (Umatch(x, "fflux ")) {untested();
558 return _yf[0].f0;
559 }else if (Umatch(x, "rflux ")) {untested();
560 return _yr[0].f0;
561 }else if (Umatch(x, "fiof{fset} ")) {untested();
562 return _mf0_c0;
563 }else if (Umatch(x, "riof{fset} ")) {untested();
564 return _mr0_c0;
565 }else{untested();
566 return DEV_INDUCTANCE::tr_probe_num(x);
569 /*--------------------------------------------------------------------------*/
570 /*--------------------------------------------------------------------------*/
571 DEV_MUTUAL_L p1;
572 DEV_INDUCTANCE p2;
573 DISPATCHER<CARD>::INSTALL
574 d1(&device_dispatcher, "K|mutual_inductor", &p1),
575 d2(&device_dispatcher, "L|inductor", &p2);
577 /*--------------------------------------------------------------------------*/
578 /*--------------------------------------------------------------------------*/
579 // vim:ts=8:sw=2:noet: