0001 function [Vn, In, nn] = spice_eit(netlist, freq)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 if ischar(netlist) && strcmp(netlist,'UNIT_TEST'); unittest(); return; end
0048
0049 if nargin < 2
0050 freq = 0;
0051 end
0052 w = 2*pi*freq;
0053 s = j*w;
0054
0055
0056 assert(iscell(netlist), 'error: expected cell array for netlist');
0057 nodes = zeros(length(netlist),2);
0058 delM = zeros(length(netlist),1);
0059 M = 0;
0060 P = 0;
0061 for ii = 1:length(netlist)
0062 tt = netlist{ii};
0063
0064 assert(isnumeric([tt{2:3}]), 'error: expected second and third field netlist to be node numbers');
0065 nodes(ii,:) = uint32([tt{2:3}]);
0066 id = tt{1};
0067 assert(ischar(id),'error: expected first field of netlist to be a component identifier');
0068 if abs(s) == 0
0069
0070 switch id(1)
0071 case 'L'
0072 id = ['Vshort_f0_' id];
0073 tt{1} = id; tt{4} = 0;
0074 netlist{ii,1} = tt;
0075 delM(M+1) = 1;
0076 end
0077 end
0078
0079
0080 if any(strcmp(id(1), {'V','E','H'}))
0081 M = M +1;
0082 Vidx{M} = id;
0083 end
0084
0085 switch id(1)
0086 case 'H'
0087 P = P+1;
0088 case 'E'
0089 P = P+2;
0090 end
0091 end
0092 nodes = uint32(nodes);
0093 gnd = min(nodes(:));
0094 delM = find(delM);
0095
0096
0097 [ii] = unique(sort(nodes(:)));
0098 jj = [1:length(ii)]';
0099 mn = min(nodes(:));
0100 map(ii-mn+1) = jj;
0101 rmap(jj) = ii;
0102
0103 nodes = map(nodes - mn +1);
0104 nodes = nodes -1;
0105
0106
0107
0108 nn = rmap(2:end)';
0109
0110
0111
0112 L = size(nodes,1);
0113 N = length(nn);
0114
0115
0116
0117 Aii = ones(L*4+P,1); Ajj=Aii; Avv=Aii*0;
0118 Bii = ones(L*2,1); Bjj=Bii; Bvv=Bii*0;
0119 Mn = N+1;
0120 Pn = L*4+1;
0121 for tt = 1:L
0122 row = netlist{tt}; val = row{4}; id = row{1};
0123 n1 = nodes(tt,1); n2 = nodes(tt,2);
0124 switch(id(1))
0125 case 'V'
0126 idx = [ ((tt-1)*4+1):((tt-1)*4+4) ];
0127
0128 vp = +1; vn = -1;
0129 if n1 == 0
0130 n1 = 1;
0131 vn = 0;
0132 elseif n2 == 0
0133 n2 = 1;
0134 vp = 0;
0135 end
0136 Aii(idx) = [ Mn Mn n1 n2 ];
0137 Ajj(idx) = [ n1 n2 Mn Mn ];
0138 Avv(idx) = [ vn vp vn vp ];
0139 idx = (tt-1)*2+1;
0140 Bii(idx) = [ Mn ];
0141 Bvv(idx) = [ val ];
0142 Mn = Mn +1;
0143 continue;
0144 case 'F'
0145
0146 Vsrc = row{4};
0147 Mi = find(strcmp(Vsrc, Vidx)) + N;
0148 assert(length(Mi) == 1,sprintf('failed to find %s for %s',Vsrc,id));
0149 gain = row{5}; assert(isnumeric(gain));
0150 idx = [ ((tt-1)*4+1):((tt-1)*4+2) ];
0151
0152 d1 = 1; d2 = 1;
0153 if n1 == 0
0154 n1 = 1;
0155 d1 = 0;
0156 end
0157 if n2 == 0
0158 n2 = 1;
0159 d2 = 0;
0160 end
0161 Aii(idx) = [ n1 n2 ];
0162 Ajj(idx) = [ Mi Mi ];
0163 Avv(idx) = [ +d1 -d2 ]*gain;
0164 continue;
0165 case 'G'
0166
0167 n1 = uint32(row{2});
0168 n2 = uint32(row{3});
0169 n3 = uint32(row{4});
0170 n4 = uint32(row{5});
0171 gain = row{6}; assert(isnumeric(gain));
0172 idx = [ ((tt-1)*4+1):((tt-1)*4+4) ];
0173
0174 d1 = 1; d2 = 1; d3 = 1; d4 = 1;
0175 if n1 == 0
0176 n1 = 1;
0177 d1 = 0;
0178 end
0179 if n2 == 0
0180 n2 = 1;
0181 d2 = 0;
0182 end
0183 if n3 == 0
0184 n3 = 1;
0185 d3 = 0;
0186 end
0187 if n4 == 0
0188 n4 = 1;
0189 d4 = 0;
0190 end
0191
0192
0193 Aii(idx) = [ n1 n2 n1 n2 ];
0194 Ajj(idx) = [ n4 n3 n3 n4 ];
0195 Avv(idx) = [ -d1*d4 -d2*d3 +d1*d3 +d2*d4 ]*gain;
0196 continue;
0197 case 'E'
0198
0199 n1 = uint32(row{2});
0200 n2 = uint32(row{3});
0201 n3 = uint32(row{4});
0202 n4 = uint32(row{5});
0203 gain = row{6}; assert(isnumeric(gain));
0204 idx = [ ((tt-1)*4+1):((tt-1)*4+4) Pn Pn+1 ];
0205
0206 d1 = 1; d2 = 1; d3 = 1; d4 = 1;
0207 if n1 == 0
0208 n1 = 1;
0209 d1 = 0;
0210 end
0211 if n2 == 0
0212 n2 = 1;
0213 d2 = 0;
0214 end
0215 if n3 == 0
0216 n3 = 1;
0217 d3 = 0;
0218 end
0219 if n4 == 0
0220 n4 = 1;
0221 d4 = 0;
0222 end
0223
0224
0225 G = gain;
0226 Aii(idx) = [ Mn Mn n1 n2 Mn Mn ];
0227 Ajj(idx) = [ n1 n2 Mn Mn n3 n4 ];
0228 Avv(idx) = [ -d1 +d2 -d1 +d2 +d3*G -d4*G ];
0229 Pn = Pn +2;
0230 Mn = Mn +1;
0231 continue;
0232 case 'H'
0233
0234 Vsrc = row{4};
0235 Mi = find(strcmp(Vsrc, Vidx)) + N;
0236 assert(length(Mi) == 1,sprintf('failed to find %s for %s',Vsrc,id));
0237 gain = row{5}; assert(isnumeric(gain));
0238 idx = [ ((tt-1)*4+1):((tt-1)*4+4) Pn ];
0239
0240 d1 = 1; d2 = 1; d3 = 1; d4 = 1;
0241 if n1 == 0
0242 n1 = 1;
0243 d1 = 0;
0244 end
0245 if n2 == 0
0246 n2 = 1;
0247 d2 = 0;
0248 end
0249 Aii(idx) = [ Mn Mn n1 n2 Mn ];
0250 Ajj(idx) = [ n1 n2 Mn Mn Mi ];
0251 Avv(idx) = [ -d1 +d2 -d1 +d2 gain ];
0252 Pn = Pn +1;
0253 Mn = Mn +1;
0254 continue;
0255 case 'I'
0256 idx = [ ((tt-1)*2+1):((tt-1)*2+2) ];
0257 ip = val; in = -val;
0258 if n1 == 0
0259 n1 = 1;
0260 in = 0;
0261 elseif n2 == 0
0262 n2 = 1;
0263 ip = 0;
0264 end
0265 Bii(idx) = [ n1 n2 ];
0266 Bvv(idx) = [ in ip ];
0267 continue;
0268 case 'R'
0269 y = 1/val;
0270 case 'C'
0271 y = s*val;
0272 case 'L'
0273 y = 1/(s*val);
0274 otherwise
0275 error(['unhandled netlist component type: ' id]);
0276 end
0277 if n1 == n2; error(sprintf('bad netlist @ line#%d: n1(%d)==n2(%d)',tt,n1,n2)); end
0278
0279
0280 yn = -y; y1 = y; y2 = y;
0281
0282 if n1 == 0
0283 n1 = 1;
0284 yn = 0;
0285 y1 = 0;
0286 elseif n2 == 0
0287 n2 = 1;
0288 yn = 0;
0289 y2 = 0;
0290 end
0291 idx = [ ((tt-1)*4+1):((tt-1)*4+4) ];
0292 Aii(idx) = [n1 n2 n1 n2];
0293 Ajj(idx) = [n2 n1 n1 n2];
0294 Avv(idx) = [yn yn y1 y2];
0295
0296
0297
0298
0299
0300 end
0301
0302
0303
0304
0305 A = sparse(Aii,Ajj,Avv,N+M,N+M);
0306 B = sparse(Bii,Bjj,Bvv,N+M,1);
0307
0308
0309
0310
0311
0312 X = A\B;
0313 Vn = full(X(1:N));
0314 In = full(X(N+1:N+M));
0315 In(delM) = [];
0316
0317 function unittest()
0318 pass = 1;
0319 netlist_rlc = {{'R1', 0, 1, 1e3},
0320 {'L1', 0, 1, 1},
0321 {'C1', 0, 1, 5e-6},
0322 {'RC2', 2, 1, 1},
0323 {'R2', 3, 2, 1},
0324 {'V1', 0, 3, 1}};
0325 tol = eps*10;
0326 for ii = 1:9
0327 switch(ii)
0328 case 1
0329 desc = 'voltage divider';
0330 netlist = {{'R1', 1, 2, 1},
0331 {'R2', 0, 2, 1},
0332 {'V0', 0, 1, 2}};
0333 Ev = [2,1]';
0334 Ei = [-1]';
0335 Enn = [1 2]';
0336 freq = 0;
0337 case 2
0338 desc = 'resistor network; gnd = n#4';
0339
0340 netlist = {{'R1', 1, 2, 2},
0341 {'R2', 1, 3, 4},
0342 {'R3', 2, 3, 5.2},
0343 {'R4', 3, 4, 6},
0344 {'R5', 2, 4, 3},
0345 {'V1', 4, 1, 6},
0346 {'V0', 0, 4, 0}};
0347 Ev = [6,3.6,3.6,0]';
0348 Ei = [-1.8,0]';
0349 Enn = [1 2 3 4]';
0350 freq = 0;
0351 case 3
0352 desc = 'reactive elements, f=0';
0353 netlist = netlist_rlc;
0354 Ev = [0.0,0.5,1.0]';
0355 Ei = [-0.5]';
0356 Enn = [1 2 3]';
0357 freq = 0;
0358 case 4
0359 desc = 'reactive elements, f=1';
0360 netlist = netlist_rlc;
0361 Ev = [0.90655 + 0.28793i;
0362 0.95328 + 0.14397i;
0363 1];
0364 Ei = -0.04672 + 0.14397i;
0365 Enn = [1 2 3]';
0366 freq = 1;
0367 tol = 6e-6;
0368 case 5
0369 desc = 'reactive elements, f=10';
0370 netlist = netlist_rlc;
0371 Ev = [0.99704 + 0.03105i;
0372 0.99852 + 0.01552i;
0373 1.0];
0374 Ei = -0.00148 + 0.01552i;
0375 Enn = [1 2 3]';
0376 freq = 10;
0377 case 6
0378 desc = 'voltage controlled current source VCCS G';
0379 netlist = {{'V1', 0, 1, 1},
0380 {'R1', 0, 1, 1},
0381 {'RL', 0, 2, 1},
0382 {'G1', 0, 2, 0, 1, 5}};
0383 Ev = [1,-5]';
0384 Ei = [-1]';
0385 Enn = [1 2]';
0386 freq = 0;
0387 case 7
0388 desc = 'current controlled current source CCCS F';
0389 netlist = {{'V1', 0, 1, 1},
0390 {'R1', 0, 1, 1},
0391 {'RL', 0, 2, 1},
0392 {'F1', 0, 2, 'V1', 5}};
0393 Ev = [1,-5]';
0394 Ei = [-1]';
0395 Enn = [1 2]';
0396 freq = 0;
0397 case 8
0398 desc = 'voltage controlled voltage source VCVS E';
0399 netlist = {{'V1', 0, 1, 1},
0400 {'R1', 0, 1, 1},
0401 {'RL', 0, 2, 1},
0402 {'E1', 0, 2, 0, 1, 5}};
0403 Ev = [1,+5]';
0404 Ei = [-1,-5]';
0405 Enn = [1 2]';
0406 freq = 0;
0407 case 9
0408 desc = 'current controlled voltage source CCVS H';
0409 netlist = {{'V1', 0, 1, 1},
0410 {'R1', 0, 1, 1},
0411 {'RL', 0, 2, 1},
0412 {'H1', 0, 2, 'V1', 5}};
0413 Ev = [1,+5]';
0414 Ei = [-1,-5]';
0415 Enn = [1 2]';
0416 freq = 0;
0417 otherwise
0418 error('oops');
0419 end
0420 desc = [sprintf('#%d ',ii) desc];
0421
0422 disp('-----------------------------------------');
0423 print_netlist(desc,netlist);
0424 [v,i,nn]=spice_eit(netlist,freq);
0425 pass=cmp(pass,'voltages',v,Ev,tol);
0426 pass=cmp(pass,'currents',i,Ei,tol);
0427 pass=cmp(pass,'node#s',nn,Enn);
0428 end
0429 disp('-----------------------------------------');
0430 if pass
0431 disp('overall: PASS');
0432 else
0433 disp('overall: FAIL');
0434 end
0435
0436 function print_netlist(desc,n)
0437 fprintf('NETLIST: %s\n',desc);
0438 for ii =1:length(n)
0439 nn = n{ii}; id = nn{1};
0440 if any(strcmp(id(1),{'G','E'}))
0441 assert(length(nn) == 6,sprintf('bad netlist, row#%d has %d elements',ii,length(nn)));
0442 fprintf(' %-5s (%2d,%2d)<-(%2d,%2d) %0.3f\n',nn{1},nn{2},nn{3},nn{4},nn{5},nn{6});
0443 elseif any(strcmp(id(1),{'F','H'}))
0444 assert(length(nn) == 5,sprintf('bad netlist, row#%d has %d elements',ii,length(nn)));
0445 fprintf(' %-5s (%2d,%2d)<-(%-5s) %0.3f\n',nn{1},nn{2},nn{3},nn{4},nn{5});
0446 else
0447 assert(length(nn) == 4,sprintf('bad netlist, row#%d has %d elements',ii,length(nn)));
0448 fprintf(' %-5s (%2d,%2d) %0.3f\n',nn{1},nn{2},nn{3},nn{4});
0449 end
0450 end
0451
0452 function pass=cmp(pass,str,X,Y,tol)
0453 if nargin < 5
0454 tol = 0;
0455 end
0456 if any(size(X) ~= size(Y))
0457 fprintf('TEST: %-30s fail; size mismatch (%d,%d)!=(%d,%d)\n',str,size(X),size(Y));
0458 pass=0;
0459 return
0460 end
0461 if tol == 0
0462 if any(X ~= Y)
0463 [ X Y ]
0464 fprintf('TEST: %-30s fail (%g)\n',str,abs(max(X(:)-Y(:))));
0465 pass=0;
0466 return;
0467 end
0468 else
0469 err=abs(X-Y);
0470 err(err<tol)=[];
0471 if length(err) > 0
0472 [ X Y ]
0473 fprintf('TEST: %-30s fail (%g, tol=%g)\n',str,norm(err),tol);
0474 pass=0;
0475 return;
0476 end
0477 end
0478 fprintf('TEST: %-30s pass\n',str);