diff --git a/src/lib/netlist/analog/nld_bjt.h b/src/lib/netlist/analog/nld_bjt.h index e2da1bd529f..0c91d58bdb6 100644 --- a/src/lib/netlist/analog/nld_bjt.h +++ b/src/lib/netlist/analog/nld_bjt.h @@ -48,7 +48,7 @@ public: { } - NETLIB_DYNAMIC() + NETLIB_IS_DYNAMIC() //NETLIB_RESETI(); NETLIB_UPDATEI(); diff --git a/src/lib/netlist/analog/nld_fourterm.h b/src/lib/netlist/analog/nld_fourterm.h index 7792607cf7a..723eccf77f5 100644 --- a/src/lib/netlist/analog/nld_fourterm.h +++ b/src/lib/netlist/analog/nld_fourterm.h @@ -115,7 +115,7 @@ public: { } - NETLIB_DYNAMIC() + NETLIB_IS_DYNAMIC() param_double_t m_cur_limit; /* current limit */ diff --git a/src/lib/netlist/analog/nld_twoterm.cpp b/src/lib/netlist/analog/nld_twoterm.cpp index 089b11f8607..9818ea9f86f 100644 --- a/src/lib/netlist/analog/nld_twoterm.cpp +++ b/src/lib/netlist/analog/nld_twoterm.cpp @@ -45,6 +45,44 @@ void generic_diode::set_param(const nl_double Is, const nl_double n, nl_double g m_VtInv = 1.0 / m_Vt; } +void generic_diode::update_diode(const nl_double nVd) +{ +#if 1 + if (nVd < NL_FCONST(-5.0) * m_Vt) + { + m_Vd = nVd; + m_G = m_gmin; + m_Id = - m_Is; + } + else if (nVd < m_Vcrit) + { + m_Vd = nVd; + //m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt); + const nl_double eVDVt = std::exp(m_Vd * m_VtInv); + m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); + m_G = m_Is * m_VtInv * eVDVt + m_gmin; + } + else + { +#if 1 + const nl_double a = std::max((nVd - m_Vd) * m_VtInv, NL_FCONST(-0.99)); + m_Vd = m_Vd + std::log1p(a) * m_Vt; +#else + m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt); +#endif + const nl_double eVDVt = std::exp(m_Vd * m_VtInv); + m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); + + m_G = m_Is * m_VtInv * eVDVt + m_gmin; + } +#else + m_Vd = m_Vd + 20.0 * m_Vt * std::tanh((nVd - m_Vd) / 20.0 / m_Vt); + const nl_double eVDVt = std::exp(m_Vd * m_VtInv); + m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); + m_G = m_Is * m_VtInv * eVDVt + m_gmin; +#endif +} + // ---------------------------------------------------------------------------------------- // nld_twoterm // ---------------------------------------------------------------------------------------- @@ -101,14 +139,14 @@ NETLIB_UPDATE_PARAM(POT2) NETLIB_RESET(C) { + // FIXME: Startup conditions set(netlist().gmin(), 0.0, -5.0 / netlist().gmin()); - //set(1.0/NETLIST_GMIN, 0.0, -5.0 * NETLIST_GMIN); + //set(netlist().gmin(), 0.0, 0.0); } NETLIB_UPDATE_PARAM(C) { - //step_time(1.0/48000.0); - m_GParallel = netlist().gmin() * m_C(); + m_GParallel = netlist().gmin(); } NETLIB_UPDATE(C) @@ -116,6 +154,14 @@ NETLIB_UPDATE(C) NETLIB_NAME(twoterm)::update(); } +NETLIB_TIMESTEP(C) +{ + /* Gpar should support convergence */ + const nl_double G = m_C() / step + m_GParallel; + const nl_double I = -G * deltaV(); + set(G, 0.0, I); +} + // ---------------------------------------------------------------------------------------- // nld_L // ---------------------------------------------------------------------------------------- @@ -128,8 +174,7 @@ NETLIB_RESET(L) NETLIB_UPDATE_PARAM(L) { - //step_time(1.0/48000.0); - //m_GParallel = netlist().gmin() / m_L(); + m_GParallel = netlist().gmin(); } NETLIB_UPDATE(L) @@ -137,6 +182,14 @@ NETLIB_UPDATE(L) NETLIB_NAME(twoterm)::update(); } +NETLIB_TIMESTEP(L) +{ + /* Gpar should support convergence */ + m_I += m_I + m_G * deltaV(); + m_G = step / m_L() + m_GParallel; + set(m_G, 0.0, m_I); +} + // ---------------------------------------------------------------------------------------- // nld_D // ---------------------------------------------------------------------------------------- diff --git a/src/lib/netlist/analog/nld_twoterm.h b/src/lib/netlist/analog/nld_twoterm.h index f59b9e62594..2ff6db1e2c3 100644 --- a/src/lib/netlist/analog/nld_twoterm.h +++ b/src/lib/netlist/analog/nld_twoterm.h @@ -137,7 +137,9 @@ public: return m_P.net().Q_Analog() - m_N.net().Q_Analog(); } - void set_mat(nl_double a11, nl_double a12, nl_double a21, nl_double a22, nl_double r1, nl_double r2) + void set_mat(const nl_double a11, const nl_double a12, + const nl_double a21, const nl_double a22, + const nl_double r1, const nl_double r2) { /* GO, GT, I */ m_P.set(-a12, a11, -r1); @@ -286,14 +288,8 @@ public: //register_term("2", m_N); } - NETLIB_TIMESTEP() - { - /* Gpar should support convergence */ - const nl_double G = m_C() / step + m_GParallel; - const nl_double I = -G * deltaV(); - set(G, 0.0, I); - } - + NETLIB_IS_TIMESTEP() + NETLIB_TIMESTEPI(); param_double_t m_C; @@ -324,13 +320,8 @@ public: //register_term("2", m_N); } - NETLIB_TIMESTEP() - { - /* Gpar should support convergence */ - m_I = m_I + m_G * deltaV(); - m_G = step / m_L() + m_GParallel; - set(m_G, 0.0, m_I); - } + NETLIB_IS_TIMESTEP() + NETLIB_TIMESTEPI(); param_double_t m_L; @@ -354,43 +345,7 @@ class generic_diode public: generic_diode(device_t &dev, pstring name); - inline void update_diode(const nl_double nVd) - { -#if 1 - if (nVd < NL_FCONST(-5.0) * m_Vt) - { - m_Vd = nVd; - m_G = m_gmin; - m_Id = - m_Is; - } - else if (nVd < m_Vcrit) - { - m_Vd = nVd; - //m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt); - const nl_double eVDVt = std::exp(m_Vd * m_VtInv); - m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); - m_G = m_Is * m_VtInv * eVDVt + m_gmin; - } - else - { -#if 1 - const nl_double a = std::max((nVd - m_Vd) * m_VtInv, NL_FCONST(0.5) - NL_FCONST(1.0)); - m_Vd = m_Vd + std::log1p(a) * m_Vt; -#else - m_Vd = m_Vd + 10.0 * m_Vt * std::tanh((nVd - m_Vd) / 10.0 / m_Vt); -#endif - const nl_double eVDVt = std::exp(m_Vd * m_VtInv); - m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); - - m_G = m_Is * m_VtInv * eVDVt + m_gmin; - } -#else - m_Vd = m_Vd + 20.0 * m_Vt * std::tanh((nVd - m_Vd) / 20.0 / m_Vt); - const nl_double eVDVt = std::exp(m_Vd * m_VtInv); - m_Id = m_Is * (eVDVt - NL_FCONST(1.0)); - m_G = m_Is * m_VtInv * eVDVt + m_gmin; -#endif - } + void update_diode(const nl_double nVd); void set_param(const nl_double Is, const nl_double n, nl_double gmin); @@ -430,7 +385,7 @@ public: register_subalias("K", m_N); } - NETLIB_DYNAMIC() + NETLIB_IS_DYNAMIC() NETLIB_UPDATE_TERMINALSI(); diff --git a/src/lib/netlist/nl_base.h b/src/lib/netlist/nl_base.h index 045f7c9b1cb..12181586b82 100644 --- a/src/lib/netlist/nl_base.h +++ b/src/lib/netlist/nl_base.h @@ -88,29 +88,35 @@ class NETLIB_NAME(name) : public device_t * dynamic device, i.e. #NETLIB_UPDATE_TERMINALSI is called on a each step * of the Newton-Raphson step of solving the linear equations. */ -#define NETLIB_DYNAMIC() \ +#define NETLIB_IS_DYNAMIC() \ public: virtual bool is_dynamic() const override { return true; } - /*! Add this to a device definition to mark the device as a time-stepping device - * and add code. - * If this is added to device definition the device is treated as an analog - * time-stepping device. Currently, only the capacitor device uses this. An other - * example would be an inductor device. - * - * Example: - * - * NETLIB_TIMESTEP() - * { - * // Gpar should support convergence - * const nl_double G = m_C.Value() / step + m_GParallel; - * const nl_double I = -G * deltaV(); - * set(G, 0.0, I); - * } - * - */ -#define NETLIB_TIMESTEP() \ - public: virtual bool is_timestep() const override { return true; } \ - public: virtual void step_time(const nl_double step) override + /*! Add this to a device definition to mark the device as a time-stepping device. + * + * You have to implement NETLIB_TIMESTEP in this case as well. Currently, only + * the capacitor and inductor devices uses this. + * + * Example: + * + * NETLIB_TIMESTEP_IS_TIMESTEP() + * NETLIB_TIMESTEPI() + * { + * // Gpar should support convergence + * const nl_double G = m_C.Value() / step + m_GParallel; + * const nl_double I = -G * deltaV(); + * set(G, 0.0, I); + * } + * + */ +#define NETLIB_IS_TIMESTEP() \ + public: virtual bool is_timestep() const override { return true; } + + /*! Used to implement the time stepping code. + * + * Please see NETLIB_IS_TIMESTEP for an example. + */ +#define NETLIB_TIMESTEPI() \ + public: virtual void timestep(const nl_double step) override #define NETLIB_UPDATE_AFTER_PARAM_CHANGE() \ public: virtual bool needs_update_after_param_change() const override { return true; } @@ -122,6 +128,8 @@ class NETLIB_NAME(name) : public device_t #define NETLIB_UPDATE_PARAMI() public: virtual void update_param() override #define NETLIB_RESETI() protected: virtual void reset() override +#define NETLIB_TIMESTEP(chip) void NETLIB_NAME(chip) :: timestep(const nl_double step) + #define NETLIB_SUB(chip) nld_ ## chip #define NETLIB_SUBXX(chip) std::unique_ptr< nld_ ## chip > @@ -1028,7 +1036,7 @@ namespace netlist virtual void reset() { } public: - virtual void step_time(ATTR_UNUSED const nl_double st) { } + virtual void timestep(ATTR_UNUSED const nl_double st) { } virtual void update_terminals() { } virtual void update_param() {} diff --git a/src/lib/netlist/solver/nld_matrix_solver.h b/src/lib/netlist/solver/nld_matrix_solver.h index 36e39462c17..f1473ce5931 100644 --- a/src/lib/netlist/solver/nld_matrix_solver.h +++ b/src/lib/netlist/solver/nld_matrix_solver.h @@ -45,7 +45,7 @@ public: : m_railstart(0) , m_last_V(0.0) , m_DD_n_m_1(0.0) - , m_h_n_m_1(1e-6) + , m_h_n_m_1(1e-9) {} void clear() diff --git a/src/lib/netlist/solver/nld_solver.cpp b/src/lib/netlist/solver/nld_solver.cpp index 3f4deb0340f..b0c70ebbde4 100644 --- a/src/lib/netlist/solver/nld_solver.cpp +++ b/src/lib/netlist/solver/nld_solver.cpp @@ -408,7 +408,7 @@ void matrix_solver_t::step(const netlist_time &delta) { const nl_double dd = delta.as_double(); for (std::size_t k=0; k < m_step_devices.size(); k++) - m_step_devices[k]->step_time(dd); + m_step_devices[k]->timestep(dd); } void matrix_solver_t::solve_base() @@ -510,6 +510,7 @@ netlist_time matrix_solver_t::compute_next_timestep(const double cur_ts) const nl_double DD_n = (n->Q_Analog() - t->m_last_V); const nl_double hn = cur_ts; + //printf("%f %f %f %f\n", DD_n, t->m_DD_n_m_1, hn, 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; @@ -526,7 +527,10 @@ netlist_time matrix_solver_t::compute_next_timestep(const double cur_ts) t->m_last_V = n->Q_Analog(); } if (new_solver_timestep < m_params.m_min_timestep) + { + //log().warning("Dynamic timestep below min timestep. Consider decreasing MIN_TIMESTEP: {1} us", new_solver_timestep*1.0e6); new_solver_timestep = m_params.m_min_timestep; + } } //if (new_solver_timestep > 10.0 * hn) // new_solver_timestep = 10.0 * hn;