KiCad PCB EDA Suite
tracks_width_versus_current.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 <wx/wx.h>
30 #include <kiface_i.h>
31 #include <dialog_helpers.h>
32 
34 #include "class_regulator_data.h"
35 #include "pcb_calculator_frame.h"
37 #include "units_scales.h"
38 
41 
42 extern double DoubleFromString( const wxString& TextValue );
43 
44 
46 {
47  // Save current parameters values in config.
48  auto cfg = static_cast<PCB_CALCULATOR_SETTINGS*>( Kiface().KifaceSettings() );
49 
50  cfg->m_TrackWidth.current = m_TrackCurrentValue->GetValue();
51  cfg->m_TrackWidth.delta_tc = m_TrackDeltaTValue->GetValue();
52  cfg->m_TrackWidth.track_len = m_TrackLengthValue->GetValue();
53  cfg->m_TrackWidth.track_len_units = m_TW_CuLength_choiceUnit->GetSelection();
54  cfg->m_TrackWidth.resistivity = m_TWResistivity->GetValue();
55  cfg->m_TrackWidth.ext_track_width = m_ExtTrackWidthValue->GetValue();
56  cfg->m_TrackWidth.ext_track_width_units = m_TW_ExtTrackWidth_choiceUnit->GetSelection();
57  cfg->m_TrackWidth.ext_track_thickness = m_ExtTrackThicknessValue->GetValue();
58  cfg->m_TrackWidth.ext_track_thickness_units = m_ExtTrackThicknessUnit->GetSelection();
59  cfg->m_TrackWidth.int_track_width = m_IntTrackWidthValue->GetValue();
60  cfg->m_TrackWidth.int_track_width_units = m_TW_IntTrackWidth_choiceUnit->GetSelection();
61  cfg->m_TrackWidth.int_track_thickness = m_IntTrackThicknessValue->GetValue();
62  cfg->m_TrackWidth.int_track_thickness_units = m_IntTrackThicknessUnit->GetSelection();
63 }
64 
65 
66 void PCB_CALCULATOR_FRAME::OnTWParametersChanged( wxCommandEvent& event )
67 {
68  switch(m_TWMode)
69  {
70  case TW_MASTER_CURRENT:
71  OnTWCalculateFromCurrent( event );
72  break;
75  break;
78  break;
79  }
80 }
81 
82 
84 {
85  // Setting the calculated values generates further events. Stop them.
86  if( m_TWNested )
87  {
88  event.StopPropagation();
89  return;
90  }
91 
92  m_TWNested = true;
93 
94  // Update state.
96  {
99  }
100 
101  // Prepare parameters:
102  double current = std::abs( DoubleFromString( m_TrackCurrentValue->GetValue() ) );
103  double extThickness = std::abs( DoubleFromString( m_ExtTrackThicknessValue->GetValue() ) );
104  double intThickness = std::abs( DoubleFromString( m_IntTrackThicknessValue->GetValue() ) );
105  double deltaT_C = std::abs( DoubleFromString( m_TrackDeltaTValue->GetValue() ) );
106 
107  // Normalize by units.
108  extThickness *= m_ExtTrackThicknessUnit->GetUnitScale();
109  intThickness *= m_IntTrackThicknessUnit->GetUnitScale();
110 
111  // Calculate the widths.
112  double extTrackWidth = TWCalculateWidth( current, extThickness, deltaT_C, false );
113  double intTrackWidth = TWCalculateWidth( current, intThickness, deltaT_C, true );
114 
115  // Update the display.
116  TWDisplayValues( current, extTrackWidth, intTrackWidth, extThickness, intThickness );
117 
118  // Re-enable the events.
119  m_TWNested = false;
120 }
121 
122 
124 {
125  // Setting the calculated values generates further events. Stop them.
126  if( m_TWNested )
127  {
128  event.StopPropagation();
129  return;
130  }
131  m_TWNested = true;
132 
133  // Update state.
135  {
138  }
139 
140  // Load parameters.
141  double current;
142  double extThickness = std::abs( DoubleFromString( m_ExtTrackThicknessValue->GetValue() ) );
143  double intThickness = std::abs( DoubleFromString( m_IntTrackThicknessValue->GetValue() ) );
144  double deltaT_C = std::abs( DoubleFromString( m_TrackDeltaTValue->GetValue() ) );
145  double extTrackWidth = std::abs( DoubleFromString( m_ExtTrackWidthValue->GetValue() ) );
146  double intTrackWidth;
147 
148  // Normalize units.
149  extThickness *= m_ExtTrackThicknessUnit->GetUnitScale();
150  intThickness *= m_IntTrackThicknessUnit->GetUnitScale();
151  extTrackWidth *= m_TW_ExtTrackWidth_choiceUnit->GetUnitScale();
152 
153  // Calculate the maximum current.
154  current = TWCalculateCurrent( extTrackWidth, extThickness, deltaT_C, false );
155 
156  // And now calculate the corresponding internal width.
157  intTrackWidth = TWCalculateWidth( current, intThickness, deltaT_C, true );
158 
159  // Update the display.
160  TWDisplayValues( current, extTrackWidth, intTrackWidth, extThickness, intThickness );
161 
162  // Re-enable the events.
163  m_TWNested = false;
164 }
165 
166 
168 {
169  // Setting the calculated values generates further events. Stop them.
170  if( m_TWNested )
171  {
172  event.StopPropagation();
173  return;
174  }
175 
176  m_TWNested = true;
177 
178  // Update state.
180  {
183  }
184 
185  // Load parameters.
186  double current;
187  double extThickness = std::abs( DoubleFromString( m_ExtTrackThicknessValue->GetValue() ) );
188  double intThickness = std::abs( DoubleFromString( m_IntTrackThicknessValue->GetValue() ) );
189  double deltaT_C = std::abs( DoubleFromString( m_TrackDeltaTValue->GetValue() ) );
190  double extTrackWidth;
191  double intTrackWidth = std::abs( DoubleFromString( m_IntTrackWidthValue->GetValue() ) );
192 
193  // Normalize units.
194  extThickness *= m_ExtTrackThicknessUnit->GetUnitScale();
195  intThickness *= m_IntTrackThicknessUnit->GetUnitScale();
196  intTrackWidth *= m_TW_IntTrackWidth_choiceUnit->GetUnitScale();
197 
198  // Calculate the maximum current.
199  current = TWCalculateCurrent( intTrackWidth, intThickness, deltaT_C, true );
200 
201  // And now calculate the corresponding external width.
202  extTrackWidth = TWCalculateWidth( current, extThickness, deltaT_C, false );
203 
204  // Update the display.
205  TWDisplayValues( current, extTrackWidth, intTrackWidth, extThickness, intThickness );
206 
207  // Re-enable the events.
208  m_TWNested = false;
209 }
210 
211 
212 void PCB_CALCULATOR_FRAME::OnTWResetButtonClick( wxCommandEvent& event )
213 {
214  // a wxString:Format( "%g", xx) is used to use local separator in floats
215  m_TrackCurrentValue->SetValue( wxString::Format( "%g", 1.0 ) );
216  m_TrackDeltaTValue->SetValue( wxString::Format( "%g", 10.0 ) );
217  m_TrackLengthValue->SetValue( wxString::Format( "%g", 20.0 ) );
218  m_TW_CuLength_choiceUnit->SetSelection( 0 );
219  m_TWResistivity->SetValue( wxString::Format( "%g", 1.72e-8 ) );
220  m_ExtTrackWidthValue->SetValue( wxString::Format( "%g", 0.2 ) );
221  m_TW_ExtTrackWidth_choiceUnit->SetSelection( 0 );
222  m_ExtTrackThicknessValue->SetValue( wxString::Format( "%g", 0.035 ) );
223  m_ExtTrackThicknessUnit->SetSelection( 0 );
224  m_IntTrackWidthValue->SetValue( wxString::Format( "%g", 0.2 ) );
225  m_TW_IntTrackWidth_choiceUnit->SetSelection( 0 );
226  m_IntTrackThicknessValue->SetValue( wxString::Format( "%g", 0.035 ) );
227  m_IntTrackThicknessUnit->SetSelection( 0 );
228 }
229 
230 
231 void PCB_CALCULATOR_FRAME::TWDisplayValues( double aCurrent, double aExtWidth,
232  double aIntWidth, double aExtThickness, double aIntThickness )
233 {
234  wxString msg;
235 
236  // Show the current.
237  if( m_TWMode != TW_MASTER_CURRENT )
238  {
239  msg.Printf( wxT( "%g" ), aCurrent );
240  m_TrackCurrentValue->SetValue( msg );
241  }
242 
243  // Load scale factors to convert into output units.
244  double extScale = m_TW_ExtTrackWidth_choiceUnit->GetUnitScale();
245  double intScale = m_TW_IntTrackWidth_choiceUnit->GetUnitScale();
246 
247  // Display the widths.
249  {
250  msg.Printf( wxT( "%g" ), aExtWidth / extScale );
251  m_ExtTrackWidthValue->SetValue( msg );
252  }
253 
255  {
256  msg.Printf( wxT( "%g" ), aIntWidth / intScale );
257  m_IntTrackWidthValue->SetValue( msg );
258  }
259 
260  // Display cross-sectional areas.
261  msg.Printf( wxT( "%g" ), (aExtWidth * aExtThickness) / (extScale * extScale) );
262  m_ExtTrackAreaValue->SetLabel( msg );
263  msg.Printf( wxT( "%g" ), (aIntWidth * aIntThickness) / (intScale * intScale) );
264  m_IntTrackAreaValue->SetLabel( msg );
265 
266  // Show area units.
267  wxString strunit = m_TW_ExtTrackWidth_choiceUnit->GetUnitName();
268  msg = strunit + wxT( "²" );
269  m_extTrackAreaUnitLabel->SetLabel( msg );
271  msg = strunit + wxT( "²" );
272  m_intTrackAreaUnitLabel->SetLabel( msg );
273 
274  // Load resistivity and length of traces.
275  double rho = std::abs( DoubleFromString( m_TWResistivity->GetValue() ) );
276  double trackLen = std::abs( DoubleFromString( m_TrackLengthValue->GetValue() ) );
277  trackLen *= m_TW_CuLength_choiceUnit->GetUnitScale();
278 
279  // Calculate resistance.
280  double extResistance = ( rho * trackLen ) / ( aExtWidth * aExtThickness );
281  double intResistance = ( rho * trackLen ) / ( aIntWidth * aIntThickness );
282 
283  // Display resistance.
284  msg.Printf( wxT( "%g" ), extResistance );
285  m_ExtTrackResistValue->SetLabel( msg );
286  msg.Printf( wxT( "%g" ), intResistance );
287  m_IntTrackResistValue->SetLabel( msg );
288 
289  // Display voltage drop along trace.
290  double extV = extResistance * aCurrent;
291  msg.Printf( wxT( "%g" ), extV );
292  m_ExtTrackVDropValue->SetLabel( msg );
293  double intV = intResistance * aCurrent;
294  msg.Printf( wxT( "%g" ), intV );
295  m_IntTrackVDropValue->SetLabel( msg );
296 
297  // And power loss.
298  msg.Printf( wxT( "%g" ), extV * aCurrent );
299  m_ExtTrackLossValue->SetLabel( msg );
300  msg.Printf( wxT( "%g" ), intV * aCurrent );
301  m_IntTrackLossValue->SetLabel( msg );
302 }
303 
304 
306 {
307  wxFont labelfont;
308  wxFont controlfont;
309 
310  // Set the font weight of the current.
311  labelfont = m_staticTextCurrent->GetFont();
312  controlfont = m_TrackCurrentValue->GetFont();
313 
314  if( m_TWMode == TW_MASTER_CURRENT )
315  {
316  labelfont.SetWeight( wxFONTWEIGHT_BOLD );
317  controlfont.SetWeight( wxFONTWEIGHT_BOLD );
318  }
319  else
320  {
321  labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
322  controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
323  }
324 
325  m_staticTextCurrent->SetFont( labelfont );
326  m_TrackCurrentValue->SetFont( controlfont );
327 
328  // Set the font weight of the external track width.
329  labelfont = m_staticTextExtWidth->GetFont();
330  controlfont = m_ExtTrackWidthValue->GetFont();
331 
333  {
334  labelfont.SetWeight( wxFONTWEIGHT_BOLD );
335  controlfont.SetWeight( wxFONTWEIGHT_BOLD );
336  }
337  else
338  {
339  labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
340  controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
341  }
342 
343  m_staticTextExtWidth->SetFont( labelfont );
344  m_ExtTrackWidthValue->SetFont( controlfont );
345 
346  // Set the font weight of the internal track width.
347  labelfont = m_staticTextIntWidth->GetFont();
348  controlfont = m_IntTrackWidthValue->GetFont();
349 
351  {
352  labelfont.SetWeight( wxFONTWEIGHT_BOLD );
353  controlfont.SetWeight( wxFONTWEIGHT_BOLD );
354  }
355  else
356  {
357  labelfont.SetWeight( wxFONTWEIGHT_NORMAL );
358  controlfont.SetWeight( wxFONTWEIGHT_NORMAL );
359  }
360 
361  m_staticTextIntWidth->SetFont( labelfont );
362  m_IntTrackWidthValue->SetFont( controlfont );
363 
364  // Text sizes have changed when the font weight was changes
365  // So, run the page layout to reflect the changes
366  wxWindow* page = m_Notebook->GetPage ( 1 );
367  page->GetSizer()->Layout();
368 }
369 
370 /* calculate track width for external or internal layers
371  *
372  * Imax = 0.048 * dT^0.44 * A^0.725 for external layer
373  * Imax = 0.024 * dT^0.44 * A^0.725 for internal layer
374  * with A = area = aThickness * trackWidth ( in mils )
375  * and dT = temperature rise in degree C
376  * Of course we want to know trackWidth
377  */
378 double PCB_CALCULATOR_FRAME::TWCalculateWidth( double aCurrent, double aThickness, double aDeltaT_C,
379  bool aUseInternalLayer )
380 {
381  // Appropriate scale for requested layer.
382  double scale = aUseInternalLayer ? 0.024 : 0.048;
383 
384  // aThickness is given in normalize units (in meters) and we need mil
385  aThickness /= UNIT_MIL;
386 
387  /* formula is Imax = scale * dT^0.44 * A^0.725
388  * or
389  * log(Imax) = log(scale) + 0.44*log(dT)
390  * +(0.725*(log(aThickness) + log(trackWidth))
391  * log(trackWidth) * 0.725 = log(Imax) - log(scale) - 0.44*log(dT) - 0.725*log(aThickness)
392  */
393  double dtmp = log( aCurrent ) - log( scale ) - 0.44 * log( aDeltaT_C ) - 0.725 * log( aThickness );
394  dtmp /= 0.725;
395  double trackWidth = exp( dtmp );
396 
397  trackWidth *= UNIT_MIL; // We are using normalize units (sizes in meters) and we have mil
398  return trackWidth; // in meters
399 }
400 
401 
402 double PCB_CALCULATOR_FRAME::TWCalculateCurrent( double aWidth, double aThickness, double aDeltaT_C,
403  bool aUseInternalLayer )
404 {
405  // Appropriate scale for requested layer.
406  double scale = aUseInternalLayer ? 0.024 : 0.048;
407 
408  // Convert thickness and width to mils.
409  aThickness /= UNIT_MIL;
410  aWidth /= UNIT_MIL;
411 
412  double area = aThickness * aWidth;
413  double current = scale * pow( aDeltaT_C, 0.44 ) * pow( area, 0.725 );
414  return current;
415 }
416 
417 
419 {
420  wxString msg;
421 
422  // Disable calculations while we initialise.
423  m_TWNested = true;
424 
425  // Read parameter values.
426  auto cfg = static_cast<PCB_CALCULATOR_SETTINGS*>( Kiface().KifaceSettings() );
427 
428  m_TrackCurrentValue->SetValue( cfg->m_TrackWidth.current );
429  m_TrackDeltaTValue->SetValue( cfg->m_TrackWidth.delta_tc );
430  m_TrackLengthValue->SetValue( cfg->m_TrackWidth.track_len );
431  m_TW_CuLength_choiceUnit->SetSelection( cfg->m_TrackWidth.track_len_units );
432  m_TWResistivity->SetValue( cfg->m_TrackWidth.resistivity );
433  m_ExtTrackWidthValue->SetValue( cfg->m_TrackWidth.ext_track_width );
434  m_TW_ExtTrackWidth_choiceUnit->SetSelection( cfg->m_TrackWidth.ext_track_width_units );
435  m_ExtTrackThicknessValue->SetValue( cfg->m_TrackWidth.ext_track_thickness );
436  m_ExtTrackThicknessUnit->SetSelection( cfg->m_TrackWidth.ext_track_thickness_units );
437  m_IntTrackWidthValue->SetValue( cfg->m_TrackWidth.int_track_width );
438  m_TW_IntTrackWidth_choiceUnit->SetSelection( cfg->m_TrackWidth.int_track_width_units );
439  m_IntTrackThicknessValue->SetValue( cfg->m_TrackWidth.int_track_thickness );
440  m_IntTrackThicknessUnit->SetSelection( cfg->m_TrackWidth.int_track_thickness_units );
441 
442  if( tracks_width_versus_current_formula.StartsWith( "<!" ) )
444  else
445  {
446  wxString html_txt;
447  ConvertMarkdown2Html( wxGetTranslation( tracks_width_versus_current_formula ), html_txt );
448  m_htmlWinFormulas->SetPage( html_txt );
449  }
450 
451  // Make sure the correct master mode is displayed.
453 
454  // Enable calculations and perform the initial one.
455  m_TWNested = false;
456  wxCommandEvent dummy;
458 }
void OnTWParametersChanged(wxCommandEvent &event) override
Function OnTWParametersChanged Called when the user changes the general parameters (i....
UNIT_SELECTOR_LEN * m_TW_ExtTrackWidth_choiceUnit
UNIT_SELECTOR_LEN * m_TW_IntTrackWidth_choiceUnit
void ConvertMarkdown2Html(const wxString &aMarkdownInput, wxString &aHtmlOutput)
virtual double GetUnitScale() override
Function GetUnitScale.
double TWCalculateCurrent(double aWidth, double aThickness, double aDeltaT_C, bool aUseInternalLayer)
Function TWCalculateCurrent Calculate maximum current based on given width and temperature rise.
void OnTWResetButtonClick(wxCommandEvent &event) override
Function OnTWResetButtonClick Called when the user clicks the reset button.
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
Definition: sch_symbol.cpp:69
enum PCB_CALCULATOR_FRAME::@39 m_TWMode
double TWCalculateWidth(double aCurrent, double aThickness, double aDeltaT_C, bool aUseInternalLayer)
Function TWCalculateWidth Calculate track width required based on given current and temperature rise.
void OnTWCalculateFromCurrent(wxCommandEvent &event) override
Function OnTWCalculateFromCurrent Called when the user changes the desired maximum current.
void TWUpdateModeDisplay()
Function TWUpdateModeDisplay Updates the fields to show whether the maximum current,...
void OnTWCalculateFromIntWidth(wxCommandEvent &event) override
Function OnTWCalculateFromIntWidth Called when the user changes the desired internal trace width.
void writeTrackWidthConfig()
Function writeTrackWidthConfig Write Track width parameters in config.
void initTrackWidthPanel()
Panel-specific initializers.
Contains structures for storage of regulator data.
KIFACE_I & Kiface()
Global KIFACE_I "get" accessor.
Helper dialog and control classes.
wxString tracks_width_versus_current_formula
wxString GetUnitName()
Definition: unit_selector.h:51
double DoubleFromString(const wxString &TextValue)
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
UNIT_SELECTOR_THICKNESS * m_IntTrackThicknessUnit
const int scale
virtual double GetUnitScale() override
Function GetUnitScale.
void OnTWCalculateFromExtWidth(wxCommandEvent &event) override
Function OnTWCalculateFromExtWidth Called when the user changes the desired external trace width.
#define UNIT_MIL
Definition: units_scales.h:35
void TWDisplayValues(double aCurrent, double aExtWidth, double aIntWidth, double aExtThickness, double aIntThickness)
Function TWDisplayValues Displays the results of a calculation (including resulting values such as th...
UNIT_SELECTOR_LEN * m_TW_CuLength_choiceUnit
UNIT_SELECTOR_THICKNESS * m_ExtTrackThicknessUnit