classdef subcircuit < circuit & circuitComponent
% SUBCIRCUIT Class for a circuit that can be added to another circuit.
% This class is derived from both CIRCUT and CIRCUITCOMPONENT classes.
%-------------------------------------------------------------------------------------
% Copyright 2018 by Koc University and Deniz Kilinc, A. Gokcen Mahmutoglu, Alper Demir
% All Rights Reserved
%-------------------------------------------------------------------------------------
properties (SetAccess = protected)
numTerms = 0;
externalNodes = node.empty; % Array of external nodes
exNodeNumbers = 0;
voltageVarInd = 0;
end
methods
function obj = subcircuit(varargin)
obj = obj@circuit(varargin{:});
end
function sealComponent(thisSubcircuit)
% we want to generate full equations - no ground removal!
thisSubcircuit.groundNodeNumber = 0;
% set number of independent voltage variables
thisSubcircuit.numIndepVoltVars = thisSubcircuit.numVoltageVars -...
~isempty(thisSubcircuit.groundNode);
% set total number of variables
thisSubcircuit.numVars = thisSubcircuit.numIndepVoltVars + ...
thisSubcircuit.numCurrentVars;
% set external node numbers
thisSubcircuit.exNodeNumbers = [thisSubcircuit.externalNodes.number];
if isempty(thisSubcircuit.exNodeNumbers)
error('This subcircuit does not have any external nodes!');
end
thisSubcircuit.Xi = NaN(thisSubcircuit.numVars,1);
thisSubcircuit.Vi = NaN(thisSubcircuit.numVarsnc,1);
% this has to come last
sealComponent@circuitComponent(thisSubcircuit);
end
function setEquationNumbers(thisSubcircuit)
termNums = thisSubcircuit.termNodeNumbers;
currInd = thisSubcircuit.currentVarInd;
voltInd = thisSubcircuit.parentCircuit.numNodes + ...
thisSubcircuit.voltageVarInd;
nVV = thisSubcircuit.numVoltageVars;
nCV = thisSubcircuit.numCurrentVars;
nExN = thisSubcircuit.numTerms;
exNodeNums = thisSubcircuit.exNodeNumbers;
indMap1 = [exNodeNums setdiff(1:nVV, exNodeNums)];
indMap2 = [termNums voltInd:(voltInd+nVV-1-nExN)];
vNums = zeros(1,nVV);
vNums(indMap1) = indMap2;
cNums = currInd:(currInd+nCV-1);
if ~isempty(thisSubcircuit.groundNode)
gGrNum = thisSubcircuit.terminals(...
thisSubcircuit.externalNodes ==...
thisSubcircuit.groundNode).number;
vNums(vNums == gGrNum) = [];
end
thisSubcircuit.voltEqNums = vNums;
thisSubcircuit.currEqNums = cNums;
end
function setExternalNodes(thisSubcircuit, varargin)
% SETEXTERNALNODES Assign external nodes to this circuit.
% Subcircuits are connected to other circuits trough their
% external nodes. This method sets the nodes in varargin as
% external nodes. The nodes in varargin can be given either
% by their reference or name.
N = nargin-1;
if(N > 0)
thisSubcircuit.externalNodes(N) = node;
for i = 1:N
exNode = thisSubcircuit.findNode(varargin{i});
if ~isempty(exNode)
thisSubcircuit.externalNodes(i) = exNode;
else
error(['This node cannot be set as an external '...
'node because it either does not exist '...
'or is not part of this subcircuit!']);
end
end
thisSubcircuit.numTerms = N;
end
end
function tlnn = getTopLevelNodeNumber(thisSubcircuit, aNodeNumber)
% call the method recursively with the equation number this
% subcircuit is assigned by its parent circuit.
tlnn = thisSubcircuit.parentCircuit.getTopLevelNodeNumber(...
thisSubcircuit.voltEqNums(aNodeNumber));
end
function setParent(thisSubcircuit, circ)
setParent@circuitComponent(thisSubcircuit, circ);
% set the voltage index of the subcircuit
thisSubcircuit.voltageVarInd = circ.numVoltageVars - ...
circ.numNodes + 1;
% Check if the ground node of the circuit is connected to the
% global ground
subGround = thisSubcircuit.groundNode;
if ~isempty(subGround)
exGrInd = find(thisSubcircuit.externalNodes == subGround);
if isempty(circ.groundNode)
error('The parent circuit does not have a ground node!');
elseif isempty(exGrInd)
error('Ground node must be an external node!');
elseif thisSubcircuit.terminals(exGrInd) ~= circ.groundNode
error(['Ground node must be connected to the'...
' ground of the parent circuit!']);
end
end
end
function tlc = getTopLevelCircuit(thisSubcircuit)
if isempty(thisSubcircuit.parentCircuit)
tlc = thisSubcircuit;
else
tlc = thisSubcircuit.parentCircuit.getTopLevelCircuit();
end
end
function forceEquationGeneration(thisSubcircuit)
thisSubcircuit.forceEqGen = true;
if isempty(thisSubcircuit.parentCircuit) == false
thisSubcircuit.parentCircuit.forceEquationGeneration();
end
end
end
methods (Access = protected)
function newSc = copyElement(thisSubcircuit)
newSc = copyElement@circuitComponent(thisSubcircuit);
newSc.nodes = node.empty;
newSc.numNodes = 0;
newSc.components = resistor.empty;
newSc.numCurrentVars = 0;
newSc.Xi = [];
newSc.Vi = [];
newSc.ti = -Inf;
newSc.forceEqGen = false;
newSc.voltageVarInd = 0;
newSc.externalNodes = node.empty;
newSc.voltageSourceSigns = [];
for i = 1:thisSubcircuit.numNodes
newSc.addNode(thisSubcircuit.nodes(i).name);
end
for i = 1:thisSubcircuit.numComponents
cc = thisSubcircuit.components(i);
newSc.addComponent(cc.copy, cc.terminals.name);
end
grnd = thisSubcircuit.groundNode;
if ~isempty(grnd)
newSc.setGroundNode(grnd.name);
end
newSc.setExternalNodes(thisSubcircuit.externalNodes.name);
end
end
end