Skip to content

Commit 49213a6

Browse files
toammannthliebig
authored andcommitted
add DjorjevicSarkar octave files
1 parent 3c24814 commit 49213a6

2 files changed

Lines changed: 463 additions & 0 deletions

File tree

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
function [CSX] = AddDjordjevicSarkarMaterial(varargin)
2+
%
3+
% Add a wideband dielectric material to a CSX struct using a multi-term
4+
% Debye fit of the Djordjevic–Sarkar model.
5+
%
6+
% Calculates Debye parameters from a single (eps_r, tanD) measurement via
7+
% 'calcDjordjevicSarkarApprox' and adds the material to the CSX struct.
8+
%
9+
% Input Parameters:
10+
% CSX - CSX struct to which the material will be added
11+
% materialName - String name of the material
12+
%
13+
% Name-Value Parameters (passed to `calcDjordjevicSarkarApprox`):
14+
% 'fMeas' - Measurement frequency [Hz]
15+
% 'epsRMeas' - Relative permittivity ε_r at 'fMeas'
16+
% 'tandMeas' - Loss tangent tan(δ) at 'fMeas'
17+
% 'f2' - Upper corner frequency of the Djordjevic–Sarkar model [Hz]
18+
% 'f1' - Lower corner frequency [Hz] (if `lowFreqEvalType` = 0)
19+
% 'epsRdc' - Permittivity at DC (if `lowFreqEvalType` = 1)
20+
% 'sigmaDC' - Optional DC conductivity [S/m]
21+
% 'nTermsPerDec' - Number of Debye terms per frequency decade
22+
%
23+
% Output:
24+
% CSX - Updated CSX struct including the defined wideband dielectric material
25+
%
26+
% Note:
27+
% - Internally uses 'calcDjordjevicSarkarApprox' to generate model parameters.
28+
% - See 'calcDjordjevicSarkarApprox' for detailed description of the model
29+
% fitting.
30+
%
31+
% Example:
32+
% CSX = AddDjordjevicSarkarMaterial(CSX, 'MyMaterial', ...
33+
% 'fMeas', 1e9, 'epsRMeas', 4.2, 'tandMeas', 0.02, ...
34+
% 'f1', 1e6, 'f2', 200e9);
35+
%
36+
% See also: calcDjordjevicSarkarApprox, AddDebyeMaterial
37+
%
38+
% Version History:
39+
% v1.0 2025-06-30 Tobias Ammann Initial version
40+
41+
p = inputParser();
42+
p.FunctionName = 'AddDjordjevicSarkarMaterial';
43+
44+
p.addRequired('CSX', @isstruct);
45+
p.addRequired('matName', @ischar);
46+
47+
% Required Parameters
48+
% Set as Parameters, checked manually too match openEMS name-value pair style
49+
p.addParameter('fMeas', [], @isPositiveScalar); % Hz
50+
p.addParameter('epsRMeas', [], @isPositiveScalar);
51+
p.addParameter('tandMeas', [], @isNonNegScalar);
52+
p.addParameter('f2', [], @isPositiveScalar); % Upper fit frequency, Hz
53+
54+
% Optional Parameters
55+
p.addParameter('lowFreqEvalType', 0, @isIntegerScalar); % 0 = use f1, 1 = use epsRdc
56+
p.addParameter('f1', nan, @isPositiveScalar); % lowFreqEvalType = 0, Hz
57+
p.addParameter('epsRdc', inf, @isPositiveScalar); % lowFreqEvalType = 1
58+
p.addParameter('sigmaDC', 0, @isNonNegScalar); % Siemens
59+
p.addParameter('nTermsPerDec', 1, @(x) isScalar(x) && x >= 1); % Number of Debye terms per decade
60+
p.addParameter('plotEn', 0, @isIntegerScalar); % Enable/Disable plots of the model
61+
62+
% Parse and manually verify required parameters
63+
p.parse(varargin{:});
64+
65+
requiredParams = {'fMeas', 'epsRMeas', 'tandMeas', 'f2'};
66+
for i = 1:numel(requiredParams)
67+
param = requiredParams{i};
68+
if ismember(param, p.UsingDefaults)
69+
error('%s: Missing required parameter ''%s''.', p.FunctionName, param);
70+
end
71+
end
72+
73+
if ((p.Results.lowFreqEvalType == 0) && ismember('f1', p.UsingDefaults))
74+
error(['%s: For ''lowFreqEvalType=0'' a value for f1 (Djordjevic Sarkar ',...
75+
'low corner frequency)must be specified.'], p.FunctionName);
76+
end
77+
78+
if ((p.Results.lowFreqEvalType == 1) && ismember('epsRdc', p.UsingDefaults))
79+
error(['%s: For ''lowFreqEvalType=1'', a value for epsRdc (value of ',...
80+
'EpsilonR at DC) must be specified.'], p.FunctionName);
81+
end
82+
83+
% Fit the model and receive Debye model parametes for openEMS
84+
paramDebye = CalcDjordjevicSarkarApprox(...
85+
'fMeas', p.Results.fMeas,...
86+
'epsRMeas', p.Results.epsRMeas,...
87+
'tandMeas', p.Results.tandMeas,...
88+
'f1', p.Results.f1,...
89+
'f2', p.Results.f2,...
90+
'lowFreqEvalType', p.Results.lowFreqEvalType,...
91+
'epsRdc', p.Results.epsRdc,...
92+
'sigmaDC', p.Results.sigmaDC,...
93+
'nTermsPerDec', p.Results.nTermsPerDec,...
94+
'plotEn', p.Results.plotEn);
95+
96+
CSX = p.Results.CSX;
97+
matName = p.Results.matName;
98+
99+
CSX = AddDebyeMaterial(CSX, matName);
100+
CSX = SetMaterialProperty(CSX, matName, ...
101+
'Epsilon', paramDebye.epsInf, ... % Epsilon here is acutally EpsilonRinf
102+
'Kappa', paramDebye.sigmaDC);
103+
104+
for i = 1:length(paramDebye.wi)
105+
106+
CSX = SetMaterialProperty(CSX, matName,...
107+
['EpsilonDelta_', int2str(i)], paramDebye.deltaEpsT(i),...
108+
['EpsilonRelaxTime_', int2str(i)], 1/paramDebye.wi(i));
109+
110+
end
111+
end
112+
113+
% Validation functions for input argument checks
114+
function val = isNonNegScalar(x)
115+
val = isnumeric(x) && isscalar(x) && (x >= 0);
116+
end
117+
118+
function val = isPositiveScalar(x)
119+
val = isnumeric(x) && isscalar(x) && (x > 0);
120+
end
121+
122+
function val = isIntegerScalar(x)
123+
val = isnumeric(x) && isscalar(x) && (round(x) == x);
124+
end
125+
126+
function val = isScalar(x)
127+
val = isnumeric(x) && isscalar(x);
128+
end

0 commit comments

Comments
 (0)