KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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_TrackDeltaTValue->ChangeValue( wxString::Format( "%g", 10.0 ) );
243 m_TrackLengthValue->ChangeValue( wxString::Format( "%g", 20.0 ) );
244 m_TW_CuLength_choiceUnit->SetSelection( 0 );
245 m_TWResistivity->SetValue( wxString::Format( "%g", copper_resistivity ) );
246
247 m_ExtTrackWidthValue->ChangeValue( wxString::Format( "%g", 0.2 ) );
248 m_TW_ExtTrackWidth_choiceUnit->SetSelection( 0 );
249 m_ExtTrackThicknessValue->ChangeValue( wxString::Format( "%g", 35.0 ) );
250 m_ExtTrackThicknessUnit->SetSelection( 1 );
251
252 m_IntTrackWidthValue->ChangeValue( wxString::Format( "%g", 0.2 ) );
253 m_TW_IntTrackWidth_choiceUnit->SetSelection( 0 );
254 m_IntTrackThicknessValue->ChangeValue( wxString::Format( "%g", 35.0 ) );
255 m_IntTrackThicknessUnit->SetSelection( 1 );
256
257 m_TrackCurrentValue->SetValue( wxString::Format( "%g", 1.0 ) );
258}
259
260
261void PANEL_TRACK_WIDTH::TWDisplayValues( double aCurrent, double aExtWidth, double aIntWidth,
262 double aExtThickness, double aIntThickness )
263{
264 wxString msg;
265
266 // Show the current.
268 {
269 msg.Printf( wxT( "%g" ), aCurrent );
270 m_TrackCurrentValue->SetValue( msg );
271 }
272
273 // Load scale factors to convert into output units.
274 double extScale = m_TW_ExtTrackWidth_choiceUnit->GetUnitScale();
275 double intScale = m_TW_IntTrackWidth_choiceUnit->GetUnitScale();
276
277 // Display the widths.
279 {
280 msg.Printf( wxT( "%g" ), aExtWidth / extScale );
281 m_ExtTrackWidthValue->SetValue( msg );
282 }
283
285 {
286 msg.Printf( wxT( "%g" ), aIntWidth / intScale );
287 m_IntTrackWidthValue->SetValue( msg );
288 }
289
290 // Display cross-sectional areas.
291 msg.Printf( wxT( "%g" ), (aExtWidth * aExtThickness) / (extScale * extScale) );
292 m_ExtTrackAreaValue->SetLabel( msg );
293 msg.Printf( wxT( "%g" ), (aIntWidth * aIntThickness) / (intScale * intScale) );
294 m_IntTrackAreaValue->SetLabel( msg );
295
296 // Show area units.
297 wxString strunit = m_TW_ExtTrackWidth_choiceUnit->GetUnitName();
298 msg = strunit + wxT( "²" );
299 m_extTrackAreaUnitLabel->SetLabel( msg );
301 msg = strunit + wxT( "²" );
302 m_intTrackAreaUnitLabel->SetLabel( msg );
303
304 // Load resistivity and length of traces.
305 double rho = std::abs( DoubleFromString( m_TWResistivity->GetValue() ) );
306 double trackLen = std::abs( DoubleFromString( m_TrackLengthValue->GetValue() ) );
308
309 // Calculate resistance.
310 double extResistance = ( rho * trackLen ) / ( aExtWidth * aExtThickness );
311 double intResistance = ( rho * trackLen ) / ( aIntWidth * aIntThickness );
312
313 // Display resistance.
314 msg.Printf( wxT( "%g" ), extResistance );
315 m_ExtTrackResistValue->SetLabel( msg );
316 msg.Printf( wxT( "%g" ), intResistance );
317 m_IntTrackResistValue->SetLabel( msg );
318
319 // Display voltage drop along trace.
320 double extV = extResistance * aCurrent;
321 msg.Printf( wxT( "%g" ), extV );
322 m_ExtTrackVDropValue->SetLabel( msg );
323 double intV = intResistance * aCurrent;
324 msg.Printf( wxT( "%g" ), intV );
325 m_IntTrackVDropValue->SetLabel( msg );
326
327 // And power loss.
328 msg.Printf( wxT( "%g" ), extV * aCurrent );
329 m_ExtTrackLossValue->SetLabel( msg );
330 msg.Printf( wxT( "%g" ), intV * aCurrent );
331 m_IntTrackLossValue->SetLabel( msg );
332}
333
334
336{
337 wxFont labelfont;
338 wxFont controlfont;
339
340 // Set the font weight of the current.
341 labelfont = m_staticTextCurrent->GetFont();
342 controlfont = m_TrackCurrentValue->GetFont();
343
345 {
346 labelfont.SetWeight( wxFONTWEIGHT_BOLD );
347 controlfont.SetWeight( wxFONTWEIGHT_BOLD );
348 }
349 else
350 {
351 labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
352 controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
353 }
354
355 m_staticTextCurrent->SetFont( labelfont );
356 m_TrackCurrentValue->SetFont( controlfont );
357
358 // Set the font weight of the external track width.
359 labelfont = m_staticTextExtWidth->GetFont();
360 controlfont = m_ExtTrackWidthValue->GetFont();
361
363 {
364 labelfont.SetWeight( wxFONTWEIGHT_BOLD );
365 controlfont.SetWeight( wxFONTWEIGHT_BOLD );
366 }
367 else
368 {
369 labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
370 controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
371 }
372
373 m_staticTextExtWidth->SetFont( labelfont );
374 m_ExtTrackWidthValue->SetFont( controlfont );
375
376 // Set the font weight of the internal track width.
377 labelfont = m_staticTextIntWidth->GetFont();
378 controlfont = m_IntTrackWidthValue->GetFont();
379
381 {
382 labelfont.SetWeight( wxFONTWEIGHT_BOLD );
383 controlfont.SetWeight( wxFONTWEIGHT_BOLD );
384 }
385 else
386 {
387 labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
388 controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
389 }
390
391 m_staticTextIntWidth->SetFont( labelfont );
392 m_IntTrackWidthValue->SetFont( controlfont );
393
394 // Text sizes have changed when the font weight was changes
395 // So, run the page layout to reflect the changes
396 GetSizer()->Layout();
397}
398
399/* calculate track width for external or internal layers
400 *
401 * Imax = 0.048 * dT^0.44 * A^0.725 for external layer
402 * Imax = 0.024 * dT^0.44 * A^0.725 for internal layer
403 * with A = area = aThickness * trackWidth ( in mils )
404 * and dT = temperature rise in degree C
405 * Of course we want to know trackWidth
406 */
407double PANEL_TRACK_WIDTH::TWCalculateWidth( double aCurrent, double aThickness, double aDeltaT_C,
408 bool aUseInternalLayer )
409{
410 // Appropriate scale for requested layer.
411 double scale = aUseInternalLayer ? 0.024 : 0.048;
412
413 // aThickness is given in normalize units (in meters) and we need mil
414 aThickness /= UNIT_MIL;
415
416 /* formula is Imax = scale * dT^0.44 * A^0.725
417 * or
418 * log(Imax) = log(scale) + 0.44*log(dT) +(0.725*(log(aThickness) + log(trackWidth))
419 * log(trackWidth) * 0.725 = log(Imax) - log(scale) - 0.44*log(dT) - 0.725*log(aThickness)
420 */
421 double dtmp = log( aCurrent ) - log( scale ) - 0.44 * log( aDeltaT_C ) - 0.725 * log( aThickness );
422 dtmp /= 0.725;
423 double trackWidth = exp( dtmp );
424
425 trackWidth *= UNIT_MIL; // We are using normalize units (sizes in meters) and we have mil
426 return trackWidth; // in meters
427}
428
429
430double PANEL_TRACK_WIDTH::TWCalculateCurrent( double aWidth, double aThickness, double aDeltaT_C,
431 bool aUseInternalLayer )
432{
433 // Appropriate scale for requested layer.
434 double scale = aUseInternalLayer ? 0.024 : 0.048;
435
436 // Convert thickness and width to mils.
437 aThickness /= UNIT_MIL;
438 aWidth /= UNIT_MIL;
439
440 double area = aThickness * aWidth;
441 double current = scale * pow( aDeltaT_C, 0.44 ) * pow( area, 0.725 );
442
443 return current;
444}
445
446
448{
449 // Disable calculations while we initialise.
450 m_TWNested = true;
451
452 // Read parameter values.
453 m_TrackCurrentValue->SetValue( aCfg->m_TrackWidth.current );
454 m_TrackDeltaTValue->SetValue( aCfg->m_TrackWidth.delta_tc );
455 m_TrackLengthValue->SetValue( aCfg->m_TrackWidth.track_len );
457#if 0 // the IPC formula is valid for copper traces, so we do not currently adjust the resistivity
458 m_TWResistivity->SetValue( aCfg->m_TrackWidth.resistivity );
459#else
460 m_TWResistivity->SetValue( wxString::Format( "%g", copper_resistivity ) );
461#endif
470
471 if( tracks_width_versus_current_formula.StartsWith( "<!" ) )
473 else
474 {
475 wxString html_txt;
476 ConvertMarkdown2Html( wxGetTranslation( tracks_width_versus_current_formula ), html_txt );
477 m_htmlWinFormulas->SetPage( html_txt );
478 }
479
480 // Make sure the correct master mode is displayed.
482
483 // Enable calculations and perform the initial one.
484 m_TWNested = false;
485
486 wxCommandEvent dummy;
488}
const char * name
Definition: DXF_plotter.cpp:57
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 ...
void ThemeChanged() override
Update UI elements of the panel when the theme changes to ensure the images and fonts/colors are appr...
enum PANEL_TRACK_WIDTH::@40 m_TWMode
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:424
double DoubleFromString(const wxString &TextValue)
const double copper_resistivity
const double copper_resistivity
wxString tracks_width_versus_current_formula
const int scale
std::vector< FAB_LAYER_COLOR > dummy
void ConvertMarkdown2Html(const wxString &aMarkdownInput, wxString &aHtmlOutput)
#define UNIT_MIL
Definition: units_scales.h:37