Browse Source
Move eseries helper class to common.
Move eseries helper class to common.
Also improves some terminology for english-speakers. Also substitues [] vector access (which creates empty elements) over at() (which throws if the item is not found).7.0
16 changed files with 731 additions and 718 deletions
-
5common/CMakeLists.txt
-
386common/eseries.cpp
-
5eeschema/dialogs/dialog_lib_symbol_properties.cpp
-
5eeschema/dialogs/dialog_symbol_properties.cpp
-
50include/eseries.h
-
9pcb_calculator/CMakeLists.txt
-
74pcb_calculator/calculator_panels/panel_eserie.cpp
-
199pcb_calculator/calculator_panels/panel_eseries.cpp
-
25pcb_calculator/calculator_panels/panel_eseries.h
-
101pcb_calculator/calculator_panels/panel_eseries_base.cpp
-
56pcb_calculator/calculator_panels/panel_eseries_base.fbp
-
14pcb_calculator/calculator_panels/panel_eseries_base.h
-
512pcb_calculator/eserie.cpp
-
0pcb_calculator/eseries_help.h
-
0pcb_calculator/eseries_help.md
-
8pcb_calculator/pcb_calculator_frame.cpp
@ -0,0 +1,386 @@ |
|||
/*
|
|||
* This program source code file |
|||
* is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020 <janvi@veith.net> |
|||
* Copyright (C) 2021-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/>.
|
|||
*/ |
|||
|
|||
#include <array>
|
|||
#include <algorithm>
|
|||
#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; |
|||
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_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( ; ; ) |
|||
{ |
|||
double curr_r; |
|||
|
|||
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; |
|||
} |
|||
|
|||
m_tables.push_back( std::move( curr_list ) ); |
|||
|
|||
return count; |
|||
} |
|||
|
|||
|
|||
void E_SERIES::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 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( abs( m_combined_table.at( i ).e_value - m_required_value ) < 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( abs( tmp ) < 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( abs( tmp ) < 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 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( abs( tmp ) < 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( abs( tmp ) < 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( '(' ), 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
|
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
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( '(' ), 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
|
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
@ -1,74 +0,0 @@ |
|||
/*
|
|||
* This program source code file is part of KICAD, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2011 jean-pierre.charras |
|||
* Copyright (C) 1992-2021 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/>.
|
|||
*/ |
|||
|
|||
/* see
|
|||
* http://www.desmith.net/NMdS/Electronics/TraceWidth.html
|
|||
* http://www.ultracad.com/articles/pcbtemp.pdf
|
|||
* for more info |
|||
*/ |
|||
|
|||
#include <calculator_panels/panel_eserie.h>
|
|||
#include <pcb_calculator_settings.h>
|
|||
#include <string_utils.h>
|
|||
|
|||
#include <i18n_utility.h> // For _HKI definition
|
|||
wxString eseries_help = |
|||
#include "eserie_help.h"
|
|||
|
|||
|
|||
PANEL_E_SERIE::PANEL_E_SERIE( wxWindow* parent, wxWindowID id, |
|||
const wxPoint& pos, const wxSize& size, |
|||
long style, const wxString& name ) : |
|||
PANEL_E_SERIE_BASE( parent, id, pos, size, style, name ) |
|||
{ |
|||
m_reqResUnits->SetLabel( wxT( "kΩ" ) ); |
|||
m_exclude1Units->SetLabel( wxT( "kΩ" ) ); |
|||
m_exclude2Units->SetLabel( wxT( "kΩ" ) ); |
|||
|
|||
// show markdown formula explanation in lower help panel
|
|||
wxString msg; |
|||
ConvertMarkdown2Html( wxGetTranslation( eseries_help ), msg ); |
|||
m_panelESeriesHelp->SetPage( msg ); |
|||
|
|||
// Needed on wxWidgets 3.0 to ensure sizers are correctly set
|
|||
GetSizer()->SetSizeHints( this ); |
|||
} |
|||
|
|||
|
|||
PANEL_E_SERIE::~PANEL_E_SERIE() |
|||
{ |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIE::ThemeChanged() |
|||
{ |
|||
// Update the HTML window with the help text
|
|||
m_panelESeriesHelp->ThemeChanged(); |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIE::SaveSettings( PCB_CALCULATOR_SETTINGS* aCfg ) |
|||
{ |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIE::LoadSettings( PCB_CALCULATOR_SETTINGS* aCfg ) |
|||
{ |
|||
} |
|||
@ -0,0 +1,199 @@ |
|||
/*
|
|||
* 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. |
|||
* |
|||
* 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/>.
|
|||
*/ |
|||
|
|||
/* see
|
|||
* http://www.desmith.net/NMdS/Electronics/TraceWidth.html
|
|||
* http://www.ultracad.com/articles/pcbtemp.pdf
|
|||
* for more info |
|||
*/ |
|||
|
|||
#include <calculator_panels/panel_eseries.h>
|
|||
#include <pcb_calculator_settings.h>
|
|||
#include <string_utils.h>
|
|||
#include <wx/msgdlg.h>
|
|||
|
|||
#include <i18n_utility.h> // For _HKI definition in eseries_help.h
|
|||
wxString eseries_help = |
|||
#include "eseries_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 ) |
|||
{ |
|||
m_reqResUnits->SetLabel( wxT( "kΩ" ) ); |
|||
m_exclude1Units->SetLabel( wxT( "kΩ" ) ); |
|||
m_exclude2Units->SetLabel( wxT( "kΩ" ) ); |
|||
|
|||
// show markdown formula explanation in lower help panel
|
|||
wxString msg; |
|||
ConvertMarkdown2Html( wxGetTranslation( eseries_help ), msg ); |
|||
m_panelESeriesHelp->SetPage( msg ); |
|||
|
|||
// Needed on wxWidgets 3.0 to ensure sizers are correctly set
|
|||
GetSizer()->SetSizeHints( this ); |
|||
} |
|||
|
|||
|
|||
PANEL_E_SERIES::~PANEL_E_SERIES() |
|||
{ |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIES::ThemeChanged() |
|||
{ |
|||
// Update the HTML window with the help text
|
|||
m_panelESeriesHelp->ThemeChanged(); |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIES::SaveSettings( PCB_CALCULATOR_SETTINGS* aCfg ) |
|||
{ |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIES::LoadSettings( PCB_CALCULATOR_SETTINGS* aCfg ) |
|||
{ |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIES::OnCalculateESeries( wxCommandEvent& event ) |
|||
{ |
|||
double reqr; // required resistor stored in local copy
|
|||
double error, err3 = 0; |
|||
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
|
|||
/*
|
|||
* 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())); |
|||
|
|||
try |
|||
{ |
|||
m_eSeries.Calculate(); |
|||
} |
|||
catch (std::out_of_range const& exc) |
|||
{ |
|||
wxString msg; |
|||
msg << "Internal error: " << exc.what(); |
|||
|
|||
wxMessageBox( msg ); |
|||
return; |
|||
} |
|||
|
|||
fs = m_eSeries.GetResults()[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
|
|||
|
|||
if( error ) |
|||
{ |
|||
if( std::abs( error ) < 0.01 ) |
|||
es.Printf( "<%.2f", 0.01 ); |
|||
else |
|||
es.Printf( "%+.2f",error); |
|||
} |
|||
else |
|||
{ |
|||
es = _( "Exact" ); |
|||
} |
|||
|
|||
m_ESeriesError2R->SetValue( es ); // anyway show 2R error string
|
|||
|
|||
if( m_eSeries.GetResults()[S3R].e_use ) // if 3R solution available
|
|||
{ |
|||
err3 = reqr + m_eSeries.GetResults()[S3R].e_value; // calculate the 3R
|
|||
err3 = ( reqr / err3 - 1 ) * 100; // error in percent
|
|||
|
|||
if( err3 ) |
|||
{ |
|||
if( std::abs( err3 ) < 0.01 ) |
|||
es.Printf( "<%.2f", 0.01 ); |
|||
else |
|||
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
|
|||
} |
|||
else // nothing better than 2R found
|
|||
{ |
|||
fs = _( "Not worth using" ); |
|||
m_ESeries_Sol3R->SetValue( fs ); |
|||
m_ESeriesError3R->SetValue( wxEmptyString ); |
|||
} |
|||
|
|||
fs = wxEmptyString; |
|||
|
|||
if( m_eSeries.GetResults()[S4R].e_use ) // show 4R solution if available
|
|||
{ |
|||
fs = m_eSeries.GetResults()[S4R].e_name; |
|||
|
|||
error = reqr + m_eSeries.GetResults()[S4R].e_value; // absolute value of solution
|
|||
error = ( reqr / error - 1 ) * 100; // error in percent
|
|||
|
|||
if( error ) |
|||
es.Printf( "%+.2f",error ); |
|||
else |
|||
es = _( "Exact" ); |
|||
|
|||
m_ESeriesError4R->SetValue( es ); |
|||
} |
|||
else // no 4R solution
|
|||
{ |
|||
fs = _( "Not worth using" ); |
|||
es = wxEmptyString; |
|||
m_ESeriesError4R->SetValue( es ); |
|||
} |
|||
|
|||
m_ESeries_Sol4R->SetValue( fs ); |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIES::OnESeriesSelection( wxCommandEvent& event ) |
|||
{ |
|||
if( event.GetEventObject() == m_e1 ) |
|||
m_eSeries.SetSeries( E1 ); |
|||
else if( event.GetEventObject() == m_e3 ) |
|||
m_eSeries.SetSeries( E3 ); |
|||
else if( event.GetEventObject() == m_e12 ) |
|||
m_eSeries.SetSeries( E12 ); |
|||
else if( event.GetEventObject() == m_e24 ) |
|||
m_eSeries.SetSeries( E24 ); |
|||
else |
|||
m_eSeries.SetSeries( E6 ); |
|||
} |
|||
@ -1,512 +0,0 @@ |
|||
/*
|
|||
* This program source code file |
|||
* is part of KiCad, a free EDA CAD application. |
|||
* |
|||
* Copyright (C) 2020 <janvi@veith.net> |
|||
* Copyright (C) 2021 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 <array>
|
|||
#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 |
|||
*/ |
|||
//#define BENCHMARK
|
|||
|
|||
#ifdef BENCHMARK
|
|||
#include <profile.h>
|
|||
#endif
|
|||
|
|||
#include "eserie.h"
|
|||
|
|||
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
|
|||
{ |
|||
for( R_DATA& i : m_luts[m_series] ) // then search it in the selected E-Serie lookup table
|
|||
{ |
|||
if( i.e_value == aValue ) // if the value to exclude is found
|
|||
i.e_use = false; // disable its use
|
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void E_SERIE::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( abs( m_cmb_lut.at( i ).e_value - m_required_value ) < abs( m_results.at( S2R ).e_value ) ) |
|||
{ |
|||
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
|
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void E_SERIE::combine4( uint32_t aSize ) |
|||
{ |
|||
uint32_t i,j; |
|||
double tmp; |
|||
|
|||
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_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_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.at(S4R).e_value ) ) // if new 4R is better
|
|||
{ |
|||
m_results.at( S4R ).e_value = tmp; // save amount of benefit
|
|||
std::string s = "( "; |
|||
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.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.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.at( S4R ).e_value ) ) // if new 4R is better
|
|||
{ |
|||
m_results.at( S4R ).e_value = tmp; // save amount of benefit
|
|||
std::string s = "( "; |
|||
s.append( m_cmb_lut.at( i ).e_name ); // mention 1st 2 component
|
|||
s.append( " ) | ( " ); // in parallel
|
|||
s.append( m_cmb_lut.at( j ).e_name ); // with 2nd 2 components
|
|||
s.append( " )" ); |
|||
m_results.at( S4R ).e_name = s; // save the result
|
|||
m_results.at( S4R ).e_use = true; // enable later use
|
|||
} |
|||
} |
|||
} |
|||
|
|||
#ifdef BENCHMARK
|
|||
printf( "Calculation time = %d mS", timer.msecs() ); |
|||
fflush( 0 ); |
|||
#endif
|
|||
} |
|||
|
|||
|
|||
void E_SERIE::NewCalc() |
|||
{ |
|||
for( R_DATA& i : m_cmb_lut ) |
|||
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_luts[m_series]) |
|||
i.e_use = true; // all selected E-values available
|
|||
} |
|||
|
|||
|
|||
uint32_t E_SERIE::combine2() |
|||
{ |
|||
uint32_t combi2R = 0; // target index counts calculated 2R combinations
|
|||
std::string s; |
|||
|
|||
for( const R_DATA& i : m_luts[m_series] ) // outer loop to sweep selected source lookup table
|
|||
{ |
|||
if( i.e_use ) |
|||
{ |
|||
for( const R_DATA& j : m_luts[m_series] ) // inner loop to combine values with itself
|
|||
{ |
|||
if( j.e_use ) |
|||
{ |
|||
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.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.at( combi2R ).e_name = s.append( j.e_name ); |
|||
combi2R++; // next destination
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
return combi2R; |
|||
} |
|||
|
|||
|
|||
void E_SERIE::combine3( uint32_t aSize ) |
|||
{ |
|||
uint32_t j = 0; |
|||
double tmp = 0; // avoid warning for being uninitialized
|
|||
std::string s; |
|||
|
|||
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
|
|||
{ |
|||
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_cmb_lut.at( j ).e_value + i.e_value; |
|||
tmp -= m_required_value; // calculate deviation
|
|||
|
|||
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.at( j ).e_name ); // with 2R combination
|
|||
s.append( " )" ); |
|||
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.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.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.at( j ).e_name ); // with 2R combination
|
|||
s.append( " )" ); |
|||
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
|
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// 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.at( S3R ).e_use == true ) && tmp ) |
|||
combine4( aSize ); |
|||
} |
|||
|
|||
|
|||
void E_SERIE::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.at( 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_SERIE::strip3() |
|||
{ |
|||
std::string s; |
|||
|
|||
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.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.at( S3R ).e_name = s; // use stripped result
|
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void E_SERIE::strip4() |
|||
{ |
|||
std::string s; |
|||
|
|||
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
|
|||
s.erase( s.find( "(" ), 1 ); |
|||
s.erase( s.find( ")" ), 1 ); |
|||
m_results.at( S4R ).e_name = s; // use stripped result
|
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIE::OnCalculateESeries( wxCommandEvent& event ) |
|||
{ |
|||
double reqr; // required resistor stored in local copy
|
|||
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
|
|||
/*
|
|||
* 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 |
|||
*/ |
|||
r.Exclude( 1000 * DoubleFromString( m_ResRequired->GetValue())); |
|||
r.Exclude( 1000 * DoubleFromString( m_ResExclude1->GetValue())); |
|||
r.Exclude( 1000 * DoubleFromString( m_ResExclude2->GetValue())); |
|||
|
|||
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 ); |
|||
error = reqr + r.GetResults()[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); |
|||
} |
|||
else |
|||
{ |
|||
es = _( "Exact" ); |
|||
} |
|||
|
|||
m_ESeriesError2R->SetValue( es ); // anyway show 2R error string
|
|||
|
|||
if( r.GetResults()[S3R].e_use ) // if 3R solution available
|
|||
{ |
|||
err3 = reqr + r.GetResults()[S3R].e_value; // calculate the 3R
|
|||
err3 = ( reqr / err3 - 1 ) * 100; // error in percent
|
|||
|
|||
if( err3 ) |
|||
{ |
|||
if( std::abs( err3 ) < 0.01 ) |
|||
es.Printf( "<%.2f", 0.01 ); |
|||
else |
|||
es.Printf( "%+.2f",err3); |
|||
} |
|||
else |
|||
{ |
|||
es = _( "Exact" ); |
|||
} |
|||
|
|||
m_ESeriesError3R->SetValue( es ); // show 3R error string
|
|||
fs = r.GetResults()[S3R].e_name; |
|||
m_ESeries_Sol3R->SetValue( fs ); // show 3R formula string
|
|||
} |
|||
else // nothing better than 2R found
|
|||
{ |
|||
fs = _( "Not worth using" ); |
|||
m_ESeries_Sol3R->SetValue( fs ); |
|||
m_ESeriesError3R->SetValue( wxEmptyString ); |
|||
} |
|||
|
|||
fs = wxEmptyString; |
|||
|
|||
if( r.GetResults()[S4R].e_use ) // show 4R solution if available
|
|||
{ |
|||
fs = r.GetResults()[S4R].e_name; |
|||
|
|||
error = reqr + r.GetResults()[S4R].e_value; // absolute value of solution
|
|||
error = ( reqr / error - 1 ) * 100; // error in percent
|
|||
|
|||
if( error ) |
|||
es.Printf( "%+.2f",error ); |
|||
else |
|||
es = _( "Exact" ); |
|||
|
|||
m_ESeriesError4R->SetValue( es ); |
|||
} |
|||
else // no 4R solution
|
|||
{ |
|||
fs = _( "Not worth using" ); |
|||
es = wxEmptyString; |
|||
m_ESeriesError4R->SetValue( es ); |
|||
} |
|||
|
|||
m_ESeries_Sol4R->SetValue( fs ); |
|||
} |
|||
|
|||
|
|||
void PANEL_E_SERIE::OnESeriesSelection( wxCommandEvent& event ) |
|||
{ |
|||
if( event.GetEventObject() == m_e1 ) |
|||
r.SetSeries( E1 ); |
|||
else if( event.GetEventObject() == m_e3 ) |
|||
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 ); |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue