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
|
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 );
|
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,
|
bool SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName, const std::string& aParamValue,
|
||||||
SIM_VALUE_GRAMMAR::NOTATION aNotation )
|
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
|
// "level" and "version" are not really parameters - they're part of the type - so silently
|
||||||
// ignore them.
|
// ignore them.
|
||||||
if( aParamName == "level" || aParamName == "version" )
|
if( paramName == "level" || paramName == "version" )
|
||||||
return true;
|
|
||||||
|
|
||||||
// Ignore purely informative LTspice-specific parameters "mfg", "icrating", "vceo".
|
|
||||||
if( aParamName == "mfg" || aParamName == "icrating" || aParamName == "vceo" )
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Also ignore "type" parameter, because Ngspice does that too.
|
// Also ignore "type" parameter, because Ngspice does that too.
|
||||||
if( aParamName == "type" )
|
if( paramName == "type" )
|
||||||
return true;
|
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
|
// 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.
|
// function, it's generally for ".model" cards, not for instantiations.
|
||||||
|
|
||||||
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
|
||||||
|
|
||||||
auto paramIt = std::find_if( params.begin(), params.end(),
|
auto paramIt = std::find_if( params.begin(), params.end(),
|
||||||
[aParamName]( const PARAM& param )
|
[paramName]( const PARAM& param )
|
||||||
{
|
{
|
||||||
return !param.info.isSpiceInstanceParam
|
return !param.info.isSpiceInstanceParam
|
||||||
&& param.info.category != PARAM::CATEGORY::SUPERFLUOUS
|
&& param.info.category != PARAM::CATEGORY::SUPERFLUOUS
|
||||||
&& ( param.info.name == boost::to_lower_copy( aParamName )
|
&& ( param.info.name == boost::to_lower_copy( paramName )
|
||||||
|| param.info.name == boost::to_lower_copy( aParamName ) + "_" );
|
|| param.info.name == boost::to_lower_copy( paramName ) + "_" );
|
||||||
} );
|
} );
|
||||||
|
|
||||||
if( paramIt != params.end() )
|
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;
|
std::vector<PARAM::INFO> ngspiceParams = ModelInfo( getModelType() ).modelParams;
|
||||||
|
|
||||||
auto ngspiceParamIt = std::find_if( ngspiceParams.begin(), ngspiceParams.end(),
|
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() )
|
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 )
|
const std::string& aSpiceCode )
|
||||||
{
|
{
|
||||||
auto model = static_cast<SIM_MODEL_SPICE*>(
|
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
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -82,9 +82,9 @@ namespace SPICE_GRAMMAR
|
||||||
commentBackslashContinuation,
|
commentBackslashContinuation,
|
||||||
plusContinuation>,
|
plusContinuation>,
|
||||||
opt<garbage>> {};
|
opt<garbage>> {};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Token separator.
|
||||||
struct sep : sor<plus<continuation>,
|
struct sep : sor<plus<continuation>,
|
||||||
garbage> {};
|
garbage> {};
|
||||||
|
|
||||||
|
@ -105,13 +105,23 @@ namespace SPICE_GRAMMAR
|
||||||
not_one<' ', '\t', '=', '(', ')', ',', '*', '/', '^', ';'>>>
|
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 paramValue : token {};
|
||||||
|
|
||||||
struct paramValuePair : seq<param,
|
struct paramValuePair : seq<param,
|
||||||
sep,
|
sep,
|
||||||
paramValue> {};
|
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>,
|
struct dotModelAko : seq<opt<sep>,
|
||||||
if_must<seq<TAO_PEGTL_ISTRING( ".model" ),
|
if_must<seq<TAO_PEGTL_ISTRING( ".model" ),
|
||||||
sep,
|
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" );
|
tao::pegtl::string_input<> in( aSpiceCode, "Spice_Code" );
|
||||||
std::unique_ptr<tao::pegtl::parse_tree::node> root;
|
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 )
|
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 paramName;
|
||||||
std::string typeString;
|
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 modelName = node->children.at( 0 )->string();
|
||||||
std::string akoName = node->children.at( 1 )->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 )
|
if( !sourceModel )
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,7 +34,8 @@ class SIM_LIBRARY_SPICE;
|
||||||
class SPICE_MODEL_PARSER
|
class SPICE_MODEL_PARSER
|
||||||
{
|
{
|
||||||
public:
|
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 ) {}
|
SPICE_MODEL_PARSER( SIM_MODEL_SPICE& aModel ) : m_model( aModel ) {}
|
||||||
virtual ~SPICE_MODEL_PARSER() = default;
|
virtual ~SPICE_MODEL_PARSER() = default;
|
||||||
|
|
Loading…
Reference in New Issue