Sim: Support ako models

This commit is contained in:
Mikolaj Wielgus 2022-10-04 17:17:41 +02:00
parent c2765f40ca
commit 120b569048
16 changed files with 179 additions and 55 deletions

View File

@ -834,15 +834,22 @@ const SIM_MODEL::PARAM& SIM_MODEL::GetBaseParam( unsigned aParamIndex ) const
}
bool SIM_MODEL::SetParamValue( unsigned aParamIndex, const std::string& aValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation )
bool SIM_MODEL::SetParamValue( int aParamIndex, const SIM_VALUE& aValue )
{
return m_params.at( aParamIndex ).value->FromString( aValue, aNotation );
*m_params.at( aParamIndex ).value = aValue;
return true;
}
bool SIM_MODEL::SetParamValue( const std::string& aParamName, const std::string& aValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation )
bool SIM_MODEL::SetParamValue( int aParamIndex, const std::string& aValue,
SIM_VALUE::NOTATION aNotation )
{
const SIM_VALUE& value = *GetParam( aParamIndex ).value;
return SetParamValue( aParamIndex, *SIM_VALUE::Create( value.GetType(), aValue, aNotation ) );
}
bool SIM_MODEL::SetParamValue( const std::string& aParamName, const SIM_VALUE& aValue )
{
std::vector<std::reference_wrapper<const PARAM>> params = GetParams();
@ -855,7 +862,16 @@ bool SIM_MODEL::SetParamValue( const std::string& aParamName, const std::string&
if( it == params.end() )
return false;
return SetParamValue( it - params.begin(), aValue, aNotation );
SetParamValue( static_cast<int>( it - params.begin() ), aValue );
return true;
}
bool SIM_MODEL::SetParamValue( const std::string& aParamName, const std::string& aValue,
SIM_VALUE::NOTATION aNotation )
{
const SIM_VALUE& value = *FindParam( aParamName )->value;
return SetParamValue( aParamName, *SIM_VALUE::Create( value.GetType(), aValue, aNotation ) );
}

View File

@ -532,12 +532,13 @@ public:
const PARAM& GetUnderlyingParam( unsigned aParamIndex ) const; // Return the actual parameter.
const PARAM& GetBaseParam( unsigned aParamIndex ) const; // Always return base parameter if it exists.
virtual bool SetParamValue( unsigned aParamIndex, const std::string& aValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation
= SIM_VALUE_GRAMMAR::NOTATION::SI );
virtual bool SetParamValue( int aParamIndex, const SIM_VALUE& aValue );
bool SetParamValue( int aParamIndex, const std::string& aValue,
SIM_VALUE::NOTATION aNotation = SIM_VALUE::NOTATION::SI );
bool SetParamValue( const std::string& aParamName, const SIM_VALUE& aValue );
bool SetParamValue( const std::string& aParamName, const std::string& aValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation = SIM_VALUE_GRAMMAR::NOTATION::SI );
SIM_VALUE::NOTATION aNotation = SIM_VALUE::NOTATION::SI );
bool HasOverrides() const;
bool HasNonInstanceOverrides() const;

View File

@ -112,7 +112,8 @@ bool SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName, co
} );
if( paramIt != params.end() )
return SetParamValue( paramIt - params.begin(), aParamValue, aNotation );
return SIM_MODEL::SetParamValue( static_cast<int>( paramIt - params.begin() ), aParamValue,
aNotation );
// One Spice param can have multiple names, we need to take this into account.
@ -142,7 +143,8 @@ bool SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const std::string& aParamName, co
if( paramIt == params.end() )
return false;
return SetParamValue( paramIt - params.begin(), aParamValue, aNotation );
return SIM_MODEL::SetParamValue( static_cast<int>( paramIt - params.begin() ), aParamValue,
aNotation );
}

View File

@ -227,30 +227,29 @@ void SIM_MODEL_SOURCE::WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) con
}
bool SIM_MODEL_SOURCE::SetParamValue( unsigned aParamIndex, const std::string& aValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation )
bool SIM_MODEL_SOURCE::SetParamValue( int aParamIndex, const SIM_VALUE& aValue )
{
// Sources are special. All preceding parameter values must be filled. If they are not, fill
// them out automatically. If a value is nulled, delete everything after it.
if( aValue == "" )
if( !aValue.HasValue() )
{
for( int paramIndex = static_cast<int>( aParamIndex );
paramIndex < GetParamCount();
++paramIndex )
{
SIM_MODEL::SetParamValue( paramIndex, "", aNotation );
SIM_MODEL::SetParamValue( paramIndex, "" );
}
}
else
{
for( unsigned paramIndex = 0; paramIndex < aParamIndex; ++paramIndex )
for( int paramIndex = 0; paramIndex < aParamIndex; ++paramIndex )
{
if( GetParam( paramIndex ).value->ToString() == "" )
SIM_MODEL::SetParamValue( paramIndex, "0", aNotation );
SIM_MODEL::SetParamValue( paramIndex, "0" );
}
}
return SIM_MODEL::SetParamValue( aParamIndex, aValue, aNotation );
return SIM_MODEL::SetParamValue( aParamIndex, aValue );
}

View File

@ -69,9 +69,7 @@ public:
void WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const override;
void WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const override;
bool SetParamValue( unsigned aParamIndex, const std::string& aValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation = SIM_VALUE_GRAMMAR::NOTATION::SI )
override;
bool SetParamValue( int aParamIndex, const SIM_VALUE& aValue ) override;
bool HasAutofill() const override { return true; }

View File

@ -25,6 +25,7 @@
#include <sim/sim_model_spice.h>
#include <sim/sim_model_raw_spice.h>
#include <sim/spice_model_parser.h>
#include <sim/sim_library_spice.h>
#include <confirm.h>
#include <boost/algorithm/string/trim.hpp>
@ -50,14 +51,15 @@ std::string SPICE_GENERATOR_SPICE::Preview( const std::string& aModelName ) cons
}
std::unique_ptr<SIM_MODEL_SPICE> SIM_MODEL_SPICE::Create( const std::string& aSpiceCode )
std::unique_ptr<SIM_MODEL_SPICE> SIM_MODEL_SPICE::Create( const SIM_LIBRARY_SPICE& aLibrary,
const std::string& aSpiceCode )
{
auto model = static_cast<SIM_MODEL_SPICE*>(
SIM_MODEL::Create( SPICE_MODEL_PARSER::ReadType( aSpiceCode ) ).release() );
try
{
model->m_spiceModelParser->ReadModel( aSpiceCode );
model->m_spiceModelParser->ReadModel( aLibrary, aSpiceCode );
}
catch( const IO_ERROR& e )
{
@ -85,14 +87,13 @@ SIM_MODEL_SPICE::SIM_MODEL_SPICE( TYPE aType,
}
bool SIM_MODEL_SPICE::SetParamValue( unsigned aParamIndex, const std::string& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation )
bool SIM_MODEL_SPICE::SetParamValue( int aParamIndex, const SIM_VALUE& aValue )
{
// Models sourced from a library are immutable.
if( m_spiceCode != "" )
return false;
return SIM_MODEL::SetParamValue( aParamIndex, aParamValue, aNotation );
return SIM_MODEL::SetParamValue( aParamIndex, aValue );
}

View File

@ -29,6 +29,8 @@
#include <sim/spice_generator.h>
#include <sim/spice_model_parser.h>
class SIM_LIBRARY_SPICE;
class SPICE_GENERATOR_SPICE : public SPICE_GENERATOR
{
@ -45,7 +47,8 @@ public:
friend class SPICE_GENERATOR_SPICE;
friend class SPICE_MODEL_PARSER;
static std::unique_ptr<SIM_MODEL_SPICE> Create( const std::string& aSpiceCode );
static std::unique_ptr<SIM_MODEL_SPICE> Create( const SIM_LIBRARY_SPICE& aLibrary,
const std::string& aSpiceCode );
SIM_MODEL_SPICE( TYPE aType,
std::unique_ptr<SPICE_GENERATOR> aSpiceGenerator );
@ -55,9 +58,7 @@ public:
std::unique_ptr<SPICE_MODEL_PARSER> aSpiceModelParser );
protected:
bool SetParamValue( unsigned aParamIndex, const std::string& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation
= SIM_VALUE_GRAMMAR::NOTATION::SI ) override;
bool SetParamValue( int aParamIndex, const SIM_VALUE& aValue ) override;
virtual bool SetParamFromSpiceCode( const std::string& aParamName,
const std::string& aParamValue,

View File

@ -65,7 +65,8 @@ std::vector<std::string> SPICE_GENERATOR_SUBCKT::CurrentNames( const std::string
}
void SPICE_MODEL_PARSER_SUBCKT::ReadModel( const std::string& aSpiceCode )
void SPICE_MODEL_PARSER_SUBCKT::ReadModel( const SIM_LIBRARY_SPICE& aLibrary,
const std::string& aSpiceCode )
{
tao::pegtl::string_input<> in( aSpiceCode, "from_content" );
std::unique_ptr<tao::pegtl::parse_tree::node> root;

View File

@ -44,7 +44,7 @@ class SPICE_MODEL_PARSER_SUBCKT : public SPICE_MODEL_PARSER
public:
using SPICE_MODEL_PARSER::SPICE_MODEL_PARSER;
void ReadModel( const std::string& aSpiceCode ) override;
void ReadModel( const SIM_LIBRARY_SPICE& aLibrary, const std::string& aSpiceCode ) override;
};

View File

@ -359,10 +359,10 @@ std::string SIM_VALUE_PARSER::ExponentToMetricSuffix( double aExponent, int& aRe
}
std::unique_ptr<SIM_VALUE> SIM_VALUE::Create( TYPE aType, std::string aString )
std::unique_ptr<SIM_VALUE> SIM_VALUE::Create( TYPE aType, std::string aString, NOTATION aNotation )
{
std::unique_ptr<SIM_VALUE> value = SIM_VALUE::Create( aType );
value->FromString( aString );
value->FromString( aString, aNotation );
return value;
}
@ -411,6 +411,18 @@ template SIM_VALUE_COMPLEX::SIM_VALUE_INST( const std::complex<double>& aValue )
template SIM_VALUE_STRING::SIM_VALUE_INST( const std::string& aValue );
template <> SIM_VALUE::TYPE SIM_VALUE_BOOL::GetType() const { return TYPE_BOOL; }
template <> SIM_VALUE::TYPE SIM_VALUE_INT::GetType() const { return TYPE_INT; }
template <> SIM_VALUE::TYPE SIM_VALUE_FLOAT::GetType() const { return TYPE_FLOAT; }
template <> SIM_VALUE::TYPE SIM_VALUE_COMPLEX::GetType() const { return TYPE_FLOAT; }
template <> SIM_VALUE::TYPE SIM_VALUE_STRING::GetType() const { return TYPE_STRING; }
// TODO
/*template <> SIM_VALUE::TYPE SIM_VALUE_BOOL_VECTOR::GetType() const { return TYPE_BOOL; }
template <> SIM_VALUE::TYPE SIM_VALUE_INT_VECTOR::GetType() const { return TYPE_INT; }
template <> SIM_VALUE::TYPE SIM_VALUE_FLOAT_VECTOR::GetType() const { return TYPE_FLOAT; }
template <> SIM_VALUE::TYPE SIM_VALUE_COMPLEX_VECTOR::GetType() const { return TYPE_COMPLEX; }*/
template <typename T>
bool SIM_VALUE_INST<T>::HasValue() const
{
@ -639,6 +651,14 @@ std::string SIM_VALUE_COMPLEX::ToSimpleString() const
}
template <typename T>
void SIM_VALUE_INST<T>::operator=( const SIM_VALUE& aOther )
{
auto other = dynamic_cast<const SIM_VALUE_INST<T>*>( &aOther );
m_value = other->m_value;
}
template <typename T>
bool SIM_VALUE_INST<T>::operator==( const T& aOther ) const
{

View File

@ -65,15 +65,19 @@ public:
TYPE_COMPLEX_VECTOR
};
static std::unique_ptr<SIM_VALUE> Create( TYPE aType, std::string aString );
static std::unique_ptr<SIM_VALUE> Create( TYPE aType, std::string aString,
NOTATION aNotation = NOTATION::SI );
static std::unique_ptr<SIM_VALUE> Create( TYPE aType );
virtual ~SIM_VALUE() = default;
SIM_VALUE() = default;
virtual TYPE GetType() const = 0;
virtual bool HasValue() const = 0;
void operator=( const std::string& aString );
virtual void operator=( const SIM_VALUE& aValue ) = 0;
virtual bool operator==( const SIM_VALUE& aOther ) const = 0;
bool operator!=( const SIM_VALUE& aOther ) const;
@ -93,13 +97,16 @@ public:
SIM_VALUE_INST() = default;
SIM_VALUE_INST( const T& aValue );
TYPE GetType() const override;
bool HasValue() const override;
// TODO: Don't pass aNotation. Make a FromSpiceString() function instead.
// TODO: Don't use FromString(). Use assignment. Values should be immutable.
bool FromString( const std::string& aString, NOTATION aNotation = NOTATION::SI ) override;
std::string ToString( NOTATION aNotation = NOTATION::SI ) const override;
std::string ToSimpleString() const override;
void operator=( const SIM_VALUE& aOther ) override;
void operator=( const T& aValue );
bool operator==( const T& aOther ) const;
bool operator==( const SIM_VALUE& aOther ) const override;

View File

@ -102,7 +102,7 @@ namespace SPICE_GRAMMAR
struct token : seq<tokenStart,
star<not_at<eolf>,
not_at<backslashContinuation>,
not_one<' ', '\t', '=', '(', ')', ',', '+', '-', '*', '/', '^', ';'>>>
not_one<' ', '\t', '=', '(', ')', ',', '*', '/', '^', ';'>>>
{};
struct param : token {};
@ -112,6 +112,18 @@ namespace SPICE_GRAMMAR
sep,
paramValue> {};
struct paramValuePairs : list<paramValuePair, sep> {};
struct dotModelAko : seq<opt<sep>,
if_must<seq<TAO_PEGTL_ISTRING( ".model" ),
sep,
modelName,
sep,
TAO_PEGTL_ISTRING( "ako:" )>,
opt<sep>,
modelName,
opt<sep,
dotModelType>,
opt<sep,
paramValuePairs>>> {};
struct dotModel : seq<opt<sep>,
if_must<TAO_PEGTL_ISTRING( ".model" ),
sep,
@ -122,6 +134,7 @@ namespace SPICE_GRAMMAR
paramValuePairs>,
opt<sep>,
newline>> {};
struct dotSubcktPinName : seq<not_at<TAO_PEGTL_ISTRING( "params:" )>,
@ -147,7 +160,8 @@ namespace SPICE_GRAMMAR
spiceUnit>>> {};
struct modelUnit : sor<dotModel,
struct modelUnit : sor<dotModelAko,
dotModel,
dotSubckt> {};
@ -229,6 +243,8 @@ namespace SPICE_GRAMMAR
template <> inline constexpr auto errorMessage<opt<sep>> = "";
template <> inline constexpr auto errorMessage<modelName> = "expected model name";
template <> inline constexpr auto errorMessage<dotModelType> = "expected model type";
template <> inline constexpr auto errorMessage<opt<sep,
dotModelType>> = "";
template <> inline constexpr auto errorMessage<opt<sep,
paramValuePairs>> = "";
template <> inline constexpr auto errorMessage<opt<sep,

View File

@ -50,11 +50,11 @@ namespace SIM_LIBRARY_SPICE_PARSER
};
void SPICE_LIBRARY_PARSER::ReadFile( const wxString& aFilePath )
void SPICE_LIBRARY_PARSER::ReadFile( const std::string& aFilePath )
{
try
{
tao::pegtl::file_input in( aFilePath.ToStdString() );
tao::pegtl::file_input in( aFilePath );
auto root = tao::pegtl::parse_tree::parse<SIM_LIBRARY_SPICE_PARSER::libraryGrammar,
SIM_LIBRARY_SPICE_PARSER::librarySelector,
tao::pegtl::nothing,
@ -68,14 +68,7 @@ void SPICE_LIBRARY_PARSER::ReadFile( const wxString& aFilePath )
{
if( node->is_type<SIM_LIBRARY_SPICE_PARSER::modelUnit>() )
{
m_library.m_models.push_back( SIM_MODEL_SPICE::Create( node->string() ) );
if( node->children.size() < 1
|| !node->children.at( 0 )->is_type<SIM_LIBRARY_SPICE_PARSER::modelName>() )
{
THROW_IO_ERROR( wxString::Format( "Model name token not found" ) );
}
m_library.m_models.push_back( SIM_MODEL_SPICE::Create( m_library, node->string() ) );
m_library.m_modelNames.emplace_back( node->children.at( 0 )->string() );
}
else if( node->is_type<SIM_LIBRARY_SPICE_PARSER::unknownLine>() )

View File

@ -35,7 +35,7 @@ class SPICE_LIBRARY_PARSER
public:
SPICE_LIBRARY_PARSER( SIM_LIBRARY_SPICE& aLibrary ) : m_library( aLibrary ) {}
virtual void ReadFile( const wxString& aFilePath );
virtual void ReadFile( const std::string& aFilePath );
private:
SIM_LIBRARY_SPICE& m_library;

View File

@ -25,6 +25,7 @@
#include <sim/spice_model_parser.h>
#include <sim/spice_grammar.h>
#include <sim/sim_model_spice.h>
#include <sim/sim_library_spice.h>
#include <boost/algorithm/string/case_conv.hpp>
#include <boost/algorithm/string/predicate.hpp>
@ -38,6 +39,7 @@ namespace SIM_MODEL_SPICE_PARSER
template <typename Rule> struct spiceUnitSelector : std::false_type {};
template <> struct spiceUnitSelector<dotModelAko> : std::true_type {};
template <> struct spiceUnitSelector<dotModel> : std::true_type {};
template <> struct spiceUnitSelector<modelName> : std::true_type {};
template <> struct spiceUnitSelector<dotModelType> : std::true_type {};
@ -130,7 +132,8 @@ SIM_MODEL::TYPE SPICE_MODEL_PARSER::ReadType( const std::string& aSpiceCode )
}
void SPICE_MODEL_PARSER::ReadModel( const std::string& aSpiceCode )
void SPICE_MODEL_PARSER::ReadModel( const SIM_LIBRARY_SPICE& aLibrary,
const std::string& aSpiceCode )
{
// The default behavior is to treat the Spice param=value pairs as the model parameters and
// values (for many models the correspondence is not exact, so this function is overridden).
@ -153,9 +156,25 @@ void SPICE_MODEL_PARSER::ReadModel( 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 paramName = "";
std::string modelName = node->children.at( 0 )->string();
std::string akoName = node->children.at( 1 )->string();
const SIM_MODEL* sourceModel = aLibrary.FindModel( modelName );
if( !sourceModel )
{
THROW_IO_ERROR( wxString::Format(
_( "Could not find model '%s' to copy for ako model '%s'" ),
akoName,
modelName ) );
}
for( int i = 0; i < static_cast<int>( sourceModel->GetParamCount() ); ++i )
m_model.SetParamValue( i, *sourceModel->GetParam( i ).value );
std::string paramName;
for( const auto& subnode : node->children )
{
@ -178,9 +197,48 @@ void SPICE_MODEL_PARSER::ReadModel( const std::string& aSpiceCode )
if( !m_model.SetParamFromSpiceCode( paramName, subnode->string() ) )
{
THROW_IO_ERROR( wxString::Format(
_( "Failed to set parameter '%s' to '%s'" ),
_( "Failed to set parameter '%s' to '%s' in model '%s'" ),
paramName,
subnode->string() ) );
subnode->string(),
modelName ) );
}
}
else
{
wxFAIL_MSG( "Unhandled parse tree subnode" );
}
}
}
else if( node->is_type<SIM_MODEL_SPICE_PARSER::dotModel>() )
{
std::string modelName;
std::string paramName;
for( const auto& subnode : node->children )
{
if( subnode->is_type<SIM_MODEL_SPICE_PARSER::modelName>() )
{
modelName = subnode->string();
}
else if( subnode->is_type<SIM_MODEL_SPICE_PARSER::dotModelType>() )
{
// Do nothing.
}
else if( subnode->is_type<SIM_MODEL_SPICE_PARSER::param>() )
{
paramName = subnode->string();
}
else if( subnode->is_type<SIM_MODEL_SPICE_PARSER::paramValue>() )
{
wxASSERT( paramName != "" );
if( !m_model.SetParamFromSpiceCode( paramName, subnode->string() ) )
{
THROW_IO_ERROR( wxString::Format(
_( "Failed to set parameter '%s' to '%s' in model '%s'" ),
paramName,
subnode->string(),
modelName ) );
}
}
else
@ -230,3 +288,9 @@ SIM_MODEL::TYPE SPICE_MODEL_PARSER::ReadTypeFromSpiceStrings( const std::string&
// have an error if there is a type KiCad does not recognize.
return SIM_MODEL::TYPE::RAWSPICE;
}
void SPICE_MODEL_PARSER::CopyModelFromLibrary( const SIM_LIBRARY_SPICE& aSourceLibrary,
const std::string& aModelName )
{
}

View File

@ -28,6 +28,7 @@
#include <sim/sim_model.h>
class SIM_MODEL_SPICE;
class SIM_LIBRARY_SPICE;
class SPICE_MODEL_PARSER
@ -36,8 +37,9 @@ public:
static SIM_MODEL::TYPE ReadType( const std::string& aSpiceCode );
SPICE_MODEL_PARSER( SIM_MODEL_SPICE& aModel ) : m_model( aModel ) {}
virtual ~SPICE_MODEL_PARSER() = default;
virtual void ReadModel( const std::string& aSpiceCode );
virtual void ReadModel( const SIM_LIBRARY_SPICE& aLibrary, const std::string& aSpiceCode );
protected:
static SIM_MODEL::TYPE ReadTypeFromSpiceStrings( const std::string& aTypeString,
@ -45,6 +47,9 @@ protected:
const std::string& aVersion = "",
bool aSkipDefaultLevel = true );
void CopyModelFromLibrary( const SIM_LIBRARY_SPICE& aSourceLibrary,
const std::string& aModelName );
SIM_MODEL_SPICE& m_model;
};