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)
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
21 *------------------------------------------------------------------
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
33 /*--------------------------------------------------------------------------*/
35 /*--------------------------------------------------------------------------*/
36 class DEV_INDUCTANCE
: public STORAGE
{
38 explicit DEV_INDUCTANCE(const DEV_INDUCTANCE
& p
)
39 :STORAGE(p
), _c_model(p
._c_model
) {}
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);}
58 void tr_iwant_matrix();
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
;}
73 COMPLEX
ac_involts()const {return ac_outvolts();}
74 COMPLEX
ac_amps()const;
76 std::string
port_name(int i
)const {itested();
79 static std::string names
[] = {"p", "n"};
85 /*--------------------------------------------------------------------------*/
86 class DEV_MUTUAL_L
: public DEV_INDUCTANCE
{
88 std::string _output_label
;
89 DEV_INDUCTANCE
* _output
;
90 std::string _input_label
;
91 DEV_INDUCTANCE
* _input
;
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
];
104 explicit DEV_MUTUAL_L(const DEV_MUTUAL_L
& p
);
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);}
123 void tr_iwant_matrix() {tr_iwant_matrix_passive();}
127 bool do_tr() {_sim
->_late_evalq
.push_back(this); return true;}
130 TIME_PAIR
tr_review() {return TIME_PAIR(NEVER
,NEVER
);}
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();}
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 {
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();
156 std::string
current_port_name(int i
)const {untested();
159 static std::string names
[] = {"l1", "l2"};
162 const std::string
current_port_value(int i
)const {
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
) {
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()
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
)
200 _output_label(p
._output_label
),
202 _input_label(p
._input_label
),
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()
220 if (_sim
->is_first_expand()) {
222 _n
[IN1
].set_to_ground(this);
224 _n
[IN1
].new_model_node(long_label() + ".i", this);
229 /*--------------------------------------------------------------------------*/
230 void DEV_MUTUAL_L::expand_first()
232 _output
= dynamic_cast<DEV_INDUCTANCE
*>(find_in_my_scope(_output_label
));
234 throw Exception_Type_Mismatch(long_label(), _output_label
, "inductor");
236 _output
->_c_model
= true;
239 _input
= dynamic_cast<DEV_INDUCTANCE
*>(find_in_my_scope(_input_label
));
241 throw Exception_Type_Mismatch(long_label(), _input_label
, "inductor");
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
);
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];
277 /*--------------------------------------------------------------------------*/
278 void DEV_INDUCTANCE::tr_iwant_matrix()
281 tr_iwant_matrix_passive();
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()
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
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
) {
326 /*--------------------------------------------------------------------------*/
327 void DEV_MUTUAL_L::tr_advance()
329 STORAGE::tr_advance();
331 for (int i
=OPT::_keep_time_steps
-1; i
>0; --i
) {
338 /*--------------------------------------------------------------------------*/
339 bool DEV_INDUCTANCE::do_tr()
341 if (using_tr_eval()) {
342 _y
[0].x
= tr_input_limited(); // _m0.c0 + _m0.c1 * x;
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());
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
;
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
);
365 _m0
.c1
= 1 / ((_i
[0].c1()==0) ? OPT::shortckt
: _i
[0].c1());
366 _m0
.c0
= -_i
[0].c0() * _m0
.c1
;
368 //_m0 = -CPOLY1(_i[0]);
370 _m0
.c1
= -_loss0
* _loss0
* _i
[0].c1();
371 _m0
.c0
= _loss0
* _loss0
* _i
[0].c0();
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
385 _y
[0].f0
= _y
[0].x
* _y
[0].f1
; // flux = I * L
386 trace3("", _y
[0].x
, _y
[0].f0
, _y
[0].f1
);
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
);
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();
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();
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();
418 /*--------------------------------------------------------------------------*/
419 void DEV_INDUCTANCE::tr_load()
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()
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()
440 _loss0
= _m0
.c0
= _m0
.c1
= 0.;
441 _sim
->mark_inc_mode_bad();
444 /*--------------------------------------------------------------------------*/
445 void DEV_MUTUAL_L::tr_unload()
449 /*--------------------------------------------------------------------------*/
450 double DEV_INDUCTANCE::tr_input()const
453 return _m0
.c0
+ _m0
.c1
* tr_involts();
458 /*--------------------------------------------------------------------------*/
459 double DEV_INDUCTANCE::tr_input_limited()const
462 return _m0
.c0
+ _m0
.c1
* tr_involts_limited();
467 /*--------------------------------------------------------------------------*/
468 double DEV_INDUCTANCE::tr_amps()const
471 return fixzero((_m0
.c1
* tr_involts() + _m0
.c0
), _m0
.c0
);
473 return _loss0
* _n
[IN1
].v0();
476 /*--------------------------------------------------------------------------*/
477 void DEV_INDUCTANCE::ac_iwant_matrix()
480 ac_iwant_matrix_passive();
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()) {
498 assert(_ev
== _y
[0].f1
);
499 assert(dynamic_cast<DEV_MUTUAL_L
*>(this) || has_tr_eval() || _ev
== double(value()));
502 if (_ev
* _sim
->_jomega
== 0.) {untested();
503 _acg
= 1. / OPT::shortckt
;
505 _acg
= 1. / (_ev
* _sim
->_jomega
);
508 _acg
= -_loss0
* _loss0
* _ev
* _sim
->_jomega
;
511 /*--------------------------------------------------------------------------*/
512 void DEV_INDUCTANCE::ac_load()
518 ac_load_diagonal_point(_n
[IN1
], _acg
);
521 /*--------------------------------------------------------------------------*/
522 void DEV_MUTUAL_L::ac_load()
526 /*--------------------------------------------------------------------------*/
527 COMPLEX
DEV_INDUCTANCE::ac_amps()const
530 return (ac_involts() * _acg
);
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();
540 }else if (Umatch(x
, "ind{uctance} |l ")) {untested();
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
);
551 return STORAGE::tr_probe_num(x
);
554 /*--------------------------------------------------------------------------*/
555 double DEV_MUTUAL_L::tr_probe_num(const std::string
& x
)const
557 if (Umatch(x
, "fflux ")) {untested();
559 }else if (Umatch(x
, "rflux ")) {untested();
561 }else if (Umatch(x
, "fiof{fset} ")) {untested();
563 }else if (Umatch(x
, "riof{fset} ")) {untested();
566 return DEV_INDUCTANCE::tr_probe_num(x
);
569 /*--------------------------------------------------------------------------*/
570 /*--------------------------------------------------------------------------*/
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: