Note

This Tutorial is now available in video format on Youtube:

Organization

Mathematica Notebooks have the ability to segment your work into logical groups by using identified headers which run from Title to Subsection. There are 6 of these headers. These groups will then collapse all lesser headers by double clicking on the vertical line shown to the right.

This organization can be accomplished after the mathematics of the problem are completed. This allows one to review the solution and annotate the steps. The readers of this document can then better understand your analysis.

List & Matrix Formation

 List Formation

A list is a group of variables and numbers separated by comma’s and enclosed by curly brackets. A list can be labelled as a variable name. An example of this is shown below:

AList = {1, a, 2, b}
{1, a, 2, b}

Also note that ending a statement with a semicolon tells Mathematica to not display the result.

BList = {c, 3, d, 4};
Using Lists to create Matrices

If one makes a List of Lists, you get a Matrix of values.

AMatrix = {AList, BList};

You can display this by using the directive MatrixForm[].

MatrixForm[AMatrix]

Matrix
Note that this way of putting the lists together, they are formed as rows. If we wish them to be formed as columns we form the matrix as shown below:

BMatrix = {{AList},{BList}};
MatrixForm[BMatrix]

Matrix2
Or, we can create a matrix of 2 columns such as:

CMatrix = {{AList, BList}};
MatrixForm[CMatrix]

Matrix3

Getting an element of a list or matrix

We have the need to extract the one or more elements of a matrix. To do this in Mathematica we use double square brackets [[ element ]]. So, for example, if we want the first row of the AMatrix:

AMatrix[[1]]
{1, a, 2, b}

To get the 3rd element in the first row we use:

AMatrix[[1,3]]
2

Using this approach we can get any element in any matrix.

Replacement and tolerances

The final operations we need to use for WCA in Mathematica are the replacement rules, using the table function and how to enter tolerances. Entering tolerances allows us to evaluate both the upper and lower limits numerically with the same expression.
 
Replacement Rules
Once we have derived the desired equation with variables, we will need to enter the specific numerical values for our circuit. To accomplish this, we will use the replacement operator provided in Mathematica, which is a backslash and period followed by the replacement. Let show this for a simple case.
Suppose we have an equation, we will call eqA:

eqA = x2 + x
x + x2

We want to replace the x with the number 2 in a specific case:

eqA /. x → 2
6

So 22=4, plus 2 is 6. The beauty of this is that the original equation still exists as a variable equation.

eqA
x + x2
Creating Lists Using the Table Function

In some cases, we need to evaluate a series of values in a similar fashion. To do this repetitive task, it is much easier to create a list of values, using the Table function.
Lets say, we want to evaluate our eqA for x values from 1 to 9, we can do this by:

valA = Table[eqA, {x, 1, 9}]
{2, 6, 12, 20, 30, 42, 56, 72, 90}

Note that doing it this way, we do not need the replacement operator.  But also note that there is not a 1 to 1 relationship between the x and y values, so let’s modify the table function so we get ordered pairs:

valA = Table[{x, eqA}, {x, 1, 9}];
MatrixForm[valA]
Matrix 4

Note that the original value of valA (a list) is now replaced with a 2 dimensional list. The original variable valA is overwritten .


Plotting

We can plot this relationship using the ListPlot function, so we can see in graphical form what this looks like.

ListPlot[valA]
Plot 1

It would be helpful if we add labels to this graph, so:

ListPlot[valA, FrameLabel → {"input values (x)", "output values (y)"}]
Plot 2
And maybe we wish to connect the dots, then use ListLinePlot:
ListLinePlot[valA, FrameLabel → {"input values (x)", "output values (y)"}]

Plot 3


Tolerances

Adding tolerances shows a range of values that some circuit parameter can take on, usually minimum and maximum values. Suppose we have a 1 kΩ with a tolerance of ± 1%. To do this we will create a list of values in the following manner:

R23 = 1000 {1 - 0.01, 1 + 0.01}
{990., 1010.}

Note that the variable R23 now has two values associated with it, its resistive lower limit and its
resistive upper limit. We will use this technique to replace variables with their numerical values to
include tolerances. For example, lets replace x with R23 in eqA

eqA /. x → R23
{981 090., 1.02111 × 106}

Review

This file, in Mathematica, is known as a NOTEBOOK. In future notebooks we will explore the basic steps in creating a Worst Case Analysis including how to 1) format the equations, 2) determine the maximum and minimum numerical values for these relationships, and 3) convey the results for a reviewer or customer.

This notebook introduced you to how to a) create matrices, b) extracting parts of matrix, c) replace variables with numbers, and d) creating a list of upper and lower limits for component parameters.

Up Next

In a future post we will look at how circuit analysis is normally performed. We will explore the mathematical format we normally put these equations in to solve them. And finally we will review an author created function which puts these equations into this form, which allows ease of viewing and the ability to double-check our work.

General Forms for Analysis

Introduction

When you first learned circuit analysis, you likely wrote LOOP equations and solved them simultaneously. Doing this you probably learned all the fun things about Matrix Algebra which allowed you to systematically solve these types of equations. We will NOT be worrying about how to solve these equations, just how to set them up. We will put them into a form that you are used to, then allow Mathematica to do the work of solving them and providing us with the solution.

 General Form to get solution

After you have written the individual loop equations, you normally write them out in a Matrix Format like is shown below:

Having the equations in this form, allows the author to “double-check” their own work. We all make mistakes, so having ways of insuring you are solving the correct equations is always helpful. You can sometimes spot mistakes by noting that the off diagonal terms (-R2) need to be identical. You can also look at the diagonal entries and review in your mind whether they are correct.

General Form of generated equations

Whether we are writing Loop equations (using KVL) or Nodal equations (using KCL), they will always be set equal to zero. Kirchhoff’s Voltage Law (KVL) states that the sum of all voltage drops in a loop must be equal to zero. Kirchhoff’s Current Law (KCL) states that the sum of all currents into a node must be equal to zero. From these we know that the equations will always be in the form F(R1)+F(R2)+…+F(Rn) = 0, or more succinctly Σni=iFi = 0. To put them into matrix form, we want to collect all the coefficients of each circuit variable (Vi or Ii), then take all the constant terms and move them to the other side of the equation. Since ALL solutions pass through this step, it might be more efficient to program a function which takes care of this organization.

Functional Programming

General Concepts

Making a function in Mathematica is merely stringing together mathematical operations on numbers, equations, or groups of equations (Matrices). The typical method for a multi-operation function is using the construct Module which has the format: Module[{list of local variables}, Sequence of mathematical operations] The mathematical operations are strung together, by placing a semi-colon at the end of the statement operation. Remember that when a semi-colon is at the end of the statement, Mathematica does not display the results of the operation. Now, in order to get an output from the function, the last statement does not have a semi-colon, and so is returning a value (or list of values} to a calling function.

Function to create the Matrix

This function was written ASSUMING that all the input equations are numbered 1 through N, in form eq1, eq2, … eqN and are Global Variables. In a later example we will go though the process of creating these equations in a format that is easy to read (which means easy to verify that they are correct). The only input to the function is a list of variables that are used in the eq# equations.

A good habit whenever writing functions, is to put comments throughout the “program” to clue the user into what is the mathematical operation is being completed in each step. To add un-executable comments into a Mathematica function use Left Parenthesis-Star, (* , to open the comment and Star-Right Parenthesis, *), to close the comment.

Lets look through these functions

Functions

CreateMatrixForm[vars_] := Module[{loc, conLoc, Y, M, dim},
     (* The General form is Y = M X, where Y is the constants column Matrix,
     M is the square Matrix and X is the List of variables *)

     (* The equations need to be named eq1, eq2, and eq3 *)
     dim = Length[vars];
     (* The variables list needs to be identical to the collect variable list *)

     (* Create a Matrix of correct size with all 0's.
        This will be populated with coefficients of the variables *)
     M = Table[0, {i, dim}, {j, dim}];

     (* This finds the locations in
       each equation (eq#) of the variable's coefficients. *)
     loc = Table[{vars[[j]],
          If[Length[Position[ToExpression["eq" <> ToString[i]], vars[[j]]]] > 0,
            Position[ToExpression["eq" <> ToString[i]], vars[[j]]][[1, 1]], 0]},
          {i, dim}, {j, Length[vars]}];

     (* This uses the locations found previously to populate the M Matrix*)
     Table[If[loc[[i, j, 2]] > 0,
          M[[i, j]] = ToExpression["eq" <> ToString[i]][[loc[[i, j, 2]]]] / loc[[i, j, 1]],
          M[[i, j]] = 0], {i, dim}, {j, dim}];

     (* This creates a column Matrix of proper size for the constants *)
     Y = Table[0, {i, dim}];

     (* This finds the location of constants in each equation using a separate function *)
     conLoc = FindConstantTerms[loc, vars];

     (* This uses the locations found previously to populate the Y Matrix*)
     Table[If[conLoc[[i, 1]] > 0, Y[[i]] =
-ToExpression[“eq” <> ToString[i]][[conLoc[[i, j]]]], 0], {i, dim}];
     (* Display's the Matrix Equation in standard form *)
     Print[MatrixForm[Y], " = ", MatrixForm[M], MatrixForm[vars] ];
      (* "Returns" the matricies Y and M *) 
     {Y, M}
]

FindConstantTerms[loc_, vars_] := Module[{a, b, c, k, dim}, 
     (* finds the length of the constant matrix Y *) 
     dim = Length[vars]; 
     
     (* Creates a column matrix of 0's, which will be populated inside this function *) 
     c = Table[{0}, {k, dim}];

      (* Loops through each equation *)
     For[k = 1, k ≤ dim, k++,

           (* Counts all elements in each equation *) 
          a = Table[i, {i, Length[ToExpression["eq" <> ToString[k]]]}]; 

          (* Finds the location of the coefficients associated with the variables *)
          b = Table[loc[[i, j, 2]], {i, dim}, {j, dim}][[k]]; 

          (* Finds all the location of all non-coefficients (constants) in each equation *) 
          c[[k]] = If[Complement[a, b] ⩵ {}, {0}, Complement[a, b]];
      ];

      (* Returns the locations in each equation to be placed in the Y equation *) 
     c
]

Conclusion

In this notebook we have identified the general form that will allow us to obtain Worst Case Analysis (WCA) solutions in a systematic way. Since we will always want to put the equations into a standard form, we created a function to perform the repetitive steps (so we won’t make errors in performing this manipulation). Then we reviewed the steps that the functions used to obtain these results.

Next time we will bring together these first two notebooks and use them to solve a relatively simple problem by using KVL to analyze a two loop circuit.

Worst Case Analysis using Mathematica

KVL Solution

These are the functions we discussed last time

In[•]:= CreateMatrixForm[vars_] := Module[{loc, conLoc, Y, M, dim},
      (* The General form is Y = M X, where Y is the constants column Matrix,
      M is the square Matrix and X is the List of variables *)

      (* The equations need to be named eq1, eq2, and eq3 *)
      dim = Length[vars];
      (* The variables list needs to be identical to the collect variable list *)

      (* Create a Matrix of correct size with all 0's.
         This will be populated with coefficients of the variables *)
      M = Table[0, {i, dim}, {j, dim}];
      
      (* This finds the locations in
         each equation (eq#) of the variable's coefficients. *)
      loc = Table[{vars[[j]],
            If[Length[Position[ToExpression["eq" <> ToString[i]], vars[[j]]]] > 0,
               Position[ToExpression["eq" <> ToString[i]], vars[[j]]][[1, 1]], 0]},
            {i, dim}, {j, Length[vars]}];
          
      (* This uses the locations found previously to populate the M Matrix*)
      Table[If[loc[[i, j, 2]] > 0,
         M[[i, j]] = ToExpression["eq" <> ToString[i]][[loc[[i, j, 2]]]] / loc[[i, j, 1]],
         M[[i, j]] = 0], {i, dim}, {j, dim}];
         
      (* This creates a column Matrix of proper size for the constants *)
         Y = Table[0, {i, dim}];
         
      (* This finds the location of constants in each equation using a separate function *)
      conLoc = FindConstantTerms[loc, vars];
      
      (* This uses the locations found previously to populate the Y Matrix*)
      Table[If[conLoc[[i, 1]] > 0, Y[[i]] =
-ToExpression[“eq” <> ToString[i]][[conLoc[[i, j]]]], 0], {i, dim}];
     
      (* Display's the Matrix Equation in standard form *)
      Print[MatrixForm[Y], " = ", MatrixForm[M], MatrixForm[vars] ];
      
      (* "Returns" the matricies Y and M *)
      {Y, M}
   ]
In[•]:= FindConstantTerms[loc_, vars_] := Module[{a, b, c, k, dim},
      (* finds the length of the constant matrix Y *)
      dim = Length[vars];

      (* Creates a column matrix of 0's, which will be populated inside this function *)
      c = Table[{0}, {k, dim}];

      (* Loops through each equation *)
      For[k = 1, k ≤ dim, k++,

         (* Counts all elements in each equation *)
         a = Table[i, {i, Length[ToExpression["eq" <> ToString[k]]]}];

         (* Finds the location of the coefficients associated with the variables *)
         b = Table[loc[[i, j, 2]], {i, dim}, {j, dim}][[k]];

         (* Finds all the location of all non-coefficients (constants) in each equation *)
         c[[k]] = If[Complement[a, b] ⩵ {}, {0}, Complement[a, b]];
      ];

      (* Returns the locations in each equation to be placed in the Y equation *)
      c
   ]

Here is the circuit we will solve.

Writing the Loop equations

In[•]:= eqI1 = -Vs + I1 R1 + I1 L1 s + (I1 - I2) R2 + (I1 - I2)
;
In[•]:= eqI2 = (I2 - I1) + (I2 - I1) R2 + I2 L2 s + I2 R3;

Collecting the coefficients of I1 and I2

In[•]:= eq1 = Collect[eqI1, {I1, I2}]
In[•]:= eq2 = Collect[eqI2, {I1, I2}]

Using our function to find the transfer function H(s)

In[•]:= {y, m} = CreateMatrixForm[{I1, I2}];

Using a built in function we can find the equation for the current I2

In[•]:= i2 = LinearSolve[m, y][[2]]
In[•]:= Vout = i2 R3
In[•]:= Hs =

Sensitivity Analysis

In[•]:= vars = Variables[Hs]
In[•]:= varTable = {R3 → 1000, C1 → 1 × 10-6, R2 → 100, R1 → 5, L1 → 2 × 10-3, L2 → 5 × 10-3, s → 1};
In[•]:= TableForm[Table[{vars[[i]], N[D[Hs, vars[[i]]] /. varTable]} , {i, Length[vars]}]]

If the results are positive, then we allow the variable to range from smallest to largest value, if it is negative then it ranges from largest value to smallest value

In[•]:= varTable =
         {R3 → 1000 {1 - 0.05, 1 + 0.05}, C1 → 1 × 10-6 {1 + 0.25, 1 - 0.15}, R2 → 100 {1 - 0.05, 1 + 0.05},
          R1 → 5 {1 + 0.05, 1 - 0.05}, L1 → 2 × 10-3 {1 + 0.1, 1 - 0.1}, L2 → 5 × 10-3 {1 + 0.1, 1 - 0.1}};

To make a Bode Plot we replace s with ⅈω, which is ⅈ 2 π f and replace the variables with their values.

In[•]:= Hjω = Hs /. s → ⅈ 2 π f /. varTable
In[•]:= LogLinearPlot [20 Log10[Abs[Hjω]], {f, 50, 106}, AxesLabel → {"Freq (Hz)", "Gain (dB)"}]

To get a time domain result,assuming a Step Input, we divide H(s) by s and replace the variables with their
values

In[•]:= Vot = InverseLaplaceTransform[ Hs /. varTable, s, t]
In[•]:= Plot[Vot, {t, 0, 5 × 10-4}, PlotRange → All]

Now, we will take the raw “notebook” and make a report from it. We start by adding a Title.

Worst-Case Analysis Report

We can hide our homemade function, by creating a sub-section, then click on the farther to the left bar which encloses our functions. Note that when we have finished, we have a downward arrow (which indicates that there is something hidden beneath this heading.

Function


Circuit

By scanning the circuit (or if you have it in a schematic capture software, save it as a jpeg), we can show the circuit diagram used for this analysis. You can use this method to add sections of a manufactures specification sheet and other pertinent information. Simply use Insert-> Picture-> From File, then find the file name.

We wish to find the transfer function of Vin (Vs) to Vout (assumed to be across R3).

Now add subsections, which describe the steps taken to arrive at the solution.

Writing the Loop equations
    
eqI1 = -Vs + I1 R1 + I1 L1 s + (I1 - I2) R2 + (I1 - I2) ;
eqI2 = (I2 - I1) + (I2 - I1) R2 + I2 L2 s + I2 R3;
Putting them into the form for our function
    eq1 = Collect[eqI1, {I1, I2}]
    
    eq2 = Collect[eqI2, {I1, I2}]
    
Using our function to see the resulting Matrix Equation
    {y, m} = CreateMatrixForm[{I1, I2}];
    
Solving for the transfer function

Using Mathematica’s built in Linear Solve Function, we can easily solve this matrix equation symbolically.

    i2 = LinearSolve[m, y][[2]]

((1 + C1 R2 s) Vs) / (R1 + R3 + L1 s + L2 s + C1 R1 R2 s + C1 R1 R3 s +
     C1 R2 R3 s + C1 L2 R1 s2 + C1 L1 R2 s2 + C1 L2 R2 s2 + C1 L1 R3 s2 + C1 L1 L2 s3)

    Vout = i2 R3

(R3 (1 + C1 R2 s) Vs) / (R1 + R3 + L1 s + L2 s + C1 R1 R2 s + C1 R1 R3 s +
     C1 R2 R3 s + C1 L2 R1 s2 + C1 L1 R2 s2 + C1 L2 R2 s2 + C1 L1 R3 s2 + C1 L1 L2 s3)

Finding the ratio of Vout to Vin, we can find the Transfer Function.

    
Hs =

(R3 (1 + C1 R2 s)) / (R1 + R3 + L1 s + L2 s + C1 R1 R2 s + C1 R1 R3 s +
     C1 R2 R3 s + C1 L2 R1 s2 + C1 L1 R2 s2 + C1 L2 R2 s2 + C1 L1 R3 s2 + C1 L1 L2 s3)

Sensitivity Analysis

Worst-Case Analysis requires us to find the maximum variation that this equation will have. To accomplish
this we need to first find the sensitivity of each variable in the transfer function. We can easily do this by taking the derivative of the equation with respect to each variable, then compute the resulting value of this derivative using the nominal value of the circuit parameters. If the result is Positive, we will put the tolerances as low to high, if it is Negative, we will put the tolerances as high to low.
vars = Variables[Hs]
{R3, C1, R2, s, R1, L1, L2}

varTable = {R3 → 1000, C1 → 1 × 10-6, R2 → 100, R1 → 5, L1 → 2 × 10-6, L2 → 5 × 10-6, s → 1};
TableForm[Table[{vars[[i]], N[D[Hs, vars[[i]]] /. varTable]} , {i, Length[vars]}]]

R3     4.95033 × 10-6
C1     -4.94934
R2     4.94934 × 10-12
s      -4.95627 × 10-6
R1     -0.000991055
L1     -0.000991055
L2     -0.00099007

Finding the Transfer Function and plotting the Bode Plot
    varTable =
        {R3 → 1000 {1 - 0.05, 1 + 0.05}, C1 → 1 × 10-6 {1 + 0.25, 1 - 0.15}, R2 → 100 {1 - 0.05, 1 + 0.05},
         R1 → 5 {1 + 0.05, 1 - 0.05}, L1 → 2 × 10-6 {1 + 0.1, 1 - 0.1}, L2 → 5 × 10-6 {1 + 0.1, 1 - 0.1}};

    Hjω = Hs /. s → ⅈ 2 π f /. varTable
    
    

We can “jazz-up” the Bode Plot by adding a frame to it, then labelling that frame, add gridlines and a Title.

    LogLinearPlot[{20 Log10[Abs[Hjω]][[1]], 20 Log10[Abs[Hjω]][[2]]},
        {f, 50, 106}, Frame → True, GridLines → Automatic,
        FrameLabel → {"Freq (Hz)", "Gain (dB)"}, PlotLabel → "Bode Magnitude Plot"]


And we can make a Phase Plot in a similar fashion.

    {f, 50, 106}, PlotRange → All, Frame → True, GridLines → Automatic,
    FrameLabel → {"Freq (Hz)", "Phase Shift (°)"}, PlotLabel → "Bode Phase Plot"]



{950. (0.00104685 + 0.000260747 ⅇ-1.9499×108 t - 0.00125322 ⅇ-4.05698×107 t - 0.0000543777 ⅇ-7983.73 t),
    1050. (0.000948092 + 0.000235313 ⅇ-2.63389×108 t - 0.0011427 ⅇ-5.42389×107 t - 0.0000407083 ⅇ-10 723.5 t)}

Now “jazz-up” the time domain plot in a similar fashion

    Plot[{Vot[[1]] /. t → time 10-3, Vot[[2]] /. t → time 10-3}, {time, 0, 100}, PlotRange → All,
        FrameLabel → {"Time (ms)", "Output Voltage (V)"}, PlotLabel → "Step Response"]


Before submitting the report, it is always a good idea to use a spell checker. Mathematica has one under Edit-> Check Spelling.

To format the document for printing, use File-> Printing Settings-> Show Page Breaks. Then you can make size the plots so they fill the page and a description is on the same page as the Plot.

Worst Case Analysis using Mathematica

KCL Solution

Sallen-Key Low-Pass Filter Analysis



Symbolic Analysis

Write nodal equations
In[•]:= eqIA = + (VA - VD) C2 s + ;
In[•]:= eqIB = + (VB - 0) C1 s + ios - ib;
In[•]:= eqIC = - ib - ios + ;
In[•]:= eqVy = Aol (VC - Vos - VB);
In[•]:= eqID = /. Vy → eqVy;
Collect terms and list them as eq1, eq2, etc.
In[•]:= eq1 = Collect[eqIA, {VA, VB, VC, VD}]
Out[•]:=
In[•]:= eq2 = Collect[eqIB, {VA, VB, VC, VD}]
Out[•]:=
In[•]:= eq3 = Collect[eqIC, {VA, VB, VC, VD}]
Out[•]:=
In[•]:= eq4 = Collect[eqID, {VA, VB, VC, VD}]
Out[•]:=
Invoke our function.
Create the matrix form.

In[•]:= {y, m} = CreateMatrixForm[{VA, VB, VC, VD}];

Find Vout as a function of Vin

In[•]:= vo = LinearSolve[m, y][[4]]

Out[•]:=
Note

This type of circuit does not allow us to extract a typical Transfer Function in the form of Voutput/Vinput. It’s transfer function is a function of the input voltage.


Numerical Analysis

Sensitivity Analysis
In[•]:=  vars = Variables[vo]
out[•]= {R3, R4, Rin, R2, C1, s, R1, C2, Ro, Aol, ib, ios, Vin, Vos}

In[•]:=  k = 103;
      μ = 10-6; 

In[•]:=  varTable = {R1 → 13.3 k, R2 → 41.2 k, R3 → 10 k,
         R4 → 56.9 k, C1 → 0.0068 μ, C2 → 0.0068 μ, Rin → 1000 k, Ro → 10,
         Aol → 10000, ib → 0.002 μ, ios → 0.001 μ, Vos → 0.01, s → 1, Vin → 0}
Out[•]:= {R1 → 13 300., R2 → 41 200., R3 → 10 000, R4 → 56 900., C1 → 6.8 × 10-9, C2 → 6.8 × 10-9,
             Rin → 1 000 000, Ro → 10, Aol → 10 000, ib → 2. × 10-9, ios → 1. × 10-9, Vos → 0.01, s → 1, Vin → 0}

In[•]:=  TableForm[Table[{vars[[i]], D[vo, vars[[i]]] /. varTable}, {i, Length[vars]}]]
Out[•]//TableForm:=
              R3       -5.73562 × 10-6
              R4       1.00502 × 106
              Rin      -3.828 × 10-13
              R2       6.69333 × 10-9
              C1       -22.097
              s          0.000040518
              R1       9.75049 × 10-9
              C2       5980.63
              Ro       6.78385 × 10-10
              Aol      -4.53903 × 10-9
              ib        307 956.
              ios      -421 902.
              Vin      6.69548
              Vos     6.69857

We will now assume that the Op Amp is an ISL70444SEH device. Resistors are 1% tolerance with another 1% to account for EOL deviations and Temperature operation. Capacitors are assumed to have a total tolerance of -19% to + 15%, which takes into account initial tolerance, temperature variation and EOL.

So the varTable takes on the form, using the sensitivity table above

In[•]:= varTable = {R1 → 13.3 k {1 - 0.02, 1 + 0.02}, R2 → 41.2 k {1 - 0.02, 1 + 0.02},
        R3 → 10 k {1 + 0.02, 1 - 0.02}, R4 → 56.9 k {1 - 0.02, 1 + 0.02},
        C1 → 0.0068 μ {1 + 0.15, 1 - 0.19}, C2 → 0.0068 μ {1 - 0.19, 1 + 0.15}, Rin → 10 000, Ro → 60,
        Aol → 31 623, ib → 650 × 10-9 {-1, 1}, ios → 50 × 10-9 {1, -1}, Vos → 0.5 × 10-3 {1, -1}};

Circuit Response Analysis

In[•]:= Plot[{(vo /. varTable /. s → 0)[[1]], (vo /. varTable /. s → 0)[[2]]},
     {Vin, -5, 5}, Frame → True, GridLines → Automatic, PlotRange → All,
     FrameLabel → {"Filter Input (V)", "Filter Output (V)"},
     PlotLabel → "Filter Circuit DC Response"]

Steady State Response at 1.5 kHz

In[•]:= Plot[{Abs[(vo /. varTable /. s → ⅈ 2 π 1500)][[1]] Sign[Vin],
     Abs[(vo /. varTable /. s → ⅈ 2 π 1500)][[2]] Sign[Vin]},
     {Vin, -5, 5}, Frame → True, GridLines → Automatic, PlotRange → All,
     FrameLabel → {"Filter Input (V)", "Filter Output (V)"},
     PlotLabel → "Filter Circuit Steady State Response"]

Lets say we want to see the steady state response through a series of frequencies.

We will now assume that the Op Amps Power Supply is +15V to -15V. So the output can never be greater than these values.

In[•]:= Animate[Plot[{Abs[(vo /. varTable /. s → ⅈ 2 π f)][[1]] Sign[Vin],
      Abs[(vo /. varTable /. s → ⅈ 2 π f)][[2]] Sign[Vin]}, {Vin, -5, 5},
      Frame → True, GridLines → Automatic, PlotRange → {{-5.1, 5.1}, {-15, 15}},
      Filling → {1 → {2}}, FrameLabel → {"Filter Input (V)", "Filter Output (V)"},
      PlotLabel → "Filter Circuit Steady State Response @ f = " <> ToString[f] <> " Hz"], {f, 0, 2500, 100}]

Note that the shaded area, is the area that the circuit will output depending on the component parameters.

Break Frequency

Now we will assume that the input voltage is 5 Volts and look at the Frequency Response of circuit by making a Bode Plot

In[•]:= Vof = vo /. varTable /. s → ⅈ 2 π f;
In[•]:= LogLinearPlot[{20 Log10[Abs[ /. Vin → 5]][[1]], 20 Log10[Abs[ /. Vin → 5]][[2]]},
{f, 10, 10 000}, Frame → True, GridLines → Automatic, FrameLabel → {"Frequency (Hz)", "Gain (dB)", "Maximum Vin (5V)"}, PlotLabel → "Filter Frequency Response"]

Now we will assume that the input voltage is 1 Volt and look at the Frequency Response of circuit by making a Bode Plot

In[•]:= LogLinearPlot[{20 Log10[Abs[ /. Vin → 1]][[1]], 20 Log10[Abs[/. Vin → 1]][[2]]},
{f, 10, 10 000}, Frame → True, GridLines → Automatic, FrameLabel → {"Frequency (Hz)", "Gain (dB)", "Vin (1V)"}, PlotLabel → "Filter Frequency Response"]

Now, lets see how the Bode Plot changes as the input voltage changes

In[•]:= Animate[LogLinearPlot[
      
{20 Log10[Abs[/. Vin → v]][[1]], 20 Log10[Abs[ /. Vin → v]][[2]]}, {f, 10, 10000},
Frame → True, GridLines → Automatic, Filling → {1 → {2}}, PlotRange → {All, {-25, 35}}, FrameLabel → {"Frequency (Hz)", "Gain (dB)", "Vin (" <> ToString[v] <> " V)"}, PlotLabel → "Filter Frequency Response"], {v, -5, 5, 2}]

Note that the shaded area, is the area that the circuit will output depending on the component parameters.