Trying to embed circuits in RF Toolbox, getting incomprehensible error cascade

4 views (last 30 days)
I'm trying to do a hierarchical RF circuit analysis, by subclassing circuit, giving it terminals, then adding it to another circuit. It allows me to do the add, but when I try to analyse, I get the following error cascade
Error using ==
Cannot call method 'eq' because one or more inputs of class 'circuit' are heterogeneous and 'eq' is
not sealed. For more details please see the method dispatching rules for heterogeneous arrays.
Error in rf.circuit.flattener/getglobalnode (line 139)
Error in rf.circuit.flattener/makenodeobjects (line 132)
Error in rf.circuit.flattener/buildcircuitlevel (line 80)
Error in rf.circuit.flattener/buildcircuitlevel (line 86)
Error in rf.circuit.flattener/flattencircuit (line 36)
Error in rf.circuit.pcircuit/calc_sparams (line 366)
Error in sparameters (line 180)
inputs{1} = calc_sparams(inputs{:});
Unfortunately, I haven't a clue what this means, as I'm new to 2014a, OO in Matlab, and the RF Toolbox.
When I create a circuit in a script by adding components, adding terminals, and then add that into another circuit in the same script, it will analyse as sparameters without error.
When I subclass circuit and add components, add ports, and analyse its sparameters, that works as well.
Is it the case that I can't add an object subclassed from circuit into another circuit, even if it has terminals? I'm suspicious that it is complaining about ==, and a subclass of circuit is not a circuit object, though it does have a superset of its properties and methods, so should work where a circuit would (I'm coming from Python, where duck-typing is the rule).
Can I nest circuits like this?
For the record, this is my classdef
classdef three_term < circuit
% creates 3 terminal test network
properties
cap
res
ind
end
methods
function s = three_term(name)
s = s@circuit(name);
s.cap = capacitor(10e-12, 'cap_name');
s.ind = inductor(2e-9, 'ind_name');
s.res = resistor(1000, 'res_name');
add(s, [1,2], s.ind);
add(s, [2,0], s.cap);
add(s, [1,0], s.res);
% setports(s, [1,0], [2,0]);
setterminals(s, [0 1 2]);
end
end
end

Accepted Answer

Joe Wargo
Joe Wargo on 13 Jun 2014
Hey Neil,
Thanks for the clarification! I think I have a handle now on what you're trying to do. There's a few workarounds I can offer:
  • Rebuild every time. I know it looks a little crummy and seems like bad computer science, but it's the easiest way forward, and for problems of "manageable size", it shouldn't hurt too much.
  • Keep a handle to the element values you'd like to change. For example:
function [newckt,newres,newind,newcap] = three_term(name)
newckt = circuit(name);
newcap = capacitor(10e-12, 'cap_name');
newind = inductor(2e-9, 'ind_name');
newres = resistor(1000, 'res_name');
add(newckt,[1,2],newind)
add(newckt,[2,0],newcap)
add(newckt,[1,0],newres)
setterminals(newckt,[0 1 2])
Then you can track and change the values of any element you like:
% Create three terminal elements
[tt1,R1,L1,C1] = three_term('a');
[tt2,R2,L2,C2] = three_term('b');
% Add them to new "parent" circuit
parent = circuit;
add(parent,[1 2 3],tt1)
add(parent,[0 2 3],tt2)
setports(parent,[1 0],[2 0],[3 0])
% Set the value of the resistor in "tt1" and find S-parameters
R1.Resistance = 100;
freq = [1e9 2e9];
S = sparameters(parent,freq);
  • Go with your original plan (you'll need to hack circuit.m to make it work). There's nothing inherently wrong with your original idea, but some of the circuit infrastructure isn't designed to handle mixtures of circuit objects and sub-classes of circuit objects. I won't get into the technical jargon, but you'll need to "Seal" the == operator. To do that, put the following method block somewhere in your circuit.m:
methods(Sealed = true)
function bool = eq(varargin)
bool = eq@handle(varargin{:});
end
end
I tested it, and it seems to work fine. Please just keep in mind that this particular solution isn't supported (yet) or documented, and could fail in a future release.
I hope that helps!
Joe
  1 Comment
Neil
Neil on 13 Jun 2014
Hi Joe,
Thanks for confirming I wasn't too far off the mark, just over-optimistic having been spoiled by the way Python 'just gets on with it' if it can.
The 'keep a handle to the variables' approach was what I meant by 'effectively flattening', and I don't really want to go there.
Hacking circuit.m so it can flatten and analyse subclassed circuits sounds like the way to go.
<edit> Was the way way to go, all works now, thankyou very much. </edit>

Sign in to comment.

More Answers (1)

Joe Wargo
Joe Wargo on 10 Jun 2014
Hey Neil,
I think for your use-case, you should not have to use OO design or create a new object type. A MATLAB function should work fine. Consider:
function newckt = three_term(name)
newckt = circuit(name);
newcap = capacitor(10e-12, 'cap_name');
newind = inductor(2e-9, 'ind_name');
newres = resistor(1000, 'res_name');
add(newckt,[1,2],newind)
add(newckt,[2,0],newcap)
add(newckt,[1,0],newres)
setterminals(newckt,[0 1 2])
Then you can create one or more of these at the command line:
>> tt1 = three_term('one');
>> tt2 = three_term('two');
Then, as a simple example, you can add these "sub-circuits" into a "parent-circuit":
>> parent = circuit;
>> add(parent,[0 1 2],tt1)
>> add(parent,[0 2 3],tt2)
Lastly, if you want the S-parameters of the parent circuit, you will need to define ports on the parent circuit, then use the sparameters function:
>> setports(parent,[1 0],[2 0])
>> freq = [1e9 2e9];
>> S = sparameters(parent,freq);
One last note: the node "0" is the global ground. Use it carefully when you have hierarchy in your system.
Hope that helps!
Joe
  1 Comment
Neil
Neil on 13 Jun 2014
Hi Joe,
I fear I've stripped too much out of my actual problem to make it shorter for presentation of the errors I saw. The reason I wanted a fully-fledged class/object for my sub-circuit was so I could use methods for altering its component values in non-trivial ways. I have already established that using a class in this way works, calling methods on my three_term object between analyses of it alone does change its parameters. So I only presented the hierarchical analysis issue.
What I am trying to do, in true OO style, is create a reusable component, with all the complexity tested thoroughly first, and then hidden, that I can embed in other circuits, then analyse.
The way function is being used in your example, the line tt1 = three_term('one'), looks for all the world to me like you're instantiating an object, the function definition just being syntax for defining a lightweight class without methods. I think it effectively has attributes, tt1.newind and tt2.newind are defined within function scope, so are not global.
So the question is, will using a function in the way you suggest allow me to instance the functions then alter the component values? I don't see how, as it doesn't have methods.
Assuming your basic premise works (I have another panic on, don't have time to test it this week), it could form the basis of a workaround that stops short of effectively flattening the hierarchy to get access to the lower level components. I could delete and rebuild the structure between each analysis, which would allow the function definition (ie the lightweight classes' init() method ;-) ) to do the complicated stuff on its input arguments. It's just not the 'create then poke' way of working that I've become used to with Python. I assume that a rebuild each time would be a lot slower than what I'm trying to do. However that's an assumption I ought to test, as it may not be a problem.
thanks for taking the time to help

Sign in to comment.

Categories

Find more on Analysis and Verification in Help Center and File Exchange

Products

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!