{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"\n",
"# Resistor Network\n",
"\n",
"### Examples - Electromagnetism\n",
"\n",
"By Magnus A. Gjennestad, Vegard Hagen, Aksel Kvaal, Morten Vassvik, Trygve B. Wiig, Peter Berg and Magnus Dahle\n",
"\n",
"Last edited: March 22nd 2018 \n",
"___\n",
"\n",
"\n",
"### Problem Formulation and Notation\n",
"\n",
"Within this example, we'll consider a resistor network consisting of $N$ repetitive units. Each unit has two resistors of magnitude $R$ and $12R$, respectively. The units are connected to a battery of voltage $V_0$, as shown in the figure below.\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![circuit1](images/4ec_image_1.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The goal of this example is to calculate the toal current propagating through the cicuit, provided by the battery. The following image explains the applied notations and variables."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![circuit2](images/4ec_image_2.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Special Case: $N=1$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"When solving a problem like this, it is often useful to look at special scenarios, if available, before one tries to solve the general problem. We will now look at two such simplified problems.\n",
"\n",
"First, consider the special case when $N=1$. The circuit then looks like the following,"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![circuit2](images/4ec_image_3.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This reduced problem is easily solved by defining $R_{eff}$, the effective resistance of the circuit connected to the battery. This implies that we may represent the circuit by the following diagram"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![circuit2](images/4ec_image_4.png)"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"where $R_{eff} = R+12R=13R$. Then, by Ohm's law,\n",
"\n",
"$$\n",
"I_{1,1} = \\frac{V_0}{13R} = \\frac{1}{13} \\frac{\\textrm{V}}{\\Omega} \\approx 0.0769 \\textrm{A}\n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Special Case: $N\\to\\infty$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As another special scenario, we will consider the case when the number of units $N$ goes to infinity. This scenario is not so trivial. Obviously, we are providing more options for the current to flow as $N\\to\\infty$. Hence, we expect the resistance to decrease in this limit. Take a minute to think about how you would solve it before you read on."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Again, we can consider an effective resistance $R_{eff}$ and represent the whole circuit as before (last image). Now, take the circuit from the previuos page with infinitely many repetitive units and add one more unit to it, so that it can be represented by the following circuit diagram"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![circuit2](images/4ec_image_5.png)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since $N$ is infinitely large, adding one more unit should not change the effective resistance $R_{eff}$ of the whole circuit. In other words, $12R$ and $R_{eff}$ are in parallel in the above sketch and the resistance of the entire circuit $R_{total}$ is still $R_{eff}$. By this argument, we can relate $R_{eff}$ to itself by\n",
"\n",
"$$\n",
"R_{total} = R_{eff} = R + \\frac{1}{\\frac{1}{12R} + \\frac{1}{R_{eff}}}\n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By solving this quadric equation for $R_{eff}$ and demanding that $R_{eff}$ be positive, we obtain\n",
"\n",
"$$\n",
"R_{eff} = 4R = 4\\Omega\n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Such that by Ohm's law, we find\n",
"$$\n",
"I_{1,1} = \\frac{V_0}{4R} = \\frac{1}{4} \\frac{\\textrm{V}}{\\Omega} \\approx 0.25 \\textrm{A}\n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Setting Up the System of Equations"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, we turn to the more general case when $1exactly the amount we need to determine all $N$ voltages $V_i$ for $i=2,\\ldots,N-1;$ uniquely."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Moreover, these equations can be formulated as a matrix problem $\\mathcal{A}\\boldsymbol{V}=\\boldsymbol{b}$\n",
"\n",
"$$\n",
"\\begin{bmatrix} 25/12R & -1/R & 0 & \\dots & 0 \\\\ \n",
" -1/R & 25/12R & -1/R & \\dots & 0 \\\\\n",
" \\vdots& \\ddots &\\ddots& \\ddots& \\vdots \\\\\n",
" 0 & \\dots &-1/R & 25/12R & -1/R \\\\\n",
" 0 & \\dots & 0 & -1/R & 25/12R\n",
"\\end{bmatrix} \\cdot \n",
"\\begin{bmatrix} V_1 \\\\ V_2 \\\\ \\vdots \\\\ V_{N-1} \\\\ V_N \\end{bmatrix} =\n",
"\\begin{bmatrix} V_0/R \\\\ 0 \\\\ \\vdots \\\\ 0 \\\\ 0 \\end{bmatrix} \n",
"$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, finding the unknown voltages amounts to solving this matrix equation $\\mathcal{A}\\boldsymbol{V}=\\boldsymbol{b}$, for the unknown voltage vector $\\boldsymbol{V}$. The matrix $\\mathcal{A}$ and the vector $\\boldsymbol{b}$ are given by the resistances within the circuit and the voltage $V_0$. Subsequently, we can calculate the total current by Ohm's law,\n",
"\n",
"$$\n",
"I_{1,1} = \\frac{V_0 - V_1}{R}\n",
"$$\n",
"\n",
"In Python, the first thing we need to do is defineing $V_0$, $R$ and $N$."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"R = 1.0 # Resistance [Ohm]\n",
"V0 = 1.0 # Applied voltage [V]\n",
"N = 10 # Number of repitative units [dimless]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then, we need to set up the matrix $\\mathcal{A}$ and the vector $\\boldsymbol{b}$ of the matrix equation. We start by initializing them both with zeros before filling them and also define two variables, $a=25/12R$ and $c=-1/R$ to simplify their filling."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# We use numpy arrays for increased efficiency\n",
"# of matrix operations and functionality.\n",
"import numpy as np \n",
"\n",
"A = np.zeros((N,N)) # Matrix of dimension NxN\n",
"b = np.zeros(N) # Vector of length N\n",
"a = 25.0/(12*R) # Scalar (constant)\n",
"c = -1.0/R # Scalar (constant)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we set up $\\boldsymbol{b}$, and $\\mathcal{A}$ row by row."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# the b-vector is all zeros except for first entry. Thus,\n",
"b[0] = V0/R\n",
"\n",
"# Set up first row\n",
"A[0,0] = a\n",
"A[0,1] = c \n",
"\n",
"# Set up last row\n",
"A[N-1,N-1] = a\n",
"A[N-1,N-2] = c\n",
"\n",
"# Set up all other rows\n",
"# OBS: if you're running Python 2.7 (or lower) you might want to use\n",
"# the 'xrange()' instead of 'range()' depending on the size of 'N'.\n",
"for row in range(1,N-1):\n",
" A[row,row-1] = c\n",
" A[row,row ] = a\n",
" A[row,row+1] = c\n",
"\n",
"# You may want to print A,b to see if it was initialized correctly:\n",
"# print(A,b)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Then we can solve the system of equations by using the built-in *Numerical Python Linear Algebra Solver*"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Voltages = [ 0.74895759 0.56032831 0.41839305 0.31132388 0.23019837 0.16825606\n",
" 0.12033508 0.08244203 0.05141914 0.02468119]\n",
"\n",
"I_11 = 0.251042413381\n"
]
}
],
"source": [
"Voltages = np.linalg.solve(A,b)\n",
"print(\"Voltages = \", Voltages)\n",
"\n",
"I11 = (V0 - Voltages[0])/R\n",
"print(\"\\nI_11 = \", I11)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We see that when $N$ becomes large (or actually already at $N\\geq15$), $I_{1,1}$ approaches the limit we found analytically as $N\\to\\infty$. That is $I_{1,1}\\to 1/4$.\n",
"\n",
"You should note that, even though the built-in solver we use in this example is implemented to be effective, it is a general solver which do **not** take advantage of the fact that $\\mathcal{A}$ is a sparse matrix for this problem.\n",
"\n",
"If $\\mathcal{A}$ becomes really large, then this solver would eventually become very slow as it unnessecarily iterates over all the zeros. As an alternative, one can use the built-in functionality of the *Scientific Python Sparse Linear Algebra* package. However, this module requires $\\mathcal{A}$ to be stored in a specific (sparse) manner."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Voltages = [ 0.74895759 0.56032831 0.41839305 0.31132388 0.23019837 0.16825606\n",
" 0.12033508 0.08244203 0.05141914 0.02468119]\n",
"\n",
"I_11 = 0.251042413381\n"
]
}
],
"source": [
"from scipy import sparse\n",
"import scipy.sparse.linalg as ssl\n",
"from scipy.sparse.linalg import spsolve\n",
"\n",
"\n",
"# Since our matrix only have non-zero values on \n",
"# THE diagonal, the UPPER(sup) diagonal and the LOWER(sub) diagonal,\n",
"# this is in fact all we need to tell Python.\n",
"\n",
"#Create create a sparse matrix\n",
"\n",
"sup_diag = np.ones(N)*c\n",
"sub_diag = np.ones(N)*c\n",
"the_diag = np.ones(N)*a\n",
" \n",
"# Offset: -1 0 1\n",
"all_diags = [sub_diag, the_diag, sup_diag]\n",
"offsets = np.array([-1, 0, 1])\n",
"\n",
"\n",
"csc=\"csc\" # Computer format of which the matrix is stored\n",
"\n",
"# Define the SPARSE matrix\n",
"A_sparse = sparse.spdiags(all_diags, offsets, N,N, format=csc)\n",
"\n",
"\n",
"# print(A_sparse.todense()) # prints the SPARSE matrix in a DENSE (normal NxN) format.\n",
"\n",
"\n",
"Voltages = spsolve(A_sparse,b)\n",
"print(\"Voltages = \", Voltages)\n",
"\n",
"I11 = (V0 - Voltages[0])/R\n",
"print(\"\\nI_11 = \", I11)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, try to compare running times of the sparse solver, with the standard solver as you increase $N$ to $10, 100, 1000, \\ldots$."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.4"
}
},
"nbformat": 4,
"nbformat_minor": 1
}