File: AddCPWPort.m

package info (click to toggle)
openems 0.0.35+dfsg.1-3
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 6,288 kB
  • sloc: cpp: 40,259; yacc: 580; lex: 350; makefile: 258; sh: 169; ruby: 19
file content (285 lines) | stat: -rw-r--r-- 12,192 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
function [CSX,port] = AddCPWPort( CSX, prio, portnr, materialname, start, stop, gap_width, dir, evec, varargin )
% [CSX,port] = AddCPWPort( CSX, prio, portnr, materialname, start, stop, gap_width, dir, evec, varargin )
%
% CSX:          CSX-object created by InitCSX()
% prio:         priority for excitation and probe boxes
% portnr:       (integer) number of the port
% materialname: property for the CPW (created by AddMetal())
% start:        3D start rowvector for port definition
% stop:         3D end rowvector for port definition
% gap_width:    width of the CPW gap (left and right)
% dir:          direction of wave propagation (choices: 0, 1, 2 or 'x','y','z')
% evec:         excitation vector, which defines the direction of the e-field (must be the same as used in AddExcitation())
%
% variable input:
%  varargin:    optional additional excitations options, see also AddExcitation
% 'ExcitePort'  true/false to make the port an active feeding port (default
%               is false)
% 'FeedShift'   shift to port from start by a given distance in drawing
%               units. Default is 0. Only active if 'ExcitePort' is set!
% 'Feed_R'      Specifiy a lumped port resistance. Default is no lumped
%               port resistance --> port has to end in an ABC.
% 'MeasPlaneShift'  Shift the measurement plane from start t a given distance
%               in drawing units. Default is the middle of start/stop.
% 'PortNamePrefix' a prefix to the port name
%
% Important: The mesh has to be already set and defined by DefineRectGrid!
%
% example:
%   CSX = AddMetal( CSX, 'metal' ); %create a PEC called 'metal'
%   start = [0       -width/2  0];
%   stop  = [length  +width/2  0];
%   [CSX,port] = AddCPWPort( CSX, 0, 1, 'metal', start, stop, gap_width, 'x', ...
%                                   [0 0 -1], 'ExcitePort', true, 'Feed_R', 50 )
% Explanation:
%   - this defines a stripline in x-direction (dir='x')
%     --> the wave travels along the x-direction
%   - with an e-field excitation in -z-direction (evec=[0 0 -1])
%   - the excitation is active and placed at x=start(1) ('ExcitePort', true)
%   - a 50 Ohm lumped port resistance is placed at x=start(1) ('Feed_R', 50)
%   - the width-direction is determined by the cross product of the
%       direction of propagtion (dir='x') and the excitation vector
%       (evec=[0 0 -1]), in this case it is the y-direction
%   - the stripline-metal is created in a xy-plane at a height at z=start(3)
%     --> The upper and lower reference plane (ground) must be defined by
%     the user
%
% Thorsten Liebig <thorsten.liebig@gmx.de> (c) 2014
%
% See also InitCSX DefineRectGrid AddMetal AddMaterial AddExcitation calcPort

%% validate arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%check mesh
if ~isfield(CSX,'RectilinearGrid')
    error 'mesh needs to be defined! Use DefineRectGrid() first!';
end
if (~isfield(CSX.RectilinearGrid,'XLines') || ~isfield(CSX.RectilinearGrid,'YLines') || ~isfield(CSX.RectilinearGrid,'ZLines'))
    error 'mesh needs to be defined! Use DefineRectGrid() first!';
end

% check dir
dir = DirChar2Int(dir);

% check evec
if ~(evec(1) == evec(2) == 0) && ~(evec(1) == evec(3) == 0) && ~(evec(2) == evec(3) == 0) || (sum(evec) == 0)
    error 'evec must have exactly one component ~= 0'
end
evec0 = evec ./ sum(evec); % evec0 is a unit vector

%set defaults
feed_shift = 0;
feed_R = inf; %(default is open, no resitance)
excite = false;
measplanepos = nan;
PortNamePrefix = '';

excite_args = {};

%% read optional arguments %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
for n=1:2:numel(varargin)
    if (strcmp(varargin{n},'FeedShift')==1);
        feed_shift = varargin{n+1};
        if (numel(feed_shift)>1)
            error 'FeedShift must be a scalar value'
        end
    elseif (strcmp(varargin{n},'Feed_R')==1);
        feed_R = varargin{n+1};
        if (numel(feed_shift)>1)
            error 'Feed_R must be a scalar value'
        end
    elseif (strcmp(varargin{n},'MeasPlaneShift')==1);
        measplanepos = varargin{n+1};
        if (numel(feed_shift)>1)
            error 'MeasPlaneShift must be a scalar value'
        end
    elseif (strcmp(varargin{n},'ExcitePort')==1);
        if ischar(varargin{n+1})
            warning('CSXCAD:AddCPWPort','depreceated: a string as excite option is no longer supported and will be removed in the future, please use true or false');
            if ~isempty(excite)
                excite = true;
            else
                excite = false;
            end
        else
            excite = varargin{n+1};
        end
    elseif (strcmpi(varargin{n},'PortNamePrefix'))
        PortNamePrefix = varargin{n+1};
    else
        excite_args{end+1} = varargin{n};
        excite_args{end+1} = varargin{n+1};
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% normalize start and stop
nstart = min( [start;stop] );
nstop  = max( [start;stop] );

% determine index (1, 2 or 3) of propagation (length of CPW)
idx_prop = dir + 1;

% determine index (1, 2 or 3) of width of CPW
dir = [0 0 0];
dir(idx_prop) = 1;
idx_height = abs(cross(dir,evec0)) * [1;2;3];

% determine index (1, 2 or 3) of height
idx_width = abs(evec0) * [1;2;3];


if (start(idx_height)~=stop(idx_height))
    error('openEMS:AddCPWPort','start/stop in height direction must be equal');
end

% direction of propagation
if stop(idx_prop)-start(idx_prop) > 0
    direction = +1;
else
    direction = -1;
end

% create the metal/material for the CPW
SL_start = start;
SL_stop = stop;
CSX = AddBox( CSX, materialname, prio, SL_start, SL_stop );

if isnan(measplanepos)
    measplanepos = (nstart(idx_prop)+nstop(idx_prop))/2;
else
    measplanepos = start(idx_prop)+direction*measplanepos;
end

% calculate position of the voltage probes
mesh{1} = sort(CSX.RectilinearGrid.XLines);
mesh{2} = sort(CSX.RectilinearGrid.YLines);
mesh{3} = sort(CSX.RectilinearGrid.ZLines);
meshlines = interp1( mesh{idx_prop}, 1:numel(mesh{idx_prop}), measplanepos, 'nearest' );
meshlines = mesh{idx_prop}(meshlines-1:meshlines+1); % get three lines (approx. at center)
if direction == -1
    meshlines = fliplr(meshlines);
end
SL_w2 = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), (nstart(idx_width)+nstop(idx_width))/2, 'nearest' );
SL_w2 = mesh{idx_width}(SL_w2); % get e-line at center of CPW (SL_width/2)
v1_start(idx_prop)   = meshlines(1);
v1_start(idx_width)  = (nstart(idx_width)+nstop(idx_width))/2;
v1_start(idx_height) = start(idx_height);
v1_stop  = v1_start;
v2_start = v1_start;
v2_stop  = v1_stop;
v2_start(idx_prop)   = meshlines(2);
v2_stop(idx_prop)    = meshlines(2);
v3_start = v2_start;
v3_stop  = v2_stop;
v3_start(idx_prop)   = meshlines(3);
v3_stop(idx_prop)    = meshlines(3);

width_add_start = [0 0 0];
width_add_stop  = [0 0 0];
width_add_start(idx_width) = (nstop(idx_width)-nstart(idx_width))/2;
width_add_stop(idx_width)  = (nstop(idx_width)-nstart(idx_width))/2+gap_width;

weight = 0.5;
% create the voltage-probes
port.U_filename{1,1} = [PortNamePrefix 'port_ut' num2str(portnr) 'A1'];
CSX = AddProbe( CSX, port.U_filename{1,1}, 0, 'weight', -1*weight );
CSX = AddBox( CSX, port.U_filename{1,1}, prio, v1_start-width_add_start, v1_stop-width_add_stop);

port.U_filename{1,2} = [PortNamePrefix 'port_ut' num2str(portnr) 'A2'];
CSX = AddProbe( CSX, port.U_filename{1,2}, 0, 'weight', weight );
CSX = AddBox( CSX, port.U_filename{1,2}, prio, v1_start+width_add_start, v1_stop+width_add_stop);


port.U_filename{2,1} = [PortNamePrefix 'port_ut' num2str(portnr) 'B1'];
CSX = AddProbe( CSX, port.U_filename{2,1}, 0, 'weight', -1*weight );
CSX = AddBox( CSX, port.U_filename{2,1}, prio, v2_start-width_add_start, v2_stop-width_add_stop );

port.U_filename{2,2} = [PortNamePrefix 'port_ut' num2str(portnr) 'B2'];
CSX = AddProbe( CSX, port.U_filename{2,2}, 0, 'weight', weight );
CSX = AddBox( CSX, port.U_filename{2,2}, prio, v2_start+width_add_start, v2_stop+width_add_stop );


port.U_filename{3,1} = [PortNamePrefix 'port_ut' num2str(portnr) 'C1'];
CSX = AddProbe( CSX, port.U_filename{3,1}, 0, 'weight', -1*weight );
CSX = AddBox( CSX, port.U_filename{3,1}, prio, v3_start-width_add_start, v3_stop-width_add_stop );

port.U_filename{3,2} = [PortNamePrefix 'port_ut' num2str(portnr) 'C2'];
CSX = AddProbe( CSX, port.U_filename{3,2}, 0, 'weight', weight );
CSX = AddBox( CSX, port.U_filename{3,2}, prio, v3_start+width_add_start, v3_stop+width_add_stop );

% calculate position of the current probes
idx = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), nstart(idx_width), 'nearest' );
i1_start(idx_width)  = mesh{idx_width}(idx) - diff(mesh{idx_width}(idx-1:idx))/2;
idx = interp1( mesh{idx_height}, 1:numel(mesh{idx_height}), start(idx_height), 'nearest' );
i1_start(idx_height) = mesh{idx_height}(idx-1) - diff(mesh{idx_height}(idx-2:idx-1))/2;
i1_stop(idx_height)  = mesh{idx_height}(idx+1) + diff(mesh{idx_height}(idx+1:idx+2))/2;
i1_start(idx_prop)   = sum(meshlines(1:2))/2;
i1_stop(idx_prop)    = i1_start(idx_prop);
idx = interp1( mesh{idx_width}, 1:numel(mesh{idx_width}), nstop(idx_width), 'nearest' );
i1_stop(idx_width)   = mesh{idx_width}(idx) + diff(mesh{idx_width}(idx:idx+1))/2;
i2_start = i1_start;
i2_stop  = i1_stop;
i2_start(idx_prop)   = sum(meshlines(2:3))/2;
i2_stop(idx_prop)    = i2_start(idx_prop);

% create the curr-probes
weight = direction;
port.I_filename{1} = [PortNamePrefix 'port_it' num2str(portnr) 'A'];
CSX = AddProbe( CSX, port.I_filename{1}, 1, 'weight', weight );
CSX = AddBox( CSX, port.I_filename{1}, prio, i1_start, i1_stop );
port.I_filename{2} = [PortNamePrefix 'port_it' num2str(portnr) 'B'];
CSX = AddProbe( CSX, port.I_filename{2}, 1,'weight', weight );
CSX = AddBox( CSX, port.I_filename{2}, prio, i2_start, i2_stop );

% create port structure
port.LengthScale = 1;
if ((CSX.ATTRIBUTE.CoordSystem==1) && (idx_prop==2))
    port.LengthScale = SL_stop(idx_height);
end
port.nr = portnr;
port.type = 'CPW';
port.drawingunit = CSX.RectilinearGrid.ATTRIBUTE.DeltaUnit;
port.v_delta = diff(meshlines)*port.LengthScale;
port.i_delta = diff( meshlines(1:end-1) + diff(meshlines)/2 )*port.LengthScale;
port.direction = direction;
port.excite = 0;
port.measplanepos = abs(v2_start(idx_prop) - start(idx_prop))*port.LengthScale;
% port

% create excitation (if enabled) and port resistance
meshline = interp1( mesh{idx_prop}, 1:numel(mesh{idx_prop}), start(idx_prop) + feed_shift*direction, 'nearest' );
ex_start(idx_prop)   = mesh{idx_prop}(meshline) ;
ex_start(idx_width)  = (nstart(idx_width)+nstop(idx_width))/2;
ex_start(idx_height) = nstart(idx_height);
ex_stop(idx_prop)    = ex_start(idx_prop);
ex_stop(idx_width)   = (nstart(idx_width)+nstop(idx_width))/2;
ex_stop(idx_height)  = nstop(idx_height);

port.excite = 0;
if excite
    port.excite = 1;
    CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_1_' num2str(portnr)], 0, evec, excite_args{:} );
    CSX = AddBox( CSX, [PortNamePrefix 'port_excite_1_' num2str(portnr)], prio, ex_start-width_add_start, ex_stop-width_add_stop );
    CSX = AddExcitation( CSX, [PortNamePrefix 'port_excite_2_' num2str(portnr)], 0, -evec, excite_args{:} );
    CSX = AddBox( CSX, [PortNamePrefix 'port_excite_2_' num2str(portnr)], prio, ex_start+width_add_start, ex_stop+width_add_stop );
end

%% CPW resitance at start of CPW line
ex_start(idx_prop) = start(idx_prop);
ex_stop(idx_prop) = ex_start(idx_prop);

if (feed_R > 0) && ~isinf(feed_R)
    CSX = AddLumpedElement( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], idx_width-1, 'R', 2*feed_R );
    CSX = AddBox( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], prio, ex_start-width_add_start, ex_stop-width_add_stop );
    CSX = AddBox( CSX, [PortNamePrefix 'port_resist_' int2str(portnr)], prio, ex_start+width_add_start, ex_stop+width_add_stop );
elseif isinf(feed_R)
    % do nothing --> open port
elseif feed_R == 0
    %port "resistance" as metal
    CSX = AddBox( CSX, materialname, prio, ex_start-width_add_start, ex_stop-width_add_stop );
    CSX = AddBox( CSX, materialname, prio, ex_start+width_add_start, ex_stop+width_add_stop );
else
    error('openEMS:AddCPWPort','CPW port with resitance <= 0 it not possible');
end
end