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/bjt_eb_pnp.c svneol=native#text/plain
nl_examples/breakout.c svneol=native#text/plain nl_examples/breakout.c svneol=native#text/plain
nl_examples/cd4066.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/msx_mixer_stage.c svneol=native#text/plain
nl_examples/ne555_astable.c svneol=native#text/plain nl_examples/ne555_astable.c svneol=native#text/plain
nl_examples/opamp.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 #if NEW_INPUT
// avoid recursive calls. Inputs are updated outside this call // 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)) 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; (*p)->net().m_last_Analog = (*p)->net().m_cur_Analog;
} }
#endif #endif
return m_xx;
} }
@ -159,8 +178,14 @@ ATTR_HOT void netlist_matrix_solver_t::schedule()
if (!m_Q_sync.net().is_queued()) if (!m_Q_sync.net().is_queued())
m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay); m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay);
#else #else
if (solve()) #if NEW_LTE
update_inputs(); 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 #endif
} }
@ -178,8 +203,14 @@ ATTR_COLD void netlist_matrix_solver_t::reset()
ATTR_COLD void netlist_matrix_solver_t::update() ATTR_COLD void netlist_matrix_solver_t::update()
{ {
if (solve()) #if NEW_LTE
update_inputs(); 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); 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(); 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. // We are already up to date. Avoid oscillations.
if (delta < netlist_time::from_nsec(1)) if (delta < netlist_time::from_nsec(1))
return true; return 1.0;
NL_VERBOSE_OUT(("Step!\n")); NL_VERBOSE_OUT(("Step!\n"));
/* update all terminals for new time step */ /* 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"); owner().netlist().warning("NEWTON_LOOPS exceeded ... reschedule");
m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay); m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay);
return false; return 1.0;
} }
} }
else else
@ -231,7 +262,7 @@ ATTR_HOT bool netlist_matrix_solver_t::solve()
while (solve_non_dynamic() > m_params.m_gs_loops) while (solve_non_dynamic() > m_params.m_gs_loops)
owner().netlist().warning("Non-Dynamic Solve iterations exceeded .. Consider increasing RESCHED_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(); this_resched[i] = m_mat_solvers[i]->solve();
} }
#else #else
// FIXME: parameter
double m_xx = m_inc.as_double() * 100;
for (int i = 0; i < t_cnt; i++) for (int i = 0; i < t_cnt; i++)
{ {
if (m_mat_solvers[i]->is_timestep()) 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 #endif
/* step circuit */ /* step circuit */
if (!m_Q_step.net().is_queued()) 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); m_Q_step.net().push_to_queue(m_inc);
#endif
} }
ATTR_COLD void NETLIB_NAME(solver)::solve_all() ATTR_COLD void NETLIB_NAME(solver)::solve_all()
{ {
for (int i = 0; i < m_mat_solvers.count(); i++) 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); //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]->solve();
m_mat_solvers[i]->update_inputs();
} }

View File

@ -9,8 +9,6 @@
#include "../nl_setup.h" #include "../nl_setup.h"
#include "../nl_base.h" #include "../nl_base.h"
#define NEW_INPUT (1)
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
// Macros // Macros
// ---------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------
@ -51,9 +49,9 @@ public:
ATTR_HOT virtual int solve_non_dynamic() = 0; ATTR_HOT virtual int solve_non_dynamic() = 0;
ATTR_HOT virtual void step(const netlist_time delta); 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 update_dynamic();
ATTR_HOT void schedule(); ATTR_HOT void schedule();

View File

@ -22,7 +22,7 @@ NETLIB_RESET(log)
NETLIB_UPDATE(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)() 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 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; 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); OUTANALOG(m_Q, V);
m_R.set_R(R); 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_time(netlist_time::zero)
, m_active(0) , m_active(0)
, m_in_queue(2) , 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_last_Q = 0;
m_new_Q = 0; m_new_Q = 0;

View File

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