pascalkuthe / OpenVAF

An innovative Verilog-A compiler
https://openvaf.semimod.de/
GNU General Public License v3.0
113 stars 15 forks source link

Math Functions #79

Closed kdotom closed 10 months ago

kdotom commented 10 months ago

Are there any limitations on the types of inputs the math functions can take? (sqrt, exp, ln) when creating a component which has the following definition: y <+ x; The va code compiles and the spice simulation produces a reasonable output. When taking the square root of this value, y <+ sqrt(x); the va code compiles and the spice simulation produces -NaN as the output.

Alternatively, is there a specific library which must be included to use these? (Side note: cos and sin appear to work well)

pascalkuthe commented 10 months ago

OpenVAF only requires the C standard library for linking math operations which is always required anyway.

The convergence issue you see here is because sqrt(x) is of course not defined for negative numbers. Even if you don't explicitly sweep negative vales the simulator may still explore negative solutions during the simulation.

To fix the issue you need to handle negativ values in your VA code somehow. One solution could be to cuoff the value at 0. These kinds of numeric problems are well known in the compact modeling space and need to be properly accounted for by the model author

kdotom commented 10 months ago

Thanks for the note. The x argument was result of a calculation which was covered by an "abs()" function, i.e. x = abs(calculation). I believe this should account for all negative values, but there may be some cases I'm missing. That said, I was able to solve the problem with the pow() function.

pascalkuthe commented 10 months ago

then it could be a case of numeric instability in the generated derivative. Can you post a minimal example?

kdotom commented 10 months ago

This produces an error in ngspice:

module testmodule(gnd, o1, i1);
        inout gnd;
        input i1;
        output o1;
        electrical i1, o1, gnd;

        parameter real x = 0;

        analog begin
                V(o1,gnd) <+ sqrt( 2*abs(V(i1,gnd))**2 + 2*abs(V(i1,gnd))**2);
        end
endmodule

but this works

module testmodule(gnd, o1, i1);
        inout gnd;
        input i1;
        output o1;
        electrical i1, o1, gnd;

        parameter real x = 0;

        analog begin
                V(o1,gnd) <+ pow( 2*abs(V(i1,gnd))**2 + 2*abs(V(i1,gnd))**2, 0.5);
        end
endmodule

The only difference between these two are the usage of pow(x,0.5) or sqrt(x).

pascalkuthe commented 10 months ago

I am not really sure how to deal with this. The derivative of sqrt(x) is x'/2sqrt(x) so for x=0 its correct that this produces NAN so from a mathematical point of view the behaviour is correct here. For pow OpenVAF calculates the derivative as (x==0.0)?0.0:((y/x)*pow(x,y). This is correct for y>=1 but not otherwise. I kind of accepted this for pow (although it's not ideal). I don't really think this should exist for sqrt tough since this is always mathematically incorrect there and leads to a discontinuity which can lead to weird convergence issues.

One way to fix this on your end is to just add a very small number in the sqrt arguments (like sqrt(1e-6 + ...)). We could theoretically add a hack to openvaf that does something similar but I don't really think we should.

These kind of discontinuities should be handled by the model IMO. I never encountered this as an issue with industry standard models. Mostly because they are careful to avoid such problems (by smoothing the sqrt function for example). Adding a workaround here would slowdown these models without providing any benefit for them.

Potentially we could hide this behind somekind of compiler option (like: --convergence-aids) which would automatically smooth nonlinear functions to avoid such problems (for exmable automatically lineraizing exp functions)

pascalkuthe commented 10 months ago

I decided to close this since really a model should never have such a case. sqrt(x) simply doesn't not have a mathematically well defined deriviatuve at x=0 and model code must ensure this case never occurs.