Preliminary support for LTE dynamic time-stepping based on Local truncation error. This enables the possibility to connect a capacitor between ground and a TTL output and get a e.g. 100 ns delay with a 1nF capacitor.

Added an example circuit (cdelay.c)
Changed the log device to support nano-second granularity.
LTE is not yet enabled due to it's ugly test-state.
This commit is contained in:
Couriersud 2014-05-15 22:50:40 +00:00
parent 3b5b4fd0ea
commit f3cf3a8e78
8 changed files with 102 additions and 20 deletions

1
.gitattributes vendored
View file

@ -370,6 +370,7 @@ nl_examples/bjt_eb.c svneol=native#text/plain
nl_examples/bjt_eb_pnp.c svneol=native#text/plain
nl_examples/breakout.c svneol=native#text/plain
nl_examples/cd4066.c svneol=native#text/plain
nl_examples/cdelay.c svneol=native#text/plain
nl_examples/msx_mixer_stage.c svneol=native#text/plain
nl_examples/ne555_astable.c svneol=native#text/plain
nl_examples/opamp.c svneol=native#text/plain

31
nl_examples/cdelay.c Normal file
View file

@ -0,0 +1,31 @@
/*
* cdelay.c
*
*/
#include "netlist/devices/net_lib.h"
NETLIST_START(7400_astable)
/*
* delay circuit
*
*/
/* Standard stuff */
SOLVER(Solver, 48000)
PARAM(Solver.ACCURACY, 1e-20)
CLOCK(clk, 5000)
TTL_7400_NAND(n1,clk,clk)
CAP(C, 1e-9)
NET_C(n1.Q, C.2)
NET_C(GND, C.1)
TTL_7400_NAND(n2,n1.Q, n1.Q)
LOG(logclk, clk)
LOG(logn1Q, C.2)
LOG(logn2Q, n2.Q)
NETLIST_END()

View file

@ -106,9 +106,28 @@ ATTR_COLD void netlist_matrix_solver_t::setup(netlist_net_t::list_t &nets, NETLI
}
}
ATTR_HOT void netlist_matrix_solver_t::update_inputs()
ATTR_HOT double netlist_matrix_solver_t::update_inputs(const double hn)
{
double m_xx = 0.0001;
#if NEW_LTE
for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p))
{
netlist_net_t *n = (*p)->m_proxied_net;
double DD_n = (n->m_cur_Analog - n->m_last_Analog) / hn;
double DD2 = (DD_n - n->m_DD_n_m_1) / (hn + n->m_h_n_m_1);
n->m_DD_n_m_1 = DD_n;
n->m_h_n_m_1 = hn;
double xx;
if (fabs(DD2) > 1e-100)
xx=sqrt(1.0e-3/fabs(0.5*DD2));
else
xx=0.0001;
if (xx<m_xx) m_xx = xx;
}
if (m_xx < 2e-9) m_xx = 2e-9;
//printf("%20s %f us\n", name().cstr(), m_xx * 1000000.0);
#endif
#if NEW_INPUT
// avoid recursive calls. Inputs are updated outside this call
for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p))
@ -133,7 +152,7 @@ ATTR_HOT void netlist_matrix_solver_t::update_inputs()
(*p)->net().m_last_Analog = (*p)->net().m_cur_Analog;
}
#endif
return m_xx;
}
@ -159,8 +178,14 @@ ATTR_HOT void netlist_matrix_solver_t::schedule()
if (!m_Q_sync.net().is_queued())
m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay);
#else
if (solve())
update_inputs();
#if NEW_LTE
double xx = solve();
if (xx<10e-6)
if (!m_Q_sync.net().is_queued())
m_Q_sync.net().push_to_queue(netlist_time::from_double(xx));
#else
solve();
#endif
#endif
}
@ -178,8 +203,14 @@ ATTR_COLD void netlist_matrix_solver_t::reset()
ATTR_COLD void netlist_matrix_solver_t::update()
{
if (solve())
update_inputs();
#if NEW_LTE
double xx = solve();
if (xx<10e-6)
if (!m_Q_sync.net().is_queued())
m_Q_sync.net().push_to_queue(netlist_time::from_double(xx));
#else
solve();
#endif
}
@ -190,7 +221,7 @@ ATTR_HOT void netlist_matrix_solver_t::step(const netlist_time delta)
m_steps[k]->step_time(dd);
}
ATTR_HOT bool netlist_matrix_solver_t::solve()
ATTR_HOT double netlist_matrix_solver_t::solve()
{
netlist_time now = owner().netlist().time();
@ -198,7 +229,7 @@ ATTR_HOT bool netlist_matrix_solver_t::solve()
// We are already up to date. Avoid oscillations.
if (delta < netlist_time::from_nsec(1))
return true;
return 1.0;
NL_VERBOSE_OUT(("Step!\n"));
/* update all terminals for new time step */
@ -223,7 +254,7 @@ ATTR_HOT bool netlist_matrix_solver_t::solve()
{
owner().netlist().warning("NEWTON_LOOPS exceeded ... reschedule");
m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay);
return false;
return 1.0;
}
}
else
@ -231,7 +262,7 @@ ATTR_HOT bool netlist_matrix_solver_t::solve()
while (solve_non_dynamic() > m_params.m_gs_loops)
owner().netlist().warning("Non-Dynamic Solve iterations exceeded .. Consider increasing RESCHED_LOOPS");
}
return true;
return update_inputs(delta.as_double());
}
// ----------------------------------------------------------------------------------------
@ -770,25 +801,33 @@ NETLIB_UPDATE(solver)
this_resched[i] = m_mat_solvers[i]->solve();
}
#else
// FIXME: parameter
double m_xx = m_inc.as_double() * 100;
for (int i = 0; i < t_cnt; i++)
{
if (m_mat_solvers[i]->is_timestep())
if (m_mat_solvers[i]->solve())
m_mat_solvers[i]->update_inputs();
{
double xx = m_mat_solvers[i]->solve();
if (m_xx > xx)
m_xx = xx;
}
}
#endif
/* step circuit */
if (!m_Q_step.net().is_queued())
#if NEW_LTE
m_Q_step.net().push_to_queue(netlist_time::from_double(m_xx));
#else
m_Q_step.net().push_to_queue(m_inc);
#endif
}
ATTR_COLD void NETLIB_NAME(solver)::solve_all()
{
for (int i = 0; i < m_mat_solvers.count(); i++)
//m_mat_solvers[i]->m_Q_sync.net().push_to_queue(m_mat_solvers[i]->m_params.m_nt_sync_delay);
if (m_mat_solvers[i]->solve())
m_mat_solvers[i]->update_inputs();
m_mat_solvers[i]->solve();
}

View file

@ -9,8 +9,6 @@
#include "../nl_setup.h"
#include "../nl_base.h"
#define NEW_INPUT (1)
// ----------------------------------------------------------------------------------------
// Macros
// ----------------------------------------------------------------------------------------
@ -51,9 +49,9 @@ public:
ATTR_HOT virtual int solve_non_dynamic() = 0;
ATTR_HOT virtual void step(const netlist_time delta);
ATTR_HOT bool solve();
ATTR_HOT double solve();
ATTR_HOT void update_inputs();
ATTR_HOT double update_inputs(const double hn);
ATTR_HOT void update_dynamic();
ATTR_HOT void schedule();

View file

@ -22,7 +22,7 @@ NETLIB_RESET(log)
NETLIB_UPDATE(log)
{
fprintf(m_file, "%e %e\n", netlist().time().as_double(), INPANALOG(m_I));
fprintf(m_file, "%20.9e %e\n", netlist().time().as_double(), INPANALOG(m_I));
}
NETLIB_NAME(log)::~NETLIB_NAME(log)()

View file

@ -91,7 +91,9 @@ ATTR_HOT ATTR_ALIGN void nld_d_to_a_proxy::update()
{
double R = INPLOGIC(m_I) ? m_family_desc->m_R_high : m_family_desc->m_R_low;
double V = INPLOGIC(m_I) ? m_family_desc->m_high_V : m_family_desc->m_low_V;
//printf("%f %f\n", R, V);
#if NEW_LTE
m_R.update_dev();
#endif
OUTANALOG(m_Q, V);
m_R.set_R(R);
}

View file

@ -473,6 +473,10 @@ ATTR_COLD netlist_net_t::netlist_net_t(const type_t atype, const family_t afamil
, m_time(netlist_time::zero)
, m_active(0)
, m_in_queue(2)
#if NEW_LTE
, m_DD_n_m_1(0.0)
, m_h_n_m_1(1e-6)
#endif
{
m_last_Q = 0;
m_new_Q = 0;

View file

@ -157,6 +157,9 @@
#include "pstring.h"
#include "pstate.h"
#define NEW_INPUT (1)
#define NEW_LTE (0)
// ----------------------------------------------------------------------------------------
// Type definitions
// ----------------------------------------------------------------------------------------
@ -651,6 +654,10 @@ public:
double m_last_Analog;
double m_cur_Analog;
double m_new_Analog;
#if NEW_LTE
double m_DD_n_m_1;
double m_h_n_m_1;
#endif
};