pcb_calculator, eserie rework and add E24 serie.

Numerous enhancements in code.
This commit is contained in:
jean-pierre charras 2021-10-14 15:20:54 +02:00
parent 0533196294
commit 84e83fc743
7 changed files with 343 additions and 180 deletions

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.0-4761b0c5)
// C++ code generated with wxFormBuilder (version 3.10.0-39-g3487c3cb)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -81,6 +81,9 @@ PANEL_E_SERIE_BASE::PANEL_E_SERIE_BASE( wxWindow* parent, wxWindowID id, const w
m_e12 = new wxRadioButton( sbSizerESeriesInput->GetStaticBox(), wxID_ANY, _("E12"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer40->Add( m_e12, 1, wxALL, 5 );
m_e24 = new wxRadioButton( sbSizerESeriesInput->GetStaticBox(), wxID_ANY, _("E24"), wxDefaultPosition, wxDefaultSize, 0 );
bSizer40->Add( m_e24, 0, wxALL, 5 );
sbSizerESeriesInput->Add( bSizer40, 1, wxEXPAND, 5 );
@ -201,6 +204,7 @@ PANEL_E_SERIE_BASE::PANEL_E_SERIE_BASE( wxWindow* parent, wxWindowID id, const w
m_e3->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnESeriesSelection ), NULL, this );
m_e6->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnESeriesSelection ), NULL, this );
m_e12->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnESeriesSelection ), NULL, this );
m_e24->Connect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnESeriesSelection ), NULL, this );
m_buttonEScalculate->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnCalculateESeries ), NULL, this );
}
@ -211,6 +215,7 @@ PANEL_E_SERIE_BASE::~PANEL_E_SERIE_BASE()
m_e3->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnESeriesSelection ), NULL, this );
m_e6->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnESeriesSelection ), NULL, this );
m_e12->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnESeriesSelection ), NULL, this );
m_e24->Disconnect( wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnESeriesSelection ), NULL, this );
m_buttonEScalculate->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_E_SERIE_BASE::OnCalculateESeries ), NULL, this );
}

View File

@ -981,6 +981,71 @@
<event name="OnRadioButton">OnESeriesSelection</event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxRadioButton" expanded="1">
<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="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="label">E24</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_e24</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"></property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value">0</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnRadioButton">OnESeriesSelection</event>
</object>
</object>
</object>
</object>
</object>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.0-4761b0c5)
// C++ code generated with wxFormBuilder (version 3.10.0-39-g3487c3cb)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -55,6 +55,7 @@ class PANEL_E_SERIE_BASE : public CALCULATOR_PANEL
wxRadioButton* m_e3;
wxRadioButton* m_e6;
wxRadioButton* m_e12;
wxRadioButton* m_e24;
wxStaticText* m_ESerieSimpleSolution;
wxTextCtrl* m_ESeries_Sol2R;
wxStaticText* m_ESeriesSimpleErr;

View File

@ -23,6 +23,7 @@
#include <algorithm>
#include <calculator_panels/panel_eserie.h>
#include <wx/msgdlg.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
@ -30,7 +31,7 @@
//#define BENCHMARK
#ifdef BENCHMARK
#include <sys/time.h>
#include <profile.h>
#endif
#include "eserie.h"
@ -39,14 +40,120 @@ extern double DoubleFromString( const wxString& TextValue );
E_SERIE r;
// 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;
int unit = 'K';
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 ) );
}
return result;
}
E_SERIE::E_SERIE()
{
// 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 };
// buildSerieData must be called in the order of En series, because
// the list of series is expected indexed by En for the serie En
buildSerieData( E1, listValuesE1 );
buildSerieData( E3, listValuesE3 );
buildSerieData( E6, listValuesE6 );
buildSerieData( E12, listValuesE12 );
int count = buildSerieData( E24, 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_cmb_lut.reserve( bufsize );
// Store predefined R_DATA items.
for( int ii = 0; ii < bufsize; ii++ )
m_cmb_lut.emplace_back( "", 0.0 );
}
int E_SERIE::buildSerieData( int aEserie, double aList[] )
{
double curr_coeff = FIRST_VALUE;
int count = 0;
std::vector<R_DATA> curr_list;
for( ; ; )
{
double curr_r = curr_coeff;
for( int ii = 0; ; ii++ )
{
if( aList[ii] == 0.0 ) // End of list
break;
double curr_r = curr_coeff * 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_coeff *= 10;
}
m_luts.push_back( std::move( curr_list ) );
return count;
}
void E_SERIE::Exclude( double aValue )
{
if( aValue ) // if there is a value to exclude other than a wire jumper
if( aValue ) // if there is a value to exclude other than a wire jumper
{
for( R_DATA& i : m_luts[m_series] ) // then search it in the selected E-Serie lookup table
{
if( i.e_value == aValue ) // if value to exclude found
if( i.e_value == aValue ) // if the value to exclude is found
i.e_use = false; // disable its use
}
}
@ -57,15 +164,15 @@ void E_SERIE::simple_solution( uint32_t aSize )
{
uint32_t i;
m_results[S2R].e_value = std::numeric_limits<double>::max(); // assume no 2R solution or max deviation
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( abs( m_cmb_lut[i].e_value - m_required_value ) < abs( m_results[S2R].e_value ) )
if( abs( m_cmb_lut.at( i ).e_value - m_required_value ) < abs( m_results.at( S2R ).e_value ) )
{
m_results[S2R].e_value = m_cmb_lut[i].e_value - m_required_value; // save signed deviation in Ohms
m_results[S2R].e_name = m_cmb_lut[i].e_name; // save combination text
m_results[S2R].e_use = true; // this is a possible solution
m_results.at( S2R ).e_value = m_cmb_lut.at( i ).e_value - m_required_value; // save signed deviation in Ohms
m_results.at( S2R ).e_name = m_cmb_lut.at( i ).e_name; // save combination text
m_results.at( S2R ).e_use = true; // this is a possible solution
}
}
}
@ -77,53 +184,53 @@ void E_SERIE::combine4( uint32_t aSize )
double tmp;
std::string s;
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
m_results.at( S4R ).e_use = false; // disable 4R solution, until
m_results.at( S4R ).e_value = m_results.at( S3R ).e_value; // 4R becomes better than 3R solution
#ifdef BENCHMARK
PROF_COUNTER combine4_timer; // start timer to count execution time
PROF_COUNTER 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_cmb_lut[i].e_value + m_cmb_lut[j].e_value; // calculate 2R+2R serial
tmp -= m_required_value; // calculate 4R deviation
tmp = m_cmb_lut.at( i ).e_value + m_cmb_lut.at( j ).e_value; // calculate 2R+2R serial
tmp -= m_required_value; // calculate 4R deviation
if( abs( tmp ) < abs( m_results[S4R].e_value ) ) // if new 4R is better
if( abs( tmp ) < abs( m_results.at(S4R).e_value ) ) // if new 4R is better
{
m_results[S4R].e_value = tmp; // save amount of benefit
m_results.at( S4R ).e_value = tmp; // save amount of benefit
std::string s = "( ";
s.append( m_cmb_lut[i].e_name ); // mention 1st 2 component
s.append( " ) + ( " ); // in series
s.append( m_cmb_lut[j].e_name ); // with 2nd 2 components
s.append( m_cmb_lut.at( i ).e_name ); // mention 1st 2 component
s.append( " ) + ( " ); // in series
s.append( m_cmb_lut.at( 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
m_results.at( S4R ).e_name = s; // save the result and
m_results.at( S4R ).e_use = true; // enable for later use
}
tmp = ( m_cmb_lut[i].e_value * m_cmb_lut[j].e_value ) /
( m_cmb_lut[i].e_value + m_cmb_lut[j].e_value ); // calculate 2R|2R parallel
tmp = ( m_cmb_lut[i].e_value * m_cmb_lut.at( j ).e_value ) /
( m_cmb_lut[i].e_value + m_cmb_lut.at( j ).e_value ); // calculate 2R|2R parallel
tmp -= m_required_value; // calculate 4R deviation
if( abs( tmp ) < abs( m_results[S4R].e_value ) ) // if new 4R is better
if( abs( tmp ) < abs( m_results.at( S4R ).e_value ) ) // if new 4R is better
{
m_results[S4R].e_value = tmp; // save amount of benefit
m_results.at( S4R ).e_value = tmp; // save amount of benefit
std::string s = "( ";
s.append( m_cmb_lut[i].e_name ); // mention 1st 2 component
s.append( m_cmb_lut.at( i ).e_name ); // mention 1st 2 component
s.append( " ) | ( " ); // in parallel
s.append( m_cmb_lut[j].e_name ); // with 2nd 2 components
s.append( m_cmb_lut.at( 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
m_results.at( S4R ).e_name = s; // save the result
m_results.at( S4R ).e_use = true; // enable later use
}
}
}
#ifdef BENCHMARK
if( m_series == E12 )
std::cout<<"4R Time = "<<combine4_timer.msecs()<<" mSec"<<std::endl;
printf( "Calculation time = %d mS", timer.msecs() );
fflush( 0 );
#endif
}
@ -154,18 +261,17 @@ uint32_t E_SERIE::combine2()
{
if( j.e_use )
{
m_cmb_lut[combi2R].e_use = true;
m_cmb_lut[combi2R].e_value = i.e_value + j.e_value; // calculate 2R serial
m_cmb_lut.at( combi2R ).e_use = true;
m_cmb_lut.at( combi2R ).e_value = i.e_value + j.e_value; // calculate 2R serial
s = i.e_name;
s.append( " + " );
m_cmb_lut[combi2R].e_name = s.append( j.e_name);
combi2R++; // next destination
m_cmb_lut[combi2R].e_use = true; // calculate 2R parallel
m_cmb_lut[combi2R].e_value = i.e_value * j.e_value /
( i.e_value + j.e_value );
m_cmb_lut.at( combi2R ).e_name = s.append( j.e_name);
combi2R++; // next destination
m_cmb_lut.at( combi2R ).e_use = true; // calculate 2R parallel
m_cmb_lut.at( combi2R ).e_value = i.e_value * j.e_value / ( i.e_value + j.e_value );
s = i.e_name;
s.append( " | " );
m_cmb_lut[combi2R].e_name = s.append( j.e_name );
m_cmb_lut.at( combi2R ).e_name = s.append( j.e_name );
combi2R++; // next destination
}
}
@ -181,8 +287,8 @@ void E_SERIE::combine3( uint32_t aSize )
double tmp = 0; // avoid warning for being uninitialized
std::string s;
m_results[S3R].e_use = false; // disable 3R solution, until
m_results[S3R].e_value = m_results[S2R].e_value; // 3R becomes better than 2R solution
m_results.at( S3R ).e_use = false; // disable 3R solution, until
m_results.at( S3R ).e_value = m_results.at( S2R ).e_value; // 3R becomes better than 2R solution
for( const R_DATA& i : m_luts[m_series] ) // 3R Outer loop to selected primary E serie LUT
{
@ -190,33 +296,33 @@ void E_SERIE::combine3( uint32_t aSize )
{
for( j = 0; j < aSize; j++ ) // inner loop combines with all 2R intermediate results
{ // R+2R serial combi
tmp = m_cmb_lut[j].e_value + i.e_value;
tmp = m_cmb_lut.at( j ).e_value + i.e_value;
tmp -= m_required_value; // calculate deviation
if( abs( tmp ) < abs( m_results[S3R].e_value ) ) // compare if better
if( abs( tmp ) < abs( m_results.at( S3R ).e_value ) ) // compare if better
{ // then take it
s = i.e_name; // mention 3rd component
s.append( " + ( " ); // in series
s.append( m_cmb_lut[j].e_name ); // with 2R combination
s.append( m_cmb_lut.at( 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
m_results.at( S3R ).e_name = s; // save S3R result
m_results.at( S3R ).e_value = tmp; // save amount of benefit
m_results.at( S3R ).e_use = true; // enable later use
}
tmp = i.e_value * m_cmb_lut[j].e_value /
( i.e_value + m_cmb_lut[j].e_value ); // calculate R + 2R parallel
tmp = i.e_value * m_cmb_lut.at( j ).e_value /
( i.e_value + m_cmb_lut.at( j ).e_value ); // calculate R + 2R parallel
tmp -= m_required_value; // calculate deviation
if( abs( tmp ) < abs( m_results[S3R].e_value ) ) // compare if better
if( abs( tmp ) < abs( m_results.at( S3R ).e_value ) ) // compare if better
{ // then take it
s = i.e_name; // mention 3rd component
s.append( " | ( " ); // in parallel
s.append( m_cmb_lut[j].e_name ); // with 2R combination
s.append( m_cmb_lut.at( 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
m_results.at( S3R ).e_name = s;
m_results.at( S3R ).e_value = tmp; // save amount of benefit
m_results.at( S3R ).e_use = true; // enable later use
}
}
}
@ -224,7 +330,7 @@ void E_SERIE::combine3( uint32_t aSize )
// 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 == true ) && tmp )
if(( m_results.at( S3R ).e_use == true ) && tmp )
combine4( aSize );
}
@ -236,7 +342,7 @@ void E_SERIE::Calculate()
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
if( m_results.at( S2R ).e_value ) // if simple 2R result is not exact
combine3( no_of_2Rcombi ); // continiue searching for a possibly better solution
strip3();
@ -248,16 +354,16 @@ void E_SERIE::strip3()
{
std::string s;
if( m_results[S3R].e_use ) // if there is a 3 term result available
if( m_results.at( 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;
s = m_results.at( 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( "(" ), 1 ); // it is known sure, this is available
s.erase( s.find( ")" ), 1 ); // in any unstripped 3R result term
m_results[S3R].e_name = s; // use stripped result
m_results.at( S3R ).e_name = s; // use stripped result
}
}
}
@ -267,18 +373,18 @@ void E_SERIE::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( m_results.at( S4R ).e_use ) // if there is a 4 term result available
{ // what are connected either by 3 "+" or by 3 "|"
s = m_results.at( 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( "(" ), 1 ); // it is known sure, they are available
s.erase( s.find( ")" ), 1 ); // in any unstripped 4R result term
{ // then strip two pair of braces
s.erase( s.find( "(" ), 1 ); // it is known sure, they are available
s.erase( s.find( ")" ), 1 ); // in any unstripped 4R result term
s.erase( s.find( "(" ), 1 );
s.erase( s.find( ")" ), 1 );
m_results[S4R].e_name = s; // use stripped result
m_results.at( S4R ).e_name = s; // use stripped result
}
}
}
@ -290,6 +396,8 @@ void PANEL_E_SERIE::OnCalculateESeries( wxCommandEvent& event )
double error, err3 = 0;
wxString es, fs; // error and formula strings
wxBusyCursor dummy;
reqr = ( 1000 * DoubleFromString( m_ResRequired->GetValue() ) );
r.SetRequiredValue( reqr ); // keep a local copy of required resistor value
r.NewCalc(); // assume all values available
@ -302,7 +410,19 @@ void PANEL_E_SERIE::OnCalculateESeries( wxCommandEvent& event )
r.Exclude( 1000 * DoubleFromString( m_ResRequired->GetValue()));
r.Exclude( 1000 * DoubleFromString( m_ResExclude1->GetValue()));
r.Exclude( 1000 * DoubleFromString( m_ResExclude2->GetValue()));
r.Calculate();
try
{
r.Calculate();
}
catch (std::out_of_range const& exc)
{
wxString msg;
msg << "Internal error: " << exc.what();
wxMessageBox( msg );
return;
}
fs = r.GetResults()[S2R].e_name; // show 2R solution formula string
m_ESeries_Sol2R->SetValue( fs );
@ -386,6 +506,8 @@ void PANEL_E_SERIE::OnESeriesSelection( wxCommandEvent& event )
r.SetSeries( E3 );
else if( event.GetEventObject() == m_e12 )
r.SetSeries( E12 );
else if( event.GetEventObject() == m_e24 )
r.SetSeries( E24 );
else
r.SetSeries( E6 );
}

View File

@ -31,86 +31,55 @@
* also used to lookup non calculable but readable BOM value strings. Supported E-series are:
*/
enum { E1, E3, E6, E12 };
// 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
#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
#define E6_VALUES 1.0, 1.5, 2.2, 3.3, 4.7, 6.8, 0.0
#define E3_VALUES 1.0, 2.2, 4.7, 0.0
#define E1_VALUES 1.0, 0.0
// First value of resistor in ohm
#define FIRST_VALUE 10
// last value of resistor in ohm
#define LAST_VALUE 1e6
/**
* 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 calcuation 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 };
enum { S2R, S3R, S4R };
/**
* 6 decade E-series values from 10 Ohms to 1M and its associated BOM strings.
* Series E3,E6,E12 are defined by additional values for cumulative use with previous series
*/
#define E1_VAL { true, "1K", 1000 },\
{ true, "10K", 10000 },\
{ true, "100K", 100000 },\
{ true, "10R", 10 },\
{ true, "100R", 100 },\
{ true, "1M", 1000000 }
#define E3_ADD { true, "22R", 22 },\
{ true, "47R", 47 },\
{ true, "220R", 220 },\
{ true, "470R", 470 },\
{ true, "2K2", 2200 },\
{ true, "4K7", 4700 },\
{ true, "22K", 22000 },\
{ true, "47K", 47000 },\
{ true, "220K", 220000 },\
{ true, "470K", 470000 }
#define E6_ADD { true, "15R", 15 },\
{ true, "33R", 33 },\
{ true, "68R", 68 },\
{ true, "150R", 150 },\
{ true, "330R", 330 },\
{ true, "680R", 680 },\
{ true, "1K5", 1500 },\
{ true, "3K3", 3300 },\
{ true, "6K8", 6800 },\
{ true, "15K", 15000 },\
{ true, "33K", 33000 },\
{ true, "68K", 68000 },\
{ true, "150K", 150000 },\
{ true, "330K", 330000 },\
{ true, "680K", 680000 }
#define E12_ADD { true, "12R", 12 },\
{ true, "18R", 18 },\
{ true, "27R", 27 },\
{ true, "39R", 39 },\
{ true, "56R", 56 },\
{ true, "82R", 82 },\
{ true, "120R", 120 },\
{ true, "180R", 180 },\
{ true, "270R", 270 },\
{ true, "390R", 390 },\
{ true, "560R", 560 },\
{ true, "820R", 820 },\
{ true, "1K2", 1200 },\
{ true, "1K8", 1800 },\
{ true, "2K7", 2700 },\
{ true, "3K9", 3900 },\
{ true, "5K6", 5600 },\
{ true, "8K2", 8200 },\
{ true, "12K", 12000 },\
{ true, "18K", 18000 },\
{ true, "27K", 27000 },\
{ true, "39K", 39000 },\
{ true, "56K", 56000 },\
{ true, "82K", 82000 },\
{ true, "120K", 120000 },\
{ true, "180K", 180000 },\
{ true, "270K", 270000 },\
{ true, "390K", 390000 },\
{ true, "560K", 560000 },\
{ true, "820K", 820000 }
// R_DATA handles a resitor: 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;
@ -119,6 +88,8 @@ struct R_DATA
class E_SERIE
{
public:
E_SERIE();
/**
* If any value of the selected E-serie not available, it can be entered as an exclude value.
*
@ -143,9 +114,18 @@ public:
void SetSeries( uint32_t aSeries ) { m_series = aSeries; }
void SetRequiredValue( double aValue ) { m_required_value = aValue; }
std::array<R_DATA,S4R+1> GetResults() { return m_results; }
// Accessor:
const std::array<R_DATA,S4R+1>& GetResults() { return m_results; }
private:
/**
* Build the list of R_DATA existing for a given serie
* Series are E1, E6 ..
* The values are extracted from the E96_VALUES list
* @return the count of items added in list
*/
int buildSerieData( int aEserie, double aList[] );
/**
* Build all 2R combinations from the selected E-serie values
*
@ -200,32 +180,20 @@ private:
void strip4();
private:
std::vector<std::vector<R_DATA>> m_luts
{
{ E1_VAL },
{ E1_VAL, E3_ADD },
{ E1_VAL, E3_ADD, E6_ADD },
{ E1_VAL, E3_ADD, E6_ADD, E12_ADD }
};
std::vector<std::vector<R_DATA>> m_luts;
/*
* TODO: Manual array size calculation is dangerous. Unlike legacy ANSI-C Arrays
* std::array can not drop length param by providing aggregate init list up
* to C++17. Reserved array size should be 2*E12² of std::vector primary list.
* Exceeding memory limit 7442 will crash the calculator without any warnings !
* Compare to previous MAX_COMB macro for legacy ANSI-C array automatic solution
* #define E12_SIZE sizeof ( e12_lut ) / sizeof ( R_DATA )
* #define MAX_COMB (2 * E12_SIZE * E12_SIZE)
/* Note: intermediate calculations use m_cmb_lut
* 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_cmb_lut; // intermediate 2R combinations
#define MAX_CMB 7442 // maximum combinations for E12
std::array<R_DATA, MAX_CMB> m_cmb_lut; // intermediate 2R combinations
std::array<R_DATA, S4R+1> m_results; // 2R, 3R and 4R results
uint32_t m_series = E6; // Radio Button State
uint32_t m_enable_4R = false; // Check Box 4R enable

View File

@ -1,16 +1,17 @@
// Do not edit this file, it is autogenerated by CMake from the .md file
_HKI( "E-series defined in IEC 60063 are a widely accepted system of preferred\n"
"numbers for electronic components. Available values are approximately\n"
"equally spaced in a logarithmic scale.\n"
_HKI( "E-series are defined in IEC 60063.\n"
"\n"
" E12: 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: 1.0 - 1.5 - 2.2 - 3.3 - 4.7 - 6.8 -\n"
" E3: 1.0 - - - 2.2 - - - 4.7 - - -\n"
" E1: 1.0 - - - - - - - - - - -\n"
"Available values are approximately equally spaced in a logarithmic scale.\n"
"\n"
"This calculator finds combinations of standard E-series components to\n"
"create arbitrary values. You can enter the required resistance from 0.0025 to 4000 kΩ.\n"
"Solutions using up to 4 components are given.\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"
"By default, the request value is always excluded from the solution set. It is also possible to specify\n"
"up to two additional values to exclude from the solution if these component values are not available\n"

View File

@ -1,15 +1,16 @@
E-series defined in IEC 60063 are a widely accepted system of preferred
numbers for electronic components. Available values are approximately
equally spaced in a logarithmic scale.
E-series are defined in IEC 60063.
E12: 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: 1.0 - 1.5 - 2.2 - 3.3 - 4.7 - 6.8 -
E3: 1.0 - - - 2.2 - - - 4.7 - - -
E1: 1.0 - - - - - - - - - - -
Available values are approximately equally spaced in a logarithmic scale.
This calculator finds combinations of standard E-series components to
create arbitrary values. You can enter the required resistance from 0.0025 to 4000 kΩ.
Solutions using up to 4 components are given.
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.
By default, the request value is always excluded from the solution set. It is also possible to specify
up to two additional values to exclude from the solution if these component values are not available