Previous 199869 Revisions Next

r30700 Wednesday 28th May, 2014 at 17:54:56 UTC by Couriersud
Netlist updates and bugfixes
- improved convergence code (max(epsilon) instead of sum(epsilon))
- identified needless updates
- changed NE555 discharge current to a value in the order of the datasheet
- improved dynamic time-stepping.

Dynamic time-stepping is not used by any current implementation right now since any fast discharge will be resolved to mV levels imposing nano-second timesteps. Great and exact but deadly for performance.
[src/emu/netlist/analog]nld_solver.c nld_solver.h
[src/emu/netlist/devices]nld_ne555.c

trunk/src/emu/netlist/devices/nld_ne555.c
r30699r30700
88#include "../analog/nld_solver.h"
99
1010#define R_OFF (1E20)
11#define R_ON (1)
11#define R_ON (25)   // Datasheet states a maximum discharge of 200mA, R = 5V / 0.2
1212
1313inline double NETLIB_NAME(NE555)::clamp(const double v, const double a, const double b)
1414{
trunk/src/emu/netlist/analog/nld_solver.c
r30699r30700
3434        delete m_inps[i];
3535}
3636
37ATTR_COLD void netlist_matrix_solver_t::setup(netlist_analog_net_t::list_t &nets, NETLIB_NAME(solver) &aowner, net_entry *list)
37ATTR_COLD void netlist_matrix_solver_t::setup(netlist_analog_net_t::list_t &nets, NETLIB_NAME(solver) &aowner)
3838{
3939   m_owner = &aowner;
4040
4141   NL_VERBOSE_OUT(("New solver setup\n"));
4242
43   for (int k = 0; k < nets.count(); k++)
44       list[k].m_net = nets[k];
43   m_nets.resize(nets.count());
4544
4645   for (int k = 0; k < nets.count(); k++)
4746   {
4847      NL_VERBOSE_OUT(("setting up net\n"));
4948
50      netlist_analog_net_t *net = list[k].m_net;
49        m_nets[k].m_net = nets[k];
50      netlist_analog_net_t *net = nets[k];
5151
5252      net->m_solver = this;
5353
r30699r30700
8181                     pterm->m_new_analog_ptr = &pterm->m_otherterm->net().as_analog().m_new_Analog;
8282
8383                  if (pterm->m_otherterm->net().isRailNet())
84                     list[k].m_rails.add(pterm);
84                     m_nets[k].m_rails.add(pterm);
8585                  else
86                      list[k].m_terms.add(pterm);
86                      m_nets[k].m_terms.add(pterm);
8787               }
8888               NL_VERBOSE_OUT(("Added terminal\n"));
8989               break;
r30699r30700
119119   }
120120}
121121
122ATTR_HOT double netlist_matrix_solver_t::compute_next_timestep(const double hn)
122template <int m_N, int _storage_N>
123ATTR_HOT double netlist_matrix_solver_direct_t<m_N, _storage_N>::compute_next_timestep(const double hn)
123124{
124125    double new_solver_timestep = m_params.m_max_timestep;
125126
126127    if (m_params.m_dynamic)
127128    {
129        /*
130         * FIXME: this is a reduced LTE focusing on the nets which drive other nets
131         *        The academically correct version using all nets is the one commented out
132         *        This causes really bad performance due to rounding errors.
133         */
134#if 0
128135        for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p))
129136        {
130137            netlist_analog_net_t *n = (*p)->m_proxied_net;
131            double DD_n = (n->m_cur_Analog - n->m_last_Analog) / hn;
138#else
139        for (int k = 0; k < N(); k++)
140        {
141            netlist_analog_net_t *n = m_nets[k].m_net;
142#endif
143            double DD_n = (n->m_cur_Analog - n->m_last_Analog);
132144
145            if (fabs(DD_n) < 2.0 * m_params.m_accuracy)
146                DD_n = 0.0;
147            else
148                DD_n = DD_n / hn;
149
133150            double h_n_m_1 = n->m_h_n_m_1;
134151            // limit last timestep in equation.
135152            //if (h_n_m_1 > 3 * hn)
r30699r30700
140157
141158            n->m_DD_n_m_1 = DD_n;
142159            n->m_h_n_m_1 = hn;
143            if (fabs(DD2) > 1e-200) // avoid div-by-zero
160            if (fabs(DD2) > 1e-50) // avoid div-by-zero
144161                new_net_timestep = sqrt(m_params.m_lte / fabs(0.5*DD2));
145162            else
163            {
146164                new_net_timestep = m_params.m_max_timestep;
147165
166                //if (hn > 0.0 && new_net_timestep > 100.0 * hn)
167                //    new_net_timestep = 100.0 * hn;
168            }
169            //if (N()==2)
170            //    printf("%s: k %d ts %e DD2 %e\n", name().cstr(), k, new_net_timestep, DD2);
171
148172            if (new_net_timestep < new_solver_timestep)
149173                new_solver_timestep = new_net_timestep;
150174        }
r30699r30700
162186    for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p))
163187        if ((*p)->m_proxied_net->m_last_Analog != (*p)->m_proxied_net->m_cur_Analog)
164188            (*p)->set_Q((*p)->m_proxied_net->m_cur_Analog);
165    for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p))
189#if 1
190    for (int k = 0; k < m_nets.count(); k++)
166191    {
167        if ((*p)->m_proxied_net->m_last_Analog != (*p)->m_proxied_net->m_cur_Analog)
168            (*p)->m_proxied_net->m_last_Analog = (*p)->m_proxied_net->m_cur_Analog;
192        netlist_analog_net_t *p= m_nets[k].m_net;
193        p->m_last_Analog = p->m_cur_Analog;
169194    }
195#else
196        for (netlist_analog_output_t * const *p = m_inps.first(); p != NULL; p = m_inps.next(p))
197        {
198            if ((*p)->m_proxied_net->m_last_Analog != (*p)->m_proxied_net->m_cur_Analog)
199                (*p)->m_proxied_net->m_last_Analog = (*p)->m_proxied_net->m_cur_Analog;
200        }
201#endif
170202}
171203
172204
r30699r30700
201233{
202234    const double new_timestep = solve();
203235
204    if (m_params.m_dynamic && new_timestep > 0)
236    if (m_params.m_dynamic && is_timestep() && new_timestep > 0)
205237        m_Q_sync.net().reschedule_in_queue(netlist_time::from_double(new_timestep));
206238}
207239
208240ATTR_COLD void netlist_matrix_solver_t::update_forced()
209241{
210    const double new_timestep = solve();
242    ATTR_UNUSED const double new_timestep = solve();
211243
212    if (!m_params.m_dynamic)
213        return;
214
215     if (new_timestep > 0)
244    if (m_params.m_dynamic && is_timestep())
216245        m_Q_sync.net().reschedule_in_queue(netlist_time::from_double(m_params.m_min_timestep));
217246}
218247
r30699r30700
305334ATTR_COLD void netlist_matrix_solver_direct_t<m_N, _storage_N>::vsetup(netlist_analog_net_t::list_t &nets, NETLIB_NAME(solver) &owner)
306335{
307336    m_dim = nets.count();
308   netlist_matrix_solver_t::setup(nets, owner, m_nets);
337   netlist_matrix_solver_t::setup(nets, owner);
309338
310339   m_terms.clear();
311340   m_rail_start = 0;
r30699r30700
477506   double cerr2 = 0;
478507   for (int i = 0; i < this->N(); i++)
479508   {
480      double e = (V[i] - this->m_nets[i].m_net->m_cur_Analog);
481      double e2 = (m_RHS[i] - this->m_last_RHS[i]);
482      cerr += e * e;
483      cerr2 += e2 * e2;
509      const double e = (V[i] - this->m_nets[i].m_net->m_cur_Analog);
510      const double e2 = (m_RHS[i] - this->m_last_RHS[i]);
511      cerr = (fabs(e) > cerr ? fabs(e) : cerr);
512        cerr2 = (fabs(e2) > cerr2 ? fabs(e2) : cerr2);
484513   }
485   return (cerr + cerr2*(100000.0 * 100000.0)) / this->N();
514   // FIXME: Review
515   return cerr + cerr2*100000.0;
486516}
487517
488518template <int m_N, int _storage_N>
489519ATTR_HOT void netlist_matrix_solver_direct_t<m_N, _storage_N>::store(
490      const double (* RESTRICT V), bool store_RHS)
520      const double (* RESTRICT V), const bool store_RHS)
491521{
492522   for (int i = 0; i < this->N(); i++)
493523   {
r30699r30700
515545
516546        store(new_v, true);
517547
518        if (err > this->m_params.m_accuracy * this->m_params.m_accuracy)
548        if (err > this->m_params.m_accuracy)
519549        {
520550            return 2;
521551        }
r30699r30700
548578   double new_val =  m_RHS[0] / m_A[0][0];
549579
550580   double e = (new_val - net->m_cur_Analog);
551   double cerr = e * e;
581   double cerr = fabs(e);
552582
553583   net->m_cur_Analog = net->m_new_Analog = new_val;
554584
555   if (is_dynamic() && (cerr  > m_params.m_accuracy * m_params.m_accuracy))
585   if (is_dynamic() && (cerr  > m_params.m_accuracy))
556586   {
557587      return 2;
558588   }
r30699r30700
578608   const double d = m_A[1][1];
579609
580610   double new_val[2];
581   new_val[1] = a / (a * d - b * c) * (m_RHS[1] - c / a * m_RHS[0]);
611   new_val[1] = (a * m_RHS[1] - c * m_RHS[0]) / (a * d - b * c);
582612   new_val[0] = (m_RHS[0] - b * new_val[1]) / a;
583613
584614   if (is_dynamic())
585615   {
586616      double err = delta(new_val);
587617      store(new_val, true);
588      if (err > m_params.m_accuracy * m_params.m_accuracy)
618      if (err > m_params.m_accuracy )
589619         return 2;
590620      else
591621         return 1;
r30699r30700
626656
627657        for (int k = 0; k < iN; k++)
628658        {
629            const int pk = k;
630659            double Idrive = 0;
631660
632661            // loop auto-vectorized
633662            for (int i = 0; i < iN; i++)
634                Idrive -= this->m_A[pk][i] * new_v[i];
663                Idrive -= this->m_A[k][i] * new_v[i];
635664
636            const double new_val = (this->m_RHS[pk] + Idrive + this->m_A[pk][pk] * new_v[pk]) / this->m_A[pk][pk];
665            const double new_val = (this->m_RHS[k] + Idrive + this->m_A[k][k] * new_v[k]) / this->m_A[k][k];
637666
638            const double e = (new_val - new_v[k]);
639            cerr += e * e;
640
667            const double e = fabs(new_val - new_v[k]);
668            cerr = (e > cerr ? e : cerr);
641669            new_v[k] = new_val;
642670        }
643        if (cerr > this->m_params.m_accuracy * this->m_params.m_accuracy)
671
672        if (cerr > this->m_params.m_accuracy)
644673        {
645674            resched = true;
646675        }
r30699r30700
745774         const double new_val = net.m_new_Analog * one_m_w[k] + (Idrive + RHS[k]) * w[k];
746775
747776         const double e = (new_val - net.m_new_Analog);
748         cerr += e * e;
777         cerr = (fabs(e) > cerr ? fabs(e) : cerr);
749778
750779         net.m_new_Analog = new_val;
751780      }
752      if (cerr > this->m_params.m_accuracy * this->m_params.m_accuracy)
781      if (cerr > this->m_params.m_accuracy)
753782      {
754783         resched = true;
755784      }
r30699r30700
790819
791820   register_param("FREQ", m_freq, 48000.0);
792821
793   register_param("ACCURACY", m_accuracy, 1e-7);
822   register_param("ACCURACY", m_accuracy, 1e-4);
794823   register_param("GS_LOOPS", m_gs_loops, 5);              // Gauss-Seidel loops
795824    register_param("NR_LOOPS", m_nr_loops, 25);             // Newton-Raphson loops
796825   register_param("PARALLEL", m_parallel, 0);
797826    register_param("GMIN", m_gmin, NETLIST_GMIN_DEFAULT);
798827    register_param("DYNAMIC_TS", m_dynamic, 0);
799   register_param("LTE", m_lte, 1e-3);                     // 1mV diff/timestep
828    register_param("LTE", m_lte, 1e-2);                     // 100mV diff/timestep
800829   register_param("MIN_TIMESTEP", m_min_timestep, 2e-9);   // double timestep resolution
801830
802831   // internal staff
r30699r30700
896925
897926    if (m_params.m_dynamic)
898927    {
899        m_params.m_max_timestep *= 100.0;
928        m_params.m_max_timestep *= 1000.0;
900929    }
901930    else
902931    {
r30699r30700
10091038         }
10101039      }
10111040   }
1012
10131041}
10141042
trunk/src/emu/netlist/analog/nld_solver.h
r30699r30700
7171
7272   class net_entry
7373   {
74       NETLIST_PREVENT_COPYING(net_entry)
75
7674   public:
7775       net_entry(netlist_analog_net_t *net) : m_net(net) {}
7876        net_entry() : m_net(NULL) {}
7977
78        net_entry(const net_entry &rhs)
79        {
80            m_net = rhs.m_net;
81            m_terms = rhs.m_terms;
82            m_rails = rhs.m_rails;
83        }
84
85        net_entry &operator=(const net_entry &rhs)
86        {
87            m_net = rhs.m_net;
88            m_terms = rhs.m_terms;
89            m_rails = rhs.m_rails;
90            return *this;
91        }
92
8093       netlist_analog_net_t * RESTRICT m_net;
8194       netlist_terminal_t::list_t m_terms;
8295       netlist_terminal_t::list_t m_rails;
8396   };
8497
85    ATTR_COLD virtual void setup(netlist_analog_net_t::list_t &nets,
86            NETLIB_NAME(solver) &owner, net_entry *list);
98    ATTR_COLD void setup(netlist_analog_net_t::list_t &nets,
99            NETLIB_NAME(solver) &owner);
87100
88101   NETLIB_NAME(solver) *m_owner;
89102
r30699r30700
92105
93106    int m_calculations;
94107
108    plinearlist_t<net_entry> m_nets;
109    plinearlist_t<netlist_analog_output_t *> m_inps;
110
95111private:
96112
97113    netlist_time m_last_step;
98114    dev_list_t m_steps;
99115    dev_list_t m_dynamic;
100    plinearlist_t<netlist_analog_output_t *> m_inps;
101116
102117    netlist_ttl_input_t m_fb_sync;
103118    netlist_ttl_output_t m_Q_sync;
r30699r30700
108123     * Don't schedule a new calculation time. The recalculation has to be
109124     * triggered by the caller after the netlist element was changed.
110125     */
111    ATTR_HOT double compute_next_timestep(const double hn);
126    ATTR_HOT virtual double compute_next_timestep(const double) = 0;
112127
113128    ATTR_HOT void update_inputs();
114129    ATTR_HOT void update_dynamic();
r30699r30700
140155   ATTR_HOT inline void gauss_LE(double (* RESTRICT x));
141156   ATTR_HOT inline double delta(
142157         const double (* RESTRICT V));
143   ATTR_HOT inline void store(const double (* RESTRICT V), bool store_RHS);
158   ATTR_HOT inline void store(const double (* RESTRICT V), const bool store_RHS);
144159
145    net_entry m_nets[_storage_N];
160    ATTR_HOT virtual double compute_next_timestep(const double);
146161
147162    double m_A[_storage_N][_storage_N];
148163    double m_RHS[_storage_N];
r30699r30700
160175        : m_term(NULL), m_net_this(-1), m_net_other(-1)
161176        {}
162177
163        netlist_terminal_t *m_term;
178        netlist_terminal_t * RESTRICT m_term;
164179      int m_net_this;
165180      int m_net_other;
166181   };

Previous 199869 Revisions Next


© 1997-2024 The MAME Team