Previous 199869 Revisions Next

r26540 Sunday 8th December, 2013 at 15:38:46 UTC by Couriersud
Netlist: Math helps ... In the end the solution of the analog subsystem boils down to

(G - D) * V = I

with G being the conductance matrix, D a diagonal matrix with total conductance on the diagonal elements, V the net voltage vector and I the current vector.

By using solely two terminal devices, we can simplify the whole calculation significantly. A BJT now is a four terminal device with two terminals being connected internally.

The system is solved using an iterative approach:

G * V - D * V = I

assuming V=Vn=Vo

Vn = D-1 * (I - G * Vo)

The above was already used in the code. However, with a pure two terminal device approach going forward we can e.g. further optimize. G typically is a sparse matrix.
[src/emu/netlist]nl_base.h
[src/emu/netlist/devices]nld_system.c nld_system.h nld_twoterm.c nld_twoterm.h

trunk/src/emu/netlist/nl_base.h
r26539r26540
251251        RESISTOR  = 4,   // Resistor
252252        CAPACITOR = 5,   // Capacitor
253253        DIODE     = 6,   // Diode
254        BJT_SWITCH_NPN = 7,  // BJT(Switch)
254        BJT_SWITCH = 7,  // BJT(Switch)
255255    };
256256
257257   ATTR_COLD netlist_object_t(const type_t atype, const family_t afamily);
r26539r26540
346346    double m_Idr; // drive current
347347    double m_g; // conductance
348348
349    netlist_terminal_t *m_otherterm;
349350};
350351
351352
r26539r26540
489490    ATTR_HOT inline void push_to_queue(const netlist_time &delay);
490491    ATTR_HOT bool is_queued() { return m_in_queue == 1; }
491492
493    // m_terms is only used by analog subsystem
494    typedef netlist_list_t<netlist_terminal_t *> terminal_list_t;
495    terminal_list_t m_terms;
496
492497protected:
493498
494499    /* prohibit use in device functions
trunk/src/emu/netlist/devices/nld_system.h
r26539r26540
8080// ----------------------------------------------------------------------------------------
8181
8282NETLIB_DEVICE_WITH_PARAMS(solver,
83        typedef netlist_list_t<netlist_core_terminal_t *> terminal_list_t;
8483        typedef netlist_list_t<netlist_net_t *>      net_list_t;
8584        typedef netlist_list_t<netlist_core_device_t *>      dev_list_t;
8685
r26539r26540
9897        netlist_time m_last_step;
9998        netlist_time m_nt_sync_delay;
10099
101        terminal_list_t m_terms;
102        terminal_list_t m_inps;
100        dev_list_t m_dynamic;
101        dev_list_t m_inps;
103102        dev_list_t m_steps;
104103
105104public:
trunk/src/emu/netlist/devices/nld_twoterm.c
r26539r26540
1010// nld_twoterm
1111// ----------------------------------------------------------------------------------------
1212
13ATTR_COLD NETLIB_NAME(twoterm)::NETLIB_NAME(twoterm)(const family_t afamily) :
14        netlist_device_t(afamily)
15{
16    m_P.m_otherterm = &m_N;
17    m_N.m_otherterm = &m_P;
18}
19
1320NETLIB_START(twoterm)
1421{
1522}
r26539r26540
3441
3542NETLIB_UPDATE_PARAM(R)
3643{
37    m_g = 1.0 / m_R.Value();
44    set_R(m_R.Value());
3845}
3946
4047NETLIB_UPDATE(R)
r26539r26540
138145    register_terminal("B", m_B);
139146    register_terminal("C", m_C);
140147    register_terminal("E", m_E);
148    register_terminal("EB", m_EB);
141149
150    m_setup->connect(m_E, m_EB);
151
152    m_B.m_otherterm = &m_EB;
153    m_EB.m_otherterm = &m_B;
154    m_C.m_otherterm = &m_E;
155    m_E.m_otherterm = &m_C;
142156}
143157
144158NETLIB_UPDATE(Q)
trunk/src/emu/netlist/devices/nld_twoterm.h
r26539r26540
6565class NETLIB_NAME(twoterm) : public netlist_device_t
6666{
6767public:
68    ATTR_COLD NETLIB_NAME(twoterm)(const family_t afamily)
69    : netlist_device_t(afamily), m_g(0.0), m_V(0.0), m_I(0.0) { }
68    ATTR_COLD NETLIB_NAME(twoterm)(const family_t afamily);
7069
7170    netlist_terminal_t m_P;
7271    netlist_terminal_t m_N;
7372
7473    virtual NETLIB_UPDATE_TERMINALS()
7574    {
76        m_P.m_g = m_N.m_g = m_g;
77        m_N.m_Idr = (m_P.net().Q_Analog() - m_V) * m_g + m_I;
78        m_P.m_Idr = (m_N.net().Q_Analog() + m_V) * m_g - m_I;
79        //printf("%f %f %f %f\n", m_N.m_Idr, m_P.m_Idr, m_N.net().Q_Analog(), m_P.net().Q_Analog());
8075    }
76
77    ATTR_HOT inline void set(const double G, const double V, const double I)
78    {
79        m_P.m_g = m_N.m_g = G;
80        m_N.m_Idr = ( -V) * G + I;
81        m_P.m_Idr = (  V) * G - I;
82    }
8183protected:
8284    ATTR_COLD virtual void start();
8385    ATTR_HOT ATTR_ALIGN void update();
8486
85    double m_g; // conductance
86    double m_V; // internal voltage source
87    double m_I; // internal current source
8887private:
8988};
9089
r26539r26540
9796public:
9897    ATTR_COLD NETLIB_NAME(R)() : NETLIB_NAME(twoterm)(RESISTOR) { }
9998
100    inline void set_R(const double R) { m_g = 1.0 / R; }
99    inline void set_R(const double R) { set(1.0 / R, 0.0, 0.0); }
101100
102101protected:
103102    ATTR_COLD virtual void start();
r26539r26540
119118
120119    ATTR_HOT void step_time(const double st)
121120    {
122        m_g = m_P.m_g = m_N.m_g = m_C.Value() / st;
123        m_I = -m_g * (m_P.net().Q_Analog()- m_N.net().Q_Analog());
121        double G = m_C.Value() / st;
122        double I = -G * (m_P.net().Q_Analog()- m_N.net().Q_Analog());
123        set(G, 0.0, I);
124124    }
125125
126126protected:
r26539r26540
151151        const double eVDVt = exp(m_Vd * m_VtInv);
152152        const double Id = m_Is * (eVDVt - 1.0);
153153
154        m_g = m_Is * m_VtInv * eVDVt;
154        double G = m_Is * m_VtInv * eVDVt;
155155
156        m_I = (Id - m_Vd * m_g);
157        //printf("Vd: %f %f %f %f\n", m_Vd, m_g, Id, m_I);
156        double I = (Id - m_Vd * G);
158157
159        NETLIB_NAME(twoterm)::update_terminals();
158        set(G, 0.0, I);
160159    }
161160
162161protected:
r26539r26540
235234    netlist_terminal_t m_C;
236235    netlist_terminal_t m_E;
237236
237    netlist_terminal_t m_EB;
238
238239protected:
239240    ATTR_COLD virtual void start();
240241
r26539r26540
247248{
248249public:
249250    ATTR_COLD NETLIB_NAME(QBJT_switch)()
250    : NETLIB_NAME(QBJT)(_type, BJT_SWITCH_NPN), m_gB(NETLIST_GMIN), m_gC(NETLIST_GMIN), m_V(0.0) { }
251    : NETLIB_NAME(QBJT)(_type, BJT_SWITCH), m_gB(NETLIST_GMIN), m_gC(NETLIST_GMIN), m_V(0.0) { }
251252
252253    NETLIB_UPDATE_TERMINALS()
253254    {
r26539r26540
257258        double vE = m_E.net().Q_Analog();
258259        double vB = m_B.net().Q_Analog();
259260
261        //printf("diff %f = %f - %f\n", vB - vE, vB, vE);
260262        if (vB - vE < m_V )
261263        {
262264            // not conducting
r26539r26540
265267            gc = NETLIST_GMIN;
266268        }
267269
268        m_B.m_g = m_E.m_g = gb;
269        m_C.m_g = gc;
270        m_B.m_g = m_EB.m_g = gb;
271        m_C.m_g = m_E.m_g = gc;
270272
271        m_B.m_Idr = (vE + v) * gb;
272        m_C.m_Idr = (vE) * gc;
273        m_E.m_Idr = (vB - v) * gb + m_C.net().Q_Analog() * gc;
273        m_B.m_Idr  = (  v) * gb;
274        m_EB.m_Idr = ( -v) * gb;
275        m_C.m_Idr  = 0.0;
276        m_E.m_Idr =  0.0;
274277    }
275278
276279protected:
277280
278281    ATTR_COLD void update_param();
279282
280    double m_gB; // conductance
281    double m_gC; // conductance
283    double m_gB; // base conductance / switch on
284    double m_gC; // collector conductance / switch on
282285    double m_V; // internal voltage source
286
283287private:
284288};
285289
trunk/src/emu/netlist/devices/nld_system.c
r26539r26540
129129            switch (p->type())
130130            {
131131                case netlist_terminal_t::TERMINAL:
132                    m_terms.add(p);
132                    switch (p->netdev().family())
133                    {
134                        case CAPACITOR:
135                            if (!m_steps.contains(&p->netdev()))
136                                m_steps.add(&p->netdev());
137                            break;
138                        case DIODE:
139                        case BJT_SWITCH:
140                            if (!m_dynamic.contains(&p->netdev()))
141                                m_dynamic.add(&p->netdev());
142                            break;
143                        default:
144                            break;
145                    }
146                    pn->object()->m_terms.add(static_cast<netlist_terminal_t *>(p));
133147                    NL_VERBOSE_OUT(("Added terminal\n"));
134                    if (p->netdev().isFamily(CAPACITOR))
135                        if (!m_steps.contains(&p->netdev()))
136                            m_steps.add(&p->netdev());
137148                    break;
138149                case netlist_terminal_t::INPUT:
139                    m_inps.add(p);
150                    if (!m_inps.contains(&p->netdev()))
151                        m_inps.add(&p->netdev());
140152                    NL_VERBOSE_OUT(("Added input\n"));
141153                    break;
142154                default:
r26539r26540
174186            p->object()->step_time(delta.as_double());
175187    }
176188    do {
189        /* update all non-linear devices  */
190        for (dev_list_t::entry_t *p = m_dynamic.first(); p != NULL; p = m_dynamic.next(p))
191            p->object()->update_terminals();
192
177193        resched = false;
178194
179195        for (net_list_t::entry_t *pn = m_nets.first(); pn != NULL; pn = m_nets.next(pn))
r26539r26540
183199            double gtot = 0;
184200            double iIdr = 0;
185201
186            for (netlist_core_terminal_t *p = net->m_head; p != NULL; p = p->m_update_list_next)
202            for (netlist_net_t::terminal_list_t::entry_t *e = net->m_terms.first(); e != NULL; e = net->m_terms.next(e))
187203            {
188                if (p->isType(netlist_core_terminal_t::TERMINAL))
189                {
190                    netlist_terminal_t *pt = static_cast<netlist_terminal_t *>(p);
191                    netlist_core_device_t &dev = pt->netdev();
192#if 0
193                    switch (pt->family())
194                    {
195                        case RESISTOR:
196                            static_cast<NETLIB_NAME(R) &>(dev).update_terminals();
197                            break;
198                        case CAPACITOR:
199                            static_cast<NETLIB_NAME(C) &>(dev).update_terminals();
200                            break;
201#if 1
202                        case DIODE:
203                            static_cast<NETLIB_NAME(D) &>(dev).update_terminals();
204                            break;
205                        case BJT_SWITCH_NPN:
206                            static_cast<NETLIB_NAME(QNPN_switch) &>(dev).update_terminals();
207                            break;
208#endif
209                        default:
210                            dev.update_terminals();
211                            break;
212                    }
213#else
214                    dev.update_terminals();
215#endif
216                    gtot += pt->m_g;
217                    iIdr += pt->m_Idr;
218                }
204                netlist_terminal_t *pt = e->object();
205                gtot += pt->m_g;
206                iIdr += pt->m_Idr + pt->m_g * pt->m_otherterm->net().Q_Analog();
219207            }
220208
221209            double new_val = iIdr / gtot;
r26539r26540
227215            NL_VERBOSE_OUT(("Info: %d\n", pn->object()->m_num_cons));
228216            NL_VERBOSE_OUT(("New: %lld %f %f\n", netlist().time().as_raw(), netlist().time().as_double(), new_val));
229217        }
230    } while (resched && (resched_cnt < 1));
218    } while (resched && (resched_cnt < 5));
231219    //if (resched_cnt >= 5)
232220    //    printf("rescheduled\n");
233221    if (resched)
234222    {
235223        schedule();
236224    }
237#if 1
238225    else
239#endif
240226    {
241227        /* update all inputs connected */
242#if 0
243        for (net_list_t::entry_t *pn = m_nets.first(); pn != NULL; pn = m_nets.next(pn))
244        {
245            if (pn->object()->m_cur.Analog != pn->object()->m_last.Analog)
246            {
247                for (netlist_core_terminal_t *p = pn->object()->m_head; p != NULL; p = p->m_update_list_next)
248                {
249                    if (p->isType(netlist_terminal_t::INPUT))
250                        p->netdev().update_dev();
251                }
252            }
253            pn->object()->m_last.Analog = pn->object()->m_cur.Analog;
254        }
255#else
256        for (terminal_list_t::entry_t *p = m_inps.first(); p != NULL; p = m_inps.next(p))
257            p->object()->netdev().update_dev();
258#endif
228        for (dev_list_t::entry_t *p = m_inps.first(); p != NULL; p = m_inps.next(p))
229            p->object()->update_dev();
230
259231        /* step circuit */
260232        if (!m_Q_step.net().is_queued())
261233            m_Q_step.net().push_to_queue(m_inc);

Previous 199869 Revisions Next


© 1997-2024 The MAME Team