diff options
Diffstat (limited to 'src/lib/netlist/analog/nlid_twoterm.cpp')
-rw-r--r-- | src/lib/netlist/analog/nlid_twoterm.cpp | 361 |
1 files changed, 201 insertions, 160 deletions
diff --git a/src/lib/netlist/analog/nlid_twoterm.cpp b/src/lib/netlist/analog/nlid_twoterm.cpp index aaddb65387a..1a3c79e713f 100644 --- a/src/lib/netlist/analog/nlid_twoterm.cpp +++ b/src/lib/netlist/analog/nlid_twoterm.cpp @@ -1,190 +1,231 @@ -// license:GPL-2.0+ +// license:BSD-3-Clause // copyright-holders:Couriersud -/* - * nld_twoterm.c - * - */ -#include "netlist/solver/nld_solver.h" - -#include "netlist/nl_factory.h" #include "nlid_twoterm.h" -#include <cmath> +#include "nl_factory.h" -namespace netlist -{ - namespace analog - { +#include "solver/nld_solver.h" -// ---------------------------------------------------------------------------------------- -// nld_twoterm -// ---------------------------------------------------------------------------------------- - -void NETLIB_NAME(twoterm)::solve_now() -{ - /* we only need to call the non-rail terminal */ - if (m_P.has_net() && !m_P.net().isRailNet()) - m_P.solve_now(); - else if (m_N.has_net() && !m_N.net().isRailNet()) - m_N.solve_now(); -} - -void NETLIB_NAME(twoterm)::solve_later(netlist_time delay) +namespace netlist::analog { - /* we only need to call the non-rail terminal */ - if (m_P.has_net() && !m_P.net().isRailNet()) - m_P.schedule_solve_after(delay); - else if (m_N.has_net() && !m_N.net().isRailNet()) - m_N.schedule_solve_after(delay); -} + // ------------------------------------------------------------------------- + // nld_twoterm + // ------------------------------------------------------------------------- -NETLIB_UPDATE(twoterm) -{ - /* only called if connected to a rail net ==> notify the solver to recalculate */ - solve_now(); -} - -// ---------------------------------------------------------------------------------------- -// nld_R_base -// ---------------------------------------------------------------------------------------- - -NETLIB_RESET(R_base) -{ - NETLIB_NAME(twoterm)::reset(); - set_R(1.0 / exec().gmin()); -} + solver::matrix_solver_t *nld_two_terminal::solver() const noexcept + { + auto *solv(m_P.solver()); + if (solv != nullptr) + return solv; + return m_N.solver(); + } -// ---------------------------------------------------------------------------------------- -// nld_POT -// ---------------------------------------------------------------------------------------- + void nld_two_terminal::solve_now() const + { + auto *solv(solver()); + if (solv != nullptr) + solv->solve_now(); + } -NETLIB_RESET(POT) -{ - nl_double v = m_Dial(); - if (m_DialIsLog()) - v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0); + NETLIB_HANDLER(two_terminal, terminal_handler) + { + // only called if connected to a rail net ==> notify the solver to + // recalculate + // printf("%s update\n", this->name().c_str()); + solve_now(); + } - m_R1.set_R(std::max(m_R() * v, exec().gmin())); - m_R2.set_R(std::max(m_R() * (plib::constants<nl_double>::one() - v), exec().gmin())); -} + // ------------------------------------------------------------------------- + // nld_POT + // ------------------------------------------------------------------------- -NETLIB_UPDATE_PARAM(POT) -{ - m_R1.solve_now(); - m_R2.solve_now(); + NETLIB_RESET(POT) + { + nl_fptype v = m_Dial(); + if (m_DialIsLog()) + v = (plib::exp(v) - nlconst::one()) + / (plib::exp(nlconst::one()) - nlconst::one()); - nl_double v = m_Dial(); - if (m_DialIsLog()) - v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0); - if (m_Reverse()) - v = 1.0 - v; - m_R1.set_R(std::max(m_R() * v, exec().gmin())); - m_R2.set_R(std::max(m_R() * (plib::constants<nl_double>::one() - v), exec().gmin())); + m_R1().set_R(std::max(m_R() * v, exec().gmin())); + m_R2().set_R(std::max(m_R() * (nlconst::one() - v), exec().gmin())); + } -} + NETLIB_UPDATE_PARAM(POT) + { + nl_fptype v = m_Dial(); + if (m_DialIsLog()) + v = (plib::exp(v) - nlconst::one()) + / (plib::exp(nlconst::one()) - nlconst::one()); + if (m_Reverse()) + v = nlconst::one() - v; + + nl_fptype r1(std::max(m_R() * v, exec().gmin())); + nl_fptype r2(std::max(m_R() * (nlconst::one() - v), exec().gmin())); + + if (m_R1().solver() == m_R2().solver()) + m_R1().change_state( + [this, &r1, &r2]() + { + m_R1().set_R(r1); + m_R2().set_R(r2); + }); + else + { + m_R1().change_state([this, &r1]() { m_R1().set_R(r1); }); + m_R2().change_state([this, &r2]() { m_R2().set_R(r2); }); + } + } + + // ------------------------------------------------------------------------- + // nld_POT2 + // ------------------------------------------------------------------------- + + NETLIB_RESET(POT2) + { + nl_fptype v = m_Dial(); -// ---------------------------------------------------------------------------------------- -// nld_POT2 -// ---------------------------------------------------------------------------------------- + if (m_DialIsLog()) + v = (plib::exp(v) - nlconst::one()) + / (plib::exp(nlconst::one()) - nlconst::one()); + if (m_Reverse()) + v = nlconst::one() - v; + m_R1().set_R(std::max(m_R() * v, exec().gmin())); + } -NETLIB_RESET(POT2) -{ - nl_double v = m_Dial(); + NETLIB_UPDATE_PARAM(POT2) + { + nl_fptype v = m_Dial(); - if (m_DialIsLog()) - v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0); - if (m_Reverse()) - v = 1.0 - v; - m_R1.set_R(std::max(m_R() * v, exec().gmin())); -} + if (m_DialIsLog()) + v = (plib::exp(v) - nlconst::one()) + / (plib::exp(nlconst::one()) - nlconst::one()); + if (m_Reverse()) + v = nlconst::one() - v; + m_R1().change_state( + [this, &v]() { m_R1().set_R(std::max(m_R() * v, exec().gmin())); }); + } -NETLIB_UPDATE_PARAM(POT2) -{ - m_R1.solve_now(); + // ------------------------------------------------------------------------- + // nld_L + // ------------------------------------------------------------------------- - nl_double v = m_Dial(); + NETLIB_RESET(L) + { + m_gmin = exec().gmin(); + m_I = nlconst::zero(); + m_G = m_gmin; + set_mat(m_G, -m_G, -m_I, // + -m_G, m_G, m_I); + } - if (m_DialIsLog()) - v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0); - if (m_Reverse()) - v = 1.0 - v; - m_R1.set_R(std::max(m_R() * v, exec().gmin())); -} + NETLIB_UPDATE_PARAM(L) {} -// ---------------------------------------------------------------------------------------- -// nld_L -// ---------------------------------------------------------------------------------------- + NETLIB_TIMESTEP(L) + { + if (ts_type == detail::time_step_type::FORWARD) + { + m_last_I = m_I; + m_last_G = m_G; + // Gpar should support convergence + m_I += m_G * deltaV(); + m_G = step / m_L() + m_gmin; + set_mat(m_G, -m_G, -m_I, // + -m_G, m_G, m_I); + } + else + { + m_I = m_last_I; + m_G = m_last_G; + } + } + + // ------------------------------------------------------------------------- + // nld_D + // ------------------------------------------------------------------------- + + NETLIB_RESET(D) + { + nl_fptype Is = m_modacc.m_IS; + nl_fptype n = m_modacc.m_N; -NETLIB_RESET(L) -{ - m_gmin = exec().gmin(); - m_I = 0.0; - m_G = m_gmin; - set_mat( m_G, -m_G, -m_I, - -m_G, m_G, m_I); - //set(1.0/NETLIST_GMIN, 0.0, -5.0 * NETLIST_GMIN); -} - -NETLIB_UPDATE_PARAM(L) -{ -} + m_D.set_param(Is, n, exec().gmin(), nlconst::T0()); + set_G_V_I(m_D.G(), nlconst::zero(), m_D.Ieq()); + } -NETLIB_TIMESTEP(L) -{ - /* Gpar should support convergence */ - m_I += m_I + m_G * deltaV(); - m_G = step / m_L() + m_gmin; - set_mat( m_G, -m_G, -m_I, - -m_G, m_G, m_I); - //set(m_G, 0.0, m_I); -} - -// ---------------------------------------------------------------------------------------- -// nld_D -// ---------------------------------------------------------------------------------------- - -NETLIB_RESET(D) -{ - nl_double Is = m_model.m_IS; - nl_double n = m_model.m_N; + NETLIB_UPDATE_PARAM(D) + { + nl_fptype Is = m_modacc.m_IS; + nl_fptype n = m_modacc.m_N; - m_D.set_param(Is, n, exec().gmin(), constants::T0()); - set_G_V_I(m_D.G(), 0.0, m_D.Ieq()); -} + m_D.set_param(Is, n, exec().gmin(), nlconst::T0()); + } -NETLIB_UPDATE_PARAM(D) -{ - nl_double Is = m_model.m_IS; - nl_double n = m_model.m_N; + NETLIB_UPDATE_TERMINALS(D) + { + m_D.update_diode(deltaV()); + const nl_fptype G(m_D.G()); + const nl_fptype I(m_D.Ieq()); + set_mat(G, -G, -I, // + -G, G, I); + // set(m_D.G(), 0.0, m_D.Ieq()); + } + + // ------------------------------------------------------------------------- + // nld_Z + // ------------------------------------------------------------------------- + + NETLIB_RESET(Z) + { + nl_fptype IsBV = m_modacc.m_IBV + / (plib::exp(m_modacc.m_BV + / nlconst::np_VT(m_modacc.m_NBV)) + - nlconst::one()); + + m_D.set_param(m_modacc.m_IS, m_modacc.m_N, exec().gmin(), + nlconst::T0()); + m_R.set_param(IsBV, m_modacc.m_NBV, exec().gmin(), nlconst::T0()); + set_G_V_I(m_D.G(), nlconst::zero(), m_D.Ieq()); + } + + NETLIB_UPDATE_PARAM(Z) + { + nl_fptype IsBV = m_modacc.m_IBV + / (plib::exp(m_modacc.m_BV + / nlconst::np_VT(m_modacc.m_NBV)) + - nlconst::one()); + + m_D.set_param(m_modacc.m_IS, m_modacc.m_N, exec().gmin(), + nlconst::T0()); + m_R.set_param(IsBV, m_modacc.m_NBV, exec().gmin(), nlconst::T0()); + set_G_V_I(m_D.G(), nlconst::zero(), m_D.Ieq()); + } + + NETLIB_UPDATE_TERMINALS(Z) + { + m_D.update_diode(deltaV()); + m_R.update_diode(-deltaV()); + const nl_fptype G(m_D.G() + m_R.G()); + const nl_fptype I(m_D.Ieq() - m_R.Ieq()); + set_mat(G, -G, -I, // + -G, G, I); + } - m_D.set_param(Is, n, exec().gmin(), constants::T0()); -} +} // namespace netlist::analog -NETLIB_UPDATE_TERMINALS(D) +namespace netlist::devices { - m_D.update_diode(deltaV()); - const nl_double G = m_D.G(); - const nl_double I = m_D.Ieq(); - set_mat( G, -G, -I, - -G, G, I); - //set(m_D.G(), 0.0, m_D.Ieq()); -} - - - } //namespace analog - - namespace devices { - NETLIB_DEVICE_IMPL_NS(analog, R, "RES", "R") - NETLIB_DEVICE_IMPL_NS(analog, POT, "POT", "R") - NETLIB_DEVICE_IMPL_NS(analog, POT2, "POT2", "R") - NETLIB_DEVICE_IMPL_NS(analog, C, "CAP", "C") - NETLIB_DEVICE_IMPL_NS(analog, L, "IND", "L") - NETLIB_DEVICE_IMPL_NS(analog, D, "DIODE", "MODEL") - NETLIB_DEVICE_IMPL_NS(analog, VS, "VS", "V") - NETLIB_DEVICE_IMPL_NS(analog, CS, "CS", "I") - } // namespace devices - -} // namespace netlist + // clang-format off + NETLIB_DEVICE_IMPL_NS(analog, R, "RES", "R") + NETLIB_DEVICE_IMPL_NS(analog, POT, "POT", "R") + NETLIB_DEVICE_IMPL_NS(analog, POT2, "POT2", "R") + NETLIB_DEVICE_IMPL_NS(analog, C, "CAP", "C") + NETLIB_DEVICE_IMPL_NS(analog, L, "IND", "L") + NETLIB_DEVICE_IMPL_NS(analog, D, "DIODE", "MODEL") + NETLIB_DEVICE_IMPL_NS(analog, Z, "ZDIODE", "MODEL") + NETLIB_DEVICE_IMPL_NS(analog, VS, "VS", "V") + NETLIB_DEVICE_IMPL_NS(analog, CS, "CS", "I") + // clang-format on +} // namespace netlist::devices |