Sim: LTspice model compat: Ignore spurious values
Also fix parsing type in ako models
This commit is contained in:
parent
a11c40197f
commit
e99d531c88
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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() )
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue