KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dielectric_djordjevic_sarkar.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <stdexcept>
23
24
25void DIELECTRIC_DJORDJEVIC_SARKAR::Fit( double aEpsRSpec, double aTanDSpec, double aFSpec,
26 double aF1, double aF2 )
27{
28 if( aF1 <= 0.0 )
29 throw std::invalid_argument( "DIELECTRIC_DJORDJEVIC_SARKAR: f1 must be positive" );
30
31 if( aF2 <= aF1 )
32 throw std::invalid_argument( "DIELECTRIC_DJORDJEVIC_SARKAR: f2 must exceed f1" );
33
34 if( aFSpec < aF1 || aFSpec > aF2 )
35 throw std::invalid_argument( "DIELECTRIC_DJORDJEVIC_SARKAR: f_spec outside [f1, f2]" );
36
37 m_f1 = aF1;
38 m_f2 = aF2;
39
40 // Short-circuit makes TanDeltaAt return an exact 0.0 and skips the complex-log below.
41 if( aTanDSpec == 0.0 )
42 {
43 m_lossless = true;
44 m_epsInf = aEpsRSpec;
45 m_m = 0.0;
46 return;
47 }
48
49 // Djordjevic et al., IEEE Trans. EMC 43(4):662-667, Nov. 2001, eqs. (9)-(11).
50 // Equivalent form in Svensson and Dermer, IEEE Trans. Adv. Packag. 24(2):191-196, May 2001.
51 // Mirrored by scikit-rf skrf/media/definedAEpTandZ0.py (djordjevicsvensson).
52 const std::complex<double> j{ 0.0, 1.0 };
53 const std::complex<double> k = std::log( ( aF2 + j * aFSpec ) / ( aF1 + j * aFSpec ) );
54
55 m_m = -aTanDSpec * aEpsRSpec / k.imag();
56 m_epsInf = aEpsRSpec * ( 1.0 + aTanDSpec * k.real() / k.imag() );
57 m_lossless = false;
58}
59
60
61std::complex<double> DIELECTRIC_DJORDJEVIC_SARKAR::ComplexEpsilonAt( double aF ) const
62{
63 if( m_lossless )
64 return { m_epsInf, 0.0 };
65
66 // Djordjevic et al. 2001, eq. (8). Kramers-Kronig consistent by construction.
67 const std::complex<double> j{ 0.0, 1.0 };
68
69 return m_epsInf + m_m * std::log( ( m_f2 + j * aF ) / ( m_f1 + j * aF ) );
70}
71
72
74{
75 return ComplexEpsilonAt( aF ).real();
76}
77
78
80{
81 if( m_lossless )
82 return 0.0;
83
84 const std::complex<double> eps = ComplexEpsilonAt( aF );
85
86 return -eps.imag() / eps.real();
87}
std::complex< double > ComplexEpsilonAt(double aF) const
Complex relative permittivity at aF. Imag part is non-positive (loss).
double TanDeltaAt(double aF) const
Loss tangent tan delta = -Im(eps) / Re(eps) at aF.
double EpsilonRealAt(double aF) const
Real part of relative permittivity at aF.
void Fit(double aEpsRSpec, double aTanDSpec, double aFSpec, double aF1=1.0e3, double aF2=1.0e12)
Fit the model from a single (epsR, tan delta) datapoint at f_spec.