diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/lib/netlist/analog/nld_bjt.cpp | 7 | ||||
-rw-r--r-- | src/lib/netlist/analog/nld_generic_models.h | 89 | ||||
-rw-r--r-- | src/lib/netlist/analog/nld_opamps.cpp | 64 | ||||
-rw-r--r-- | src/lib/netlist/analog/nlid_twoterm.h | 3 | ||||
-rw-r--r-- | src/lib/netlist/macro/nlm_opamp.cpp | 2 | ||||
-rw-r--r-- | src/lib/netlist/plib/putil.h | 7 | ||||
-rw-r--r-- | src/lib/netlist/solver/nld_matrix_solver.cpp | 5 |
7 files changed, 114 insertions, 63 deletions
diff --git a/src/lib/netlist/analog/nld_bjt.cpp b/src/lib/netlist/analog/nld_bjt.cpp index a174b3876b2..98a0d80836f 100644 --- a/src/lib/netlist/analog/nld_bjt.cpp +++ b/src/lib/netlist/analog/nld_bjt.cpp @@ -49,7 +49,7 @@ namespace analog // nld_Q - Base classes // ----------------------------------------------------------------------------- - /*! Class representing the bjt model paramers. + /*! Class representing the bjt model parameters. * * This is the model representation of the bjt model. Typically, SPICE uses * the following parameters. A "Y" in the first column indicates that the @@ -71,7 +71,7 @@ namespace analog * | | ISC | leakage saturation current | A | 0 | 8 | | * | | NC | leakage emission coefficient | - | 2 | 1.5 | | * | | RB | zero bias base resistance | | 0 | 100 | * | - * | | IRB | current where base resistance falls halfway to its min value | A | infinte | 0.1 | * | + * | | IRB | current where base resistance falls halfway to its min value | A | infinite | 0.1 | * | * | | RBM | minimum base resistance at high currents | | RB | 10 | * | * | | RE | emitter resistance | | 0 | 1 | * | * | | RC | collector resistance | | 0 | 10 | * | @@ -271,6 +271,7 @@ namespace analog connect("B", "m_CJC.1"); connect("C", "m_CJC.2"); } + } protected: @@ -428,6 +429,8 @@ namespace analog const nl_double Ie = (sIe + gee * m_gD_BE.Vd() - gec * m_gD_BC.Vd()) * polarity; const nl_double Ic = (sIc - gce * m_gD_BE.Vd() + gcc * m_gD_BC.Vd()) * polarity; + // "Circuit Design", page 174 + m_D_EB.set_mat( gee, gec - gee, -Ie, gce - gee, gee - gec, Ie); m_D_CB.set_mat( gcc, gce - gcc, -Ic, diff --git a/src/lib/netlist/analog/nld_generic_models.h b/src/lib/netlist/analog/nld_generic_models.h index 6bb8b815baf..c18452e1109 100644 --- a/src/lib/netlist/analog/nld_generic_models.h +++ b/src/lib/netlist/analog/nld_generic_models.h @@ -47,17 +47,25 @@ namespace analog capacitor_e type() const { return capacitor_e::VARIABLE_CAPACITY; } + // Circuit Simulation, page 284, 5.360 + // q(un+1) - q(un) = int(un, un+1, C(U)) = (C0+C1)/2 * (un+1-un) + // The direct application of formulas 5.359 and 5.360 has + // issues with pulses. Therefore G and Ieq are expressed differently + // so that G depends on un+1 only and Ieq on un only. + // In both cases, i = G * un+1 + Ieq + nl_double G(nl_double cap) const { - //return m_h * (2.0 * cap - m_c) + m_gmin; + //return m_h * cap + m_gmin; return m_h * 0.5 * (cap + m_c) + m_gmin; + //return m_h * cap + m_gmin; } nl_double Ieq(nl_double cap, nl_double v) const { - plib::unused_var(v); - // return m_h * (cap * v - m_charge) - G(cap) * v; + //return -m_h * 0.5 * ((cap + m_c) * m_v + (cap - m_c) * v) ; return -m_h * 0.5 * (cap + m_c) * m_v; + //return -m_h * cap * m_v; } void timestep(nl_double cap, nl_double v, nl_double step) @@ -76,28 +84,31 @@ namespace analog nl_double m_gmin; }; + // "Circuit simulation", page 274 template <> class generic_capacitor<capacitor_e::CONSTANT_CAPACITY> { public: generic_capacitor(device_t &dev, const pstring &name) : m_h(dev, name + ".m_h", 0.0) + , m_v(dev, name + ".m_v", 0.0) , m_gmin(0.0) { } capacitor_e type() const { return capacitor_e::CONSTANT_CAPACITY; } nl_double G(nl_double cap) const { return cap * m_h + m_gmin; } - nl_double Ieq(nl_double cap, nl_double v) const { return - G(cap) * v; } + nl_double Ieq(nl_double cap, nl_double v) const { return - G(cap) * m_v; } void timestep(nl_double cap, nl_double v, nl_double step) { - plib::unused_var(cap, v); m_h = 1.0 / step; + m_v = v; } void setparams(nl_double gmin) { m_gmin = gmin; } private: state_var<nl_double> m_h; + state_var<double> m_v; nl_double m_gmin; }; @@ -127,6 +138,7 @@ namespace analog , m_gmin(1e-15) , m_VtInv(0.0) , m_Vcrit(0.0) + , m_name(name) { set_param(1e-15, 1, 1e-15, 300.0); } @@ -135,37 +147,46 @@ namespace analog { nl_double IseVDVt(0.0); - if (TYPE == diode_e::BIPOLAR && nVd < m_Vmin) + if (TYPE == diode_e::BIPOLAR) { - m_Vd = nVd; - m_G = m_gmin; - m_Id = - m_Is; + //printf("%s: %g %g\n", m_name.c_str(), nVd, (double) m_Vd); + if (nVd > m_Vcrit) + { + const nl_double d = std::min(1e100, nVd - m_Vd); + const nl_double a = std::abs(d) * m_VtInv; + m_Vd = m_Vd + (d < 0 ? -1.0 : 1.0) * std::log1p(a) * m_Vt; + } + else + m_Vd = std::max(-1e100, nVd); + //m_Vd = nVd; + + if (m_Vd < m_Vmin) + { + m_G = m_gmin; + m_Id = - m_Is; + } + else + { + IseVDVt = std::exp(m_logIs + m_Vd * m_VtInv); + m_Id = IseVDVt - m_Is; + m_G = IseVDVt * m_VtInv + m_gmin; + } } - else if (TYPE == diode_e::MOS && nVd < constants::zero()) + else if (TYPE == diode_e::MOS) { - m_Vd = nVd; - m_G = m_Is * m_VtInv + m_gmin; - m_Id = m_G * m_Vd; - } - else if (/*TYPE == diode_e::MOS || */nVd < m_Vcrit) - { - m_Vd = nVd; - IseVDVt = std::exp(std::min(300.0, m_logIs + m_Vd * m_VtInv)); - m_Id = IseVDVt - m_Is; - m_G = IseVDVt * m_VtInv + m_gmin; - } - else - { - if (TYPE == diode_e::MOS && m_Vd < constants::zero()) - m_Vd = std::min(m_Vmin, nVd); - - const nl_double d = (nVd - m_Vd); - const nl_double a = std::abs(nVd - m_Vd) * m_VtInv; - m_Vd = m_Vd + (d < 0 ? -1.0 : 1.0) * std::log1p(a) * m_Vt; - IseVDVt = std::exp(m_logIs + m_Vd * m_VtInv); - //const double IseVDVt = m_Is * std::exp(m_Vd * m_VtInv); - m_Id = IseVDVt - m_Is; - m_G = IseVDVt * m_VtInv + m_gmin; + if (nVd < constants::zero()) + { + m_Vd = nVd; + m_G = m_Is * m_VtInv + m_gmin; + m_Id = m_G * m_Vd; + } + else /* log stepping should already be done in mosfet */ + { + m_Vd = nVd; + IseVDVt = std::exp(std::min(300.0, m_logIs + m_Vd * m_VtInv)); + m_Id = IseVDVt - m_Is; + m_G = IseVDVt * m_VtInv + m_gmin; + } } } @@ -207,6 +228,8 @@ namespace analog nl_double m_VtInv; nl_double m_Vcrit; + + pstring m_name; }; diff --git a/src/lib/netlist/analog/nld_opamps.cpp b/src/lib/netlist/analog/nld_opamps.cpp index 8c3c655bfa9..0539a5dea51 100644 --- a/src/lib/netlist/analog/nld_opamps.cpp +++ b/src/lib/netlist/analog/nld_opamps.cpp @@ -115,6 +115,8 @@ namespace netlist , m_VREF(*this, "VREF") { m_type = static_cast<int>(m_model.m_TYPE); + if (m_type < 1 || m_type > 3) + log().fatal(MF_1_UNKNOWN_OPAMP_TYPE, m_type); if (m_type == 1) { @@ -127,38 +129,42 @@ namespace netlist connect("RP1.1", "G1.OP"); } - else if (m_type == 3) + if (m_type == 2 || m_type == 3) { create_and_register_subdevice("CP1", m_CP); create_and_register_subdevice("EBUF", m_EBUF); - create_and_register_subdevice("DN", m_DN, "D(IS=1e-15 N=1)"); - create_and_register_subdevice("DP", m_DP, "D(IS=1e-15 N=1)"); - - //m_DP->m_model.setTo("D(IS=1e-15 N=1)"); - //m_DN->m_model.setTo("D(IS=1e-15 N=1)"); register_subalias("PLUS", "G1.IP"); register_subalias("MINUS", "G1.IN"); - register_subalias("OUT", "EBUF.OP"); - - connect("EBUF.ON", "VREF"); connect("G1.ON", "VREF"); connect("RP1.2", "VREF"); connect("CP1.2", "VREF"); + connect("EBUF.ON", "VREF"); connect("EBUF.IN", "VREF"); connect("RP1.1", "G1.OP"); connect("CP1.1", "RP1.1"); + connect("EBUF.IP", "RP1.1"); + } + if (m_type == 2) + { + register_subalias("OUT", "EBUF.OP"); + } + if (m_type == 3) + { + + create_and_register_subdevice("DN", m_DN, "D(IS=1e-15 N=1)"); + create_and_register_subdevice("DP", m_DP, "D(IS=1e-15 N=1)"); + connect("DP.K", "VH"); connect("VL", "DN.A"); connect("DP.A", "DN.K"); connect("DN.K", "RP1.1"); - connect("EBUF.IP", "RP1.1"); + + register_subalias("OUT", "EBUF.OP"); } - else - log().fatal(MF_1_UNKNOWN_OPAMP_TYPE, m_type); } @@ -194,6 +200,7 @@ namespace netlist const double cVt = 0.0258 * 1.0; // * m_n; const double cId = m_model.m_DAB; // 3 mA const double cVd = cVt * std::log(cId / 1e-15 + 1.0); + m_VH.push(m_VCC() - m_model.m_VLH - cVd); m_VL.push(m_GND() + m_model.m_VLL + cVd); m_VREF.push((m_VCC() + m_GND()) / 2.0); @@ -211,28 +218,41 @@ namespace netlist m_RP.set_R(RO); m_G1.m_G.setTo(G); } - else if (m_type == 3) + if (m_type == 3 || m_type == 2) { m_EBUF->reset(); - m_DP->reset(); - m_DN->reset(); m_CP->reset(); m_RP.reset(); - - m_EBUF->m_G.setTo(1.0); - m_EBUF->m_RO.setTo(m_model.m_RO); - +#if 0 + double CP = 0.0; + double RP = 1000; + double G = m_model.m_UGF / m_model.m_FPF / RP; +#else double CP = m_model.m_DAB / m_model.m_SLEW; - double RP = 0.5 / 3.1459 / CP / m_model.m_FPF; + double RP = 0.5 / constants::pi() / CP / m_model.m_FPF; double G = m_model.m_UGF / m_model.m_FPF / RP; - - //printf("Min Freq %s: %f\n", name().c_str(), 1.0 / (CP*RP / (G*RP))); +#endif + printf("OPAMP %s: %g %g %g\n", name().c_str(), CP, RP, G); + if (m_model.m_SLEW / (4.0 * constants::pi() * 0.0258) < m_model.m_UGF) + printf("failed!\n"); m_CP->m_C.setTo(CP); m_RP.set_R(RP); m_G1.m_G.setTo(G); } + if (m_type == 2) + { + m_EBUF->m_G.setTo(1.0); + m_EBUF->m_RO.setTo(m_model.m_RO); + } + if (m_type == 3) + { + m_DP->reset(); + m_DN->reset(); + m_EBUF->m_G.setTo(1.0); + m_EBUF->m_RO.setTo(m_model.m_RO); + } } diff --git a/src/lib/netlist/analog/nlid_twoterm.h b/src/lib/netlist/analog/nlid_twoterm.h index 8e93d1a6fba..63ab43db591 100644 --- a/src/lib/netlist/analog/nlid_twoterm.h +++ b/src/lib/netlist/analog/nlid_twoterm.h @@ -313,7 +313,7 @@ namespace analog * |NL? |name |parameter |units|default| example|area | * |:--:|:-----|:--------------------------------|:----|------:|-------:|:----:| * | Y |IS |saturation current |A |1.0e-14| 1.0e-14| * | - * | |RS |ohmic resistanc |Ohm | 0| 10| * | + * | |RS |ohmic resistance |Ohm | 0| 10| * | * | Y |N |emission coefficient |- | 1| 1| | * | |TT |transit-time |sec | 0| 0.1ns| | * | |CJO |zero-bias junction capacitance |F | 0| 2pF| * | @@ -359,6 +359,7 @@ namespace analog register_subalias("K", m_N); } + /* needed by nld_opamp ... */ template <class CLASS> NETLIB_NAME(D)(CLASS &owner, const pstring &name, const pstring &model) : NETLIB_NAME(twoterm)(owner, name) diff --git a/src/lib/netlist/macro/nlm_opamp.cpp b/src/lib/netlist/macro/nlm_opamp.cpp index 849f7820046..2c61430c935 100644 --- a/src/lib/netlist/macro/nlm_opamp.cpp +++ b/src/lib/netlist/macro/nlm_opamp.cpp @@ -225,7 +225,7 @@ NETLIST_START(OPAMP_lib) NET_MODEL("LM324 OPAMP(TYPE=3 VLH=2.0 VLL=0.2 FPF=5 UGF=500k SLEW=0.3M RI=1000k RO=50 DAB=0.00075)") NET_MODEL("LM358 OPAMP(TYPE=3 VLH=2.0 VLL=0.2 FPF=5 UGF=500k SLEW=0.3M RI=1000k RO=50 DAB=0.001)") - NET_MODEL("MB3614 OPAMP(TYPE=3 VLH=1.4 VLL=0.02 FPF=2 UGF=500k SLEW=0.6M RI=1000k RO=50 DAB=0.0002)") + NET_MODEL("MB3614 OPAMP(TYPE=3 VLH=1.4 VLL=0.02 FPF=2 UGF=200k SLEW=0.6M RI=1000k RO=50 DAB=0.002)") NET_MODEL("UA741 OPAMP(TYPE=3 VLH=1.0 VLL=1.0 FPF=5 UGF=1000k SLEW=0.5M RI=2000k RO=75 DAB=0.0017)") NET_MODEL("LM747 OPAMP(TYPE=3 VLH=1.0 VLL=1.0 FPF=5 UGF=1000k SLEW=0.5M RI=2000k RO=50 DAB=0.0017)") NET_MODEL("LM747A OPAMP(TYPE=3 VLH=2.0 VLL=2.0 FPF=5 UGF=1000k SLEW=0.7M RI=6000k RO=50 DAB=0.0015)") diff --git a/src/lib/netlist/plib/putil.h b/src/lib/netlist/plib/putil.h index 5cc4fc53187..7ec668a1f8f 100644 --- a/src/lib/netlist/plib/putil.h +++ b/src/lib/netlist/plib/putil.h @@ -62,10 +62,11 @@ namespace plib template <typename T> struct constants { - static constexpr T zero() noexcept { return static_cast<T>(0); } - static constexpr T one() noexcept { return static_cast<T>(1); } - static constexpr T two() noexcept { return static_cast<T>(2); } + static constexpr T zero() noexcept { return static_cast<T>(0); } + static constexpr T one() noexcept { return static_cast<T>(1); } + static constexpr T two() noexcept { return static_cast<T>(2); } static constexpr T sqrt2() noexcept { return static_cast<T>(1.414213562373095048801688724209); } + static constexpr T pi() noexcept { return static_cast<T>(3.14159265358979323846264338327950); } /*! * \brief Electric constant of vacuum diff --git a/src/lib/netlist/solver/nld_matrix_solver.cpp b/src/lib/netlist/solver/nld_matrix_solver.cpp index 0a7bf5ef3c3..1b92017c284 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.cpp +++ b/src/lib/netlist/solver/nld_matrix_solver.cpp @@ -570,9 +570,12 @@ namespace devices analog_net_t *n = m_nets[k]; terms_for_net_t *t = m_terms[k].get(); - const nl_double DD_n = (n->Q_Analog() - t->m_last_V); + //const nl_double DD_n = (n->Q_Analog() - t->m_last_V); + // avoid floating point exceptions + const nl_double DD_n = std::max(-1e100, std::min(1e100,(n->Q_Analog() - t->m_last_V))); const nl_double hn = cur_ts; + //printf("%g %g %g %g\n", DD_n, hn, t->m_DD_n_m_1, t->m_h_n_m_1); nl_double DD2 = (DD_n / hn - t->m_DD_n_m_1 / t->m_h_n_m_1) / (hn + t->m_h_n_m_1); nl_double new_net_timestep; |