Move E-series resistor selector table out of resistor value

Fixes https://gitlab.com/kicad/code/kicad/-/issues/14627
This commit is contained in:
Steve Bollinger 2023-06-26 23:21:40 +00:00 committed by Jon Evans
parent aa8dbc03a2
commit a318c57d77
21 changed files with 2025 additions and 617 deletions

View File

@ -2,8 +2,7 @@
* This program source code file
* is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 <janvi@veith.net>
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2023 KiCad Developers, see AUTHORS.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
@ -19,369 +18,85 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <array>
#include <algorithm>
#include <limits>
#include <cmath>
#include "eseries.h"
/*
* If BENCHMARK is defined, any 4R E12 calculations will print its execution time to console
* My Hasswell Enthusiast reports 225 mSec what are reproducible within plusminus 2 percent
*/
//#define BENCHMARK
#ifdef BENCHMARK
#include <profile.h>
#endif
// Return a string from aValue (aValue is expected in ohms)
// If aValue < 1000 the returned string is aValue with unit = R
// If aValue >= 1000 the returned string is aValue/1000 with unit = K
// with notation similar to 2K2
// If aValue >= 1e6 the returned string is aValue/1e6 with unit = M
// with notation = 1M
static std::string strValue( double aValue )
namespace ESERIES
{
std::string result;
if( aValue < 1000.0 )
const std::vector<uint16_t> ESERIES_VALUES::s_e24table = {
100, 110, 120, 130, 150, 160, 180, 200, 220, 240, 270, 300,
330, 360, 390, 430, 470, 510, 560, 620, 680, 750, 820, 910
};
const std::vector<uint16_t> ESERIES_VALUES::s_e192table = {
100, 101, 102, 104, 105, 106, 107, 109, 110, 111, 113, 114, 115, 117, 118, 120, 121, 123,
124, 126, 127, 129, 130, 132, 133, 135, 137, 138, 140, 142, 143, 145, 147, 149, 150, 152,
154, 156, 158, 160, 162, 164, 165, 167, 169, 172, 174, 176, 178, 180, 182, 184, 187, 189,
191, 193, 196, 198, 200, 203, 205, 208, 210, 213, 215, 218, 221, 223, 226, 229, 232, 234,
237, 240, 243, 246, 249, 252, 255, 258, 261, 264, 267, 271, 274, 277, 280, 284, 287, 291,
294, 298, 301, 305, 309, 312, 316, 320, 324, 328, 332, 336, 340, 344, 348, 352, 357, 361,
365, 370, 374, 379, 383, 388, 392, 397, 402, 407, 412, 417, 422, 427, 432, 437, 442, 448,
453, 459, 464, 470, 475, 481, 487, 493, 499, 505, 511, 517, 523, 530, 536, 542, 549, 556,
562, 569, 576, 583, 590, 597, 604, 612, 619, 626, 634, 642, 649, 657, 665, 673, 681, 690,
698, 706, 715, 723, 732, 741, 750, 759, 768, 777, 787, 796, 806, 816, 825, 835, 845, 856,
866, 876, 887, 898, 909, 920, 931, 942, 953, 965, 976, 988
};
ESERIES_VALUES::ESERIES_VALUES( int aESeries )
{
const std::vector<uint16_t>* baseSeries = &s_e24table;
unsigned int baseSeriesSkipValue = 24;
if( ESERIES::E1 == aESeries || ESERIES::E3 == aESeries || ESERIES::E6 == aESeries
|| ESERIES::E12 == aESeries || ESERIES::E24 == aESeries )
{
result = std::to_string( static_cast<int>( aValue ) );
result += 'R';
// The below table depends on the values and order of entries
// in the E1,E3, etc. enum in eseries.h
const unsigned int skipTableE124[] = { 24, 8, 4, 2, 1 };
baseSeries = &ESERIES_VALUES::s_e24table;
baseSeriesSkipValue = skipTableE124[aESeries];
}
else
else if( ESERIES::E48 == aESeries || ESERIES::E96 == aESeries || ESERIES::E192 == aESeries )
{
double div = 1e3;
char unit = 'K';
baseSeries = &ESERIES_VALUES::s_e192table;
if( aValue >= 1e6 )
{
div = 1e6;
unit = 'M';
}
aValue /= div;
int integer = static_cast<int>( aValue );
result = std::to_string(integer);
result += unit;
// Add mantissa: 1 digit, suitable for series up to E24
double mantissa = aValue - integer;
if( mantissa > 0 )
result += std::to_string( static_cast<int>( (mantissa*10)+0.5 ) );
// The below calculation depends on the values and order of entries
// in the E1,E3, etc. enum in eseries.h
baseSeriesSkipValue = 1 << ( ESERIES::E192 - aESeries );
}
return result;
}
unsigned int decadeBaseLen = baseSeries->size();
reserve( decadeBaseLen / baseSeriesSkipValue );
E_SERIES::E_SERIES()
{
// Build the list of available resistor values in each En serie
double listValuesE1[] = { E1_VALUES };
double listValuesE3[] = { E3_VALUES };
double listValuesE6[] = { E6_VALUES };
double listValuesE12[] = { E12_VALUES };
double listValuesE24[] = { E24_VALUES };
// buildSeriesData must be called in the order of En series, because
// the list of series is expected indexed by En for the serie En
buildSeriesData( listValuesE1 );
buildSeriesData( listValuesE3 );
buildSeriesData( listValuesE6 );
buildSeriesData( listValuesE12 );
int count = buildSeriesData( listValuesE24 );
// Reserve a buffer for intermediate calculations:
// the buffer size is 2*count*count to store all combinaisons of 2 values
// there are 2*count*count = 29282 combinations for E24
int bufsize = 2*count*count;
m_combined_table.reserve( bufsize );
// Store predefined R_DATA items.
for( int ii = 0; ii < bufsize; ii++ )
m_combined_table.emplace_back( "", 0.0 );
}
int E_SERIES::buildSeriesData( const double aList[] )
{
double curr_decade = FIRST_VALUE;
int count = 0;
std::vector<R_DATA> curr_list;
for( ; ; )
for( unsigned int idx = 0; idx < decadeBaseLen; idx += baseSeriesSkipValue )
{
double curr_r = LAST_VALUE;
for( int ii = 0; ; ii++ )
{
if( aList[ii] == 0.0 ) // End of list
break;
curr_r = curr_decade * aList[ii];
curr_list.emplace_back( strValue( curr_r ), curr_r );
count++;
if( curr_r >= LAST_VALUE )
break;
}
if( curr_r >= LAST_VALUE )
break;
curr_decade *= 10;
emplace_back( ( *baseSeries )[idx] );
}
m_tables.push_back( std::move( curr_list ) );
return count;
shrink_to_fit();
}
void E_SERIES::Exclude( double aValue )
ESERIES_IN_DECADE::ESERIES_IN_DECADE( int aESeries, int aDecadeExponent )
{
if( aValue != 0.0 ) // if there is a value to exclude other than a wire jumper
ESERIES::ESERIES_VALUES seriesValues( aESeries );
uint16_t decadeBase = seriesValues[0];
unsigned int decadeBaseLen = seriesValues.size();
double decadeMultiplier = std::pow( 10, aDecadeExponent );
reserve( decadeBaseLen );
for( const uint16_t seriesValue : seriesValues )
{
for( R_DATA& i : m_tables[m_series] ) // then search it in the selected E-Series table
{
if( i.e_value == aValue ) // if the value to exclude is found
i.e_use = false; // disable its use
}
}
}
void E_SERIES::simple_solution( uint32_t aSize )
{
uint32_t i;
m_results.at( S2R ).e_value = std::numeric_limits<double>::max(); // assume no 2R solution or max deviation
for( i = 0; i < aSize; i++ )
{
if( std::abs( m_combined_table.at( i ).e_value - m_required_value ) < std::abs( m_results.at( S2R ).e_value ) )
{
m_results[S2R].e_value = m_combined_table[ i ].e_value - m_required_value; // save signed deviation in Ohms
m_results[S2R].e_name = m_combined_table[ i ].e_name; // save combination text
m_results[S2R].e_use = true; // this is a possible solution
}
}
}
void E_SERIES::combine4( uint32_t aSize )
{
uint32_t i,j;
double tmp;
m_results[S4R].e_use = false; // disable 4R solution, until
m_results[S4R].e_value = m_results[S3R].e_value; // 4R becomes better than 3R solution
#ifdef BENCHMARK
PROF_TIMER timer; // start timer to count execution time
#endif
for( i = 0; i < aSize; i++ ) // 4R search outer loop
{ // scan valid intermediate 2R solutions
for( j = 0; j < aSize; j++ ) // inner loop combines all with itself
{
tmp = m_combined_table[i].e_value + m_combined_table[j].e_value; // calculate 2R+2R serial
tmp -= m_required_value; // calculate 4R deviation
if( std::abs( tmp ) < std::abs( m_results.at(S4R).e_value ) ) // if new 4R is better
{
m_results[S4R].e_value = tmp; // save amount of benefit
std::string s = "( ";
s.append( m_combined_table[i].e_name ); // mention 1st 2 component
s.append( " ) + ( " ); // in series
s.append( m_combined_table[j].e_name ); // with 2nd 2 components
s.append( " )" );
m_results[S4R].e_name = s; // save the result and
m_results[S4R].e_use = true; // enable for later use
}
tmp = ( m_combined_table[i].e_value * m_combined_table[j].e_value ) /
( m_combined_table[i].e_value + m_combined_table[j].e_value ); // calculate 2R|2R parallel
tmp -= m_required_value; // calculate 4R deviation
if( std::abs( tmp ) < std::abs( m_results[S4R].e_value ) ) // if new 4R is better
{
m_results[S4R].e_value = tmp; // save amount of benefit
std::string s = "( ";
s.append( m_combined_table[i].e_name ); // mention 1st 2 component
s.append( " ) | ( " ); // in parallel
s.append( m_combined_table[j].e_name ); // with 2nd 2 components
s.append( " )" );
m_results[S4R].e_name = s; // save the result
m_results[S4R].e_use = true; // enable later use
}
}
emplace_back( decadeMultiplier * seriesValue / decadeBase );
}
#ifdef BENCHMARK
printf( "Calculation time = %d mS", timer.msecs() );
fflush( 0 );
#endif
shrink_to_fit();
}
void E_SERIES::NewCalc()
{
for( R_DATA& i : m_combined_table )
i.e_use = false; // before any calculation is done, assume that
for( R_DATA& i : m_results )
i.e_use = false; // no combinations and no results are available
for( R_DATA& i : m_tables[m_series])
i.e_use = true; // all selected E-values available
}
uint32_t E_SERIES::combine2()
{
uint32_t combi2R = 0; // target index counts calculated 2R combinations
std::string s;
for( const R_DATA& i : m_tables[m_series] ) // outer loop to sweep selected source lookup table
{
if( i.e_use )
{
for( const R_DATA& j : m_tables[m_series] ) // inner loop to combine values with itself
{
if( j.e_use )
{
m_combined_table[combi2R].e_use = true;
m_combined_table[combi2R].e_value = i.e_value + j.e_value; // calculate 2R serial
s = i.e_name;
s.append( " + " );
m_combined_table[combi2R].e_name = s.append( j.e_name);
combi2R++; // next destination
m_combined_table[combi2R].e_use = true; // calculate 2R parallel
m_combined_table[combi2R].e_value = i.e_value * j.e_value / ( i.e_value + j.e_value );
s = i.e_name;
s.append( " | " );
m_combined_table[combi2R].e_name = s.append( j.e_name );
combi2R++; // next destination
}
}
}
}
return combi2R;
}
void E_SERIES::combine3( uint32_t aSize )
{
uint32_t j = 0;
double tmp = 0; // avoid warning for being uninitialized
std::string s;
m_results[S3R].e_use = false; // disable 3R solution, until 3R
m_results[S3R].e_value = m_results[S2R].e_value; // becomes better than 2R solution
for( const R_DATA& i : m_tables[m_series] ) // 3R Outer loop to selected primary E series table
{
if( i.e_use ) // skip all excluded values
{
for( j = 0; j < aSize; j++ ) // inner loop combines with all 2R intermediate
{ // results R+2R serial combi
tmp = m_combined_table[j].e_value + i.e_value;
tmp -= m_required_value; // calculate deviation
if( std::abs( tmp ) < std::abs( m_results[S3R].e_value ) ) // compare if better
{ // then take it
s = i.e_name; // mention 3rd component
s.append( " + ( " ); // in series
s.append( m_combined_table[j].e_name ); // with 2R combination
s.append( " )" );
m_results[S3R].e_name = s; // save S3R result
m_results[S3R].e_value = tmp; // save amount of benefit
m_results[S3R].e_use = true; // enable later use
}
tmp = i.e_value * m_combined_table[j].e_value /
( i.e_value + m_combined_table[j].e_value ); // calculate R + 2R parallel
tmp -= m_required_value; // calculate deviation
if( std::abs( tmp ) < std::abs( m_results[S3R].e_value ) ) // compare if better
{ // then take it
s = i.e_name; // mention 3rd component
s.append( " | ( " ); // in parallel
s.append( m_combined_table[j].e_name ); // with 2R combination
s.append( " )" );
m_results[S3R].e_name = s;
m_results[S3R].e_value = tmp; // save amount of benefit
m_results[S3R].e_use = true; // enable later use
}
}
}
}
// If there is a 3R result with remaining deviation consider to search a possibly better
// 4R solution
// calculate 4R for small series always
if( m_results[S3R].e_use && tmp )
combine4( aSize );
}
void E_SERIES::Calculate()
{
uint32_t no_of_2Rcombi = 0;
no_of_2Rcombi = combine2(); // combine all 2R combinations for selected E serie
simple_solution( no_of_2Rcombi ); // search for simple 2 component solution
if( m_results[S2R].e_value ) // if simple 2R result is not exact
combine3( no_of_2Rcombi ); // continiue searching for a possibly better solution
strip3();
strip4();
}
void E_SERIES::strip3()
{
std::string s;
if( m_results[S3R].e_use ) // if there is a 3 term result available
{ // what is connected either by two "|" or by 3 plus
s = m_results[S3R].e_name;
if( ( std::count( s.begin(), s.end(), '+' ) == 2 )
|| ( std::count( s.begin(), s.end(), '|' ) == 2 ) )
{ // then strip one pair of braces
s.erase( s.find( "( " ), 2 ); // it is known sure, this is available
s.erase( s.find( " )" ), 2 ); // in any unstripped 3R result term
m_results[S3R].e_name = s; // use stripped result
}
}
}
void E_SERIES::strip4()
{
std::string s;
if( m_results[S4R].e_use ) // if there is a 4 term result available
{ // what are connected either by 3 "+" or by 3 "|"
s = m_results[S4R].e_name;
if( ( std::count( s.begin(), s.end(), '+' ) == 3 )
|| ( std::count( s.begin(), s.end(), '|' ) == 3 ) )
{ // then strip two pair of braces
s.erase( s.find( "( " ), 2 ); // it is known sure, they are available
s.erase( s.find( " )" ), 2 ); // in any unstripped 4R result term
s.erase( s.find( "( " ), 2 );
s.erase( s.find( " )" ), 2 );
m_results[S4R].e_name = s; // use stripped result
}
}
}
} // namespace ESERIES

View File

@ -18,6 +18,8 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <array>
#include <vector>
#include <string>
@ -27,174 +29,149 @@
* E-Values derived from a geometric sequence formula by Charles Renard were already
* accepted and widely used before the ISO recommendation no. 3 has been published.
* For this historical reason, rounding rules of some values are sometimes irregular.
* The current list of values is recorded in IEC 60063:2015.
* Previously it was in IEC publication 63.
* Although all E-Values could be calculated at runtime, we initialize them in a lookup table
* what seems the most easy way to consider any inconvenient irregular rules. Same table is
* also used to lookup non calculable but readable BOM value strings. Supported E-series are:
* also used to lookup non calculable but readable BOM value strings.
*/
// List of normalized values between 1 and 10
// The terminal 0.0 value is a end of list value
// Note also due to calculation time the E24 serie is the biggest usable.
#define E24_VALUES 1.0, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2.0, 2.2, 2.4, 2.7, 3.0,\
3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1, 0.0
// The resistor calculator cannot operate on series larger than E24 due to calculation time
#define E12_VALUES 1.0, 1.2, 1.5, 1.8, 2.2, 2.7, 3.3, 3.9, 4.7, 5.6, 6.8, 8.2, 0.0
// Values are stored in the 100-999 decade. This is so that all values are integers
// and can be stored precisely. If the values are real values with a fraction part then
// the fractional part is typically imprecisely stores. In the 100 decade the values
// can be stored as precise values in integers. If used in floating point types
// they are as precise as before
#define E6_VALUES 1.0, 1.5, 2.2, 3.3, 4.7, 6.8, 0.0
// If you want the values in the first decade then simply divide every value in
// the list by the first value in the list.
#define E3_VALUES 1.0, 2.2, 4.7, 0.0
// E96 is a proper subset of E192. It is every 2nd value. E48 is every 4th value of E192.
// That is, all the series with 3 significant figures are subsets of the same series, E192.
#define E1_VALUES 1.0, 0.0
// E24 is not a subset of E48 or E192. All series below E48 have only 2 significant figures
// and are differently from the series with 3 significant figures.
// E12, E6 and E3 are proper subsets of E24. Specifically they are evenly spaced
// values selected from E24. E12 is every 2nd value, E6 every 4th, E3 every 8th.
// First value of resistor in ohm
#define FIRST_VALUE 10
// E1 is not in the IEC standard.
// last value of resistor in ohm
#define LAST_VALUE 1e6
// The value 0 is not present in any series. It does not fit in any decade.
// It must be special cased in any calcuation or method of selection of
// values.
/**
* List of handled E series values:
* Note: series bigger than E24 have no interest because
* - probably the user will fing the needed value inside these series
* - the calculation time can be *very high* for series > E24
*/
enum { E1, E3, E6, E12, E24 };
/**
* This calculator suggests solutions for 2R, 3R and 4R replacement combinations
*/
enum { S2R, S3R, S4R };
// R_DATA handles a resistor: string value, value and allowed to use
struct R_DATA
namespace ESERIES
{
R_DATA() :
e_use( true ),
e_value( 0.0 )
{}
R_DATA( const std::string& aName, double aValue )
{
e_use = true;
e_name = aName;
e_value = aValue;
}
bool e_use;
std::string e_name;
double e_value;
enum
{
E1,
E3,
E6,
E12,
E24,
E48,
E96,
E192
};
class E_SERIES
/* \brief Creates a vector of integers of E series values
*
*/
class ESERIES_VALUES : public std::vector<uint16_t>
{
public:
E_SERIES();
/**
* If any value of the selected E-series not available, it can be entered as an exclude value.
*
* @param aValue is the value to exclude from calculation
* Values to exclude are set to false in the selected E-series source lookup table
*/
void Exclude( double aValue );
/**
* initialize next calculation and erase results from previous calculation
*/
void NewCalc();
/**
* called on calculate button to execute all the 2R, 3R and 4R calculations
*/
void Calculate();
/**
* Interface for CheckBox, RadioButton, RequriedResistor and calculated Results
*/
void SetSeries( uint32_t aSeries ) { m_series = aSeries; }
void SetRequiredValue( double aValue ) { m_required_value = aValue; }
// Accessor:
const std::array<R_DATA,S4R+1>& GetResults() { return m_results; }
ESERIES_VALUES( int aESeries );
private:
/**
* Add values from aList to m_tables. Covers all decades between FIRST_VALUE and LAST_VALUE.
* @return the count of items added to m_tables.
*/
int buildSeriesData( const double aList[] );
/**
* Build all 2R combinations from the selected E-series values
*
* Pre-calculated value combinations are saved in intermediate look up table m_combined_table
* @return is the number of found combinations what also depends from exclude values
*/
uint32_t combine2();
/**
* Search for closest two component solution
*
* @param aSize is the number of valid 2R combinations in m_combined_table on where to search
* The 2R result with smallest deviation will be saved in results
*/
void simple_solution( uint32_t aSize );
/**
* Check if there is a better 3 R solution than previous one using only two components.
*
* @param aSize gives the number of available combinations to be checked inside
* m_combined_table. Therefore m_combined_table is combined with the primary
* E-series look up table. The 3R result with smallest deviation will be saved
* in results if better than 2R
*/
void combine3( uint32_t aSize );
/**
* Check if there is a better four component solution.
*
* @param aSsize gives the number of 2R combinations to be checked inside m_combined_table
* Occupied calculation time depends from number of available E-series values with the power
* of 4 why execution for E12 is conditional with 4R check box for the case the previously
* found 3R solution is already exact
*/
void combine4( uint32_t aSize );
/*
* Strip redundant braces from three component result
*
* Example: R1+(R2+R3) become R1+R2+R3
* and R1|(R2|R3) become R1|R2|R3
* while R1+(R2|R3) or (R1+R2)|R3) remains untouched
*/
void strip3();
/*
* Strip redundant braces from four component result
*
* Example: (R1+R2)+(R3+R4) become R1+R2+R3+R4
* and (R1|R2)|(R2|R3) become R1|R2|R3|R4
* while (R1+R2)|(R3+R4) remains untouched
*/
void strip4();
private:
std::vector<std::vector<R_DATA>> m_tables;
/* Note: intermediate calculations use m_combined_table
* if the biggest list is En, reserved array size should be 2*En*En of std::vector primary list.
* 2 component combinations including redundant swappable terms are for the moment
* ( using values between 10 ohms and 1Mohm )
* 72 combinations for E1
* 512 combinations for E3
* 1922 combinations for E6
* 7442 combinations for E12
* 29282 combinations for E24
*/
std::vector<R_DATA> m_combined_table; // intermediate 2R combinations
std::array<R_DATA, S4R+1> m_results; // 2R, 3R and 4R results
uint32_t m_series = E6; // Radio Button State
double m_required_value = 0.0; // required Resistor
static const std::vector<uint16_t> s_e24table;
static const std::vector<uint16_t> s_e192table;
};
/*! \brief Creates a vector of integers of the E1 series values.
*
*/
class E1_VALUES : public ESERIES_VALUES
{
public:
E1_VALUES() : ESERIES_VALUES( E1 ) {}
};
/*! \brief Creates a vector of integers of the E3 series values.
*
*/
class E3_VALUES : public ESERIES_VALUES
{
public:
E3_VALUES() : ESERIES_VALUES( E3 ) {}
};
/*! \brief Creates a vector of integers of the E6 series values.
*
*/
class E6_VALUES : public ESERIES_VALUES
{
public:
E6_VALUES() : ESERIES_VALUES( E6 ) {}
};
/*! \brief Creates a vector of integers of the E12 series values.
*
*/
class E12_VALUES : public ESERIES_VALUES
{
public:
E12_VALUES() : ESERIES_VALUES( E12 ) {}
};
/*! \brief Creates a vector of integers of the E24 series values.
*
*/
class E24_VALUES : public ESERIES_VALUES
{
public:
E24_VALUES() : ESERIES_VALUES( E24 ) {}
};
/*! \brief Creates a vector of integers of the E48 series values.
*
*/
class E48_VALUES : public ESERIES_VALUES
{
public:
E48_VALUES() : ESERIES_VALUES( E48 ) {}
};
/*! \brief Creates a vector of integers of the E96 series values.
*
*/
class E96_VALUES : public ESERIES_VALUES
{
public:
E96_VALUES() : ESERIES_VALUES( E96 ) {}
};
/*! \brief Creates a vector of integers of the E192 series values.
*
*/
class E192_VALUES : public ESERIES_VALUES
{
public:
E192_VALUES() : ESERIES_VALUES( E192 ) {}
};
/*! \brief Creates a vector of doubles of the values in the requested eseries and decade.
*
* The eSeries to select is a specified using the enumeration values above.
* The decade is specified as an integer exponent to the base 10.
* To receive vales between 100 and 1000 specify 2 as the exponent as each value will
* be normalized to betwen 1.0 and 10.0 and then multiplied by 10^2.
*/
class ESERIES_IN_DECADE : public std::vector<double>
{
public:
ESERIES_IN_DECADE( int eSeries, int decadeExponent );
};
} // namespace ESERIES

View File

@ -22,6 +22,8 @@ set( PCB_CALCULATOR_SRCS
calculator_panels/panel_cable_size_base.cpp
calculator_panels/panel_color_code.cpp
calculator_panels/panel_color_code_base.cpp
calculator_panels/panel_eseries_display.cpp
calculator_panels/panel_eseries_display_base.cpp
calculator_panels/panel_galvanic_corrosion.cpp
calculator_panels/panel_galvanic_corrosion_base.cpp
calculator_panels/panel_electrical_spacing.cpp
@ -31,8 +33,8 @@ set( PCB_CALCULATOR_SRCS
calculator_panels/panel_electrical_spacing_iec60664_base.cpp
calculator_panels/panel_electrical_spacing_ipc2221.cpp
calculator_panels/panel_electrical_spacing_ipc2221_base.cpp
calculator_panels/panel_eseries.cpp
calculator_panels/panel_eseries_base.cpp
calculator_panels/panel_r_calculator.cpp
calculator_panels/panel_r_calculator_base.cpp
calculator_panels/panel_fusing_current.cpp
calculator_panels/panel_fusing_current_base.cpp
calculator_panels/panel_regulator.cpp
@ -60,6 +62,7 @@ set( PCB_CALCULATOR_SRCS
dialogs/dialog_regulator_form_base.cpp
dialogs/dialog_regulator_form.cpp
pcb_calculator_utils.cpp
resistor_substitution_utils.cpp
../common/env_vars.cpp # needed on MSW to avoid a link issue (a symbol not found)
)
@ -223,7 +226,8 @@ endfunction()
md_doc2h( ${CMAKE_CURRENT_SOURCE_DIR}/attenuators/pi_formula )
md_doc2h( ${CMAKE_CURRENT_SOURCE_DIR}/attenuators/tee_formula )
md_doc2h( ${CMAKE_CURRENT_SOURCE_DIR}/tracks_width_versus_current_formula )
md_doc2h( ${CMAKE_CURRENT_SOURCE_DIR}/eseries_help )
md_doc2h( ${CMAKE_CURRENT_SOURCE_DIR}/eseries_display_help )
md_doc2h( ${CMAKE_CURRENT_SOURCE_DIR}/r_calculator_help )
md_doc2h( ${CMAKE_CURRENT_SOURCE_DIR}/fusing_current_help )
md_doc2h( ${CMAKE_CURRENT_SOURCE_DIR}/galvanic_corrosion_help )
md_doc2h( ${CMAKE_CURRENT_SOURCE_DIR}/iec60664_help )
@ -234,7 +238,8 @@ set( DOCS_LIST
${CMAKE_CURRENT_SOURCE_DIR}/attenuators/bridget_tee_formula.h
${CMAKE_CURRENT_SOURCE_DIR}/attenuators/splitter_formula.h
${CMAKE_CURRENT_SOURCE_DIR}/tracks_width_versus_current_formula.h
${CMAKE_CURRENT_SOURCE_DIR}/eseries_help.h
${CMAKE_CURRENT_SOURCE_DIR}/eseries_display_help.h
${CMAKE_CURRENT_SOURCE_DIR}/r_calculator_help.h
${CMAKE_CURRENT_SOURCE_DIR}/fusing_current_help.h
${CMAKE_CURRENT_SOURCE_DIR}/galvanic_corrosion_help.h
${CMAKE_CURRENT_SOURCE_DIR}/iec60664_help.h

View File

@ -0,0 +1,443 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2023 Kicad Developers, see AUTHORS.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 3
* 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, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include <calculator_panels/panel_eseries_display.h>
#include <pcb_calculator_settings.h>
#include <string_utils.h>
#include <wx/msgdlg.h>
#include <wx/settings.h> // for IsDark
#include <eseries.h>
#include <i18n_utility.h> // For _HKI definition in eseries_display_help.h
wxString eseries_display_help =
#include "eseries_display_help.h"
PANEL_ESERIES_DISPLAY::PANEL_ESERIES_DISPLAY( wxWindow * parent, wxWindowID id,
const wxPoint& pos, const wxSize& size,
long style, const wxString& name ) :
PANEL_ESERIES_DISPLAY_BASE( parent, id, pos, size, style, name )
{
// show markdown stuff in lower help panel
wxString msg;
ConvertMarkdown2Html( wxGetTranslation( eseries_display_help ), msg );
m_panelESeriesHelp->SetPage( msg );
// Calculate E1,E3,E6,E12,E24,E48,E96 column background colours
// Get appearances. Note that I believe these panels will not be
// re-constructed on a mode change so this only works if you open
// the window *after* you set your dark mode.
const wxSystemAppearance appearances = wxSystemSettings::GetAppearance();
const bool selectDark = appearances.IsDark();
recalculateColumnColours( selectDark );
// Lay out the smaller tree containing E1,E3,E6, and E12
populateE112Tree();
// Set colours of smaller tree.
recolourE112Tree();
// Lay out the larger tree containing E24, R48 and E96
populateE2496Tree();
// Set colours of larger tree.
recolourE2496Tree();
// Needed on wxWidgets 3.0 to ensure sizers are correctly set
GetSizer()->SetSizeHints( this );
// Make the grid lines disappear into the window background
// making the value boxes appear to be separated from each other.
wxColour gridLineColour = parent->GetBackgroundColour();
m_GridEseries112->SetGridLineColour( gridLineColour );
m_GridEseries112->EnableGridLines( true );
m_GridEseries112->SetColLabelSize( wxGRID_AUTOSIZE );
m_GridEseries112->AutoSize();
m_GridEseries2496->SetGridLineColour( gridLineColour );
m_GridEseries2496->EnableGridLines( true );
m_GridEseries2496->SetColLabelSize( wxGRID_AUTOSIZE );
m_GridEseries2496->AutoSize();
Layout();
}
PANEL_ESERIES_DISPLAY::~PANEL_ESERIES_DISPLAY()
{
}
void PANEL_ESERIES_DISPLAY::ThemeChanged()
{
// Calculate E1,E3,E6,E12,E24,E48,E96 column background colours
// Get appearances.
const wxSystemAppearance appearances = wxSystemSettings::GetAppearance();
const bool selectDark = appearances.IsDark();
recalculateColumnColours( selectDark );
// Set colours of smaller tree.
recolourE112Tree();
// Set colours of larger tree.
recolourE2496Tree();
}
void PANEL_ESERIES_DISPLAY::SaveSettings( PCB_CALCULATOR_SETTINGS* aCfg )
{
}
void PANEL_ESERIES_DISPLAY::LoadSettings( PCB_CALCULATOR_SETTINGS* aCfg )
{
}
void PANEL_ESERIES_DISPLAY::recalculateColumnColours( bool aDarkModeOn )
{
// if in a dark mode then darken colors significantly so that
// the white numerals on top stand out better
const int colourAdjust = aDarkModeOn ? s_darkAdjustValue : 100;
m_colourE1Column = wxColour( s_cE1BGR ).ChangeLightness( colourAdjust );
const wxColour colourE3Column( wxColour( s_cE3BGR ).ChangeLightness( colourAdjust ) );
const wxColour colourE6Column( wxColour( s_cE6BGR ).ChangeLightness( colourAdjust ) );
const wxColour colourE12Column( wxColour( s_cE12BGR ).ChangeLightness( colourAdjust ) );
const wxColour colourE24Column( wxColour( s_cE24BGR ).ChangeLightness( colourAdjust ) );
const wxColour colourE48Column( wxColour( s_cE48BGR ).ChangeLightness( colourAdjust ) );
const wxColour colourE96Column( wxColour( s_cE96BGR ).ChangeLightness( colourAdjust ) );
m_colourE3Pair[0] = colourE3Column;
m_colourE3Pair[1] = colourE3Column.ChangeLightness( s_altAdjustValue );
m_colourE6Pair[0] = colourE6Column;
m_colourE6Pair[1] = colourE6Column.ChangeLightness( s_altAdjustValue );
m_colourE12Pair[0] = colourE12Column;
m_colourE12Pair[1] = colourE12Column.ChangeLightness( s_altAdjustValue );
m_colourE24Pair[0] = colourE24Column;
m_colourE24Pair[1] = colourE24Column.ChangeLightness( s_altAdjustValue );
m_colourE48Pair[0] = colourE48Column;
m_colourE48Pair[1] = colourE48Column.ChangeLightness( s_altAdjustValue );
m_colourE96Pair[0] = colourE96Column;
m_colourE96Pair[1] = colourE96Column.ChangeLightness( s_altAdjustValue );
s_colourMatching = m_GridEseries2496->GetLabelBackgroundColour();
}
void PANEL_ESERIES_DISPLAY::populateE112Tree()
{
// Lay out E1, R3, E6, E12 tree.
ESERIES::ESERIES_VALUES eSeries12 = ESERIES::ESERIES_VALUES( ESERIES::E12 );
int row = 0;
wxString value;
m_GridEseries112->BeginBatch();
m_GridEseries112->DeleteCols( 0, m_GridEseries112->GetNumberCols() );
m_GridEseries112->DeleteRows( 0, m_GridEseries112->GetNumberRows() );
m_GridEseries112->AppendCols( 4 ); // E1, E3, E6, E12
m_GridEseries112->AppendRows( 12 ); // Sufficient rows for all of E12
m_GridEseries112->SetColLabelValue( 0, "E1" );
m_GridEseries112->SetColLabelValue( 1, "E3" );
m_GridEseries112->SetColLabelValue( 2, "E6" );
m_GridEseries112->SetColLabelValue( 3, "E12" );
value = wxString( "" ) << eSeries12[0];
m_GridEseries112->SetCellValue( 0, 0, value );
m_GridEseries112->SetCellSize( 0, 0, 12, 1 );
for( const uint16_t& seriesEntry : eSeries12 )
{
value = wxString( "" ) << seriesEntry;
if( 0 == row % 4 )
{
// Set E3 column
m_GridEseries112->SetCellValue( row, 1, value );
m_GridEseries112->SetCellSize( row, 1, 4, 1 );
}
if( 0 == row % 2 )
{
// Set E6 column
m_GridEseries112->SetCellValue( row, 2, value );
m_GridEseries112->SetCellSize( row, 2, 2, 1 );
}
// Set E12 column
m_GridEseries112->SetCellValue( row, 3, value );
++row;
}
for( int i = 0; i < 3; ++i )
{
// Resize data columns to fit data and set as minimum size
m_GridEseries112->AutoSizeColumn( i, true );
}
m_GridEseries112->EndBatch();
}
void PANEL_ESERIES_DISPLAY::populateE2496Tree()
{
// Lay out E24, E48, E96 tree.
ESERIES::ESERIES_VALUES eSeries24 = ESERIES::ESERIES_VALUES( ESERIES::E24 );
ESERIES::ESERIES_VALUES eSeries96 = ESERIES::ESERIES_VALUES( ESERIES::E96 );
// This is the number of times the table is wrapped around into another
// column. Like in a newspaper. The term column is not used since
// the grid already has columns. The 96 in the second calculation
// is the number of entries in the largest series displayed (E96)
constexpr unsigned int numStripes = 4;
constexpr unsigned int stripeHeight = 96 / numStripes;
int idx = 0;
int stripe = 0;
wxString value;
m_GridEseries2496->BeginBatch();
m_GridEseries2496->DeleteCols( 0, m_GridEseries2496->GetNumberCols() );
m_GridEseries2496->DeleteRows( 0, m_GridEseries2496->GetNumberRows() );
// Column headers are E24, E48, E96, -
// repeated numStripes times over. And the last - is omitted.
m_GridEseries2496->AppendCols( numStripes * 4 - 1 );
m_GridEseries2496->AppendRows( stripeHeight );
m_GridEseries2496->SetColLabelValue( 0 + 0, "E24" );
m_GridEseries2496->SetColLabelValue( 1 + 0, "E48" );
m_GridEseries2496->SetColLabelValue( 2 + 0, "E96" );
m_GridEseries2496->SetColLabelValue( 3 + 0, "-" );
m_GridEseries2496->SetColLabelValue( 0 + 4, "E24" );
m_GridEseries2496->SetColLabelValue( 1 + 4, "E48" );
m_GridEseries2496->SetColLabelValue( 2 + 4, "E96" );
m_GridEseries2496->SetColLabelValue( 3 + 4, "-" );
m_GridEseries2496->SetColLabelValue( 0 + 8, "E24" );
m_GridEseries2496->SetColLabelValue( 1 + 8, "E48" );
m_GridEseries2496->SetColLabelValue( 2 + 8, "E96" );
m_GridEseries2496->SetColLabelValue( 3 + 8, "-" );
m_GridEseries2496->SetColLabelValue( 0 + 12, "E24" );
m_GridEseries2496->SetColLabelValue( 1 + 12, "E48" );
m_GridEseries2496->SetColLabelValue( 2 + 12, "E96" );
for( const uint16_t& seriesEntry : eSeries24 )
{
value = wxString( "" ) << seriesEntry;
int row = ( idx * 4 ) % stripeHeight;
int colOffset = ( ( idx * 4 ) / stripeHeight ) * 4;
m_GridEseries2496->SetCellValue( row, colOffset, value );
m_GridEseries2496->SetCellSize( row, colOffset, 4, 1 );
++idx;
}
idx = 0;
for( const uint16_t& seriesEntry : eSeries96 )
{
value = wxString( "" ) << seriesEntry;
int row = idx % stripeHeight;
int colOffset = ( idx / stripeHeight ) * 4;
if( 0 == row % 2 )
{
// Set E48 column
m_GridEseries2496->SetCellValue( row, colOffset + 1, value );
m_GridEseries2496->SetCellSize( row, colOffset + 1, 2, 1 );
}
// Set E96 column
m_GridEseries2496->SetCellValue( row, colOffset + 2, value );
++idx;
}
// cause the areas between stripes to appear more empty
// by making them a single cell the height of the stripe
// this causes the horizontal row lines rows to disappear
for( unsigned int stripeGap = 1; stripeGap < numStripes; ++stripeGap )
{
const int stripeColumn = -1 + stripeGap * 4;
m_GridEseries2496->SetCellSize( 0, stripeColumn, stripeHeight, 1 );
}
for( int i = 0; i < numStripes * 4 - 1; ++i )
{
// Resize the column to fit data and set as minimum size
m_GridEseries2496->AutoSizeColumn( i, true );
}
m_GridEseries2496->EndBatch();
}
void PANEL_ESERIES_DISPLAY::recolourE112Tree()
{
const unsigned int numRows = m_GridEseries112->GetNumberRows();
m_GridEseries112->BeginBatch();
// Colouring E1 is easy. There is only one item.
m_GridEseries112->SetCellBackgroundColour( 0, 0, m_colourE1Column );
bool alternateColour = false;
int cellWidth = 0, cellHeight = 0;
// Colour E3 column
for( int row = 0; row < numRows; row += cellHeight )
{
m_GridEseries112->SetCellBackgroundColour( row, 1, m_colourE3Pair[alternateColour] );
// get height for iteration above
m_GridEseries112->GetCellSize( row, 1, &cellHeight, &cellWidth );
alternateColour = !alternateColour;
if( cellHeight < 1 )
cellHeight = 1; // Do not loop forever, always make progress.
}
// Colour E6 column
alternateColour = false;
for( int row = 0; row < numRows; row += cellHeight )
{
m_GridEseries112->SetCellBackgroundColour( row, 2, m_colourE6Pair[alternateColour] );
// get height for iteration above
m_GridEseries112->GetCellSize( row, 2, &cellHeight, &cellWidth );
alternateColour = !alternateColour;
if( cellHeight < 1 )
cellHeight = 1; // Do not loop forever, always make progress.
}
// Colour E12 column
alternateColour = false;
for( int row = 0; row < numRows; row += cellHeight )
{
m_GridEseries112->SetCellBackgroundColour( row, 3, m_colourE12Pair[alternateColour] );
// get height for iteration above
m_GridEseries112->GetCellSize( row, 3, &cellHeight, &cellWidth );
alternateColour = !alternateColour;
if( cellHeight < 1 )
cellHeight = 1; // Do not loop forever, always make progress.
}
m_GridEseries112->EndBatch();
}
void PANEL_ESERIES_DISPLAY::recolourE2496Tree()
{
const unsigned int numRows = m_GridEseries2496->GetNumberRows();
constexpr unsigned int numStripes = 4;
constexpr unsigned int stripeHeight = 96 / numStripes;
m_GridEseries2496->BeginBatch();
bool alternateColour = false;
int cellWidth = 0, cellHeight = 0;
// Colour E24 columns
for( int row = 0; row < numRows; row += cellHeight )
{
for( int stripe = 0; stripe < numStripes; ++stripe )
{
m_GridEseries2496->SetCellBackgroundColour( row, 0 + 4 * stripe,
m_colourE24Pair[alternateColour] );
}
// get height for iteration above
m_GridEseries2496->GetCellSize( row, 0, &cellHeight, &cellWidth );
alternateColour = !alternateColour;
if( cellHeight < 1 )
cellHeight = 1; // Do not loop forever, always make progress.
}
// Colour E48 columns
alternateColour = false;
for( int row = 0; row < numRows; row += cellHeight )
{
for( int stripe = 0; stripe < numStripes; ++stripe )
{
m_GridEseries2496->SetCellBackgroundColour( row, 1 + 4 * stripe,
m_colourE48Pair[alternateColour] );
}
// get height for iteration above
m_GridEseries2496->GetCellSize( row, 1, &cellHeight, &cellWidth );
alternateColour = !alternateColour;
if( cellHeight < 1 )
cellHeight = 1; // Do not loop forever, always make progress.
}
// Colour E96 columns
alternateColour = false;
for( int row = 0; row < numRows; row += cellHeight )
{
for( int stripe = 0; stripe < numStripes; ++stripe )
{
m_GridEseries2496->SetCellBackgroundColour( row, 2 + 4 * stripe,
m_colourE96Pair[alternateColour] );
}
// get height for iteration above
m_GridEseries2496->GetCellSize( row, 2, &cellHeight, &cellWidth );
alternateColour = !alternateColour;
if( cellHeight < 1 )
cellHeight = 1; // Do not loop forever, always make progress.
}
// recolour empty areas between columns to match label background
// to make them less eye-catching
for( unsigned int stripeGap = 1; stripeGap < numStripes; ++stripeGap )
{
const int stripeColumn = -1 + stripeGap * 4;
m_GridEseries2496->SetCellBackgroundColour( 0, stripeColumn, s_colourMatching );
}
m_GridEseries2496->EndBatch();
}

View File

@ -0,0 +1,156 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 1992-2022 Kicad Developers, see AUTHORS.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 3
* 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef PANEL_ESERIES_DISPLAY_H
#define PANEL_ESERIES_DISPLAY_H
#include <eseries.h>
#include "panel_eseries_display_base.h"
class PCB_CALCULATOR_SETTINGS;
class PANEL_ESERIES_DISPLAY : public PANEL_ESERIES_DISPLAY_BASE
{
public:
PANEL_ESERIES_DISPLAY( wxWindow* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = wxTAB_TRAVERSAL,
const wxString& name = wxEmptyString );
~PANEL_ESERIES_DISPLAY();
// Methods from CALCULATOR_PANEL that must be overridden
void LoadSettings( PCB_CALCULATOR_SETTINGS* aCfg ) override;
void SaveSettings( PCB_CALCULATOR_SETTINGS* aCfg ) override;
void ThemeChanged() override;
private:
/*! \brief Recalculate colours used to highlight the E-series columns.
*
* Each colour is a pair of colours which are used in alternate rows
* to make the table easier to follow.
*/
void recalculateColumnColours( bool aDarkModeOn );
/*! \brief Fill small E-series tree with values.
*
* Contains values from E1, E3, E6 and E12 series.
*/
void populateE112Tree();
/*! \brief Fill larger E-series tree with values.
*
* Contains values from E24, E48, E96 series.
*/
void populateE2496Tree();
/*! \brief Colour small E-series tree according to current theme.
*
* Contains values from E1, E3, E6 and E12 series.
*/
void recolourE112Tree();
/*! \brief Colour large E-series tree according to current theme.
*
* Contains values from E24, E48, E96 series.
*/
void recolourE2496Tree();
/*! \brief Adjustment factor to create alternating R-series table entry colours.
*
* This is to make the table easier to read.
* This value is passed to wxColour::ChangeLightness().
*/
constexpr static int s_altAdjustValue = 125;
/*! \brief Adjustment factor to create darker grid cells in dark theme.
*
* Without this the light numbers on the grid backgrounds are difficult to read.
* This value is passed to wxColour::ChangeLightness().
*/
constexpr static int s_darkAdjustValue = 78;
/*! \brief Colour for E1 column in light theme. Passed to wxColour constructor.
*
* HTML honeydew
*/
constexpr static uint32_t s_cE1BGR = 0xf0fff0;
/*! \brief Colour for E3 column in light theme. Passed to wxColour constructor.
*
* HTML palegreen
*/
constexpr static uint32_t s_cE3BGR = 0x98fb98;
/*! \brief Colour for E6 column in light theme. Passed to wxColour constructor.
*
* HTML cornflowerblue
*/
constexpr static uint32_t s_cE6BGR = 0xed9564;
/*! \brief Colour for E12 column in light theme. Passed to wxColour constructor.
*
* HTML plum
*/
constexpr static uint32_t s_cE12BGR = 0xdda0dd;
/*! \brief Colour for E24 column in light theme. Passed to wxColour constructor.
*
* HTML skyblue
*/
constexpr static uint32_t s_cE24BGR = 0xebce87;
/*! \brief Colour for E48 column in light theme. Passed to wxColour constructor.
*
* HTML olivedrab
*/
constexpr static uint32_t s_cE48BGR = 0x23e86b;
/*! \brief Colour for E96 column in light theme. Passed to wxColour constructor.
*
* HTML lightsalmon
*/
constexpr static uint32_t s_cE96BGR = 0x7aa0ff;
/*! \brief Calculated colour for E1 column in current (light,dark) theme. */
wxColour m_colourE1Column;
/*! \brief Calculated colours for E3 column in current (light,dark) theme. */
wxColour m_colourE3Pair[2];
/*! \brief Calculated colours for E6 column in current (light,dark) theme. */
wxColour m_colourE6Pair[2];
/*! \brief Calculated colours for E12 column in current (light,dark) theme. */
wxColour m_colourE12Pair[2];
/*! \brief Calculated colours for E24 column in current (light,dark) theme. */
wxColour m_colourE24Pair[2];
/*! \brief Calculated colours for E48 column in current (light,dark) theme. */
wxColour m_colourE48Pair[2];
/*! \brief Calculated colours for E96 column in current (light,dark) theme. */
wxColour m_colourE96Pair[2];
/*! \brief Calculated matching colour for empty columns. Same as background of labels */
wxColour s_colourMatching;
};
#endif

View File

@ -0,0 +1,98 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-282-g1fa54006)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "panel_eseries_display_base.h"
///////////////////////////////////////////////////////////////////////////
PANEL_ESERIES_DISPLAY_BASE::PANEL_ESERIES_DISPLAY_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : CALCULATOR_PANEL( parent, id, pos, size, style, name )
{
wxBoxSizer* bSizerESeries;
bSizerESeries = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bTablesSizerESeries;
bTablesSizerESeries = new wxBoxSizer( wxHORIZONTAL );
wxStaticBoxSizer* sbLowerSizerEseries2496;
sbLowerSizerEseries2496 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("E24,E48,E96") ), wxVERTICAL );
m_GridEseries2496 = new wxGrid( sbLowerSizerEseries2496->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
// Grid
m_GridEseries2496->CreateGrid( 1, 1 );
m_GridEseries2496->EnableEditing( false );
m_GridEseries2496->EnableGridLines( false );
m_GridEseries2496->EnableDragGridSize( false );
m_GridEseries2496->SetMargins( 0, 0 );
// Columns
m_GridEseries2496->EnableDragColMove( false );
m_GridEseries2496->EnableDragColSize( false );
m_GridEseries2496->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_GridEseries2496->EnableDragRowSize( false );
m_GridEseries2496->SetRowLabelSize( 0 );
m_GridEseries2496->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Label Appearance
// Cell Defaults
m_GridEseries2496->SetDefaultCellAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
sbLowerSizerEseries2496->Add( m_GridEseries2496, 0, wxALL, 5 );
bTablesSizerESeries->Add( sbLowerSizerEseries2496, 0, 0, 5 );
wxStaticBoxSizer* sbLowerSizerEseries112;
sbLowerSizerEseries112 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("E1,E3,E6,E12") ), wxVERTICAL );
m_GridEseries112 = new wxGrid( sbLowerSizerEseries112->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
// Grid
m_GridEseries112->CreateGrid( 1, 1 );
m_GridEseries112->EnableEditing( false );
m_GridEseries112->EnableGridLines( false );
m_GridEseries112->EnableDragGridSize( false );
m_GridEseries112->SetMargins( 0, 0 );
// Columns
m_GridEseries112->EnableDragColMove( false );
m_GridEseries112->EnableDragColSize( false );
m_GridEseries112->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_GridEseries112->EnableDragRowSize( false );
m_GridEseries112->SetRowLabelSize( 0 );
m_GridEseries112->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Label Appearance
// Cell Defaults
m_GridEseries112->SetDefaultCellAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
sbLowerSizerEseries112->Add( m_GridEseries112, 0, wxALL, 5 );
bTablesSizerESeries->Add( sbLowerSizerEseries112, 1, 0, 5 );
bSizerESeries->Add( bTablesSizerESeries, 0, wxTOP, 5 );
m_panelESeriesHelp = new HTML_WINDOW( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO );
m_panelESeriesHelp->SetMinSize( wxSize( -1,100 ) );
bSizerESeries->Add( m_panelESeriesHelp, 1, wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND, 5 );
this->SetSizer( bSizerESeries );
this->Layout();
bSizerESeries->Fit( this );
}
PANEL_ESERIES_DISPLAY_BASE::~PANEL_ESERIES_DISPLAY_BASE()
{
}

View File

@ -0,0 +1,340 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="16" />
<object class="Project" expanded="1">
<property name="class_decoration"></property>
<property name="code_generation">C++</property>
<property name="disconnect_events">1</property>
<property name="disconnect_mode">source_name</property>
<property name="disconnect_php_events">0</property>
<property name="disconnect_python_events">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">panel_eseries_display_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="name">panel_eseries_display_base</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_array_enum">0</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Panel" expanded="1">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">PANEL_ESERIES_DISPLAY_BASE</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="subclass">CALCULATOR_PANEL; calculator_panels/calculator_panel.h; </property>
<property name="tooltip"></property>
<property name="two_step_creation">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizerESeries</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxTOP</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bTablesSizerESeries</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag"></property>
<property name="proportion">0</property>
<object class="wxStaticBoxSizer" expanded="1">
<property name="id">wxID_ANY</property>
<property name="label">E24,E48,E96</property>
<property name="minimum_size"></property>
<property name="name">sbLowerSizerEseries2496</property>
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxGrid" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="autosize_cols">0</property>
<property name="autosize_rows">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="cell_bg"></property>
<property name="cell_font"></property>
<property name="cell_horiz_alignment">wxALIGN_CENTER</property>
<property name="cell_text"></property>
<property name="cell_vert_alignment">wxALIGN_CENTER</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="col_label_size"></property>
<property name="col_label_values"></property>
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
<property name="cols">1</property>
<property name="column_sizes"></property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="drag_col_move">0</property>
<property name="drag_col_size">0</property>
<property name="drag_grid_size">0</property>
<property name="drag_row_size">0</property>
<property name="editing">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="grid_line_color"></property>
<property name="grid_lines">0</property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label_bg"></property>
<property name="label_font"></property>
<property name="label_text"></property>
<property name="margin_height">0</property>
<property name="margin_width">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_GridEseries2496</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="row_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="row_label_size">0</property>
<property name="row_label_values"></property>
<property name="row_label_vert_alignment">wxALIGN_CENTER</property>
<property name="row_sizes"></property>
<property name="rows">1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag"></property>
<property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="0">
<property name="id">wxID_ANY</property>
<property name="label">E1,E3,E6,E12</property>
<property name="minimum_size"></property>
<property name="name">sbLowerSizerEseries112</property>
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxGrid" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="autosize_cols">0</property>
<property name="autosize_rows">0</property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="cell_bg"></property>
<property name="cell_font"></property>
<property name="cell_horiz_alignment">wxALIGN_CENTER</property>
<property name="cell_text"></property>
<property name="cell_vert_alignment">wxALIGN_CENTER</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="col_label_size"></property>
<property name="col_label_values"></property>
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
<property name="cols">1</property>
<property name="column_sizes"></property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="drag_col_move">0</property>
<property name="drag_col_size">0</property>
<property name="drag_grid_size">0</property>
<property name="drag_row_size">0</property>
<property name="editing">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="grid_line_color"></property>
<property name="grid_lines">0</property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label_bg"></property>
<property name="label_font"></property>
<property name="label_text"></property>
<property name="margin_height">0</property>
<property name="margin_width">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_GridEseries112</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="row_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="row_label_size">0</property>
<property name="row_label_values"></property>
<property name="row_label_vert_alignment">wxALIGN_CENTER</property>
<property name="row_sizes"></property>
<property name="rows">1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxBOTTOM|wxLEFT|wxRIGHT|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxHtmlWindow" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,100</property>
<property name="moveable">1</property>
<property name="name">m_panelESeriesHelp</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxHW_SCROLLBAR_AUTO</property>
<property name="subclass">HTML_WINDOW; html_window.h; </property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
</object>
</object>
</object>
</object>
</object>
</wxFormBuilder_Project>

View File

@ -0,0 +1,48 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-282-g1fa54006)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
#include "html_window.h"
#include "calculator_panels/calculator_panel.h"
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/string.h>
#include <wx/font.h>
#include <wx/grid.h>
#include <wx/gdicmn.h>
#include <wx/sizer.h>
#include <wx/statbox.h>
#include <wx/html/htmlwin.h>
#include <wx/panel.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class PANEL_ESERIES_DISPLAY_BASE
///////////////////////////////////////////////////////////////////////////////
class PANEL_ESERIES_DISPLAY_BASE : public CALCULATOR_PANEL
{
private:
protected:
wxGrid* m_GridEseries2496;
wxGrid* m_GridEseries112;
HTML_WINDOW* m_panelESeriesHelp;
public:
PANEL_ESERIES_DISPLAY_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = 0, const wxString& name = wxEmptyString );
~PANEL_ESERIES_DISPLAY_BASE();
};

View File

@ -2,7 +2,7 @@
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2011 jean-pierre.charras
* Copyright (C) 1992-2022 Kicad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2023 Kicad Developers, see AUTHORS.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
@ -24,23 +24,23 @@
* for more info
*/
#include <calculator_panels/panel_eseries.h>
#include <calculator_panels/panel_r_calculator.h>
#include <pcb_calculator_settings.h>
#include <string_utils.h>
#include <wx/msgdlg.h>
#include <html_window.h>
#include <eseries.h>
#include "resistor_substitution_utils.h"
#include <i18n_utility.h> // For _HKI definition in eseries_help.h
wxString eseries_help =
#include "eseries_help.h"
#include <i18n_utility.h> // For _HKI definition in r_calculator_help.h
wxString r_calculator_help =
#include "r_calculator_help.h"
extern double DoubleFromString( const wxString& TextValue );
PANEL_E_SERIES::PANEL_E_SERIES( wxWindow* parent, wxWindowID id, const wxPoint& pos,
const wxSize& size, long style, const wxString& name ) :
PANEL_E_SERIES_BASE( parent, id, pos, size, style, name )
PANEL_R_CALCULATOR::PANEL_R_CALCULATOR( wxWindow* parent, wxWindowID id, const wxPoint& pos,
const wxSize& size, long style, const wxString& name ) :
PANEL_R_CALCULATOR_BASE( parent, id, pos, size, style, name )
{
m_reqResUnits->SetLabel( wxT( "kΩ" ) );
m_exclude1Units->SetLabel( wxT( "kΩ" ) );
@ -62,7 +62,7 @@ PANEL_E_SERIES::PANEL_E_SERIES( wxWindow* parent, wxWindowID id, const wxPoint&
// show markdown formula explanation in lower help panel
wxString msg;
ConvertMarkdown2Html( wxGetTranslation( eseries_help ), msg );
ConvertMarkdown2Html( wxGetTranslation( r_calculator_help ), msg );
m_panelESeriesHelp->SetPage( msg );
// Needed on wxWidgets 3.0 to ensure sizers are correctly set
@ -70,54 +70,54 @@ PANEL_E_SERIES::PANEL_E_SERIES( wxWindow* parent, wxWindowID id, const wxPoint&
}
PANEL_E_SERIES::~PANEL_E_SERIES()
PANEL_R_CALCULATOR::~PANEL_R_CALCULATOR()
{
}
void PANEL_E_SERIES::ThemeChanged()
void PANEL_R_CALCULATOR::ThemeChanged()
{
// Update the HTML window with the help text
m_panelESeriesHelp->ThemeChanged();
}
void PANEL_E_SERIES::SaveSettings( PCB_CALCULATOR_SETTINGS* aCfg )
void PANEL_R_CALCULATOR::SaveSettings( PCB_CALCULATOR_SETTINGS* aCfg )
{
}
void PANEL_E_SERIES::LoadSettings( PCB_CALCULATOR_SETTINGS* aCfg )
void PANEL_R_CALCULATOR::LoadSettings( PCB_CALCULATOR_SETTINGS* aCfg )
{
}
void PANEL_E_SERIES::OnCalculateESeries( wxCommandEvent& event )
void PANEL_R_CALCULATOR::OnCalculateESeries( wxCommandEvent& event )
{
double reqr; // required resistor stored in local copy
double reqr; // required resistor stored in local copy
double error, err3 = 0;
wxString es, fs; // error and formula strings
wxString es, fs; // error and formula strings
wxBusyCursor dummy;
reqr = ( 1000 * DoubleFromString( m_ResRequired->GetValue() ) );
m_eSeries.SetRequiredValue( reqr ); // keep a local copy of required resistor value
m_eSeries.NewCalc(); // assume all values available
m_eSeries.NewCalc(); // assume all values available
/*
* Exclude itself. For the case, a value from the available series is found as required value,
* the calculator assumes this value needs a replacement for the reason of being not available.
* Two further exclude values can be entered to exclude and are skipped as not being available.
* All values entered in KiloOhms are converted to Ohm for internal calculation
*/
m_eSeries.Exclude( 1000 * DoubleFromString( m_ResRequired->GetValue()));
m_eSeries.Exclude( 1000 * DoubleFromString( m_ResExclude1->GetValue()));
m_eSeries.Exclude( 1000 * DoubleFromString( m_ResExclude2->GetValue()));
m_eSeries.Exclude( 1000 * DoubleFromString( m_ResRequired->GetValue() ) );
m_eSeries.Exclude( 1000 * DoubleFromString( m_ResExclude1->GetValue() ) );
m_eSeries.Exclude( 1000 * DoubleFromString( m_ResExclude2->GetValue() ) );
try
{
m_eSeries.Calculate();
}
catch (std::out_of_range const& exc)
catch( std::out_of_range const& exc )
{
wxString msg;
msg << "Internal error: " << exc.what();
@ -126,17 +126,18 @@ void PANEL_E_SERIES::OnCalculateESeries( wxCommandEvent& event )
return;
}
fs = m_eSeries.GetResults()[S2R].e_name; // show 2R solution formula string
fs = m_eSeries.GetResults()[RES_EQUIV_CALC::S2R].e_name; // show 2R solution formula string
m_ESeries_Sol2R->SetValue( fs );
error = reqr + m_eSeries.GetResults()[S2R].e_value; // absolute value of solution
error = ( reqr / error - 1 ) * 100; // error in percent
error = reqr
+ m_eSeries.GetResults()[RES_EQUIV_CALC::S2R].e_value; // absolute value of solution
error = ( reqr / error - 1 ) * 100; // error in percent
if( error )
{
if( std::abs( error ) < 0.01 )
es.Printf( "<%.2f", 0.01 );
else
es.Printf( "%+.2f",error);
es.Printf( "%+.2f", error );
}
else
{
@ -145,9 +146,9 @@ void PANEL_E_SERIES::OnCalculateESeries( wxCommandEvent& event )
m_ESeriesError2R->SetValue( es ); // anyway show 2R error string
if( m_eSeries.GetResults()[S3R].e_use ) // if 3R solution available
if( m_eSeries.GetResults()[RES_EQUIV_CALC::S3R].e_use ) // if 3R solution available
{
err3 = reqr + m_eSeries.GetResults()[S3R].e_value; // calculate the 3R
err3 = reqr + m_eSeries.GetResults()[RES_EQUIV_CALC::S3R].e_value; // calculate the 3R
err3 = ( reqr / err3 - 1 ) * 100; // error in percent
if( err3 )
@ -155,18 +156,18 @@ void PANEL_E_SERIES::OnCalculateESeries( wxCommandEvent& event )
if( std::abs( err3 ) < 0.01 )
es.Printf( "<%.2f", 0.01 );
else
es.Printf( "%+.2f",err3);
es.Printf( "%+.2f", err3 );
}
else
{
es = _( "Exact" );
}
m_ESeriesError3R->SetValue( es ); // show 3R error string
fs = m_eSeries.GetResults()[S3R].e_name;
m_ESeries_Sol3R->SetValue( fs ); // show 3R formula string
m_ESeriesError3R->SetValue( es ); // show 3R error string
fs = m_eSeries.GetResults()[RES_EQUIV_CALC::S3R].e_name;
m_ESeries_Sol3R->SetValue( fs ); // show 3R formula string
}
else // nothing better than 2R found
else // nothing better than 2R found
{
fs = _( "Not worth using" );
m_ESeries_Sol3R->SetValue( fs );
@ -175,21 +176,22 @@ void PANEL_E_SERIES::OnCalculateESeries( wxCommandEvent& event )
fs = wxEmptyString;
if( m_eSeries.GetResults()[S4R].e_use ) // show 4R solution if available
if( m_eSeries.GetResults()[RES_EQUIV_CALC::S4R].e_use ) // show 4R solution if available
{
fs = m_eSeries.GetResults()[S4R].e_name;
fs = m_eSeries.GetResults()[RES_EQUIV_CALC::S4R].e_name;
error = reqr + m_eSeries.GetResults()[S4R].e_value; // absolute value of solution
error = reqr
+ m_eSeries.GetResults()[RES_EQUIV_CALC::S4R].e_value; // absolute value of solution
error = ( reqr / error - 1 ) * 100; // error in percent
if( error )
es.Printf( "%+.2f",error );
es.Printf( "%+.2f", error );
else
es = _( "Exact" );
m_ESeriesError4R->SetValue( es );
}
else // no 4R solution
else // no 4R solution
{
fs = _( "Not worth using" );
es = wxEmptyString;
@ -200,16 +202,16 @@ void PANEL_E_SERIES::OnCalculateESeries( wxCommandEvent& event )
}
void PANEL_E_SERIES::OnESeriesSelection( wxCommandEvent& event )
void PANEL_R_CALCULATOR::OnESeriesSelection( wxCommandEvent& event )
{
if( event.GetEventObject() == m_e1 )
m_eSeries.SetSeries( E1 );
m_eSeries.SetSeries( ESERIES::E1 );
else if( event.GetEventObject() == m_e3 )
m_eSeries.SetSeries( E3 );
m_eSeries.SetSeries( ESERIES::E3 );
else if( event.GetEventObject() == m_e12 )
m_eSeries.SetSeries( E12 );
m_eSeries.SetSeries( ESERIES::E12 );
else if( event.GetEventObject() == m_e24 )
m_eSeries.SetSeries( E24 );
m_eSeries.SetSeries( ESERIES::E24 );
else
m_eSeries.SetSeries( E6 );
m_eSeries.SetSeries( ESERIES::E6 );
}

View File

@ -17,22 +17,23 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PANEL_E_SERIES_H
#define PANEL_E_SERIES_H
#ifndef PANEL_R_CALCULATOR_H
#define PANEL_R_CALCULATOR_H
#include "panel_eseries_base.h"
#include <eseries.h>
#include "panel_r_calculator_base.h"
#include "resistor_substitution_utils.h"
class PCB_CALCULATOR_SETTINGS;
class PANEL_E_SERIES : public PANEL_E_SERIES_BASE
class PANEL_R_CALCULATOR : public PANEL_R_CALCULATOR_BASE
{
public:
PANEL_E_SERIES( wxWindow* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
~PANEL_E_SERIES();
PANEL_R_CALCULATOR( wxWindow* parent, wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString );
~PANEL_R_CALCULATOR();
// Methods from CALCULATOR_PANEL that must be overridden
void LoadSettings( PCB_CALCULATOR_SETTINGS* aCfg ) override;
@ -52,7 +53,7 @@ public:
void OnESeriesSelection( wxCommandEvent& event ) override;
private:
E_SERIES m_eSeries;
RES_EQUIV_CALC m_eSeries;
};
#endif

View File

@ -1,15 +1,15 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 3.10.1-282-g1fa54006)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "panel_eseries_base.h"
#include "panel_r_calculator_base.h"
///////////////////////////////////////////////////////////////////////////
PANEL_E_SERIES_BASE::PANEL_E_SERIES_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : CALCULATOR_PANEL( parent, id, pos, size, style, name )
PANEL_R_CALCULATOR_BASE::PANEL_R_CALCULATOR_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : CALCULATOR_PANEL( parent, id, pos, size, style, name )
{
wxBoxSizer* bSizerESeries;
bSizerESeries = new wxBoxSizer( wxVERTICAL );
@ -203,22 +203,22 @@ PANEL_E_SERIES_BASE::PANEL_E_SERIES_BASE( wxWindow* parent, wxWindowID id, const
bSizerESeries->Fit( this );
// Connect Events
m_e1->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_e3->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_e6->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_e12->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_e24->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_buttonEScalculate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnCalculateESeries ), NULL, this );
m_e1->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_e3->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_e6->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_e12->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_e24->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_buttonEScalculate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnCalculateESeries ), NULL, this );
}
PANEL_E_SERIES_BASE::~PANEL_E_SERIES_BASE()
PANEL_R_CALCULATOR_BASE::~PANEL_R_CALCULATOR_BASE()
{
// Disconnect Events
m_e1->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_e3->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_e6->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_e12->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_e24->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnESeriesSelection ), NULL, this );
m_buttonEScalculate->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_E_SERIES_BASE::OnCalculateESeries ), NULL, this );
m_e1->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_e3->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_e6->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_e12->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_e24->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnESeriesSelection ), NULL, this );
m_buttonEScalculate->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_R_CALCULATOR_BASE::OnCalculateESeries ), NULL, this );
}

View File

@ -11,13 +11,13 @@
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">panel_eseries_base</property>
<property name="file">panel_r_calculator_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="name">panel_eseries_base</property>
<property name="name">panel_r_calculator_base</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
@ -35,6 +35,7 @@
<property name="bg"></property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="fg"></property>
@ -43,10 +44,10 @@
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size"></property>
<property name="name">PANEL_E_SERIES_BASE</property>
<property name="name">PANEL_R_CALCULATOR_BASE</property>
<property name="pos"></property>
<property name="size">-1,-1</property>
<property name="subclass">CALCULATOR_PANEL; calculator_panels/calculator_panel.h; </property>
<property name="subclass">CALCULATOR_PANEL; calculator_panels/panel_r_calculator.h; forward_declare</property>
<property name="tooltip"></property>
<property name="two_step_creation">0</property>
<property name="window_extra_style"></property>
@ -119,6 +120,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -180,6 +182,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -244,6 +247,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -305,6 +309,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -366,6 +371,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -430,6 +436,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -491,6 +498,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -552,6 +560,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -616,6 +625,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -679,6 +689,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -746,6 +757,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -811,6 +823,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -876,6 +889,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -941,6 +955,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1006,6 +1021,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1103,6 +1119,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1164,6 +1181,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1228,6 +1246,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1289,6 +1308,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1353,6 +1373,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1414,6 +1435,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1475,6 +1497,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1539,6 +1562,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1600,6 +1624,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1664,6 +1689,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1725,6 +1751,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1786,6 +1813,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1850,6 +1878,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1911,6 +1940,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -1975,6 +2005,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -2038,6 +2069,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -2101,6 +2133,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
@ -2160,20 +2193,20 @@
</object>
</object>
</object>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxBOTTOM|wxRIGHT</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="0">
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bLowerESeries</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALL</property>
<property name="proportion">1</property>
<object class="wxStaticBoxSizer" expanded="0">
<object class="wxStaticBoxSizer" expanded="1">
<property name="id">wxID_ANY</property>
<property name="label">Help</property>
<property name="minimum_size"></property>
@ -2206,6 +2239,7 @@
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="drag_accept_files">0</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// C++ code generated with wxFormBuilder (version 3.10.1-282-g1fa54006)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -34,9 +34,9 @@
///////////////////////////////////////////////////////////////////////////////
/// Class PANEL_E_SERIES_BASE
/// Class PANEL_R_CALCULATOR_BASE
///////////////////////////////////////////////////////////////////////////////
class PANEL_E_SERIES_BASE : public CALCULATOR_PANEL
class PANEL_R_CALCULATOR_BASE : public CALCULATOR_PANEL
{
private:
@ -82,9 +82,9 @@ class PANEL_E_SERIES_BASE : public CALCULATOR_PANEL
public:
PANEL_E_SERIES_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 );
PANEL_R_CALCULATOR_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 );
~PANEL_E_SERIES_BASE();
~PANEL_R_CALCULATOR_BASE();
};

View File

@ -0,0 +1,14 @@
// Do not edit this file, it is autogenerated by CMake from the .md file
_HKI( "Passive components are commonly made with E-series values appropriate to their precision.\n"
"Capacitors commonly use E12 values. 10% and 5% resistors commonly use E24 values. 1%\n"
"resistors use E96 values. Other series are not commonly used.\n"
"\n"
"To select a value begin with the calculated target value and then round it to 2\n"
"significant figures for E24 or below or 3 significant figures for E48 and up.\n"
"Then find the value in the table which is nearest to the significant figures\n"
"remaining and substitute it for those figures.\n"
"\n"
"For example if the calculated target value is 16,834.2Ω then this rounds to 16,800Ω.\n"
"The nearest value to 168 is 169 and the selected E96 value is 16.9kΩ.\n"
"\n"
"The value 0 is a special case and is not present in any series." );

View File

@ -0,0 +1,13 @@
Passive components are commonly made with E-series values appropriate to their precision.
Capacitors commonly use E12 values. 10% and 5% resistors commonly use E24 values. 1%
resistors use E96 values. Other series are not commonly used.
To select a value begin with the calculated target value and then round it to 2
significant figures for E24 or below or 3 significant figures for E48 and up.
Then find the value in the table which is nearest to the significant figures
remaining and substitute it for those figures.
For example if the calculated target value is 16,834.2Ω then this rounds to 16,800Ω.
The nearest value to 168 is 169 and the selected E96 value is 16.9kΩ.
The value 0 is a special case and is not present in any series.

View File

@ -1,24 +0,0 @@
// Do not edit this file, it is autogenerated by CMake from the .md file
_HKI( "E-series are defined in IEC 60063.\n"
"\n"
"Available values are approximately equally spaced in a logarithmic scale.\n"
"\n"
" E24(5%): 1.0 1.1 1.2 1.3 1.5 1.6 1.8 2.0 2.2 2.4 2.7 3.0 3.3 3.6 3.9 4.3 4.7 5.1 5.6 6.2 6.8 7.5 8.2 9.1\n"
" E12(10%): 1.0 1.2 1.5 1.8 2.2 2.7 3.3 3.9 4.7 5.6 6.8 8.2\n"
" E6(20%): 1.0 - 1.5 - 2.2 - 3.3 - 4.7 - 6.8 -\n"
" E3(50%): 1.0 - - - 2.2 - - - 4.7 - - -\n"
" E1 : 1.0 - - - - - - - - - - -\n"
"\n"
"- This calculator finds combinations of standard E-series (between 10Ω and 1MΩ) to create arbitrary values.\n"
"- You can enter the required resistance from 0.0025 to 4000 kΩ.\n"
"- Solutions using up to 4 components are given.\n"
"\n"
"The requested value is always excluded from the solution set.<br>\n"
"Optionally up to two additional values can be excluded in case of component availability problems.\n"
"\n"
"Solutions are given in the following formats:\n"
"\n"
" R1 + R2 +...+ Rn resistors in series\n"
" R1 | R2 |...| Rn resistors in parallel\n"
" R1 + (R2|R3)... any combination of the above\n"
"" );

View File

@ -42,13 +42,14 @@
#include <calculator_panels/panel_galvanic_corrosion.h>
#include <calculator_panels/panel_color_code.h>
#include <calculator_panels/panel_electrical_spacing.h>
#include <calculator_panels/panel_eseries.h>
#include <calculator_panels/panel_r_calculator.h>
#include <calculator_panels/panel_fusing_current.h>
#include <calculator_panels/panel_regulator.h>
#include <calculator_panels/panel_track_width.h>
#include <calculator_panels/panel_transline.h>
#include <calculator_panels/panel_via_size.h>
#include <calculator_panels/panel_wavelength.h>
#include <calculator_panels/panel_eseries_display.h>
#include "widgets/wx_menubar.h"
@ -142,6 +143,7 @@ void PCB_CALCULATOR_FRAME::loadPages()
m_treebook->AddPage( nullptr, _( "General system design" ) );
AddCalculator( new PANEL_REGULATOR( m_treebook ), _( "Regulators" ) );
AddCalculator( new PANEL_R_CALCULATOR( m_treebook ), _( "Resistor Calculator" ) );
m_treebook->AddPage( nullptr, _( "Power, current and isolation" ) );
@ -159,7 +161,7 @@ void PCB_CALCULATOR_FRAME::loadPages()
m_treebook->AddPage( nullptr, _( "Memo" ) );
AddCalculator( new PANEL_E_SERIES( m_treebook ), _( "E-Series" ) );
AddCalculator( new PANEL_ESERIES_DISPLAY( m_treebook ), _( "E-Series" ) );
AddCalculator( new PANEL_COLOR_CODE( m_treebook ), _( "Color Code" ) );
AddCalculator( new PANEL_BOARD_CLASS( m_treebook ), _( "Board Classes" ) );
AddCalculator( new PANEL_GALVANIC_CORROSION( m_treebook ), _( "Galvanic Corrosion" ) );

View File

@ -0,0 +1,14 @@
// Do not edit this file, it is autogenerated by CMake from the .md file
_HKI( "- This calculator finds combinations of standard E-series (between 10Ω and 1MΩ) to create arbitrary values.\n"
"- You can enter the required resistance from 0.0025 to 4000 kΩ.\n"
"- Solutions using up to 4 components are given.\n"
"\n"
"The requested value is always excluded from the solution set.<br>\n"
"Optionally up to two additional values can be excluded in case of component availability problems.\n"
"\n"
"Solutions are given in the following formats:\n"
"\n"
" R1 + R2 +...+ Rn resistors in series\n"
" R1 | R2 |...| Rn resistors in parallel\n"
" R1 + (R2|R3)... any combination of the above\n"
"" );

View File

@ -1,13 +1,3 @@
E-series are defined in IEC 60063.
Available values are approximately equally spaced in a logarithmic scale.
E24(5%): 1.0 1.1 1.2 1.3 1.5 1.6 1.8 2.0 2.2 2.4 2.7 3.0 3.3 3.6 3.9 4.3 4.7 5.1 5.6 6.2 6.8 7.5 8.2 9.1
E12(10%): 1.0 1.2 1.5 1.8 2.2 2.7 3.3 3.9 4.7 5.6 6.8 8.2
E6(20%): 1.0 - 1.5 - 2.2 - 3.3 - 4.7 - 6.8 -
E3(50%): 1.0 - - - 2.2 - - - 4.7 - - -
E1 : 1.0 - - - - - - - - - - -
- This calculator finds combinations of standard E-series (between 10Ω and 1MΩ) to create arbitrary values.
- You can enter the required resistance from 0.0025 to 4000 kΩ.
- Solutions using up to 4 components are given.

View File

@ -0,0 +1,393 @@
/*
* This program source code file
* is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 <janvi@veith.net>
* Copyright (C) 2021-2023 KiCad Developers, see AUTHORS.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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <cstdint>
#include <string>
#include <algorithm>
#include <limits>
#include "resistor_substitution_utils.h"
#include "eseries.h"
/*
* If BENCHMARK is defined, any 4R E12 calculations will print its execution time to console
* My Hasswell Enthusiast reports 225 mSec what are reproducible within plusminus 2 percent
*/
//#define BENCHMARK
#ifdef BENCHMARK
#include <profile.h>
#endif
// Return a string from aValue (aValue is expected in ohms)
// If aValue < 1000 the returned string is aValue with unit = R
// If aValue >= 1000 the returned string is aValue/1000 with unit = K
// with notation similar to 2K2
// If aValue >= 1e6 the returned string is aValue/1e6 with unit = M
// with notation = 1M
static std::string strValue( double aValue )
{
std::string result;
if( aValue < 1000.0 )
{
result = std::to_string( static_cast<int>( aValue ) );
result += 'R';
}
else
{
double div = 1e3;
char unit = 'K';
if( aValue >= 1e6 )
{
div = 1e6;
unit = 'M';
}
aValue /= div;
int valueAsInt = static_cast<int>( aValue );
result = std::to_string( valueAsInt );
result += unit;
// Add mantissa: 1 digit, suitable for series up to E24
double mantissa = aValue - valueAsInt;
if( mantissa > 0 )
result += std::to_string( static_cast<int>( ( mantissa * 10 ) + 0.5 ) );
}
return result;
}
RES_EQUIV_CALC::RES_EQUIV_CALC()
{
// Build the list of available resistor values in each En serie
const ESERIES::ESERIES_VALUES listValuesE1 = ESERIES::E1_VALUES();
const ESERIES::ESERIES_VALUES listValuesE3 = ESERIES::E3_VALUES();
const ESERIES::ESERIES_VALUES listValuesE6 = ESERIES::E6_VALUES();
const ESERIES::ESERIES_VALUES listValuesE12 = ESERIES::E12_VALUES();
const ESERIES::ESERIES_VALUES listValuesE24 = ESERIES::E24_VALUES();
// buildSeriesData must be called in the order of En series, because
// the list of series is expected indexed by En for the serie En
buildSeriesData( listValuesE1 );
buildSeriesData( listValuesE3 );
buildSeriesData( listValuesE6 );
buildSeriesData( listValuesE12 );
int count = buildSeriesData( listValuesE24 );
// Reserve a buffer for intermediate calculations:
// the buffer size is 2*count*count to store all combinations of 2 values
// there are 2*count*count = 29282 combinations for E24
int bufsize = 2 * count * count;
m_combined_table.reserve( bufsize );
// Store predefined R_DATA items.
for( int ii = 0; ii < bufsize; ii++ )
m_combined_table.emplace_back( "", 0.0 );
}
int RES_EQUIV_CALC::buildSeriesData( const ESERIES::ESERIES_VALUES aList )
{
uint_fast32_t curr_decade = FIRST_VALUE;
int count = 0;
std::vector<R_DATA> curr_list;
uint_fast16_t first_value_in_decade = aList[0];
for( ;; )
{
double curr_r = LAST_VALUE;
for( const uint16_t listvalue : aList )
{
curr_r = 1.0 * curr_decade * listvalue / first_value_in_decade;
curr_list.emplace_back( strValue( curr_r ), curr_r );
count++;
if( curr_r >= LAST_VALUE )
break;
}
if( curr_r >= LAST_VALUE )
break;
curr_decade *= 10;
}
m_tables.push_back( std::move( curr_list ) );
return count;
}
void RES_EQUIV_CALC::Exclude( double aValue )
{
if( aValue != 0.0 ) // if there is a value to exclude other than a wire jumper
{
for( R_DATA& i : m_tables[m_series] ) // then search it in the selected E-Series table
{
if( i.e_value == aValue ) // if the value to exclude is found
i.e_use = false; // disable its use
}
}
}
void RES_EQUIV_CALC::simple_solution( uint32_t aSize )
{
uint32_t i;
m_results.at( S2R ).e_value =
std::numeric_limits<double>::max(); // assume no 2R solution or max deviation
for( i = 0; i < aSize; i++ )
{
if( std::abs( m_combined_table.at( i ).e_value - m_required_value )
< std::abs( m_results.at( S2R ).e_value ) )
{
m_results[S2R].e_value =
m_combined_table[i].e_value - m_required_value; // save signed deviation in Ohms
m_results[S2R].e_name = m_combined_table[i].e_name; // save combination text
m_results[S2R].e_use = true; // this is a possible solution
}
}
}
void RES_EQUIV_CALC::combine4( uint32_t aSize )
{
uint32_t i, j;
double tmp;
m_results[S4R].e_use = false; // disable 4R solution, until
m_results[S4R].e_value = m_results[S3R].e_value; // 4R becomes better than 3R solution
#ifdef BENCHMARK
PROF_TIMER timer; // start timer to count execution time
#endif
for( i = 0; i < aSize; i++ ) // 4R search outer loop
{ // scan valid intermediate 2R solutions
for( j = 0; j < aSize; j++ ) // inner loop combines all with itself
{
tmp = m_combined_table[i].e_value
+ m_combined_table[j].e_value; // calculate 2R+2R serial
tmp -= m_required_value; // calculate 4R deviation
if( std::abs( tmp ) < std::abs( m_results.at( S4R ).e_value ) ) // if new 4R is better
{
m_results[S4R].e_value = tmp; // save amount of benefit
std::string s = "( ";
s.append( m_combined_table[i].e_name ); // mention 1st 2 component
s.append( " ) + ( " ); // in series
s.append( m_combined_table[j].e_name ); // with 2nd 2 components
s.append( " )" );
m_results[S4R].e_name = s; // save the result and
m_results[S4R].e_use = true; // enable for later use
}
tmp = ( m_combined_table[i].e_value * m_combined_table[j].e_value )
/ ( m_combined_table[i].e_value
+ m_combined_table[j].e_value ); // calculate 2R|2R parallel
tmp -= m_required_value; // calculate 4R deviation
if( std::abs( tmp ) < std::abs( m_results[S4R].e_value ) ) // if new 4R is better
{
m_results[S4R].e_value = tmp; // save amount of benefit
std::string s = "( ";
s.append( m_combined_table[i].e_name ); // mention 1st 2 component
s.append( " ) | ( " ); // in parallel
s.append( m_combined_table[j].e_name ); // with 2nd 2 components
s.append( " )" );
m_results[S4R].e_name = s; // save the result
m_results[S4R].e_use = true; // enable later use
}
}
}
#ifdef BENCHMARK
printf( "Calculation time = %d mS", timer.msecs() );
fflush( 0 );
#endif
}
void RES_EQUIV_CALC::NewCalc()
{
for( R_DATA& i : m_combined_table )
i.e_use = false; // before any calculation is done, assume that
for( R_DATA& i : m_results )
i.e_use = false; // no combinations and no results are available
for( R_DATA& i : m_tables[m_series] )
i.e_use = true; // all selected E-values available
}
uint32_t RES_EQUIV_CALC::combine2()
{
uint32_t combi2R = 0; // target index counts calculated 2R combinations
std::string s;
for( const R_DATA& i : m_tables[m_series] ) // outer loop to sweep selected source lookup table
{
if( i.e_use )
{
for( const R_DATA& j : m_tables[m_series] ) // inner loop to combine values with itself
{
if( j.e_use )
{
m_combined_table[combi2R].e_use = true;
m_combined_table[combi2R].e_value =
i.e_value + j.e_value; // calculate 2R serial
s = i.e_name;
s.append( " + " );
m_combined_table[combi2R].e_name = s.append( j.e_name );
combi2R++; // next destination
m_combined_table[combi2R].e_use = true; // calculate 2R parallel
m_combined_table[combi2R].e_value =
i.e_value * j.e_value / ( i.e_value + j.e_value );
s = i.e_name;
s.append( " | " );
m_combined_table[combi2R].e_name = s.append( j.e_name );
combi2R++; // next destination
}
}
}
}
return combi2R;
}
void RES_EQUIV_CALC::combine3( uint32_t aSize )
{
uint32_t j = 0;
double tmp = 0; // avoid warning for being uninitialized
std::string s;
m_results[S3R].e_use = false; // disable 3R solution, until 3R
m_results[S3R].e_value = m_results[S2R].e_value; // becomes better than 2R solution
for( const R_DATA& i : m_tables[m_series] ) // 3R Outer loop to selected primary E series table
{
if( i.e_use ) // skip all excluded values
{
for( j = 0; j < aSize; j++ ) // inner loop combines with all 2R intermediate
{ // results R+2R serial combi
tmp = m_combined_table[j].e_value + i.e_value;
tmp -= m_required_value; // calculate deviation
if( std::abs( tmp ) < std::abs( m_results[S3R].e_value ) ) // compare if better
{ // then take it
s = i.e_name; // mention 3rd component
s.append( " + ( " ); // in series
s.append( m_combined_table[j].e_name ); // with 2R combination
s.append( " )" );
m_results[S3R].e_name = s; // save S3R result
m_results[S3R].e_value = tmp; // save amount of benefit
m_results[S3R].e_use = true; // enable later use
}
tmp = i.e_value * m_combined_table[j].e_value
/ ( i.e_value + m_combined_table[j].e_value ); // calculate R + 2R parallel
tmp -= m_required_value; // calculate deviation
if( std::abs( tmp ) < std::abs( m_results[S3R].e_value ) ) // compare if better
{ // then take it
s = i.e_name; // mention 3rd component
s.append( " | ( " ); // in parallel
s.append( m_combined_table[j].e_name ); // with 2R combination
s.append( " )" );
m_results[S3R].e_name = s;
m_results[S3R].e_value = tmp; // save amount of benefit
m_results[S3R].e_use = true; // enable later use
}
}
}
}
// If there is a 3R result with remaining deviation consider to search a possibly better
// 4R solution
// calculate 4R for small series always
if( m_results[S3R].e_use && tmp )
combine4( aSize );
}
void RES_EQUIV_CALC::Calculate()
{
uint32_t no_of_2Rcombi = 0;
no_of_2Rcombi = combine2(); // combine all 2R combinations for selected E serie
simple_solution( no_of_2Rcombi ); // search for simple 2 component solution
if( m_results[S2R].e_value ) // if simple 2R result is not exact
combine3( no_of_2Rcombi ); // continiue searching for a possibly better solution
strip3();
strip4();
}
void RES_EQUIV_CALC::strip3()
{
std::string s;
if( m_results[S3R].e_use ) // if there is a 3 term result available
{ // what is connected either by two "|" or by 3 plus
s = m_results[S3R].e_name;
if( ( std::count( s.begin(), s.end(), '+' ) == 2 )
|| ( std::count( s.begin(), s.end(), '|' ) == 2 ) )
{ // then strip one pair of braces
s.erase( s.find( "( " ), 2 ); // it is known sure, this is available
s.erase( s.find( " )" ), 2 ); // in any unstripped 3R result term
m_results[S3R].e_name = s; // use stripped result
}
}
}
void RES_EQUIV_CALC::strip4()
{
std::string s;
if( m_results[S4R].e_use ) // if there is a 4 term result available
{ // what are connected either by 3 "+" or by 3 "|"
s = m_results[S4R].e_name;
if( ( std::count( s.begin(), s.end(), '+' ) == 3 )
|| ( std::count( s.begin(), s.end(), '|' ) == 3 ) )
{ // then strip two pair of braces
s.erase( s.find( "( " ), 2 ); // it is known sure, they are available
s.erase( s.find( " )" ), 2 ); // in any unstripped 4R result term
s.erase( s.find( "( " ), 2 );
s.erase( s.find( " )" ), 2 );
m_results[S4R].e_name = s; // use stripped result
}
}
}

View File

@ -0,0 +1,187 @@
/*
* This program source code file
* is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2023 KiCad Developers, see AUTHORS.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 3 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, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
#include <cstdint>
#include <vector>
#include <array>
#include "eseries.h"
// First value of resistor in ohm
// This value is only pertinent to the resistor calculator.
// It is used to reduce the computational complexity of its calculations.
// There are valid resistor values using E-series numbers below this
// value and above the below LAST_VALUE.
#define FIRST_VALUE 10
// last value of resistor in ohm
// This value is only pertinent to the resistor calculator. See above.
#define LAST_VALUE 1e6
// R_DATA handles a resistor: string value, value and allowed to use
struct R_DATA
{
R_DATA() : e_use( true ), e_value( 0.0 ) {}
R_DATA( const std::string& aName, double aValue )
{
e_use = true;
e_name = aName;
e_value = aValue;
}
bool e_use;
std::string e_name;
double e_value;
};
class RES_EQUIV_CALC
/*! \brief Performs calculations on E-series values primarily to find target values.
*
* E_SERIES class stores and performs calcuations on E-series values. It currently
* is targeted toward the resistor calculator and hard codes some limitations
* to optimize its use in the resistor calculator.
*
* At this time these limitations are that this class ignores all E-series larger
* than E24 and it does not consider resistor values below 10 Ohm or above 1M Ohm.
*/
{
public:
RES_EQUIV_CALC();
/**
* This calculator suggests solutions for 2R, 3R and 4R replacement combinations
*/
enum
{
S2R,
S3R,
S4R
};
/**
* If any value of the selected E-series not available, it can be entered as an exclude value.
*
* @param aValue is the value to exclude from calculation
* Values to exclude are set to false in the selected E-series source lookup table
*/
void Exclude( double aValue );
/**
* initialize next calculation and erase results from previous calculation
*/
void NewCalc();
/**
* called on calculate button to execute all the 2R, 3R and 4R calculations
*/
void Calculate();
/**
* Interface for CheckBox, RadioButton, RequriedResistor and calculated Results
*/
void SetSeries( uint32_t aSeries ) { m_series = aSeries; }
void SetRequiredValue( double aValue ) { m_required_value = aValue; }
// Accessor:
const std::array<R_DATA, S4R + 1>& GetResults() { return m_results; }
private:
/**
* Add values from aList to m_tables. Covers all decades between FIRST_VALUE and LAST_VALUE.
* @return the count of items added to m_tables.
*/
int buildSeriesData( const ESERIES::ESERIES_VALUES );
/**
* Build all 2R combinations from the selected E-series values
*
* Pre-calculated value combinations are saved in intermediate look up table m_combined_table
* @return is the number of found combinations what also depends from exclude values
*/
uint32_t combine2();
/**
* Search for closest two component solution
*
* @param aSize is the number of valid 2R combinations in m_combined_table on where to search
* The 2R result with smallest deviation will be saved in results
*/
void simple_solution( uint32_t aSize );
/**
* Check if there is a better 3 R solution than previous one using only two components.
*
* @param aSize gives the number of available combinations to be checked inside
* m_combined_table. Therefore m_combined_table is combined with the primary
* E-series look up table. The 3R result with smallest deviation will be saved
* in results if better than 2R
*/
void combine3( uint32_t aSize );
/**
* Check if there is a better four component solution.
*
* @param aSsize gives the number of 2R combinations to be checked inside m_combined_table
* Occupied calculation time depends from number of available E-series values with the power
* of 4 why execution for E12 is conditional with 4R check box for the case the previously
* found 3R solution is already exact
*/
void combine4( uint32_t aSize );
/*
* Strip redundant braces from three component result
*
* Example: R1+(R2+R3) become R1+R2+R3
* and R1|(R2|R3) become R1|R2|R3
* while R1+(R2|R3) or (R1+R2)|R3) remains untouched
*/
void strip3();
/*
* Strip redundant braces from four component result
*
* Example: (R1+R2)+(R3+R4) become R1+R2+R3+R4
* and (R1|R2)|(R2|R3) become R1|R2|R3|R4
* while (R1+R2)|(R3+R4) remains untouched
*/
void strip4();
private:
std::vector<std::vector<R_DATA>> m_tables;
/* Note: intermediate calculations use m_combined_table
* if the biggest list is En, reserved array size should be 2*En*En of std::vector primary list.
* 2 component combinations including redundant swappable terms are for the moment
* ( using values between 10 ohms and 1Mohm )
* 72 combinations for E1
* 512 combinations for E3
* 1922 combinations for E6
* 7442 combinations for E12
* 29282 combinations for E24
*/
std::vector<R_DATA> m_combined_table; // intermediate 2R combinations
std::array<R_DATA, S4R + 1> m_results; // 2R, 3R and 4R results
uint32_t m_series = ESERIES::E6; // Radio Button State
double m_required_value = 0.0; // required Resistor
};