Sim: Refactor Spice code generation to a new SPICE_GENERATOR class

This commit is contained in:
Mikolaj Wielgus 2022-09-14 09:19:25 +02:00
parent e473e71ef8
commit e4c5bc6c66
24 changed files with 783 additions and 672 deletions

View File

@ -75,7 +75,7 @@ bool DIALOG_SIGNAL_LIST::TransferDataToWindow()
for( const auto& item : m_circuitModel->GetItems() )
{
// Add all possible currents for the primitive.
for( const auto& currentName : item.model->GenerateSpiceCurrentNames( item.refName ) )
for( const auto& currentName : item.model->SpiceGenerator().CurrentNames( item.refName ) )
m_signals->Append( currentName );
}
}

View File

@ -338,7 +338,7 @@ void DIALOG_SIM_MODEL<T>::updateModelCodeTab()
wxTextFile file;
wxString text;
text << curModel().GenerateSpicePreview( modelName );
text << curModel().SpiceGenerator().Preview( modelName );
text << "\n";
text << "--- FILE SOURCE (" << path << ") ---\n";
text << "\n";
@ -356,7 +356,7 @@ void DIALOG_SIM_MODEL<T>::updateModelCodeTab()
}
}
else
m_codePreview->SetText( curModel().GenerateSpicePreview( modelName ) );
m_codePreview->SetText( curModel().SpiceGenerator().Preview( modelName ) );
m_codePreview->SetEditable( false ); // ???
m_wasCodePreviewUpdated = true;

View File

@ -177,7 +177,7 @@ wxString NETLIST_EXPORTER_SPICE::GetItemName( const wxString& aRefName ) const
if( it == spiceItems.end() )
return "";
return it->model->GenerateSpiceItemName( aRefName );
return it->model->SpiceGenerator().ItemName( aRefName );
}
@ -425,7 +425,7 @@ void NETLIST_EXPORTER_SPICE::writeModels( OUTPUTFORMATTER& aFormatter )
if( !item.model->IsEnabled() )
continue;
aFormatter.Print( 0, "%s", TO_UTF8( item.model->GenerateSpiceModelLine( item.modelName ) ) );
aFormatter.Print( 0, "%s", TO_UTF8( item.model->SpiceGenerator().ModelLine( item.modelName ) ) );
}
}
@ -438,10 +438,10 @@ void NETLIST_EXPORTER_SPICE::writeItems( OUTPUTFORMATTER& aFormatter )
continue;
aFormatter.Print( 0, "%s",
TO_UTF8( item.model->GenerateSpiceItemLine( item.refName,
item.modelName,
item.pinNumbers,
item.pinNetNames ) ) );
TO_UTF8( item.model->SpiceGenerator().ItemLine( item.refName,
item.modelName,
item.pinNumbers,
item.pinNetNames ) ) );
}
}

View File

@ -42,6 +42,7 @@
#include <iterator>
using SPICE_GENERATOR = SIM_MODEL::SPICE_GENERATOR;
using DEVICE_TYPE = SIM_MODEL::DEVICE_TYPE_;
using TYPE = SIM_MODEL::TYPE;
@ -83,36 +84,220 @@ namespace SIM_MODEL_SPICE_PARSER
}
wxString SPICE_GENERATOR::ModelLine( const wxString& aModelName ) const
{
LOCALE_IO toggle;
if( !m_model.HasSpiceNonInstanceOverrides() && !m_model.requiresSpiceModelLine() )
return "";
wxString result = "";
result << wxString::Format( ".model %s ", aModelName );
size_t indentLength = result.Length();
result << wxString::Format( "%s \n", m_model.GetSpiceInfo().modelType );
for( const PARAM& param : m_model.GetParams() )
{
if( param.info.isSpiceInstanceParam )
continue;
wxString name = ( param.info.spiceModelName == "" ) ?
param.info.name : param.info.spiceModelName;
wxString value = param.value->ToSpiceString();
if( value == "" )
continue;
result << wxString::Format( "+%s%s=%s\n", wxString( ' ', indentLength - 1 ), name, value );
}
return result;
}
wxString SPICE_GENERATOR::ItemLine( const wxString& aRefName,
const wxString& aModelName ) const
{
// Use linear symbol pin numbers enumeration. Used in model preview.
std::vector<wxString> pinNumbers;
for( int i = 0; i < m_model.GetPinCount(); ++i )
pinNumbers.push_back( wxString::FromCDouble( i + 1 ) );
return ItemLine( aRefName, aModelName, pinNumbers );
}
wxString SPICE_GENERATOR::ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers ) const
{
std::vector<wxString> pinNetNames;
for( const PIN& pin : GetPins() )
pinNetNames.push_back( pin.name );
return ItemLine( aRefName, aModelName, aSymbolPinNumbers, pinNetNames );
}
wxString SPICE_GENERATOR::ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result;
result << ItemName( aRefName );
result << ItemPins( aRefName, aModelName, aSymbolPinNumbers, aPinNetNames );
result << ItemModelName( aModelName );
result << ItemParams();
result << "\n";
return result;
}
wxString SPICE_GENERATOR::ItemName( const wxString& aRefName ) const
{
if( aRefName != "" && aRefName.StartsWith( m_model.GetSpiceInfo().itemType ) )
return aRefName;
else
return m_model.GetSpiceInfo().itemType + aRefName;
}
wxString SPICE_GENERATOR::ItemPins( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result;
int ncCounter = 0;
for( const PIN& pin : GetPins() )
{
auto it = std::find( aSymbolPinNumbers.begin(), aSymbolPinNumbers.end(),
pin.symbolPinNumber );
if( it == aSymbolPinNumbers.end() )
{
LOCALE_IO toggle;
result << wxString::Format( " NC-%s-%u", aRefName, ncCounter++ );
}
else
{
long symbolPinIndex = std::distance( aSymbolPinNumbers.begin(), it );
result << " " << aPinNetNames.at( symbolPinIndex );
}
}
return result;
}
wxString SPICE_GENERATOR::ItemModelName( const wxString& aModelName ) const
{
return " " + aModelName;
}
wxString SPICE_GENERATOR::ItemParams() const
{
wxString result;
for( const PARAM& param : GetInstanceParams() )
{
wxString name = ( param.info.spiceInstanceName == "" ) ?
param.info.name : param.info.spiceInstanceName;
wxString value = param.value->ToSpiceString();
if( value != "" )
result << " " << name << "=" << value;
}
return result;
}
wxString SPICE_GENERATOR::TuningLine( const wxString& aSymbol ) const
{
// TODO.
return "";
}
std::vector<wxString> SPICE_GENERATOR::CurrentNames( const wxString& aRefName ) const
{
LOCALE_IO toggle;
return { wxString::Format( "I(%s)", ItemName( aRefName ) ) };
}
wxString SPICE_GENERATOR::Preview( const wxString& aModelName ) const
{
wxString spiceCode = ModelLine( aModelName );
if( spiceCode == "" )
spiceCode = m_model.m_spiceCode;
if( spiceCode == "" && m_model.GetBaseModel() )
spiceCode = m_model.GetBaseModel()->m_spiceCode;
wxString itemLine = ItemLine( "", aModelName );
if( spiceCode != "" )
spiceCode << "\n";
spiceCode << itemLine;
return spiceCode.Trim();
}
std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> SPICE_GENERATOR::GetInstanceParams() const
{
std::vector<std::reference_wrapper<const PARAM>> instanceParams;
for( const PARAM& param : m_model.GetParams() )
{
if( param.info.isSpiceInstanceParam )
instanceParams.emplace_back( param );
}
return instanceParams;
}
SIM_MODEL::DEVICE_INFO SIM_MODEL::DeviceTypeInfo( DEVICE_TYPE_ aDeviceType )
{
switch( aDeviceType )
{
case DEVICE_TYPE_::NONE: return { "", "" };
case DEVICE_TYPE_::R: return { "R", "Resistor" };
case DEVICE_TYPE_::C: return { "C", "Capacitor" };
case DEVICE_TYPE_::L: return { "L", "Inductor" };
case DEVICE_TYPE_::TLINE: return { "TLINE", "Transmission Line" };
case DEVICE_TYPE_::SW: return { "SW", "Switch" };
case DEVICE_TYPE_::NONE: return { "", "" };
case DEVICE_TYPE_::R: return { "R", "Resistor" };
case DEVICE_TYPE_::C: return { "C", "Capacitor" };
case DEVICE_TYPE_::L: return { "L", "Inductor" };
case DEVICE_TYPE_::TLINE: return { "TLINE", "Transmission Line" };
case DEVICE_TYPE_::SW: return { "SW", "Switch" };
case DEVICE_TYPE_::D: return { "D", "Diode" };
case DEVICE_TYPE_::NPN: return { "NPN", "NPN BJT" };
case DEVICE_TYPE_::PNP: return { "PNP", "PNP BJT" };
case DEVICE_TYPE_::D: return { "D", "Diode" };
case DEVICE_TYPE_::NPN: return { "NPN", "NPN BJT" };
case DEVICE_TYPE_::PNP: return { "PNP", "PNP BJT" };
case DEVICE_TYPE_::NJFET: return { "NJFET", "N-channel JFET" };
case DEVICE_TYPE_::PJFET: return { "PJFET", "P-channel JFET" };
case DEVICE_TYPE_::NJFET: return { "NJFET", "N-channel JFET" };
case DEVICE_TYPE_::PJFET: return { "PJFET", "P-channel JFET" };
case DEVICE_TYPE_::NMOS: return { "NMOS", "N-channel MOSFET" };
case DEVICE_TYPE_::PMOS: return { "PMOS", "P-channel MOSFET" };
case DEVICE_TYPE_::NMES: return { "NMES", "N-channel MESFET" };
case DEVICE_TYPE_::PMES: return { "PMES", "P-channel MESFET" };
case DEVICE_TYPE_::NMOS: return { "NMOS", "N-channel MOSFET" };
case DEVICE_TYPE_::PMOS: return { "PMOS", "P-channel MOSFET" };
case DEVICE_TYPE_::NMES: return { "NMES", "N-channel MESFET" };
case DEVICE_TYPE_::PMES: return { "PMES", "P-channel MESFET" };
case DEVICE_TYPE_::V: return { "V", "Voltage Source" };
case DEVICE_TYPE_::I: return { "I", "Current Source" };
case DEVICE_TYPE_::V: return { "V", "Voltage Source" };
case DEVICE_TYPE_::I: return { "I", "Current Source" };
case DEVICE_TYPE_::SUBCKT: return { "SUBCKT", "Subcircuit" };
case DEVICE_TYPE_::XSPICE: return { "XSPICE", "XSPICE Code Model" };
case DEVICE_TYPE_::SPICE: return { "SPICE", "Raw Spice Element" };
case DEVICE_TYPE_::_ENUM_END: break;
case DEVICE_TYPE_::SUBCKT: return { "SUBCKT", "Subcircuit" };
case DEVICE_TYPE_::XSPICE: return { "XSPICE", "XSPICE Code Model" };
case DEVICE_TYPE_::SPICE: return { "SPICE", "Raw Spice Element" };
case DEVICE_TYPE_::_ENUM_END: break;
}
wxFAIL;
@ -907,123 +1092,6 @@ void SIM_MODEL::ReadSpiceCode( const wxString& aSpiceCode )
}
wxString SIM_MODEL::GenerateSpiceModelLine( const wxString& aModelName ) const
{
LOCALE_IO toggle;
if( !HasSpiceNonInstanceOverrides() && !requiresSpiceModelLine() )
return "";
wxString result = "";
result << wxString::Format( ".model %s ", aModelName );
size_t indentLength = result.Length();
result << wxString::Format( "%s \n", GetSpiceInfo().modelType );
for( const PARAM& param : GetParams() )
{
if( param.info.isSpiceInstanceParam )
continue;
wxString name = ( param.info.spiceModelName == "" ) ?
param.info.name : param.info.spiceModelName;
wxString value = param.value->ToSpiceString();
if( value == "" )
continue;
result << wxString::Format( "+%s%s=%s\n", wxString( ' ', indentLength - 1 ), name, value );
}
return result;
}
wxString SIM_MODEL::GenerateSpiceItemName( const wxString& aRefName ) const
{
if( aRefName != "" && aRefName.StartsWith( GetSpiceInfo().itemType ) )
return aRefName;
else
return GetSpiceInfo().itemType + aRefName;
}
wxString SIM_MODEL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName ) const
{
// Use linear symbol pin numbers enumeration. Used in model preview.
std::vector<wxString> pinNumbers;
for( int i = 0; i < GetPinCount(); ++i )
pinNumbers.push_back( wxString::FromCDouble( i + 1 ) );
return GenerateSpiceItemLine( aRefName, aModelName, pinNumbers );
}
wxString SIM_MODEL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers ) const
{
std::vector<wxString> pinNetNames;
for( const PIN& pin : GetPins() )
pinNetNames.push_back( pin.name );
return GenerateSpiceItemLine( aRefName, aModelName, aSymbolPinNumbers, pinNetNames );
}
wxString SIM_MODEL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result;
result << GenerateSpiceItemName( aRefName );
result << GenerateSpiceItemPins( aRefName, aModelName, aSymbolPinNumbers, aPinNetNames );
result << GenerateSpiceItemModelName( aModelName );
result << GenerateSpiceItemParams();
result << "\n";
return result;
}
wxString SIM_MODEL::GenerateSpiceTuningLine( const wxString& aSymbol ) const
{
// TODO.
return "";
}
wxString SIM_MODEL::GenerateSpicePreview( const wxString& aModelName ) const
{
wxString spiceCode = GenerateSpiceModelLine( aModelName );
if( spiceCode == "" )
spiceCode = m_spiceCode;
if( spiceCode == "" && GetBaseModel() )
spiceCode = GetBaseModel()->m_spiceCode;
wxString itemLine = GenerateSpiceItemLine( "", aModelName );
if( spiceCode != "" )
spiceCode << "\n";
spiceCode << itemLine;
return spiceCode.Trim();
}
std::vector<wxString> SIM_MODEL::GenerateSpiceCurrentNames( const wxString& aRefName ) const
{
LOCALE_IO toggle;
return { wxString::Format( "I(%s)", GenerateSpiceItemName( aRefName ) ) };
}
void SIM_MODEL::AddPin( const PIN& aPin )
{
m_pins.push_back( aPin );
@ -1096,20 +1164,6 @@ std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> SIM_MODEL::GetParams
}
std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> SIM_MODEL::GetSpiceInstanceParams() const
{
std::vector<std::reference_wrapper<const PARAM>> spiceInstanceParams;
for( const PARAM& param : GetParams() )
{
if( param.info.isSpiceInstanceParam )
spiceInstanceParams.emplace_back( param );
}
return spiceInstanceParams;
}
const SIM_MODEL::PARAM& SIM_MODEL::GetUnderlyingParam( unsigned aParamIndex ) const
{
return m_params.at( aParamIndex );
@ -1190,8 +1244,12 @@ bool SIM_MODEL::HasSpiceNonInstanceOverrides() const
}
SIM_MODEL::SIM_MODEL( TYPE aType ) : m_baseModel( nullptr ), m_type( aType ),
m_isEnabled( true ), m_isInferred( false )
SIM_MODEL::SIM_MODEL( TYPE aType, std::unique_ptr<SPICE_GENERATOR> aSpiceGenerator ) :
m_spiceGenerator( std::move( aSpiceGenerator ) ),
m_baseModel( nullptr ),
m_type( aType ),
m_isEnabled( true ),
m_isInferred( false )
{
}
@ -1238,59 +1296,6 @@ void SIM_MODEL::WriteInferredDataFields( std::vector<T>& aFields, const wxString
}
wxString SIM_MODEL::GenerateSpiceItemPins( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result;
int ncCounter = 0;
for( const PIN& pin : GetSpicePins() )
{
auto it = std::find( aSymbolPinNumbers.begin(), aSymbolPinNumbers.end(),
pin.symbolPinNumber );
if( it == aSymbolPinNumbers.end() )
{
LOCALE_IO toggle;
result << wxString::Format( " NC-%s-%u", aRefName, ncCounter++ );
}
else
{
long symbolPinIndex = std::distance( aSymbolPinNumbers.begin(), it );
result << " " << aPinNetNames.at( symbolPinIndex );
}
}
return result;
}
wxString SIM_MODEL::GenerateSpiceItemModelName( const wxString& aModelName ) const
{
return " " + aModelName;
}
wxString SIM_MODEL::GenerateSpiceItemParams() const
{
wxString result;
for( const PARAM& param : GetSpiceInstanceParams() )
{
wxString name = ( param.info.spiceInstanceName == "" ) ?
param.info.name : param.info.spiceInstanceName;
wxString value = param.value->ToSpiceString();
if( value != "" )
result << " " << name << "=" << value;
}
return result;
}
wxString SIM_MODEL::GenerateParamValuePair( const PARAM& aParam, bool& aIsFirst ) const
{
wxString result;

View File

@ -108,6 +108,50 @@ namespace SIM_MODEL_GRAMMAR
class SIM_MODEL
{
public:
struct PIN;
struct PARAM;
class SPICE_GENERATOR
{
public:
SPICE_GENERATOR( const SIM_MODEL& aModel ) : m_model( aModel ) {}
virtual wxString ModelLine( const wxString& aModelName ) const;
wxString ItemLine( const wxString& aRefName,
const wxString& aModelName ) const;
wxString ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers ) const;
virtual wxString ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const;
virtual wxString ItemName( const wxString& aRefName ) const;
virtual wxString ItemPins( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const;
virtual wxString ItemModelName( const wxString& aModelName ) const;
virtual wxString ItemParams() const;
virtual wxString TuningLine( const wxString& aSymbol ) const;
virtual std::vector<wxString> CurrentNames( const wxString& aRefName ) const;
virtual wxString Preview( const wxString& aModelName ) const;
protected:
virtual std::vector<std::reference_wrapper<const SIM_MODEL::PIN>> GetPins() const
{
return m_model.GetPins();
}
std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> GetInstanceParams() const;
const SIM_MODEL& m_model;
};
static constexpr auto REFERENCE_FIELD = "Reference";
static constexpr auto VALUE_FIELD = "Value";
@ -463,6 +507,8 @@ public:
static void SetFieldValue( std::vector<T>& aFields, const wxString& aFieldName,
const wxString& aValue );
const SPICE_GENERATOR& SpiceGenerator() const { return *m_spiceGenerator; }
// Move semantics.
// Rule of five.
@ -472,7 +518,6 @@ public:
SIM_MODEL( SIM_MODEL&& aOther ) = default;
SIM_MODEL& operator=(SIM_MODEL&& aOther ) = delete;
virtual void ReadSpiceCode( const wxString& aSpiceCode );
template <typename T>
@ -493,23 +538,7 @@ public:
virtual bool HasToIncludeSpiceLibrary() const { return GetBaseModel() && !HasOverrides(); }
virtual wxString GenerateSpiceModelLine( const wxString& aModelName ) const;
virtual wxString GenerateSpiceItemName( const wxString& aRefName ) const;
wxString GenerateSpiceItemLine( const wxString& aRefName, const wxString& aModelName ) const;
wxString GenerateSpiceItemLine( const wxString& aRefName, const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers ) const;
virtual wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const;
virtual wxString GenerateSpiceTuningLine( const wxString& aSymbol ) const;
virtual wxString GenerateSpicePreview( const wxString& aModelName ) const;
SPICE_INFO GetSpiceInfo() const { return SpiceInfo( GetType() ); }
virtual std::vector<wxString> GenerateSpiceCurrentNames( const wxString& aRefName ) const;
void AddPin( const PIN& aPin );
int FindModelPinIndex( const wxString& aSymbolPinNumber );
@ -541,7 +570,6 @@ public:
const PARAM* FindParam( const wxString& aParamName ) const;
std::vector<std::reference_wrapper<const PARAM>> GetParams() const;
std::vector<std::reference_wrapper<const PARAM>> GetSpiceInstanceParams() const;
const PARAM& GetUnderlyingParam( unsigned aParamIndex ) const; // Return the actual parameter.
const PARAM& GetBaseParam( unsigned aParamIndex ) const; // Always return base parameter if it exists.
@ -564,20 +592,14 @@ public:
bool IsEnabled() const { return m_isEnabled; }
protected:
SIM_MODEL( TYPE aType );
SIM_MODEL( TYPE aType ) : SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ) ) {}
SIM_MODEL( TYPE aType, std::unique_ptr<SPICE_GENERATOR> aSpiceGenerator );
virtual void CreatePins( unsigned aSymbolPinCount );
template <typename T>
void WriteInferredDataFields( std::vector<T>& aFields, const wxString& aValue ) const;
virtual wxString GenerateSpiceItemPins( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const;
virtual wxString GenerateSpiceItemModelName( const wxString& aModelName ) const;
virtual wxString GenerateSpiceItemParams() const;
virtual wxString GenerateParamValuePair( const PARAM& aParam, bool& aIsFirst ) const;
wxString GenerateParamsField( const wxString& aPairSeparator ) const;
@ -586,11 +608,6 @@ protected:
void ParsePinsField( unsigned aSymbolPinCount, const wxString& aPinsField );
void ParseDisabledField( const wxString& aDisabledField );
virtual std::vector<std::reference_wrapper<const PIN>> GetSpicePins() const
{
return GetPins();
}
virtual bool SetParamFromSpiceCode( const wxString& aParamName, const wxString& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation
= SIM_VALUE_GRAMMAR::NOTATION::SPICE );
@ -629,6 +646,7 @@ private:
virtual std::vector<wxString> getPinNames() const { return {}; }
std::unique_ptr<SPICE_GENERATOR> m_spiceGenerator;
const SIM_MODEL* m_baseModel;
const TYPE m_type;

View File

@ -25,10 +25,54 @@
#include <sim/sim_model_behavioral.h>
#include <locale_io.h>
using SPICE_GENERATOR = SIM_MODEL_BEHAVIORAL::SPICE_GENERATOR;
SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType )
: SIM_MODEL( aType ),
m_isInferred( false )
wxString SPICE_GENERATOR::ModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SPICE_GENERATOR::ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
LOCALE_IO toggle;
switch( m_model.GetType() )
{
case TYPE::R_BEHAVIORAL:
case TYPE::C_BEHAVIORAL:
case TYPE::L_BEHAVIORAL:
return SIM_MODEL::SPICE_GENERATOR::ItemLine( aRefName,
m_model.GetParam( 0 ).value->ToString(),
aSymbolPinNumbers,
aPinNetNames );
case TYPE::V_BEHAVIORAL:
return SIM_MODEL::SPICE_GENERATOR::ItemLine( aRefName,
wxString::Format( "V=%s", m_model.GetParam( 0 ).value->ToString() ),
aSymbolPinNumbers,
aPinNetNames );
case TYPE::I_BEHAVIORAL:
return SIM_MODEL::SPICE_GENERATOR::ItemLine( aRefName,
wxString::Format( "I=%s", m_model.GetParam( 0 ).value->ToString() ),
aSymbolPinNumbers,
aPinNetNames );
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_BEHAVIORAL" );
return "";
}
}
SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType ) :
SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ) ),
m_isInferred( false )
{
static PARAM::INFO resistor = makeParams( "r", "Expression for resistance", "Ω" );
static PARAM::INFO capacitor = makeParams( "c", "Expression for capacitance", "F" );
@ -87,46 +131,6 @@ void SIM_MODEL_BEHAVIORAL::WriteDataLibFields( std::vector<LIB_FIELD>& aFields )
}
wxString SIM_MODEL_BEHAVIORAL::GenerateSpiceModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SIM_MODEL_BEHAVIORAL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
LOCALE_IO toggle;
switch( GetType() )
{
case TYPE::R_BEHAVIORAL:
case TYPE::C_BEHAVIORAL:
case TYPE::L_BEHAVIORAL:
return SIM_MODEL::GenerateSpiceItemLine( aRefName,
GetParam( 0 ).value->ToString(),
aSymbolPinNumbers,
aPinNetNames );
case TYPE::V_BEHAVIORAL:
return SIM_MODEL::GenerateSpiceItemLine( aRefName,
wxString::Format( "V=%s", GetParam( 0 ).value->ToString() ), aSymbolPinNumbers,
aPinNetNames );
case TYPE::I_BEHAVIORAL:
return SIM_MODEL::GenerateSpiceItemLine( aRefName,
wxString::Format( "I=%s", GetParam( 0 ).value->ToString() ), aSymbolPinNumbers,
aPinNetNames );
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_BEHAVIORAL" );
return "";
}
}
bool SIM_MODEL_BEHAVIORAL::parseValueField( const wxString& aValueField )
{
wxString expr = aValueField;

View File

@ -31,6 +31,19 @@
class SIM_MODEL_BEHAVIORAL : public SIM_MODEL
{
public:
class SPICE_GENERATOR : public SIM_MODEL::SPICE_GENERATOR
{
public:
using SIM_MODEL::SPICE_GENERATOR::SPICE_GENERATOR;
wxString ModelLine( const wxString& aModelName ) const override;
wxString ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
};
SIM_MODEL_BEHAVIORAL( TYPE aType );
void ReadDataSchFields( unsigned aSymbolPinCount,
@ -41,12 +54,6 @@ public:
void WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const override;
void WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const override;
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
private:
bool parseValueField( const wxString& aValueField );
@ -61,6 +68,7 @@ private:
static PARAM::INFO makeParams( wxString aName, wxString aDescription, wxString aUnit );
bool m_isInferred;
};

View File

@ -26,10 +26,33 @@
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
using SPICE_GENERATOR = SIM_MODEL_IDEAL::SPICE_GENERATOR;
SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType )
: SIM_MODEL( aType ),
m_isInferred( false )
wxString SPICE_GENERATOR::ModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SPICE_GENERATOR::ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString valueStr = m_model.GetParam( 0 ).value->ToString( SIM_VALUE::NOTATION::SPICE );
if( valueStr != "" )
return SIM_MODEL::SPICE_GENERATOR::ItemLine( aRefName, valueStr, aSymbolPinNumbers,
aPinNetNames );
else
return "";
}
SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType ) :
SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ) ),
m_isInferred( false )
{
static PARAM::INFO resistor = makeParamInfo( "r", "Resistance", "Ω" );
static PARAM::INFO capacitor = makeParamInfo( "c", "Capacitance", "F" );
@ -84,26 +107,6 @@ void SIM_MODEL_IDEAL::WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) cons
}
wxString SIM_MODEL_IDEAL::GenerateSpiceModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SIM_MODEL_IDEAL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString valueStr = GetParam( 0 ).value->ToString( SIM_VALUE::NOTATION::SPICE );
if( valueStr != "" )
return SIM_MODEL::GenerateSpiceItemLine( aRefName, valueStr, aSymbolPinNumbers, aPinNetNames );
else
return "";
}
template <typename T>
void SIM_MODEL_IDEAL::inferredWriteDataFields( std::vector<T>& aFields ) const
{

View File

@ -31,6 +31,19 @@
class SIM_MODEL_IDEAL : public SIM_MODEL
{
public:
class SPICE_GENERATOR : public SIM_MODEL::SPICE_GENERATOR
{
public:
using SIM_MODEL::SPICE_GENERATOR::SPICE_GENERATOR;
wxString ModelLine( const wxString& aModelName ) const override;
wxString ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
};
SIM_MODEL_IDEAL( TYPE aType );
void ReadDataSchFields( unsigned aSymbolPinCount, const std::vector<SCH_FIELD>* aFields ) override;
@ -39,13 +52,6 @@ public:
void WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const override;
void WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const override;
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
private:
template <typename T>
void inferredWriteDataFields( std::vector<T>& aFields ) const;

View File

@ -24,8 +24,22 @@
#include <sim/sim_model_mutual_inductor.h>
using SPICE_GENERATOR = SIM_MODEL_MUTUAL_INDUCTOR::SPICE_GENERATOR;
SIM_MODEL_MUTUAL_INDUCTOR::SIM_MODEL_MUTUAL_INDUCTOR() : SIM_MODEL( SIM_MODEL::TYPE::L_MUTUAL )
wxString SPICE_GENERATOR::ItemParams() const
{
wxString result;
for( const PARAM& param : GetInstanceParams() )
result << " " << param.value->ToSpiceString();
return result;
}
SIM_MODEL_MUTUAL_INDUCTOR::SIM_MODEL_MUTUAL_INDUCTOR() :
SIM_MODEL( SIM_MODEL::TYPE::L_MUTUAL, std::make_unique<SPICE_GENERATOR>( *this ) )
{
static std::vector<PARAM::INFO> paramInfos = makeParamInfos();
@ -34,17 +48,6 @@ SIM_MODEL_MUTUAL_INDUCTOR::SIM_MODEL_MUTUAL_INDUCTOR() : SIM_MODEL( SIM_MODEL::T
}
wxString SIM_MODEL_MUTUAL_INDUCTOR::GenerateSpiceItemParams() const
{
wxString result;
for( const PARAM& param : GetSpiceInstanceParams() )
result << param.value->ToSimpleString() << " ";
return result;
}
const std::vector<SIM_MODEL::PARAM::INFO> SIM_MODEL_MUTUAL_INDUCTOR::makeParamInfos()
{
std::vector<PARAM::INFO> paramInfos;

View File

@ -31,9 +31,15 @@
class SIM_MODEL_MUTUAL_INDUCTOR : public SIM_MODEL
{
public:
SIM_MODEL_MUTUAL_INDUCTOR();
class SPICE_GENERATOR : public SIM_MODEL::SPICE_GENERATOR
{
public:
using SIM_MODEL::SPICE_GENERATOR::SPICE_GENERATOR;
wxString GenerateSpiceItemParams() const override;
wxString ItemParams() const override;
};
SIM_MODEL_MUTUAL_INDUCTOR();
private:
static const std::vector<PARAM::INFO> makeParamInfos();

View File

@ -25,34 +25,15 @@
#include <sim/sim_model_ngspice.h>
#include <locale_io.h>
using SPICE_GENERATOR = SIM_MODEL_NGSPICE::SPICE_GENERATOR;
using TYPE = SIM_MODEL::TYPE;
SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType )
: SIM_MODEL( aType )
{
const MODEL_INFO& modelInfo = ModelInfo( getModelType() );
for( const SIM_MODEL::PARAM::INFO& paramInfo : modelInfo.instanceParams )
{
// For now, only the geometry parameters.
if( paramInfo.category == SIM_MODEL::PARAM::CATEGORY::PRINCIPAL
|| paramInfo.category == SIM_MODEL::PARAM::CATEGORY::GEOMETRY )
{
AddParam( paramInfo, getIsOtherVariant() );
}
}
for( const SIM_MODEL::PARAM::INFO& paramInfo : modelInfo.modelParams )
AddParam( paramInfo, getIsOtherVariant() );
}
std::vector<wxString> SIM_MODEL_NGSPICE::GenerateSpiceCurrentNames( const wxString& aRefName ) const
std::vector<wxString> SPICE_GENERATOR::CurrentNames( const wxString& aRefName ) const
{
LOCALE_IO toggle;
switch( TypeInfo( GetType() ).deviceType )
switch( m_model.GetTypeInfo().deviceType )
{
case DEVICE_TYPE_::NPN:
case DEVICE_TYPE_::PNP:
@ -74,7 +55,7 @@ std::vector<wxString> SIM_MODEL_NGSPICE::GenerateSpiceCurrentNames( const wxStri
case DEVICE_TYPE_::C:
case DEVICE_TYPE_::L:
case DEVICE_TYPE_::D:
return SIM_MODEL::GenerateSpiceCurrentNames( aRefName );
return CurrentNames( aRefName );
default:
wxFAIL_MSG( "Unhandled model device type in SIM_MODEL_NGSPICE" );
@ -83,6 +64,26 @@ std::vector<wxString> SIM_MODEL_NGSPICE::GenerateSpiceCurrentNames( const wxStri
}
SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType )
: SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ) )
{
const MODEL_INFO& modelInfo = ModelInfo( getModelType() );
for( const SIM_MODEL::PARAM::INFO& paramInfo : modelInfo.instanceParams )
{
// For now, only the geometry parameters.
if( paramInfo.category == SIM_MODEL::PARAM::CATEGORY::PRINCIPAL
|| paramInfo.category == SIM_MODEL::PARAM::CATEGORY::GEOMETRY )
{
AddParam( paramInfo, getIsOtherVariant() );
}
}
for( const SIM_MODEL::PARAM::INFO& paramInfo : modelInfo.modelParams )
AddParam( paramInfo, getIsOtherVariant() );
}
bool SIM_MODEL_NGSPICE::SetParamFromSpiceCode( const wxString& aParamName, const wxString& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation )
{

View File

@ -33,9 +33,16 @@ class SIM_MODEL_NGSPICE : public SIM_MODEL
public:
friend struct MODEL_INFO_MAP;
SIM_MODEL_NGSPICE( TYPE aType );
class SPICE_GENERATOR : public SIM_MODEL::SPICE_GENERATOR
{
public:
using SIM_MODEL::SPICE_GENERATOR::SPICE_GENERATOR;
std::vector<wxString> GenerateSpiceCurrentNames( const wxString& aRefName ) const override;
std::vector<wxString> CurrentNames( const wxString& aRefName ) const override;
};
SIM_MODEL_NGSPICE( TYPE aType );
bool SetParamFromSpiceCode( const wxString& aParamName, const wxString& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation ) override;

View File

@ -27,6 +27,8 @@
#include <pegtl/contrib/parse_tree.hpp>
#include <locale_io.h>
using SPICE_GENERATOR = SIM_MODEL_SOURCE::SPICE_GENERATOR;
namespace SIM_MODEL_SOURCE_PARSER
{
@ -38,63 +40,36 @@ namespace SIM_MODEL_SOURCE_PARSER
}
SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType )
: SIM_MODEL( aType ),
m_isInferred( false )
{
for( const SIM_MODEL::PARAM::INFO& paramInfo : makeParamInfos( aType ) )
AddParam( paramInfo );
}
void SIM_MODEL_SOURCE::WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const
{
SIM_MODEL::WriteDataSchFields( aFields );
if( m_isInferred )
inferredWriteDataFields( aFields );
}
void SIM_MODEL_SOURCE::WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const
{
SIM_MODEL::WriteDataLibFields( aFields );
if( m_isInferred )
inferredWriteDataFields( aFields );
}
wxString SIM_MODEL_SOURCE::GenerateSpiceModelLine( const wxString& aModelName ) const
wxString SPICE_GENERATOR::ModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SIM_MODEL_SOURCE::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
wxString SPICE_GENERATOR::ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
LOCALE_IO toggle;
wxString model;
wxString ac = FindParam( "ac" )->value->ToSpiceString();
wxString ph = FindParam( "ph" )->value->ToSpiceString();
wxString ac = m_model.FindParam( "ac" )->value->ToSpiceString();
wxString ph = m_model.FindParam( "ph" )->value->ToSpiceString();
if( ac != "" )
model << wxString::Format( "AC %s %s ", ac, ph );
if( GetSpiceInfo().inlineTypeString != "" )
if( m_model.GetSpiceInfo().inlineTypeString != "" )
{
wxString args = "";
switch( GetType() )
switch( m_model.GetType() )
{
case TYPE::V_PWL:
case TYPE::I_PWL:
{
tao::pegtl::string_input<> in( GetParam( 0 ).value->ToString().ToUTF8(),
tao::pegtl::string_input<> in( m_model.GetParam( 0 ).value->ToString().ToUTF8(),
"from_content" );
std::unique_ptr<tao::pegtl::parse_tree::node> root;
@ -158,8 +133,8 @@ wxString SIM_MODEL_SOURCE::GenerateSpiceItemLine( const wxString& aRefName,
args << getParamValueString( "dt", "0" ) << " ";
args << getParamValueString( "td", "0" ) << " ";
auto min = dynamic_cast<SIM_VALUE_FLOAT&>( *FindParam( "max" )->value );
auto max = dynamic_cast<SIM_VALUE_FLOAT&>( *FindParam( "min" )->value );
auto min = dynamic_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "max" )->value );
auto max = dynamic_cast<SIM_VALUE_FLOAT&>( *m_model.FindParam( "min" )->value );
SIM_VALUE_FLOAT range = max - min;
SIM_VALUE_FLOAT offset = ( max + min ) / SIM_VALUE_FLOAT( 2 );
@ -196,7 +171,7 @@ wxString SIM_MODEL_SOURCE::GenerateSpiceItemLine( const wxString& aRefName,
break;*/
default:
for( const PARAM& param : GetParams() )
for( const PARAM& param : m_model.GetParams() )
{
wxString argStr = param.value->ToString( SIM_VALUE_GRAMMAR::NOTATION::SPICE );
@ -206,12 +181,51 @@ wxString SIM_MODEL_SOURCE::GenerateSpiceItemLine( const wxString& aRefName,
break;
}
model << wxString::Format( "%s( %s)", GetSpiceInfo().inlineTypeString, args );
model << wxString::Format( "%s( %s)", m_model.GetSpiceInfo().inlineTypeString, args );
}
else
model << GetParam( 0 ).value->ToSpiceString();
model << m_model.GetParam( 0 ).value->ToSpiceString();
return SIM_MODEL::GenerateSpiceItemLine( aRefName, model, aSymbolPinNumbers, aPinNetNames );
return SIM_MODEL::SPICE_GENERATOR::ItemLine( aRefName, model, aSymbolPinNumbers, aPinNetNames );
}
wxString SPICE_GENERATOR::getParamValueString( const wxString& aParamName,
const wxString& aDefaultValue ) const
{
wxString result = m_model.FindParam( aParamName )->value->ToSpiceString();
if( result == "" )
result = aDefaultValue;
return result;
}
SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType )
: SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ) ),
m_isInferred( false )
{
for( const SIM_MODEL::PARAM::INFO& paramInfo : makeParamInfos( aType ) )
AddParam( paramInfo );
}
void SIM_MODEL_SOURCE::WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const
{
SIM_MODEL::WriteDataSchFields( aFields );
if( m_isInferred )
inferredWriteDataFields( aFields );
}
void SIM_MODEL_SOURCE::WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const
{
SIM_MODEL::WriteDataLibFields( aFields );
if( m_isInferred )
inferredWriteDataFields( aFields );
}
@ -263,18 +277,6 @@ void SIM_MODEL_SOURCE::inferredWriteDataFields( std::vector<T>& aFields ) const
}
wxString SIM_MODEL_SOURCE::getParamValueString( const wxString& aParamName,
const wxString& aDefaultValue ) const
{
wxString result = FindParam( aParamName )->value->ToSpiceString();
if( result == "" )
result = aDefaultValue;
return result;
}
const std::vector<SIM_MODEL::PARAM::INFO>& SIM_MODEL_SOURCE::makeParamInfos( TYPE aType )
{
static std::vector<SIM_MODEL::PARAM::INFO> vdc = makeDcParamInfos( "y", "V" );

View File

@ -46,17 +46,28 @@ namespace SIM_MODEL_SOURCE_GRAMMAR
class SIM_MODEL_SOURCE : public SIM_MODEL
{
public:
class SPICE_GENERATOR : public SIM_MODEL::SPICE_GENERATOR
{
public:
using SIM_MODEL::SPICE_GENERATOR::SPICE_GENERATOR;
wxString ModelLine( const wxString& aModelName ) const override;
wxString ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
private:
wxString getParamValueString( const wxString& aParamName,
const wxString& aDefaultValue ) const;
};
SIM_MODEL_SOURCE( TYPE aType );
void WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const override;
void WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const override;
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
wxString GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
bool SetParamValue( unsigned aParamIndex, const wxString& aValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation = SIM_VALUE_GRAMMAR::NOTATION::SI )
override;
@ -72,8 +83,6 @@ private:
std::vector<wxString> getPinNames() const override { return { "+", "-" }; }
wxString getParamValueString( const wxString& aParamName, const wxString& aDefaultValue ) const;
static const std::vector<PARAM::INFO>& makeParamInfos( TYPE aType );
static std::vector<PARAM::INFO> makeDcParamInfos( wxString aPrefix, wxString aUnit );
@ -94,6 +103,7 @@ private:
static void appendAcParamInfos( std::vector<PARAM::INFO>& aParamInfos, wxString aUnit );
bool m_isInferred;
};

View File

@ -26,6 +26,8 @@
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
using SPICE_GENERATOR = SIM_MODEL_SPICE::SPICE_GENERATOR;
namespace SIM_MODEL_SPICE_PARSER
{
@ -36,8 +38,85 @@ namespace SIM_MODEL_SPICE_PARSER
}
SIM_MODEL_SPICE::SIM_MODEL_SPICE( TYPE aType )
: SIM_MODEL( aType )
wxString SPICE_GENERATOR::ModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SPICE_GENERATOR::ItemName( const wxString& aRefName ) const
{
wxString elementType = m_model.GetParam( static_cast<int>( SPICE_PARAM::TYPE ) ).value->ToString();
if( aRefName != "" && aRefName.StartsWith( elementType ) )
return aRefName;
else
return elementType + aRefName;
}
wxString SPICE_GENERATOR::ItemPins( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result;
for( const PIN& pin : GetPins() )
{
auto it = std::find( aSymbolPinNumbers.begin(), aSymbolPinNumbers.end(),
pin.symbolPinNumber );
if( it != aSymbolPinNumbers.end() )
{
long symbolPinIndex = std::distance( aSymbolPinNumbers.begin(), it );
result << " " << aPinNetNames.at( symbolPinIndex );
}
}
return result;
}
wxString SPICE_GENERATOR::ItemModelName( const wxString& aModelName ) const
{
return "";
}
wxString SPICE_GENERATOR::ItemParams() const
{
wxString result;
for( const PARAM& param : GetInstanceParams() )
{
if( param.info.name != "model" )
result << "";
else
result << " " << param.value->ToString();
}
return result;
}
wxString SPICE_GENERATOR::Preview( const wxString& aModelName ) const
{
std::vector<wxString> pinNumbers;
std::vector<wxString> pinNetNames;
for( int i = 0; i < m_model.GetPinCount(); ++i )
{
pinNumbers.push_back( wxString::FromCDouble( i + 1 ) );
pinNetNames.push_back( wxString::FromCDouble( i + 1 ) );
}
return ItemLine( "", aModelName, pinNumbers, pinNetNames );
}
SIM_MODEL_SPICE::SIM_MODEL_SPICE( TYPE aType ) :
SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ) )
{
static std::vector<PARAM::INFO> paramInfos = makeParamInfos();
@ -81,38 +160,6 @@ void SIM_MODEL_SPICE::WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) cons
}
wxString SIM_MODEL_SPICE::GenerateSpiceModelLine( const wxString& aModelName ) const
{
return "";
}
wxString SIM_MODEL_SPICE::GenerateSpiceItemName( const wxString& aRefName ) const
{
wxString elementType = GetParam( static_cast<int>( SPICE_PARAM::TYPE ) ).value->ToString();
if( aRefName != "" && aRefName.StartsWith( elementType ) )
return aRefName;
else
return elementType + aRefName;
}
wxString SIM_MODEL_SPICE::GenerateSpicePreview( const wxString& aModelName ) const
{
std::vector<wxString> pinNumbers;
std::vector<wxString> pinNetNames;
for( int i = 0; i < GetPinCount(); ++i )
{
pinNumbers.push_back( wxString::FromCDouble( i + 1 ) );
pinNetNames.push_back( wxString::FromCDouble( i + 1 ) );
}
return GenerateSpiceItemLine( "", aModelName, pinNumbers, pinNetNames );
}
void SIM_MODEL_SPICE::CreatePins( unsigned aSymbolPinCount )
{
for( unsigned symbolPinIndex = 0; symbolPinIndex < aSymbolPinCount; ++symbolPinIndex )
@ -120,51 +167,6 @@ void SIM_MODEL_SPICE::CreatePins( unsigned aSymbolPinCount )
}
wxString SIM_MODEL_SPICE::GenerateSpiceItemPins( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result;
for( const PIN& pin : GetSpicePins() )
{
auto it = std::find( aSymbolPinNumbers.begin(), aSymbolPinNumbers.end(),
pin.symbolPinNumber );
if( it != aSymbolPinNumbers.end() )
{
long symbolPinIndex = std::distance( aSymbolPinNumbers.begin(), it );
result << " " << aPinNetNames.at( symbolPinIndex );
}
}
return result;
}
wxString SIM_MODEL_SPICE::GenerateSpiceItemModelName( const wxString& aModelName ) const
{
return "";
}
wxString SIM_MODEL_SPICE::GenerateSpiceItemParams() const
{
wxString result;
for( const PARAM& param : GetSpiceInstanceParams() )
{
if( param.info.name != "model" )
result << "";
else
result << " " << param.value->ToString();
}
return result;
}
bool SIM_MODEL_SPICE::SetParamFromSpiceCode( const wxString& aParamName,
const wxString& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation )

View File

@ -31,6 +31,25 @@
class SIM_MODEL_SPICE : public SIM_MODEL
{
public:
class SPICE_GENERATOR : public SIM_MODEL::SPICE_GENERATOR
{
public:
using SIM_MODEL::SPICE_GENERATOR::SPICE_GENERATOR;
wxString ModelLine( const wxString& aModelName ) const override;
wxString ItemName( const wxString& aRefName ) const override;
wxString ItemPins( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
wxString ItemModelName( const wxString& aModelName ) const override;
wxString ItemParams() const override;
wxString Preview( const wxString& aModelName ) const override;
};
DEFINE_ENUM_CLASS_WITH_ITERATOR( SPICE_PARAM,
TYPE,
MODEL,
@ -53,29 +72,16 @@ public:
void WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const override;
void WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const override;
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
wxString GenerateSpiceItemName( const wxString& aRefName ) const override;
wxString GenerateSpicePreview( const wxString& aModelName ) const override;
protected:
void CreatePins( unsigned aSymbolPinCount ) override;
wxString GenerateSpiceItemPins( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
wxString GenerateSpiceItemModelName( const wxString& aModelName ) const override;
wxString GenerateSpiceItemParams() const override;
bool SetParamFromSpiceCode( const wxString& aParamName, const wxString& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation
= SIM_VALUE_GRAMMAR::NOTATION::SPICE ) override;
private:
std::vector<PARAM::INFO> makeParamInfos();
static std::vector<PARAM::INFO> makeParamInfos();
template <typename T>
void readLegacyDataFields( unsigned aSymbolPinCount, const std::vector<T>* aFields );
@ -84,6 +90,7 @@ private:
bool requiresSpiceModelLine() const override { return false; }
std::vector<std::unique_ptr<PARAM::INFO>> m_paramInfos;
};

View File

@ -27,6 +27,8 @@
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
using SPICE_GENERATOR = SIM_MODEL_SUBCKT::SPICE_GENERATOR;
namespace SIM_MODEL_SUBCKT_SPICE_PARSER
{
@ -46,8 +48,29 @@ namespace SIM_MODEL_SUBCKT_SPICE_PARSER
}
SIM_MODEL_SUBCKT::SIM_MODEL_SUBCKT( TYPE aType )
: SIM_MODEL( aType )
wxString SPICE_GENERATOR::ModelLine( const wxString& aModelName ) const
{
return "";
}
std::vector<wxString> SPICE_GENERATOR::CurrentNames( const wxString& aRefName ) const
{
std::vector<wxString> currentNames;
for( const PIN& pin : GetPins() )
{
currentNames.push_back( wxString::Format( "I(%s:%s)",
ItemName( aRefName ),
pin.name ) );
}
return currentNames;
}
SIM_MODEL_SUBCKT::SIM_MODEL_SUBCKT( TYPE aType ) :
SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ) )
{
}
@ -122,27 +145,6 @@ void SIM_MODEL_SUBCKT::ReadSpiceCode( const wxString& aSpiceCode )
}
wxString SIM_MODEL_SUBCKT::GenerateSpiceModelLine( const wxString& aModelName ) const
{
return "";
}
std::vector<wxString> SIM_MODEL_SUBCKT::GenerateSpiceCurrentNames( const wxString& aRefName ) const
{
std::vector<wxString> currentNames;
for( const PIN& pin : GetPins() )
{
currentNames.push_back( wxString::Format( "I(%s:%s)",
GenerateSpiceItemName( aRefName ),
pin.name ) );
}
return currentNames;
}
void SIM_MODEL_SUBCKT::SetBaseModel( const SIM_MODEL& aBaseModel )
{
SIM_MODEL::SetBaseModel( aBaseModel );

View File

@ -31,11 +31,19 @@
class SIM_MODEL_SUBCKT : public SIM_MODEL
{
public:
class SPICE_GENERATOR : public SIM_MODEL::SPICE_GENERATOR
{
public:
using SIM_MODEL::SPICE_GENERATOR::SPICE_GENERATOR;
wxString ModelLine( const wxString& aModelName ) const override;
std::vector<wxString> CurrentNames( const wxString& aRefName ) const override;
};
SIM_MODEL_SUBCKT( TYPE aType );
void ReadSpiceCode( const wxString& aSpiceCode ) override;
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
std::vector<wxString> GenerateSpiceCurrentNames( const wxString& aRefName ) const override;
void SetBaseModel( const SIM_MODEL& aBaseModel ) override;
protected:
@ -44,6 +52,7 @@ protected:
private:
bool requiresSpiceModelLine() const override { return true; }
std::vector<std::unique_ptr<PARAM::INFO>> m_paramInfos;
};

View File

@ -24,8 +24,84 @@
#include <sim/sim_model_switch.h>
using SPICE_GENERATOR = SIM_MODEL_SWITCH::SPICE_GENERATOR;
SIM_MODEL_SWITCH::SIM_MODEL_SWITCH( TYPE aType ) : SIM_MODEL( aType )
wxString SPICE_GENERATOR::ItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result;
switch( m_model.GetType() )
{
case TYPE::SW_V:
{
result << SIM_MODEL::SPICE_GENERATOR::ItemLine( aRefName, aModelName, aSymbolPinNumbers,
aPinNetNames );
break;
}
case TYPE::SW_I:
{
wxString vsourceName = "V__" + aRefName;
// Current switches measure input current through a voltage source.
result << vsourceName << " " << aPinNetNames[0] << " " << aPinNetNames[1] << " 0\n";
result << SIM_MODEL::SPICE_GENERATOR::ItemLine( aRefName, vsourceName + " " + aModelName,
aSymbolPinNumbers, aPinNetNames );
break;
}
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_SWITCH" );
break;
}
return result;
}
wxString SPICE_GENERATOR::ItemParams() const
{
wxString result;
for( const PARAM& param : GetInstanceParams() )
{
// The only instance param is "ic", which is positional.
wxString value = param.value->ToSpiceString();
if( value == "none" )
result << "";
else
result << value;
}
return result;
}
std::vector<std::reference_wrapper<const SIM_MODEL::PIN>> SPICE_GENERATOR::GetPins() const
{
switch( m_model.GetType() )
{
case TYPE::SW_V:
return { m_model.GetPin( 2 ), m_model.GetPin( 3 ), m_model.GetPin( 0 ), m_model.GetPin( 1 ) };
case TYPE::SW_I:
return { m_model.GetPin( 2 ), m_model.GetPin( 3 ) };
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_SWITCH" );
return {};
}
}
SIM_MODEL_SWITCH::SIM_MODEL_SWITCH( TYPE aType ) :
SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ) )
{
static std::vector<PARAM::INFO> vsw = makeSwVParamInfos();
static std::vector<PARAM::INFO> isw = makeSwIParamInfos();
@ -51,62 +127,6 @@ SIM_MODEL_SWITCH::SIM_MODEL_SWITCH( TYPE aType ) : SIM_MODEL( aType )
}
wxString SIM_MODEL_SWITCH::GenerateSpiceItemParams() const
{
wxString result;
for( const PARAM& param : GetSpiceInstanceParams() )
{
// The only instance param is "ic", which is positional.
wxString value = param.value->ToSpiceString();
if( value == "none" )
result << "";
else
result << value;
}
return result;
}
wxString SIM_MODEL_SWITCH::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const
{
wxString result;
switch( GetType() )
{
case TYPE::SW_V:
{
result << SIM_MODEL::GenerateSpiceItemLine( aRefName, aModelName, aSymbolPinNumbers,
aPinNetNames );
break;
}
case TYPE::SW_I:
{
wxString vsourceName = "V__" + aRefName;
// Current switches measure input current through a voltage source.
result << vsourceName << " " << aPinNetNames[0] << " " << aPinNetNames[1] << " 0\n";
result << SIM_MODEL::GenerateSpiceItemLine( aRefName, vsourceName + " " + aModelName,
aSymbolPinNumbers, aPinNetNames );
break;
}
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_SWITCH" );
break;
}
return result;
}
wxString SIM_MODEL_SWITCH::GenerateParamValuePair( const PARAM& aParam, bool& aIsFirst ) const
{
if( aParam.info.name == "ic" && aParam.value->ToString() == "none" )
@ -118,23 +138,6 @@ wxString SIM_MODEL_SWITCH::GenerateParamValuePair( const PARAM& aParam, bool& aI
}
std::vector<std::reference_wrapper<const SIM_MODEL::PIN>> SIM_MODEL_SWITCH::GetSpicePins() const
{
switch( GetType() )
{
case TYPE::SW_V:
return { GetPin( 2 ), GetPin( 3 ), GetPin( 0 ), GetPin( 1 ) };
case TYPE::SW_I:
return { GetPin( 2 ), GetPin( 3 ) };
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_SWITCH" );
return {};
}
}
const std::vector<SIM_MODEL::PARAM::INFO> SIM_MODEL_SWITCH::makeSwVParamInfos()
{
std::vector<PARAM::INFO> paramInfos;

View File

@ -31,16 +31,23 @@
class SIM_MODEL_SWITCH : public SIM_MODEL
{
public:
SIM_MODEL_SWITCH( TYPE aType );
class SPICE_GENERATOR : public SIM_MODEL::SPICE_GENERATOR
{
public:
using SIM_MODEL::SPICE_GENERATOR::SPICE_GENERATOR;
wxString GenerateSpiceItemParams() const override;
wxString GenerateSpiceItemLine( const wxString& aRefName, const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
wxString ItemLine( const wxString& aRefName, const wxString& aModelName,
const std::vector<wxString>& aSymbolPinNumbers,
const std::vector<wxString>& aPinNetNames ) const override;
wxString ItemParams() const override;
std::vector<std::reference_wrapper<const PIN>> GetPins() const override;
};
SIM_MODEL_SWITCH( TYPE aType );
protected:
wxString GenerateParamValuePair( const PARAM& aParam, bool& aIsFirst ) const override;
std::vector<std::reference_wrapper<const PIN>> GetSpicePins() const override;
private:
std::vector<wxString> getPinNames() const override

View File

@ -25,12 +25,53 @@
#include <sim/sim_model_tline.h>
#include <locale_io.h>
using SPICE_GENERATOR = SIM_MODEL_TLINE::SPICE_GENERATOR;
using PARAM = SIM_MODEL::PARAM;
SIM_MODEL_TLINE::SIM_MODEL_TLINE( TYPE aType )
: SIM_MODEL( aType ),
m_isInferred( false )
wxString SPICE_GENERATOR::ModelLine( const wxString& aModelName ) const
{
wxString r, l, g, c, len;
switch( m_model.GetType() )
{
case TYPE::TLINE_Z0:
{
auto z0 = static_cast<const SIM_VALUE_FLOAT&>( *m_model.FindParam( "z0" )->value );
auto td = static_cast<const SIM_VALUE_FLOAT&>( *m_model.FindParam( "td" )->value );
if( !z0.HasValue() || !td.HasValue() )
return wxString::Format( ".model %s LTRA()\n", aModelName );
r = SIM_VALUE_FLOAT( 0 ).ToSpiceString();
l = ( td * z0 ).ToSpiceString();
g = SIM_VALUE_FLOAT( 0 ).ToSpiceString();
c = ( td / z0 ).ToSpiceString();
len = SIM_VALUE_FLOAT( 1 ).ToSpiceString();
break;
}
case TYPE::TLINE_RLGC:
r = m_model.FindParam( "r" )->value->ToSpiceString();
l = m_model.FindParam( "l" )->value->ToSpiceString();
g = m_model.FindParam( "g" )->value->ToSpiceString();
c = m_model.FindParam( "c" )->value->ToSpiceString();
len = m_model.FindParam( "len" )->value->ToSpiceString();
break;
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_TLINE" );
return "";
}
return wxString::Format( ".model %s LTRA( r=%s l=%s g=%s c=%s len=%s )\n",
aModelName, r, l, g, c, len );
}
SIM_MODEL_TLINE::SIM_MODEL_TLINE( TYPE aType ) :
SIM_MODEL( aType, std::make_unique<SPICE_GENERATOR>( *this ) ),
m_isInferred( false )
{
static std::vector<PARAM::INFO> z0 = makeZ0ParamInfos();
static std::vector<PARAM::INFO> rlgc = makeRlgcParamInfos();
@ -72,46 +113,6 @@ void SIM_MODEL_TLINE::WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) cons
}
wxString SIM_MODEL_TLINE::GenerateSpiceModelLine( const wxString& aModelName ) const
{
wxString r, l, g, c, len;
switch( GetType() )
{
case TYPE::TLINE_Z0:
{
auto z0 = static_cast<const SIM_VALUE_FLOAT&>( *FindParam( "z0" )->value );
auto td = static_cast<const SIM_VALUE_FLOAT&>( *FindParam( "td" )->value );
if( !z0.HasValue() || !td.HasValue() )
return wxString::Format( ".model %s ltra()\n", aModelName );
r = SIM_VALUE_FLOAT( 0 ).ToSpiceString();
l = ( td * z0 ).ToSpiceString();
g = SIM_VALUE_FLOAT( 0 ).ToSpiceString();
c = ( td / z0 ).ToSpiceString();
len = SIM_VALUE_FLOAT( 1 ).ToSpiceString();
break;
}
case TYPE::TLINE_RLGC:
r = FindParam( "r" )->value->ToSpiceString();
l = FindParam( "l" )->value->ToSpiceString();
g = FindParam( "g" )->value->ToSpiceString();
c = FindParam( "c" )->value->ToSpiceString();
len = FindParam( "len" )->value->ToSpiceString();
break;
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_TLINE" );
return "";
}
return wxString::Format( ".model %s ltra( r=%s l=%s g=%s c=%s len=%s )\n",
aModelName, r, l, g, c, len );
}
template <typename T>
void SIM_MODEL_TLINE::inferredWriteDataFields( std::vector<T>& aFields ) const
{

View File

@ -31,13 +31,20 @@
class SIM_MODEL_TLINE : public SIM_MODEL
{
public:
class SPICE_GENERATOR : public SIM_MODEL::SPICE_GENERATOR
{
public:
using SIM_MODEL::SPICE_GENERATOR::SPICE_GENERATOR;
wxString ModelLine( const wxString& aModelName ) const override;
};
SIM_MODEL_TLINE( TYPE aType );
void WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const override;
void WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const override;
wxString GenerateSpiceModelLine( const wxString& aModelName ) const override;
private:
template <typename T>
void inferredReadDataFields( unsigned aSymbolPinCount, const std::vector<T>* aFields );

View File

@ -823,7 +823,7 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
symbol->GetFields() );
wxString ref = symbol->GetRef( &m_frame->GetCurrentSheet() );
std::vector<wxString> currentNames = model->GenerateSpiceCurrentNames( ref );
std::vector<wxString> currentNames = model->SpiceGenerator().CurrentNames( ref );
if( currentNames.size() == 0 )
return true;