%This program takes a netlist (similar to SPICE), parses it to derive the
%circuit equations, then solves them symbolically.
%
%Full documentation available at www.swarthmore.edu/NatSci/echeeve1/Ref/mna/MNA1.html
%
if ~exist('FirstTime_rjla')
disp(sprintf('Full documentation available at www.swarthmore.edu/NatSci/echeeve1/Ref/mna/MNA1.html'));
end
disp(sprintf('\n\nStarted -- please be patient.\n'));
[Name N1 N2 arg3]=textread(fname,'%s %s %s %s ');
tic
%Initialize
numElem=0; %Number of passive elements.
numV=0; %Number of independent voltage sources
numO=0; %Number of op amps
numI=0; %Number of independent current sources
numNode=0; %Number of nodes, not including ground (node 0).
%Parse the input file
for i=1:length(Name),
switch(Name{i}(1)),
case {'R','L','C'},
numElem=numElem+1;
Element(numElem).Name=Name{i};
Element(numElem).Node1=str2num(N1{i});
Element(numElem).Node2=str2num(N2{i});
try
Element(numElem).Value=str2num(arg3{i});
catch
Element(numElem).Value=nan;
end
case 'V',
numV=numV+1;
Vsource(numV).Name=Name{i};
Vsource(numV).Node1=str2num(N1{i});
Vsource(numV).Node2=str2num(N2{i});
try
Vsource(numV).Value=str2num(arg3{i});
catch
Vsource(numV).Value=nan;
end
case 'O',
numO=numO+1;
Opamp(numO).Name=Name{i};
Opamp(numO).Node1=str2num(N1{i});
Opamp(numO).Node2=str2num(N2{i});
Opamp(numO).Node3=str2num(arg3{i});
case 'I'
numI=numI+1;
Isource(numI).Name=Name{i};
Isource(numI).Node1=str2num(N1{i});
Isource(numI).Node2=str2num(N2{i});
try
Isource(numI).Value=str2num(arg3{i});
catch
Isource(numI).Value=nan;
end
end
numNode=max(str2num(N1{i}),max(str2num(N2{i}),numNode));
end
%Preallocate all of the cell arrays #################################
G=cell(numNode,numNode);
V=cell(numNode,1);
I=cell(numNode,1);
if ((numV+numO)~=0),
B=cell(numNode,numV+numO);
C=cell(numV+numO,numNode);
D=cell(numV+numO,numV+numO);
E=cell(numV+numO,1);
J=cell(numV+numO,1);
end
%Done preallocating cell arrays -------------------------------------
%Fill the G matrix ##################################################
%Initially, make the G Matrix all zeros.
[G{:}]=deal('0');
%Now fill the G matrix with conductances from netlist
for i=1:numElem,
n1=Element(i).Node1;
n2=Element(i).Node2;
%Make up a string with the conductance of current element.
switch(Element(i).Name(1)),
case 'R',
g = ['1/' Element(i).Name];
case 'L',
g = ['1/s/' Element(i).Name];
case 'C',
g = ['s*' Element(i).Name];
end
%If neither side of the element is connected to ground
%then subtract it from appropriate location in matrix.
if (n1~=0) & (n2~=0),
G{n1,n2}=[ G{n1,n2} '-' g];
G{n2,n1}=[ G{n2,n1} '-' g];
end
%If node 1 is connected to graound, add element to diagonal
%of matrix.
if (n1~=0),
G{n1,n1}=[ G{n1,n1} '+' g];
end
%Ditto for node 2.
if (n2~=0),
G{n2,n2}=[ G{n2,n2} '+' g];
end
%Go to next element.
% i=i+4;
end
%The G matrix is finished -------------------------------------------
%Fill the I matrix ##################################################
[I{:}]=deal('0');
for j=1:numNode,
for i=1:numI,
if (Isource(i).Node1==j),
I{j}=[I{j} '-' Isource(i).Name];
elseif (Isource(i).Node2==j),
I{j}=[I{j} '+' Isource(i).Name];
end
end
end
%The I matrix is done -----------------------------------------------
%Fill the V matrix ##################################################
for i=1:numNode,
V{i}=['v_' num2str(i)];
end
%The V matrix is finished -------------------------------------------
if ((numV+numO)~=0),
%Fill the B matrix ##################################################
%Initially, fill with zeros.
[B{:}]=deal('0');
%First handle the case of the independent voltage sources.
for i=1:numV, %Go through each independent source.
for j=1:numNode %Go through each node.
if (Vsource(i).Node1==j), %If node is first node,
B{j,i}='1'; %then put '1' in the matrices.
elseif (Vsource(i).Node2==j), %If second node, put -1.
B{j,i}='-1';
end
end
end
%Now handle the case of the Op Amp
for i=1:numO,
for j=1:numNode
if (Opamp(i).Node3==j),
B{j,i+numV}='1';
else
B{j,i+numV}='0';
end
end
end
%The B matrix is finished -------------------------------------------
%Fill the C matrix ##################################################
%Initially, fill with zeros.
[C{:}]=deal('0');
%First handle the case of the independent voltage sources.
for i=1:numV, %Go through each independent source.
for j=1:numNode %Go through each node.
if (Vsource(i).Node1==j), %If node is first node,
C{i,j}='1'; %then put '1' in the matrices.
elseif (Vsource(i).Node2==j), %If second node, put -1.
C{i,j}='-1';
end
end
end
%Now handle the case of the Op Amp
for i=1:numO,
for j=1:numNode
if (Opamp(i).Node1==j),
C{i+numV,j}='1';
elseif (Opamp(i).Node2==j),
C{i+numV,j}='-1';
else
C{i+numV,j}='0';
end
end
end
%The C matrix is finished ------------------------------------------
%Fill the D matrix ##################################################
%The D matrix is non-zero only for CCVS and VCVS (not included
%in this simple implementation of SPICE)
[D{:}]=deal('0');
%The D matrix is finished -------------------------------------------
%Fill the E matrix ##################################################
%Start with all zeros
[E{:}]=deal('0');
for i=1:numV,
E{i}=Vsource(i).Name;
end
%The E matrix is finished -------------------------------------------
%Fill the J matrix ##################################################
for i=1:numV,
J{i}=['I_' Vsource(i).Name];
end
for i=1:numO,
J{i+numV}=['I_' Opamp(i).Name];
end
%The J matrix is finished -------------------------------------------
end %if ((numV+numO)~=0)
%Form the A, X, and Z matrices (As cell arrays of strings).
if ((numV+numO)~=0),
Acell=[deal(G) deal(B); deal(C) deal(D)];
Xcell=[deal(V); deal(J)];
Zcell=[deal(I); deal(E)];
else
Acell=[deal(G)];
Xcell=[deal(V)];
Zcell=[deal(I)];
end
%Declare symbolic variables #########################################
%This next section declares all variables used as symbolic variables.
%Make "s" a symbolic variable
SymString='syms s ';
%Add each of the passive elements to the list of symbolic variables.
for i=1:numElem,
SymString=[SymString Element(i).Name ' '];
end
%Add each element of matrix J and E to the list of symbolic variables.
for i=1:numV,
SymString=[SymString J{i} ' '];
SymString=[SymString E{i} ' '];
end
%Add each opamp output to the list of symbolic variables.
for i=1:numO,
SymString=[SymString J{i+numV} ' '];
end
%Add independent current sources to the list of symbolic variables.
for i=1:numI,
SymString=[SymString Isource(i).Name ' '];
end
%Add independent voltage sources to list of symbolic variables.
for i=1:numNode,
SymString=[SymString V{i} ' '];
end
%Evaluate the string with symbolic variables
eval(SymString);
%Done declaring symbolic variables ----------------------------------
%Create the variables A, X, and Z ###################################
%Right now the matrices Acell, Xcell and Zcell hold cell arrays of
%strings. These must be converted to a symbolic array. This is
%accompplished by creating strings that represent the assignment of
%the symbolic arrays, and then evaluating these strings.
%Create assignments for three arrays
Astring='A=[';
Xstring='X=[';
Zstring='Z=[';
for i=1:length(Acell), %for each row in the arrays.
for j=1:length(Acell), %for each column in matrix A.
Astring=[Astring ' ' Acell{i,j}]; %Get element from Acell
end
Astring=[Astring ';']; %Mark end of row with semicolon
Xstring=[Xstring Xcell{i} ';']; %Enter element into array X;
Zstring=[Zstring Zcell{i} ';']; %Enter element into array Z;
end
Astring=[Astring '];']; %Close array assignment.
Xstring=[Xstring '];'];
Zstring=[Zstring '];'];
%Evaluate strings with array assignments.
eval([Astring ' ' Xstring ' ' Zstring])
%Done creating the variables A, X, and Z ----------------------------
%Solve matrrix equation - this is the meat of the algorithm.
V=simplify(inv(A)*Z);
%Evaluate each of the unknowns in the matrix X.
for i=1:length(V),
eval([char(X(i)) '=' char(V(i)) ';']);
end
%Assign a numeric value to each passive element, if one is provided.
for i=1:numElem
if ~isnan(Element(i).Value),
eval([Element(i).Name '=' num2str(Element(i).Value) ';']);
end
end
%Assign a numeric value to each voltage source, if one is provided.
for i=1:numV
if ~isnan(Vsource(i).Value),
eval([Vsource(i).Name '=' num2str(Vsource(i).Value) ';']);
end
end
%Assign a numeric value to each passive element, if one is provided.
for i=1:numI
if ~isnan(Isource(i).Value),
eval([Isource(i).Name '=' num2str(Isource(i).Value) ';']);
end
end
disp(sprintf('Done! Elapsed time = %g seconds.\n',toc));
beep;
disp('Netlist');
for i=1:size(Name),
disp(sprintf(' %s %s %s %s',Name{i},N1{i},N2{i},arg3{i}));
end
disp(' ');
disp('Solved variables:');
disp(X)
if ~exist('FirstTime_rjla')
disp(sprintf('\nFull documentation available at www.swarthmore.edu/NatSci/echeeve1/Ref/mna/MNA1.html'));
FirstTime_rjla=1;
end