/*$Id: d_coil.cc,v 26.14 2007/02/07 09:06:48 al Exp $ -*- C++ -*- * Copyright (C) 2001 Albert Davis * Author: Albert Davis * * This file is part of "Gnucap", the Gnu Circuit Analysis Package * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. *------------------------------------------------------------------ * inductors * y.x = amps, y.f0 = flux, ev = y.f1 = henrys * q = y history in time * i.x = amps, i.f0 = volts, i.f1 = ohms * m.x = volts, m.c0 = amps, acg = m.c1 = mhos */ //testing=script 2006.07.17 #include "l_dispatcher.h" #include "e_ccsrc.h" #include "e_storag.h" extern DISPATCHER device_dispatcher; /*--------------------------------------------------------------------------*/ namespace { /*--------------------------------------------------------------------------*/ class DEV_INDUCTANCE : public STORAGE { private: explicit DEV_INDUCTANCE(const DEV_INDUCTANCE& p) :STORAGE(p) {} public: explicit DEV_INDUCTANCE() :STORAGE() {} public: // override virtual char id_letter()const {return 'L';} const char* dev_type()const {return "inductor";} int max_nodes()const {return 2;} int min_nodes()const {return 2;} int out_nodes()const {untested();return 2;} int matrix_nodes()const {return 2;} int net_nodes()const {return 2;} bool is_1port()const {return true;} CARD* clone()const {return new DEV_INDUCTANCE(*this);} //void parse_spice(CS&); //ELEMENT //void print(OMSTREAM,LANGUAGE)const; //ELEMENT //void elabo1(); //COMPONENT void map_nodes(); void precalc(); void tr_iwant_matrix(); void dc_begin(); void tr_begin(); void tr_restore(); void dc_advance(); void tr_advance(); bool tr_needs_eval()const; void tr_queue_eval(); bool do_tr(); void tr_load(); DPAIR tr_review(); //void tr_accept(); //CARD/nothing void tr_unload(); double tr_involts()const {return tr_outvolts();} double tr_input()const {return _m0.c0 + _m0.c1 * tr_involts();} double tr_involts_limited()const {return tr_outvolts_limited();} double tr_input_limited()const {return _m0.c0+_m0.c1*tr_involts_limited();} //double tr_amps()const //ELEMENT double tr_probe_num(CS&)const; void ac_iwant_matrix(); void ac_begin(); void do_ac(); void ac_load(); COMPLEX ac_involts()const {return ac_outvolts();} //COMPLEX ac_amps()const; //ELEMENT //XPROBE ac_probe_ext(CS&)const;//ELEMENT }; /*--------------------------------------------------------------------------*/ class DEV_MUTUAL_L : public COMPONENT { private: explicit DEV_MUTUAL_L(const DEV_MUTUAL_L& p); public: explicit DEV_MUTUAL_L(); private: // override virtual char id_letter()const {untested();return 'K';} bool print_type_in_spice()const {untested(); return false;} const char* dev_type()const {untested(); return "mutual_inductor";} int max_nodes()const {unreachable(); return 0;} int min_nodes()const {unreachable(); return 0;} //int out_nodes()const //CARD 0 //int matrix_nodes()const //CARD 0 //int net_nodes()const //CARD 0 bool is_2port()const {untested(); return true;} CARD* clone()const { return new DEV_MUTUAL_L(*this);} void parse_spice(CS&); void print(OMSTREAM&, LANGUAGE)const; void elabo1(); void map_nodes() {} //void precalc(); //CARD/nothing //void dc_begin(); //CARD/nothing //void tr_begin(); //CARD/nothing //void tr_restore(); //CARD/nothing //void dc_advance(); //CARD/nothing //void tr_advance(); //CARD/nothing //bool tr_needs_eval(); //CARD/nothing //void tr_queue_eval(); //CARD/nothing //bool do_tr(); //CARD/nothing //void tr_load(); //CARD/nothing //DPAIR tr_review(); //CARD/nothing //void tr_accept(); //CARD/nothing //void tr_unload(); //CARD/nothing #if 0 double tr_involts()const {untested(); return dn_diff(_n[IN1].v0(), _n[IN2].v0());} double tr_involts_limited()const {unreachable(); return volts_limited(_n[IN1],_n[IN2]);} #endif //double tr_probe_num(CS&)const;//CKT_BASE/nothing //void ac_begin(); //CARD/nothing //void do_ac(); //CARD/nothing //void ac_load(); //CARD/nothing COMPLEX ac_involts()const {untested();return _n[IN1]->vac()-_n[IN2]->vac();} //XPROBE ac_probe_ext(CS&)const;//CKT_BASE/nothing private: std::string _output_label; DEV_INDUCTANCE* _output; std::string _input_label; DEV_INDUCTANCE* _input; }; /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ DEV_MUTUAL_L::DEV_MUTUAL_L() :COMPONENT(), _output_label(), _output(0), _input_label(), _input(0) { } /*--------------------------------------------------------------------------*/ DEV_MUTUAL_L::DEV_MUTUAL_L(const DEV_MUTUAL_L& p) :COMPONENT(p), _output_label(p._output_label), _output(p._output), _input_label(p._input_label), _input(p._input) { } /*--------------------------------------------------------------------------*/ void DEV_MUTUAL_L::parse_spice(CS& cmd) { parse_Label(cmd); _output_label = cmd.ctos(TOKENTERM); _output_label[0] = toupper(_output_label[0]); _input_label = cmd.ctos(TOKENTERM); _input_label[0] = toupper(_input_label[0]); set_value(cmd.ctof()); } /*--------------------------------------------------------------------------*/ void DEV_MUTUAL_L::print(OMSTREAM& o, LANGUAGE lang)const { assert(lang == lSPICE); o << short_label(); if (_output) { o << ' ' << _output->short_label(); }else{ o << " " << _output_label; } if (_input) { o << ' ' << _input->short_label(); }else{ o << " " << _input_label; } o << ' ' << value() << '\n'; } /*--------------------------------------------------------------------------*/ // replace both primary and secondary (both simple L's) // with the CCCS - L equivalent // only works for 2. void DEV_MUTUAL_L::elabo1() { COMPONENT::elabo1(); _output = dynamic_cast( find_in_my_scope(_output_label, bERROR)); if (!_output) {untested(); error(bERROR,long_label() + ": " +_output_label + " is not an inductor\n"); }else{ } _input = dynamic_cast( find_in_my_scope(_input_label, bERROR)); if (!_input) {untested(); error(bERROR,long_label() + ": " + _input_label + " is not an inductor\n"); }else{ } _output->new_subckt(); _input->new_subckt(); double l1 = _output->value(); double l2 = _input->value(); double lm = value() * sqrt(l1 * l2); double det = l1 * l2 - lm * lm; DEV_INDUCTANCE* pri = dynamic_cast(_output->clone()); if (!pri) {untested(); error(bERROR, long_label() + ": " + _output_label + " is not an inductor\n"); }else{ } if (pri->has_common()) {untested(); error(bERROR, long_label() + ": " + _output_label + " must be linear, giving up\n"); }else{ } pri->set_owner(_output); pri->set_value(det / l2); _output->subckt()->push_back(pri); DEV_INDUCTANCE* sec = dynamic_cast(_input->clone()); if (!sec) {untested(); error(bERROR, long_label() + ": " + _input_label + " is not an inductor\n"); }else{ } if (sec->has_common()) {untested(); error(bERROR, long_label() + ": " + _input_label + " must be linear, giving up\n"); }else{ } sec->set_owner(_input); sec->set_value(det / l1); _input->subckt()->push_back(sec); const CARD* proto = device_dispatcher["cccs"]; assert(proto); CCSRC_BASE* sub = dynamic_cast(proto->clone()); assert(sub); sub->set_parameters_cc("F" + sec->short_label(), _output, NULL, -lm / l1, _output->_n[OUT1], _output->_n[OUT2], sec); _output->subckt()->push_back(sub).elabo2(); proto = device_dispatcher["cccs"]; assert(proto); sub = dynamic_cast(proto->clone()); assert(sub); sub->set_parameters_cc("F" + pri->short_label(), _input, NULL, -lm / l2, _input->_n[OUT1], _input->_n[OUT2], pri); _input->subckt()->push_back(sub).elabo2(); assert(!is_constant()); /* because of integration */ } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::map_nodes() { if (subckt()) { subckt()->map_nodes(); }else{ } COMPONENT::map_nodes(); } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::tr_iwant_matrix() { if (subckt()) { subckt()->tr_iwant_matrix(); }else{ tr_iwant_matrix_passive(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::precalc() { if (subckt()) { subckt()->precalc(); }else{ STORAGE::precalc(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::dc_begin() { if (subckt()) {untested(); subckt()->dc_begin(); }else{ STORAGE::dc_begin(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::tr_begin() { if (subckt()) { subckt()->tr_begin(); }else{ STORAGE::tr_begin(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::tr_restore() { if (subckt()) {untested(); subckt()->tr_restore(); }else{ STORAGE::tr_restore(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::dc_advance() { if (subckt()) { subckt()->dc_advance(); }else{ STORAGE::dc_advance(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::tr_advance() { if (subckt()) { subckt()->tr_advance(); }else{ STORAGE::tr_advance(); } } /*--------------------------------------------------------------------------*/ bool DEV_INDUCTANCE::tr_needs_eval()const { assert(!is_q_for_eval()); if (subckt()) {untested(); return subckt()->tr_needs_eval(); }else{ return true; //BUG// errors when it has a current probe, as in mutual inductance //work around: always return true. //return STORAGE::tr_needs_eval(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::tr_queue_eval() { if (subckt()) { if (subckt()->tr_needs_eval()) { subckt()->tr_queue_eval(); }else{untested(); } }else{ STORAGE::tr_queue_eval(); } } /*--------------------------------------------------------------------------*/ bool DEV_INDUCTANCE::do_tr() { if (subckt()) {untested(); set_converged(subckt()->do_tr()); }else{ double x = NOT_VALID; if (using_tr_eval()) { //x = tr_involts_limited(); _y0.x = tr_input_limited(); // _m0.c0 + _m0.c1 * x; tr_eval(); if (_y0.f1 == 0.) {untested(); error(bDANGER, long_label() + ": short circuit, L = 0\n"); _y0.f1 = OPT::shortckt; set_converged(conv_check()); }else{ } }else{ //x = _n[OUT1].v0() - _n[OUT2].v0(); //x = tr_involts(); _y0.x = tr_input(); // _m0.c0 + _m0.c1 * x; assert(_y0.f1 == value()); _y0.f0 = _y0.x * _y0.f1; assert(converged()); } store_values(); q_load(); _q[0] = _y0; // i is really voltage .. // _i[0].x = current, _i[0].f0 = voltage, _i[0].f1 = ohms _i[0] = differentiate(); _m0.x = x; _m0.c1 = 1 / ((_i[0].c1()==0) ? OPT::shortckt : _i[0].c1()); _m0.c0 = -_i[0].c0() * _m0.c1; } return converged(); } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::tr_load() { if (subckt()) { subckt()->tr_load(); }else{ tr_load_passive(); } } /*--------------------------------------------------------------------------*/ DPAIR DEV_INDUCTANCE::tr_review() { if (subckt()) { return subckt()->tr_review(); }else{ return STORAGE::tr_review(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::tr_unload() {untested(); if (subckt()) {untested(); subckt()->tr_unload(); }else{untested(); tr_unload_passive(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::ac_iwant_matrix() { if (subckt()) { subckt()->ac_iwant_matrix(); }else{ ac_iwant_matrix_passive(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::ac_begin() { if (subckt()) { subckt()->ac_begin(); }else{ _ev = _y0.f1; } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::do_ac() { if (subckt()) { subckt()->do_ac(); }else{ if (using_ac_eval()) { ac_eval(); }else{ assert(_ev == _y0.f1); assert(has_tr_eval() || _ev == double(value())); } if (_ev * SIM::jomega == 0.) {untested(); _acg = 1. / OPT::shortckt; }else{ _acg = 1. / (_ev * SIM::jomega); } ac_load(); } } /*--------------------------------------------------------------------------*/ void DEV_INDUCTANCE::ac_load() { if (subckt()) { unreachable(); subckt()->ac_load(); }else{ ac_load_passive(); } } /*--------------------------------------------------------------------------*/ double DEV_INDUCTANCE::tr_probe_num(CS& cmd)const { if (subckt()) { return COMPONENT::tr_probe_num(cmd); }else{ if (cmd.pmatch("FLUX")) {untested(); return _q[0].f0; }else if (cmd.pmatch("INDuctance") || cmd.pmatch("L")) {untested(); return _q[0].f1; }else if (cmd.pmatch("DLDT")) {untested(); return (_q[0].f1 - _q[1].f1) / _dt; }else if (cmd.pmatch("DL")) {untested(); return (_q[0].f1 - _q[1].f1); }else if (cmd.pmatch("DFDT")) {untested(); return (_q[0].f0 - _q[1].f0) / _dt; }else if (cmd.pmatch("DFLUX")) {untested(); return (_q[0].f0 - _q[1].f0); }else{ return STORAGE::tr_probe_num(cmd); } } } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ DEV_MUTUAL_L p1; DEV_INDUCTANCE p2; DISPATCHER::INSTALL d1(&device_dispatcher, "K,mutual_inductor", &p1), d2(&device_dispatcher, "L,inductor", &p2); } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/