netlist: prepare road towards trapezoidal integration.

* This is a long term transition goal. Documented in source (see
NL_USE_BACKWARD_EULER).
This commit is contained in:
couriersud 2020-07-17 23:11:39 +02:00
parent 65a2745af0
commit 5d0786a449
5 changed files with 40 additions and 13 deletions

View File

@ -131,7 +131,7 @@ namespace analog
nl_fptype m_gmin;
};
#if 1
#if (NL_USE_BACKWARD_EULER)
// Constant model for constant capacitor model
// Backward Euler
// "Circuit simulation", page 274
@ -166,7 +166,7 @@ namespace analog
struct generic_capacitor_const
{
public:
generic_capacitor_const(device_t &dev, const pstring &name)
generic_capacitor_const(core_device_t &dev, const pstring &name)
: m_gmin(nlconst::zero())
, m_vn(0)
, m_in(0)
@ -195,6 +195,10 @@ namespace analog
m_trn = h;
return { G + m_gmin, -Ieq };
}
void restore_state() noexcept
{
// this one has no state
}
void setparams(nl_fptype gmin) noexcept { m_gmin = gmin; }
private:
nl_fptype m_gmin;

View File

@ -83,6 +83,7 @@ namespace netlist
, m_ff(*this, "m_ff", false)
, m_last_reset(*this, "m_last_reset", false)
, m_overshoot(*this, "m_overshoot", 0.0)
, m_undershoot(*this, "m_undershoot", 0.0)
, m_ovlimit(0.0)
{
register_subalias("GND", m_R3.N()); // Pin 1
@ -138,10 +139,13 @@ namespace netlist
}
else
{
const auto delta = m_THRES() + m_overshoot - vthresh;
const bool bthresh = (delta > 0.0);
#if (NL_USE_BACKWARD_EULER)
const bool bthresh = (m_THRES() + m_overshoot > vthresh);
const bool btrig = (m_TRIG() - m_overshoot > vtrig);
#else
const bool bthresh = (m_THRES() + m_overshoot > vthresh);
const bool btrig = (m_TRIG() - m_undershoot > vtrig);
#endif
if (!btrig)
m_ff = true;
else if (bthresh)
@ -154,7 +158,11 @@ namespace netlist
if (m_last_out && !out)
{
m_overshoot += ((m_THRES() - vthresh)) * 2;
#if (NL_USE_BACKWARD_EULER)
m_overshoot += ((m_THRES() - vthresh)) * 2.0;
#else
m_overshoot += ((m_THRES() - vthresh));
#endif
m_overshoot = plib::clamp(m_overshoot(), nlconst::zero(), ovlimit);
//if (this->name() == "IC6_2")
// printf("%f %s %f %f %f\n", exec().time().as_double(), this->name().c_str(), m_overshoot(), m_R2.P()(), m_THRES());
@ -166,8 +174,13 @@ namespace netlist
}
else if (!m_last_out && out)
{
m_overshoot += (vtrig - m_TRIG()) * 2;
#if (NL_USE_BACKWARD_EULER)
m_overshoot += (vtrig - m_TRIG()) * 2.0;
m_overshoot = plib::clamp(m_overshoot(), nlconst::zero(), ovlimit);
#else
m_undershoot += (vtrig - m_TRIG());
m_undershoot = plib::clamp(m_undershoot(), nlconst::zero(), ovlimit);
#endif
m_RDIS.change_state([this]()
{
m_RDIS.set_R(nlconst::magic(R_OFF));
@ -193,6 +206,7 @@ namespace netlist
state_var<bool> m_ff;
state_var<bool> m_last_reset;
state_var<nl_fptype> m_overshoot;
state_var<nl_fptype> m_undershoot;
nl_fptype m_ovlimit;
nl_fptype clamp_hl(const nl_fptype v, const nl_fptype a, const nl_fptype b) noexcept

View File

@ -28,14 +28,9 @@ NETLIST_EXTERNAL(loc_lib)
NETLIST_START(ex2N6027)
/* This is a circuit pushing the solvers to the limits
* 50,000 maximum NR loops.
*/
SOLVER(Solver, 48000)
PARAM(Solver.ACCURACY, 1e-5)
PARAM(Solver.DYNAMIC_TS, 1)
PARAM(Solver.DYNAMIC_MIN_TIMESTEP, 1e-9)
PARAM(Solver.NR_LOOPS, 50000)
PARAM(Solver.METHOD, "MAT_CR")
LOCAL_SOURCE(loc_lib)

View File

@ -97,6 +97,20 @@
#define NL_USE_COPY_INSTEAD_OF_REFERENCE (0)
#endif
/// \brief Use backward Euler integration
///
/// This will use backward Euler instead of trapezoidal integration.
///
/// FIXME: Longterm this will become a runtime setting. Only the capacitor model
/// currently has a trapezoidal version and there is no support currently for
/// variable capacitors.
/// The change will have impact on timings since trapezoidal improves timing
/// accuracy.
#ifndef NL_USE_BACKWARD_EULER
#define NL_USE_BACKWARD_EULER (1)
#endif
/// \brief Use the truthtable implementation of 7448 instead of the coded device
///
/// FIXME: Using truthtable is a lot slower than the explicit device

View File

@ -532,7 +532,7 @@ namespace solver
if (dynamic_device_count() != 0)
{
step(timestep_type::FORWARD, delta);
auto resched = solve_nr_base();
const auto resched = solve_nr_base();
if (resched)
return newton_loops_exceeded(delta);