- fixed a bug in which the fallback solver was called instead of gauss - seidel.
- matrix solvers are now subdevices of the solver devices
- matrix solvers can now be scheduled independently
- Rename RESCHED_LOOPS to GS_LOOPS (Gauss Seidel)
- Added paragmenter NR_LOOPS (Newton Raphson)
This commit is contained in:
Couriersud 2014-04-18 17:58:35 +00:00
parent 3c46c03671
commit 4b4b4542b2
8 changed files with 139 additions and 83 deletions

View file

@ -14,7 +14,7 @@ NETLIST_START(msx)
SOLVER(Solver, 48000)
PARAM(Solver.ACCURACY, 1e-5)
//PARAM(Solver.CONVERG, 0.3)
PARAM(Solver.RESCHED_LOOPS, 150)
PARAM(Solver.GS_LOOPS, 50)
RES(RAY8910, 2345) // Max Voltage

View file

@ -14,7 +14,7 @@ NETLIST_START(main)
SOLVER(Solver, 48000)
//PARAM(Solver.ACCURACY, 1e-3)
//PARAM(Solver.CONVERG, 1.0)
//PARAM(Solver.RESCHED_LOOPS, 30)
//PARAM(Solver.GS_LOOPS, 30)
/* Opamp wired as impedance changer */
SUBMODEL(op, opamp)

View file

@ -89,12 +89,10 @@ static DipswitchDesc dipswitch1_desc("winning_score", "Winning Score", 0, "11",
#endif
CIRCUIT_LAYOUT( pongdoubles )
SOLVER(Solver)
PARAM(Solver.FREQ, 48000)
PARAM(Solver.ACCURACY, 1e-7) // works and is sufficient
SOLVER(Solver, 48000)
PARAM(Solver.ACCURACY, 1e-7) // works and is sufficient
//CHIP("CLOCK", CLOCK_14_318_MHZ)
MAINCLOCK(CLOCK)
PARAM(CLOCK.FREQ, 14318000.0)
MAINCLOCK(CLOCK, 14318000.0)
ANALOG_INPUT(V5, 5)
#define VCC "V5", Q

View file

@ -11,7 +11,7 @@ NETLIST_START(vccs)
CLOCK(clk, 1000) // 1000 Hz
SOLVER(Solver, 48000)
PARAM(Solver.ACCURACY, 1e-12)
PARAM(Solver.RESCHED_LOOPS, 10000)
PARAM(Solver.GS_LOOPS, 10000)
VCCS(VV)
PARAM(VV.G, 100) // typical OP-AMP amplification

View file

@ -114,26 +114,35 @@ ATTR_HOT void netlist_matrix_solver_t::update_dynamic()
ATTR_HOT void netlist_matrix_solver_t::schedule()
{
// FIXME: Make this a parameter
#if 0
if (/*!m_scheduled &&*/ m_owner != NULL)
{
m_scheduled = true;
this->m_owner->schedule();
}
if (!m_Q_sync.net().is_queued())
m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay);
#else
solve();
update_inputs();
m_scheduled = false;
if (solve())
update_inputs();
#endif
}
ATTR_COLD void netlist_matrix_solver_t::start()
{
register_output("Q_sync", m_Q_sync);
register_input("FB_sync", m_fb_sync);
connect(m_fb_sync, m_Q_sync);
}
ATTR_COLD void netlist_matrix_solver_t::reset()
{
m_last_step = netlist_time::zero;
m_scheduled = true;
}
ATTR_COLD void netlist_matrix_solver_t::update()
{
if (solve())
update_inputs();
}
ATTR_HOT void netlist_matrix_solver_t::step(const netlist_time delta)
{
const double dd = delta.as_double();
@ -141,7 +150,7 @@ ATTR_HOT void netlist_matrix_solver_t::step(const netlist_time delta)
m_steps[k]->step_time(dd);
}
ATTR_HOT void netlist_matrix_solver_t::solve()
ATTR_HOT bool netlist_matrix_solver_t::solve()
{
netlist_time now = owner().netlist().time();
@ -159,18 +168,34 @@ ATTR_HOT void netlist_matrix_solver_t::solve()
if (is_dynamic())
{
int this_resched;
int newton_loops = 0;
do
{
update_dynamic();
while ((this_resched = solve_non_dynamic()) > m_params.m_resched_loops)
while ((this_resched = solve_non_dynamic()) > m_params.m_gs_loops)
owner().netlist().warning("Dynamic Solve iterations exceeded .. Consider increasing RESCHED_LOOPS");
} while (this_resched > 1);
newton_loops++;
} while (this_resched > 1 && newton_loops < m_params.m_nr_loops);
// reschedule ....
if (this_resched > 1 && !m_Q_sync.net().is_queued())
{
#if 1
owner().netlist().warning("NEWTON_LOOPS exceeded ... reschedule");
m_Q_sync.net().push_to_queue(m_params.m_nt_sync_delay);
#else
owner().netlist().warning("NEWTON_LOOPS exceeded ... reschedule all");
m_owner->reschedule_all();
#endif
return false;
}
}
else
{
while (solve_non_dynamic() > m_params.m_resched_loops)
while (solve_non_dynamic() > m_params.m_gs_loops)
owner().netlist().warning("Non-Dynamic Solve iterations exceeded .. Consider increasing RESCHED_LOOPS");
}
return true;
}
// ----------------------------------------------------------------------------------------
@ -300,17 +325,25 @@ ATTR_HOT void netlist_matrix_solver_direct_t<m_N, _storage_N>::gauss_LE(
for (int i = 0; i < N(); i++) {
#if 0
/* Find the row with the largest first value */
maxrow = i;
for (j=i+1;j<n;j++) {
if (ABS(a[i][j]) > ABS(a[i][maxrow]))
double tmp;
int maxrow = i;
for (int j = i + 1; j < N(); j++)
{
if (fabs(A[j][i]) > fabs(A[maxrow][i]))
maxrow = j;
}
/* Swap the maxrow and ith row */
for (k=i;k<n+1;k++) {
tmp = a[k][i];
a[k][i] = a[k][maxrow];
a[k][maxrow] = tmp;
if (maxrow != i)
{
/* Swap the maxrow and ith row */
for (int k = i; k < N(); k++) {
tmp = A[i][k];
A[i][k] = A[maxrow][k];
A[maxrow][k] = tmp;
}
tmp = RHS[i];
RHS[i] = RHS[maxrow];
RHS[maxrow] = tmp;
}
#endif
/* Singular matrix? */
@ -321,15 +354,14 @@ ATTR_HOT void netlist_matrix_solver_direct_t<m_N, _storage_N>::gauss_LE(
/* Eliminate column i from row j */
for (int j = i + 1; j < N(); j++)
{
double f1 = A[j][i] * f;
if (f1 != 0.0)
if (A[j][i] != 0.0)
{
for (int k = i; k < N(); k++)
{
const double f1 = A[j][i] * f;
for (int k = i; k < N(); k++)
A[j][k] -= A[i][k] * f1;
}
RHS[j] -= RHS[i] * f1;
RHS[j] -= RHS[i] * f1;
}
}
}
@ -559,11 +591,13 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::solve_non_dy
else
{
w[k] = 1.0 / gtot_t;
one_m_w[k] = 0.0;
one_m_w[k] = 1.0 - 1.0;
}
RHS[k] = RHS_t;
}
for (int k = 0; k < N(); k++)
m_nets[k]->m_new_Analog = m_nets[k]->m_cur_Analog;
//NL_VERBOSE_OUT(("%f %d\n", w, m_nets.count());
do {
@ -580,27 +614,34 @@ ATTR_HOT int netlist_matrix_solver_gauss_seidel_t<m_N, _storage_N>::solve_non_dy
for (int i = 0; i < term_count; i++)
{
iIdr += terms[i]->m_go * terms[i]->m_otherterm->net().Q_Analog();
iIdr += terms[i]->m_go * terms[i]->m_otherterm->net().m_new_Analog;
//iIdr += terms[i]->m_go * terms[i]->m_otherterm->net().Q_Analog();
}
//double new_val = (net->m_cur_Analog * gabs[k] + iIdr) / (gtot[k]);
double new_val = net->m_cur_Analog * one_m_w[k] + iIdr * w[k];
double new_val = net->m_new_Analog * one_m_w[k] + iIdr * w[k];
double e = (new_val - net->m_cur_Analog);
double e = (new_val - net->m_new_Analog);
cerr += e * e;
net->m_cur_Analog = net->m_new_Analog = new_val;
net->m_new_Analog = new_val;
}
if (resched || cerr / m_nets.count() > m_params.m_accuracy * m_params.m_accuracy)
if (cerr > m_params.m_accuracy * m_params.m_accuracy)
{
resched = true;
//last_resched_net = net;
}
resched_cnt++;
} while (resched && (resched_cnt < m_params.m_resched_loops / 3 ));
} while (resched && (resched_cnt < m_params.m_gs_loops));
if (resched)
return m_fallback.solve_non_dynamic();
{
//netlist().warning("Falling back to direct solver .. Consider increasing RESCHED_LOOPS");
return m_fallback.solve_non_dynamic();
}
for (int k = 0; k < N(); k++)
m_nets[k]->m_cur_Analog = m_nets[k]->m_new_Analog;
return resched_cnt;
}
@ -648,29 +689,26 @@ ATTR_COLD static void process_net(net_groups_t groups, int &cur_group, netlist_n
NETLIB_START(solver)
{
register_output("Q_sync", m_Q_sync);
register_output("Q_step", m_Q_step);
//register_input("FB", m_feedback);
register_param("SYNC_DELAY", m_sync_delay, NLTIME_FROM_NS(5).as_double());
register_param("SYNC_DELAY", m_sync_delay, NLTIME_FROM_NS(10).as_double());
//register_param("SYNC_DELAY", m_sync_delay, NLTIME_FROM_US(10).as_double());
m_nt_sync_delay = m_sync_delay.Value();
register_param("FREQ", m_freq, 48000.0);
m_inc = netlist_time::from_hz(m_freq.Value());
register_param("ACCURACY", m_accuracy, 1e-7);
register_param("CONVERG", m_convergence, 0.3);
register_param("RESCHED_LOOPS", m_resched_loops, 35);
register_param("GS_LOOPS", m_gs_loops, 7); // Gauss-Seidel loops
register_param("NR_LOOPS", m_nr_loops, 25); // Newton-Raphson loops
register_param("PARALLEL", m_parallel, 0);
register_param("GMIN", m_gmin, NETLIST_GMIN_DEFAULT);
// internal staff
register_input("FB_sync", m_fb_sync);
register_input("FB_step", m_fb_step);
connect(m_fb_sync, m_Q_sync);
connect(m_fb_step, m_Q_step);
//save(NAME(m_last_step));
@ -730,9 +768,16 @@ NETLIB_UPDATE(solver)
for (int i = 0; i < t_cnt; i++)
{
if (m_mat_solvers[i]->is_timestep())
m_mat_solvers[i]->solve();
m_mat_solvers[i]->update_inputs();
if (m_mat_solvers[i]->solve());
m_mat_solvers[i]->update_inputs();
}
#if 0
for (int i = 0; i < t_cnt; i++)
{
if (m_mat_solvers[i]->is_timestep())
m_mat_solvers[i]->update_inputs();
}
#endif
#endif
/* step circuit */
@ -740,6 +785,13 @@ NETLIB_UPDATE(solver)
m_Q_step.net().push_to_queue(m_inc);
}
ATTR_COLD void NETLIB_NAME(solver)::reschedule_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);
}
ATTR_COLD void NETLIB_NAME(solver)::post_start()
{
netlist_net_t::list_t groups[100];
@ -817,9 +869,16 @@ ATTR_COLD void NETLIB_NAME(solver)::post_start()
ms->m_params.m_accuracy = m_accuracy.Value();
ms->m_params.m_convergence_factor = m_convergence.Value();
ms->m_params.m_resched_loops = m_resched_loops.Value();
ms->setup(groups[i], *this);
ms->m_params.m_gs_loops = m_gs_loops.Value();
ms->m_params.m_nr_loops = m_nr_loops.Value();
ms->m_params.m_nt_sync_delay = m_sync_delay.Value();
ms->setup(groups[i], *this);
register_sub(*ms, pstring::sprintf("Solver %d",m_mat_solvers.count()));
m_mat_solvers.add(ms);
SOLVER_VERBOSE_OUT(("%d ==> %d nets %s\n", i, groups[i].count(), (*groups[i].first())->m_head->name().cstr()));
SOLVER_VERBOSE_OUT((" has %s elements\n", ms->is_dynamic() ? "dynamic" : "no dynamic"));
SOLVER_VERBOSE_OUT((" has %s elements\n", ms->is_timestep() ? "timestep" : "no timestep"));

View file

@ -29,16 +29,18 @@ struct netlist_solver_parameters_t
{
double m_accuracy;
double m_convergence_factor;
int m_resched_loops;
int m_gs_loops;
int m_nr_loops;
netlist_time m_nt_sync_delay;
};
class netlist_matrix_solver_t
class netlist_matrix_solver_t : public netlist_device_t
{
public:
typedef netlist_list_t<netlist_matrix_solver_t *> list_t;
typedef netlist_core_device_t::list_t dev_list_t;
netlist_matrix_solver_t() : m_scheduled(true), m_owner(NULL) {}
netlist_matrix_solver_t() : m_owner(NULL) {}
virtual ~netlist_matrix_solver_t() {}
ATTR_COLD virtual void setup(netlist_net_t::list_t &nets, NETLIB_NAME(solver) &owner);
@ -47,7 +49,7 @@ public:
ATTR_HOT virtual int solve_non_dynamic() = 0;
ATTR_HOT virtual void step(const netlist_time delta);
ATTR_HOT void solve();
ATTR_HOT bool solve();
ATTR_HOT void update_inputs();
ATTR_HOT void update_dynamic();
@ -58,14 +60,20 @@ public:
ATTR_HOT inline bool is_timestep() { return m_steps.count() > 0; }
ATTR_HOT inline const NETLIB_NAME(solver) &owner() const;
ATTR_COLD virtual void reset();
ATTR_HOT void update();
ATTR_COLD void start();
ATTR_COLD virtual void reset();
netlist_solver_parameters_t m_params;
bool m_scheduled;
netlist_ttl_output_t m_Q_sync;
protected:
netlist_net_t::list_t m_nets;
netlist_ttl_input_t m_fb_sync;
netlist_net_t::list_t m_nets;
dev_list_t m_dynamic;
netlist_core_terminal_t::list_t m_inps;
dev_list_t m_steps;
@ -126,9 +134,10 @@ public:
ATTR_COLD virtual void setup(netlist_net_t::list_t &nets, NETLIB_NAME(solver) &owner)
{
/* FIXME: setup the fallback first, because setup sets m_solver on nets */
m_fallback.setup(nets, owner);
netlist_matrix_solver_t::setup(nets, owner);
m_fallback.m_params = m_params;
m_fallback.setup(nets, owner);
}
ATTR_HOT int solve_non_dynamic();
@ -162,43 +171,31 @@ private:
NETLIB_DEVICE_WITH_PARAMS(solver,
typedef netlist_core_device_t::list_t dev_list_t;
netlist_ttl_input_t m_fb_sync;
netlist_ttl_output_t m_Q_sync;
netlist_ttl_input_t m_fb_step;
netlist_ttl_output_t m_Q_step;
netlist_ttl_input_t m_fb_step;
netlist_ttl_output_t m_Q_step;
netlist_param_double_t m_freq;
netlist_param_double_t m_sync_delay;
netlist_param_double_t m_accuracy;
netlist_param_double_t m_convergence;
netlist_param_double_t m_gmin;
netlist_param_int_t m_resched_loops;
netlist_param_int_t m_nr_loops;
netlist_param_int_t m_gs_loops;
netlist_param_int_t m_parallel;
netlist_time m_inc;
netlist_time m_nt_sync_delay;
netlist_matrix_solver_t::list_t m_mat_solvers;
public:
ATTR_COLD ~NETLIB_NAME(solver)();
ATTR_HOT inline void schedule();
ATTR_COLD void post_start();
ATTR_COLD void reschedule_all();
ATTR_HOT inline double gmin() { return m_gmin.Value(); }
);
ATTR_HOT inline void NETLIB_NAME(solver)::schedule()
{
if (!m_Q_sync.net().is_queued())
{
m_Q_sync.net().push_to_queue(m_nt_sync_delay);
}
}
ATTR_HOT inline const NETLIB_NAME(solver) &netlist_matrix_solver_t::owner() const
{
return *m_owner;

View file

@ -231,6 +231,7 @@ ATTR_COLD void netlist_base_t::reset()
for (tagmap_devices_t::entry_t *entry = m_devices.first(); entry != NULL; entry = m_devices.next(entry))
{
netlist_device_t *dev = entry->object();
//printf("step %s\n", dev->name().cstr());
dev->update_dev();
}
@ -487,7 +488,8 @@ ATTR_COLD netlist_net_t::netlist_net_t(const type_t atype, const family_t afamil
ATTR_COLD netlist_net_t::~netlist_net_t()
{
netlist().remove_save_items(this);
if (isInitialized())
netlist().remove_save_items(this);
}
ATTR_HOT void netlist_net_t::inc_active(netlist_core_terminal_t &term)

View file

@ -310,7 +310,7 @@ public:
virtual ~netlist_object_t();
ATTR_COLD void init_object(netlist_base_t &nl, const pstring &aname);
ATTR_COLD bool isInitalized() { return (m_netlist != NULL); }
ATTR_COLD bool isInitialized() { return (m_netlist != NULL); }
ATTR_COLD const pstring name() const;