Login / Register 0 items | $0.00 New @ KVR
tunca
KVRist
 
476 posts since 26 Mar, 2015

Postby tunca; Mon Feb 05, 2018 9:17 am Re: Halite - an analog circuit simulator in ~1k lines of code

Richard_Synapse wrote:
tunca wrote:Hi!

Thanks for this one!

But i wonder if it's possible to convert this result to plugin or source code?

I'm electric engineer and using Spice programs.I can convert my Spice designs to netlist to use with "Halite".But i would like to convert your design's results to source code...


Halite is source code. So yes you could use it in a plug-in (probably rather for experimental purposes though, due to its performance).

tunca wrote:Can you convert it to Halite,please?I just want to understand how to convert netlists.


See my post above, and have a look at the image. You label the nodes using integers starting from 0 (ground) that's it :)

Richard


Thanks for reply!

But i can't get plot view of output from your example.Any tip?
http://analogobsession.com/ VST, AU, AAX for WIN & MAC
tunca
KVRist
 
476 posts since 26 Mar, 2015

Postby tunca; Mon Feb 05, 2018 9:36 am Re: Halite - an analog circuit simulator in ~1k lines of code

Code: Select all
    //Fairchild Summing Amp
   
    NetList * net = new NetList(20);
   
    net->addComponent(new Voltage(+24, 3, 0));
   
    net->addComponent(new Resistor(3300000, 11, 15)); //R1
    net->addComponent(new Resistor(150, 16, 0)); //R2
    net->addComponent(new Resistor(150000, 1, 5)); //R3
    net->addComponent(new Resistor(560, 15, 0)); //R4
    net->addComponent(new Resistor(3900, 1, 4)); //R5
    net->addComponent(new Resistor(4.7, 8, 7)); //R6
    net->addComponent(new Resistor(4.7, 8, 13)); //R7
    net->addComponent(new Resistor(1, 17, 16)); //R8
    net->addComponent(new Resistor(47, 2, 1)); //R9
    net->addComponent(new Resistor(150000, 10, 9)); //R10
    net->addComponent(new Resistor(680, 9, 0)); //R11

    net->addComponent(new Capacitor(0.33, 15, 0)); //C1
    net->addComponent(new Capacitor(0.0047, 6, 16)); //C2
    net->addComponent(new Capacitor(0.1, 8, 14)); //C3
    net->addComponent(new Capacitor(0.1, 17, 8)); //C4
    net->addComponent(new Capacitor(0.0075, 14, 0)); //C5
    net->addComponent(new Capacitor(0.02, 11, 10)); //C2

    net->addComponent(new BJT(5,11,16)); //Q1
    net->addComponent(new BJT(6, 5, 10)); //Q2
   
    net->addComponent(new Probe(14, 0)); //Out
http://analogobsession.com/ VST, AU, AAX for WIN & MAC
mystran
KVRAF
 
4955 posts since 11 Feb, 2006, from Helsinki, Finland

Postby mystran; Mon Feb 05, 2018 9:41 am Re: Halite - an analog circuit simulator in ~1k lines of code

tunca wrote:But i can't get plot view of output from your example.Any tip?


As I noted in the first post, the plotting code is not included, because it would drag in several megabytes of dependencies and make everything very complicated (not to mention it doesn't even run on Windows yet).

Really this is not a realistic end-user product, because it's missing every single "user friendly" feature that wasn't essentially to get the core simulation working... and the performance is very poor, since it's very naive, but that makes it short and easy to understand. So it is essentially an "extended example" for fellow programmers.
Image <- plugins | forum
mystran
KVRAF
 
4955 posts since 11 Feb, 2006, from Helsinki, Finland

Postby mystran; Mon Feb 05, 2018 9:45 am Re: Halite - an analog circuit simulator in ~1k lines of code

tunca wrote:
Code: Select all
    //Fairchild Summing Amp
   
    NetList * net = new NetList(20);
   
    net->addComponent(new Voltage(+24, 3, 0));
   
    net->addComponent(new Resistor(3300000, 11, 15)); //R1
    net->addComponent(new Resistor(150, 16, 0)); //R2
    net->addComponent(new Resistor(150000, 1, 5)); //R3
    net->addComponent(new Resistor(560, 15, 0)); //R4
    net->addComponent(new Resistor(3900, 1, 4)); //R5
    net->addComponent(new Resistor(4.7, 8, 7)); //R6
    net->addComponent(new Resistor(4.7, 8, 13)); //R7
    net->addComponent(new Resistor(1, 17, 16)); //R8
    net->addComponent(new Resistor(47, 2, 1)); //R9
    net->addComponent(new Resistor(150000, 10, 9)); //R10
    net->addComponent(new Resistor(680, 9, 0)); //R11

    net->addComponent(new Capacitor(0.33, 15, 0)); //C1
    net->addComponent(new Capacitor(0.0047, 6, 16)); //C2
    net->addComponent(new Capacitor(0.1, 8, 14)); //C3
    net->addComponent(new Capacitor(0.1, 17, 8)); //C4
    net->addComponent(new Capacitor(0.0075, 14, 0)); //C5
    net->addComponent(new Capacitor(0.02, 11, 10)); //C2

    net->addComponent(new BJT(5,11,16)); //Q1
    net->addComponent(new BJT(6, 5, 10)); //Q2
   
    net->addComponent(new Probe(14, 0)); //Out


Something to watch out for: the simulator will fail (hard) unless every node of the netlist is connected to something. So if you create the netlist with size of 20, you MUST use every single node from 0 to 19 (inclusive). This is one of those things I did for simplicity, since the code to automatically figure the number of actual nodes needed would add another 200+ lines of complexity (well, maybe not quite that much just for skipping unneeded nodes, but it's still significant).
Image <- plugins | forum
User avatar
Richard_Synapse
KVRian
 
831 posts since 19 Dec, 2010

Postby Richard_Synapse; Mon Feb 05, 2018 9:48 am Re: Halite - an analog circuit simulator in ~1k lines of code

tunca wrote:Thanks for reply!

But i can't get plot view of output from your example.Any tip?


I'm afraid you will have to code everything you need (like plotting, new parts etc.) yourself. What mystran provided is just the essential simulator, as a great educational tool, to show how it can be done.

If your question is how to extract voltages, there is that probe class. What I did in my quick test though is to just grab the voltages directly via net->getMNA().

Richard
Synapse Audio Software - www.synapse-audio.com
tunca
KVRist
 
476 posts since 26 Mar, 2015

Postby tunca; Mon Feb 05, 2018 9:50 am Re: Halite - an analog circuit simulator in ~1k lines of code

mystran wrote:
tunca wrote:
Code: Select all
    //Fairchild Summing Amp
   
    NetList * net = new NetList(20);
   
    net->addComponent(new Voltage(+24, 3, 0));
   
    net->addComponent(new Resistor(3300000, 11, 15)); //R1
    net->addComponent(new Resistor(150, 16, 0)); //R2
    net->addComponent(new Resistor(150000, 1, 5)); //R3
    net->addComponent(new Resistor(560, 15, 0)); //R4
    net->addComponent(new Resistor(3900, 1, 4)); //R5
    net->addComponent(new Resistor(4.7, 8, 7)); //R6
    net->addComponent(new Resistor(4.7, 8, 13)); //R7
    net->addComponent(new Resistor(1, 17, 16)); //R8
    net->addComponent(new Resistor(47, 2, 1)); //R9
    net->addComponent(new Resistor(150000, 10, 9)); //R10
    net->addComponent(new Resistor(680, 9, 0)); //R11

    net->addComponent(new Capacitor(0.33, 15, 0)); //C1
    net->addComponent(new Capacitor(0.0047, 6, 16)); //C2
    net->addComponent(new Capacitor(0.1, 8, 14)); //C3
    net->addComponent(new Capacitor(0.1, 17, 8)); //C4
    net->addComponent(new Capacitor(0.0075, 14, 0)); //C5
    net->addComponent(new Capacitor(0.02, 11, 10)); //C2

    net->addComponent(new BJT(5,11,16)); //Q1
    net->addComponent(new BJT(6, 5, 10)); //Q2
   
    net->addComponent(new Probe(14, 0)); //Out


Something to watch out for: the simulator will fail (hard) unless every node of the netlist is connected to something. So if you create the netlist with size of 20, you MUST use every single node from 0 to 19 (inclusive). This is one of those things I did for simplicity, since the code to automatically figure the number of actual nodes needed would add another 200+ lines of complexity (well, maybe not quite that much just for skipping unneeded nodes, but it's still significant).


Thanks for explanation.

How many nodes should i use? I can see 17 is last node.So i need to create 18 node?

Also i'm getting a Failed To Find A Pivot error.
http://analogobsession.com/ VST, AU, AAX for WIN & MAC
mystran
KVRAF
 
4955 posts since 11 Feb, 2006, from Helsinki, Finland

Postby mystran; Mon Feb 05, 2018 10:50 am Re: Halite - an analog circuit simulator in ~1k lines of code

tunca wrote:How many nodes should i use? I can see 17 is last node.So i need to create 18 node?

Also i'm getting a Failed To Find A Pivot error.


If you're using all nodes from 0 (ground) to 17 then 18 is the correct size for the netlist. Every node in the range actually needs to be used though. If not, then you need to rename nodes to fill in the gaps. I don't see node 12 connected to anything, so that might be the problem (also the only thing connected to node 3 is the voltage source; that's probably also not right).

Also make sure you get the BJT pin order right. At least LTSpice wants "c,b,e" where as Halite wants "b,c,e" order. I probably should have checked what Spice used and matched that, but I don't really want to change it now.

The "failed to find a pivot" error usually means that a node is not connected to anything, because then the node gets an equation that looks like 0*v=0 which doesn't have a unique solution. In theory you can also get that error in some other situations where the circuit equations don't make sense, but I think you'd have to abuse the voltage sources in creative ways to get that with the included components (since rest of the components have some built in resistance specifically to try to avoid ill-defined circuits).

Also keep in mind that if your original Spice schematic drawing uses labels to connect nodes, those need to be assigned the same number, since they are logically the same node.
Image <- plugins | forum
User avatar
Audiority
KVRian
 
712 posts since 15 Nov, 2005, from Italy

Postby Audiority; Wed Feb 07, 2018 8:36 am Re: Halite - an analog circuit simulator in ~1k lines of code

that's great mystran! I will play with it very soon. Right now I'm using various tools to discretize the circuit and get all I need for my code, but the solver fails miserably on small voltage circuits. I will try yours! :)
Progsounds | Audiority | Epic SoundLab
Need a Kontakt scripter? Contact me.
User avatar
Audiority
KVRian
 
712 posts since 15 Nov, 2005, from Italy

Postby Audiority; Wed Feb 07, 2018 8:43 am Re: Halite - an analog circuit simulator in ~1k lines of code

double
Last edited by Audiority on Sun Feb 11, 2018 11:11 am, edited 1 time in total.
Progsounds | Audiority | Epic SoundLab
Need a Kontakt scripter? Contact me.
stratum
KVRAF
 
1852 posts since 29 May, 2012

Postby stratum; Sun Feb 11, 2018 10:20 am Re: Halite - an analog circuit simulator in ~1k lines of code

If there is anybody else who is trying to figure out what this code is doing:

Code: Select all
   void simulateTick()
   {
      int iter;
      for (iter = 0; iter < maxIter; ++iter)
      {
         // restore matrix state and add dynamic values
         updatePre();
         luFactor();
         luForward();
         luSolve();

         if (newton()) break;
      }

      system.time += tStep;

      update();


It seems to be this:
https://stackoverflow.com/questions/297 ... ons-method (see newtonund)

This is similar to the code Urs H. had posted some time ago about a prototype of the repro filter, the difference is that he was calculating dF (the Jacobian matrix) for the whole system while mystran's code seems to be dealing with each nonlinear component separately. I guess both are equivalent in some sense.

An unrelated note that may not be obvious about Richard's fuzz face circuit above: A realistic simulation requires a rough model of the guitar pickup, it's not a voltage source with zero internal resistance. Whether this actually matters or not depends on whether the voltage at node (2) ever drops to a low enough value at the same time the incoming signal amplitude being high enough to cause a temporary change in the impedance seen at that node.
~stratum~
mystran
KVRAF
 
4955 posts since 11 Feb, 2006, from Helsinki, Finland

Postby mystran; Sun Feb 11, 2018 11:14 am Re: Halite - an analog circuit simulator in ~1k lines of code

stratum wrote:This is similar to the code Urs H. had posted some time ago about a prototype of the repro filter, the difference is that he was calculating dF (the Jacobian matrix) for the whole system while mystran's code seems to be dealing with each nonlinear component separately. I guess both are equivalent in some sense.


It's not really even different; the MNA matrix would be the Jacobian if the system was an ODE. In practice it's a DAE rather than an ODE (some of the equations are algebraic rather than differential; I have no idea if it would still be fine to call it Jacobian, but that doesn't really matter), but in practice that doesn't matter as far as the algorithm is concerned. There is also no technical reason in the current solver for the non-linearities need to be "separate" the way I've made them, it's essentially just a matter of how you want to describe the equations.

In practice, once you add a pre-factorization stage to avoid solving the whole matrix every time-step and iteration, it suddenly makes a whole lot of sense to describe the equations in such a way that all the non-linear stuff can be pivoted into a small sub-matrix at the bottom-right and the reason I've described the components the way I do is to minimize the size of the non-linear submatrix (even though it doesn't matter for the naive solver). This way you can do the resistive parts of the circuits once, the reactive components (eg. one dimensions per capacitor/inductor) once per time-step, and just iterate the non-linear parts (eg. one dimensions per dimension of non-linearity) and the smaller the "innermost" non-linear submatrix ends up the faster the simulation will run.

Keep in mind that any mathematically equivalent way to describe the system is equally valid, just like any equivalent way to solve the matrix equation is equally valid. As such, you can manipulate the equations as much as you want, in order to come up with a form that you can solve as efficiently as possible. :)

An unrelated note that may not be obvious about Richard's fuzz face circuit above: A realistic simulation requires a rough model of the guitar pickup, it's not a voltage source with zero internal resistance.


You could make the voltage source resistive if you wanted to (or just add series resistance which does the same thing). Whether that's an accurate model is another thing, since the pickup is likely to have some reactive impedance as well.... but then again you can also put another pedal as a buffer between your guitar and your fuzz face and if you do that then the "ideal voltage source" approximation is suddenly fine again.
Image <- plugins | forum
stratum
KVRAF
 
1852 posts since 29 May, 2012

Postby stratum; Sun Feb 11, 2018 11:38 am Re: Halite - an analog circuit simulator in ~1k lines of code

Thanks for the explanation. Since I cannot visualize the multidimensional surface the newton's algorithm travels in this case, I can't understand the difference fully, but I guess as long as the algorithm does converge, that does not matter.

As for the fuzzface, it's a simple circuit made with unreliable components and it's a bit tricky to get it right as far as I know. I have never bothered to build one to see myself, I'm not a fan of them, but here is a description by somebody who did: http://www.geofex.com/article_folders/f ... fftech.htm As far as I can see this article gives enough reasons to be concerned about the internal resistance of the source.
Last edited by stratum on Sun Feb 11, 2018 11:41 am, edited 1 time in total.
~stratum~
User avatar
Richard_Synapse
KVRian
 
831 posts since 19 Dec, 2010

Postby Richard_Synapse; Sun Feb 11, 2018 11:41 am Re: Halite - an analog circuit simulator in ~1k lines of code

stratum wrote:An unrelated note that may not be obvious about Richard's fuzz face circuit above: A realistic simulation requires a rough model of the guitar pickup, it's not a voltage source with zero internal resistance. Whether this actually matters or not depends on whether the voltage at node (2) ever drops to a low enough value at the same time the incoming signal amplitude being high enough to cause a temporary change in the impedance seen at that node.


It was just a test I whipped up quickly for fun, because the circuit happens to use elements that mystran already provided in his code. Another issue with the example is that the Fuzz parameter is hardwired for simplicity, but it should really have that cap attached to the Fuzz pot. And last but not least the transistor models are very important for the behavior of this specific circuit, so there is really a lot to do if you want to have an accurate reproduction of a real Fuzz Face.

Richard
Synapse Audio Software - www.synapse-audio.com
stratum
KVRAF
 
1852 posts since 29 May, 2012

Postby stratum; Sun Feb 11, 2018 11:48 am Re: Halite - an analog circuit simulator in ~1k lines of code

It was just a test I whipped up quickly for fun. A second issue with the example is that the Fuzz parameter is hardwired for simplicity, but it should really have that cap attached to the Fuzz pot. And last but not least the transistor models are very important for the behavior of this specific circuit, so there is really a lot to do if you want to have an accurate reproduction of a real Fuzz Face.


I have an old generation Line6 pod pro and their model (or interpretation of the typical use case) simulates a faint amount of blocking distortion on bass strings. I guess that's the behavior expected from a correctly built one, and the coupling capacitor between the pickup and the first transistor seems to be the only possible source for this behavior.
~stratum~
mystran
KVRAF
 
4955 posts since 11 Feb, 2006, from Helsinki, Finland

Postby mystran; Sun Feb 11, 2018 12:25 pm Re: Halite - an analog circuit simulator in ~1k lines of code

stratum wrote:Thanks for the explanation. Since I cannot visualize the multidimensional surface the newton's algorithm travels in this case, I can't understand the difference fully, but I guess as long as the algorithm does converge, that does not matter.


I doubt anyone can really visualise the hyper-surface, but there's no good reason to even try.

Essentially the "matrix" is just a set of linear equations. When the equations we want to solve are non-linear, we pick some estimate and find the linear tangent (hyper-)plane for the "true" non-linear surface at that point. If the non-linearities are "separate" you can do this by finding the partial derivatives one dimension at a time, but there is real reason it has to be this way (it's just convenient in many cases). Then we put the tangent plane (or projections of it) back to the equations where the non-linearities where and try again until the estimate no longer changes (which implies the tangents won't change either).

Also when it comes to transient analysis, we can usually just reuse the tangent plane from the previous time-step and skip the initial estimate completely. This generally works wonders when the circuit state is changing "slowly" in comparison to the time-step and in case of an (almost) static circuit it means we don't even need to evaluate the non-linearities at all (which is why you can get "zero iterations" with Halite in some cases). With lots of high frequency stuff going on this might not be the ideal choice, but in that case you have other problems like aliasing to deal with and the right thing to do is to decrease the time-step (ie. increasing the sampling rate).

The real difference (besides the different approach to "initial guess") between my code and the code from Urs is that he iterates on the error residue rather than the values directly. This is mathematically equivalent and potentially a bit better numerically (and in some cases can be profitable since it can save some iterations if numerical precision starts becoming an issue), but adds a little bit of overhead in the main solver, especially if you want to early-out those dimensions that have already converged, so I didn't bother. LU even with just partial pivoting is usually fairly well behaved anyway, so it's not a huge deal either way.

The only truly "weird stuff" that I do is with the capacitors, where rather than solving for the voltage or current over the capacitors, I just plug in an algebraic equation (which makes little sense in terms of the actual circuit) to solve for trapezoidal TDF2 state directly, which then saves a separate integration step, since you can just pick the new value directly (ie. the integration is done as a by-product of solving rest of the system). While the downside of this is that the integration method is now hard-coded into the stamps, I left it in to illustrate how you can plug pretty much arbitrary linear equations into the system and have it solved together with everything else.
Image <- plugins | forum
PreviousNext

Moderator: Moderators (Main)

Return to DSP and Plug-in Development