KiCad PCB EDA Suite
Loading...
Searching...
No Matches
common/transline_calculations/twistedpair.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2011 Michael Margraf <[email protected]>
3 * Modifications 2011 for Kicad: Jean-Pierre Charras
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or (at
9 * your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this package. If not, see <https://www.gnu.org/licenses/>.
18 */
19
22
23#include <algorithm>
24
25
26namespace TC = TRANSLINE_CALCULATIONS;
28
29
60{
62
63 const double twist = GetParameter( TCP::TWISTEDPAIR_TWIST );
64 const double epsrEnv = GetParameter( TCP::TWISTEDPAIR_EPSILONR_ENV );
65 const double Din = GetParameter( TCP::PHYS_DIAM_IN );
66 const double Dout = GetParameter( TCP::PHYS_DIAM_OUT );
67 const double freq = GetParameter( TCP::FREQUENCY );
68 const double len = GetParameter( TCP::PHYS_LEN );
69 const double epsr = GetDispersedEpsilonR( freq );
70 const double tand = GetDispersedTanDelta( freq );
71
73
74 // Lefferson defines theta in degrees for the 0.0007 * theta^2 term. The KiCad
75 // legacy implementation used radians, which made the twist contribution about
76 // 3300x too small. Convert to degrees before squaring.
77 const double theta_rad = std::atan( twist * M_PI * Dout );
78 const double theta_deg = theta_rad * ( 180.0 / M_PI );
79
80 const double beta = 0.25 + 0.0007 * theta_deg * theta_deg;
81 const double epsEff = epsrEnv + beta * ( epsr - epsrEnv );
83
84 const double z0 = ( TC::ZF0 / M_PI / std::sqrt( epsEff ) ) * std::acosh( Dout / Din );
85 SetParameter( TCP::Z0, z0 );
86
87 const double skinDepth = GetParameter( TCP::SKIN_DEPTH );
88 const double sigma = GetParameter( TCP::SIGMA );
89
90 // Capping the depth at the wire radius makes the annulus the full cross-section at DC
91 const double currentDepth = std::min( skinDepth, Din / 2.0 );
92
93 // Proximity factor for parallel wires (Wadell, "Transmission Line Design Handbook",
94 // section 3.3.1, eq. 3.3.1.4). It is a skin-effect result, so fade it out towards DC
95 const double spacing = Dout / Din;
96 const double proximity = spacing / std::sqrt( spacing * spacing - 1.0 );
97 const double crowding = 1.0 + ( proximity - 1.0 ) * ( 1.0 - 2.0 * currentDepth / Din );
98
99 // Lefferson 1971 does not cover loss. Conductor loss is R/(2*Z0) with R the skin
100 // resistance of both wires (Pozar, "Microwave Engineering" 4th ed., Table 2.1)
101 SetParameter( TCP::LOSS_CONDUCTOR, TC::LOG2DB * len * crowding / currentDepth / sigma / M_PI / z0
102 / ( Din - currentDepth ) );
103
104 // Only the insulation is lossy, so tan delta carries its filling factor (Garg and Bahl,
105 // "Microstrip Lines and Slotlines" eq. 2.80). The fit can exceed 1 at tight twist
106 const double lossFraction = std::min( 1.0, beta * epsr / epsEff );
107
109 TC::LOG2DB * len * M_PI / TC::C0 * freq * std::sqrt( epsEff ) * tand * lossFraction );
110
111 SetParameter( TCP::ANG_L, 2.0 * M_PI * len * std::sqrt( epsEff ) * freq / TC::C0 );
112
114}
115
116
118{
119 // 1-D Newton on whichever diameter the UI flagged as the unknown. MinimiseZ0Error1D
120 // runs Analyse repeatedly until |Z0 - Z0_target| is below the base-class tolerance or
121 // the iteration cap is reached, then recomputes PHYS_LEN from ANG_L to keep the
122 // UI round-trip consistent with the legacy TRANSLINE::minimizeZ0Error1D contract.
123 const TCP target =
125
126 return MinimiseZ0Error1D( target, TCP::Z0, true );
127}
128
129
131{
136
137 const double Z0 = GetParameter( TCP::Z0 );
138 const double angL = GetParameter( TCP::ANG_L );
139 const double len = GetParameter( TCP::PHYS_LEN );
140 const double Din = GetParameter( TCP::PHYS_DIAM_IN );
141 const double Dout = GetParameter( TCP::PHYS_DIAM_OUT );
142
143 const bool Z0_invalid = !std::isfinite( Z0 ) || Z0 <= 0;
144 const bool angL_invalid = !std::isfinite( angL ) || angL < 0;
145 const bool len_invalid = !std::isfinite( len ) || len < 0;
146 const bool Din_invalid = !std::isfinite( Din ) || Din <= 0.0;
147 const bool Dout_invalid = !std::isfinite( Dout ) || Dout <= 0.0;
148 const bool geometry_invalid = Din >= Dout;
149
154 ( Din_invalid || geometry_invalid ) ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
156 ( Dout_invalid || geometry_invalid ) ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
157}
158
159
161{
166
167 const double Z0 = GetParameter( TCP::Z0 );
168 const double angL = GetParameter( TCP::ANG_L );
169 const double len = GetParameter( TCP::PHYS_LEN );
170 const double Din = GetParameter( TCP::PHYS_DIAM_IN );
171 const double Dout = GetParameter( TCP::PHYS_DIAM_OUT );
172
173 const bool Z0_invalid = !std::isfinite( Z0 ) || Z0 <= 0;
174 const bool angL_invalid = !std::isfinite( angL ) || angL < 0;
175 const bool len_invalid = !std::isfinite( len ) || len < 0;
176 const bool Din_invalid = !std::isfinite( Din ) || Din <= 0.0;
177 const bool Dout_invalid = !std::isfinite( Dout ) || Dout <= 0.0;
178 const bool geometry_invalid = Din >= Dout;
179
185 : ( Dout_invalid ? TRANSLINE_STATUS::WARNING : TRANSLINE_STATUS::OK );
186
193 : Din_status );
197 : Dout_status );
198}
double GetDispersedEpsilonR(double aF) const
Dispersed permittivity at aF. Returns raw EPSILONR when the model is inactive.
TRANSLINE_PARAMETERS m_synthesizeTarget
Which geometry parameter is the unknown during synthesis (set by the UI)
double GetDispersedTanDelta(double aF) const
Dispersed loss tangent at aF. Returns raw TAND when the model is inactive.
double GetParameter(const TRANSLINE_PARAMETERS aParam) const
Gets the given calculation property.
void SetParameter(const TRANSLINE_PARAMETERS aParam, const double aValue)
Sets the given calculation property.
void SetSynthesisResult(TRANSLINE_PARAMETERS aParam, const double aValue, const TRANSLINE_STATUS aStatus=TRANSLINE_STATUS::OK)
Sets a synthesis result.
void UpdateDielectricModel()
Refit the Djordjevic-Sarkar model from the current parameter map.
double SkinDepth() const
Calculate skin depth.
bool MinimiseZ0Error1D(TRANSLINE_PARAMETERS aOptimise, TRANSLINE_PARAMETERS aMeasure, bool aRecalculateLength=false)
minimizeZ0Error1D
void SetAnalysisResult(TRANSLINE_PARAMETERS aParam, const double aValue, const TRANSLINE_STATUS aStatus=TRANSLINE_STATUS::OK)
Sets an analysis result.
static double UnitPropagationDelay(double aEpsilonEff)
Calculates the unit propagation delay (ps/cm) for the given effective permittivity.
bool Synthesize(SYNTHESIZE_OPTS aOpts) override
Synthesize Din or Dout to hit the target Z0. Length is recomputed from ANG_L.
void Analyse() override
Analyse pair geometry to output Z0, electrical length, losses, skin depth, εeff.
void SetSynthesisResults() override
Sets the output values and status following synthesis.
void SetAnalysisResults() override
Sets the output values and status following analysis.
TRANSLINE_PARAMETERS TCP
#define M_PI
SYNTHESIZE_OPTS
Options for specifying synthesis inputs, targets, or strategies.
TRANSLINE_STATUS
Parameter status values.
TRANSLINE_PARAMETERS
All possible parameters used (as inputs or outputs) by the transmission line calculations.