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 The 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
18 * along with this program. If not, see <https://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>
35#include <units_scales.h>
36
38
39#include <i18n_utility.h> // For _HKI definition
42
43extern double DoubleFromString( const wxString& TextValue );
44
45// The track width formula is valid only for copper material
46const double copper_resistivity = 1.72e-8;
47
48
49PANEL_TRACK_WIDTH::PANEL_TRACK_WIDTH( wxWindow* parent, wxWindowID id,
50 const wxPoint& pos, const wxSize& size,
51 long style, const wxString& name ) :
52 PANEL_TRACK_WIDTH_BASE( parent, id, pos, size, style, name ),
54 m_TWNested( false )
55{
56 m_trackTempUnits->SetLabel( wxT( "°C" ) );
57 m_resistivityUnits->SetLabel( wxT( "Ω⋅m" ) );
58
59 m_extTrackResUnits->SetLabel( wxT( "Ω" ) );
60 m_intTrackResUnits->SetLabel( wxT( "Ω" ) );
61
62 m_staticText63->SetLabel( _( "Temperature rise" ) + wxT( " (ΔT):" ) );
63
64 // Needed on wxWidgets 3.0 to ensure sizers are correctly set
65 GetSizer()->SetSizeHints( this );
66}
67
68
72
73
75{
76 m_htmlWinFormulas->ThemeChanged();
77}
78
79
96
97
98void PANEL_TRACK_WIDTH::OnTWParametersChanged( wxCommandEvent& event )
99{
100 switch(m_TWMode)
101 {
102 case TW_MASTER_CURRENT: OnTWCalculateFromCurrent( event ); break;
105 }
106}
107
108
110{
111 // Setting the calculated values generates further events. Stop them.
112 if( m_TWNested )
113 {
114 event.StopPropagation();
115 return;
116 }
117
118 m_TWNested = true;
119
120 // Update state.
122 {
125 }
126
127 // Prepare parameters:
128 double current = std::abs( DoubleFromString( m_TrackCurrentValue->GetValue() ) );
129 double extThickness = std::abs( DoubleFromString( m_ExtTrackThicknessValue->GetValue() ) );
130 double intThickness = std::abs( DoubleFromString( m_IntTrackThicknessValue->GetValue() ) );
131 double deltaT_C = std::abs( DoubleFromString( m_TrackDeltaTValue->GetValue() ) );
132
133 // Normalize by units.
134 extThickness *= m_ExtTrackThicknessUnit->GetUnitScale();
135 intThickness *= m_IntTrackThicknessUnit->GetUnitScale();
136
137 // Calculate the widths.
138 double extTrackWidth = TWCalculateWidth( current, extThickness, deltaT_C, false );
139 double intTrackWidth = TWCalculateWidth( current, intThickness, deltaT_C, true );
140
141 // Update the display.
142 TWDisplayValues( current, extTrackWidth, intTrackWidth, extThickness, intThickness );
143
144 // Re-enable the events.
145 m_TWNested = false;
146}
147
148
150{
151 // Setting the calculated values generates further events. Stop them.
152 if( m_TWNested )
153 {
154 event.StopPropagation();
155 return;
156 }
157 m_TWNested = true;
158
159 // Update state.
161 {
164 }
165
166 // Load parameters.
167 double current;
168 double extThickness = std::abs( DoubleFromString( m_ExtTrackThicknessValue->GetValue() ) );
169 double intThickness = std::abs( DoubleFromString( m_IntTrackThicknessValue->GetValue() ) );
170 double deltaT_C = std::abs( DoubleFromString( m_TrackDeltaTValue->GetValue() ) );
171 double extTrackWidth = std::abs( DoubleFromString( m_ExtTrackWidthValue->GetValue() ) );
172 double intTrackWidth;
173
174 // Normalize units.
175 extThickness *= m_ExtTrackThicknessUnit->GetUnitScale();
176 intThickness *= m_IntTrackThicknessUnit->GetUnitScale();
177 extTrackWidth *= m_TW_ExtTrackWidth_choiceUnit->GetUnitScale();
178
179 // Calculate the maximum current.
180 current = TWCalculateCurrent( extTrackWidth, extThickness, deltaT_C, false );
181
182 // And now calculate the corresponding internal width.
183 intTrackWidth = TWCalculateWidth( current, intThickness, deltaT_C, true );
184
185 // Update the display.
186 TWDisplayValues( current, extTrackWidth, intTrackWidth, extThickness, intThickness );
187
188 // Re-enable the events.
189 m_TWNested = false;
190}
191
192
194{
195 // Setting the calculated values generates further events. Stop them.
196 if( m_TWNested )
197 {
198 event.StopPropagation();
199 return;
200 }
201
202 m_TWNested = true;
203
204 // Update state.
206 {
209 }
210
211 // Load parameters.
212 double current;
213 double extThickness = std::abs( DoubleFromString( m_ExtTrackThicknessValue->GetValue() ) );
214 double intThickness = std::abs( DoubleFromString( m_IntTrackThicknessValue->GetValue() ) );
215 double deltaT_C = std::abs( DoubleFromString( m_TrackDeltaTValue->GetValue() ) );
216 double extTrackWidth;
217 double intTrackWidth = std::abs( DoubleFromString( m_IntTrackWidthValue->GetValue() ) );
218
219 // Normalize units.
220 extThickness *= m_ExtTrackThicknessUnit->GetUnitScale();
221 intThickness *= m_IntTrackThicknessUnit->GetUnitScale();
222 intTrackWidth *= m_TW_IntTrackWidth_choiceUnit->GetUnitScale();
223
224 // Calculate the maximum current.
225 current = TWCalculateCurrent( intTrackWidth, intThickness, deltaT_C, true );
226
227 // And now calculate the corresponding external width.
228 extTrackWidth = TWCalculateWidth( current, extThickness, deltaT_C, false );
229
230 // Update the display.
231 TWDisplayValues( current, extTrackWidth, intTrackWidth, extThickness, intThickness );
232
233 // Re-enable the events.
234 m_TWNested = false;
235}
236
237
238void PANEL_TRACK_WIDTH::OnTWResetButtonClick( wxCommandEvent& event )
239{
240 // Note: a wxString:Format( "%g", xx) is used to use local separator in floats
241
242 // Init main parameters:
243 m_TrackDeltaTValue->ChangeValue( wxString::Format( "%g", 10.0 ) );
244 m_TrackLengthValue->ChangeValue( wxString::Format( "%g", 20.0 ) );
245 m_TW_CuLength_choiceUnit->SetSelection( 0 );
246 m_TWResistivity->SetValue( wxString::Format( "%g", copper_resistivity ) );
247
248 m_ExtTrackWidthValue->ChangeValue( wxString::Format( "%g", 0.2 ) );
249 m_TW_ExtTrackWidth_choiceUnit->SetSelection( 0 );
250 m_ExtTrackThicknessValue->ChangeValue( wxString::Format( "%g", 35.0 ) );
251 m_ExtTrackThicknessUnit->SetSelection( 1 );
252
253 m_IntTrackWidthValue->ChangeValue( wxString::Format( "%g", 0.2 ) );
254 m_TW_IntTrackWidth_choiceUnit->SetSelection( 0 );
255 m_IntTrackThicknessValue->ChangeValue( wxString::Format( "%g", 35.0 ) );
256 m_IntTrackThicknessUnit->SetSelection( 1 );
257
258 m_TrackCurrentValue->SetValue( wxString::Format( "%g", 1.0 ) );
259}
260
261
262void PANEL_TRACK_WIDTH::TWDisplayValues( double aCurrent, double aExtWidth, double aIntWidth,
263 double aExtThickness, double aIntThickness )
264{
265 wxString msg;
266
267 // Show the current.
269 {
270 msg.Printf( wxT( "%g" ), aCurrent );
271 m_TrackCurrentValue->SetValue( msg );
272 }
273
274 // Load scale factors to convert into output units.
275 double extScale = m_TW_ExtTrackWidth_choiceUnit->GetUnitScale();
276 double intScale = m_TW_IntTrackWidth_choiceUnit->GetUnitScale();
277
278 // Display the widths.
280 {
281 msg.Printf( wxT( "%g" ), aExtWidth / extScale );
282 m_ExtTrackWidthValue->SetValue( msg );
283 }
284
286 {
287 msg.Printf( wxT( "%g" ), aIntWidth / intScale );
288 m_IntTrackWidthValue->SetValue( msg );
289 }
290
291 // Display cross-sectional areas.
292 msg.Printf( wxT( "%g" ), (aExtWidth * aExtThickness) / (extScale * extScale) );
293 m_ExtTrackAreaValue->SetLabel( msg );
294 msg.Printf( wxT( "%g" ), (aIntWidth * aIntThickness) / (intScale * intScale) );
295 m_IntTrackAreaValue->SetLabel( msg );
296
297 // Show area units.
298 wxString strunit = m_TW_ExtTrackWidth_choiceUnit->GetUnitName();
299 msg = strunit + wxT( "²" );
300 m_extTrackAreaUnitLabel->SetLabel( msg );
301 strunit = m_TW_IntTrackWidth_choiceUnit->GetUnitName();
302 msg = strunit + wxT( "²" );
303 m_intTrackAreaUnitLabel->SetLabel( msg );
304
305 // Load resistivity and length of traces.
306 double rho = std::abs( DoubleFromString( m_TWResistivity->GetValue() ) );
307 double trackLen = std::abs( DoubleFromString( m_TrackLengthValue->GetValue() ) );
308 trackLen *= m_TW_CuLength_choiceUnit->GetUnitScale();
309
310 // Calculate resistance.
311 double extResistance = ( rho * trackLen ) / ( aExtWidth * aExtThickness );
312 double intResistance = ( rho * trackLen ) / ( aIntWidth * aIntThickness );
313
314 // Display resistance.
315 msg.Printf( wxT( "%g" ), extResistance );
316 m_ExtTrackResistValue->SetLabel( msg );
317 msg.Printf( wxT( "%g" ), intResistance );
318 m_IntTrackResistValue->SetLabel( msg );
319
320 // Display voltage drop along trace.
321 double extV = extResistance * aCurrent;
322 msg.Printf( wxT( "%g" ), extV );
323 m_ExtTrackVDropValue->SetLabel( msg );
324 double intV = intResistance * aCurrent;
325 msg.Printf( wxT( "%g" ), intV );
326 m_IntTrackVDropValue->SetLabel( msg );
327
328 // And power loss.
329 msg.Printf( wxT( "%g" ), extV * aCurrent );
330 m_ExtTrackLossValue->SetLabel( msg );
331 msg.Printf( wxT( "%g" ), intV * aCurrent );
332 m_IntTrackLossValue->SetLabel( msg );
333}
334
335
337{
338 wxFont labelfont;
339 wxFont controlfont;
340
341 // Set the font weight of the current.
342 labelfont = m_staticTextCurrent->GetFont();
343 controlfont = m_TrackCurrentValue->GetFont();
344
346 {
347 labelfont.SetWeight( wxFONTWEIGHT_BOLD );
348 controlfont.SetWeight( wxFONTWEIGHT_BOLD );
349 }
350 else
351 {
352 labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
353 controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
354 }
355
356 m_staticTextCurrent->SetFont( labelfont );
357 m_TrackCurrentValue->SetFont( controlfont );
358
359 // Set the font weight of the external track width.
360 labelfont = m_staticTextExtWidth->GetFont();
361 controlfont = m_ExtTrackWidthValue->GetFont();
362
364 {
365 labelfont.SetWeight( wxFONTWEIGHT_BOLD );
366 controlfont.SetWeight( wxFONTWEIGHT_BOLD );
367 }
368 else
369 {
370 labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
371 controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
372 }
373
374 m_staticTextExtWidth->SetFont( labelfont );
375 m_ExtTrackWidthValue->SetFont( controlfont );
376
377 // Set the font weight of the internal track width.
378 labelfont = m_staticTextIntWidth->GetFont();
379 controlfont = m_IntTrackWidthValue->GetFont();
380
382 {
383 labelfont.SetWeight( wxFONTWEIGHT_BOLD );
384 controlfont.SetWeight( wxFONTWEIGHT_BOLD );
385 }
386 else
387 {
388 labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
389 controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
390 }
391
392 m_staticTextIntWidth->SetFont( labelfont );
393 m_IntTrackWidthValue->SetFont( controlfont );
394
395 // Text sizes have changed when the font weight was changes
396 // So, run the page layout to reflect the changes
397 GetSizer()->Layout();
398}
399
400// Calculate track width for external or internal layers using the IPC-2152 based Brooks & Adam
401// fit. Widths and thicknesses are passed in internal units (meters) and converted to mils for the
402// closed-form equation, which is expressed in mils and amperes.
403double PANEL_TRACK_WIDTH::TWCalculateWidth( double aCurrent, double aThickness, double aDeltaT_C,
404 bool aUseInternalLayer )
405{
407 aCurrent, aThickness / UNIT_MIL, aDeltaT_C, aUseInternalLayer );
408
409 return widthMils * UNIT_MIL; // Convert back to internal units (meters)
410}
411
412
413double PANEL_TRACK_WIDTH::TWCalculateCurrent( double aWidth, double aThickness, double aDeltaT_C,
414 bool aUseInternalLayer )
415{
416 return TRACK_WIDTH_CALCULATIONS::CurrentFromWidth( aWidth / UNIT_MIL, aThickness / UNIT_MIL,
417 aDeltaT_C, aUseInternalLayer );
418}
419
420
422{
423 // Disable calculations while we initialise.
424 m_TWNested = true;
425
426 // Read parameter values.
427 m_TrackCurrentValue->SetValue( aCfg->m_TrackWidth.current );
428 m_TrackDeltaTValue->SetValue( aCfg->m_TrackWidth.delta_tc );
429 m_TrackLengthValue->SetValue( aCfg->m_TrackWidth.track_len );
431#if 0 // the IPC formula is valid for copper traces, so we do not currently adjust the resistivity
432 m_TWResistivity->SetValue( aCfg->m_TrackWidth.resistivity );
433#else
434 m_TWResistivity->SetValue( wxString::Format( "%g", copper_resistivity ) );
435#endif
444
445 if( tracks_width_versus_current_formula.StartsWith( "<!" ) )
447 else
448 {
449 wxString html_txt;
450 ConvertMarkdown2Html( wxGetTranslation( tracks_width_versus_current_formula ), html_txt );
451 m_htmlWinFormulas->SetPage( html_txt );
452 }
453
454 // Make sure the correct master mode is displayed.
456
457 // Enable calculations and perform the initial one.
458 m_TWNested = false;
459
460 wxCommandEvent dummy;
462}
const char * name
PANEL_TRACK_WIDTH_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
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
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...
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...
enum PANEL_TRACK_WIDTH::@132265162345043127367315227343052112174236206025 m_TWMode
#define _(s)
Some functions to handle hotkeys in KiCad.
double CurrentFromWidth(double aWidthMils, double aThicknessMils, double aDeltaT_C, bool aUseInternalLayer)
Compute the maximum current a track can carry for a given temperature rise.
double WidthFromCurrent(double aCurrentA, double aThicknessMils, double aDeltaT_C, bool aUseInternalLayer)
Compute the track width required to carry a given current for a given temperature rise.
EDA_ANGLE abs(const EDA_ANGLE &aAngle)
Definition eda_angle.h:400
double DoubleFromString(const wxString &TextValue)
const double copper_resistivity
wxString tracks_width_versus_current_formula
#define UNIT_MIL
std::vector< FAB_LAYER_COLOR > dummy
void ConvertMarkdown2Html(const wxString &aMarkdownInput, wxString &aHtmlOutput)