/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2011 jean-pierre.charras
* Copyright (C) 1992-2011 Kicad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/* see
* http://www.desmith.net/NMdS/Electronics/TraceWidth.html
* http://www.ultracad.com/articles/pcbtemp.pdf
* for more info
*/
#include "wx/wx.h"
#include "wx/config.h"
#include "pcb_calculator_frame_base.h"
#include "pcb_calculator.h"
#include "UnitSelector.h"
#include "units_scales.h"
extern double ReturnDoubleFromString( const wxString& TextValue );
// Key words to read/write some parameters in config:
#define KEYWORD_TW_CURRENT wxT( "TW_Track_Current" )
#define KEYWORD_TW_DELTA_TC wxT( "TW_Delta_TC" )
#define KEYWORD_TW_TRACK_COPPER_THICKNESS wxT( "TW_Track_CopperThickness" )
#define KEYWORD_TW_TRACK_LEN wxT( "TW_Track_Len" )
#define KEYWORD_TW_TRACK_COPPER_THICKNESS_UNIT wxT( "TW_Track_CopperThickness_Unit" )
#define KEYWORD_TW_TRACK_LEN_UNIT wxT( "TW_Track_Len_Unit" )
#define KEYWORD_TW_EXTTRACK_WIDTH_UNIT wxT( "TW_ExtTrack_Width_Unit" )
#define KEYWORD_TW_INTTRACK_WIDTH_UNIT wxT( "TW_IntTrack_Width_Unit" )
void PCB_CALCULATOR_FRAME::TW_WriteConfig()
{
// Save current parameters values in config:
m_Config->Write( KEYWORD_TW_EXTTRACK_WIDTH_UNIT, m_TW_ExtTrackWidth_choiceUnit->GetSelection() );
m_Config->Write( KEYWORD_TW_INTTRACK_WIDTH_UNIT, m_TW_IntTrackWidth_choiceUnit->GetSelection() );
m_Config->Write( KEYWORD_TW_TRACK_COPPER_THICKNESS_UNIT,
m_TW_CuThickness_choiceUnit->GetSelection() );
m_Config->Write( KEYWORD_TW_TRACK_LEN_UNIT, m_TW_CuLength_choiceUnit->GetSelection() );
m_Config->Write( KEYWORD_TW_CURRENT, m_TrackCurrentValue->GetValue() );
m_Config->Write( KEYWORD_TW_DELTA_TC, m_TrackDeltaTValue->GetValue() );
m_Config->Write( KEYWORD_TW_TRACK_COPPER_THICKNESS, m_TrackThicknessValue->GetValue() );
m_Config->Write( KEYWORD_TW_TRACK_LEN, m_TrackLengthValue->GetValue() );
}
void PCB_CALCULATOR_FRAME::OnTWCalculateButt( wxCommandEvent& event )
{
// Prepare parameters:
double current = ReturnDoubleFromString( m_TrackCurrentValue->GetValue() );
double thickness = ReturnDoubleFromString( m_TrackThicknessValue->GetValue() );
double deltaT_C = ReturnDoubleFromString( m_TrackDeltaTValue->GetValue() );
double track_len = ReturnDoubleFromString( m_TrackLengthValue->GetValue() );
double extTrackWidth;
double intTrackWidth;
// Normalize units:
thickness *= m_TW_CuThickness_choiceUnit->GetUnitScale();
track_len *= m_TW_CuLength_choiceUnit->GetUnitScale();
extTrackWidth = TWCalculate( current, thickness, deltaT_C, false );
intTrackWidth = TWCalculate( current, thickness, deltaT_C, true );
// Display values:
wxString msg;
msg.Printf( wxT( "%g" ), extTrackWidth / m_TW_ExtTrackWidth_choiceUnit->GetUnitScale() );
m_ExtTrackWidthValue->SetValue( msg );
msg.Printf( wxT( "%g" ), intTrackWidth / m_TW_IntTrackWidth_choiceUnit->GetUnitScale() );
m_IntTrackWidthValue->SetValue( msg );
// Display areas:
double scale = m_TW_ExtTrackWidth_choiceUnit->GetUnitScale();
double ext_area = thickness * extTrackWidth;
msg.Printf( wxT( "%g" ), ext_area / (scale * scale) );
m_ExtTrackAreaValue->SetValue( msg );
wxString strunit = m_TW_ExtTrackWidth_choiceUnit->GetUnitName();
msg = strunit + wxT( " x " ) + strunit;
m_ExtTrackAreaUnitLabel->SetLabel( msg );
scale = m_TW_IntTrackWidth_choiceUnit->GetUnitScale();
double int_area = thickness * intTrackWidth;
msg.Printf( wxT( "%g" ), int_area / (scale * scale) );
m_IntTrackAreaValue->SetValue( msg );
strunit = m_TW_IntTrackWidth_choiceUnit->GetUnitName();
msg = strunit + wxT( " x " ) + strunit;
m_IntTrackAreaUnitLabel->SetLabel( msg );
// Display resistance (assuming using copper ):
double rho = 1.72e-008; // In Ohms*meter
double ext_res = rho / ext_area * track_len;
msg.Printf( wxT( "%g" ), ext_res );
m_ExtTrackResistValue->SetValue( msg );
double int_res = rho / int_area * track_len;
msg.Printf( wxT( "%g" ), int_res );
m_IntTrackResistValue->SetValue( msg );
// Display drop voltage
double ext_drop_volt = ext_res * current;
msg.Printf( wxT( "%g" ), ext_drop_volt );
m_ExtTrackVDropValue->SetValue( msg );
double int_drop_volt = int_res * current;
msg.Printf( wxT( "%g" ), int_drop_volt );
m_IntTrackVDropValue->SetValue( msg );
// Display power loss
double loss = ext_drop_volt * current;
msg.Printf( wxT( "%g" ), loss );
m_ExtTrackLossValue->SetValue( msg );
loss = int_drop_volt * current;
msg.Printf( wxT( "%g" ), loss );
m_IntTrackLossValue->SetValue( msg );
}
/* calculate track width for external or internal layers
*
* Imax = 0.048 * dT^0.44 * A^0.725 for external layer
* Imax = 0.024 * dT^0.44 * A^0.725 for internal layer
* with A = area = aThickness * trackWidth ( in mils )
* and dT = temperature rise in degree C
* Of course we want to know trackWidth
*/
double PCB_CALCULATOR_FRAME::TWCalculate( double aCurrent, double aThickness, double aDeltaT_C,
bool aUseInternalLayer )
{
double scale = 0.048; // We are using normalize units (sizes in meters)
if( aUseInternalLayer )
scale *= 0.024 / 0.048;
// aThickness is given in normalize units (in meters) and we need mil
aThickness /= UNIT_MIL;
/* formula is Imax = scale * dT^0.44 * A^0.725
* or
* log(Imax) = log(scale) + 0.44*log(dT)
* +(0.725*(log(aThickness) + log(trackWidth))
* log(trackWidth) * 0.725 = ln(Imax) - ln(scale) - 0.44*log(dT) - 0.725*log(aThickness)
*/
double dtmp = log( aCurrent ) - log( scale ) - 0.44 * log( aDeltaT_C ) - 0.725 * log( aThickness );
dtmp /= 0.725;
double trackWidth = exp( dtmp );
trackWidth *= UNIT_MIL; // We are using normalize units (sizes in meters) and we have mil
return trackWidth; // in meters
}
void PCB_CALCULATOR_FRAME::TW_Init()
{
int tmp;
wxString msg;
// Read parameters values:
m_Config->Read( KEYWORD_TW_EXTTRACK_WIDTH_UNIT, &tmp, 0 );
m_TW_ExtTrackWidth_choiceUnit->SetSelection( tmp );
m_Config->Read( KEYWORD_TW_INTTRACK_WIDTH_UNIT, &tmp, 0 );
m_TW_IntTrackWidth_choiceUnit->SetSelection( tmp );
m_Config->Read( KEYWORD_TW_TRACK_COPPER_THICKNESS_UNIT, &tmp, 0 );
m_TW_CuThickness_choiceUnit->SetSelection( tmp );
m_Config->Read( KEYWORD_TW_TRACK_LEN_UNIT, &tmp, 0 );
m_TW_CuLength_choiceUnit->SetSelection( tmp );
m_Config->Read( KEYWORD_TW_CURRENT, &msg, wxT( "1.0" ) );
m_TrackCurrentValue->SetValue( msg );
m_Config->Read( KEYWORD_TW_DELTA_TC, &msg, wxT( "10.0" ) );
m_TrackDeltaTValue->SetValue( msg );
m_Config->Read( KEYWORD_TW_TRACK_COPPER_THICKNESS, &msg, wxT( "0.035" ) );
m_TrackThicknessValue->SetValue( msg );
m_Config->Read( KEYWORD_TW_TRACK_LEN, &msg, wxT( "20" ) );
m_TrackLengthValue->SetValue( msg );
// Init formulas text
m_htmlWinFormulas->AppendToPage( _( "
The formula (from IPC 2221) is:" ) );
m_htmlWinFormulas->AppendToPage( _( "
I = K * dT0.44 * (W*H)0.725" ) );
m_htmlWinFormulas->AppendToPage( _( "
Internal traces : K = 0.024" ) );
m_htmlWinFormulas->AppendToPage( _( "
External traces: K = 0.048" ) );
m_htmlWinFormulas->AppendToPage( _( "
where:" ) );
m_htmlWinFormulas->AppendToPage( _( "
I = maximum current in Amps" ) );
m_htmlWinFormulas->AppendToPage( _( "
dT = temperature rise above ambient in deg C" ) );
m_htmlWinFormulas->AppendToPage( _( "
W,H = Width and Thickness in mils" ) );
}