From e99d531c88c4cd701f0dd7a6b92ebea15d4a11a1 Mon Sep 17 00:00:00 2001 From: Mikolaj Wielgus Date: Tue, 4 Oct 2022 22:41:19 +0200 Subject: [PATCH] Sim: LTspice model compat: Ignore spurious values Also fix parsing type in ako models --- eeschema/sim/sim_library.cpp | 2 +- eeschema/sim/sim_model_ngspice.cpp | 35 ++++++++++++++++++++--------- eeschema/sim/sim_model_spice.cpp | 2 +- eeschema/sim/spice_grammar.h | 18 +++++++++++---- eeschema/sim/spice_model_parser.cpp | 23 ++++++++++++++++--- eeschema/sim/spice_model_parser.h | 3 ++- 6 files changed, 62 insertions(+), 21 deletions(-) diff --git a/eeschema/sim/sim_library.cpp b/eeschema/sim/sim_library.cpp index 5db8672a22..743df77c33 100644 --- a/eeschema/sim/sim_library.cpp +++ b/eeschema/sim/sim_library.cpp @@ -50,7 +50,7 @@ void SIM_LIBRARY::ReadFile( const std::string& aFilePath ) SIM_MODEL* SIM_LIBRARY::FindModel( const std::string& aModelName ) const { - for( unsigned i = 0; i < GetModelNames().size(); ++i ) + for( int i = 0; i < static_cast( GetModelNames().size() ); ++i ) { std::string curModelName = GetModelNames().at( i ); diff --git a/eeschema/sim/sim_model_ngspice.cpp b/eeschema/sim/sim_model_ngspice.cpp index d081d7b3c6..c5254ddf4e 100644 --- a/eeschema/sim/sim_model_ngspice.cpp +++ b/eeschema/sim/sim_model_ngspice.cpp @@ -84,31 +84,44 @@ SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType ) : bool SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName, const std::string& aParamValue, SIM_VALUE_GRAMMAR::NOTATION aNotation ) { + std::string paramName = boost::to_lower_copy( aParamName ); + // "level" and "version" are not really parameters - they're part of the type - so silently // ignore them. - if( aParamName == "level" || aParamName == "version" ) - return true; - - // Ignore purely informative LTspice-specific parameters "mfg", "icrating", "vceo". - if( aParamName == "mfg" || aParamName == "icrating" || aParamName == "vceo" ) + if( paramName == "level" || paramName == "version" ) return true; // Also ignore "type" parameter, because Ngspice does that too. - if( aParamName == "type" ) + if( paramName == "type" ) return true; + if( GetDeviceType() == DEVICE_TYPE_::NPN || GetDeviceType() == DEVICE_TYPE_::PNP ) + { + // Ignore the purely informative LTspice-specific parameters "mfg", "icrating", "vceo". + if( paramName == "mfg" || paramName == "icrating" || paramName == "vceo" ) + return true; + + // Ignore unused parameters. + if( paramName == "bvcbo" || paramName == "nbvcbo" + || paramName == "tbvcbo1" || paramName == "tbvcbo2" + || paramName == "bvbe" || paramName == "ibvbe" || paramName == "nbvbe" ) + { + return true; + } + } + // First we try to use the name as is. Note that you can't set instance parameters from this // function, it's generally for ".model" cards, not for instantiations. std::vector> params = GetParams(); auto paramIt = std::find_if( params.begin(), params.end(), - [aParamName]( const PARAM& param ) + [paramName]( const PARAM& param ) { return !param.info.isSpiceInstanceParam && param.info.category != PARAM::CATEGORY::SUPERFLUOUS - && ( param.info.name == boost::to_lower_copy( aParamName ) - || param.info.name == boost::to_lower_copy( aParamName ) + "_" ); + && ( param.info.name == boost::to_lower_copy( paramName ) + || param.info.name == boost::to_lower_copy( paramName ) + "_" ); } ); if( paramIt != params.end() ) @@ -121,9 +134,9 @@ bool SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName, co std::vector ngspiceParams = ModelInfo( getModelType() ).modelParams; auto ngspiceParamIt = std::find_if( ngspiceParams.begin(), ngspiceParams.end(), - [aParamName]( const PARAM& param ) + [paramName]( const PARAM& param ) { - return param.info.name == boost::to_lower_copy( aParamName ); + return param.info.name == boost::to_lower_copy( paramName ); } ); if( ngspiceParamIt == ngspiceParams.end() ) diff --git a/eeschema/sim/sim_model_spice.cpp b/eeschema/sim/sim_model_spice.cpp index 2217fabb8d..030ad7d943 100644 --- a/eeschema/sim/sim_model_spice.cpp +++ b/eeschema/sim/sim_model_spice.cpp @@ -55,7 +55,7 @@ std::unique_ptr SIM_MODEL_SPICE::Create( const SIM_LIBRARY_SPIC const std::string& aSpiceCode ) { auto model = static_cast( - SIM_MODEL::Create( SPICE_MODEL_PARSER::ReadType( aSpiceCode ) ).release() ); + SIM_MODEL::Create( SPICE_MODEL_PARSER::ReadType( aLibrary, aSpiceCode ) ).release() ); try { diff --git a/eeschema/sim/spice_grammar.h b/eeschema/sim/spice_grammar.h index cc4f0b0b45..e8a6d2af96 100644 --- a/eeschema/sim/spice_grammar.h +++ b/eeschema/sim/spice_grammar.h @@ -82,9 +82,9 @@ namespace SPICE_GRAMMAR commentBackslashContinuation, plusContinuation>, opt> {}; - - + + // Token separator. struct sep : sor, garbage> {}; @@ -105,13 +105,23 @@ namespace SPICE_GRAMMAR not_one<' ', '\t', '=', '(', ')', ',', '*', '/', '^', ';'>>> {}; - struct param : token {}; + // Param names cannot be `token` because LTspice models contain spurious values without + // parameter names, which we need to skip. + struct param : identifier {}; + struct paramValue : token {}; struct paramValuePair : seq {}; - struct paramValuePairs : list {}; + struct paramValuePairs : list, + sep> {}; struct dotModelAko : seq, if_must in( aSpiceCode, "Spice_Code" ); std::unique_ptr root; @@ -71,7 +72,23 @@ SIM_MODEL::TYPE SPICE_MODEL_PARSER::ReadType( const std::string& aSpiceCode ) for( const auto& node : root->children ) { - if( node->is_type() ) + if( node->is_type() ) + { + std::string modelName = node->children.at( 0 )->string(); + std::string akoName = node->children.at( 1 )->string(); + const SIM_MODEL* sourceModel = aLibrary.FindModel( akoName ); + + if( !sourceModel ) + { + THROW_IO_ERROR( wxString::Format( + _( "Could not find model '%s' to copy for ako model '%s'" ), + akoName, + modelName ) ); + } + + return sourceModel->GetType(); + } + else if( node->is_type() ) { std::string paramName; std::string typeString; @@ -161,7 +178,7 @@ void SPICE_MODEL_PARSER::ReadModel( const SIM_LIBRARY_SPICE& aLibrary, std::string modelName = node->children.at( 0 )->string(); std::string akoName = node->children.at( 1 )->string(); - const SIM_MODEL* sourceModel = aLibrary.FindModel( modelName ); + const SIM_MODEL* sourceModel = aLibrary.FindModel( akoName ); if( !sourceModel ) { diff --git a/eeschema/sim/spice_model_parser.h b/eeschema/sim/spice_model_parser.h index 62802fffcb..828b205d08 100644 --- a/eeschema/sim/spice_model_parser.h +++ b/eeschema/sim/spice_model_parser.h @@ -34,7 +34,8 @@ class SIM_LIBRARY_SPICE; class SPICE_MODEL_PARSER { public: - static SIM_MODEL::TYPE ReadType( const std::string& aSpiceCode ); + static SIM_MODEL::TYPE ReadType( const SIM_LIBRARY_SPICE& aLibrary, + const std::string& aSpiceCode ); SPICE_MODEL_PARSER( SIM_MODEL_SPICE& aModel ) : m_model( aModel ) {} virtual ~SPICE_MODEL_PARSER() = default;