/* * This program source code file * is part of KiCad, a free EDA CAD application. * * Copyright (C) 2020 * Copyright (C) 2020 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 . */ #include #include #include #include #include #include #ifdef BENCHMARK #include #endif #include #include "eserie.h" #include "profile.h" wxString eseries_help = #include "eserie_help.h" eserie r; void eserie::set_reqR( double aR ) { reqR = aR; } void eserie::set_rb( uint32_t a_rb ) { rb_state = a_rb; } uint32_t eserie::get_rb( void ) { return rb_state; } std::array eserie::get_rslt( void ) { return results; } void eserie::exclude( double aValue ) { if( aValue ) // if there is a value to exclude other than a wire jumper { for( r_data& i : luts[rb_state] ) // then search it in the selected E-Serie lookup table { if( i.e_value == aValue ) // if value to exclude found { i.e_use = false; // disable its use } } } } void eserie::simple_solution( uint32_t aSize ) { uint32_t i; results[S2R].e_value = std::numeric_limits::max(); // assume no 2R solution or max deviation for( i = 0; i < aSize; i++ ) { if( abs( cmb_lut[i].e_value - reqR ) < abs( results[S2R].e_value ) ) { results[S2R].e_value = cmb_lut[i].e_value - reqR; // save signed deviation in Ohms results[S2R].e_name = cmb_lut[i].e_name; // save combination text results[S2R].e_use = true; // this is a possible solution } } } void eserie::combine4( uint32_t aSize ) { uint32_t i,j; double tmp; std::string s; results[S4R].e_use = false; // disable 4R solution, until results[S4R].e_value = results[S3R].e_value; // 4R becomes better than 3R solution #ifdef BENCHMARK PROF_COUNTER combine4_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 = cmb_lut[i].e_value + cmb_lut[j].e_value; // calculate 2R+2R serial tmp -= reqR; // calculate 4R deviation if( abs( tmp ) < abs( results[S4R].e_value ) ) // if new 4R is better { results[S4R].e_value = tmp; // save amount of benefit std::string s = "( "; s.append( cmb_lut[i].e_name ); // mention 1st 2 component s.append( " ) + ( " ); // in series s.append( cmb_lut[j].e_name ); // with 2nd 2 components s.append( " )" ); results[S4R].e_name = s; // save the result and results[S4R].e_use = true; // enable for later use } tmp = ( cmb_lut[i].e_value * cmb_lut[j].e_value ) / ( cmb_lut[i].e_value + cmb_lut[j].e_value ); // calculate 2R|2R parallel tmp -= reqR; // calculate 4R deviation if( abs( tmp ) < abs( results[S4R].e_value ) ) // if new 4R is better { results[S4R].e_value = tmp; // save amount of benefit std::string s = "( "; s.append( cmb_lut[i].e_name ); // mention 1st 2 component s.append( " ) | ( " ); // in parallel s.append( cmb_lut[j].e_name ); // with 2nd 2 components s.append( " )" ); results[S4R].e_name = s; // save the result results[S4R].e_use = true; // enable later use } } } #ifdef BENCHMARK if( rb_state == E12 ) { std::cout<<"4R Time = "<GetValue() ) ); r.set_reqR(reqr); // keep a local copy of requred resistor value r.new_calc(); // 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 availabe. * 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() ) ); r.calculate(); fs = r.get_rslt()[S2R].e_name; // show 2R solution formula string m_ESeries_Sol2R->SetValue( fs ); error = reqr + r.get_rslt()[S2R].e_value; // absolute value of solution error = ( reqr / error - 1 ) * 100; // error in percent if( error ) { es.Printf( "%+.2f",error); // if 2R solution with error } else { es = "Exact"; // 2R solution is already exact } m_ESeriesError2R->SetValue( es ); // anyway show 2R error string if( r.get_rslt()[S3R].e_use ) // if 3R solution available { err3 = reqr + r.get_rslt()[S3R].e_value; // calculate the 3R err3 = ( reqr / err3 - 1 ) * 100; // error in percent if( err3 ) // build 3R error string { es.Printf( "%+.2f",err3); } else { es = "Exact"; } m_ESeriesError3R->SetValue( es ); // show 3R error string fs = r.get_rslt()[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.get_rslt()[S4R].e_use ) // show 4R solution if available { fs = r.get_rslt()[S4R].e_name; error = reqr + r.get_rslt()[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 PCB_CALCULATOR_FRAME::OnESerieSelection( wxCommandEvent& event ) { r.set_rb ( event.GetSelection() ); } void PCB_CALCULATOR_FRAME::ES_Init() // initialize ESeries tab at each pcb-calculator start { wxString msg; // show markdown formula explanation in lower help panel ConvertMarkdown2Html( wxGetTranslation( eseries_help ), msg ); m_panelESeriesHelp->SetPage( msg ); }