Sim: LTspice model compat: Ignore spurious values

Also fix parsing type in ako models
This commit is contained in:
Mikolaj Wielgus 2022-10-04 22:41:19 +02:00
parent a11c40197f
commit e99d531c88
6 changed files with 62 additions and 21 deletions

View File

@ -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<int>( GetModelNames().size() ); ++i )
{
std::string curModelName = GetModelNames().at( i );

View File

@ -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<std::reference_wrapper<const PARAM>> 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<PARAM::INFO> 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() )

View File

@ -55,7 +55,7 @@ std::unique_ptr<SIM_MODEL_SPICE> SIM_MODEL_SPICE::Create( const SIM_LIBRARY_SPIC
const std::string& aSpiceCode )
{
auto model = static_cast<SIM_MODEL_SPICE*>(
SIM_MODEL::Create( SPICE_MODEL_PARSER::ReadType( aSpiceCode ) ).release() );
SIM_MODEL::Create( SPICE_MODEL_PARSER::ReadType( aLibrary, aSpiceCode ) ).release() );
try
{

View File

@ -82,9 +82,9 @@ namespace SPICE_GRAMMAR
commentBackslashContinuation,
plusContinuation>,
opt<garbage>> {};
// Token separator.
struct sep : sor<plus<continuation>,
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<param,
sep,
paramValue> {};
struct paramValuePairs : list<paramValuePair, sep> {};
struct paramValuePairs : list<sor<paramValuePair,
// In some LTspice models there are spurious values without
// specified parameter name. Ngspice ignores these, and we
// follow suit.
// TODO: Possibly create an LTspice compatibility mode, so
// that we don't have to silently ignore values blanketly.
token>,
sep> {};
struct dotModelAko : seq<opt<sep>,
if_must<seq<TAO_PEGTL_ISTRING( ".model" ),
sep,

View File

@ -50,7 +50,8 @@ namespace SIM_MODEL_SPICE_PARSER
}
SIM_MODEL::TYPE SPICE_MODEL_PARSER::ReadType( const std::string& aSpiceCode )
SIM_MODEL::TYPE SPICE_MODEL_PARSER::ReadType( const SIM_LIBRARY_SPICE& aLibrary,
const std::string& aSpiceCode )
{
tao::pegtl::string_input<> in( aSpiceCode, "Spice_Code" );
std::unique_ptr<tao::pegtl::parse_tree::node> 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<SIM_MODEL_SPICE_PARSER::dotModel>() )
if( node->is_type<SIM_MODEL_SPICE_PARSER::dotModelAko>() )
{
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<SIM_MODEL_SPICE_PARSER::dotModel>() )
{
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 )
{

View File

@ -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;