KiCad PCB EDA Suite
panel_track_width.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 (C) 2011 jean-pierre.charras
5 * Copyright (C) 1992-2015 Kicad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 3
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21/* see
22 * http://www.desmith.net/NMdS/Electronics/TraceWidth.html
23 * http://www.ultracad.com/articles/pcbtemp.pdf
24 * for more info
25 */
26
27#include <cassert>
28#include <cmath>
29#include <kiface_base.h>
30
33#include <string_utils.h>
34#include <units_scales.h>
35
37
38#include <i18n_utility.h> // For _HKI definition
41
42extern double DoubleFromString( const wxString& TextValue );
43
44// The IPC2221 formula used to calculate track width is valid only for copper material
45const double copper_resistivity = 1.72e-8;
46
47
48PANEL_TRACK_WIDTH::PANEL_TRACK_WIDTH( wxWindow* parent, wxWindowID id,
49 const wxPoint& pos, const wxSize& size,
50 long style, const wxString& name ) :
51 PANEL_TRACK_WIDTH_BASE( parent, id, pos, size, style, name ),
52 m_TWMode( TW_MASTER_CURRENT ),
53 m_TWNested( false )
54{
55 m_trackTempUnits->SetLabel( wxT( "°C" ) );
56 m_resistivityUnits->SetLabel( wxT( "Ω⋅m" ) );
57
58 m_extTrackResUnits->SetLabel( wxT( "Ω" ) );
59 m_intTrackResUnits->SetLabel( wxT( "Ω" ) );
60
61 m_staticText63->SetLabel( _( "Temperature rise" ) + wxT( " (ΔT):" ) );
62
63 // Needed on wxWidgets 3.0 to ensure sizers are correctly set
64 GetSizer()->SetSizeHints( this );
65}
66
67
69{
70}
71
72
74{
76}
77
78
80{
81 aCfg->m_TrackWidth.current = m_TrackCurrentValue->GetValue();
82 aCfg->m_TrackWidth.delta_tc = m_TrackDeltaTValue->GetValue();
83 aCfg->m_TrackWidth.track_len = m_TrackLengthValue->GetValue();
85 aCfg->m_TrackWidth.resistivity = m_TWResistivity->GetValue();
94}
95
96
97void PANEL_TRACK_WIDTH::OnTWParametersChanged( wxCommandEvent& event )
98{
99 switch(m_TWMode)
100 {
101 case TW_MASTER_CURRENT: OnTWCalculateFromCurrent( event ); break;
104 }
105}
106
107
109{
110 // Setting the calculated values generates further events. Stop them.
111 if( m_TWNested )
112 {
113 event.StopPropagation();
114 return;
115 }
116
117 m_TWNested = true;
118
119 // Update state.
121 {
124 }
125
126 // Prepare parameters:
127 double current = std::abs( DoubleFromString( m_TrackCurrentValue->GetValue() ) );
128 double extThickness = std::abs( DoubleFromString( m_ExtTrackThicknessValue->GetValue() ) );
129 double intThickness = std::abs( DoubleFromString( m_IntTrackThicknessValue->GetValue() ) );
130 double deltaT_C = std::abs( DoubleFromString( m_TrackDeltaTValue->GetValue() ) );
131
132 // Normalize by units.
133 extThickness *= m_ExtTrackThicknessUnit->GetUnitScale();
134 intThickness *= m_IntTrackThicknessUnit->GetUnitScale();
135
136 // Calculate the widths.
137 double extTrackWidth = TWCalculateWidth( current, extThickness, deltaT_C, false );
138 double intTrackWidth = TWCalculateWidth( current, intThickness, deltaT_C, true );
139
140 // Update the display.
141 TWDisplayValues( current, extTrackWidth, intTrackWidth, extThickness, intThickness );
142
143 // Re-enable the events.
144 m_TWNested = false;
145}
146
147
149{
150 // Setting the calculated values generates further events. Stop them.
151 if( m_TWNested )
152 {
153 event.StopPropagation();
154 return;
155 }
156 m_TWNested = true;
157
158 // Update state.
160 {
163 }
164
165 // Load parameters.
166 double current;
167 double extThickness = std::abs( DoubleFromString( m_ExtTrackThicknessValue->GetValue() ) );
168 double intThickness = std::abs( DoubleFromString( m_IntTrackThicknessValue->GetValue() ) );
169 double deltaT_C = std::abs( DoubleFromString( m_TrackDeltaTValue->GetValue() ) );
170 double extTrackWidth = std::abs( DoubleFromString( m_ExtTrackWidthValue->GetValue() ) );
171 double intTrackWidth;
172
173 // Normalize units.
174 extThickness *= m_ExtTrackThicknessUnit->GetUnitScale();
175 intThickness *= m_IntTrackThicknessUnit->GetUnitScale();
177
178 // Calculate the maximum current.
179 current = TWCalculateCurrent( extTrackWidth, extThickness, deltaT_C, false );
180
181 // And now calculate the corresponding internal width.
182 intTrackWidth = TWCalculateWidth( current, intThickness, deltaT_C, true );
183
184 // Update the display.
185 TWDisplayValues( current, extTrackWidth, intTrackWidth, extThickness, intThickness );
186
187 // Re-enable the events.
188 m_TWNested = false;
189}
190
191
193{
194 // Setting the calculated values generates further events. Stop them.
195 if( m_TWNested )
196 {
197 event.StopPropagation();
198 return;
199 }
200
201 m_TWNested = true;
202
203 // Update state.
205 {
208 }
209
210 // Load parameters.
211 double current;
212 double extThickness = std::abs( DoubleFromString( m_ExtTrackThicknessValue->GetValue() ) );
213 double intThickness = std::abs( DoubleFromString( m_IntTrackThicknessValue->GetValue() ) );
214 double deltaT_C = std::abs( DoubleFromString( m_TrackDeltaTValue->GetValue() ) );
215 double extTrackWidth;
216 double intTrackWidth = std::abs( DoubleFromString( m_IntTrackWidthValue->GetValue() ) );
217
218 // Normalize units.
219 extThickness *= m_ExtTrackThicknessUnit->GetUnitScale();
220 intThickness *= m_IntTrackThicknessUnit->GetUnitScale();
222
223 // Calculate the maximum current.
224 current = TWCalculateCurrent( intTrackWidth, intThickness, deltaT_C, true );
225
226 // And now calculate the corresponding external width.
227 extTrackWidth = TWCalculateWidth( current, extThickness, deltaT_C, false );
228
229 // Update the display.
230 TWDisplayValues( current, extTrackWidth, intTrackWidth, extThickness, intThickness );
231
232 // Re-enable the events.
233 m_TWNested = false;
234}
235
236
237void PANEL_TRACK_WIDTH::OnTWResetButtonClick( wxCommandEvent& event )
238{
239 // Note: a wxString:Format( "%g", xx) is used to use local separator in floats
240
241 // Init main parameters:
242 m_TrackCurrentValue->SetValue( wxString::Format( "%g", 1.0 ) );
243 m_TrackDeltaTValue->SetValue( wxString::Format( "%g", 10.0 ) );
244 m_TrackLengthValue->SetValue( wxString::Format( "%g", 20.0 ) );
245 m_TW_CuLength_choiceUnit->SetSelection( 0 );
247
248 // m_ExtTrackWidthValue is not reinitialized: it will be calculated from previous parameters
249 m_TW_ExtTrackWidth_choiceUnit->SetSelection( 0 );
250 m_ExtTrackThicknessValue->SetValue( wxString::Format( "%g", 0.035 ) );
251 m_ExtTrackThicknessUnit->SetSelection( 0 );
252
253 // m_IntTrackWidthValue is not reinitialized: it will be calculated from previous parameters
254 m_TW_IntTrackWidth_choiceUnit->SetSelection( 0 );
255 m_IntTrackThicknessValue->SetValue( wxString::Format( "%g", 0.035 ) );
256 m_IntTrackThicknessUnit->SetSelection( 0 );
257}
258
259
260void PANEL_TRACK_WIDTH::TWDisplayValues( double aCurrent, double aExtWidth, double aIntWidth,
261 double aExtThickness, double aIntThickness )
262{
263 wxString msg;
264
265 // Show the current.
267 {
268 msg.Printf( wxT( "%g" ), aCurrent );
269 m_TrackCurrentValue->SetValue( msg );
270 }
271
272 // Load scale factors to convert into output units.
273 double extScale = m_TW_ExtTrackWidth_choiceUnit->GetUnitScale();
274 double intScale = m_TW_IntTrackWidth_choiceUnit->GetUnitScale();
275
276 // Display the widths.
278 {
279 msg.Printf( wxT( "%g" ), aExtWidth / extScale );
280 m_ExtTrackWidthValue->SetValue( msg );
281 }
282
284 {
285 msg.Printf( wxT( "%g" ), aIntWidth / intScale );
286 m_IntTrackWidthValue->SetValue( msg );
287 }
288
289 // Display cross-sectional areas.
290 msg.Printf( wxT( "%g" ), (aExtWidth * aExtThickness) / (extScale * extScale) );
291 m_ExtTrackAreaValue->SetLabel( msg );
292 msg.Printf( wxT( "%g" ), (aIntWidth * aIntThickness) / (intScale * intScale) );
293 m_IntTrackAreaValue->SetLabel( msg );
294
295 // Show area units.
296 wxString strunit = m_TW_ExtTrackWidth_choiceUnit->GetUnitName();
297 msg = strunit + wxT( "²" );
298 m_extTrackAreaUnitLabel->SetLabel( msg );
300 msg = strunit + wxT( "²" );
301 m_intTrackAreaUnitLabel->SetLabel( msg );
302
303 // Load resistivity and length of traces.
304 double rho = std::abs( DoubleFromString( m_TWResistivity->GetValue() ) );
305 double trackLen = std::abs( DoubleFromString( m_TrackLengthValue->GetValue() ) );
307
308 // Calculate resistance.
309 double extResistance = ( rho * trackLen ) / ( aExtWidth * aExtThickness );
310 double intResistance = ( rho * trackLen ) / ( aIntWidth * aIntThickness );
311
312 // Display resistance.
313 msg.Printf( wxT( "%g" ), extResistance );
314 m_ExtTrackResistValue->SetLabel( msg );
315 msg.Printf( wxT( "%g" ), intResistance );
316 m_IntTrackResistValue->SetLabel( msg );
317
318 // Display voltage drop along trace.
319 double extV = extResistance * aCurrent;
320 msg.Printf( wxT( "%g" ), extV );
321 m_ExtTrackVDropValue->SetLabel( msg );
322 double intV = intResistance * aCurrent;
323 msg.Printf( wxT( "%g" ), intV );
324 m_IntTrackVDropValue->SetLabel( msg );
325
326 // And power loss.
327 msg.Printf( wxT( "%g" ), extV * aCurrent );
328 m_ExtTrackLossValue->SetLabel( msg );
329 msg.Printf( wxT( "%g" ), intV * aCurrent );
330 m_IntTrackLossValue->SetLabel( msg );
331}
332
333
335{
336 wxFont labelfont;
337 wxFont controlfont;
338
339 // Set the font weight of the current.
340 labelfont = m_staticTextCurrent->GetFont();
341 controlfont = m_TrackCurrentValue->GetFont();
342
344 {
345 labelfont.SetWeight( wxFONTWEIGHT_BOLD );
346 controlfont.SetWeight( wxFONTWEIGHT_BOLD );
347 }
348 else
349 {
350 labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
351 controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
352 }
353
354 m_staticTextCurrent->SetFont( labelfont );
355 m_TrackCurrentValue->SetFont( controlfont );
356
357 // Set the font weight of the external track width.
358 labelfont = m_staticTextExtWidth->GetFont();
359 controlfont = m_ExtTrackWidthValue->GetFont();
360
362 {
363 labelfont.SetWeight( wxFONTWEIGHT_BOLD );
364 controlfont.SetWeight( wxFONTWEIGHT_BOLD );
365 }
366 else
367 {
368 labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
369 controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
370 }
371
372 m_staticTextExtWidth->SetFont( labelfont );
373 m_ExtTrackWidthValue->SetFont( controlfont );
374
375 // Set the font weight of the internal track width.
376 labelfont = m_staticTextIntWidth->GetFont();
377 controlfont = m_IntTrackWidthValue->GetFont();
378
380 {
381 labelfont.SetWeight( wxFONTWEIGHT_BOLD );
382 controlfont.SetWeight( wxFONTWEIGHT_BOLD );
383 }
384 else
385 {
386 labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
387 controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
388 }
389
390 m_staticTextIntWidth->SetFont( labelfont );
391 m_IntTrackWidthValue->SetFont( controlfont );
392
393 // Text sizes have changed when the font weight was changes
394 // So, run the page layout to reflect the changes
395 GetSizer()->Layout();
396}
397
398/* calculate track width for external or internal layers
399 *
400 * Imax = 0.048 * dT^0.44 * A^0.725 for external layer
401 * Imax = 0.024 * dT^0.44 * A^0.725 for internal layer
402 * with A = area = aThickness * trackWidth ( in mils )
403 * and dT = temperature rise in degree C
404 * Of course we want to know trackWidth
405 */
406double PANEL_TRACK_WIDTH::TWCalculateWidth( double aCurrent, double aThickness, double aDeltaT_C,
407 bool aUseInternalLayer )
408{
409 // Appropriate scale for requested layer.
410 double scale = aUseInternalLayer ? 0.024 : 0.048;
411
412 // aThickness is given in normalize units (in meters) and we need mil
413 aThickness /= UNIT_MIL;
414
415 /* formula is Imax = scale * dT^0.44 * A^0.725
416 * or
417 * log(Imax) = log(scale) + 0.44*log(dT) +(0.725*(log(aThickness) + log(trackWidth))
418 * log(trackWidth) * 0.725 = log(Imax) - log(scale) - 0.44*log(dT) - 0.725*log(aThickness)
419 */
420 double dtmp = log( aCurrent ) - log( scale ) - 0.44 * log( aDeltaT_C ) - 0.725 * log( aThickness );
421 dtmp /= 0.725;
422 double trackWidth = exp( dtmp );
423
424 trackWidth *= UNIT_MIL; // We are using normalize units (sizes in meters) and we have mil
425 return trackWidth; // in meters
426}
427
428
429double PANEL_TRACK_WIDTH::TWCalculateCurrent( double aWidth, double aThickness, double aDeltaT_C,
430 bool aUseInternalLayer )
431{
432 // Appropriate scale for requested layer.
433 double scale = aUseInternalLayer ? 0.024 : 0.048;
434
435 // Convert thickness and width to mils.
436 aThickness /= UNIT_MIL;
437 aWidth /= UNIT_MIL;
438
439 double area = aThickness * aWidth;
440 double current = scale * pow( aDeltaT_C, 0.44 ) * pow( area, 0.725 );
441
442 return current;
443}
444
445
447{
448 // Disable calculations while we initialise.
449 m_TWNested = true;
450
451 // Read parameter values.
452 m_TrackCurrentValue->SetValue( aCfg->m_TrackWidth.current );
453 m_TrackDeltaTValue->SetValue( aCfg->m_TrackWidth.delta_tc );
454 m_TrackLengthValue->SetValue( aCfg->m_TrackWidth.track_len );
456#if 0 // the IPC formula is valid for copper traces, so we do not currently adjust the resistivity
457 m_TWResistivity->SetValue( aCfg->m_TrackWidth.resistivity );
458#else
460#endif
469
470 if( tracks_width_versus_current_formula.StartsWith( "<!" ) )
472 else
473 {
474 wxString html_txt;
475 ConvertMarkdown2Html( wxGetTranslation( tracks_width_versus_current_formula ), html_txt );
476 m_htmlWinFormulas->SetPage( html_txt );
477 }
478
479 // Make sure the correct master mode is displayed.
481
482 // Enable calculations and perform the initial one.
483 m_TWNested = false;
484
485 wxCommandEvent dummy;
487}
const char * name
Definition: DXF_plotter.cpp:56
bool SetPage(const wxString &aSource) override
Definition: html_window.cpp:38
void ThemeChanged()
Definition: html_window.cpp:63
Class PANEL_TRACK_WIDTH_BASE.
wxStaticText * m_IntTrackResistValue
UNIT_SELECTOR_THICKNESS * m_IntTrackThicknessUnit
UNIT_SELECTOR_LEN * m_TW_IntTrackWidth_choiceUnit
UNIT_SELECTOR_THICKNESS * m_ExtTrackThicknessUnit
UNIT_SELECTOR_LEN * m_TW_ExtTrackWidth_choiceUnit
UNIT_SELECTOR_LEN * m_TW_CuLength_choiceUnit
wxStaticText * m_ExtTrackResistValue
wxStaticText * m_intTrackAreaUnitLabel
wxStaticText * m_extTrackAreaUnitLabel
PANEL_TRACK_WIDTH(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
double TWCalculateCurrent(double aWidth, double aThickness, double aDeltaT_C, bool aUseInternalLayer)
Calculate maximum current based on given width and temperature rise.
void SaveSettings(PCB_CALCULATOR_SETTINGS *aCfg) override
Save the settings from the panel.
double TWCalculateWidth(double aCurrent, double aThickness, double aDeltaT_C, bool aUseInternalLayer)
Calculate track width required based on given current and temperature rise.
void OnTWCalculateFromIntWidth(wxCommandEvent &event) override
Update the calculations when the user changes the desired internal trace width.
void TWUpdateModeDisplay()
Update the fields to show whether the maximum current, external trace width, or internal trace width ...
enum PANEL_TRACK_WIDTH::@38 m_TWMode
void ThemeChanged() override
Update UI elements of the panel when the theme changes to ensure the images and fonts/colors are appr...
void OnTWResetButtonClick(wxCommandEvent &event) override
Update the calculations when the user clicks the reset button.
void OnTWParametersChanged(wxCommandEvent &event) override
Update the calculations the user changes the general parameters.
void OnTWCalculateFromCurrent(wxCommandEvent &event) override
Update the calculations when the user changes the desired maximum current.
void OnTWCalculateFromExtWidth(wxCommandEvent &event) override
Update the calculations when the user changes the desired external trace width.
void LoadSettings(PCB_CALCULATOR_SETTINGS *aCfg) override
Load the settings into the panel.
void TWDisplayValues(double aCurrent, double aExtWidth, double aIntWidth, double aExtThickness, double aIntThickness)
Display the results of a calculation (including resulting values such as the resistance and power los...
double GetUnitScale() override
Function GetUnitScale.
double GetUnitScale() override
Function GetUnitScale.
wxString GetUnitName()
Definition: unit_selector.h:51
#define _(s)
Some functions to handle hotkeys in KiCad.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition: eda_angle.h:401
double DoubleFromString(const wxString &TextValue)
const double copper_resistivity
wxString tracks_width_versus_current_formula
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
static LIB_SYMBOL * dummy()
Used to draw a dummy shape when a LIB_SYMBOL is not found in library.
Definition: sch_symbol.cpp:74
const int scale
void ConvertMarkdown2Html(const wxString &aMarkdownInput, wxString &aHtmlOutput)
#define UNIT_MIL
Definition: units_scales.h:37