brummer10 / guitarix

guitarix virtual versatile amplification for Jack/Linux
236 stars 24 forks source link

build-plug.py "singular matrix" error #109

Open FalconBry opened 2 years ago

FalconBry commented 2 years ago

Hello, I am trying to use build-plug.py on a very basic diode clipper schematic. diode_clipper_asym

However as soon as I add the extra series diode D3 to get asymmetric clipping the script errors as follow;

$ python build-plug.py -i diode_clipper_asym.sch --table_neg 1 -x 2.0 --build

Input file 1: diode_clipper_asym.sch module_id: diode_clipper_asym ['D3', 'DIODE', 'Is=10e-12,mUt=30e-3', 'unnamed_net3', 'GND'] ['D1', 'DIODE', 'Is=10e-12,mUt=30e-3', 'unnamed_net1', 'unnamed_net3'] ['D2', 'DIODE', 'Is=10e-12,mUt=30e-3', 'GND', 'unnamed_net1'] ['R1', 'RESISTOR', '2.2k', 'unnamed_net1', 'unnamed_net2'] ['C1', 'CAPACITOR', '4.7u', 'unnamed_net2', 'V1'] ['OUT1', 'OUTPUT', 'None', 'unnamed_net1'] ['IN1', 'INPUT', 'None', 'V1']

S = ((D(3), 'u3', GND,), (D(1), 'u1', 'u3',), (D(2), GND, 'u1',), (R(1), 'u1', 'u2',), (C(1), 'u2', 'V1',), (OUT, 'u1',), (IN, 'V1',), ) V = {C(1): 4.7e-6, D(1): dict(Is=10e-12, mUt=30e-3), D(2): dict(Is=10e-12, mUt=30e-3), D(3): dict(Is=10e-12, mUt=30e-3), R(1): 2.2e3, }

Traceback (most recent call last): File "build-plug.py", line 680, in main(sys.argv[1:]) File "build-plug.py", line 677, in main dk.build() File "build-plug.py", line 552, in build faustdsp, faustui = c1.get_faust_code(filename=str(dspname)) File "./analog.py", line 779, in get_faust_code self._ensure_filter(symbolic=symbolic) File "./analog.py", line 417, in _ensure_filter sim = dk_simulator.SimulatePy(dk_simulator.EquationSystem(p), self.solver, self.dc_method) File "./dk_simulator.py", line 756, in init self.Si = self.S.I File "/usr/lib/python2.7/dist-packages/numpy/matrixlib/defmatrix.py", line 972, in getI return asmatrix(func(self)) File "/usr/lib/python2.7/dist-packages/scipy/linalg/basic.py", line 687, in inv raise LinAlgError("singular matrix") numpy.linalg.linalg.LinAlgError: singular matrix lex@msi:~/guitarlex/build/gschem-schematics$

brummer10 commented 2 years ago

Hi Yes, that is a known issue. dklib fail to create a IIR filter for that case. Still dkbuilder is a experimental tool, and it has some drawbacks. To work around this issue, I use different diode types instead cascaded diodes.

FalconBry commented 2 years ago

I see. Btw; It seems the tool generates an IIR filter even if there is no filtering at all in the circuit. If I remove C1 in the above circuit it still generates a fi.iir in the faust file.

brummer10 commented 2 years ago

Yes. The first thing we do is calculate the linear response as a IIR filter. Then we measure the response in the non-linear domain. Hence, it's always a IIR filter running into a interpolation table, or for the case the circuit is strict linear (like a EQ or a Wah) simple just a IIR filter. We've had attempts to create direct C++ code but it turns out that the dsp load of the generated filters was much to high then been usable. So we striped it down to generate faust IIR filter coefficients for linear response.

FalconBry commented 2 years ago

"The first thing we do is calculate the linear response as a IIR filter." I see. Is it calculated for the entire circuits linear response? I mean; most analog circuits have EQ filtering in multiple places. Often before, between and after several cascaded non-linear sections. Does the tool maintain that order for us or must we split the circuit into sections and glue the resulting code together afterwards?

brummer10 commented 2 years ago

You must split the circuit by yourself, but the tool will glue it together to one plugin. Example is shown here: https://linuxmusicians.com/viewtopic.php?f=44&t=19586 and here one with multiple non-linear parts: https://linuxmusicians.com/viewtopic.php?f=44&t=19806

FalconBry commented 2 years ago

Hello, Ok, I am exploring the possibilities of the dkbuilder tool. I noticed that feeding it a circuit like; voxac30_s02_pre_eq ...it generates the variable IIR filter response but doesn't implement the volume potentiometer. That is, no code generation for the gain reduction of the pot. Is that normal behavior? I guess we have to add that manually?

Btw; do you perhaps know of a method or program under linux to plot the bode response of an LV2 plugin (or whatever audio plugin format/code)? Thank you.

brummer10 commented 2 years ago

That happen when the analyser can't fetch any influence of a variable resistor. Bu, I tried your circuit from above and get it working as expected. For reference I've attached the schematic I used. Here is the resulting filter I got out of it:


/*******************************************************************************
**************************** File generated by *********************************
********************************************************************************
 ./build-plug.py -i voxac30_volume.sch -b
*******************************************************************************/

// generated automatically
// DO NOT MODIFY!
declare id "voxac30_volume";
declare name "voxac30_volume";
declare category "Extern";
declare shortname "voxac30_volume";
declare description "voxac30_volume";

import("stdfaust.lib");

/*******************************************************************************
  * voxac30_volume generated by dkbuiler from voxac30_volume.sch
*******************************************************************************/

p1 = pre : fi.iir((b0/a0,b1/a0,b2/a0),(a1/a0,a2/a0)) with {
    LogPot(a, x) = ba.if(a, (exp(a * x) - 1) / (exp(a) - 1), x);
    Inverted(b, x) = ba.if(b, 1 - x, x);
    s = 0.993;
    fs = float(ma.SR);
    pre = _;

    gain = vslider("gain[name:gain][style:knob]", 0.5, 0, 1, 0.01) : Inverted(0) : LogPot(3) : si.smooth(s);

    b0 = gain*(-8.34298338411429e-10*pow(fs,2)*gain + fs*(8.34298338411429e-10*fs + 8.34298338411429e-6));

    b1 = gain*(1.66859667682286e-9*pow(fs,2)*gain - 1.66859667682286e-9*pow(fs,2));

    b2 = gain*(-8.34298338411429e-10*pow(fs,2)*gain + fs*(8.34298338411429e-10*fs - 8.34298338411429e-6));

    a0 = fs*(3.33719335364572e-11*fs + 1.03452993963017e-5) + gain*(fs*gain*(-8.35966935088252e-10*fs - 5.00579003046858e-7) + fs*(8.02595001551795e-10*fs - 1.15133170700777e-6) + 0.000834298338411429) + 0.0166859667682286;

    a1 = -6.67438670729143e-11*pow(fs,2) + gain*(1.6719338701765e-9*pow(fs,2)*gain - 1.60519000310359e-9*pow(fs,2) + 0.00166859667682286) + 0.0333719335364572;

    a2 = fs*(3.33719335364572e-11*fs - 1.03452993963017e-5) + gain*(fs*gain*(-8.35966935088252e-10*fs + 5.00579003046858e-7) + fs*(8.02595001551795e-10*fs + 1.15133170700777e-6) + 0.000834298338411429) + 0.0166859667682286;
};

process =  p1 ;

voxac30_volume.sch.tar.gz

build-plug.py have a option to plot the filter, as well faust have some options to do a plot for the files, other than that Ardour has a option to show the frequency and power response.

brummer10 commented 2 years ago

For the fun I made quickly the power amp stage of the Voxac30: voxac30_poweramp.sch.tar.gz

It should replace the stage_03. I build a guitarix plugin from it by: ./build-plug.py -i voxac30_poweramp.sch -g 1 -r 1=0.3 -b

FalconBry commented 2 years ago

Yes, you are right, the generated code DOES work as intended. I checked by comparing the plugin's magnitude response with SPICE bode plot of the same circuit. I was misled by the log potentiometer. Even though I had request a LOG pot it hardly felt like one. So I changed the C code to scale the slider value as v^3. This gives a much more realistic feel on the potmeter control.

I will take a look at your vox amp later on:)

Btw; do you still have the same schematics you used on the hoffman plexi; https://linuxmusicians.com/viewtopic.php?f=44&t=19806?

brummer10 commented 2 years ago

To make a controller logarithmic, you must add ,a=3 to the value field. were the value (3 - 9) sets the logarithmic scale. I'll check my schematic folders to find the plexi ones.

brummer10 commented 2 years ago

Here they are:

plexi-schematics.tar.gz

FalconBry commented 2 years ago

Aha! Are all these things documented somewhere? I don't want to bother you too much with all these questions. Btw; Is it ok to continue our discussion here or is there a more appropriate place?

Thank you for the schematics.

brummer10 commented 2 years ago

This is the right place here, and I'm open to answer all questions about it (and fetch your input). At least we make it open source for that reason. Documentation is were it all leaks. For the Plexi, for example I use the schematics from Hoffmann as inspiration. I know from all my research in this area that values given in schematics have to be take with care, often, the theoretical value in the circuit drawing differ a lot from the real value. Hence I experience a lot with variations in that field and check the results by plot and ear. That isn't documented anywhere.

FalconBry commented 2 years ago

Ok, great! Yes, I'm aware of errors and or differences in schematics vs the real devices. But I was referring to peculiarities of the tools like the

brummer10 commented 2 years ago

That's why I said your input is welcome. I wont said this tool is perfect, the opposite is the case. So, when ever you've a idea to make it better, it will be more then welcome. re: Log Pot, often I try to recreate a special logarithmic beehive, before I noticed that this controller is simply inverted log.

brummer10 commented 2 years ago

Beside that, I guess you are aware that I've developed a couple of plugs already with this tool, were I work around the drawbacks it has. Still, some academical research could improve the dkbuilder for sure.

FalconBry commented 2 years ago

Yes, I understand that the dkbuilder tool is still in experimental stage. Nevertheless, I think it's great to have such a tool at all. I am currently just exploring it's capabilities and limitations. The best way of doing that IMO is to actually use the tool and see what comes out.

For example; I've build your hoffman PlexiPowerAmp and noticed an absurd low value for R3 100 Ohm. That is the negative feedback resistor. The lowest I have seen in real devices is ~1k in fender amps. Marshall is usually 47k or 100k.

Then when I change the value in the schematic to 47k, build the plug and run it, the Presence control has barely any effect. Back to 100 ohm and Presence works. Any ideas?

brummer10 commented 2 years ago

That may be relate to the windings or the resistance of the transformer, but I'm not sure. Never found some useful resources about that. Maybe reduce the resistance of the transformer may help here, maybe implement inductors in the signal flow, check out the jcm800_power.sch for a more complex implementation of a power amp. Unfortunately that one is to complex to generate a usable filter, but is the most correct we've ever done. At least I come to the 100 ohm by experimenting to get the presence working at all.

FalconBry commented 2 years ago

Might indeed be the output resistance of the transformer. It's currently set to 5400 Ohm in the plexi. That seems way to high if you imagine a speaker load of 8 ohm don't you think? Wait a second, shoudn't the transformer output be loaded by an 8 Ohm load for the SPICE simulation?

FalconBry commented 2 years ago

Oh wait, the 5400 Ohm is probably the primary winding.

FalconBry commented 2 years ago

Does dkbuilder model Miller Capacitance and Slew Rate in op-amps, transistors, tubes etc.?

brummer10 commented 2 years ago

dkbuilder is based on this thesis: https://www.vut.cz/www_base/zav_prace_soubor_verejne.php?file_id=60090 you'll find our implementation for the models in DK/models.py

FalconBry commented 2 years ago

Thanks Hermann for the pointers.

Ok, so parasitic capacitance (Miller effect) is not simulated/modeled. This is something to consider since it plays a huge role in the frequency response of analog circuitry.

Take for example, the second stage grid in Marshall plexi amps. That grid is fed through a large 470k mixer resistor. Together with the ~200pF Miller grid capacitance this forms a low-pass filter with cutoff frequency of ~1690 Hz! If left out of the simulation it will result in a huge sonic inaccuracy. (in the above case; way too much treble on the lead channel)

Of course the above example is easily fixed by adding a 200pF C in parallel to the grid, but I haven't seen anyone doing this in the schematics yet.

Anyway, I thought I mention it here so that new users of dkbuilder are aware of this limitation. The workaround is often easy though.

mikeoliphant commented 2 years ago

I've been following this thread with interest. I don't have much to contribute as I'm not a mathematician or an electrical engineer, but as a programmer/guitarist I would very much like to see progress on the performance and accessibility of tools like dkbuilder.

brummer10 commented 2 years ago

Ok, so parasitic capacitance (Miller effect) is not simulated/modeled. This is something to consider since it plays a huge role in the frequency response of analog circuitry.

Yes, you are right. If you've a idea how we could implement it, that would be welcome. What I do to work around this issue is, doing a frequency plot of the circuit, compare the result with the expected one, and add extra filters to compensate the diff. Hence that's why I've add 11kHz low-pass filters in the plexi simulation.

FalconBry commented 2 years ago

The correct place to add miller cap. is probably in the models. But I have currently no knowledge of the model system in use.

As a workaround you can simply add a parasitic capacitor to the schematic at the correct place.

The way you did it in your plexi sim is adding an extra RC filter (150Ohm, 0.1u). Adding a 200pF cap. parallel to the triode grid is a more realistic simulation provided you leave any series resistance/impedance in-place. For example, the well known 68k input resistor in conjunction with the miller cap will then automatically form the 12k low-pass.

FalconBry commented 2 years ago

Hermann, Is there a way to set the wiper position of a potmeter in the schematics? It seems to me it is currently fixed at 50%. This influences the generated non-lin tables greatly.

brummer10 commented 2 years ago

Sorry, nope. I sometimes append a extra active volume control circuit and replace the potentiometer with a resistor,

FalconBry commented 2 years ago

Ok. I am currently studying the python code. Is there any particular reason why the tables are split in pos and neg halves? I mean; why not 1 single table?

FalconBry commented 2 years ago

Me again, I noticed that if a filter is incorporated in the non-linear circuit, for example the cathode resistor bypass C in a triode circuit, the resulting stage gain is computed twice! Once in the IIR filter and once in the table generation. Resulting in a unrealistic huge stage gain in de faust code.

How to fix? Leaving out the bypass C in the circuit during table generation? I am not sure if that would lead to simulation inaccuracy. Scaling the filter output down? By how much? Why not normalize the frequency response once a non-lin circuit is detected, and leave the gain to the tables? Just thinking out loud I guess.

brummer10 commented 2 years ago

Is there any particular reason why the tables are split in pos and neg halves?

It's a way easier and lighter to implement it in C/C++ this way.

I noticed that if a filter is incorporated in the non-linear circuit, for example the cathode resistor bypass C in a triode circuit, the resulting stage gain is computed twice! Once in the IIR filter and once in the table generation. Resulting in a unrealistic huge stage gain in de faust code.

How to fix?

Not really, It may be that already the IIR filter is way to loud, I guess that's because of the missing compression. That could be solved by adjust the table operator. ( -o ) I didn't find a way to automate that factor, so a general factor is used. So using -o 0.1 will reduce the operator and therewith the gain nonlinear (compression). Additional there is the --reduce_gain (-r ) flag witch will reduce the gain linear.