netlist: Document alternative approach to CD4016. (nw)

The CD4016 is an analog switch IC. Document an experimental approach
to implement the analog switch as a 3 terminal element which is
completely being dealt with as part as the linear system.

The intention was to improve convergence when the switch is in a
feedback loop. One example are two-opamp tridiagonal wave generators.
Unfortunately the approach did not work out and in addition was
performing far worse than the net-separating original code.

Also updated comment in nld_generic_models.h.
This commit is contained in:
couriersud 2020-04-17 23:08:31 +02:00
parent 5cd3a44607
commit 1af4b9f870
2 changed files with 109 additions and 39 deletions

View File

@ -14,7 +14,9 @@
//
// Set to 0 to use a linearized diode model in the range exceeding
// maximum dissipation. The intention is to have a faster
// convergence but this yet not really is observable
// convergence. On selected circuits (LM3900 trapezoidal) this is
// observable and has a 10% impact.
// FIXME: More research needed
//
#define USE_TEXTBOOK_DIODE (1)

View File

@ -11,6 +11,20 @@
#include "netlist/solver/nld_solver.h"
#include "nlid_system.h"
// This is an experimental approach to implement the analog switch.
// This will make the switch a 3 terminal element which is completely
// being dealt with as part as the linear system.
//
// The intention was to improve convergence when the switch is in a feedback
// loop. One example are two-opamp tridiagonal wave generators.
// Unfortunately the approach did not work out and in addition was performing
// far worse than the net-separating original code.
//
// FIXME: The transfer function needs review
//
#define USE_DYNAMIC_APPROACH (0)
namespace netlist
{
namespace devices
@ -27,56 +41,110 @@ namespace netlist
{
}
NETLIB_RESETI();
NETLIB_UPDATEI();
NETLIB_RESETI()
{
// Start in off condition
// FIXME: is ROFF correct?
m_R.set_R(plib::reciprocal(exec().gmin()));
}
NETLIB_UPDATEI()
{
nl_fptype sup = (m_supply.VCC().Q_Analog() - m_supply.GND().Q_Analog());
nl_fptype in = m_control() - m_supply.GND().Q_Analog();
nl_fptype rON = m_base_r() * nlconst::magic(5.0) / sup;
nl_fptype R = -nlconst::one();
nl_fptype low = nlconst::magic(0.45) * sup;
nl_fptype high = nlconst::magic(0.55) * sup;
bool new_state(false);
if (in < low)
{
R = plib::reciprocal(exec().gmin());
}
else if (in > high)
{
R = rON;
new_state = true;
}
if (R > nlconst::zero() && (m_last != new_state))
{
m_last = new_state;
m_R.update();
m_R.set_R(R);
m_R.solve_later();
}
}
private:
nld_power_pins m_supply;
analog::NETLIB_SUB(R_base) m_R;
analog_input_t m_control;
param_fp_t m_base_r;
state_var<bool> m_last;
};
NETLIB_RESET(CD4066_GATE)
NETLIB_OBJECT(CD4066_GATE_DYNAMIC)
{
// Start in off condition
// FIXME: is ROFF correct?
m_R.set_R(plib::reciprocal(exec().gmin()));
}
NETLIB_UPDATE(CD4066_GATE)
{
nl_fptype sup = (m_supply.VCC().Q_Analog() - m_supply.GND().Q_Analog());
nl_fptype low = nlconst::magic(0.45) * sup;
nl_fptype high = nlconst::magic(0.55) * sup;
nl_fptype in = m_control() - m_supply.GND().Q_Analog();
nl_fptype rON = m_base_r() * nlconst::magic(5.0) / sup;
nl_fptype R = -nlconst::one();
bool new_state(false);
if (in < low)
NETLIB_CONSTRUCTOR(CD4066_GATE_DYNAMIC)
NETLIB_FAMILY("CD4XXX")
, m_supply(*this, "VDD", "VSS")
, m_R(*this, "R", true)
, m_DUM1(*this, "_DUM1", true)
, m_DUM2(*this, "_DUM2", true)
, m_base_r(*this, "BASER", nlconst::magic(270.0))
, m_last(*this, "m_last", false)
{
R = plib::reciprocal(exec().gmin());
}
else if (in > high)
{
R = rON;
new_state = true;
}
//printf("%s %f %f %g\n", name().c_str(), sup, in, R);
if (R > nlconst::zero() && (m_last != new_state))
{
m_last = new_state;
m_R.update();
m_R.set_R(R);
m_R.solve_later();
}
}
register_subalias("CTL", m_DUM1.m_P); // Cathode
connect(m_DUM1.m_P, m_DUM2.m_P);
connect(m_DUM1.m_N, m_R.m_P);
connect(m_DUM2.m_N, m_R.m_N);
}
NETLIB_RESETI()
{
// Start in off condition
// FIXME: is ROFF correct?
}
NETLIB_UPDATEI()
{
}
NETLIB_UPDATE_TERMINALSI()
{
nl_fptype sup = (m_supply.VCC().Q_Analog() - m_supply.GND().Q_Analog());
nl_fptype in = m_DUM1.m_P.net().Q_Analog() - m_supply.GND().Q_Analog();
nl_fptype rON = m_base_r() * nlconst::magic(5.0) / sup;
nl_fptype R = std::exp(-(in / sup - 0.55) * 25.0) + rON;
nl_fptype G = plib::reciprocal(R);
// dI/dVin = (VR1-VR2)*(1.0/sup*b) * exp((Vin/sup-a) * b)
const auto dfdz = 25.0/(R*sup) * m_R.deltaV();
const auto Ieq = dfdz * in;
m_R.set_mat( G, -G, 0.0,
-G, G, 0.0);
//VIN VR1
m_DUM1.set_mat( 0.0, 0.0, 0.0, // IIN
dfdz, 0.0, Ieq); // IR1
m_DUM2.set_mat( 0.0, 0.0, 0.0, // IIN
-dfdz, 0.0, -Ieq); // IR2
}
NETLIB_IS_DYNAMIC(true)
private:
nld_power_pins m_supply;
analog::nld_twoterm m_R;
analog::nld_twoterm m_DUM1;
analog::nld_twoterm m_DUM2;
param_fp_t m_base_r;
state_var<bool> m_last;
};
#if !USE_DYNAMIC_APPROACH
NETLIB_DEVICE_IMPL(CD4066_GATE, "CD4066_GATE", "")
#else
NETLIB_DEVICE_IMPL_ALIAS(CD4066_GATE, CD4066_GATE_DYNAMIC, "CD4066_GATE", "")
#endif
} //namespace devices
} // namespace netlist