Circuit simulation
Lucipy ships two approaches to simulate a circuit configuration which both solve circuit as a first order differential equation system using idealized math elements.
The method
Routing.to_sympy()provides an export to a system of equations written symbolically, translating the analog circuit to its idealized math counterpart. This system can then be solved analytically or numerically.The class
Simulationdoes something similar but without making use of Sympy, instead directly working on the UCI matrix. It computes the right hand side function by loop unrolling the LUCIDAC multipliers.
Both approaches are currently limited to the LUCIDAC standard configuration
of Math block elements. This section concentrates on the approach provided
by Simulation. Furher approaches are discussed in the section
Alternative simulation approaches.
Guiding principle of this simulator
This Simulator adopts the convention with the column order
M1 Mul
M0 Int
The basic idea is to relate the standard first order differential equation \(\dot{\vec x} = \vec f(\vec x)\) with the LUCIDAC system matrix \(M = UCI\) that relates Math-block inputs with Math-block outputs. We cut the circuit at the analog integrators and identity \(\dot x^{out} = f(x^{in})\). Diagrammatically,
+---> dot x -->[ MInt ]--> x ---+
| |
| |
+---------...-[ UCI Matrix ]<----+
This feedback network is linearized as in
ic = state^OUT -> U C I -> state^IN -> M -> state^OUT -> ...
In sloppy words this means that \(f := M~x^{in}\). However, it is not as simple as that, because the LUCIDAC also contains non-integrating compute elements, in particular the multipliers. By splitting the matrix \(M \in \mathbb{R}^{32\times 32}\) into four smaller ones \(A, B, C, D \in \mathbb{R}^{16 \times 16}\) as in
Note how this notation maps implicit summing of the UCI matrix on the summing property of a matrix multiplication.
We can easily seperate the actual state vector variables \(\vec x := I\) from the derived variables \(M\). This is done by loop unrolling, which means to compute the effect of the Mul-Block while evaluating \(f\).
First, let us write out the vectors
This is a definition for REV0 where the superfluous Math block outputs are used for constant givers \(c_i = 1\).
The algorithm is as following: The set of equations is written out as
and then compute (eq I) \(M^{in} = g(I^{out})\) with an initial guess \(M^{out}=0\) and then iteratively reinserting the solution for \(M^{out}\). (eq II) boils then down to \(I^{in} = f(I^{out})\) and thus solving the RHS from the beginning.
Alternative simulation approaches
For sure there are many other ways how one could simulate the LUCIDAC. A few approaches are presented here with their advantages and disadvantages.
Graph/Netlist simulation
The prefered way of electronics simulation is to set up the actual netlist graph. Given that the UCI matrix is basically the adjacency matrix for this graph, this is not too hard. One can then linarize this graph, making it a forest of compute trees each leading to the computation of a single state variable. Such a linearization can happen at compile time or at evaluation/run time. The disadvantage of this approach is that the actual matrix structure of the LUCIDAC is rather lost, in particular the implicit summing structure.
The tensorial simulation approach
Loop unrolling at compile time results in some tensorial structure (Einstein sum convention applies)
Computing E, F, G from A, B, C is definetly possible and would allow for a “full closed” (yet spare matrix) description of the LUCIDAC. In such a formulation
\(D\) collects all linear terms
\(E\) collects all quadratic terms (think of \(\dot x = xy\)), i.e. computations that require one multipler.
\(F\) collects all terms requiring two multipliers. Think of \(\dot x = m_2\) and \(m_2 = x m_1\) and \(m_1 = x x\).
\(G\) collects all terms requiring three multipliers
\(H\) collects all terms requiring all four multipliers of the system.
Despite \(H\) is a tensor of rank 6, there are only a handful of realizations of this matrix possible, given the four multipliers of the system. That means: A lot of indices for actually performing very little work. Despite a theoretical study, such a “compilation” step has little advantage. For sure in the numpy model, setting up large spare matrices before doing a “hot” computation might probably save time. However, the systems for LUCIDAC are nevertheless so small that no digital computer will have a hard time simulating even in vanilla python.
Including imperfection
A first option to model the non-idealities of analog computing hardware is to introduce transfer functions which model what computing elements are doing. We have a Matlab/Simulink simulator available which uses this kind of modeling. More realistic models are available with Spice but require to describe both the reconfigurable hardware as well as its configuration within Spice. However, we provide software to generate these files soon.
API Reference
- class lucipy.simulator.Simulation(circuit, realtime=False)[source]
A simulator for the LUCIDAC. Please refer to the documentation for a theoretical and practical introduction.
Important properties and limitations:
Currently only understands mblocks
M1 = MulandM0 = IntUnrolls Mul blocks at evaluation time, which is slow
Note that the system state is purely hold in I.
Note that k0 is implemented in a way that 1 time unit = 10_000 and k0 slow results are thus divided by 100 in time. Should probably be done in another way so the simulation time is seconds.
- Parameters:
realtime – If set, resulting times will be in seconds. If not, k0=10.000 equals time unit 1.
- nonzero()[source]
Returns the number of nonzero entries in each 2x2 block matrix. This makes it easy to count the different type of connections in a circuit (like INT->INT, MUL->INT, INT->MUL, MUL->MUL).
- solve_ivp(t_final, clip=True, ics=None, **kwargs_for_solve_ivp)[source]
Solves the initial value problem defined by the LUCIDAC Circuit.
Good-to-know options for solve_ivp:
- Parameters:
t_final – Final time to run simulation to. Start time is always 0. Units depend on
realtime=True/Falsein constructor.ics – Initial Conditions to start with. If none given, the MIntBlock configuration is used. If given, a list with
0 <= size <= 8has to be provided.clip – Whether to carry out bounded-in-bounded-out value clipping as a real analog computer would do
dense_output – value
True``allows for interpolating on ``res.sol(linspace(...))method – value
LSODAis good for stiff problems