mirror of
https://github.com/holub/mame
synced 2025-04-19 15:11:37 +03:00
netlist: add RELTOL/VNTOL solver parameters. Type safety. [Couriersud]
The newly added RELTOL and VNTOL parameters implement Newton convergence checks comparable following other SPICE implementations. The ACCURACY solver parameter now is only used for convergence checks in iterative solvers. In addition, type safety was significantly improved and a lot of "magic" numbers are identifiable now.
This commit is contained in:
parent
7518cc226b
commit
77ea61bac7
@ -21,17 +21,22 @@ namespace analog
|
||||
class diode
|
||||
{
|
||||
public:
|
||||
diode() : m_Is(1e-15), m_VT(0.0258), m_VT_inv(plib::reciprocal(m_VT)) {}
|
||||
diode()
|
||||
: m_Is(plib::constants<nl_fptype>::cast(1e-15))
|
||||
, m_VT(plib::constants<nl_fptype>::cast(0.0258))
|
||||
, m_VT_inv(plib::reciprocal(m_VT))
|
||||
{}
|
||||
|
||||
diode(const nl_fptype Is, const nl_fptype n)
|
||||
{
|
||||
m_Is = Is;
|
||||
m_VT = 0.0258 * n;
|
||||
m_VT = plib::constants<nl_fptype>::cast(0.0258) * n;
|
||||
m_VT_inv = plib::reciprocal(m_VT);
|
||||
}
|
||||
void set(const nl_fptype Is, const nl_fptype n)
|
||||
{
|
||||
m_Is = Is;
|
||||
m_VT = 0.0258 * n;
|
||||
m_VT = plib::constants<nl_fptype>::cast(0.0258) * n;
|
||||
m_VT_inv = plib::reciprocal(m_VT);
|
||||
}
|
||||
nl_fptype I(const nl_fptype V) const { return m_Is * std::exp(V * m_VT_inv) - m_Is; }
|
||||
@ -179,9 +184,9 @@ namespace analog
|
||||
, m_RB(*this, "m_RB", true)
|
||||
, m_RC(*this, "m_RC", true)
|
||||
, m_BC(*this, "m_BC", true)
|
||||
, m_gB(1e-9)
|
||||
, m_gC(1e-9)
|
||||
, m_V(0.0)
|
||||
, m_gB(plib::constants<nl_fptype>::cast(1e-9))
|
||||
, m_gC(plib::constants<nl_fptype>::cast(1e-9))
|
||||
, m_V(plib::constants<nl_fptype>::zero())
|
||||
, m_state_on(*this, "m_state_on", 0)
|
||||
{
|
||||
register_subalias("B", m_RB.m_P);
|
||||
@ -237,13 +242,13 @@ namespace analog
|
||||
connect(m_D_EB.m_N, m_D_CB.m_N);
|
||||
connect(m_D_CB.m_P, m_D_EC.m_N);
|
||||
|
||||
if (m_model.m_CJE > 0.0)
|
||||
if (m_model.m_CJE > plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
create_and_register_subdevice("m_CJE", m_CJE);
|
||||
connect("B", "m_CJE.1");
|
||||
connect("E", "m_CJE.2");
|
||||
}
|
||||
if (m_model.m_CJC > 0.0)
|
||||
if (m_model.m_CJC > plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
create_and_register_subdevice("m_CJC", m_CJC);
|
||||
connect("B", "m_CJC.1");
|
||||
@ -292,13 +297,14 @@ namespace analog
|
||||
NETLIB_RESET(QBJT_switch)
|
||||
{
|
||||
NETLIB_NAME(QBJT)::reset();
|
||||
const auto zero(plib::constants<nl_fptype>::zero());
|
||||
|
||||
m_state_on = 0;
|
||||
|
||||
m_RB.set_G_V_I(exec().gmin(), 0.0, 0.0);
|
||||
m_RC.set_G_V_I(exec().gmin(), 0.0, 0.0);
|
||||
m_RB.set_G_V_I(exec().gmin(), zero, zero);
|
||||
m_RC.set_G_V_I(exec().gmin(), zero, zero);
|
||||
|
||||
m_BC.set_G_V_I(exec().gmin() / 10.0, 0.0, 0.0);
|
||||
m_BC.set_G_V_I(exec().gmin() / plib::constants<nl_fptype>::cast(10.0), zero, zero);
|
||||
|
||||
}
|
||||
|
||||
@ -323,24 +329,25 @@ namespace analog
|
||||
|
||||
set_qtype((m_model.type() == "NPN") ? BJT_NPN : BJT_PNP);
|
||||
|
||||
nl_fptype alpha = BF / (1.0 + BF);
|
||||
nl_fptype alpha = BF / (plib::constants<nl_fptype>::one() + BF);
|
||||
|
||||
diode d(IS, NF);
|
||||
|
||||
// Assume 5mA Collector current for switch operation
|
||||
|
||||
m_V = d.V(0.005 / alpha);
|
||||
const auto cc(plib::constants<nl_fptype>::cast(0.005));
|
||||
m_V = d.V(cc / alpha);
|
||||
|
||||
/* Base current is 0.005 / beta
|
||||
* as a rough estimate, we just scale the conductance down */
|
||||
|
||||
m_gB = plib::reciprocal((m_V/(0.005 / BF)));
|
||||
m_gB = plib::reciprocal((m_V/(cc / BF)));
|
||||
|
||||
//m_gB = d.gI(0.005 / alpha);
|
||||
|
||||
if (m_gB < exec().gmin())
|
||||
m_gB = exec().gmin();
|
||||
m_gC = d.gI(0.005); // very rough estimate
|
||||
m_gC = d.gI(cc); // very rough estimate
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_TERMINALS(QBJT_switch)
|
||||
@ -350,12 +357,13 @@ namespace analog
|
||||
const unsigned new_state = (m_RB.deltaV() * m > m_V ) ? 1 : 0;
|
||||
if (m_state_on ^ new_state)
|
||||
{
|
||||
const auto zero(plib::constants<nl_fptype>::zero());
|
||||
const nl_fptype gb = new_state ? m_gB : exec().gmin();
|
||||
const nl_fptype gc = new_state ? m_gC : exec().gmin();
|
||||
const nl_fptype v = new_state ? m_V * m : 0;
|
||||
const nl_fptype v = new_state ? m_V * m : zero;
|
||||
|
||||
m_RB.set_G_V_I(gb, v, 0.0);
|
||||
m_RC.set_G_V_I(gc, 0.0, 0.0);
|
||||
m_RB.set_G_V_I(gb, v, zero);
|
||||
m_RC.set_G_V_I(gc, zero, zero);
|
||||
m_state_on = new_state;
|
||||
}
|
||||
}
|
||||
@ -395,7 +403,7 @@ namespace analog
|
||||
|
||||
NETLIB_UPDATE_TERMINALS(QBJT_EB)
|
||||
{
|
||||
const nl_fptype polarity = (qtype() == BJT_NPN ? 1.0 : -1.0);
|
||||
const nl_fptype polarity = plib::constants<nl_fptype>::cast(qtype() == BJT_NPN ? 1.0 : -1.0);
|
||||
|
||||
m_gD_BE.update_diode(-m_D_EB.deltaV() * polarity);
|
||||
m_gD_BC.update_diode(-m_D_CB.deltaV() * polarity);
|
||||
@ -431,8 +439,8 @@ namespace analog
|
||||
|
||||
set_qtype((m_model.type() == "NPN") ? BJT_NPN : BJT_PNP);
|
||||
|
||||
m_alpha_f = BF / (1.0 + BF);
|
||||
m_alpha_r = BR / (1.0 + BR);
|
||||
m_alpha_f = BF / (plib::constants<nl_fptype>::one() + BF);
|
||||
m_alpha_r = BR / (plib::constants<nl_fptype>::one() + BR);
|
||||
|
||||
m_gD_BE.set_param(IS / m_alpha_f, NF, exec().gmin(), constants::T0());
|
||||
m_gD_BC.set_param(IS / m_alpha_r, NR, exec().gmin(), constants::T0());
|
||||
|
@ -38,10 +38,10 @@ namespace analog
|
||||
{
|
||||
public:
|
||||
generic_capacitor(device_t &dev, const pstring &name)
|
||||
: m_h(dev, name + ".m_h", 0.0)
|
||||
, m_c(dev, name + ".m_c", 0.0)
|
||||
, m_v(dev, name + ".m_v", 0.0)
|
||||
, m_gmin(0.0)
|
||||
: m_h(dev, name + ".m_h", plib::constants<nl_fptype>::zero())
|
||||
, m_c(dev, name + ".m_c", plib::constants<nl_fptype>::zero())
|
||||
, m_v(dev, name + ".m_v", plib::constants<nl_fptype>::zero())
|
||||
, m_gmin(plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ namespace analog
|
||||
nl_fptype G(nl_fptype cap) const
|
||||
{
|
||||
//return m_h * cap + m_gmin;
|
||||
return m_h * 0.5 * (cap + m_c) + m_gmin;
|
||||
return m_h * plib::constants<nl_fptype>::half() * (cap + m_c) + m_gmin;
|
||||
//return m_h * cap + m_gmin;
|
||||
}
|
||||
|
||||
@ -65,7 +65,7 @@ namespace analog
|
||||
{
|
||||
plib::unused_var(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 * plib::constants<nl_fptype>::half() * (cap + m_c) * m_v;
|
||||
//return -m_h * cap * m_v;
|
||||
}
|
||||
|
||||
@ -91,9 +91,9 @@ namespace analog
|
||||
{
|
||||
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)
|
||||
: m_h(dev, name + ".m_h", plib::constants<nl_fptype>::zero())
|
||||
, m_v(dev, name + ".m_v", plib::constants<nl_fptype>::zero())
|
||||
, m_gmin(plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
}
|
||||
|
||||
@ -133,25 +133,29 @@ namespace analog
|
||||
{
|
||||
public:
|
||||
generic_diode(device_t &dev, const pstring &name)
|
||||
: m_Vd(dev, name + ".m_Vd", 0.7)
|
||||
, m_Id(dev, name + ".m_Id", 0.0)
|
||||
, m_G(dev, name + ".m_G", 1e-15)
|
||||
, m_Vt(0.0)
|
||||
, m_Vmin(0.0) // not used in MOS model
|
||||
, m_Is(0.0)
|
||||
, m_logIs(0.0)
|
||||
, m_n(0.0)
|
||||
, m_gmin(1e-15)
|
||||
, m_VtInv(0.0)
|
||||
, m_Vcrit(0.0)
|
||||
: m_Vd(dev, name + ".m_Vd", plib::constants<nl_fptype>::cast(0.7))
|
||||
, m_Id(dev, name + ".m_Id", plib::constants<nl_fptype>::zero())
|
||||
, m_G(dev, name + ".m_G", plib::constants<nl_fptype>::cast(1e-15))
|
||||
, m_Vt(plib::constants<nl_fptype>::zero())
|
||||
, m_Vmin(plib::constants<nl_fptype>::zero()) // not used in MOS model
|
||||
, m_Is(plib::constants<nl_fptype>::zero())
|
||||
, m_logIs(plib::constants<nl_fptype>::zero())
|
||||
, m_n(plib::constants<nl_fptype>::zero())
|
||||
, m_gmin(plib::constants<nl_fptype>::cast(1e-15))
|
||||
, m_VtInv(plib::constants<nl_fptype>::zero())
|
||||
, m_Vcrit(plib::constants<nl_fptype>::zero())
|
||||
, m_name(name)
|
||||
{
|
||||
set_param(1e-15, 1, 1e-15, 300.0);
|
||||
set_param(
|
||||
plib::constants<nl_fptype>::cast(1e-15)
|
||||
, plib::constants<nl_fptype>::cast(1)
|
||||
, plib::constants<nl_fptype>::cast(1e-15)
|
||||
, plib::constants<nl_fptype>::cast(300.0));
|
||||
}
|
||||
|
||||
void update_diode(const nl_fptype nVd)
|
||||
{
|
||||
nl_fptype IseVDVt(0.0);
|
||||
nl_fptype IseVDVt(plib::constants<nl_fptype>::zero());
|
||||
|
||||
if (TYPE == diode_e::BIPOLAR)
|
||||
{
|
||||
@ -160,7 +164,7 @@ namespace analog
|
||||
{
|
||||
const nl_fptype d = std::min(+fp_constants<nl_fptype>::DIODE_MAXDIFF(), nVd - m_Vd);
|
||||
const nl_fptype a = std::abs(d) * m_VtInv;
|
||||
m_Vd = m_Vd + (d < 0 ? -1.0 : 1.0) * std::log1p(a) * m_Vt;
|
||||
m_Vd = m_Vd + plib::constants<nl_fptype>::cast(d < 0 ? -1.0 : 1.0) * std::log1p(a) * m_Vt;
|
||||
}
|
||||
else
|
||||
m_Vd = std::max(-fp_constants<nl_fptype>::DIODE_MAXDIFF(), nVd);
|
||||
@ -205,7 +209,7 @@ namespace analog
|
||||
|
||||
m_Vt = m_n * temp * constants::k_b() / constants::Q_e();
|
||||
|
||||
m_Vmin = -5.0 * m_Vt;
|
||||
m_Vmin = plib::constants<nl_fptype>::cast(-5.0) * m_Vt;
|
||||
|
||||
m_Vcrit = m_Vt * std::log(m_Vt / m_Is / constants::sqrt2());
|
||||
m_VtInv = constants::one() / m_Vt;
|
||||
|
@ -195,20 +195,20 @@ namespace analog
|
||||
, m_cap_gb(*this, "m_cap_gb")
|
||||
, m_cap_gs(*this, "m_cap_gs")
|
||||
, m_cap_gd(*this, "m_cap_gd")
|
||||
, m_phi(0.0)
|
||||
, m_gamma(0.0)
|
||||
, m_vto(0.0)
|
||||
, m_beta(0.0)
|
||||
, m_lambda(0.0)
|
||||
, m_Leff(0.0)
|
||||
, m_CoxWL(0.0)
|
||||
, m_polarity(qtype() == FET_NMOS ? 1.0 : -1.0)
|
||||
, m_Cgb(0.0)
|
||||
, m_Cgs(0.0)
|
||||
, m_Cgd(0.0)
|
||||
, m_phi(plib::constants<nl_fptype>::zero())
|
||||
, m_gamma(plib::constants<nl_fptype>::zero())
|
||||
, m_vto(plib::constants<nl_fptype>::zero())
|
||||
, m_beta(plib::constants<nl_fptype>::zero())
|
||||
, m_lambda(plib::constants<nl_fptype>::zero())
|
||||
, m_Leff(plib::constants<nl_fptype>::zero())
|
||||
, m_CoxWL(plib::constants<nl_fptype>::zero())
|
||||
, m_polarity(plib::constants<nl_fptype>::cast(qtype() == FET_NMOS ? 1.0 : -1.0))
|
||||
, m_Cgb(plib::constants<nl_fptype>::zero())
|
||||
, m_Cgs(plib::constants<nl_fptype>::zero())
|
||||
, m_Cgd(plib::constants<nl_fptype>::zero())
|
||||
, m_capmod(2)
|
||||
, m_Vgs(*this, "m_Vgs", 0.0)
|
||||
, m_Vgd(*this, "m_Vgd", 0.0)
|
||||
, m_Vgs(*this, "m_Vgs", plib::constants<nl_fptype>::zero())
|
||||
, m_Vgd(*this, "m_Vgd", plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
register_subalias("S", m_SG.m_P); // Source
|
||||
register_subalias("G", m_SG.m_N); // Gate
|
||||
@ -220,7 +220,7 @@ namespace analog
|
||||
connect(m_DG.m_P, m_SD.m_N);
|
||||
|
||||
set_qtype((m_model.type() == "NMOS_DEFAULT") ? FET_NMOS : FET_PMOS);
|
||||
m_polarity = qtype() == FET_NMOS ? 1.0 : -1.0;
|
||||
m_polarity = qtype() == plib::constants<nl_fptype>::cast(FET_NMOS ? 1.0 : -1.0);
|
||||
|
||||
m_capmod = m_model.m_CAPMOD;
|
||||
// printf("capmod %d %g %g\n", m_capmod, (nl_fptype)m_model.m_VTO, m_polarity);
|
||||
@ -241,46 +241,49 @@ namespace analog
|
||||
|
||||
// calculate effective channel length
|
||||
m_Leff = m_model.m_L - 2 * m_model.m_LD;
|
||||
nl_assert_always(m_Leff > 0.0, "Effective Lateral diffusion would be negative for model " + m_model.name());
|
||||
nl_assert_always(m_Leff > plib::constants<nl_fptype>::zero(), "Effective Lateral diffusion would be negative for model " + m_model.name());
|
||||
|
||||
nl_fptype Cox = (m_model.m_TOX > 0.0) ? (constants::eps_SiO2() * constants::eps_0() / m_model.m_TOX) : 0.0;
|
||||
nl_fptype Cox = (m_model.m_TOX > plib::constants<nl_fptype>::zero()) ? (constants::eps_SiO2() * constants::eps_0() / m_model.m_TOX) : plib::constants<nl_fptype>::zero();
|
||||
|
||||
// calculate DC transconductance coefficient
|
||||
if (m_model.m_KP > 0)
|
||||
if (m_model.m_KP > plib::constants<nl_fptype>::zero())
|
||||
m_beta = m_model.m_KP * m_model.m_W / m_Leff;
|
||||
else if (Cox > 0 && m_model.m_UO > 0)
|
||||
m_beta = m_model.m_UO * 1e-4 * Cox * m_model.m_W / m_Leff;
|
||||
else if (Cox > plib::constants<nl_fptype>::zero() && m_model.m_UO > plib::constants<nl_fptype>::zero())
|
||||
m_beta = m_model.m_UO * plib::constants<nl_fptype>::cast(1e-4) * Cox * m_model.m_W / m_Leff;
|
||||
else
|
||||
m_beta = 2e-5 * m_model.m_W / m_Leff;
|
||||
m_beta = plib::constants<nl_fptype>::cast(2e-5) * m_model.m_W / m_Leff;
|
||||
|
||||
//FIXME::UT can disappear
|
||||
const nl_fptype Vt = constants::T0() * constants::k_b() / constants::Q_e();
|
||||
|
||||
// calculate surface potential if not given
|
||||
|
||||
if (m_model.m_PHI > 0.0)
|
||||
if (m_model.m_PHI > plib::constants<nl_fptype>::zero())
|
||||
m_phi = m_model.m_PHI;
|
||||
else if (m_model.m_NSUB > 0.0)
|
||||
else if (m_model.m_NSUB > plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
nl_assert_always(m_model.m_NSUB * 1e6 >= constants::NiSi(), "Error calculating phi for model " + m_model.name());
|
||||
m_phi = 2 * Vt * std::log (m_model.m_NSUB * 1e6 / constants::NiSi());
|
||||
nl_assert_always(m_model.m_NSUB * plib::constants<nl_fptype>::cast(1e6) >= constants::NiSi(), "Error calculating phi for model " + m_model.name());
|
||||
m_phi = plib::constants<nl_fptype>::two() * Vt * std::log (m_model.m_NSUB * plib::constants<nl_fptype>::cast(1e6) / constants::NiSi());
|
||||
}
|
||||
else
|
||||
m_phi = 0.6;
|
||||
m_phi = plib::constants<nl_fptype>::cast(0.6);
|
||||
|
||||
// calculate bulk threshold if not given
|
||||
if (m_model.m_GAMMA > 0.0)
|
||||
if (m_model.m_GAMMA > plib::constants<nl_fptype>::zero())
|
||||
m_gamma = m_model.m_GAMMA;
|
||||
else
|
||||
{
|
||||
if (Cox > 0.0 && m_model.m_NSUB > 0)
|
||||
m_gamma = std::sqrt (2.0 * constants::Q_e() * constants::eps_Si() * constants::eps_0() * m_model.m_NSUB * 1e6) / Cox;
|
||||
if (Cox > plib::constants<nl_fptype>::zero() && m_model.m_NSUB > plib::constants<nl_fptype>::zero())
|
||||
m_gamma = std::sqrt (plib::constants<nl_fptype>::two()
|
||||
* constants::Q_e() * constants::eps_Si() * constants::eps_0()
|
||||
* m_model.m_NSUB * plib::constants<nl_fptype>::cast(1e6)) / Cox;
|
||||
else
|
||||
m_gamma = 0.0;
|
||||
m_gamma = plib::constants<nl_fptype>::zero();
|
||||
}
|
||||
|
||||
m_vto = m_model.m_VTO;
|
||||
if(m_vto != 0.0)
|
||||
// FIXME zero conversion
|
||||
if(m_vto != plib::constants<nl_fptype>::zero())
|
||||
log().warning(MW_MOSFET_THRESHOLD_VOLTAGE(m_model.name()));
|
||||
|
||||
/* FIXME: VTO if missing may be calculated from TPG, NSS and temperature. Usually models
|
||||
@ -302,7 +305,7 @@ namespace analog
|
||||
//const nl_nl_fptype Ugs = -m_SG.deltaV() * m_polarity; // Gate - Source
|
||||
const nl_fptype Ugd = m_Vgd; // Gate - Drain
|
||||
const nl_fptype Ugs = m_Vgs; // Gate - Source
|
||||
const nl_fptype Ubs = 0.0; // Bulk - Source == 0 if connected
|
||||
const nl_fptype Ubs = plib::constants<nl_fptype>::zero(); // Bulk - Source == 0 if connected
|
||||
const nl_fptype Ugb = Ugs - Ubs;
|
||||
|
||||
m_cap_gb.timestep(m_Cgb, Ugb, step);
|
||||
@ -385,21 +388,21 @@ namespace analog
|
||||
if (Vctrl <= -m_phi)
|
||||
{
|
||||
Cgb = m_CoxWL;
|
||||
Cgs = 0.0;
|
||||
Cgd = 0.0;
|
||||
Cgs = plib::constants<nl_fptype>::zero();
|
||||
Cgd = plib::constants<nl_fptype>::zero();
|
||||
}
|
||||
else if (Vctrl <= -m_phi / 2.0)
|
||||
else if (Vctrl <= -m_phi / plib::constants<nl_fptype>::two())
|
||||
{
|
||||
Cgb = -Vctrl * m_CoxWL / m_phi;
|
||||
Cgs = 0.0;
|
||||
Cgd = 0.0;
|
||||
Cgs = plib::constants<nl_fptype>::zero();
|
||||
Cgd = plib::constants<nl_fptype>::zero();
|
||||
}
|
||||
// Depletion
|
||||
else if (Vctrl <= 0)
|
||||
{
|
||||
Cgb = -Vctrl * m_CoxWL / m_phi;
|
||||
Cgs = Vctrl * m_CoxWL * (4.0 / 3.0) / m_phi + (2.0 / 3.0) * m_CoxWL;
|
||||
Cgd = 0.0;
|
||||
Cgs = Vctrl * m_CoxWL * plib::constants<nl_fptype>::cast(4.0 / 3.0) / m_phi + plib::constants<nl_fptype>::cast(2.0 / 3.0) * m_CoxWL;
|
||||
Cgd = plib::constants<nl_fptype>::zero();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -408,18 +411,18 @@ namespace analog
|
||||
// saturation
|
||||
if (Vdsat <= Vds)
|
||||
{
|
||||
Cgb = 0;
|
||||
Cgs = (2.0 / 3.0) * m_CoxWL;
|
||||
Cgd = 0;
|
||||
Cgb = plib::constants<nl_fptype>::zero();
|
||||
Cgs = plib::constants<nl_fptype>::cast(2.0 / 3.0) * m_CoxWL;
|
||||
Cgd = plib::constants<nl_fptype>::zero();
|
||||
}
|
||||
else
|
||||
{
|
||||
// linear
|
||||
const nl_fptype Sqr1 = std::pow(Vdsat - Vds, 2);
|
||||
const nl_fptype Sqr2 = std::pow(2.0 * Vdsat - Vds, 2);
|
||||
const nl_fptype Sqr1 = static_cast<nl_fptype>(std::pow(Vdsat - Vds, 2));
|
||||
const nl_fptype Sqr2 = static_cast<nl_fptype>(std::pow(plib::constants<nl_fptype>::two() * Vdsat - Vds, 2));
|
||||
Cgb = 0;
|
||||
Cgs = m_CoxWL * (1.0 - Sqr1 / Sqr2) * (2.0 / 3.0);
|
||||
Cgd = m_CoxWL * (1.0 - Vdsat * Vdsat / Sqr2) * (2.0 / 3.0);
|
||||
Cgs = m_CoxWL * (plib::constants<nl_fptype>::one() - Sqr1 / Sqr2) * plib::constants<nl_fptype>::cast(2.0 / 3.0);
|
||||
Cgd = m_CoxWL * (plib::constants<nl_fptype>::one() - Vdsat * Vdsat / Sqr2) * plib::constants<nl_fptype>::cast(2.0 / 3.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -447,16 +450,16 @@ namespace analog
|
||||
|
||||
// limit step sizes
|
||||
|
||||
const nl_fptype k = 3.5; // see "Circuit Simulation", page 185
|
||||
const nl_fptype k = plib::constants<nl_fptype>::cast(3.5); // see "Circuit Simulation", page 185
|
||||
nl_fptype d = (Vgs - m_Vgs);
|
||||
Vgs = m_Vgs + plib::reciprocal(k) * (d < 0 ? -1.0 : 1.0) * std::log1p(k * std::abs(d));
|
||||
Vgs = m_Vgs + plib::reciprocal(k) * plib::constants<nl_fptype>::cast(d < 0 ? -1.0 : 1.0) * std::log1p(k * std::abs(d));
|
||||
d = (Vgd - m_Vgd);
|
||||
Vgd = m_Vgd + plib::reciprocal(k) * (d < 0 ? -1.0 : 1.0) * std::log1p(k * std::abs(d));
|
||||
Vgd = m_Vgd + plib::reciprocal(k) * plib::constants<nl_fptype>::cast(d < 0 ? -1.0 : 1.0) * std::log1p(k * std::abs(d));
|
||||
|
||||
m_Vgs = Vgs;
|
||||
m_Vgd = Vgd;
|
||||
|
||||
const nl_fptype Vbs = 0.0; // Bulk - Source == 0 if connected
|
||||
const nl_fptype Vbs = plib::constants<nl_fptype>::zero(); // Bulk - Source == 0 if connected
|
||||
//const nl_nl_fptype Vbd = m_SD.deltaV() * m_polarity; // Bulk - Drain = Source - Drain
|
||||
const nl_fptype Vds = Vgs - Vgd;
|
||||
const nl_fptype Vbd = -Vds; // Bulk - Drain = Source - Drain
|
||||
@ -468,11 +471,11 @@ namespace analog
|
||||
|
||||
// Are we in forward mode ?
|
||||
// in backward mode, just swap source and drain
|
||||
const bool is_forward = Vds >= 0;
|
||||
const bool is_forward = Vds >= plib::constants<nl_fptype>::zero();
|
||||
|
||||
// calculate Vth
|
||||
const nl_fptype Vbulk = is_forward ? Vbs : Vbd;
|
||||
const nl_fptype phi_m_Vbulk = (m_phi > Vbulk) ? std::sqrt(m_phi - Vbulk) : 0.0;
|
||||
const nl_fptype phi_m_Vbulk = (m_phi > Vbulk) ? std::sqrt(m_phi - Vbulk) : plib::constants<nl_fptype>::zero();
|
||||
const nl_fptype Vth = m_vto * m_polarity + m_gamma * (phi_m_Vbulk - std::sqrt(m_phi));
|
||||
|
||||
const nl_fptype Vctrl = (is_forward ? Vgs : Vgd) - Vth;
|
||||
@ -480,34 +483,34 @@ namespace analog
|
||||
nl_fptype Ids(0), gm(0), gds(0), gmb(0);
|
||||
const nl_fptype absVds = std::abs(Vds);
|
||||
|
||||
if (Vctrl <= 0.0)
|
||||
if (Vctrl <= plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
// cutoff region
|
||||
Ids = 0.0;
|
||||
gm = 0.0;
|
||||
gds = 0.0;
|
||||
gmb = 0.0;
|
||||
Ids = plib::constants<nl_fptype>::zero();
|
||||
gm = plib::constants<nl_fptype>::zero();
|
||||
gds = plib::constants<nl_fptype>::zero();
|
||||
gmb = plib::constants<nl_fptype>::zero();
|
||||
}
|
||||
else
|
||||
{
|
||||
const nl_fptype beta = m_beta * (1.0 + m_lambda * absVds);
|
||||
const nl_fptype beta = m_beta * (plib::constants<nl_fptype>::one() + m_lambda * absVds);
|
||||
if (Vctrl <= absVds)
|
||||
{
|
||||
// saturation region
|
||||
Ids = beta * Vctrl * Vctrl / 2.0;
|
||||
Ids = beta * Vctrl * Vctrl / plib::constants<nl_fptype>::two();
|
||||
gm = beta * Vctrl;
|
||||
gds = m_lambda * m_beta * Vctrl * Vctrl / 2.0;
|
||||
gds = m_lambda * m_beta * Vctrl * Vctrl / plib::constants<nl_fptype>::two();
|
||||
}
|
||||
else
|
||||
{
|
||||
// linear region
|
||||
Ids = beta * absVds * (Vctrl - absVds / 2);
|
||||
Ids = beta * absVds * (Vctrl - absVds / plib::constants<nl_fptype>::two());
|
||||
gm = beta * absVds;
|
||||
gds = beta * (Vctrl - absVds) + m_lambda * m_beta * absVds * (Vctrl - absVds / 2.0);
|
||||
gds = beta * (Vctrl - absVds) + m_lambda * m_beta * absVds * (Vctrl - absVds / plib::constants<nl_fptype>::two());
|
||||
}
|
||||
|
||||
// backgate transconductance
|
||||
const nl_fptype bgtc = (phi_m_Vbulk != 0.0) ? (m_gamma / phi_m_Vbulk / 2.0) : 0.0;
|
||||
const nl_fptype bgtc = (phi_m_Vbulk != plib::constants<nl_fptype>::zero()) ? (m_gamma / phi_m_Vbulk / plib::constants<nl_fptype>::two()) : plib::constants<nl_fptype>::zero();
|
||||
gmb = gm * bgtc;
|
||||
}
|
||||
|
||||
@ -524,27 +527,27 @@ namespace analog
|
||||
const nl_fptype IeqBS = m_D_BS.Ieq();
|
||||
const nl_fptype gbs = m_D_BS.G();
|
||||
#else
|
||||
const nl_fptype IeqBS = 0.0;
|
||||
const nl_fptype gbs = 0.0;
|
||||
const nl_fptype IeqBS = plib::constants<nl_fptype>::zero();
|
||||
const nl_fptype gbs = plib::constants<nl_fptype>::zero();
|
||||
#endif
|
||||
// exchange controlling nodes if necessary
|
||||
const nl_fptype gsource = is_forward ? (gm + gmb) : 0;
|
||||
const nl_fptype gdrain = is_forward ? 0.0 : (gm + gmb);
|
||||
const nl_fptype gsource = is_forward ? (gm + gmb) : plib::constants<nl_fptype>::zero();
|
||||
const nl_fptype gdrain = is_forward ? plib::constants<nl_fptype>::zero() : (gm + gmb);
|
||||
|
||||
const nl_fptype IeqDS = (is_forward) ?
|
||||
Ids - gm * Vgs - gmb * Vbs - gds * Vds
|
||||
: -Ids - gm * Vgd - gmb * Vbd - gds * Vds;
|
||||
|
||||
// IG = 0
|
||||
nl_fptype IG = 0.0;
|
||||
nl_fptype IG = plib::constants<nl_fptype>::zero();
|
||||
nl_fptype ID = (+IeqBD - IeqDS) * m_polarity;
|
||||
nl_fptype IS = (+IeqBS + IeqDS) * m_polarity;
|
||||
nl_fptype IB = (-IeqBD - IeqBS) * m_polarity;
|
||||
|
||||
nl_fptype gGG = 0.0;
|
||||
nl_fptype gGD = 0.0;
|
||||
nl_fptype gGS = 0.0;
|
||||
nl_fptype gGB = 0.0;
|
||||
nl_fptype gGG = plib::constants<nl_fptype>::zero();
|
||||
nl_fptype gGD = plib::constants<nl_fptype>::zero();
|
||||
nl_fptype gGS = plib::constants<nl_fptype>::zero();
|
||||
nl_fptype gGB = plib::constants<nl_fptype>::zero();
|
||||
|
||||
nl_fptype gDG = gm;
|
||||
nl_fptype gDD = gds + gbd - gdrain;
|
||||
@ -556,7 +559,7 @@ namespace analog
|
||||
nl_fptype gSS = gbs + gds + gsource;
|
||||
const nl_fptype gSB = -gbs - gmb;
|
||||
|
||||
nl_fptype gBG = 0.0;
|
||||
nl_fptype gBG = plib::constants<nl_fptype>::zero();
|
||||
const nl_fptype gBD = -gbd;
|
||||
const nl_fptype gBS = -gbs;
|
||||
nl_fptype gBB = gbs + gbd;
|
||||
@ -577,16 +580,16 @@ namespace analog
|
||||
|
||||
// Source connected to body, Diode S-B shorted!
|
||||
const nl_fptype gSSBB = gSS + gBB + gBS + gSB;
|
||||
|
||||
const auto zero(plib::constants<nl_fptype>::zero());
|
||||
// S G
|
||||
m_SG.set_mat( gSSBB, gSG + gBG, +(IS + IB), // S
|
||||
gGS + gGB, gGG, IG ); // G
|
||||
// D G
|
||||
m_DG.set_mat( gDD, gDG, +ID, // D
|
||||
gGD, 0.0, 0.0 ); // G
|
||||
gGD, zero, zero ); // G
|
||||
// S D
|
||||
m_SD.set_mat( 0.0, gSD + gBD, 0.0, // S
|
||||
gDS + gDB, 0.0, 0.0); // D
|
||||
m_SD.set_mat( zero, gSD + gBD, zero, // S
|
||||
gDS + gDB, zero, zero); // D
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(MOSFET)
|
||||
|
@ -197,13 +197,13 @@ namespace netlist
|
||||
|
||||
NETLIB_UPDATE(opamp)
|
||||
{
|
||||
const nl_fptype cVt = 0.0258 * 1.0; // * m_n;
|
||||
const nl_fptype cVt = plib::constants<nl_fptype>::cast(0.0258 * 1.0); // * m_n;
|
||||
const nl_fptype cId = m_model.m_DAB; // 3 mA
|
||||
const nl_fptype cVd = cVt * std::log(cId / 1e-15 + 1.0);
|
||||
const nl_fptype cVd = cVt * std::log(cId / plib::constants<nl_fptype>::cast(1e-15) + plib::constants<nl_fptype>::one());
|
||||
|
||||
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);
|
||||
m_VREF.push((m_VCC() + m_GND()) / plib::constants<nl_fptype>::two());
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(opamp)
|
||||
@ -220,11 +220,11 @@ namespace netlist
|
||||
if (m_type == 3 || m_type == 2)
|
||||
{
|
||||
nl_fptype CP = m_model.m_DAB / m_model.m_SLEW;
|
||||
nl_fptype RP = 0.5 / constants::pi() / CP / m_model.m_FPF;
|
||||
nl_fptype RP = plib::constants<nl_fptype>::half() / constants::pi() / CP / m_model.m_FPF;
|
||||
nl_fptype G = m_model.m_UGF / m_model.m_FPF / RP;
|
||||
|
||||
//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)
|
||||
if (m_model.m_SLEW / (plib::constants<nl_fptype>::four() * constants::pi() * plib::constants<nl_fptype>::cast(0.0258)) < m_model.m_UGF)
|
||||
log().warning(MW_OPAMP_FAIL_CONVERGENCE(this->name()));
|
||||
|
||||
m_CP->m_C.setTo(CP);
|
||||
@ -234,12 +234,12 @@ namespace netlist
|
||||
}
|
||||
if (m_type == 2)
|
||||
{
|
||||
m_EBUF->m_G.setTo(1.0);
|
||||
m_EBUF->m_G.setTo(plib::constants<nl_fptype>::one());
|
||||
m_EBUF->m_RO.setTo(m_model.m_RO);
|
||||
}
|
||||
if (m_type == 3)
|
||||
{
|
||||
m_EBUF->m_G.setTo(1.0);
|
||||
m_EBUF->m_G.setTo(plib::constants<nl_fptype>::one());
|
||||
m_EBUF->m_RO.setTo(m_model.m_RO);
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
/* FIXME : convert to parameters */
|
||||
|
||||
#define R_OFF (plib::reciprocal(exec().gmin()))
|
||||
#define R_ON 0.01
|
||||
#define R_ON plib::constants<nl_fptype>::cast(0.01)
|
||||
|
||||
namespace netlist
|
||||
{
|
||||
|
@ -53,15 +53,15 @@
|
||||
#warning "Do not include rescap.h in a netlist environment"
|
||||
#endif
|
||||
#ifndef RES_R
|
||||
#define RES_R(res) (static_cast<nl_fptype>(res))
|
||||
#define RES_K(res) (static_cast<nl_fptype>(res) * 1e3)
|
||||
#define RES_M(res) (static_cast<nl_fptype>(res) * 1e6)
|
||||
#define CAP_U(cap) (static_cast<nl_fptype>(cap) * 1e-6)
|
||||
#define CAP_N(cap) (static_cast<nl_fptype>(cap) * 1e-9)
|
||||
#define CAP_P(cap) (static_cast<nl_fptype>(cap) * 1e-12)
|
||||
#define IND_U(ind) (static_cast<nl_fptype>(ind) * 1e-6)
|
||||
#define IND_N(ind) (static_cast<nl_fptype>(ind) * 1e-9)
|
||||
#define IND_P(ind) (static_cast<nl_fptype>(ind) * 1e-12)
|
||||
#define RES_R(res) (res)
|
||||
#define RES_K(res) ((res) * 1e3)
|
||||
#define RES_M(res) ((res) * 1e6)
|
||||
#define CAP_U(cap) ((cap) * 1e-6)
|
||||
#define CAP_N(cap) ((cap) * 1e-9)
|
||||
#define CAP_P(cap) ((cap) * 1e-12)
|
||||
#define IND_U(ind) ((ind) * 1e-6)
|
||||
#define IND_N(ind) ((ind) * 1e-9)
|
||||
#define IND_P(ind) ((ind) * 1e-12)
|
||||
#endif
|
||||
|
||||
#endif /* NLD_TWOTERM_H_ */
|
||||
|
@ -67,16 +67,17 @@ NETLIB_UPDATE_TERMINALS(LVCCS)
|
||||
{
|
||||
const nl_fptype m_mult = m_G() * m_gfac; // 1.0 ==> 1V ==> 1A
|
||||
const nl_fptype vi = m_IP.net().Q_Analog() - m_IN.net().Q_Analog();
|
||||
const auto c1(plib::constants<nl_fptype>::cast(0.2));
|
||||
|
||||
if (std::abs(m_mult / m_cur_limit() * vi) > 0.5)
|
||||
m_vi = m_vi + 0.2*std::tanh((vi - m_vi)/0.2);
|
||||
if (std::abs(m_mult / m_cur_limit() * vi) > plib::constants<nl_fptype>::half())
|
||||
m_vi = m_vi + c1 * std::tanh((vi - m_vi) / c1);
|
||||
else
|
||||
m_vi = vi;
|
||||
|
||||
const nl_fptype x = m_mult / m_cur_limit() * m_vi;
|
||||
const nl_fptype X = std::tanh(x);
|
||||
|
||||
const nl_fptype beta = m_mult * (1.0 - X*X);
|
||||
const nl_fptype beta = m_mult * (plib::constants<nl_fptype>::one() - X*X);
|
||||
const nl_fptype I = m_cur_limit() * X - beta * m_vi;
|
||||
|
||||
m_OP.set_go_gt_I(-beta, plib::constants<nl_fptype>::zero(), I);
|
||||
|
@ -39,15 +39,15 @@ namespace netlist {
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR(VCCS)
|
||||
, m_G(*this, "G", 1.0)
|
||||
, m_RI(*this, "RI", 1e9)
|
||||
, m_G(*this, "G", plib::constants<nl_fptype>::one())
|
||||
, m_RI(*this, "RI", plib::constants<nl_fptype>::cast(1e9))
|
||||
, m_OP(*this, "OP", &m_IP)
|
||||
, m_ON(*this, "ON", &m_IP)
|
||||
, m_IP(*this, "IP", &m_IN) // <= this should be NULL and terminal be filtered out prior to solving...
|
||||
, m_IN(*this, "IN", &m_IP) // <= this should be NULL and terminal be filtered out prior to solving...
|
||||
, m_OP1(*this, "_OP1", &m_IN)
|
||||
, m_ON1(*this, "_ON1", &m_IN)
|
||||
, m_gfac(1.0)
|
||||
, m_gfac(plib::constants<nl_fptype>::one())
|
||||
{
|
||||
connect(m_OP, m_OP1);
|
||||
connect(m_ON, m_ON1);
|
||||
@ -85,8 +85,8 @@ namespace netlist {
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_DERIVED(LVCCS, VCCS)
|
||||
, m_cur_limit(*this, "CURLIM", 1000.0)
|
||||
, m_vi(0.0)
|
||||
, m_cur_limit(*this, "CURLIM", plib::constants<nl_fptype>::cast(1000.0))
|
||||
, m_vi(plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
}
|
||||
|
||||
@ -174,7 +174,7 @@ namespace netlist {
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_DERIVED(VCVS, VCCS)
|
||||
, m_RO(*this, "RO", 1.0)
|
||||
, m_RO(*this, "RO", plib::constants<nl_fptype>::one())
|
||||
, m_OP2(*this, "_OP2", &m_ON2)
|
||||
, m_ON2(*this, "_ON2", &m_OP2)
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ NETLIB_RESET(POT)
|
||||
{
|
||||
nl_fptype v = m_Dial();
|
||||
if (m_DialIsLog())
|
||||
v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0);
|
||||
v = (std::exp(v) - plib::constants<nl_fptype>::one()) / (std::exp(plib::constants<nl_fptype>::one()) - plib::constants<nl_fptype>::one());
|
||||
|
||||
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
||||
m_R2.set_R(std::max(m_R() * (plib::constants<nl_fptype>::one() - v), exec().gmin()));
|
||||
@ -77,9 +77,9 @@ NETLIB_UPDATE_PARAM(POT)
|
||||
|
||||
nl_fptype v = m_Dial();
|
||||
if (m_DialIsLog())
|
||||
v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0);
|
||||
v = (std::exp(v) - plib::constants<nl_fptype>::one()) / (std::exp(plib::constants<nl_fptype>::one()) - plib::constants<nl_fptype>::one());
|
||||
if (m_Reverse())
|
||||
v = 1.0 - v;
|
||||
v = plib::constants<nl_fptype>::one() - v;
|
||||
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
||||
m_R2.set_R(std::max(m_R() * (plib::constants<nl_fptype>::one() - v), exec().gmin()));
|
||||
|
||||
@ -94,9 +94,9 @@ NETLIB_RESET(POT2)
|
||||
nl_fptype v = m_Dial();
|
||||
|
||||
if (m_DialIsLog())
|
||||
v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0);
|
||||
v = (std::exp(v) - plib::constants<nl_fptype>::one()) / (std::exp(plib::constants<nl_fptype>::one()) - plib::constants<nl_fptype>::one());
|
||||
if (m_Reverse())
|
||||
v = 1.0 - v;
|
||||
v = plib::constants<nl_fptype>::one() - v;
|
||||
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
||||
}
|
||||
|
||||
@ -108,9 +108,9 @@ NETLIB_UPDATE_PARAM(POT2)
|
||||
nl_fptype v = m_Dial();
|
||||
|
||||
if (m_DialIsLog())
|
||||
v = (std::exp(v) - 1.0) / (std::exp(1.0) - 1.0);
|
||||
v = (std::exp(v) - plib::constants<nl_fptype>::one()) / (std::exp(plib::constants<nl_fptype>::one()) - plib::constants<nl_fptype>::one());
|
||||
if (m_Reverse())
|
||||
v = 1.0 - v;
|
||||
v = plib::constants<nl_fptype>::one() - v;
|
||||
m_R1.set_R(std::max(m_R() * v, exec().gmin()));
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ NETLIB_UPDATE_PARAM(POT2)
|
||||
NETLIB_RESET(L)
|
||||
{
|
||||
m_gmin = exec().gmin();
|
||||
m_I = 0.0;
|
||||
m_I = plib::constants<nl_fptype>::zero();
|
||||
m_G = m_gmin;
|
||||
set_mat( m_G, -m_G, -m_I,
|
||||
-m_G, m_G, m_I);
|
||||
@ -152,7 +152,7 @@ NETLIB_RESET(D)
|
||||
nl_fptype n = m_model.m_N;
|
||||
|
||||
m_D.set_param(Is, n, exec().gmin(), constants::T0());
|
||||
set_G_V_I(m_D.G(), 0.0, m_D.Ieq());
|
||||
set_G_V_I(m_D.G(), plib::constants<nl_fptype>::zero(), m_D.Ieq());
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAM(D)
|
||||
|
@ -128,8 +128,8 @@ namespace analog
|
||||
void set_R(const nl_fptype R)
|
||||
{
|
||||
const nl_fptype G = plib::constants<nl_fptype>::one() / R;
|
||||
set_mat( G, -G, 0.0,
|
||||
-G, G, 0.0);
|
||||
set_mat( G, -G, plib::constants<nl_fptype>::zero(),
|
||||
-G, G, plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
|
||||
NETLIB_RESETI();
|
||||
@ -142,7 +142,7 @@ namespace analog
|
||||
NETLIB_OBJECT_DERIVED(R, R_base)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR_DERIVED(R, R_base)
|
||||
, m_R(*this, "R", 1e9)
|
||||
, m_R(*this, "R", plib::constants<nl_fptype>::cast(1e9))
|
||||
{
|
||||
}
|
||||
|
||||
@ -178,7 +178,7 @@ namespace analog
|
||||
, m_R1(*this, "_R1")
|
||||
, m_R2(*this, "_R2")
|
||||
, m_R(*this, "R", 10000)
|
||||
, m_Dial(*this, "DIAL", 0.5)
|
||||
, m_Dial(*this, "DIAL", plib::constants<nl_fptype>::half())
|
||||
, m_DialIsLog(*this, "DIALLOG", false)
|
||||
, m_Reverse(*this, "REVERSE", false)
|
||||
{
|
||||
@ -208,8 +208,8 @@ namespace analog
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(POT2)
|
||||
, m_R1(*this, "_R1")
|
||||
, m_R(*this, "R", 10000)
|
||||
, m_Dial(*this, "DIAL", 0.5)
|
||||
, m_R(*this, "R", plib::constants<nl_fptype>::cast(10000.0))
|
||||
, m_Dial(*this, "DIAL", plib::constants<nl_fptype>::half())
|
||||
, m_DialIsLog(*this, "DIALLOG", false)
|
||||
, m_Reverse(*this, "REVERSE", false)
|
||||
{
|
||||
@ -239,7 +239,7 @@ namespace analog
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_DERIVED(C, twoterm)
|
||||
, m_C(*this, "C", 1e-6)
|
||||
, m_C(*this, "C", plib::constants<nl_fptype>::cast(1e-6))
|
||||
, m_cap(*this, "m_cap")
|
||||
{
|
||||
}
|
||||
@ -289,10 +289,10 @@ namespace analog
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_DERIVED(L, twoterm)
|
||||
, m_L(*this, "L", 1e-6)
|
||||
, m_gmin(0.0)
|
||||
, m_G(0.0)
|
||||
, m_I(0.0)
|
||||
, m_L(*this, "L", plib::constants<nl_fptype>::cast(1e-6))
|
||||
, m_gmin(plib::constants<nl_fptype>::zero())
|
||||
, m_G(plib::constants<nl_fptype>::zero())
|
||||
, m_I(plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
//register_term("1", m_P);
|
||||
//register_term("2", m_N);
|
||||
@ -392,12 +392,12 @@ namespace analog
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_DERIVED(VS, twoterm)
|
||||
, m_t(*this, "m_t", 0.0)
|
||||
, m_R(*this, "R", 0.1)
|
||||
, m_V(*this, "V", 0.0)
|
||||
, m_t(*this, "m_t", plib::constants<nl_fptype>::zero())
|
||||
, m_R(*this, "R", plib::constants<nl_fptype>::cast(0.1))
|
||||
, m_V(*this, "V", plib::constants<nl_fptype>::zero())
|
||||
, m_func(*this,"FUNC", "")
|
||||
, m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager())
|
||||
, m_funcparam({0.0})
|
||||
, m_funcparam({plib::constants<nl_fptype>::zero()})
|
||||
{
|
||||
register_subalias("P", m_P);
|
||||
register_subalias("N", m_N);
|
||||
@ -413,7 +413,7 @@ namespace analog
|
||||
m_funcparam[0] = m_t;
|
||||
this->set_G_V_I(plib::reciprocal(m_R()),
|
||||
m_compiled.evaluate(m_funcparam),
|
||||
0.0);
|
||||
plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -422,7 +422,7 @@ namespace analog
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
NETLIB_NAME(twoterm)::reset();
|
||||
this->set_G_V_I(plib::reciprocal(m_R()), m_V(), 0.0);
|
||||
this->set_G_V_I(plib::reciprocal(m_R()), m_V(), plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -442,11 +442,11 @@ namespace analog
|
||||
{
|
||||
public:
|
||||
NETLIB_CONSTRUCTOR_DERIVED(CS, twoterm)
|
||||
, m_t(*this, "m_t", 0.0)
|
||||
, m_I(*this, "I", 1.0)
|
||||
, m_t(*this, "m_t", plib::constants<nl_fptype>::zero())
|
||||
, m_I(*this, "I", plib::constants<nl_fptype>::one())
|
||||
, m_func(*this,"FUNC", "")
|
||||
, m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager())
|
||||
, m_funcparam({0.0})
|
||||
, m_funcparam({plib::constants<nl_fptype>::zero()})
|
||||
{
|
||||
register_subalias("P", m_P);
|
||||
register_subalias("N", m_N);
|
||||
@ -460,8 +460,9 @@ namespace analog
|
||||
m_t += step;
|
||||
m_funcparam[0] = m_t;
|
||||
const nl_fptype I = m_compiled.evaluate(m_funcparam);
|
||||
set_mat(0.0, 0.0, -I,
|
||||
0.0, 0.0, I);
|
||||
const auto zero(plib::constants<nl_fptype>::zero());
|
||||
set_mat(zero, zero, -I,
|
||||
zero, zero, I);
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -470,15 +471,17 @@ namespace analog
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
NETLIB_NAME(twoterm)::reset();
|
||||
set_mat(0.0, 0.0, -m_I(),
|
||||
0.0, 0.0, m_I());
|
||||
const auto zero(plib::constants<nl_fptype>::zero());
|
||||
set_mat(zero, zero, -m_I(),
|
||||
zero, zero, m_I());
|
||||
}
|
||||
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
solve_now();
|
||||
set_mat(0.0, 0.0, -m_I(),
|
||||
0.0, 0.0, m_I());
|
||||
const auto zero(plib::constants<nl_fptype>::zero());
|
||||
set_mat(zero, zero, -m_I(),
|
||||
zero, zero, m_I());
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace netlist
|
||||
, m_supply(*this, "VDD", "VSS", true)
|
||||
, m_R(*this, "R")
|
||||
, m_control(*this, "CTL")
|
||||
, m_base_r(*this, "BASER", 270.0)
|
||||
, m_base_r(*this, "BASER", plib::constants<nl_fptype>::cast(270.0))
|
||||
{
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ namespace netlist
|
||||
nl_fptype high = plib::constants<nl_fptype>::cast(0.55) * sup;
|
||||
nl_fptype in = m_control() - m_supply.GND();
|
||||
nl_fptype rON = m_base_r() * plib::constants<nl_fptype>::cast(5.0) / sup;
|
||||
nl_fptype R = -1.0;
|
||||
nl_fptype R = -plib::constants<nl_fptype>::one();
|
||||
|
||||
if (in < low)
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ namespace netlist { namespace devices {
|
||||
, m_R(*this, "_R")
|
||||
, m_S(*this, "S")
|
||||
, m_E(*this, "E")
|
||||
, m_base_r(*this, "BASER", 45.0)
|
||||
, m_base_r(*this, "BASER", plib::constants<nl_fptype>::cast(45.0))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -31,8 +31,8 @@ namespace netlist
|
||||
, m_last_trig(*this, "m_last_trig", 0)
|
||||
, m_state(*this, "m_state", 0)
|
||||
, m_KP(*this, "m_KP", 0)
|
||||
, m_K(*this, "K", (m_dev_type == 4538) ? 1.0 : 0.4) // CD4538 datasheet states PW=RC
|
||||
, m_RI(*this, "RI", 400.0) // around 250 for HC series, 400 on LS/TTL, estimated from datasheets
|
||||
, m_K(*this, "K", plib::constants<nl_fptype>::cast((m_dev_type == 4538) ? 1.0 : 0.4)) // CD4538 datasheet states PW=RC
|
||||
, m_RI(*this, "RI", plib::constants<nl_fptype>::cast(400.0)) // around 250 for HC series, 400 on LS/TTL, estimated from datasheets
|
||||
{
|
||||
if ((m_dev_type != 9602) && (m_dev_type != 4538) )
|
||||
m_dev_type = 74123;
|
||||
@ -241,7 +241,7 @@ namespace netlist
|
||||
}
|
||||
if (m_state == 2)
|
||||
{
|
||||
const nl_fptype vHigh = m_RP.m_R.m_P() * (1.0 - m_KP);
|
||||
const nl_fptype vHigh = m_RP.m_R.m_P() * (plib::constants<nl_fptype>::one() - m_KP);
|
||||
if (m_CV() > vHigh)
|
||||
{
|
||||
m_RP_Q.push(0, NLTIME_FROM_NS(10)); // R_OFF
|
||||
@ -255,7 +255,7 @@ namespace netlist
|
||||
|
||||
NETLIB_RESET(74123)
|
||||
{
|
||||
m_KP = plib::reciprocal(1.0 + exp(m_K()));
|
||||
m_KP = plib::reciprocal(plib::constants<nl_fptype>::one() + std::exp(m_K()));
|
||||
|
||||
m_RP.reset();
|
||||
m_RN.reset();
|
||||
|
@ -85,7 +85,7 @@ namespace netlist
|
||||
, m_ENQ(*this, "ENQ")
|
||||
, m_RNG(*this, "RNG")
|
||||
, m_FC(*this, "FC")
|
||||
, m_CAP(*this, "CAP", 1e-6)
|
||||
, m_CAP(*this, "CAP", plib::constants<nl_fptype>::cast(1e-6))
|
||||
{
|
||||
register_subalias("GND", m_R_FC.m_N);
|
||||
|
||||
@ -98,8 +98,8 @@ namespace netlist
|
||||
|
||||
NETLIB_RESETI()
|
||||
{
|
||||
m_R_FC.set_R(90000.0);
|
||||
m_R_RNG.set_R(90000.0);
|
||||
m_R_FC.set_R( plib::constants<nl_fptype>::cast(90000.0));
|
||||
m_R_RNG.set_R(plib::constants<nl_fptype>::cast(90000.0));
|
||||
m_clock.reset();
|
||||
}
|
||||
NETLIB_UPDATEI();
|
||||
@ -179,16 +179,16 @@ namespace netlist
|
||||
nl_fptype v_rng = m_RNG();
|
||||
|
||||
/* coefficients */
|
||||
const nl_fptype k1 = 1.9904769024796283E+03;
|
||||
const nl_fptype k2 = 1.2070059213983407E+03;
|
||||
const nl_fptype k3 = 1.3266985579561108E+03;
|
||||
const nl_fptype k4 = -1.5500979825922698E+02;
|
||||
const nl_fptype k5 = 2.8184536266938172E+00;
|
||||
const nl_fptype k6 = -2.3503421582744556E+02;
|
||||
const nl_fptype k7 = -3.3836786704527788E+02;
|
||||
const nl_fptype k8 = -1.3569136703258670E+02;
|
||||
const nl_fptype k9 = 2.9914575453819188E+00;
|
||||
const nl_fptype k10 = 1.6855569086173170E+00;
|
||||
const nl_fptype k1 = plib::constants<nl_fptype>::cast( 1.9904769024796283E+03);
|
||||
const nl_fptype k2 = plib::constants<nl_fptype>::cast( 1.2070059213983407E+03);
|
||||
const nl_fptype k3 = plib::constants<nl_fptype>::cast( 1.3266985579561108E+03);
|
||||
const nl_fptype k4 = plib::constants<nl_fptype>::cast(-1.5500979825922698E+02);
|
||||
const nl_fptype k5 = plib::constants<nl_fptype>::cast( 2.8184536266938172E+00);
|
||||
const nl_fptype k6 = plib::constants<nl_fptype>::cast(-2.3503421582744556E+02);
|
||||
const nl_fptype k7 = plib::constants<nl_fptype>::cast(-3.3836786704527788E+02);
|
||||
const nl_fptype k8 = plib::constants<nl_fptype>::cast(-1.3569136703258670E+02);
|
||||
const nl_fptype k9 = plib::constants<nl_fptype>::cast( 2.9914575453819188E+00);
|
||||
const nl_fptype k10 = plib::constants<nl_fptype>::cast( 1.6855569086173170E+00);
|
||||
|
||||
/* scale due to input resistance */
|
||||
|
||||
@ -212,7 +212,7 @@ namespace netlist
|
||||
|
||||
// FIXME: we need a possibility to remove entries from queue ...
|
||||
// or an exact model ...
|
||||
m_clock.m_inc = netlist_time::from_fp<nl_fptype>(0.5 / freq);
|
||||
m_clock.m_inc = netlist_time::from_fp(plib::constants<nl_fptype>::half() / freq);
|
||||
//m_clock.update();
|
||||
|
||||
//NL_VERBOSE_OUT(("{1} {2} {3} {4}\n", name(), v_freq, v_rng, freq));
|
||||
|
@ -69,9 +69,11 @@ namespace netlist
|
||||
{
|
||||
//m_V0.initial(0.0);
|
||||
//m_RV.do_reset();
|
||||
m_RV.set_G_V_I(plib::constants<nl_fptype>::one() / R_LOW, 0.0, 0.0);
|
||||
m_RV.set_G_V_I(plib::constants<nl_fptype>::one() / plib::constants<nl_fptype>::cast(R_LOW),
|
||||
plib::constants<nl_fptype>::zero(),
|
||||
plib::constants<nl_fptype>::zero());
|
||||
m_inc = netlist_time::from_fp(plib::reciprocal(m_FREQ()));
|
||||
if (m_FREQ() < 24000 || m_FREQ() > 56000)
|
||||
if (m_FREQ() < plib::constants<nl_fptype>::cast(24000) || m_FREQ() > plib::constants<nl_fptype>::cast(56000))
|
||||
log().warning(MW_FREQUENCY_OUTSIDE_OF_SPECS_1(m_FREQ()));
|
||||
|
||||
m_shift = 0x1ffff;
|
||||
@ -81,7 +83,7 @@ namespace netlist
|
||||
NETLIB_UPDATE_PARAM(MM5837_dip)
|
||||
{
|
||||
m_inc = netlist_time::from_fp(plib::reciprocal(m_FREQ()));
|
||||
if (m_FREQ() < 24000 || m_FREQ() > 56000)
|
||||
if (m_FREQ() < plib::constants<nl_fptype>::cast(24000) || m_FREQ() > plib::constants<nl_fptype>::cast(56000))
|
||||
log().warning(MW_FREQUENCY_OUTSIDE_OF_SPECS_1(m_FREQ()));
|
||||
}
|
||||
|
||||
@ -102,7 +104,7 @@ namespace netlist
|
||||
|
||||
if (state != last_state)
|
||||
{
|
||||
const nl_fptype R = state ? R_HIGH : R_LOW;
|
||||
const nl_fptype R = plib::constants<nl_fptype>::cast(state ? R_HIGH : R_LOW);
|
||||
const nl_fptype V = state ? m_VDD() : m_VSS();
|
||||
|
||||
// We only need to update the net first if this is a time stepping net
|
||||
|
@ -140,11 +140,11 @@ namespace netlist
|
||||
m_RDIS.reset();
|
||||
|
||||
/* FIXME make resistances a parameter, properly model other variants */
|
||||
m_R1.set_R(5000);
|
||||
m_R2.set_R(5000);
|
||||
m_R3.set_R(5000);
|
||||
m_ROUT.set_R(20);
|
||||
m_RDIS.set_R(R_OFF);
|
||||
m_R1.set_R(plib::constants<nl_fptype>::cast(5000));
|
||||
m_R2.set_R(plib::constants<nl_fptype>::cast(5000));
|
||||
m_R3.set_R(plib::constants<nl_fptype>::cast(5000));
|
||||
m_ROUT.set_R(plib::constants<nl_fptype>::cast(20));
|
||||
m_RDIS.set_R(plib::constants<nl_fptype>::cast(R_OFF));
|
||||
|
||||
m_last_out = true;
|
||||
}
|
||||
@ -161,9 +161,9 @@ namespace netlist
|
||||
}
|
||||
else
|
||||
{
|
||||
const nl_fptype vt = clamp(m_R2.m_P(), 0.7, 1.4);
|
||||
const nl_fptype vt = clamp(m_R2.m_P(), plib::constants<nl_fptype>::cast(0.7), plib::constants<nl_fptype>::cast(1.4));
|
||||
const bool bthresh = (m_THRES() > vt);
|
||||
const bool btrig = (m_TRIG() > clamp(m_R2.m_N(), 0.7, 1.4));
|
||||
const bool btrig = (m_TRIG() > clamp(m_R2.m_N(), plib::constants<nl_fptype>::cast(0.7), plib::constants<nl_fptype>::cast(1.4)));
|
||||
|
||||
if (!btrig)
|
||||
m_ff = true;
|
||||
@ -177,14 +177,14 @@ namespace netlist
|
||||
{
|
||||
m_RDIS.update();
|
||||
m_OUT.push(m_R3.m_N());
|
||||
m_RDIS.set_R(R_ON);
|
||||
m_RDIS.set_R(plib::constants<nl_fptype>::cast(R_ON));
|
||||
}
|
||||
else if (!m_last_out && out)
|
||||
{
|
||||
m_RDIS.update();
|
||||
// FIXME: Should be delayed by 100ns
|
||||
m_OUT.push(m_R1.m_P());
|
||||
m_RDIS.set_R(R_OFF);
|
||||
m_RDIS.set_R(plib::constants<nl_fptype>::cast(R_OFF));
|
||||
}
|
||||
m_last_reset = reset;
|
||||
m_last_out = out;
|
||||
|
@ -16,8 +16,8 @@ namespace netlist
|
||||
NETLIB_OBJECT_DERIVED(r2r_dac, twoterm)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR_DERIVED(r2r_dac, twoterm)
|
||||
, m_VIN(*this, "VIN", 1.0)
|
||||
, m_R(*this, "R", 1.0)
|
||||
, m_VIN(*this, "VIN", plib::constants<nl_fptype>::one())
|
||||
, m_R(*this, "R", plib::constants<nl_fptype>::one())
|
||||
, m_num(*this, "N", 1)
|
||||
, m_val(*this, "VAL", 1)
|
||||
{
|
||||
@ -44,7 +44,7 @@ namespace netlist
|
||||
nl_fptype V = m_VIN() / static_cast<nl_fptype>(1 << m_num())
|
||||
* static_cast<nl_fptype>(m_val());
|
||||
|
||||
this->set_G_V_I(plib::reciprocal(m_R()), V, 0.0);
|
||||
this->set_G_V_I(plib::reciprocal(m_R()), V, plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
} //namespace analog
|
||||
|
||||
|
@ -85,8 +85,8 @@ namespace netlist
|
||||
m_RVI.reset();
|
||||
m_RVO.reset();
|
||||
m_is_timestep = m_RVO.m_P.net().solver()->has_timestep_devices();
|
||||
m_RVI.set_G_V_I(plib::constants<nl_fptype>::one() / m_model.m_RI, m_model.m_VI, 0.0);
|
||||
m_RVO.set_G_V_I(plib::constants<nl_fptype>::one() / m_model.m_ROL, m_model.m_VOL, 0.0);
|
||||
m_RVI.set_G_V_I(plib::constants<nl_fptype>::one() / m_model.m_RI, m_model.m_VI, plib::constants<nl_fptype>::zero());
|
||||
m_RVO.set_G_V_I(plib::constants<nl_fptype>::one() / m_model.m_ROL, m_model.m_VOL, plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
|
||||
NETLIB_UPDATEI()
|
||||
@ -98,7 +98,7 @@ namespace netlist
|
||||
m_last_state = 0;
|
||||
if (m_is_timestep)
|
||||
m_RVO.update();
|
||||
m_RVO.set_G_V_I(plib::constants<nl_fptype>::one() / m_model.m_ROH, m_model.m_VOH, 0.0);
|
||||
m_RVO.set_G_V_I(plib::constants<nl_fptype>::one() / m_model.m_ROH, m_model.m_VOH, plib::constants<nl_fptype>::zero());
|
||||
m_RVO.solve_later();
|
||||
}
|
||||
}
|
||||
@ -109,7 +109,7 @@ namespace netlist
|
||||
m_last_state = 1;
|
||||
if (m_is_timestep)
|
||||
m_RVO.update();
|
||||
m_RVO.set_G_V_I(plib::constants<nl_fptype>::one() / m_model.m_ROL, m_model.m_VOL, 0.0);
|
||||
m_RVO.set_G_V_I(plib::constants<nl_fptype>::one() / m_model.m_ROL, m_model.m_VOL, plib::constants<nl_fptype>::zero());
|
||||
m_RVO.solve_later();
|
||||
}
|
||||
}
|
||||
|
@ -52,11 +52,11 @@ namespace netlist
|
||||
nl_assert(m_logic_family != nullptr);
|
||||
// FIXME: Variable supply voltage!
|
||||
nl_fptype supply_V = logic_family()->fixed_V();
|
||||
if (supply_V == 0.0) supply_V = 5.0;
|
||||
if (supply_V == plib::constants<nl_fptype>::zero()) supply_V = plib::constants<nl_fptype>::cast(5.0);
|
||||
|
||||
if (m_I.Q_Analog() > logic_family()->high_thresh_V(0.0, supply_V))
|
||||
if (m_I.Q_Analog() > logic_family()->high_thresh_V(plib::constants<nl_fptype>::zero(), supply_V))
|
||||
out().push(1, netlist_time::quantum());
|
||||
else if (m_I.Q_Analog() < logic_family()->low_thresh_V(0.0, supply_V))
|
||||
else if (m_I.Q_Analog() < logic_family()->low_thresh_V(plib::constants<nl_fptype>::zero(), supply_V))
|
||||
out().push(0, netlist_time::quantum());
|
||||
else
|
||||
{
|
||||
@ -112,7 +112,7 @@ namespace netlist
|
||||
//FIXME: Use power terminals and change info to warning or error
|
||||
if (!f)
|
||||
{
|
||||
if (logic_family()->fixed_V() == 0.0)
|
||||
if (logic_family()->fixed_V() == plib::constants<nl_fptype>::zero())
|
||||
log().error(MI_NO_POWER_TERMINALS_ON_DEVICE_1(state().setup().de_alias(out_proxied->device().name())));
|
||||
else
|
||||
log().info(MI_NO_POWER_TERMINALS_ON_DEVICE_1(state().setup().de_alias(out_proxied->device().name())));
|
||||
@ -148,7 +148,9 @@ namespace netlist
|
||||
{
|
||||
// FIXME: Variable voltage
|
||||
nl_fptype supply_V = logic_family()->fixed_V();
|
||||
if (supply_V == 0.0) supply_V = 5.0;
|
||||
// FIXME: comparison to zero
|
||||
if (supply_V == plib::constants<nl_fptype>::zero())
|
||||
supply_V = plib::constants<nl_fptype>::cast(5.0);
|
||||
|
||||
//m_Q.initial(0.0);
|
||||
m_last_state = -1;
|
||||
@ -160,9 +162,10 @@ namespace netlist
|
||||
m_VCCHack->initial(supply_V);
|
||||
m_is_timestep = m_RN.m_P.net().solver()->has_timestep_devices();
|
||||
m_RN.set_G_V_I(plib::constants<nl_fptype>::one() / logic_family()->R_low(),
|
||||
logic_family()->low_offset_V(), 0.0);
|
||||
logic_family()->low_offset_V(), plib::constants<nl_fptype>::zero());
|
||||
m_RP.set_G_V_I(G_OFF,
|
||||
0.0, 0.0);
|
||||
plib::constants<nl_fptype>::zero(),
|
||||
plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
|
||||
NETLIB_UPDATE(d_to_a_proxy)
|
||||
@ -178,16 +181,18 @@ namespace netlist
|
||||
if (state)
|
||||
{
|
||||
m_RN.set_G_V_I(G_OFF,
|
||||
0.0, 0.0);
|
||||
plib::constants<nl_fptype>::zero(),
|
||||
plib::constants<nl_fptype>::zero());
|
||||
m_RP.set_G_V_I(plib::constants<nl_fptype>::one() / logic_family()->R_high(),
|
||||
logic_family()->high_offset_V(), 0.0);
|
||||
logic_family()->high_offset_V(), plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RN.set_G_V_I(plib::constants<nl_fptype>::one() / logic_family()->R_low(),
|
||||
logic_family()->low_offset_V(), 0.0);
|
||||
logic_family()->low_offset_V(), plib::constants<nl_fptype>::zero());
|
||||
m_RP.set_G_V_I(G_OFF,
|
||||
0.0, 0.0);
|
||||
plib::constants<nl_fptype>::zero(),
|
||||
plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
m_RN.solve_later(); // RN, RP are connected ...
|
||||
m_last_state = state;
|
||||
|
@ -104,7 +104,7 @@ namespace netlist
|
||||
|
||||
private:
|
||||
|
||||
static constexpr const nl_fptype G_OFF = 1e-9;
|
||||
static constexpr const nl_fptype G_OFF = plib::constants<nl_fptype>::cast(1e-9);
|
||||
|
||||
plib::unique_ptr<analog_output_t> m_GNDHack; // FIXME: Long term, we need to connect proxy gnd to device gnd
|
||||
plib::unique_ptr<analog_output_t> m_VCCHack; // FIXME: Long term, we need to connect proxy gnd to device gnd
|
||||
|
@ -52,9 +52,9 @@ namespace devices
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(mainclock)
|
||||
, m_Q(*this, "Q")
|
||||
, m_freq(*this, "FREQ", 7159000.0 * 5)
|
||||
, m_freq(*this, "FREQ", plib::constants<nl_fptype>::cast(7159000.0 * 5))
|
||||
{
|
||||
m_inc = netlist_time::from_fp<decltype(m_freq())>(1.0 / (m_freq()*2.0));
|
||||
m_inc = netlist_time::from_fp(plib::reciprocal(m_freq()*plib::constants<nl_fptype>::two()));
|
||||
}
|
||||
|
||||
NETLIB_RESETI()
|
||||
@ -64,7 +64,7 @@ namespace devices
|
||||
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
m_inc = netlist_time::from_fp<decltype(m_freq())>(1.0 / (m_freq()*2.0));
|
||||
m_inc = netlist_time::from_fp(plib::reciprocal(m_freq()*plib::constants<nl_fptype>::two()));
|
||||
}
|
||||
|
||||
NETLIB_UPDATEI()
|
||||
@ -91,9 +91,9 @@ namespace devices
|
||||
NETLIB_CONSTRUCTOR(clock)
|
||||
, m_feedback(*this, "FB")
|
||||
, m_Q(*this, "Q")
|
||||
, m_freq(*this, "FREQ", 7159000.0 * 5.0)
|
||||
, m_freq(*this, "FREQ", plib::constants<nl_fptype>::cast(7159000.0 * 5.0))
|
||||
{
|
||||
m_inc = netlist_time::from_fp<decltype(m_freq())>(1.0 / (m_freq()*2.0));
|
||||
m_inc = netlist_time::from_fp(plib::reciprocal(m_freq()*plib::constants<nl_fptype>::two()));
|
||||
|
||||
connect(m_feedback, m_Q);
|
||||
}
|
||||
@ -101,7 +101,7 @@ namespace devices
|
||||
|
||||
NETLIB_UPDATE_PARAMI()
|
||||
{
|
||||
m_inc = netlist_time::from_fp<decltype(m_freq())>(1.0 / (m_freq() * 2.0));
|
||||
m_inc = netlist_time::from_fp(plib::reciprocal(m_freq()*plib::constants<nl_fptype>::two()));
|
||||
}
|
||||
|
||||
NETLIB_UPDATEI()
|
||||
@ -128,7 +128,7 @@ namespace devices
|
||||
, m_Q(*this, "Q")
|
||||
, m_func(*this,"FUNC", "")
|
||||
, m_compiled(this->name() + ".FUNCC", this, this->state().run_state_manager())
|
||||
, m_funcparam({0.0})
|
||||
, m_funcparam({plib::constants<nl_fptype>::zero()})
|
||||
{
|
||||
if (m_func() != "")
|
||||
m_compiled.compile(std::vector<pstring>({{pstring("T")}}), m_func());
|
||||
@ -160,19 +160,19 @@ namespace devices
|
||||
NETLIB_OBJECT(extclock)
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(extclock)
|
||||
, m_freq(*this, "FREQ", 7159000.0 * 5.0)
|
||||
, m_freq(*this, "FREQ", plib::constants<nl_fptype>::cast(7159000.0 * 5.0))
|
||||
, m_pattern(*this, "PATTERN", "1,1")
|
||||
, m_offset(*this, "OFFSET", 0.0)
|
||||
, m_offset(*this, "OFFSET", plib::constants<nl_fptype>::zero())
|
||||
, m_feedback(*this, "FB")
|
||||
, m_Q(*this, "Q")
|
||||
, m_cnt(*this, "m_cnt", 0)
|
||||
, m_off(*this, "m_off", netlist_time::zero())
|
||||
{
|
||||
m_inc[0] = netlist_time::from_fp<decltype(m_freq())>(1.0 / (m_freq() * 2.0));
|
||||
m_inc[0] = netlist_time::from_fp(plib::reciprocal(m_freq()*plib::constants<nl_fptype>::two()));
|
||||
|
||||
connect(m_feedback, m_Q);
|
||||
|
||||
netlist_time base = netlist_time::from_fp<decltype(m_freq())>(1.0 / (m_freq()*2.0));
|
||||
netlist_time base = netlist_time::from_fp(plib::reciprocal(m_freq()*plib::constants<nl_fptype>::two()));
|
||||
std::vector<pstring> pat(plib::psplit(m_pattern(),","));
|
||||
m_off = netlist_time::from_fp(m_offset());
|
||||
|
||||
@ -250,12 +250,12 @@ namespace devices
|
||||
{
|
||||
NETLIB_CONSTRUCTOR(analog_input)
|
||||
, m_Q(*this, "Q")
|
||||
, m_IN(*this, "IN", 0.0)
|
||||
, m_IN(*this, "IN", plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
}
|
||||
|
||||
NETLIB_UPDATEI() { }
|
||||
NETLIB_RESETI() { m_Q.initial(0.0); }
|
||||
NETLIB_RESETI() { m_Q.initial(plib::constants<nl_fptype>::zero()); }
|
||||
NETLIB_UPDATE_PARAMI() { m_Q.push(m_IN()); }
|
||||
|
||||
private:
|
||||
@ -275,7 +275,7 @@ namespace devices
|
||||
}
|
||||
NETLIB_UPDATEI()
|
||||
{
|
||||
m_Q.push(0.0);
|
||||
m_Q.push(plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
NETLIB_RESETI() { }
|
||||
protected:
|
||||
@ -316,8 +316,8 @@ namespace devices
|
||||
, m_ROUT(*this, "m_ROUT", true)
|
||||
, m_I(*this, "_I")
|
||||
, m_Q(*this, "_Q")
|
||||
, m_p_RIN(*this, "RIN", 1.0e6)
|
||||
, m_p_ROUT(*this, "ROUT", 50.0)
|
||||
, m_p_RIN(*this, "RIN", plib::constants<nl_fptype>::cast(1.0e6))
|
||||
, m_p_ROUT(*this, "ROUT", plib::constants<nl_fptype>::cast(50.0))
|
||||
|
||||
{
|
||||
register_subalias("I", m_RIN.m_P);
|
||||
@ -371,7 +371,7 @@ namespace devices
|
||||
pstring n = plib::pfmt("A{1}")(i);
|
||||
m_I.push_back(pool().make_unique<analog_input_t>(*this, n));
|
||||
inps.push_back(n);
|
||||
m_vals.push_back(0.0);
|
||||
m_vals.push_back(plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
m_compiled.compile(inps, m_func());
|
||||
}
|
||||
@ -402,8 +402,8 @@ namespace devices
|
||||
NETLIB_CONSTRUCTOR(res_sw)
|
||||
, m_R(*this, "_R")
|
||||
, m_I(*this, "I")
|
||||
, m_RON(*this, "RON", 1.0)
|
||||
, m_ROFF(*this, "ROFF", 1.0E20)
|
||||
, m_RON(*this, "RON", plib::constants<nl_fptype>::one())
|
||||
, m_ROFF(*this, "ROFF", plib::constants<nl_fptype>::cast(1.0E20))
|
||||
, m_last_state(*this, "m_last_state", 0)
|
||||
{
|
||||
register_subalias("1", m_R.m_P);
|
||||
|
@ -40,14 +40,14 @@ namespace netlist
|
||||
public:
|
||||
logic_family_ttl_t() : logic_family_desc_t()
|
||||
{
|
||||
m_fixed_V = 5.0;
|
||||
m_low_thresh_PCNT = 0.8 / 5.0;
|
||||
m_high_thresh_PCNT = 2.0 / 5.0;
|
||||
m_fixed_V = plib::constants<nl_fptype>::cast(5.0);
|
||||
m_low_thresh_PCNT = plib::constants<nl_fptype>::cast(0.8 / 5.0);
|
||||
m_high_thresh_PCNT = plib::constants<nl_fptype>::cast(2.0 / 5.0);
|
||||
// m_low_V - these depend on sinked/sourced current. Values should be suitable for typical applications.
|
||||
m_low_VO = 0.1;
|
||||
m_high_VO = 1.0; // 4.0
|
||||
m_R_low = 1.0;
|
||||
m_R_high = 130.0;
|
||||
m_low_VO = plib::constants<nl_fptype>::cast(0.1);
|
||||
m_high_VO = plib::constants<nl_fptype>::cast(1.0); // 4.0
|
||||
m_R_low = plib::constants<nl_fptype>::cast(1.0);
|
||||
m_R_high = plib::constants<nl_fptype>::cast(130.0);
|
||||
}
|
||||
unique_pool_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
|
||||
unique_pool_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
|
||||
@ -67,14 +67,14 @@ namespace netlist
|
||||
public:
|
||||
logic_family_cd4xxx_t() : logic_family_desc_t()
|
||||
{
|
||||
m_fixed_V = 0.0;
|
||||
m_low_thresh_PCNT = 1.5 / 5.0;
|
||||
m_high_thresh_PCNT = 3.5 / 5.0;
|
||||
m_fixed_V = plib::constants<nl_fptype>::cast(0.0);
|
||||
m_low_thresh_PCNT = plib::constants<nl_fptype>::cast(1.5 / 5.0);
|
||||
m_high_thresh_PCNT = plib::constants<nl_fptype>::cast(3.5 / 5.0);
|
||||
// m_low_V - these depend on sinked/sourced current. Values should be suitable for typical applications.
|
||||
m_low_VO = 0.05;
|
||||
m_high_VO = 0.05; // 4.95
|
||||
m_R_low = 10.0;
|
||||
m_R_high = 10.0;
|
||||
m_low_VO = plib::constants<nl_fptype>::cast(0.05);
|
||||
m_high_VO = plib::constants<nl_fptype>::cast(0.05); // 4.95
|
||||
m_R_low = plib::constants<nl_fptype>::cast(10.0);
|
||||
m_R_high = plib::constants<nl_fptype>::cast(10.0);
|
||||
}
|
||||
unique_pool_ptr<devices::nld_base_d_to_a_proxy> create_d_a_proxy(netlist_state_t &anetlist, const pstring &name, logic_output_t *proxied) const override;
|
||||
unique_pool_ptr<devices::nld_base_a_to_d_proxy> create_a_d_proxy(netlist_state_t &anetlist, const pstring &name, logic_input_t *proxied) const override;
|
||||
@ -669,7 +669,7 @@ namespace netlist
|
||||
auto *p = dynamic_cast<analog_net_t *>(this);
|
||||
|
||||
if (p != nullptr)
|
||||
p->m_cur_Analog = 0.0;
|
||||
p->m_cur_Analog = plib::constants<nl_fptype>::zero();
|
||||
|
||||
/* rebuild m_list and reset terminals to active or analog out state */
|
||||
|
||||
@ -727,7 +727,7 @@ namespace netlist
|
||||
|
||||
analog_net_t::analog_net_t(netlist_state_t &nl, const pstring &aname, detail::core_terminal_t *mr)
|
||||
: net_t(nl, aname, mr)
|
||||
, m_cur_Analog(*this, "m_cur_Analog", 0.0)
|
||||
, m_cur_Analog(*this, "m_cur_Analog", plib::constants<nl_fptype>::zero())
|
||||
, m_solver(nullptr)
|
||||
{
|
||||
}
|
||||
|
@ -764,12 +764,12 @@ namespace netlist
|
||||
|
||||
void set_conductivity(const nl_fptype G) noexcept
|
||||
{
|
||||
set_go_gt_I(-G, G, 0.0);
|
||||
set_go_gt_I(-G, G, plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
|
||||
void set_go_gt(const nl_fptype GO, const nl_fptype GT) noexcept
|
||||
{
|
||||
set_go_gt_I(GO, GT, 0.0);
|
||||
set_go_gt_I(GO, GT, plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
|
||||
void set_go_gt_I(const nl_fptype GO, const nl_fptype GT, const nl_fptype I) noexcept
|
||||
|
@ -128,6 +128,7 @@ namespace netlist
|
||||
static inline constexpr long double TIMESTEP_MINDIV() noexcept { return 1e-60L; }
|
||||
|
||||
static inline constexpr const char * name() noexcept { return "long double"; }
|
||||
static inline constexpr const char * suffix() noexcept { return "L"; }
|
||||
};
|
||||
|
||||
/*! Specific constants for double floating point type
|
||||
@ -142,6 +143,7 @@ namespace netlist
|
||||
static inline constexpr double TIMESTEP_MINDIV() noexcept { return 1e-60; }
|
||||
|
||||
static inline constexpr const char * name() noexcept { return "double"; }
|
||||
static inline constexpr const char * suffix() noexcept { return ""; }
|
||||
};
|
||||
|
||||
/*! Specific constants for float floating point type
|
||||
@ -156,6 +158,7 @@ namespace netlist
|
||||
static inline constexpr float TIMESTEP_MINDIV() noexcept { return 1e-8f; }
|
||||
|
||||
static inline constexpr const char * name() noexcept { return "float"; }
|
||||
static inline constexpr const char * suffix() noexcept { return "f"; }
|
||||
};
|
||||
} // namespace netlist
|
||||
|
||||
|
@ -413,7 +413,15 @@ void parser_t::device(const pstring &dev_type)
|
||||
nl_fptype parser_t::eval_param(const token_t &tok)
|
||||
{
|
||||
static std::array<pstring, 7> macs = {"", "RES_R", "RES_K", "RES_M", "CAP_U", "CAP_N", "CAP_P"};
|
||||
static std::array<nl_fptype, 7> facs = {1, 1, 1e3, 1e6, 1e-6, 1e-9, 1e-12};
|
||||
static std::array<nl_fptype, 7> facs = {
|
||||
plib::constants<nl_fptype>::cast(1.0),
|
||||
plib::constants<nl_fptype>::cast(1.0),
|
||||
plib::constants<nl_fptype>::cast(1e3),
|
||||
plib::constants<nl_fptype>::cast(1e6),
|
||||
plib::constants<nl_fptype>::cast(1e-6),
|
||||
plib::constants<nl_fptype>::cast(1e-9),
|
||||
plib::constants<nl_fptype>::cast(1e-12)
|
||||
};
|
||||
std::size_t f=0;
|
||||
nl_fptype ret(0);
|
||||
|
||||
@ -423,7 +431,7 @@ nl_fptype parser_t::eval_param(const token_t &tok)
|
||||
if (f>0)
|
||||
{
|
||||
require_token(m_tok_param_left);
|
||||
ret = get_number_double();
|
||||
ret = static_cast<nl_fptype>(get_number_double());
|
||||
require_token(m_tok_param_right);
|
||||
}
|
||||
else
|
||||
|
@ -119,9 +119,10 @@ namespace netlist
|
||||
m_namespace_stack.pop();
|
||||
}
|
||||
|
||||
void nlparse_t::register_param(const pstring ¶m, const nl_fptype value)
|
||||
void nlparse_t::register_param_x(const pstring ¶m, const nl_fptype value)
|
||||
{
|
||||
if (std::abs(value - std::floor(value)) > 1e-30 || std::abs(value) > 1e9)
|
||||
if (std::abs(value - std::floor(value)) > plib::constants<nl_fptype>::cast(1e-30)
|
||||
|| std::abs(value) > plib::constants<nl_fptype>::cast(1e9))
|
||||
register_param(param, plib::pfmt("{1:.9}").e(value));
|
||||
else
|
||||
register_param(param, plib::pfmt("{1}")(static_cast<long>(value)));
|
||||
@ -945,15 +946,15 @@ nl_fptype models_t::value(const pstring &model, const pstring &entity)
|
||||
auto p = std::next(tmp.begin(), static_cast<pstring::difference_type>(tmp.size() - 1));
|
||||
switch (*p)
|
||||
{
|
||||
case 'M': factor = 1e6; break;
|
||||
case 'M': factor = plib::constants<nl_fptype>::cast(1e6); break;
|
||||
case 'k':
|
||||
case 'K': factor = 1e3; break;
|
||||
case 'm': factor = 1e-3; break;
|
||||
case 'u': factor = 1e-6; break;
|
||||
case 'n': factor = 1e-9; break;
|
||||
case 'p': factor = 1e-12; break;
|
||||
case 'f': factor = 1e-15; break;
|
||||
case 'a': factor = 1e-18; break;
|
||||
case 'K': factor = plib::constants<nl_fptype>::cast(1e3); break;
|
||||
case 'm': factor = plib::constants<nl_fptype>::cast(1e-3); break;
|
||||
case 'u': factor = plib::constants<nl_fptype>::cast(1e-6); break;
|
||||
case 'n': factor = plib::constants<nl_fptype>::cast(1e-9); break;
|
||||
case 'p': factor = plib::constants<nl_fptype>::cast(1e-12); break;
|
||||
case 'f': factor = plib::constants<nl_fptype>::cast(1e-15); break;
|
||||
case 'a': factor = plib::constants<nl_fptype>::cast(1e-18); break;
|
||||
default:
|
||||
if (*p < '0' || *p > '9')
|
||||
throw nl_exception(MF_UNKNOWN_NUMBER_FACTOR_IN_1(entity));
|
||||
@ -1125,9 +1126,10 @@ void setup_t::prepare_to_run()
|
||||
//FIXME: check for errors ...
|
||||
bool err(false);
|
||||
auto v = plib::pstonum_ne<nl_fptype>(p->second, err);
|
||||
if (err || std::abs(v - std::floor(v)) > 1e-6 )
|
||||
if (err || std::abs(v - std::floor(v)) > plib::constants<nl_fptype>::cast(1e-6) )
|
||||
log().fatal(MF_HND_VAL_NOT_SUPPORTED(p->second));
|
||||
d.second->set_hint_deactivate(v == 0.0);
|
||||
// FIXME comparison with zero
|
||||
d.second->set_hint_deactivate(v == plib::constants<nl_fptype>::zero());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -244,7 +244,16 @@ namespace netlist
|
||||
void register_link(const pstring &sin, const pstring &sout);
|
||||
void register_link_arr(const pstring &terms);
|
||||
void register_param(const pstring ¶m, const pstring &value);
|
||||
void register_param(const pstring ¶m, const nl_fptype value);
|
||||
|
||||
// FIXME: quick hack
|
||||
void register_param_x(const pstring ¶m, const nl_fptype value);
|
||||
template <typename T>
|
||||
typename std::enable_if<std::is_floating_point<T>::value || std::is_integral<T>::value>::type
|
||||
register_param(const pstring ¶m, T value)
|
||||
{
|
||||
register_param_x(param, static_cast<nl_fptype>(value));
|
||||
}
|
||||
|
||||
void register_lib_entry(const pstring &name, const pstring &sourcefile);
|
||||
void register_frontier(const pstring &attach, const nl_fptype r_IN, const nl_fptype r_OUT);
|
||||
|
||||
|
@ -216,8 +216,9 @@ namespace plib {
|
||||
type total() const noexcept { return m_time; }
|
||||
ctype count() const noexcept { return m_count; }
|
||||
|
||||
double as_seconds() const noexcept { return static_cast<double>(total())
|
||||
/ static_cast<double>(T::per_second()); }
|
||||
template <typename S>
|
||||
S as_seconds() const noexcept { return static_cast<S>(total())
|
||||
/ static_cast<S>(T::per_second()); }
|
||||
|
||||
guard_t guard() noexcept { return guard_t(*this); }
|
||||
private:
|
||||
@ -247,7 +248,8 @@ namespace plib {
|
||||
constexpr type average() const noexcept { return 0; }
|
||||
constexpr type total() const noexcept { return 0; }
|
||||
constexpr ctype count() const noexcept { return 0; }
|
||||
constexpr double as_seconds() const noexcept { return 0.0; }
|
||||
template <typename S>
|
||||
S as_seconds() const noexcept { return static_cast<S>(0.0); }
|
||||
constexpr static bool enabled = false;
|
||||
guard_t guard() { return guard_t(); }
|
||||
};
|
||||
|
@ -195,9 +195,9 @@ namespace plib {
|
||||
template <typename NT>
|
||||
NT pfunction<NT>::evaluate(const std::vector<NT> &values) noexcept
|
||||
{
|
||||
std::array<NT, 20> stack = { 0 };
|
||||
std::array<NT, 20> stack = { plib::constants<NT>::zero() };
|
||||
unsigned ptr = 0;
|
||||
stack[0] = 0.0;
|
||||
stack[0] = plib::constants<NT>::zero();
|
||||
for (auto &rc : m_precompiled)
|
||||
{
|
||||
switch (rc.m_cmd)
|
||||
@ -226,5 +226,6 @@ namespace plib {
|
||||
|
||||
template class pfunction<float>;
|
||||
template class pfunction<double>;
|
||||
template class pfunction<long double>;
|
||||
|
||||
} // namespace plib
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "pstate.h"
|
||||
#include "pstring.h"
|
||||
#include "putil.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -42,7 +43,7 @@ namespace plib {
|
||||
};
|
||||
struct rpn_inst
|
||||
{
|
||||
rpn_inst() : m_cmd(ADD), m_param(0.0) { }
|
||||
rpn_inst() : m_cmd(ADD), m_param(plib::constants<NT>::zero()) { }
|
||||
rpn_cmd m_cmd;
|
||||
NT m_param;
|
||||
};
|
||||
@ -116,6 +117,7 @@ namespace plib {
|
||||
|
||||
extern template class pfunction<float>;
|
||||
extern template class pfunction<double>;
|
||||
extern template class pfunction<long double>;
|
||||
|
||||
} // namespace plib
|
||||
|
||||
|
@ -123,7 +123,7 @@ namespace plib
|
||||
|
||||
template <typename FT>
|
||||
static constexpr const typename std::enable_if<std::is_floating_point<FT>::value, ptime>::type
|
||||
from_fp(const FT t) noexcept { return ptime(static_cast<internal_type>(std::floor(t * static_cast<FT>(RES) + 0.5)), RES); }
|
||||
from_fp(const FT t) noexcept { return ptime(static_cast<internal_type>(std::floor(t * static_cast<FT>(RES) + static_cast<FT>(0.5))), RES); }
|
||||
|
||||
static constexpr const ptime from_double(const double t) noexcept
|
||||
{ return from_fp<double>(t); }
|
||||
|
@ -221,10 +221,13 @@ namespace plib
|
||||
struct constants
|
||||
{
|
||||
static inline constexpr T zero() noexcept { return static_cast<T>(0); }
|
||||
static inline constexpr T half() noexcept { return static_cast<T>(0.5); }
|
||||
static inline constexpr T one() noexcept { return static_cast<T>(1); }
|
||||
static inline constexpr T two() noexcept { return static_cast<T>(2); }
|
||||
static inline constexpr T sqrt2() noexcept { return static_cast<T>(1.414213562373095048801688724209); }
|
||||
static inline constexpr T pi() noexcept { return static_cast<T>(3.14159265358979323846264338327950); }
|
||||
static inline constexpr T three() noexcept { return static_cast<T>(3); }
|
||||
static inline constexpr T four() noexcept { return static_cast<T>(4); }
|
||||
static inline constexpr T sqrt2() noexcept { return static_cast<T>(1.414213562373095048801688724209L); }
|
||||
static inline constexpr T pi() noexcept { return static_cast<T>(3.14159265358979323846264338327950L); }
|
||||
|
||||
/*!
|
||||
* \brief Electric constant of vacuum
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
opt_dir(*this, "d", "dir", "", "output directory for the generated files"),
|
||||
|
||||
opt_grp4(*this, "Options for run command", "These options are only used by the run command."),
|
||||
opt_ttr (*this, "t", "time_to_run", 1.0, "time to run the emulation (seconds)\n\n abc def\n\n xyz"),
|
||||
opt_ttr (*this, "t", "time_to_run", 1, "time to run the emulation (seconds)\n\n abc def\n\n xyz"),
|
||||
opt_stats(*this, "s", "statistics", "gather runtime statistics"),
|
||||
opt_logs(*this, "l", "log" , "define terminal to log. This option may be specified repeatedly."),
|
||||
opt_inp(*this, "i", "input", "", "input file to process (default is none)"),
|
||||
@ -311,7 +311,7 @@ void netlist_tool_callbacks_t::vlog(const plib::plog_level &l, const pstring &ls
|
||||
struct input_t
|
||||
{
|
||||
input_t(const netlist::setup_t &setup, const pstring &line)
|
||||
: m_value(0.0)
|
||||
: m_value(plib::constants<nl_fptype>::zero())
|
||||
{
|
||||
std::array<char, 400> buf; // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
double t(0);
|
||||
@ -402,7 +402,7 @@ void tool_app_t::run()
|
||||
}
|
||||
|
||||
|
||||
pout("startup time ==> {1:5.3f}\n", t.as_seconds() );
|
||||
pout("startup time ==> {1:5.3f}\n", t.as_seconds<nl_fptype>() );
|
||||
|
||||
t.reset();
|
||||
|
||||
@ -462,10 +462,10 @@ void tool_app_t::run()
|
||||
nt.stop();
|
||||
}
|
||||
|
||||
nl_fptype emutime = t.as_seconds();
|
||||
auto emutime(t.as_seconds<nl_fptype>());
|
||||
pout("{1:f} seconds emulation took {2:f} real time ==> {3:5.2f}%\n",
|
||||
(ttr - nlt).as_double(), emutime,
|
||||
(ttr - nlt).as_double() / emutime * 100.0);
|
||||
(ttr - nlt).as_fp<nl_fptype>(), emutime,
|
||||
(ttr - nlt).as_fp<nl_fptype>() / emutime * plib::constants<nl_fptype>::cast(100.0));
|
||||
}
|
||||
|
||||
void tool_app_t::validate()
|
||||
|
@ -501,7 +501,7 @@ namespace solver
|
||||
|
||||
std::vector<bool> touched(1024, false); // FIXME!
|
||||
|
||||
nl_fptype weight = 0.0;
|
||||
nl_fptype weight = plib::constants<nl_fptype>::zero();
|
||||
auto &term = m_terms[row];
|
||||
for (std::size_t i = 0; i < term.count(); i++)
|
||||
{
|
||||
@ -560,7 +560,7 @@ namespace solver
|
||||
this->m_stat_calculations,
|
||||
static_cast<nl_fptype>(this->m_stat_calculations) / this->exec().time().as_fp<nl_fptype>(),
|
||||
this->m_iterative_fail,
|
||||
100.0 * static_cast<nl_fptype>(this->m_iterative_fail)
|
||||
plib::constants<nl_fptype>::cast(100.0) * static_cast<nl_fptype>(this->m_iterative_fail)
|
||||
/ static_cast<nl_fptype>(this->m_stat_calculations),
|
||||
static_cast<nl_fptype>(this->m_iterative_total) / static_cast<nl_fptype>(this->m_stat_calculations));
|
||||
}
|
||||
|
@ -49,26 +49,29 @@ namespace solver
|
||||
struct solver_parameters_t
|
||||
{
|
||||
solver_parameters_t(device_t &parent)
|
||||
: m_freq(parent, "FREQ", 48000.0)
|
||||
: m_freq(parent, "FREQ", plib::constants<nl_fptype>::cast(48000.0))
|
||||
|
||||
/* iteration parameters */
|
||||
, m_gs_sor(parent, "SOR_FACTOR", 1.059)
|
||||
, m_method(parent, "METHOD", matrix_type_e::MAT_CR)
|
||||
, m_fp_type(parent, "FPTYPE", matrix_fp_type_e::DOUBLE)
|
||||
, m_accuracy(parent, "ACCURACY", 1e-7)
|
||||
, m_gs_loops(parent, "GS_LOOPS", 9) // Gauss-Seidel loops
|
||||
, m_gs_sor(parent, "SOR_FACTOR", plib::constants<nl_fptype>::cast(1.059))
|
||||
, m_method(parent, "METHOD", matrix_type_e::MAT_CR)
|
||||
, m_fp_type(parent, "FPTYPE", matrix_fp_type_e::DOUBLE)
|
||||
, m_reltol(parent, "RELTOL", plib::constants<nl_fptype>::cast(1e-3)) ///< SPICE RELTOL parameter
|
||||
, m_vntol(parent, "VNTOL", plib::constants<nl_fptype>::cast(1e-6)) ///< SPICE VNTOL parameter
|
||||
, m_accuracy(parent, "ACCURACY", plib::constants<nl_fptype>::cast(1e-7)) ///< Iterative solver accuracy
|
||||
, m_nr_loops(parent, "NR_LOOPS", 250) ///< Maximum number of Newton-Raphson loops
|
||||
, m_gs_loops(parent, "GS_LOOPS", 9) ///< Maximum number of Gauss-Seidel loops
|
||||
|
||||
/* general parameters */
|
||||
, m_gmin(parent, "GMIN", 1e-9)
|
||||
, m_pivot(parent, "PIVOT", false) // use pivoting - on supported solvers
|
||||
, m_nr_loops(parent, "NR_LOOPS", 250) // Newton-Raphson loops
|
||||
, m_nr_recalc_delay(parent, "NR_RECALC_DELAY", netlist_time::quantum().as_fp<nl_fptype>()) // Delay to next solve attempt if nr loops exceeded
|
||||
, m_gmin(parent, "GMIN", plib::constants<nl_fptype>::cast(1e-9))
|
||||
, m_pivot(parent, "PIVOT", false) ///< use pivoting on supported solvers
|
||||
, m_nr_recalc_delay(parent, "NR_RECALC_DELAY",
|
||||
netlist_time::quantum().as_fp<nl_fptype>()) ///< Delay to next solve attempt if nr loops exceeded
|
||||
, m_parallel(parent, "PARALLEL", 0)
|
||||
|
||||
/* automatic time step */
|
||||
, m_dynamic_ts(parent, "DYNAMIC_TS", false)
|
||||
, m_dynamic_lte(parent, "DYNAMIC_LTE", 1e-5) // diff/timestep
|
||||
, m_dynamic_min_ts(parent, "DYNAMIC_MIN_TIMESTEP", 1e-6) // nl_fptype timestep resolution
|
||||
, m_dynamic_ts(parent, "DYNAMIC_TS", false) ///< Use dynamic time stepping
|
||||
, m_dynamic_lte(parent, "DYNAMIC_LTE", plib::constants<nl_fptype>::cast(1e-5)) ///< dynamic time stepping slope
|
||||
, m_dynamic_min_ts(parent, "DYNAMIC_MIN_TIMESTEP", plib::constants<nl_fptype>::cast(1e-6)) ///< smallest time step allowed
|
||||
|
||||
/* matrix sorting */
|
||||
, m_sort_type(parent, "SORT_TYPE", matrix_sort_type_e::PREFER_IDENTITY_TOP_LEFT)
|
||||
@ -95,11 +98,13 @@ namespace solver
|
||||
param_fp_t m_gs_sor;
|
||||
param_enum_t<matrix_type_e> m_method;
|
||||
param_enum_t<matrix_fp_type_e> m_fp_type;
|
||||
param_fp_t m_reltol;
|
||||
param_fp_t m_vntol;
|
||||
param_fp_t m_accuracy;
|
||||
param_num_t<std::size_t> m_nr_loops;
|
||||
param_num_t<std::size_t> m_gs_loops;
|
||||
param_fp_t m_gmin;
|
||||
param_logic_t m_pivot;
|
||||
param_num_t<std::size_t> m_nr_loops;
|
||||
param_fp_t m_nr_recalc_delay;
|
||||
param_int_t m_parallel;
|
||||
param_logic_t m_dynamic_ts;
|
||||
@ -229,31 +234,6 @@ namespace solver
|
||||
return max_rail;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void store(const T & V)
|
||||
{
|
||||
const std::size_t iN = this->m_terms.size();
|
||||
for (std::size_t i = 0; i < iN; i++)
|
||||
this->m_terms[i].setV(V[i]);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
auto delta(const T & V) -> typename std::decay<decltype(V[0])>::type
|
||||
{
|
||||
/* NOTE: Ideally we should also include currents (RHS) here. This would
|
||||
* need a reevaluation of the right hand side after voltages have been updated
|
||||
* and thus belong into a different calculation. This applies to all solvers.
|
||||
*/
|
||||
|
||||
const std::size_t iN = this->m_terms.size();
|
||||
using vtype = typename std::decay<decltype(V[0])>::type;
|
||||
vtype cerr = 0;
|
||||
for (std::size_t i = 0; i < iN; i++)
|
||||
cerr = std::max(cerr, std::abs(V[i] - this->m_terms[i].getV<vtype>()));
|
||||
return cerr;
|
||||
}
|
||||
|
||||
void set_pointers()
|
||||
{
|
||||
const std::size_t iN = this->m_terms.size();
|
||||
@ -392,6 +372,8 @@ namespace solver
|
||||
const solver_parameters_t *params, const std::size_t size)
|
||||
: matrix_solver_t(anetlist, name, nets, params)
|
||||
, m_dim(size)
|
||||
, m_new_V(size)
|
||||
, m_RHS(size)
|
||||
, m_mat_ptr(size, this->max_railstart() + 1)
|
||||
, m_last_V(size, plib::constants<nl_fptype>::zero())
|
||||
, m_DD_n_m_1(size, plib::constants<nl_fptype>::zero())
|
||||
@ -413,8 +395,15 @@ namespace solver
|
||||
static constexpr const std::size_t SIZEABS = plib::parray<FT, SIZE>::SIZEABS();
|
||||
static constexpr const std::size_t m_pitch_ABS = (((SIZEABS + 0) + 7) / 8) * 8;
|
||||
|
||||
PALIGNAS_VECTOROPT()
|
||||
plib::parray<FT, SIZE> m_new_V;
|
||||
PALIGNAS_VECTOROPT()
|
||||
plib::parray<FT, SIZE> m_RHS;
|
||||
|
||||
PALIGNAS_VECTOROPT()
|
||||
plib::parray2D<float_type *, SIZE, 0> m_mat_ptr;
|
||||
|
||||
// FIXME: below should be private
|
||||
/* state - variable time_stepping */
|
||||
PALIGNAS_VECTOROPT()
|
||||
plib::parray<nl_fptype, SIZE> m_last_V;
|
||||
@ -423,7 +412,38 @@ namespace solver
|
||||
PALIGNAS_VECTOROPT()
|
||||
plib::parray<nl_fptype, SIZE> m_h_n_m_1;
|
||||
|
||||
constexpr std::size_t size() const noexcept { return (SIZE > 0) ? static_cast<std::size_t>(SIZE) : m_dim; }
|
||||
constexpr std::size_t size() const noexcept
|
||||
{
|
||||
return (SIZE > 0) ? static_cast<std::size_t>(SIZE) : m_dim;
|
||||
}
|
||||
|
||||
void store()
|
||||
{
|
||||
const std::size_t iN = size();
|
||||
for (std::size_t i = 0; i < iN; i++)
|
||||
this->m_terms[i].setV(m_new_V[i]);
|
||||
}
|
||||
|
||||
bool check_err()
|
||||
{
|
||||
/* NOTE: Ideally we should also include currents (RHS) here. This would
|
||||
* need a reevaluation of the right hand side after voltages have been updated
|
||||
* and thus belong into a different calculation. This applies to all solvers.
|
||||
*/
|
||||
|
||||
const std::size_t iN = size();
|
||||
const auto reltol(static_cast<FT>(m_params.m_reltol));
|
||||
const auto vntol(static_cast<FT>(m_params.m_vntol));
|
||||
for (std::size_t i = 0; i < iN; i++)
|
||||
{
|
||||
const auto vold(this->m_terms[i].template getV<FT>());
|
||||
const auto vnew(m_new_V[i]);
|
||||
const auto tol(vntol + reltol * std::max(std::abs(vnew),std::abs(vold)));
|
||||
if (std::abs(vnew - vold) > tol)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
netlist_time compute_next_timestep(const nl_fptype cur_ts) override
|
||||
{
|
||||
@ -431,7 +451,7 @@ namespace solver
|
||||
|
||||
if (m_params.m_dynamic_ts)
|
||||
{
|
||||
for (std::size_t k = 0; k < m_terms.size(); k++)
|
||||
for (std::size_t k = 0; k < size(); k++)
|
||||
{
|
||||
auto &t = m_terms[k];
|
||||
//const nl_fptype DD_n = (n->Q_Analog() - t->m_last_V);
|
||||
@ -507,8 +527,7 @@ namespace solver
|
||||
}
|
||||
}
|
||||
|
||||
template <typename RT>
|
||||
void fill_matrix(RT &RHS)
|
||||
void fill_matrix_and_rhs()
|
||||
{
|
||||
const std::size_t N = size();
|
||||
|
||||
@ -549,7 +568,7 @@ namespace solver
|
||||
RHS_t += (/*m_Idr[i]*/ (- go[i]) * *cnV[i]);
|
||||
}
|
||||
|
||||
RHS[k] = static_cast<FT>(RHS_t);
|
||||
m_RHS[k] = static_cast<FT>(RHS_t);
|
||||
// update diagonal element ...
|
||||
*tcr_r[railstart] += static_cast<FT>(gtot_t); //mat.A[mat.diag[k]] += gtot_t;
|
||||
}
|
||||
|
@ -51,12 +51,8 @@ namespace solver
|
||||
template <typename T>
|
||||
void LE_back_subst(T & x);
|
||||
|
||||
PALIGNAS_VECTOROPT()
|
||||
plib::parray<FT, SIZE> m_new_V;
|
||||
PALIGNAS_VECTOROPT()
|
||||
plib::parray2D<FT, SIZE, m_pitch_ABS> m_A;
|
||||
PALIGNAS_VECTOROPT()
|
||||
plib::parray<FT, SIZE> m_RHS;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -81,7 +77,7 @@ namespace solver
|
||||
const FT f1 = -f * m_A[j][i];
|
||||
for (auto &k : nzrd)
|
||||
m_A[j][k] += m_A[i][k] * f1;
|
||||
m_RHS[j] += m_RHS[i] * f1;
|
||||
this->m_RHS[j] += this->m_RHS[i] * f1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,8 +89,8 @@ namespace solver
|
||||
std::size_t maxrow = i;
|
||||
for (std::size_t j = i + 1; j < kN; j++)
|
||||
{
|
||||
//if (std::abs(m_A[j][i]) > std::abs(m_A[maxrow][i]))
|
||||
if (m_A[j][i] * m_A[j][i] > m_A[maxrow][i] * m_A[maxrow][i])
|
||||
if (std::abs(m_A[j][i]) > std::abs(m_A[maxrow][i]))
|
||||
//if (m_A[j][i] * m_A[j][i] > m_A[maxrow][i] * m_A[maxrow][i])
|
||||
maxrow = j;
|
||||
}
|
||||
|
||||
@ -104,7 +100,7 @@ namespace solver
|
||||
for (std::size_t k = 0; k < kN; k++) {
|
||||
std::swap(m_A[i][k], m_A[maxrow][k]);
|
||||
}
|
||||
std::swap(m_RHS[i], m_RHS[maxrow]);
|
||||
std::swap(this->m_RHS[i], this->m_RHS[maxrow]);
|
||||
}
|
||||
/* FIXME: Singular matrix? */
|
||||
const FT f = plib::reciprocal(m_A[i][i]);
|
||||
@ -123,7 +119,7 @@ namespace solver
|
||||
// pj[k] = pj[k] + pi[k] * f1;
|
||||
//for (unsigned k = i+1; k < kN; k++)
|
||||
//A(j,k) += A(i,k) * f1;
|
||||
m_RHS[j] += m_RHS[i] * f1;
|
||||
this->m_RHS[j] += this->m_RHS[i] * f1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -145,7 +141,7 @@ namespace solver
|
||||
FT tmp = 0;
|
||||
for (std::size_t k = j+1; k < kN; k++)
|
||||
tmp += m_A[j][k] * x[k];
|
||||
x[j] = (m_RHS[j] - tmp) / m_A[j][j];
|
||||
x[j] = (this->m_RHS[j] - tmp) / m_A[j][j];
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -157,7 +153,7 @@ namespace solver
|
||||
const auto e = nzrd.size(); // - 1; /* exclude RHS element */
|
||||
for ( std::size_t k = 0; k < e; k++)
|
||||
tmp += m_A[j][nzrd[k]] * x[nzrd[k]];
|
||||
x[j] = (m_RHS[j] - tmp) / m_A[j][j];
|
||||
x[j] = (this->m_RHS[j] - tmp) / m_A[j][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -166,11 +162,13 @@ namespace solver
|
||||
unsigned matrix_solver_direct_t<FT, SIZE>::solve_non_dynamic(const bool newton_raphson)
|
||||
{
|
||||
this->LE_solve();
|
||||
this->LE_back_subst(m_new_V);
|
||||
this->LE_back_subst(this->m_new_V);
|
||||
|
||||
const FT err = (newton_raphson ? this->delta(m_new_V) : plib::constants<FT>::zero());
|
||||
this->store(m_new_V);
|
||||
return (err > static_cast<FT>(this->m_params.m_accuracy)) ? 2 : 1;
|
||||
bool err(false);
|
||||
if (newton_raphson)
|
||||
err = this->check_err();
|
||||
this->store();
|
||||
return (err) ? 2 : 1;
|
||||
}
|
||||
|
||||
template <typename FT, int SIZE>
|
||||
@ -178,7 +176,7 @@ namespace solver
|
||||
{
|
||||
/* populate matrix */
|
||||
this->clear_square_mat(m_A);
|
||||
this->fill_matrix(m_RHS);
|
||||
this->fill_matrix_and_rhs();
|
||||
|
||||
this->m_stat_calculations++;
|
||||
return this->solve_non_dynamic(newton_raphson);
|
||||
@ -191,9 +189,7 @@ namespace solver
|
||||
const std::size_t size)
|
||||
: matrix_solver_ext_t<FT, SIZE>(anetlist, name, nets, params, size)
|
||||
, m_pitch(m_pitch_ABS ? m_pitch_ABS : (((size + 0) + 7) / 8) * 8)
|
||||
, m_new_V(size)
|
||||
, m_A(size, m_pitch)
|
||||
, m_RHS(size)
|
||||
{
|
||||
this->build_mat_ptr(m_A);
|
||||
}
|
||||
|
@ -35,19 +35,19 @@ namespace solver
|
||||
unsigned vsolve_non_dynamic(const bool newton_raphson) override
|
||||
{
|
||||
this->clear_square_mat(this->m_A);
|
||||
this->fill_matrix(this->m_RHS);
|
||||
this->fill_matrix_and_rhs();
|
||||
|
||||
std::array<FT, 1> new_V = { this->m_RHS[0] / this->m_A[0][0] };
|
||||
this->m_new_V[0] = this->m_RHS[0] / this->m_A[0][0];
|
||||
|
||||
const FT err = (newton_raphson ? this->delta(new_V) : plib::constants<FT>::zero());
|
||||
this->store(new_V);
|
||||
return (err > static_cast<FT>(this->m_params.m_accuracy)) ? 2 : 1;
|
||||
bool err(false);
|
||||
if (newton_raphson)
|
||||
err = this->check_err();
|
||||
this->store();
|
||||
return (err) ? 2 : 1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace solver
|
||||
} // namespace netlist
|
||||
|
||||
|
@ -35,7 +35,7 @@ namespace solver
|
||||
unsigned vsolve_non_dynamic(const bool newton_raphson) override
|
||||
{
|
||||
this->clear_square_mat(this->m_A);
|
||||
this->fill_matrix(this->m_RHS);
|
||||
this->fill_matrix_and_rhs();
|
||||
|
||||
const float_type a = this->m_A[0][0];
|
||||
const float_type b = this->m_A[0][1];
|
||||
@ -44,12 +44,15 @@ namespace solver
|
||||
|
||||
const float_type v1 = (a * this->m_RHS[1] - c * this->m_RHS[0]) / (a * d - b * c);
|
||||
const float_type v0 = (this->m_RHS[0] - b * v1) / a;
|
||||
std::array<float_type, 2> new_V = {v0, v1};
|
||||
this->m_new_V[0] = v0;
|
||||
this->m_new_V[1] = v1;
|
||||
|
||||
this->m_stat_calculations++;
|
||||
const float_type err = (newton_raphson ? this->delta(new_V) : plib::constants<FT>::zero());
|
||||
this->store(new_V);
|
||||
return (err > static_cast<float_type>(this->m_params.m_accuracy)) ? 2 : 1;
|
||||
bool err(false);
|
||||
if (newton_raphson)
|
||||
err = this->check_err();
|
||||
this->store();
|
||||
return (err) ? 2 : 1;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -36,8 +36,6 @@ namespace solver
|
||||
const analog_net_t::list_t &nets,
|
||||
const solver_parameters_t *params, const std::size_t size)
|
||||
: matrix_solver_ext_t<FT, SIZE>(anetlist, name, nets, params, size)
|
||||
, RHS(size)
|
||||
, new_V(size)
|
||||
, mat(static_cast<typename mat_type::index_type>(size))
|
||||
, m_proc()
|
||||
{
|
||||
@ -120,9 +118,6 @@ namespace solver
|
||||
|
||||
pstring static_compile_name();
|
||||
|
||||
plib::parray<FT, SIZE> RHS;
|
||||
plib::parray<FT, SIZE> new_V;
|
||||
|
||||
mat_type mat;
|
||||
|
||||
plib::dynproc<void, FT * , FT * , FT * > m_proc;
|
||||
@ -137,9 +132,11 @@ namespace solver
|
||||
void matrix_solver_GCR_t<FT, SIZE>::generate_code(plib::putf8_fmt_writer &strm)
|
||||
{
|
||||
const std::size_t iN = this->size();
|
||||
pstring fptype(fp_constants<FT>::name());
|
||||
pstring fpsuffix(fp_constants<FT>::suffix());
|
||||
|
||||
for (std::size_t i = 0; i < mat.nz_num; i++)
|
||||
strm("double m_A{1} = m_A[{2}];\n", i, i);
|
||||
strm("{1} m_A{2} = m_A[{3}];\n", fptype, i, i);
|
||||
|
||||
for (std::size_t i = 0; i < iN - 1; i++)
|
||||
{
|
||||
@ -150,7 +147,7 @@ namespace solver
|
||||
std::size_t pi = mat.diag[i];
|
||||
|
||||
//const FT f = 1.0 / m_A[pi++];
|
||||
strm("const double f{1} = 1.0 / m_A{2};\n", i, pi);
|
||||
strm("const {1} f{2} = 1.0{3} / m_A{4};\n", fptype, i, fpsuffix, pi);
|
||||
pi++;
|
||||
const std::size_t piie = mat.row_idx[i+1];
|
||||
|
||||
@ -164,7 +161,7 @@ namespace solver
|
||||
pj++;
|
||||
|
||||
//const FT f1 = - m_A[pj++] * f;
|
||||
strm("\tconst double f{1}_{2} = -f{3} * m_A{4};\n", i, j, i, pj);
|
||||
strm("\tconst {1} f{2}_{3} = -f{4} * m_A{5};\n", fptype, i, j, i, pj);
|
||||
pj++;
|
||||
|
||||
// subtract row i from j */
|
||||
@ -186,7 +183,7 @@ namespace solver
|
||||
strm("\tV[{1}] = RHS[{2}] / m_A{3};\n", iN - 1, iN - 1, mat.diag[iN - 1]);
|
||||
for (std::size_t j = iN - 1; j-- > 0;)
|
||||
{
|
||||
strm("\tdouble tmp{1} = 0.0;\n", j);
|
||||
strm("\t{1} tmp{2} = 0.0{3};\n", fptype, j, fpsuffix);
|
||||
const std::size_t e = mat.row_idx[j+1];
|
||||
for (std::size_t pk = mat.diag[j] + 1; pk < e; pk++)
|
||||
{
|
||||
@ -214,8 +211,9 @@ namespace solver
|
||||
t.imbue(std::locale::classic());
|
||||
plib::putf8_fmt_writer strm(&t);
|
||||
pstring name = static_compile_name();
|
||||
pstring fptype(fp_constants<FT>::name());
|
||||
|
||||
strm.writeline(plib::pfmt("extern \"C\" void {1}(double * __restrict m_A, double * __restrict RHS, double * __restrict V)\n")(name));
|
||||
strm.writeline(plib::pfmt("extern \"C\" void {1}({2} * __restrict m_A, {2} * __restrict RHS, {2} * __restrict V)\n")(name, fptype));
|
||||
strm.writeline("{\n");
|
||||
generate_code(strm);
|
||||
strm.writeline("}\n");
|
||||
@ -228,28 +226,30 @@ namespace solver
|
||||
{
|
||||
/* populate matrix */
|
||||
mat.set_scalar(plib::constants<FT>::zero());
|
||||
this->fill_matrix(RHS);
|
||||
this->fill_matrix_and_rhs();
|
||||
|
||||
/* now solve it */
|
||||
|
||||
if (m_proc.resolved())
|
||||
{
|
||||
m_proc(&mat.A[0], &RHS[0], &new_V[0]);
|
||||
m_proc(&mat.A[0], &this->m_RHS[0], &this->m_new_V[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// parallel is slow -- very slow
|
||||
//mat.gaussian_elimination_parallel(RHS);
|
||||
mat.gaussian_elimination(RHS);
|
||||
mat.gaussian_elimination(this->m_RHS);
|
||||
/* backward substitution */
|
||||
mat.gaussian_back_substitution(new_V, RHS);
|
||||
mat.gaussian_back_substitution(this->m_new_V, this->m_RHS);
|
||||
}
|
||||
|
||||
this->m_stat_calculations++;
|
||||
|
||||
const FT err = (newton_raphson ? this->delta(new_V) : plib::constants<FT>::zero());
|
||||
this->store(new_V);
|
||||
return (err > static_cast<FT>(this->m_params.m_accuracy)) ? 2 : 1;
|
||||
bool err(false);
|
||||
if (newton_raphson)
|
||||
err = this->check_err();
|
||||
this->store();
|
||||
return (err) ? 2 : 1;
|
||||
}
|
||||
|
||||
} // namespace solver
|
||||
|
@ -101,12 +101,10 @@ namespace solver
|
||||
{
|
||||
const std::size_t iN = this->size();
|
||||
|
||||
plib::parray<FT, SIZE> RHS(iN);
|
||||
|
||||
m_ops.m_mat.set_scalar(plib::constants<FT>::zero());
|
||||
|
||||
/* populate matrix and V for first estimate */
|
||||
this->fill_matrix(RHS);
|
||||
this->fill_matrix_and_rhs();
|
||||
|
||||
for (std::size_t k = 0; k < iN; k++)
|
||||
{
|
||||
@ -116,7 +114,7 @@ namespace solver
|
||||
const float_type accuracy = static_cast<float_type>(this->m_params.m_accuracy);
|
||||
|
||||
auto iter = std::max(plib::constants<std::size_t>::one(), this->m_params.m_gs_loops());
|
||||
auto gsl = m_gmres.solve(m_ops, this->m_new_V, RHS, iter, accuracy);
|
||||
auto gsl = m_gmres.solve(m_ops, this->m_new_V, this->m_RHS, iter, accuracy);
|
||||
|
||||
this->m_iterative_total += gsl;
|
||||
this->m_stat_calculations++;
|
||||
@ -127,9 +125,11 @@ namespace solver
|
||||
return matrix_solver_direct_t<FT, SIZE>::vsolve_non_dynamic(newton_raphson);
|
||||
}
|
||||
|
||||
const float_type err = (newton_raphson ? this->delta(this->m_new_V) : plib::constants<FT>::zero());
|
||||
this->store(this->m_new_V);
|
||||
return (err > static_cast<float_type>(this->m_params.m_accuracy)) ? 2 : 1;
|
||||
bool err(false);
|
||||
if (newton_raphson)
|
||||
err = this->check_err();
|
||||
this->store();
|
||||
return (err) ? 2 : 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -204,8 +204,6 @@ namespace solver
|
||||
static constexpr const bool incremental = true;
|
||||
const std::size_t iN = this->size();
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
std::array<float_type, storage_N> new_V;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
std::array<float_type, m_pitch> v;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
@ -277,11 +275,13 @@ namespace solver
|
||||
|
||||
m_cnt++;
|
||||
|
||||
this->LE_compute_x(new_V);
|
||||
this->LE_compute_x(this->m_new_V);
|
||||
|
||||
const float_type err = (newton_raphson ? this->delta(new_V) : plib::constants<FT>::zero());
|
||||
this->store(new_V);
|
||||
return (err > static_cast<FT>(this->m_params.m_accuracy)) ? 2 : 1;
|
||||
bool err(false);
|
||||
if (newton_raphson)
|
||||
err = this->check_err();
|
||||
this->store();
|
||||
return (err) ? 2 : 1;
|
||||
}
|
||||
|
||||
template <typename FT, int SIZE>
|
||||
@ -289,7 +289,7 @@ namespace solver
|
||||
{
|
||||
|
||||
this->clear_square_mat(this->m_A);
|
||||
this->fill_matrix(this->m_RHS);
|
||||
this->fill_matrix_and_rhs();
|
||||
|
||||
this->m_stat_calculations++;
|
||||
return this->solve_non_dynamic(newton_raphson);
|
||||
|
@ -36,8 +36,6 @@ namespace solver
|
||||
, m_lp_fact(*this, "m_lp_fact", 0)
|
||||
, w(size, plib::constants<FT>::zero())
|
||||
, one_m_w(size, plib::constants<FT>::zero())
|
||||
, RHS(size, plib::constants<FT>::zero())
|
||||
//, new_V(size, 0.0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -47,8 +45,6 @@ namespace solver
|
||||
state_var<float_type> m_lp_fact;
|
||||
std::vector<float_type> w;
|
||||
std::vector<float_type> one_m_w;
|
||||
std::vector<float_type> RHS;
|
||||
//std::vector<float_type> new_V;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
@ -74,9 +70,9 @@ namespace solver
|
||||
|
||||
for (std::size_t k = 0; k < iN; k++)
|
||||
{
|
||||
nl_fptype gtot_t = 0.0;
|
||||
nl_fptype gabs_t = 0.0;
|
||||
nl_fptype RHS_t = 0.0;
|
||||
nl_fptype gtot_t = plib::constants<nl_fptype>::zero();
|
||||
nl_fptype gabs_t = plib::constants<nl_fptype>::zero();
|
||||
nl_fptype RHS_t = plib::constants<nl_fptype>::zero();
|
||||
|
||||
const std::size_t term_count = this->m_terms[k].count();
|
||||
const nl_fptype * const gt = this->m_gtn[k];
|
||||
@ -95,7 +91,7 @@ namespace solver
|
||||
for (std::size_t i = this->m_terms[k].railstart(); i < term_count; i++)
|
||||
RHS_t = RHS_t - go[i] * *other_cur_analog[i];
|
||||
|
||||
RHS[k] = static_cast<float_type>(RHS_t);
|
||||
this->m_RHS[k] = static_cast<float_type>(RHS_t);
|
||||
|
||||
if (this->m_params.m_use_gabs)
|
||||
{
|
||||
@ -136,7 +132,7 @@ namespace solver
|
||||
for (std::size_t i = 0; i < railstart; i++)
|
||||
Idrive = Idrive - static_cast<float_type>(go[i]) * this->m_new_V[static_cast<std::size_t>(net_other[i])];
|
||||
|
||||
const float_type new_val = this->m_new_V[k] * one_m_w[k] + (Idrive + RHS[k]) * w[k];
|
||||
const float_type new_val = this->m_new_V[k] * one_m_w[k] + (Idrive + this->m_RHS[k]) * w[k];
|
||||
|
||||
err = std::max(std::abs(new_val - this->m_new_V[k]), err);
|
||||
this->m_new_V[k] = new_val;
|
||||
@ -158,9 +154,11 @@ namespace solver
|
||||
return matrix_solver_direct_t<FT, SIZE>::vsolve_non_dynamic(newton_raphson);
|
||||
}
|
||||
|
||||
const float_type err = (newton_raphson ? this->delta(this->m_new_V) : plib::constants<FT>::zero());
|
||||
this->store(this->m_new_V);
|
||||
return (err > static_cast<float_type>(this->m_params.m_accuracy)) ? 2 : 1;
|
||||
bool err(false);
|
||||
if (newton_raphson)
|
||||
err = this->check_err();
|
||||
this->store();
|
||||
return (err) ? 2 : 1;
|
||||
}
|
||||
|
||||
} // namespace solver
|
||||
|
@ -117,7 +117,7 @@ namespace solver
|
||||
const std::size_t iN = this->size();
|
||||
|
||||
this->clear_square_mat(this->m_A);
|
||||
this->fill_matrix(this->m_RHS);
|
||||
this->fill_matrix_and_rhs();
|
||||
|
||||
bool resched = false;
|
||||
|
||||
@ -210,10 +210,11 @@ namespace solver
|
||||
return matrix_solver_direct_t<FT, SIZE>::solve_non_dynamic(newton_raphson);
|
||||
}
|
||||
|
||||
const float_type err = (newton_raphson ? this->delta(this->m_new_V) : plib::constants<FT>::zero());
|
||||
this->store(this->m_new_V);
|
||||
return (err > static_cast<float_type>(this->m_params.m_accuracy)) ? 2 : 1;
|
||||
|
||||
bool err(false);
|
||||
if (newton_raphson)
|
||||
err = this->check_err();
|
||||
this->store();
|
||||
return (err) ? 2 : 1;
|
||||
}
|
||||
|
||||
} // namespace solver
|
||||
|
@ -213,8 +213,6 @@ namespace solver
|
||||
{
|
||||
const auto iN = this->size();
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
std::array<float_type, storage_N> new_V;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
std::array<float_type, storage_N> t; // FIXME: convert to member
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
@ -224,12 +222,12 @@ namespace solver
|
||||
{
|
||||
/* complete calculation */
|
||||
this->LE_invert();
|
||||
this->LE_compute_x(new_V);
|
||||
this->LE_compute_x(this->m_new_V);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Solve Ay = b for y */
|
||||
this->LE_compute_x(new_V);
|
||||
this->LE_compute_x(this->m_new_V);
|
||||
|
||||
/* determine changed rows */
|
||||
|
||||
@ -261,7 +259,7 @@ namespace solver
|
||||
const unsigned r = rows[i];
|
||||
FT tmp = plib::constants<FT>::zero();
|
||||
for (unsigned k = 0; k < iN; k++)
|
||||
tmp += VT(r,k) * new_V[k];
|
||||
tmp += VT(r,k) * this->m_new_V[k];
|
||||
w[i] = tmp;
|
||||
}
|
||||
|
||||
@ -328,7 +326,7 @@ namespace solver
|
||||
const unsigned row = rows[j];
|
||||
tmp += Ainv(i,row) * t[j];
|
||||
}
|
||||
new_V[i] -= tmp;
|
||||
this->m_new_V[i] -= tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -340,22 +338,24 @@ namespace solver
|
||||
float_type tmp = plib::constants<FT>::zero();
|
||||
for (unsigned j=0; j<iN; j++)
|
||||
{
|
||||
tmp += A(i,j) * new_V[j];
|
||||
tmp += A(i,j) * this->m_new_V[j];
|
||||
}
|
||||
if (std::abs(tmp-RHS(i)) > static_cast<float_type>(1e-6))
|
||||
plib::perrlogger("{} failed on row {}: {} RHS: {}\n", this->name(), i, std::abs(tmp-RHS(i)), RHS(i));
|
||||
}
|
||||
|
||||
const float_type err = (newton_raphson ? this->delta(new_V) : plib::constants<FT>::zero());
|
||||
this->store(new_V);
|
||||
return (err > static_cast<float_type>(this->m_params.m_accuracy)) ? 2 : 1;
|
||||
bool err(false);
|
||||
if (newton_raphson)
|
||||
err = this->check_err();
|
||||
this->store();
|
||||
return (err) ? 2 : 1;
|
||||
}
|
||||
|
||||
template <typename FT, int SIZE>
|
||||
unsigned matrix_solver_w_t<FT, SIZE>::vsolve_non_dynamic(const bool newton_raphson)
|
||||
{
|
||||
this->clear_square_mat(this->m_A);
|
||||
this->fill_matrix(this->m_RHS);
|
||||
this->fill_matrix_and_rhs();
|
||||
|
||||
this->m_stat_calculations++;
|
||||
return this->solve_non_dynamic(newton_raphson);
|
||||
|
Loading…
Reference in New Issue
Block a user