OpAmpDetailed

model OpAmpDetailed "Detailed model of an operational amplifier"
    import Modelica.Constants.pi;

    parameter SI.Resistance Rdm = 2e+6 "Input resistance (differential input mode)";
    parameter SI.Resistance Rcm = 2e+9 "Input resistance (common mode)";
    parameter SI.Capacitance Cin = 1.4e-12 "Input capacitance";
    parameter SI.Voltage Vos = 0.001 "Input offset voltage";
    parameter SI.Current Ib = 8e-8 "Input bias current";
    parameter SI.Current Ios = 2e-8 "Input offset current";
    parameter SI.Voltage vcp = 0 "Correction value for limiting by p_supply";
    parameter SI.Voltage vcm = 0 "Correction value for limiting by msupply";
    parameter Real Avd0 = 106 "Differential amplifier [dB]";
    parameter Real CMRR = 90 "Common-mode rejection [dB]";
    parameter SI.Frequency fp1 = 5 "Dominant pole";
    parameter SI.Frequency fp2 = 2e+6 "Pole frequency";
    parameter SI.Frequency fp3 = 2e+7 "Pole frequency";
    parameter SI.Frequency fp4 = 1e+8 "Pole frequency";
    parameter SI.Frequency fz = 5e+6 "Zero frequency";
    parameter SI.VoltageSlope sr_p = 500000 "Slew rate for increase";
    parameter SI.VoltageSlope sr_m = 500000 "Slew rate for decrease";
    parameter SI.Resistance Rout = 75 "Output resistance";
    parameter SI.Current Imaxso = 0.025 "Maximal output current (source current)";
    parameter SI.Current Imaxsi = 0.025 "Maximal output current (sink current)";
    parameter SI.Time Ts = 1.2e-6 "Sampling time";
    constant Real Pi = 3.141592654 "Obsolete constant pi; will be removed in future release";
    final parameter SI.Voltage vcp_abs = abs(vcp) "Positive correction value for limiting by p_supply";
    final parameter SI.Voltage vcm_abs = abs(vcm) "Positive correction value for limiting by msupply";
    final parameter SI.Current I1 = Ib + 0.5 * Ios "Current of internal source I1";
    final parameter SI.Current I2 = Ib - 0.5 * Ios "Current of internal source I2";
    final parameter Real Avd0_val = 10 ^ (0.05 * Avd0) "Differential mode gain";
    final parameter Real Avcm_val = 0.5 * (Avd0_val / 10 ^ (0.05 * CMRR)) "Common mode gain";
    final parameter SI.VoltageSlope sr_p_val = abs(sr_p) "Value of slew rate for increase";
    final parameter SI.VoltageSlope sr_m_val = -abs(sr_m) "Negative alue of slew rate for increase";
    final parameter SI.Current Imaxso_val = abs(Imaxso) "Orientation out outp";
    final parameter SI.Current Imaxsi_val = abs(Imaxsi) "Orientation into outp";
    Modelica.Electrical.Analog.Interfaces.PositivePin p "Positive pin of the input port"
        annotation (Placement(
            transformation(extent = {
                {-110, -70}, 
                {-90, -50}}),
            iconTransformation(extent = {
                {-110, -70}, 
                {-90, -50}})));
    Modelica.Electrical.Analog.Interfaces.NegativePin m "Negative pin of the input port"
        annotation (Placement(
            transformation(extent = {
                {-90, 50}, 
                {-110, 70}}),
            iconTransformation(extent = {
                {-90, 50}, 
                {-110, 70}})));
    Modelica.Electrical.Analog.Interfaces.PositivePin outp "Output pin"
        annotation (Placement(
            transformation(extent = {
                {110, -10}, 
                {90, 10}}),
            iconTransformation(extent = {
                {110, -10}, 
                {90, 10}})));
    Modelica.Electrical.Analog.Interfaces.PositivePin p_supply "Positive output voltage limitation"
        annotation (Placement(
            transformation(extent = {
                {-10, 90}, 
                {10, 110}}),
            iconTransformation(extent = {
                {-10, 90}, 
                {10, 110}})));
    Modelica.Electrical.Analog.Interfaces.NegativePin m_supply "Negative output voltage limitation"
        annotation (Placement(
            transformation(extent = {
                {-10, -110}, 
                {10, -90}}),
            iconTransformation(extent = {
                {-10, -110}, 
                {10, -90}})));
    SI.Voltage v_pos;
    SI.Voltage v_neg;
    SI.Voltage v_vos;
    SI.Voltage v_3;
    SI.Voltage v_in;
    SI.Voltage v_4;
    SI.Current i_vos;
    SI.Current i_3;
    SI.Current i_r2;
    SI.Current i_c3;
    SI.Current i_4;
    Real q_fr1;
    Real q_fr2;
    Real q_fr3;
    SI.Voltage q_sum;
    SI.Voltage q_sum_help;
    SI.Voltage q_fp1;
    SI.Voltage v_source;
    SI.Voltage x "Auxiliary variable for slew rate";
    SI.Voltage v_out;
    SI.Current i_out;

    function FCNiout_limit "Internal limitation function"
        extends Modelica.Icons.Function;

        input SI.Voltage v_source;
        input SI.Voltage v_out;
        input SI.Resistance Rout;
        input SI.Current Imaxsi_val;
        input SI.Current Imaxso_val;
        output SI.Current result;
    algorithm
        if v_source + Rout * Imaxsi_val < v_out then 
            result := Imaxsi_val;
        elseif v_out < v_source - Rout * Imaxso_val then 
            result := -Imaxso_val;
        else 
            result := (v_out - v_source) / Rout;
        end if;
        return;

        annotation (Documentation(info = "<html>\n<p>Internal limitation function, designed for OpAmpDetailed, not for purpose of external usage.</p>\n</html>"));
    end FCNiout_limit;

    function FCNq_sum_limit "Internal limitation function"
        extends Modelica.Icons.Function;

        input SI.Voltage q_sum;
        input SI.Voltage q_sum_ltf;
        input SI.Voltage v_pos;
        input SI.Voltage v_neg;
        input SI.Voltage vcp;
        input SI.Voltage vcm;
        output SI.Voltage result;
    algorithm
        if v_pos - vcp < q_sum and v_pos - vcp <= q_sum_ltf then 
            result := v_pos - vcp;
        elseif q_sum < v_neg + vcm and q_sum_ltf <= v_neg + vcm then 
            result := v_neg + vcm;
        else 
            result := q_sum;
        end if;
        return;

        annotation (Documentation(info = "<html>\n<p>Internal limitation function, designed for OpAmpDetailed, not for purpose of external usage.</p>\n</html>"));
    end FCNq_sum_limit;
initial equation
    x = 0;
    v_source = q_fp1;
equation
    assert(0 < Rout, "Rout must be > 0.0.");
    0 = i_3 + i_r2 + i_c3 - i_vos;
    q_fr2 + (2 * pi * fp3) ^ (-1) * der(q_fr2) = q_fr1 + (2 * pi * fz) ^ (-1) * der(q_fr1);
    i_3 = I1 + v_3 / Rcm;
    i_4 = I2 + v_4 / Rcm;
    i_c3 = Cin * der(v_in);
    i_out = outp.i;
    i_out = FCNiout_limit(v_source, v_out, Rout, Imaxsi_val, Imaxso_val);
    q_sum = Avd0_val * q_fr3 + Avcm_val * (v_3 + v_4);
    v_3 = p.v - v_vos;
    v_4 = m.v;
    v_in = Rdm * i_r2;
    v_neg = m_supply.v;
    v_out = outp.v;
    v_pos = p_supply.v;
    v_vos = Vos;
    q_sum_help = FCNq_sum_limit(q_sum, q_fp1, v_pos, v_neg, vcp_abs, vcm_abs);
    m.i = i_4 - i_r2 - i_c3;
    p.i = i_vos;
    m_supply.i = 0;
    p_supply.i = 0;
    p.v - m.v = v_vos + v_in;
    der(x) = (q_fp1 - v_source) / Ts;
    der(q_fp1) = 2 * pi * fp1 * (q_sum_help - q_fp1);
    der(q_fr1) = 2 * pi * fp2 * (v_in - q_fr1);
    der(q_fr3) = 2 * pi * fp4 * (q_fr2 - q_fr3);
    der(v_source) = smooth(0, noEvent(if sr_p_val < der(x) then sr_p_val else if der(x) < sr_m_val then sr_m_val else der(x)));

    annotation (
        defaultComponentName = "opAmp",
        Documentation(
            info = "<html>\n<p>The OpAmpDetailed model is a general operational amplifier model. The emphasis is on separating each important data sheet parameter into a sub-circuit independent of the other parameters. The model is broken down into five functional stages <strong>input</strong>, <strong>frequency response</strong>, <strong>gain</strong>, <strong>slew rate</strong> and an <strong>output</strong> stage. Each stage contains data sheet parameters to be modeled. This partitioning and the modelling of the separate submodels are based on the description in <strong>[CP92]</strong>.</p>\n<p>Using <strong>[CP92]</strong> Joachim Haase (Fraunhofer Institute for Integrated Circuits, Design Automation Division) transferred 2001 operational amplifier models into VHDL-AMS. Now one of these models, the model &quot;amp(macro)&quot; was transferred into Modelica.</p>\n<dl><dt><strong>Reference:</strong> </dt>\n<dd><strong>[CP92]</strong> Conelly, J.A.; Choi, P.: Macromodelling with SPICE. Englewood Cliffs: Prentice-Hall, 1992 </dd>\n</dl></html>",
            revisions = "<html>\n<dl>\n<dt><em>June 17, 2009</em></dt>\n<dd>by Susann Wolf initially implemented</dd>\n</dl>\n</html>"),
        Icon(
            coordinateSystem(
                preserveAspectRatio = true,
                extent = {
                    {-100, -100}, 
                    {100, 100}}),
            graphics = {
                Text(
                    extent = {
                        {-150, 150}, 
                        {150, 110}},
                    textString = "%name",
                    lineColor = {0, 0, 255}), 
                Polygon(
                    points = {
                        {70, 0}, 
                        {-70, 80}, 
                        {-70, -80}, 
                        {70, 0}},
                    fillColor = {255, 255, 255},
                    fillPattern = FillPattern.Solid,
                    lineColor = {0, 0, 255}), 
                Line(
                    points = {
                        {0, 40}, 
                        {0, 110}},
                    color = {0, 0, 255}), 
                Line(
                    points = {
                        {0, -40}, 
                        {0, -90}},
                    color = {0, 0, 255}), 
                Line(
                    points = {
                        {-90, 60}, 
                        {-70, 60}},
                    color = {0, 0, 255}), 
                Line(
                    points = {
                        {-90, -60}, 
                        {-70, -60}},
                    color = {0, 0, 255}), 
                Line(
                    points = {
                        {70, 0}, 
                        {90, 0}},
                    color = {0, 0, 255}), 
                Line(
                    points = {
                        {-58, 50}, 
                        {-38, 50}},
                    color = {0, 0, 255}), 
                Line(
                    points = {
                        {-60, -51}, 
                        {-38, -51}},
                    color = {0, 0, 255}), 
                Line(
                    points = {
                        {-49, -40}, 
                        {-49, -61}},
                    color = {0, 0, 255})}));
end OpAmpDetailed;