Skip to content

Add NMOS PMOS Transistors #376

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jun 7, 2025
Merged

Conversation

jClugstor
Copy link
Member

Checklist

  • Appropriate tests were added
  • Any code changes were done in a way that does not break public API
  • All documentation related to code changes were updated
  • The new code follows the
    contributor guidelines, in particular the SciML Style Guide and
    COLPRAC.
  • Any new documentation only uses public API

Additional context

Add any other context about the problem here.

@ChrisRackauckas
Copy link
Member

Add the docstring to the docs

@ChrisRackauckas
Copy link
Member

Rebase

@ChrisRackauckas
Copy link
Member

Rebase

@jClugstor
Copy link
Member Author

I can't seem to figure out this error. I think I'm missing an import or something. If I define it on it's own it works fine:

using ModelingToolkit, ModelingToolkitStandardLibrary
using OrdinaryDiffEq
using NonlinearSolve
import ModelingToolkitStandardLibrary: Electrical.Pin, Electrical.Voltage, Electrical.Ground, Electrical.Resistor, Electrical.Capacitor, Electrical.NMOS
using ModelingToolkitStandardLibrary.Blocks: Constant
using ModelingToolkit: t_nounits as t, D_nounits as D


@mtkmodel CustomNMOS begin
    @variables begin
        V_GS(t)
        V_DS(t)
        V_OV(t)
    end


    @components begin
        d = Pin()
        g = Pin()
        s = Pin()
        b = Pin()
    end

    @parameters begin
        V_tn = 0.8
        R_DS = 1e7
        lambda = 1 / 25

        if !use_transconductance
            mu_n
            C_ox
            W
            L
        else
            k_n = 20e-3
        end

    end

    @structural_parameters begin
        use_bulk = false
        use_transconductance = true
        use_channel_length_modulation = true
    end

    begin
        if !use_transconductance
            k_n = mu_n * C_ox * (W / L)
        end
    end

    @equations begin
        V_DS ~ ifelse(d.v < s.v, s.v - d.v, d.v - s.v)
        V_GS ~ g.v - ifelse(d.v < s.v, d.v, s.v)
        V_OV ~ V_GS - V_tn

        d.i ~
            ifelse(d.v < s.v, -1, 1) * ifelse(V_GS < V_tn,
                0 + V_DS / R_DS,
                ifelse(V_DS < V_OV,
                    ifelse(use_channel_length_modulation, k_n * (1 + lambda * V_DS) * (V_OV - V_DS / 2) * V_DS + V_DS / R_DS, k_n * (V_OV - V_DS / 2) * V_DS + V_DS / R_DS),
                    ifelse(use_channel_length_modulation, ((k_n * V_OV^2) / 2) * (1 + lambda * V_DS) + V_DS / R_DS, (k_n * V_OV^2) / 2 + V_DS / R_DS)
                )
            )

        g.i ~ 0
        s.i ~ -d.i
    end
end


@mtkmodel Custom_SimpleNMOSCircuit begin
    @components begin
        Q1 = CustomNMOS(use_channel_length_modulation=false)
        Vcc = Voltage()
        Vb = Voltage()
        ground = Ground()

        Vcc_const = Constant(k=V_cc)
        Vb_const = Constant(k=V_b)
    end

    @parameters begin
        V_cc = 5.0
        V_b = 3.5
    end
    @equations begin
        #voltage sources
        connect(Vcc_const.output, Vcc.V)
        connect(Vb_const.output, Vb.V)

        #ground connections
        connect(Vcc.n, Vb.n, ground.g, Q1.s)

        #other stuff
        connect(Vcc.p, Q1.d)
        connect(Vb.p, Q1.g)
    end
end

@mtkbuild custom_sys = Custom_SimpleNMOSCircuit(V_cc=5.0, V_b=3.5)

but then when I try to use the library version which is the exact same code:

# from library
@mtkmodel SimpleNMOSCircuit begin
    @components begin
        Q1 = NMOS(use_channel_length_modulation=false)
        Vcc = Voltage()
        Vb = Voltage()
        ground = Ground()

        Vcc_const = Constant(k=V_cc)
        Vb_const = Constant(k=V_b)
    end

    @parameters begin
        V_cc = 5.0
        V_b = 3.5
    end
    @equations begin
        #voltage sources
        connect(Vcc_const.output, Vcc.V)
        connect(Vb_const.output, Vb.V)

        #ground connections
        connect(Vcc.n, Vb.n, ground.g, Q1.s)

        #other stuff
        connect(Vcc.p, Q1.d)
        connect(Vb.p, Q1.g)
    end
end

@mtkbuild custom_sys = SimpleNMOSCircuit(V_cc=5.0, V_b=3.5)

I get

ERROR: MethodError: no method matching *(::ModelingToolkit.NoValue, ::Num)
The function `*` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...)
   @ Base operators.jl:596
  *(::ChainRulesCore.NoTangent, ::Any)
   @ ChainRulesCore ~/.julia/packages/ChainRulesCore/U6wNx/src/tangent_arithmetic.jl:64
  *(::Any, ::ChainRulesCore.NoTangent)
   @ ChainRulesCore ~/.julia/packages/ChainRulesCore/U6wNx/src/tangent_arithmetic.jl:65
  ...

Stacktrace:
 [1] 
   @ ModelingToolkitStandardLibrary.Electrical ~/.julia/packages/ModelingToolkit/YLJ0I/src/systems/model_parsing.jl:918
 [2] __NMOS__
   @ ~/.julia/packages/ModelingToolkit/YLJ0I/src/systems/model_parsing.jl:140 [inlined]
 [3] #_#385
   @ ~/.julia/packages/ModelingToolkit/YLJ0I/src/systems/model_parsing.jl:25 [inlined]
 [4] macro expansion
   @ ~/.julia/packages/ModelingToolkit/YLJ0I/src/systems/abstractsystem.jl:1957 [inlined]
 [5] 
   @ Main ~/.julia/packages/ModelingToolkit/YLJ0I/src/systems/model_parsing.jl:140
 [6] __SimpleNMOSCircuit__
   @ ~/.julia/packages/ModelingToolkit/YLJ0I/src/systems/model_parsing.jl:140 [inlined]
 [7] #_#385
   @ ~/.julia/packages/ModelingToolkit/YLJ0I/src/systems/model_parsing.jl:25 [inlined]
 [8] top-level scope
   @ ~/.julia/packages/ModelingToolkit/YLJ0I/src/systems/abstractsystem.jl:1957
Some type information was truncated. Use `show(err)` to see complete types.

@ChrisRackauckas
Copy link
Member

@ven-k can you look into this? It would be good to make the NoValue stuff throw earlier.

@ChrisRackauckas
Copy link
Member

What's left here?

@jClugstor
Copy link
Member Author

jClugstor commented Jun 7, 2025

Making the NMOS or PMOS with use_channel_length_modulation = false fails.

Q1 = NMOS(use_channel_length_modulation = false, name = :no_lambda)

ERROR: MethodError: no method matching *(::ModelingToolkit.NoValue, ::Num)
The function `*` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...)
   @ Base operators.jl:596
  *(::ChainRulesCore.NotImplemented, ::Any)
   @ ChainRulesCore ~/.julia/packages/ChainRulesCore/U6wNx/src/tangent_arithmetic.jl:37
  *(::Any, ::ChainRulesCore.NoTangent)
   @ ChainRulesCore ~/.julia/packages/ChainRulesCore/U6wNx/src/tangent_arithmetic.jl:65
  ...

Stacktrace:
 [1] 
   @ ModelingToolkitStandardLibrary.Electrical ~/.julia/packages/ModelingToolkit/aau6A/src/systems/model_parsing.jl:920
 [2] __NMOS__
   @ ~/.julia/packages/ModelingToolkit/aau6A/src/systems/model_parsing.jl:140 [inlined]
 [3] #_#402
   @ ~/.julia/packages/ModelingToolkit/aau6A/src/systems/model_parsing.jl:25 [inlined]
 [4] top-level scope
   @ REPL[2]:1
Some type information was truncated. Use `show(err)` to see complete types.

which points here https://github.com/SciML/ModelingToolkit.jl/blob/01b388a3ebdb7e00e9b1dc395f8480b645f3923d/src/systems/model_parsing.jl#L909

so it looks like something is messing up when setting defaults?

I have

 if use_channel_length_modulation
            lambda = 1 / 25, [description = "Channel length modulation coefficient (V^(-1))"]
 end

in the transistor model, since lambda isn't used if there's no channel length modulation, and use_channel_length_modulation is a structural parameter, am I using that right?

If I have just

lambda = 1 / 25, [description = "Channel length modulation coefficient (V^(-1))"]

in my parameters it does work, but then the model has an extra parameter that it doesn't use.

@ChrisRackauckas
Copy link
Member

what's the issue with just having it zero?

@jClugstor
Copy link
Member Author

Honestly we probably don't need use_channel_length_modulation as a parameter anyway. Looking at the Modelica Standard Library implementation, it doesn't have an equivalent toggle either. If a user wants to ignore the channel length effect they can just set lambda to zero.

@ChrisRackauckas ChrisRackauckas merged commit 04efb4d into SciML:main Jun 7, 2025
6 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants