Sim Model Editor: Serialize models in fields

Implemented serialization and deserialization of models in symbol fields
through the SIM_VALUE class. We don't carry the Spice legacy of
case-insensitive suffixes, instead we conform to the SI standard (i.e. M
is Mega, not milli, P is peta, p is pico).

Parameter grid value validation is implemented by simply not allowing
any characters that will make the value invalid (instead of highlighting
the field in a red color). This will likely be changed at some point in
the future.
This commit is contained in:
Mikolaj Wielgus 2022-03-09 02:40:59 +01:00
parent c5a256291e
commit 978f01553b
32 changed files with 1804 additions and 929 deletions

View File

@ -318,6 +318,7 @@ if( KICAD_SPICE )
sim/sim_plot_frame.cpp
sim/sim_plot_frame_base.cpp
sim/sim_plot_panel.cpp
sim/sim_property.cpp
sim/sim_workbook.cpp
sim/sim_model.cpp
sim/sim_model_behavioral.cpp

View File

@ -22,9 +22,12 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <widgets/wx_grid.h>
#include <dialog_spice_model.h>
#include <sim/sim_property.h>
#include <widgets/wx_grid.h>
#include <kiplatform/ui.h>
#include <confirm.h>
#include <locale_io.h>
using TYPE = SIM_VALUE_BASE::TYPE;
using CATEGORY = SIM_MODEL::PARAM::CATEGORY;
@ -49,11 +52,12 @@ DIALOG_SPICE_MODEL<T>::DIALOG_SPICE_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbo
{
if( type == typeFromFields )
{
m_models.push_back( SIM_MODEL::Create( aFields ) );
m_models.push_back( SIM_MODEL::Create( type, m_symbol.GetAllPins().size(),
&aFields ) );
m_curModelType = type;
}
else
m_models.push_back( SIM_MODEL::Create( type ) );
m_models.push_back( SIM_MODEL::Create( type, m_symbol.GetAllPins().size() ) );
SIM_MODEL::DEVICE_TYPE deviceType = SIM_MODEL::TypeInfo( type ).deviceType;
@ -74,11 +78,38 @@ DIALOG_SPICE_MODEL<T>::DIALOG_SPICE_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbo
for( SIM_MODEL::DEVICE_TYPE deviceType : SIM_MODEL::DEVICE_TYPE_ITERATOR() )
m_deviceTypeChoice->Append( SIM_MODEL::DeviceTypeInfo( deviceType ).description );
m_paramGrid = m_paramGridMgr->AddPage();
m_scintillaTricks = std::make_unique<SCINTILLA_TRICKS>( m_codePreview, wxT( "{}" ), false );
m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SPICE_MODEL::onSelectionChange, this );
m_paramGrid->SetValidationFailureBehavior( wxPG_VFB_STAY_IN_PROPERTY
| wxPG_VFB_BEEP
| wxPG_VFB_MARK_CELL );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::DESCRIPTION ), 50 );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::VALUE ), 18 );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::UNIT ), 10 );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::DEFAULT ), 12 );
m_paramGrid->SetColumnProportion( static_cast<int>( PARAM_COLUMN::TYPE ), 10 );
if( wxPropertyGrid* grid = m_paramGrid->GetGrid() )
{
grid->AddActionTrigger( wxPG_ACTION_EDIT, WXK_RETURN );
grid->DedicateKey( WXK_RETURN );
grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_RETURN );
grid->DedicateKey( WXK_UP );
grid->DedicateKey( WXK_DOWN );
// Doesn't work for some reason.
//grid->DedicateKey( WXK_TAB );
//grid->AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY, WXK_TAB );
//grid->AddActionTrigger( wxPG_ACTION_PREV_PROPERTY, WXK_TAB, wxMOD_SHIFT );
}
else
wxFAIL;
Layout();
}
@ -89,7 +120,7 @@ bool DIALOG_SPICE_MODEL<T>::TransferDataFromWindow()
if( !DIALOG_SPICE_MODEL_BASE::TransferDataFromWindow() )
return false;
m_models[static_cast<int>( m_curModelType )]->WriteFields( m_fields );
getCurModel().WriteFields( m_fields );
return true;
}
@ -100,8 +131,8 @@ bool DIALOG_SPICE_MODEL<T>::TransferDataToWindow()
{
try
{
m_models[static_cast<int>( SIM_MODEL::ReadTypeFromFields( m_fields ) )]
= SIM_MODEL::Create( m_fields );
m_models.at( static_cast<int>( SIM_MODEL::ReadTypeFromFields( m_fields ) ) )
= SIM_MODEL::Create( m_symbol.GetAllPins().size(), m_fields );
}
catch( KI_PARAM_ERROR& e )
{
@ -117,6 +148,15 @@ bool DIALOG_SPICE_MODEL<T>::TransferDataToWindow()
template <typename T>
void DIALOG_SPICE_MODEL<T>::updateWidgets()
{
updateModelParamsTab();
updateModelCodeTab();
updatePinAssignmentsTab();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::updateModelParamsTab()
{
SIM_MODEL::DEVICE_TYPE deviceType = SIM_MODEL::TypeInfo( m_curModelType ).deviceType;
@ -141,11 +181,11 @@ void DIALOG_SPICE_MODEL<T>::updateWidgets()
// This wxPropertyGridManager stuff has to be here because it segfaults in the constructor.
m_paramGridMgr->SetColumnCount( static_cast<int>( COLUMN::END_ ) );
m_paramGridMgr->SetColumnCount( static_cast<int>( PARAM_COLUMN::END_ ) );
m_paramGridMgr->SetColumnTitle( static_cast<int>( COLUMN::UNIT ), "Unit" );
m_paramGridMgr->SetColumnTitle( static_cast<int>( COLUMN::DEFAULT ), "Default" );
m_paramGridMgr->SetColumnTitle( static_cast<int>( COLUMN::TYPE ), "Type" );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::UNIT ), "Unit" );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::DEFAULT ), "Default" );
m_paramGridMgr->SetColumnTitle( static_cast<int>( PARAM_COLUMN::TYPE ), "Type" );
m_paramGridMgr->ShowHeader();
@ -176,9 +216,7 @@ void DIALOG_SPICE_MODEL<T>::updateWidgets()
m_paramGrid->Append( new wxPropertyCategory( "Flags" ) );
m_paramGrid->HideProperty( "Flags" );
SIM_MODEL& curModel = *m_models[static_cast<int>( m_curModelType )];
for( const SIM_MODEL::PARAM& param : curModel.Params() )
for( const SIM_MODEL::PARAM& param : getCurModel().Params() )
addParamPropertyIfRelevant( param );
m_paramGrid->CollapseAll();
@ -186,36 +224,107 @@ void DIALOG_SPICE_MODEL<T>::updateWidgets()
template <typename T>
void DIALOG_SPICE_MODEL<T>::onDeviceTypeChoice( wxCommandEvent& aEvent )
void DIALOG_SPICE_MODEL<T>::updateModelCodeTab()
{
SIM_MODEL::DEVICE_TYPE deviceType =
static_cast<SIM_MODEL::DEVICE_TYPE>( m_deviceTypeChoice->GetSelection() );
m_curModelType = m_curModelTypeOfDeviceType.at( deviceType );
updateWidgets();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onTypeChoice( wxCommandEvent& aEvent )
void DIALOG_SPICE_MODEL<T>::updatePinAssignmentsTab()
{
SIM_MODEL::DEVICE_TYPE deviceType =
static_cast<SIM_MODEL::DEVICE_TYPE>( m_deviceTypeChoice->GetSelection() );
wxString typeDescription = m_typeChoice->GetString( m_typeChoice->GetSelection() );
m_pinAssignmentsGrid->ClearRows();
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
std::vector<SCH_PIN*> pinList = m_symbol.GetAllPins();
m_pinAssignmentsGrid->AppendRows( static_cast<int>( pinList.size() ) );
for( int i = 0; i < m_pinAssignmentsGrid->GetNumberRows(); ++i )
{
if( deviceType == SIM_MODEL::TypeInfo( type ).deviceType
&& typeDescription == SIM_MODEL::TypeInfo( type ).description )
{
m_curModelType = type;
break;
}
wxString symbolPinString = getSymbolPinString( i + 1 );
m_pinAssignmentsGrid->SetReadOnly( i, static_cast<int>( PIN_COLUMN::SYMBOL ) );
m_pinAssignmentsGrid->SetCellValue( i, static_cast<int>( PIN_COLUMN::SYMBOL ),
symbolPinString );
// Using `new` here shouldn't cause a memory leak because `SetCellEditor()` calls
// `DecRef()` on its last editor.
m_pinAssignmentsGrid->SetCellEditor( i, static_cast<int>( PIN_COLUMN::MODEL ),
new wxGridCellChoiceEditor() );
m_pinAssignmentsGrid->SetCellValue( i, static_cast<int>( PIN_COLUMN::MODEL ),
"Not Connected" );
}
m_curModelTypeOfDeviceType.at( deviceType ) = m_curModelType;
updateWidgets();
for( unsigned int i = 0; i < getCurModel().Pins().size(); ++i )
{
int symbolPinNumber = getCurModel().Pins().at( i ).symbolPinNumber;
if( symbolPinNumber == SIM_MODEL::PIN::NOT_CONNECTED )
continue;
wxString modelPinString = getModelPinString( i + 1 );
wxArrayString choices;
m_pinAssignmentsGrid->SetCellValue( symbolPinNumber - 1,
static_cast<int>( PIN_COLUMN::MODEL ),
modelPinString );
}
updatePinAssignmentsGridEditors();
// TODO: Show a preview of the symbol with the pin numbers shown.
// TODO: Maybe show a preview of the code for subcircuits and code models.
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::updatePinAssignmentsGridEditors()
{
wxString modelPinChoicesString = "";
bool isFirst = true;
for( unsigned int i = 0; i < getCurModel().Pins().size(); ++i )
{
const SIM_MODEL::PIN& modelPin = getCurModel().Pins().at( i );
int modelPinNumber = static_cast<int>( i + 1 );
if( modelPin.symbolPinNumber != SIM_MODEL::PIN::NOT_CONNECTED )
continue;
if( isFirst )
{
modelPinChoicesString << getModelPinString( modelPinNumber );
isFirst = false;
}
else
modelPinChoicesString << "," << getModelPinString( modelPinNumber );
}
if( !isFirst )
modelPinChoicesString << ",";
modelPinChoicesString << "Not Connected";
for( int i = 0; i < m_pinAssignmentsGrid->GetNumberRows(); ++i )
{
wxGridCellChoiceEditor* editor = static_cast<wxGridCellChoiceEditor*>(
m_pinAssignmentsGrid->GetCellEditor( i, static_cast<int>( PIN_COLUMN::MODEL ) ) );
if( !editor )
{
// Shouldn't happen.
wxFAIL_MSG( "Grid cell editor is null" );
return;
}
wxString curModelPinString = m_pinAssignmentsGrid->GetCellValue(
i, static_cast<int>( PIN_COLUMN::MODEL ) );
if( curModelPinString == "Not Connected" )
editor->SetParameters( modelPinChoicesString );
else
editor->SetParameters( curModelPinString + "," + modelPinChoicesString );
}
}
@ -295,26 +404,28 @@ wxPGProperty* DIALOG_SPICE_MODEL<T>::newParamProperty( const SIM_MODEL::PARAM& a
switch( aParam.info.type )
{
case TYPE::INT:
prop = new wxIntProperty( paramDescription );
prop = new SIM_PROPERTY( paramDescription,aParam.info.name, *aParam.value,
SIM_VALUE_BASE::TYPE::INT );
break;
case TYPE::FLOAT:
prop = new wxFloatProperty( paramDescription );
prop = new SIM_PROPERTY( paramDescription,aParam.info.name, *aParam.value,
SIM_VALUE_BASE::TYPE::FLOAT );
break;
case TYPE::BOOL:
prop = new wxBoolProperty( paramDescription );
prop = new wxBoolProperty( paramDescription, aParam.info.name );
prop->SetAttribute( wxPG_BOOL_USE_CHECKBOX, true );
break;
default:
prop = new wxStringProperty( paramDescription );
prop = new wxStringProperty( paramDescription, aParam.info.name );
break;
}
prop->SetAttribute( wxPG_ATTR_UNITS, aParam.info.unit );
// Legacy due to the way we extracted parameters from Ngspice.
// Legacy due to the way we extracted the parameters from Ngspice.
if( aParam.isOtherVariant )
prop->SetCell( 3, aParam.info.defaultValueOfOtherVariant );
else
@ -325,7 +436,7 @@ wxPGProperty* DIALOG_SPICE_MODEL<T>::newParamProperty( const SIM_MODEL::PARAM& a
switch( aParam.info.type )
{
case TYPE::BOOL: typeStr = wxString( "Bool" ); break;
case TYPE::INT: typeStr = wxString( "Integer" ); break;
case TYPE::INT: typeStr = wxString( "Int" ); break;
case TYPE::FLOAT: typeStr = wxString( "Float" ); break;
case TYPE::COMPLEX: typeStr = wxString( "Complex" ); break;
case TYPE::STRING: typeStr = wxString( "String" ); break;
@ -335,7 +446,178 @@ wxPGProperty* DIALOG_SPICE_MODEL<T>::newParamProperty( const SIM_MODEL::PARAM& a
case TYPE::COMPLEX_VECTOR: typeStr = wxString( "Complex Vector" ); break;
}
prop->SetCell( static_cast<int>( COLUMN::TYPE ), typeStr );
prop->SetCell( static_cast<int>( PARAM_COLUMN::TYPE ), typeStr );
return prop;
}
template <typename T>
SIM_MODEL& DIALOG_SPICE_MODEL<T>::getCurModel() const
{
return *m_models.at( static_cast<int>( m_curModelType ) );
}
template <typename T>
wxString DIALOG_SPICE_MODEL<T>::getSymbolPinString( int symbolPinNumber ) const
{
wxString name = "";
SCH_PIN* symbolPin = m_symbol.GetAllPins().at( symbolPinNumber - 1 );
if( symbolPin )
name = symbolPin->GetShownName();
LOCALE_IO toggle;
if( name.IsEmpty() )
return wxString::Format( "%d", symbolPinNumber );
else
return wxString::Format( "%d (%s)", symbolPinNumber, symbolPin->GetShownName() );
}
template <typename T>
wxString DIALOG_SPICE_MODEL<T>::getModelPinString( int modelPinNumber ) const
{
const wxString& pinName = getCurModel().Pins().at( modelPinNumber - 1 ).name;
LOCALE_IO toggle;
if( pinName.IsEmpty() )
return wxString::Format( "%d", modelPinNumber, pinName );
else
return wxString::Format( "%d (%s)", modelPinNumber, pinName );
}
template <typename T>
int DIALOG_SPICE_MODEL<T>::getModelPinNumber( const wxString& aModelPinString ) const
{
if( aModelPinString == "Not Connected" )
return SIM_MODEL::PIN::NOT_CONNECTED;
int length = aModelPinString.Find( " " );
if( length == wxNOT_FOUND )
length = static_cast<int>( aModelPinString.Length() );
long result = 0;
aModelPinString.Mid( 0, length ).ToCLong( &result );
return static_cast<int>( result );
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onDeviceTypeChoice( wxCommandEvent& aEvent )
{
SIM_MODEL::DEVICE_TYPE deviceType =
static_cast<SIM_MODEL::DEVICE_TYPE>( m_deviceTypeChoice->GetSelection() );
m_curModelType = m_curModelTypeOfDeviceType.at( deviceType );
updateWidgets();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onTypeChoice( wxCommandEvent& aEvent )
{
SIM_MODEL::DEVICE_TYPE deviceType =
static_cast<SIM_MODEL::DEVICE_TYPE>( m_deviceTypeChoice->GetSelection() );
wxString typeDescription = m_typeChoice->GetString( m_typeChoice->GetSelection() );
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
if( deviceType == SIM_MODEL::TypeInfo( type ).deviceType
&& typeDescription == SIM_MODEL::TypeInfo( type ).description )
{
m_curModelType = type;
break;
}
}
m_curModelTypeOfDeviceType.at( deviceType ) = m_curModelType;
updateWidgets();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onPinAssignmentsGridCellChange( wxGridEvent& aEvent )
{
int symbolPinNumber = aEvent.GetRow() + 1;
int oldModelPinNumber = getModelPinNumber( aEvent.GetString() );
int modelPinNumber = getModelPinNumber(
m_pinAssignmentsGrid->GetCellValue( aEvent.GetRow(), aEvent.GetCol() ) );
if( oldModelPinNumber != SIM_MODEL::PIN::NOT_CONNECTED )
getCurModel().Pins().at( oldModelPinNumber - 1 ).symbolPinNumber =
SIM_MODEL::PIN::NOT_CONNECTED;
if( modelPinNumber != SIM_MODEL::PIN::NOT_CONNECTED )
getCurModel().Pins().at( modelPinNumber - 1 ).symbolPinNumber = symbolPinNumber;
updatePinAssignmentsGridEditors();
aEvent.Skip();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onPinAssignmentsGridSize( wxSizeEvent& aEvent )
{
wxGridUpdateLocker deferRepaintsTillLeavingScope( m_pinAssignmentsGrid );
int gridWidth = KIPLATFORM::UI::GetUnobscuredSize( m_pinAssignmentsGrid ).x;
m_pinAssignmentsGrid->SetColSize( static_cast<int>( PIN_COLUMN::MODEL ), gridWidth / 2 );
m_pinAssignmentsGrid->SetColSize( static_cast<int>( PIN_COLUMN::SYMBOL ), gridWidth / 2 );
aEvent.Skip();
}
template <typename T>
void DIALOG_SPICE_MODEL<T>::onSelectionChange( wxPropertyGridEvent& aEvent )
{
// TODO: Activate also when the whole property grid is selected with tab key.
wxPropertyGrid* grid = m_paramGrid->GetGrid();
if( !grid )
{
wxFAIL;
return;
}
wxWindow* editorControl = grid->GetEditorControl();
if( !editorControl )
{
wxFAIL;
return;
}
// Without this, the user had to press tab before they could edit the field.
editorControl->SetFocus();
}
/*template <typename T>
void DIALOG_SPICE_MODEL<T>::onPropertyChanged( wxPropertyGridEvent& aEvent )
{
wxString name = aEvent.GetPropertyName();
for( SIM_MODEL::PARAM& param : getCurModel().Params() )
{
if( param.info.name == name )
{
try
{
param.value->FromString( m_paramGrid->GetPropertyValueAsString( param.info.name ) );
}
catch( KI_PARAM_ERROR& e )
{
DisplayErrorMessage( this, e.What() );
}
}
}
}*/

View File

@ -41,7 +41,8 @@ template <typename T>
class DIALOG_SPICE_MODEL : public DIALOG_SPICE_MODEL_BASE
{
public:
enum class COLUMN : int { DESCRIPTION = 0, VALUE, UNIT, DEFAULT, TYPE, END_ };
enum class PARAM_COLUMN : int { DESCRIPTION, VALUE, UNIT, DEFAULT, TYPE, END_ };
enum class PIN_COLUMN : int { SYMBOL, MODEL };
DIALOG_SPICE_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol, std::vector<T>& aSchFields );
@ -49,15 +50,28 @@ private:
bool TransferDataFromWindow() override;
bool TransferDataToWindow() override;
void updateModel();
void updateWidgets();
void onDeviceTypeChoice( wxCommandEvent& aEvent ) override;
void onTypeChoice( wxCommandEvent& aEvent ) override;
void updateModelParamsTab();
void updateModelCodeTab();
void updatePinAssignmentsTab();
void updatePinAssignmentsGridEditors();
void addParamPropertyIfRelevant( const SIM_MODEL::PARAM& aParam );
wxPGProperty* newParamProperty( const SIM_MODEL::PARAM& aParam ) const;
SIM_MODEL& getCurModel() const;
wxString getSymbolPinString( int aSymbolPinNumber ) const;
wxString getModelPinString( int aModelPinNumber ) const;
int getModelPinNumber( const wxString& aModelPinString ) const;
void onDeviceTypeChoice( wxCommandEvent& aEvent ) override;
void onTypeChoice( wxCommandEvent& aEvent ) override;
void onPinAssignmentsGridCellChange( wxGridEvent& aEvent ) override;
void onPinAssignmentsGridSize( wxSizeEvent& aEvent ) override;
virtual void onSelectionChange( wxPropertyGridEvent& aEvent );
//void onPropertyChanged( wxPropertyGridEvent& aEvent ) override;
SCH_SYMBOL& m_symbol;
std::vector<T>& m_fields;
@ -65,7 +79,6 @@ private:
std::map<SIM_MODEL::DEVICE_TYPE, SIM_MODEL::TYPE> m_curModelTypeOfDeviceType;
SIM_MODEL::TYPE m_curModelType = SIM_MODEL::TYPE::NONE;
wxPropertyGridPage* m_paramGrid;
wxPGProperty* m_firstCategory; // Used to add principal parameters to root (any better ideas?)
std::unique_ptr<SCINTILLA_TRICKS> m_scintillaTricks;
};

View File

@ -46,7 +46,7 @@ DIALOG_SPICE_MODEL_BASE::DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID i
m_staticText124->Wrap( -1 );
fgSizer15->Add( m_staticText124, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
m_staticText125 = new wxStaticText( sbSizer4->GetStaticBox(), wxID_ANY, wxT("/home/mikolaj/Downloads/1N4148.lib"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText125 = new wxStaticText( sbSizer4->GetStaticBox(), wxID_ANY, wxT("etc/kicad-sim/diodes.lib"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText125->Wrap( -1 );
fgSizer15->Add( m_staticText125, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
@ -94,8 +94,10 @@ DIALOG_SPICE_MODEL_BASE::DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID i
bSizer12->Add( fgSizer16, 0, wxEXPAND, 5 );
m_paramGridMgr = new wxPropertyGridManager(m_parametersPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPGMAN_DEFAULT_STYLE);
m_paramGridMgr = new wxPropertyGridManager(m_parametersPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxPGMAN_DEFAULT_STYLE|wxPG_SPLITTER_AUTO_CENTER);
m_paramGridMgr->SetExtraStyle( wxPG_EX_MODE_BUTTONS|wxPG_EX_NATIVE_DOUBLE_BUFFERING );
m_paramGrid = m_paramGridMgr->AddPage( wxT("Page"), wxNullBitmap );
bSizer12->Add( m_paramGridMgr, 1, wxALL|wxEXPAND, 5 );
@ -165,34 +167,34 @@ DIALOG_SPICE_MODEL_BASE::DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID i
wxBoxSizer* bSizer10;
bSizer10 = new wxBoxSizer( wxVERTICAL );
m_pinAssignmentGrid = new WX_GRID( m_pinAssignmentsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_pinAssignmentsGrid = new WX_GRID( m_pinAssignmentsPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
// Grid
m_pinAssignmentGrid->CreateGrid( 0, 2 );
m_pinAssignmentGrid->EnableEditing( true );
m_pinAssignmentGrid->EnableGridLines( true );
m_pinAssignmentGrid->EnableDragGridSize( false );
m_pinAssignmentGrid->SetMargins( 0, 0 );
m_pinAssignmentsGrid->CreateGrid( 0, 2 );
m_pinAssignmentsGrid->EnableEditing( true );
m_pinAssignmentsGrid->EnableGridLines( true );
m_pinAssignmentsGrid->EnableDragGridSize( false );
m_pinAssignmentsGrid->SetMargins( 0, 0 );
// Columns
m_pinAssignmentGrid->SetColSize( 0, 160 );
m_pinAssignmentGrid->SetColSize( 1, 160 );
m_pinAssignmentGrid->EnableDragColMove( false );
m_pinAssignmentGrid->EnableDragColSize( true );
m_pinAssignmentGrid->SetColLabelValue( 0, wxT("Schematic Pin") );
m_pinAssignmentGrid->SetColLabelValue( 1, wxT("Model Pin") );
m_pinAssignmentGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_pinAssignmentsGrid->SetColSize( 0, 160 );
m_pinAssignmentsGrid->SetColSize( 1, 160 );
m_pinAssignmentsGrid->EnableDragColMove( false );
m_pinAssignmentsGrid->EnableDragColSize( true );
m_pinAssignmentsGrid->SetColLabelValue( 0, wxT("Symbol Pin") );
m_pinAssignmentsGrid->SetColLabelValue( 1, wxT("Model Pin") );
m_pinAssignmentsGrid->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Rows
m_pinAssignmentGrid->EnableDragRowSize( false );
m_pinAssignmentGrid->SetRowLabelSize( 0 );
m_pinAssignmentGrid->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
m_pinAssignmentsGrid->EnableDragRowSize( false );
m_pinAssignmentsGrid->SetRowLabelSize( 0 );
m_pinAssignmentsGrid->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
// Label Appearance
// Cell Defaults
m_pinAssignmentGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP );
bSizer10->Add( m_pinAssignmentGrid, 1, wxALL|wxEXPAND, 5 );
m_pinAssignmentsGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_TOP );
bSizer10->Add( m_pinAssignmentsGrid, 1, wxALL|wxEXPAND, 5 );
m_pinAssignmentsPanel->SetSizer( bSizer10 );
@ -226,6 +228,9 @@ DIALOG_SPICE_MODEL_BASE::DIALOG_SPICE_MODEL_BASE( wxWindow* parent, wxWindowID i
// Connect Events
m_deviceTypeChoice->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onDeviceTypeChoice ), NULL, this );
m_typeChoice->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onTypeChoice ), NULL, this );
m_paramGridMgr->Connect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( DIALOG_SPICE_MODEL_BASE::onPropertyChanged ), NULL, this );
m_pinAssignmentsGrid->Connect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_SPICE_MODEL_BASE::onPinAssignmentsGridCellChange ), NULL, this );
m_pinAssignmentsGrid->Connect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_SPICE_MODEL_BASE::onPinAssignmentsGridSize ), NULL, this );
}
DIALOG_SPICE_MODEL_BASE::~DIALOG_SPICE_MODEL_BASE()
@ -233,5 +238,8 @@ DIALOG_SPICE_MODEL_BASE::~DIALOG_SPICE_MODEL_BASE()
// Disconnect Events
m_deviceTypeChoice->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onDeviceTypeChoice ), NULL, this );
m_typeChoice->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SPICE_MODEL_BASE::onTypeChoice ), NULL, this );
m_paramGridMgr->Disconnect( wxEVT_PG_CHANGED, wxPropertyGridEventHandler( DIALOG_SPICE_MODEL_BASE::onPropertyChanged ), NULL, this );
m_pinAssignmentsGrid->Disconnect( wxEVT_GRID_CELL_CHANGED, wxGridEventHandler( DIALOG_SPICE_MODEL_BASE::onPinAssignmentsGridCellChange ), NULL, this );
m_pinAssignmentsGrid->Disconnect( wxEVT_SIZE, wxSizeEventHandler( DIALOG_SPICE_MODEL_BASE::onPinAssignmentsGridSize ), NULL, this );
}

View File

@ -190,11 +190,11 @@
<property name="orient">wxVERTICAL</property>
<property name="parent">1</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxFlexGridSizer" expanded="0">
<object class="wxFlexGridSizer" expanded="1">
<property name="cols">3</property>
<property name="flexible_direction">wxBOTH</property>
<property name="growablecols">1</property>
@ -497,7 +497,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">/home/mikolaj/Downloads/1N4148.lib</property>
<property name="label">etc/kicad-sim/diodes.lib</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
@ -1044,13 +1044,20 @@
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxPGMAN_DEFAULT_STYLE</property>
<property name="style">wxPGMAN_DEFAULT_STYLE|wxPG_SPLITTER_AUTO_CENTER</property>
<property name="subclass">; ; forward_declare</property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnPropertyGridChanged">onPropertyChanged</event>
<object class="propGridPage" expanded="1">
<property name="bitmap"></property>
<property name="label">Page</property>
<property name="name">m_paramGrid</property>
<property name="permission">protected</property>
</object>
</object>
</object>
</object>
@ -1281,7 +1288,7 @@
<property name="close_button">1</property>
<property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
<property name="col_label_size"></property>
<property name="col_label_values">&quot;Schematic Pin&quot; &quot;Model Pin&quot;</property>
<property name="col_label_values">&quot;Symbol Pin&quot; &quot;Model Pin&quot;</property>
<property name="col_label_vert_alignment">wxALIGN_CENTER</property>
<property name="cols">2</property>
<property name="column_sizes">160,160</property>
@ -1317,7 +1324,7 @@
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_pinAssignmentGrid</property>
<property name="name">m_pinAssignmentsGrid</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
@ -1339,6 +1346,8 @@
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnGridCellChange">onPinAssignmentsGridCellChange</event>
<event name="OnSize">onPinAssignmentsGridSize</event>
</object>
</object>
</object>

View File

@ -62,10 +62,11 @@ class DIALOG_SPICE_MODEL_BASE : public wxDialog
wxStaticText* m_staticText8;
wxChoice* m_typeChoice;
wxPropertyGridManager* m_paramGridMgr;
wxPropertyGridPage* m_paramGrid;
wxPanel* m_codePanel;
wxStyledTextCtrl* m_codePreview;
wxPanel* m_pinAssignmentsPanel;
WX_GRID* m_pinAssignmentGrid;
WX_GRID* m_pinAssignmentsGrid;
wxStaticLine* m_staticline1;
wxCheckBox* m_excludeSymbol;
wxStdDialogButtonSizer* m_sdbSizer1;
@ -75,6 +76,9 @@ class DIALOG_SPICE_MODEL_BASE : public wxDialog
// Virtual event handlers, override them in your derived class
virtual void onDeviceTypeChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void onTypeChoice( wxCommandEvent& event ) { event.Skip(); }
virtual void onPropertyChanged( wxPropertyGridEvent& event ) { event.Skip(); }
virtual void onPinAssignmentsGridCellChange( wxGridEvent& event ) { event.Skip(); }
virtual void onPinAssignmentsGridSize( wxSizeEvent& event ) { event.Skip(); }
public:

View File

@ -958,6 +958,17 @@ std::vector<SCH_PIN*> SCH_SYMBOL::GetPins( const SCH_SHEET_PATH* aSheet ) const
}
std::vector<SCH_PIN*> SCH_SYMBOL::GetAllPins() const
{
std::vector<SCH_PIN*> pins;
for( const auto& p : m_pins )
pins.push_back( p.get() );
return pins;
}
void SCH_SYMBOL::SwapData( SCH_ITEM* aItem )
{
wxCHECK_RET( (aItem != nullptr) && (aItem->Type() == SCH_SYMBOL_T),

View File

@ -479,6 +479,14 @@ public:
*/
std::vector<SCH_PIN*> GetPins( const SCH_SHEET_PATH* aSheet = nullptr ) const;
/**
* Retrieve all SCH_PINs (from all sheets)
*
* @return a vector of pointers (non-owning) to SCH_PINs
*/
std::vector<SCH_PIN*> GetAllPins() const;
std::vector<std::unique_ptr<SCH_PIN>>& GetRawPins() { return m_pins; }
/**

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016-2018 CERN
* Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2018-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
* @author Maciej Suminski <maciej.suminski@cern.ch>

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* @author Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
*
@ -58,7 +58,7 @@ public:
LTRA,
TRANLINE,
URC,
TRANSLINE,
//TRANSLINE,
SWITCH,
CSWITCH,
DIODE,
@ -95,6 +95,7 @@ public:
wxString name;
wxString variant1;
wxString variant2;
std::vector<wxString> pinNames;
wxString description;
std::vector<SIM_MODEL::PARAM::INFO> modelParams;
std::vector<SIM_MODEL::PARAM::INFO> instanceParams;

View File

@ -26,8 +26,8 @@
#include <macros.h>
// This script was originally autogenerated using an ugly Bash script, but later modified manually.
// Search the Git history if you want to use it to add new models (but don't use it to regenerate
// the current ones).
// Search the Git history if you want to use that script to add new models, but don't use it to
// regenerate the current ones.
// We cannot use designated initializers until we upgrade to C++20 (we're C++17 now),
// so we do this instead.
@ -84,7 +84,7 @@ static auto QOR() { NGSPICE::PARAM_FLAGS p; p.orQuery=true; p.redundant=true; r
#define QO() {}
#define QOR() {}
const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( MODEL_TYPE aType )
{
// To speed up builds a switch statement is used instead of a std::map literal.
// NOTE: I'm not sure if that helped at all, so feel free to try to use std::map instead.
@ -93,15 +93,15 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
default:
wxFAIL;
KI_FALLTHROUGH;
case NGSPICE::MODEL_TYPE::NONE:
case NGSPICE::MODEL_TYPE::_ENUM_END:
case MODEL_TYPE::NONE:
case MODEL_TYPE::_ENUM_END:
{
static MODEL_INFO model = {};
return model;
}
case NGSPICE::MODEL_TYPE::RESISTOR:
case MODEL_TYPE::RESISTOR:
{
static MODEL_INFO model = { "Resistor", "R", "", "Simple linear resistor",
static MODEL_INFO model = { "Resistor", "R", "", { "+", "-" }, "Simple linear resistor",
// Model parameters
{
{ "rsh", 103, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, Q(), "ohm/m", SIM_MODEL::PARAM::CATEGORY::DISTRIBUTED_QUANTITIES, "0", "", "Sheet resistance" },
@ -157,9 +157,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::CAPACITOR:
case MODEL_TYPE::CAPACITOR:
{
static MODEL_INFO model = { "Capacitor", "C", "", "Fixed capacitor",
static MODEL_INFO model = { "Capacitor", "C", "", { "+", "-" }, "Fixed capacitor",
// Model parameters
{
{ "cap", 113, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, A(), "F", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "0", "", "Model capacitance" },
@ -209,9 +209,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::INDUCTOR:
case MODEL_TYPE::INDUCTOR:
{
static MODEL_INFO model = { "Inductor", "L", "", "Fixed inductor",
static MODEL_INFO model = { "Inductor", "L", "", { "+", "-" }, "Fixed inductor",
// Model parameters
{
{ "ind", 100, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, A(), "H", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "0", "", "Model inductance" },
@ -249,9 +249,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::LTRA:
case MODEL_TYPE::LTRA:
{
static MODEL_INFO model = { "LTRA", "LTRA", "", "Lossy transmission line",
static MODEL_INFO model = { "LTRA", "LTRA", "", { "1+", "1-", "2+", "2-" }, "Lossy transmission line",
// Model parameters
{
{ "ltra", 0, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::BOOL, {}, "", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "1", "", "LTRA model" },
@ -287,9 +287,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::TRANLINE:
case MODEL_TYPE::TRANLINE:
{
static MODEL_INFO model = { "Tranline", "", "", "Lossless transmission line",
static MODEL_INFO model = { "Tranline", "", "", { "1+", "1-", "2+", "2-" }, "Lossless transmission line",
// Model parameters
{
},
@ -315,9 +315,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::URC:
case MODEL_TYPE::URC:
{
static MODEL_INFO model = { "URC", "URC", "", "Uniform R.C. line",
static MODEL_INFO model = { "URC", "URC", "", { "1+", "2+", "-" }, "Uniform R.C. line",
// Model parameters
{
{ "k", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "", SIM_MODEL::PARAM::CATEGORY::PRINCIPAL, "1.5", "", "Propagation constant" },
@ -338,9 +338,10 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::TRANSLINE:
/*case MODEL_TYPE::TRANSLINE:
{
static MODEL_INFO model = { "TransLine", "", "", "Simple Lossy Transmission Line",
// FIXME: Second and fourth pins should be set to zero.
static MODEL_INFO model = { "TransLine", "", "", { "1+", "0", "2+", "0" }, "Simple Lossy Transmission Line",
// Model parameters
{
{ "r", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "ohm/m", SIM_MODEL::PARAM::CATEGORY::DISTRIBUTED_QUANTITIES, "", "", "resistance per length" },
@ -357,10 +358,10 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
{ "length", 3, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "m", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "", "", "length of line" },
} };
return model;
}
case NGSPICE::MODEL_TYPE::SWITCH:
}*/
case MODEL_TYPE::SWITCH:
{
static MODEL_INFO model = { "Switch", "SW", "", "Ideal voltage controlled switch",
static MODEL_INFO model = { "Switch", "SW", "", { "+", "-", "Ctrl+", "Ctrl-" }, "Ideal voltage controlled switch",
// Model parameters
{
{ "sw", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::BOOL, U(), "", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "NaN", "", "Switch model" },
@ -384,9 +385,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::CSWITCH:
case MODEL_TYPE::CSWITCH:
{
static MODEL_INFO model = { "CSwitch", "CSW", "", "Current controlled ideal switch",
static MODEL_INFO model = { "CSwitch", "CSW", "", { "+", "-", "Ctrl+", "Ctrl-" }, "Current controlled ideal switch",
// Model parameters
{
{ "csw", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::BOOL, U(), "", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "NaN", "", "Current controlled switch model" },
@ -409,9 +410,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::DIODE:
case MODEL_TYPE::DIODE:
{
static MODEL_INFO model = { "Diode", "D", "", "Junction Diode model",
static MODEL_INFO model = { "Diode", "D", "", { "Anode", "Cathode" }, "Junction Diode model",
// Model parameters
{
{ "level", 100, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "1", "", "Diode level selector" },
@ -429,7 +430,7 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
{ "tt", 104, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, A(), "s", SIM_MODEL::PARAM::CATEGORY::DC, "0", "", "Transit Time" },
{ "ttt1", 125, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, A(), "s", SIM_MODEL::PARAM::CATEGORY::TEMPERATURE, "0", "", "Transit Time 1st order temp. coeff." },
{ "ttt2", 126, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, A(), "s", SIM_MODEL::PARAM::CATEGORY::TEMPERATURE, "0", "", "Transit Time 2nd order temp. coeff." },
{ "cjo", 105, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, A(), "F", SIM_MODEL::PARAM::CATEGORY::DC, "0", "", "Junction capacitance" },
{ "cjo", 105, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, A(), "F", SIM_MODEL::PARAM::CATEGORY::CAPACITANCE, "0", "", "Junction capacitance" },
{ "cj0", 105, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, AR(), "F", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "0", "", "Junction capacitance" },
{ "cj", 105, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, AR(), "F", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "0", "", "Junction capacitance" },
{ "vj", 106, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "V", SIM_MODEL::PARAM::CATEGORY::DC, "1", "", "Junction potential" },
@ -438,7 +439,7 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
{ "mj", 107, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, R(), "", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "0.5", "", "n.a." },
{ "tm1", 127, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "1/deg C^2", SIM_MODEL::PARAM::CATEGORY::TEMPERATURE, "0", "", "Grading coefficient 1st temp. coeff." },
{ "tm2", 128, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "1/deg C", SIM_MODEL::PARAM::CATEGORY::TEMPERATURE, "0", "", "Grading coefficient 2nd temp. coeff." },
{ "cjp", 119, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "F", SIM_MODEL::PARAM::CATEGORY::DC, "0", "", "Sidewall junction capacitance" },
{ "cjp", 119, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "F", SIM_MODEL::PARAM::CATEGORY::CAPACITANCE, "0", "", "Sidewall junction capacitance" },
{ "cjsw", 119, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, R(), "", SIM_MODEL::PARAM::CATEGORY::SUPERFLUOUS, "0", "", "n.a." },
{ "php", 120, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "V", SIM_MODEL::PARAM::CATEGORY::DC, "1", "", "Sidewall junction potential" },
{ "mjsw", 121, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "0.33", "", "Sidewall Grading coefficient" },
@ -526,9 +527,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::BJT:
case MODEL_TYPE::BJT:
{
static MODEL_INFO model = { "BJT", "NPN", "PNP", "Bipolar Junction Transistor",
static MODEL_INFO model = { "BJT", "NPN", "PNP", { "Collector", "Base", "Emitter" }, "Bipolar Junction Transistor",
// Model parameters
{
{ "type", 309, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "npn", "pnp", "NPN or PNP" },
@ -742,9 +743,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::VBIC:
case MODEL_TYPE::VBIC:
{
static MODEL_INFO model = { "VBIC", "NPN", "PNP", "Vertical Bipolar Inter-Company Model",
static MODEL_INFO model = { "VBIC", "NPN", "PNP", { "Collector", "Base", "Emitter" }, "Vertical Bipolar Inter-Company Model",
// Model parameters
{
{ "type", 305, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "npn", "pnp", "NPN or PNP" },
@ -915,9 +916,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::HICUM2:
case MODEL_TYPE::HICUM2:
{
static MODEL_INFO model = { "hicum2", "NPN", "PNP", "High Current Model for BJT",
static MODEL_INFO model = { "hicum2", "NPN", "PNP", { "Collector", "Base", "Emitter" }, "High Current Model for BJT",
// Model parameters
{
{ "type", 305, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "npn", "pnp", "For transistor type NPN(+1) or PNP (-1)" },
@ -1136,9 +1137,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::JFET:
case MODEL_TYPE::JFET:
{
static MODEL_INFO model = { "JFET", "NJF", "PJF", "Junction Field effect transistor",
static MODEL_INFO model = { "JFET", "NJF", "PJF", { "Drain", "Gate", "Source" }, "Junction Field effect transistor",
// Model parameters
{
{ "type", 305, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "njf", "pjf", "N-type or P-type JFET model" },
@ -1203,9 +1204,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::JFET2:
case MODEL_TYPE::JFET2:
{
static MODEL_INFO model = { "JFET2", "NJF", "PJF", "Short channel field effect transistor",
static MODEL_INFO model = { "JFET2", "NJF", "PJF", { "Drain", "Gate", "Source" }, "Short channel field effect transistor",
// Model parameters
{
{ "type", 305, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "njf", "pjf", "N-type or P-type JFET2 model" },
@ -1283,9 +1284,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::MES:
case MODEL_TYPE::MES:
{
static MODEL_INFO model = { "MES", "NMF", "PMF", "GaAs MESFET model",
static MODEL_INFO model = { "MES", "NMF", "PMF", { "Drain", "Gate", "Source" }, "GaAs MESFET model",
// Model parameters
{
{ "type", 305, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::BOOL, {}, "", SIM_MODEL::PARAM::CATEGORY::FLAGS, "-693161728", "116101380", "N-type or P-type MESfet model" },
@ -1341,9 +1342,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::MESA:
case MODEL_TYPE::MESA:
{
static MODEL_INFO model = { "MESA", "NMF", "PMF", "GaAs MESFET model",
static MODEL_INFO model = { "MESA", "NMF", "PMF", { "Drain", "Gate", "Source" }, "GaAs MESFET model",
// Model parameters
{
{ "type", 165, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "nmf", "nmf", "N-type or P-type MESfet model" },
@ -1433,9 +1434,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::HFET1:
case MODEL_TYPE::HFET1:
{
static MODEL_INFO model = { "HFET1", "NMF", "PMF", "HFET1 Model",
static MODEL_INFO model = { "HFET1", "NMF", "PMF", { "Drain", "Gate", "Source", "Bulk" }, "HFET1 Model",
// Model parameters
{
{ "vt0", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "V", SIM_MODEL::PARAM::CATEGORY::DC, "0.15", "0.15", "Pinch-off voltage" },
@ -1494,9 +1495,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::HFET2:
case MODEL_TYPE::HFET2:
{
static MODEL_INFO model = { "HFET2", "NMF", "PMF", "HFET2 Model",
static MODEL_INFO model = { "HFET2", "NMF", "PMF", { "Drain", "Gate", "Source", "Bulk" }, "HFET2 Model",
// Model parameters
{
{ "type", 139, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "nhfet", "nhfet", "NHFET or PHFET" },
@ -1552,9 +1553,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::MOS1:
case MODEL_TYPE::MOS1:
{
static MODEL_INFO model = { "Mos1", "NMOS", "PMOS", "Level 1 MOSfet model with Meyer capacitance model",
static MODEL_INFO model = { "Mos1", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Level 1 MOSfet model with Meyer capacitance model",
// Model parameters
{
{ "type", 133, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "nmos", "pmos", "N-channel or P-channel MOS" },
@ -1674,9 +1675,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::MOS2:
case MODEL_TYPE::MOS2:
{
static MODEL_INFO model = { "Mos2", "NMOS", "PMOS", "Level 2 MOSfet model with Meyer capacitance model",
static MODEL_INFO model = { "Mos2", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Level 2 MOSfet model with Meyer capacitance model",
// Model parameters
{
{ "type", 141, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "nmos", "pmos", "N-channel or P-channel MOS" },
@ -1803,9 +1804,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::MOS3:
case MODEL_TYPE::MOS3:
{
static MODEL_INFO model = { "Mos3", "NMOS", "PMOS", "Level 3 MOSfet model with Meyer capacitance model",
static MODEL_INFO model = { "Mos3", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Level 3 MOSfet model with Meyer capacitance model",
// Model parameters
{
{ "type", 144, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "nmos", "pmos", "N-channel or P-channel MOS" },
@ -1943,9 +1944,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::BSIM1:
case MODEL_TYPE::BSIM1:
{
static MODEL_INFO model = { "BSIM1", "NMOS", "PMOS", "Berkeley Short Channel IGFET Model",
static MODEL_INFO model = { "BSIM1", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Berkeley Short Channel IGFET Model",
// Model parameters
{
{ "vfb", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "V", SIM_MODEL::PARAM::CATEGORY::DC, "0", "0", "Flat band voltage" },
@ -2049,9 +2050,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::BSIM2:
case MODEL_TYPE::BSIM2:
{
static MODEL_INFO model = { "BSIM2", "NMOS", "PMOS", "Berkeley Short Channel IGFET Model",
static MODEL_INFO model = { "BSIM2", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Berkeley Short Channel IGFET Model",
// Model parameters
{
{ "vfb", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::FLOAT, {}, "V", SIM_MODEL::PARAM::CATEGORY::DC, "-1", "-1", "Flat band voltage" },
@ -2211,9 +2212,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::MOS6:
case MODEL_TYPE::MOS6:
{
static MODEL_INFO model = { "Mos6", "NMOS", "PMOS", "Level 6 MOSfet model with Meyer capacitance model",
static MODEL_INFO model = { "Mos6", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Level 6 MOSfet model with Meyer capacitance model",
// Model parameters
{
{ "type", 140, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "nmos", "pmos", "N-channel or P-channel MOS" },
@ -2342,9 +2343,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::BSIM3:
case MODEL_TYPE::BSIM3:
{
static MODEL_INFO model = { "BSIM3", "NMOS", "PMOS", "Berkeley Short Channel IGFET Model Version-3",
static MODEL_INFO model = { "BSIM3", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Berkeley Short Channel IGFET Model Version-3",
// Model parameters
{
{ "capmod", 100, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::CAPACITANCE, "3", "3", "Capacitance model selector" },
@ -2828,9 +2829,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::MOS9:
case MODEL_TYPE::MOS9:
{
static MODEL_INFO model = { "Mos9", "NMOS", "PMOS", "Modified Level 3 MOSfet model",
static MODEL_INFO model = { "Mos9", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Modified Level 3 MOSfet model",
// Model parameters
{
{ "type", 144, SIM_MODEL::PARAM::DIR::OUT, SIM_VALUE_BASE::TYPE::STRING, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "nmos", "pmos", "N-channel or P-channel MOS" },
@ -2968,9 +2969,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::B4SOI:
case MODEL_TYPE::B4SOI:
{
static MODEL_INFO model = { "B4SOI", "NMOS", "PMOS", "Berkeley SOI MOSFET model version 4.4.0",
static MODEL_INFO model = { "B4SOI", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Berkeley SOI MOSFET model version 4.4.0",
// Model parameters
{
{ "mtrlmod", 100, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "0", "0", "parameter for non-silicon substrate or metal gate selector" },
@ -3968,9 +3969,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::BSIM4:
case MODEL_TYPE::BSIM4:
{
static MODEL_INFO model = { "BSIM4", "NMOS", "PMOS", "Berkeley Short Channel IGFET Model-4",
static MODEL_INFO model = { "BSIM4", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Berkeley Short Channel IGFET Model-4",
// Model parameters
{
{ "cvchargemod", 76, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::CAPACITANCE, "0", "0", "Capacitance Charge model selector" },
@ -4955,9 +4956,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::B3SOIFD:
case MODEL_TYPE::B3SOIFD:
{
static MODEL_INFO model = { "B3SOIFD", "NMOS", "PMOS", "Berkeley SOI MOSFET (FD) model version 2.1",
static MODEL_INFO model = { "B3SOIFD", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Berkeley SOI MOSFET (FD) model version 2.1",
// Model parameters
{
{ "capmod", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::CAPACITANCE, "2", "2", "Capacitance model selector" },
@ -5386,9 +5387,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::B3SOIDD:
case MODEL_TYPE::B3SOIDD:
{
static MODEL_INFO model = { "B3SOIDD", "NMOS", "PMOS", "Berkeley SOI MOSFET (DD) model version 2.1",
static MODEL_INFO model = { "B3SOIDD", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Berkeley SOI MOSFET (DD) model version 2.1",
// Model parameters
{
{ "capmod", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::CAPACITANCE, "2", "2", "Capacitance model selector" },
@ -5817,9 +5818,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::B3SOIPD:
case MODEL_TYPE::B3SOIPD:
{
static MODEL_INFO model = { "B3SOIPD", "NMOS", "PMOS", "Berkeley SOI (PD) MOSFET model version 2.2.3",
static MODEL_INFO model = { "B3SOIPD", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Berkeley SOI (PD) MOSFET model version 2.2.3",
// Model parameters
{
{ "capmod", 101, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::CAPACITANCE, "2", "2", "Capacitance model selector" },
@ -6334,9 +6335,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::HISIM2:
case MODEL_TYPE::HISIM2:
{
static MODEL_INFO model = { "HiSIM2", "NMOS", "PMOS", "Hiroshima University STARC IGFET Model 2.8.0",
static MODEL_INFO model = { "HiSIM2", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Hiroshima University STARC IGFET Model 2.8.0",
// Model parameters
{
{ "info", 4, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "0", "0", "information level (for debug, etc.)" },
@ -6890,9 +6891,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::HISIMHV1:
case MODEL_TYPE::HISIMHV1:
{
static MODEL_INFO model = { "HiSIMHV1", "NMOS", "PMOS", "Hiroshima University STARC IGFET Model - HiSIM_HV v.1",
static MODEL_INFO model = { "HiSIMHV1", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Hiroshima University STARC IGFET Model - HiSIM_HV v.1",
// Model parameters
{
{ "info", 4, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "0", "0", "Information level (for debug, etc.)" },
@ -7503,9 +7504,9 @@ const NGSPICE::MODEL_INFO& NGSPICE::ModelInfo( NGSPICE::MODEL_TYPE aType )
} };
return model;
}
case NGSPICE::MODEL_TYPE::HISIMHV2:
case MODEL_TYPE::HISIMHV2:
{
static MODEL_INFO model = { "HiSIMHV2", "NMOS", "PMOS", "Hiroshima University STARC IGFET Model - HiSIM_HV v.2",
static MODEL_INFO model = { "HiSIMHV2", "NMOS", "PMOS", { "Drain", "Gate", "Source", "Bulk" }, "Hiroshima University STARC IGFET Model - HiSIM_HV v.2",
// Model parameters
{
{ "info", 4, SIM_MODEL::PARAM::DIR::INOUT, SIM_VALUE_BASE::TYPE::INT, {}, "", SIM_MODEL::PARAM::CATEGORY::DC, "0", "0", "Information level (for debug, etc.)" },

File diff suppressed because it is too large Load Diff

View File

@ -25,13 +25,13 @@
#ifndef SIM_MODEL_H
#define SIM_MODEL_H
#include <map>
#include <stdexcept>
#include <enum_vector.h>
#include <sch_field.h>
#include <lib_field.h>
#include <sim/sim_value.h>
#include <wx/string.h>
#include <map>
#include <stdexcept>
class SIM_MODEL
@ -40,6 +40,7 @@ public:
static constexpr auto DEVICE_TYPE_FIELD = "Model_Device";
static constexpr auto TYPE_FIELD = "Model_Type";
static constexpr auto FILE_FIELD = "Model_File";
static constexpr auto PIN_SEQUENCE_FIELD = "Model_Pin_Sequence";
static constexpr auto PARAMS_FIELD = "Model_Params";
@ -237,6 +238,15 @@ public:
};
struct PIN
{
static constexpr auto NOT_CONNECTED = 0;
int symbolPinNumber;
const wxString name;
};
struct PARAM
{
enum class DIR
@ -290,16 +300,19 @@ public:
static DEVICE_INFO DeviceTypeInfo( DEVICE_TYPE aDeviceType );
static INFO TypeInfo( TYPE aType );
template <typename T>
static TYPE ReadTypeFromFields( const std::vector<T>& aFields );
template <typename T>
static std::unique_ptr<SIM_MODEL> Create( const std::vector<T>& aFields );
static std::unique_ptr<SIM_MODEL> Create( TYPE aType );
template <typename T>
static std::unique_ptr<SIM_MODEL> Create( int symbolPinCount, const std::vector<T>& aFields );
template <typename T = void>
static std::unique_ptr<SIM_MODEL> Create( TYPE aType,
int symbolPinCount,
const std::vector<T>* aFields = nullptr );
// Move semantics.
@ -312,40 +325,59 @@ public:
SIM_MODEL( TYPE aType );
template <typename T>
SIM_MODEL( const std::vector<T>& aFields );
void ReadDataFields( int symbolPinCount, const std::vector<T>* aFields );
// C++ doesn't allow virtual template methods, so we do this:
virtual void ReadDataSchFields( int symbolPinCount, const std::vector<SCH_FIELD>* aFields );
virtual void ReadDataLibFields( int symbolPinCount, const std::vector<LIB_FIELD>* aFields );
template <typename T>
void WriteFields( std::vector<T>& aFields );
// C++ doesn't allow virtual template methods, so we do this:
virtual void DoWriteSchFields( std::vector<SCH_FIELD>& aFields );
virtual void DoWriteLibFields( std::vector<LIB_FIELD>& aFields );
virtual void WriteDataSchFields( std::vector<SCH_FIELD>& aFields );
virtual void WriteDataLibFields( std::vector<LIB_FIELD>& aFields );
virtual void WriteCode( wxString& aCode ) = 0;
TYPE GetType() { return m_type; }
wxString GetFile() { return m_file; }
void SetFile( const wxString& aFile ) { m_file = aFile; }
virtual wxString GetFile() { return m_file; }
virtual void SetFile( const wxString& aFile ) { m_file = aFile; }
std::vector<PIN>& Pins() { return m_pins; }
std::vector<PARAM>& Params() { return m_params; }
private:
TYPE m_type;
wxString m_file;
std::vector<PIN> m_pins;
std::vector<PARAM> m_params;
template <typename T>
static wxString getFieldValue( const std::vector<T>& aFields, const wxString& aFieldName );
void doReadDataFields( int symbolPinCount, const std::vector<T>* aFields );
template <typename T>
void doWriteFields( std::vector<T>& aFields );
template <typename T>
static wxString getFieldValue( const std::vector<T>* aFields, const wxString& aFieldName );
template <typename T>
static void setFieldValue( std::vector<T>& aFields, const wxString& aFieldName,
const wxString& aValue );
virtual std::vector<wxString> getPinNames() { return {}; }
wxString generatePinSequence();
void parsePinSequence( int symbolPinCount, const wxString& aPinSequence );
virtual wxString generateParamValuePairs();
virtual void parseParamValuePairs( const wxString& aParamValuePairs );

View File

@ -24,7 +24,18 @@
#include <sim/sim_model_behavioral.h>
SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType ) : SIM_MODEL( aType )
template SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
: SIM_MODEL( aType )
{
static PARAM::INFO resistor = makeParamInfo( "r", "Expression for resistance", "ohm" );
static PARAM::INFO capacitor = makeParamInfo( "c", "Expression for capacitance", "F" );
@ -42,6 +53,8 @@ SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType ) : SIM_MODEL( aType )
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_IDEAL" );
}
ReadDataFields( symbolPinCount, aFields );
}

View File

@ -31,7 +31,8 @@
class SIM_MODEL_BEHAVIORAL : public SIM_MODEL
{
public:
SIM_MODEL_BEHAVIORAL( TYPE aType );
template <typename T = void>
SIM_MODEL_BEHAVIORAL( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;

View File

@ -24,7 +24,18 @@
#include <sim/sim_model_codemodel.h>
SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType ) : SIM_MODEL( aType )
template SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_CODEMODEL::SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
: SIM_MODEL( aType )
{
}

View File

@ -31,7 +31,8 @@
class SIM_MODEL_CODEMODEL : public SIM_MODEL
{
public:
SIM_MODEL_CODEMODEL( TYPE aType );
template <typename T = void>
SIM_MODEL_CODEMODEL( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;
};

View File

@ -27,7 +27,17 @@
using PARAM = SIM_MODEL::PARAM;
SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType ) : SIM_MODEL( aType )
template SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
: SIM_MODEL( aType )
{
static PARAM::INFO resistor = makeParamInfo( "r", "Resistance", "ohm" );
static PARAM::INFO capacitor = makeParamInfo( "c", "Capacitance", "F" );
@ -41,6 +51,8 @@ SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType ) : SIM_MODEL( aType )
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_IDEAL" );
}
ReadDataFields( symbolPinCount, aFields );
}
@ -50,6 +62,12 @@ void SIM_MODEL_IDEAL::WriteCode( wxString& aCode )
}
std::vector<wxString> SIM_MODEL_IDEAL::getPinNames()
{
return { "+", "-" };
}
PARAM::INFO SIM_MODEL_IDEAL::makeParamInfo( wxString aName, wxString aDescription, wxString aUnit )
{
SIM_MODEL::PARAM::INFO paramInfo = {};

View File

@ -31,11 +31,14 @@
class SIM_MODEL_IDEAL : public SIM_MODEL
{
public:
SIM_MODEL_IDEAL( TYPE aType );
template <typename T = void>
SIM_MODEL_IDEAL( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;
private:
std::vector<wxString> getPinNames() override;
static PARAM::INFO makeParamInfo( wxString aName, wxString aDescription, wxString aUnit );
};

View File

@ -27,7 +27,17 @@
using TYPE = SIM_MODEL::TYPE;
SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType ) : SIM_MODEL( aType )
template SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
: SIM_MODEL( aType )
{
const NGSPICE::MODEL_INFO& modelInfo = NGSPICE::ModelInfo( getModelType() );
@ -42,6 +52,8 @@ SIM_MODEL_NGSPICE::SIM_MODEL_NGSPICE( TYPE aType ) : SIM_MODEL( aType )
Params().emplace_back( paramInfo );
Params().back().isOtherVariant = getIsOtherVariant();
}
ReadDataFields( symbolPinCount, aFields );
}
@ -51,6 +63,12 @@ void SIM_MODEL_NGSPICE::WriteCode( wxString& aCode )
}
std::vector<wxString> SIM_MODEL_NGSPICE::getPinNames()
{
return NGSPICE::ModelInfo( getModelType() ).pinNames;
}
NGSPICE::MODEL_TYPE SIM_MODEL_NGSPICE::getModelType()
{
switch( GetType() )
@ -62,7 +80,7 @@ NGSPICE::MODEL_TYPE SIM_MODEL_NGSPICE::getModelType()
case TYPE::TLINE_LOSSY: return NGSPICE::MODEL_TYPE::LTRA;
case TYPE::TLINE_LOSSLESS: return NGSPICE::MODEL_TYPE::TRANLINE;
case TYPE::TLINE_UNIFORM_RC: return NGSPICE::MODEL_TYPE::URC;
case TYPE::TLINE_KSPICE: return NGSPICE::MODEL_TYPE::TRANSLINE;
//case TYPE::TLINE_KSPICE: return NGSPICE::MODEL_TYPE::TRANSLINE;
case TYPE::SWITCH_VCTRL: return NGSPICE::MODEL_TYPE::SWITCH;
case TYPE::SWITCH_ICTRL: return NGSPICE::MODEL_TYPE::CSWITCH;
case TYPE::DIODE: return NGSPICE::MODEL_TYPE::DIODE;

View File

@ -32,11 +32,14 @@
class SIM_MODEL_NGSPICE : public SIM_MODEL
{
public:
SIM_MODEL_NGSPICE( TYPE aType );
template <typename T = void>
SIM_MODEL_NGSPICE( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;
private:
std::vector<wxString> getPinNames() override;
NGSPICE::MODEL_TYPE getModelType();
bool getIsOtherVariant();
};

View File

@ -25,8 +25,19 @@
#include <sim/sim_model_rawspice.h>
SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType ) : SIM_MODEL( aType )
template SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_RAWSPICE::SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
: SIM_MODEL( aType )
{
ReadDataFields( symbolPinCount, aFields );
}

View File

@ -31,7 +31,8 @@
class SIM_MODEL_RAWSPICE : public SIM_MODEL
{
public:
SIM_MODEL_RAWSPICE( TYPE aType );
template <typename T = void>
SIM_MODEL_RAWSPICE( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;
};

View File

@ -27,10 +27,21 @@
using PARAM = SIM_MODEL::PARAM;
SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType ) : SIM_MODEL( aType )
template SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount, const std::vector<T>* aFields )
: SIM_MODEL( aType )
{
for( const PARAM::INFO& paramInfo : makeParams( aType ) )
Params().emplace_back( paramInfo );
ReadDataFields( symbolPinCount, aFields );
}
@ -480,12 +491,12 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeWhiteNoise( wxString aPrefix, wxS
paramInfo.description = "White noise RMS amplitude";
paramInfos.push_back( paramInfo );
paramInfo.name = "rtsam";
paramInfo.name = "nt";
paramInfo.type = SIM_VALUE_BASE::TYPE::FLOAT;
paramInfo.unit = aUnit;
paramInfo.unit = "s";
paramInfo.category = SIM_MODEL::PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "0";
paramInfo.description = "Burst noise amplitude";
paramInfo.description = "Time step";
paramInfos.push_back( paramInfo );
return paramInfos;
@ -497,6 +508,14 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makePinkNoise( wxString aPrefix, wxSt
std::vector<PARAM::INFO> paramInfos;
PARAM::INFO paramInfo;
paramInfo.name = aPrefix + "o";
paramInfo.type = SIM_VALUE_BASE::TYPE::FLOAT;
paramInfo.unit = aUnit;
paramInfo.category = SIM_MODEL::PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "";
paramInfo.description = "DC offset";
paramInfos.push_back( paramInfo );
paramInfo.name = "nalpha";
paramInfo.type = SIM_VALUE_BASE::TYPE::FLOAT;
paramInfo.unit = "";
@ -530,6 +549,14 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeBurstNoise( wxString aPrefix, wxS
std::vector<PARAM::INFO> paramInfos;
PARAM::INFO paramInfo;
paramInfo.name = "rtsam";
paramInfo.type = SIM_VALUE_BASE::TYPE::FLOAT;
paramInfo.unit = aUnit;
paramInfo.category = SIM_MODEL::PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "0";
paramInfo.description = "Burst noise amplitude";
paramInfos.push_back( paramInfo );
paramInfo.name = "rtscapt";
paramInfo.type = SIM_VALUE_BASE::TYPE::FLOAT;
paramInfo.unit = "s";

View File

@ -31,7 +31,8 @@
class SIM_MODEL_SOURCE : public SIM_MODEL
{
public:
SIM_MODEL_SOURCE( TYPE aType );
template <typename T = void>
SIM_MODEL_SOURCE( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;

View File

@ -24,8 +24,20 @@
#include <sim/sim_model_subcircuit.h>
SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType ) : SIM_MODEL( aType )
template SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount,
const std::vector<void>* aFields );
template SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount,
const std::vector<SCH_FIELD>* aFields );
template SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount,
const std::vector<LIB_FIELD>* aFields );
template <typename T>
SIM_MODEL_SUBCIRCUIT::SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount,
const std::vector<T>* aFields )
: SIM_MODEL( aType )
{
ReadDataFields( symbolPinCount, aFields );
}

View File

@ -31,7 +31,8 @@
class SIM_MODEL_SUBCIRCUIT : public SIM_MODEL
{
public:
SIM_MODEL_SUBCIRCUIT( TYPE aType );
template <typename T = void>
SIM_MODEL_SUBCIRCUIT( TYPE aType, int symbolPinCount, const std::vector<T>* aFields = nullptr );
void WriteCode( wxString& aCode ) override;
};

View File

@ -0,0 +1,185 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <sim/sim_property.h>
#include <sim/sim_value.h>
#include <ki_exception.h>
#include <confirm.h>
#include <wx/combo.h>
#include <wx/combobox.h>
wxBEGIN_EVENT_TABLE( SIM_VALIDATOR, wxValidator )
EVT_TEXT( wxID_ANY, SIM_VALIDATOR::onText )
EVT_CHAR( SIM_VALIDATOR::onChar )
EVT_MOUSE_EVENTS( SIM_VALIDATOR::onMouse )
wxEND_EVENT_TABLE()
SIM_VALIDATOR::SIM_VALIDATOR( SIM_VALUE_BASE::TYPE aValueType,
SIM_VALUE_PARSER::NOTATION aNotation )
: wxValidator(),
m_valueType( aValueType ),
m_notation( aNotation )
{
wxTextEntry* textEntry = getTextEntry();
if( !textEntry )
return;
m_prevText = textEntry->GetValue();
m_prevInsertionPoint = textEntry->GetInsertionPoint();
}
wxObject* SIM_VALIDATOR::Clone() const
{
return new SIM_VALIDATOR( *this );
}
bool SIM_VALIDATOR::Validate( wxWindow* aParent )
{
if( !m_validatorWindow->IsEnabled() )
return true;
wxTextEntry* const textEntry = getTextEntry();
if( !textEntry )
return false;
return isValid( textEntry->GetValue() );
}
bool SIM_VALIDATOR::TransferToWindow()
{
return true;
}
bool SIM_VALIDATOR::TransferFromWindow()
{
return true;
}
bool SIM_VALIDATOR::isValid( const wxString& aString )
{
return SIM_VALUE_PARSER::IsValid( aString, m_valueType, m_notation );
}
wxTextEntry* SIM_VALIDATOR::getTextEntry()
{
// Taken from wxTextValidator.
if( wxDynamicCast( m_validatorWindow, wxTextCtrl ) )
return ( wxTextCtrl* ) m_validatorWindow;
if( wxDynamicCast( m_validatorWindow, wxComboBox ) )
return ( wxComboBox* ) m_validatorWindow;
if( wxDynamicCast( m_validatorWindow, wxComboCtrl ) )
return ( wxComboCtrl* ) m_validatorWindow;
wxFAIL_MSG(
"SIM_VALIDATOR can only be used with wxTextCtrl, wxComboBox, or wxComboCtrl"
);
return nullptr;
}
void SIM_VALIDATOR::onText( wxCommandEvent& aEvent )
{
wxTextEntry* textEntry = getTextEntry();
if( !textEntry )
return;
if( !isValid( textEntry->GetValue() ) )
{
textEntry->ChangeValue( m_prevText );
textEntry->SetInsertionPoint( m_prevInsertionPoint );
}
m_prevText = textEntry->GetValue();
m_prevInsertionPoint = textEntry->GetInsertionPoint();
}
void SIM_VALIDATOR::onChar( wxKeyEvent& aEvent )
{
aEvent.Skip();
wxTextEntry* textEntry = getTextEntry();
if( !textEntry )
return;
m_prevInsertionPoint = textEntry->GetInsertionPoint();
}
void SIM_VALIDATOR::onMouse( wxMouseEvent& aEvent )
{
aEvent.Skip();
wxTextEntry* textEntry = getTextEntry();
if( !textEntry )
return;
m_prevInsertionPoint = textEntry->GetInsertionPoint();
}
SIM_PROPERTY::SIM_PROPERTY( const wxString& aLabel, const wxString& aName,
SIM_VALUE_BASE& aValue,
SIM_VALUE_BASE::TYPE aValueType,
SIM_VALUE_PARSER::NOTATION aNotation )
: wxStringProperty( aLabel, aName, aValue.ToString() ),
m_valueType( aValueType ),
m_notation( aNotation ),
m_value( aValue )
{
}
wxValidator* SIM_PROPERTY::DoGetValidator() const
{
return new SIM_VALIDATOR( m_valueType, m_notation );
}
bool SIM_PROPERTY::StringToValue( wxVariant& aVariant, const wxString& aText, int aArgFlags ) const
{
try
{
m_value.FromString( aText );
}
catch( KI_PARAM_ERROR& e )
{
aVariant = aText;
return false;
}
aVariant = m_value.ToString();
return true;
}

View File

@ -0,0 +1,80 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2022 Mikolaj Wielgus
* Copyright (C) 2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef SIM_PROPERTY_H
#define SIM_PROPERTY_H
#include <sim/sim_value.h>
#include <wx/propgrid/props.h>
class SIM_VALIDATOR : public wxValidator
{
public:
SIM_VALIDATOR( SIM_VALUE_BASE::TYPE aValueType, SIM_VALUE_PARSER::NOTATION aNotation );
SIM_VALIDATOR( const SIM_VALIDATOR& aValidator ) = default;
wxObject* Clone() const override;
bool Validate( wxWindow* aParent ) override;
bool TransferToWindow() override;
bool TransferFromWindow() override;
private:
bool isValid( const wxString& aString );
wxTextEntry* getTextEntry();
void onText( wxCommandEvent& aEvent );
void onChar( wxKeyEvent& aEvent );
void onMouse( wxMouseEvent& aEvent );
SIM_VALUE_BASE::TYPE m_valueType;
SIM_VALUE_PARSER::NOTATION m_notation;
wxString m_prevText;
long m_prevInsertionPoint;
wxDECLARE_EVENT_TABLE();
};
class SIM_PROPERTY : public wxStringProperty
{
public:
SIM_PROPERTY( const wxString& aLabel, const wxString& aName, SIM_VALUE_BASE& aValue,
SIM_VALUE_BASE::TYPE aValueType = SIM_VALUE_BASE::TYPE::FLOAT,
SIM_VALUE_PARSER::NOTATION aNotation = SIM_VALUE_PARSER::NOTATION::SI );
wxValidator* DoGetValidator() const override;
bool StringToValue( wxVariant& aVariant, const wxString& aText, int aArgFlags = 0 )
const override;
protected:
SIM_VALUE_BASE::TYPE m_valueType;
SIM_VALUE_PARSER::NOTATION m_notation;
SIM_VALUE_BASE& m_value;
};
#endif // SIM_PROPERTY_H

View File

@ -23,8 +23,290 @@
*/
#include <sim/sim_value.h>
#include <wx/translation.h>
#include <ki_exception.h>
#include <locale_io.h>
#include <complex>
#include <pegtl/contrib/parse_tree.hpp>
#define CALL_INSTANCE( ValueType, Notation, func, ... ) \
switch( ValueType ) \
{ \
case SIM_VALUE_BASE::TYPE::INT: \
switch( Notation ) \
{ \
case NOTATION::SI: \
func<SIM_VALUE_BASE::TYPE::INT, NOTATION::SI>( __VA_ARGS__ ); \
break; \
\
case NOTATION::SPICE: \
func<SIM_VALUE_BASE::TYPE::INT, NOTATION::SPICE>( __VA_ARGS__ ); \
break; \
} \
break; \
\
case SIM_VALUE_BASE::TYPE::FLOAT: \
switch( Notation ) \
{ \
case NOTATION::SI: \
func<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SI>( __VA_ARGS__ ); \
break; \
\
case NOTATION::SPICE: \
func<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SPICE>( __VA_ARGS__ ); \
break; \
} \
break; \
\
case SIM_VALUE_BASE::TYPE::BOOL: \
case SIM_VALUE_BASE::TYPE::COMPLEX: \
case SIM_VALUE_BASE::TYPE::STRING: \
case SIM_VALUE_BASE::TYPE::BOOL_VECTOR: \
case SIM_VALUE_BASE::TYPE::INT_VECTOR: \
case SIM_VALUE_BASE::TYPE::FLOAT_VECTOR: \
case SIM_VALUE_BASE::TYPE::COMPLEX_VECTOR: \
wxFAIL_MSG( "Unhandled SIM_VALUE_BASE type" ); \
break; \
}
template <SIM_VALUE_BASE::TYPE ValueType, SIM_VALUE_PARSER::NOTATION Notation>
static inline void doIsValid( tao::pegtl::string_input<>& aIn )
{
tao::pegtl::parse<SIM_VALUE_PARSER::numberGrammar<ValueType, Notation>>( aIn );
}
bool SIM_VALUE_PARSER::IsValid( const wxString& aString,
SIM_VALUE_BASE::TYPE aValueType,
NOTATION aNotation )
{
tao::pegtl::string_input<> in( aString, "from_input" );
try
{
CALL_INSTANCE( aValueType, aNotation, doIsValid, in );
}
catch( tao::pegtl::parse_error& e )
{
return false;
}
return true;
}
template <SIM_VALUE_BASE::TYPE ValueType, SIM_VALUE_PARSER::NOTATION Notation>
static inline std::unique_ptr<tao::pegtl::parse_tree::node> doParse(
tao::pegtl::string_input<>& aIn )
{
return tao::pegtl::parse_tree::parse<SIM_VALUE_PARSER::numberGrammar<ValueType, Notation>,
SIM_VALUE_PARSER::numberSelector>
( aIn );
}
template <SIM_VALUE_BASE::TYPE ValueType, SIM_VALUE_PARSER::NOTATION Notation>
static inline void handleNodeForParse( tao::pegtl::parse_tree::node& aNode,
SIM_VALUE_PARSER::PARSE_RESULT& aParseResult )
{
if( aNode.is_type<SIM_VALUE_PARSER::significand<ValueType>>() )
{
aParseResult.significand = aNode.string();
aParseResult.isEmpty = false;
for( const auto& subnode : aNode.children )
{
if( subnode->is_type<SIM_VALUE_PARSER::intPart>() )
aParseResult.intPart = std::stol( subnode->string() );
else if( subnode->is_type<SIM_VALUE_PARSER::fracPart>() )
aParseResult.fracPart = std::stol( subnode->string() );
}
}
else if( aNode.is_type<SIM_VALUE_PARSER::exponent>() )
{
aParseResult.exponent = std::stol( aNode.string() );
aParseResult.isEmpty = false;
}
else if( aNode.is_type<SIM_VALUE_PARSER::metricSuffix<ValueType, Notation>>() )
{
aParseResult.metricSuffixExponent =
SIM_VALUE_PARSER::MetricSuffixToExponent( aNode.string(), Notation );
aParseResult.isEmpty = false;
}
else
wxFAIL_MSG( "Unhandled parse tree node" );
}
SIM_VALUE_PARSER::PARSE_RESULT SIM_VALUE_PARSER::Parse( const wxString& aString,
SIM_VALUE_BASE::TYPE aValueType,
NOTATION aNotation )
{
LOCALE_IO toggle;
tao::pegtl::string_input<> in( aString.ToStdString(), "from_input" );
std::unique_ptr<tao::pegtl::parse_tree::node> root;
try
{
CALL_INSTANCE( aValueType, aNotation, root = doParse, in );
}
catch( tao::pegtl::parse_error& e )
{
throw KI_PARAM_ERROR( wxString::Format( _( "Failed to parse '%s': %s" ), aString,
e.what() ) );
}
wxASSERT( root );
PARSE_RESULT result;
try
{
for( const auto& node : root->children )
CALL_INSTANCE( aValueType, aNotation, handleNodeForParse, *node, result );
}
catch( std::invalid_argument& e )
{
throw KI_PARAM_ERROR( wxString::Format( _( "Failed to parse '%s': %s" ), aString,
e.what() ) );
}
return result;
}
long SIM_VALUE_PARSER::MetricSuffixToExponent( std::string aMetricSuffix, NOTATION aNotation )
{
switch( aNotation )
{
case NOTATION::SI:
if( aMetricSuffix.empty() )
return 0;
switch( aMetricSuffix[0] )
{
case 'a': return -18;
case 'f': return -15;
case 'p': return -12;
case 'n': return -9;
case 'u': return -6;
case 'm': return -3;
case 'k':
case 'K': return 3;
case 'M': return 6;
case 'G': return 9;
case 'T': return 12;
case 'P': return 15;
case 'E': return 18;
}
break;
case NOTATION::SPICE:
std::transform( aMetricSuffix.begin(), aMetricSuffix.end(), aMetricSuffix.begin(),
::tolower );
if( aMetricSuffix == "f" )
return -15;
else if( aMetricSuffix == "p" )
return -12;
else if( aMetricSuffix == "n" )
return -9;
else if( aMetricSuffix == "u" )
return -6;
else if( aMetricSuffix == "m" )
return -3;
else if( aMetricSuffix == "" )
return 0;
else if( aMetricSuffix == "k" )
return 3;
else if( aMetricSuffix == "meg" )
return 6;
else if( aMetricSuffix == "g" )
return 9;
else if( aMetricSuffix == "t" )
return 12;
break;
}
throw KI_PARAM_ERROR( wxString::Format( _( "Unknown simulator value suffix: \"%s\"" ),
aMetricSuffix ) );
}
wxString SIM_VALUE_PARSER::ExponentToMetricSuffix( double aExponent, long& aReductionExponent,
NOTATION aNotation )
{
if( aNotation == NOTATION::SI && aExponent >= -18 && aExponent <= -15 )
{
aReductionExponent = -18;
return "a";
}
else if( aExponent > -15 && aExponent <= -12 )
{
aReductionExponent = -15;
return "f";
}
else if( aExponent > -12 && aExponent <= -9 )
{
aReductionExponent = -12;
return "p";
}
else if( aExponent > -9 && aExponent <= -6 )
{
aReductionExponent = -9;
return "n";
}
else if( aExponent > -6 && aExponent <= -3 )
{
aReductionExponent = -6;
return "u";
}
else if( aExponent > -3 && aExponent < 0 )
{
aReductionExponent = -3;
return "m";
}
else if( aExponent > 0 && aExponent < 3 )
{
aReductionExponent = 0;
return "";
}
else if( aExponent >= 3 && aExponent < 6 )
{
aReductionExponent = 3;
return "k";
}
else if( aExponent >= 6 && aExponent < 9 )
{
aReductionExponent = 6;
return ( aNotation == NOTATION::SI ) ? "M" : "Meg";
}
else if( aExponent >= 9 && aExponent < 12 )
{
aReductionExponent = 9;
return "G";
}
else if( aExponent >= 12 && aExponent < 15 )
{
aReductionExponent = 12;
return "T";
}
else if( aNotation == NOTATION::SI && aExponent >= 15 && aExponent < 18 )
{
aReductionExponent = 15;
return "P";
}
else if( aNotation == NOTATION::SI && aExponent >= 18 && aExponent <= 21 )
{
aReductionExponent = 18;
return "E";
}
aReductionExponent = 0;
return "";
}
std::unique_ptr<SIM_VALUE_BASE> SIM_VALUE_BASE::Create( TYPE aType, wxString aString )
@ -50,7 +332,7 @@ std::unique_ptr<SIM_VALUE_BASE> SIM_VALUE_BASE::Create( TYPE aType )
case TYPE::COMPLEX_VECTOR: return std::make_unique<SIM_VALUE<std::complex<double>>>();
}
wxFAIL_MSG( "Unknown SIM_VALUE type" );
wxFAIL_MSG( _( "Unknown SIM_VALUE type" ) );
return nullptr;
}
@ -62,15 +344,105 @@ void SIM_VALUE_BASE::operator=( const wxString& aString )
template <typename T>
SIM_VALUE<T>::SIM_VALUE( const T& aValue ) : m_value(aValue)
SIM_VALUE<T>::SIM_VALUE( const T& aValue ) : m_value( aValue )
{
}
template <typename T>
void SIM_VALUE<T>::FromString( const wxString& aString )
template <>
void SIM_VALUE<bool>::FromString( const wxString& aString )
{
LOCALE_IO toggle;
SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( aString );
if( parseResult.isEmpty )
{
m_value = NULLOPT;
return;
}
if( !parseResult.intPart
|| ( *parseResult.intPart != 0 && *parseResult.intPart != 1 )
|| parseResult.fracPart
|| parseResult.exponent
|| parseResult.metricSuffixExponent )
{
throw KI_PARAM_ERROR( wxString::Format( _( "Invalid Bool simulator value string: '%s'" ),
aString ) );
}
m_value = *parseResult.intPart;
}
template <>
void SIM_VALUE<long>::FromString( const wxString& aString )
{
SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( aString );
if( parseResult.isEmpty )
{
m_value = NULLOPT;
return;
}
if( !parseResult.intPart || parseResult.fracPart )
{
throw KI_PARAM_ERROR( wxString::Format( _( "Invalid Int simulator value string: '%s'" ),
aString ) );
}
long exponent = parseResult.exponent ? *parseResult.exponent : 0;
exponent += parseResult.metricSuffixExponent ? *parseResult.metricSuffixExponent : 0;
m_value = static_cast<double>( *parseResult.intPart ) * std::pow( 10, exponent );
}
template <>
void SIM_VALUE<double>::FromString( const wxString& aString )
{
SIM_VALUE_PARSER::PARSE_RESULT parseResult = SIM_VALUE_PARSER::Parse( aString );
// Single dot should be allowed in fields.
// TODO: disallow single dot in models.
if( parseResult.isEmpty || parseResult.significand == "." )
{
m_value = NULLOPT;
return;
}
if( parseResult.significand.empty() )
throw KI_PARAM_ERROR( wxString::Format( _( "Invalid Float simulator value string: '%s'" ),
aString ) );
long exponent = parseResult.exponent ? *parseResult.exponent : 0;
exponent += parseResult.metricSuffixExponent ? *parseResult.metricSuffixExponent : 0;
m_value = std::stod( parseResult.significand ) * std::pow( 10, exponent );
}
template <>
void SIM_VALUE<std::complex<double>>::FromString( const wxString& aString )
{
// TODO
/*LOCALE_IO toggle;
double value = 0;
if( !aString.ToDouble( &value ) )
throw KI_PARAM_ERROR( _( "Invalid complex sim value string" ) );
m_value = value;*/
}
template <>
void SIM_VALUE<wxString>::FromString( const wxString& aString )
{
m_value = aString;
}
@ -95,7 +467,11 @@ template <>
wxString SIM_VALUE<bool>::ToString() const
{
LOCALE_IO toggle;
return wxString::Format( "%d", m_value );
if( m_value.has_value() )
return wxString::Format( "%d", *m_value );
return "";
}
@ -103,7 +479,20 @@ template <>
wxString SIM_VALUE<long>::ToString() const
{
LOCALE_IO toggle;
return wxString::Format( "%d", m_value );
if( m_value.has_value() )
{
double exponent = std::log10( *m_value );
long reductionExponent = 0;
wxString metricSuffix = SIM_VALUE_PARSER::ExponentToMetricSuffix( exponent,
reductionExponent );
long reducedValue = *m_value / static_cast<long>( std::pow( 10, reductionExponent ) );
return wxString::Format( "%d%s", reducedValue, metricSuffix );
}
return "";
}
@ -111,7 +500,20 @@ template <>
wxString SIM_VALUE<double>::ToString() const
{
LOCALE_IO toggle;
return wxString::Format( "%f", m_value );
if( m_value.has_value() )
{
double exponent = std::log10( *m_value );
long reductionExponent = 0;
wxString metricSuffix = SIM_VALUE_PARSER::ExponentToMetricSuffix( exponent,
reductionExponent );
double reducedValue = *m_value / std::pow( 10, reductionExponent );
return wxString::Format( "%g%s", reducedValue, metricSuffix );
}
else
return "";
}
@ -119,7 +521,11 @@ template <>
wxString SIM_VALUE<std::complex<double>>::ToString() const
{
LOCALE_IO toggle;
return wxString::Format( "%f+%fi", m_value.real(), m_value.imag() );
if( m_value.has_value() )
return wxString::Format( "%g+%gi", m_value->real(), m_value->imag() );
return "";
}
@ -127,7 +533,38 @@ template <>
wxString SIM_VALUE<wxString>::ToString() const
{
LOCALE_IO toggle;
return m_value;
if( m_value.has_value() )
return *m_value;
return ""; // Empty string is completely equivalent to null string.
}
template <typename T>
wxString SIM_VALUE<T>::ToSimpleString() const
{
if( m_value.has_value() )
{
wxString result = "";
result << *m_value;
return result;
}
return "";
}
template <>
wxString SIM_VALUE<std::complex<double>>::ToSimpleString() const
{
// TODO
/*wxString result = "";
result << *m_value;
return result;*/
return "";
}

View File

@ -25,8 +25,11 @@
#ifndef SIM_VALUE_H
#define SIM_VALUE_H
#include <memory>
#include <wx/string.h>
#include <core/optional.h>
#include <memory>
#include <pegtl.hpp>
class SIM_VALUE_BASE
{
@ -48,11 +51,17 @@ public:
static std::unique_ptr<SIM_VALUE_BASE> Create( TYPE aType, wxString aString );
static std::unique_ptr<SIM_VALUE_BASE> Create( TYPE aType );
virtual ~SIM_VALUE_BASE() = default;
SIM_VALUE_BASE() = default;
void operator=( const wxString& aString );
virtual bool operator==( const SIM_VALUE_BASE& aOther ) const = 0;
virtual void FromString( const wxString& aString ) = 0;
virtual wxString ToString() const = 0;
// For parsers that don't accept strings with our suffixes.
virtual wxString ToSimpleString() const = 0;
};
@ -65,12 +74,134 @@ public:
void FromString( const wxString& aString ) override;
wxString ToString() const override;
wxString ToSimpleString() const override;
void operator=( const T& aValue );
bool operator==( const SIM_VALUE_BASE& aOther ) const override;
private:
T m_value;
OPT<T> m_value = NULLOPT;
wxString getMetricSuffix();
};
#endif /* SIM_VALUE_H */
namespace SIM_VALUE_PARSER
{
using namespace tao::pegtl;
enum class NOTATION
{
SI,
SPICE
};
template <NOTATION Notation>
wxString allowedIntChars;
struct spaces : plus<space> {};
struct digits : plus<tao::pegtl::digit> {}; // For some reason it fails on just "digit".
struct sign : one<'+', '-'> {};
struct intPart : digits {};
//struct fracPartPrefix : one<'.'> {};
struct fracPart : digits {};
//struct fracPartWithPrefix : seq<fracPartPrefix, fracPart> {};
template <SIM_VALUE_BASE::TYPE ValueType>
struct significand;
template <> struct significand<SIM_VALUE_BASE::TYPE::FLOAT> :
sor<seq<intPart, one<'.'>, fracPart>,
seq<intPart, one<'.'>>,
intPart,
seq<one<'.'>, fracPart>,
one<'.'>> {};
template <> struct significand<SIM_VALUE_BASE::TYPE::INT> : intPart {};
struct exponentPrefix : one<'e', 'E'> {};
struct exponent : seq<opt<sign>, opt<digits>> {};
struct exponentWithPrefix : seq<exponentPrefix, exponent> {};
template <SIM_VALUE_BASE::TYPE ValueType, NOTATION Notation>
struct metricSuffix;
template <> struct metricSuffix<SIM_VALUE_BASE::TYPE::INT, NOTATION::SI>
: one<'k', 'K', 'M', 'G', 'T', 'P', 'E'> {};
template <> struct metricSuffix<SIM_VALUE_BASE::TYPE::INT, NOTATION::SPICE>
: sor<TAO_PEGTL_ISTRING( "k" ),
TAO_PEGTL_ISTRING( "Meg" ),
TAO_PEGTL_ISTRING( "G" ),
TAO_PEGTL_ISTRING( "T" )> {};
template <> struct metricSuffix<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SI>
: one<'a', 'f', 'p', 'n', 'u', 'm', 'k', 'K', 'M', 'G', 'T', 'P', 'E'> {};
template <> struct metricSuffix<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SPICE>
: sor<TAO_PEGTL_ISTRING( "f" ),
TAO_PEGTL_ISTRING( "p" ),
TAO_PEGTL_ISTRING( "n" ),
TAO_PEGTL_ISTRING( "u" ),
TAO_PEGTL_ISTRING( "m" ),
//TAO_PEGTL_ISTRING( "mil" ),
TAO_PEGTL_ISTRING( "k" ),
TAO_PEGTL_ISTRING( "Meg" ),
TAO_PEGTL_ISTRING( "G" ),
TAO_PEGTL_ISTRING( "T" )> {};
template <SIM_VALUE_BASE::TYPE ValueType, NOTATION Notation>
struct number : seq<significand<ValueType>,
opt<exponentWithPrefix>,
opt<metricSuffix<ValueType, Notation>>> {};
template <SIM_VALUE_BASE::TYPE ValueType, NOTATION Notation>
struct numberGrammar : must<opt<number<ValueType, Notation>>, eof> {};
template <typename Rule>
struct numberSelector : std::false_type {};
template <> struct numberSelector<significand<SIM_VALUE_BASE::TYPE::INT>> : std::true_type {};
template <> struct numberSelector<significand<SIM_VALUE_BASE::TYPE::FLOAT>> : std::true_type {};
template <> struct numberSelector<intPart> : std::true_type {};
template <> struct numberSelector<fracPart> : std::true_type {};
template <> struct numberSelector<exponent> : std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::INT, NOTATION::SI>>
: std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::INT, NOTATION::SPICE>>
: std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SI>>
: std::true_type {};
template <> struct numberSelector<metricSuffix<SIM_VALUE_BASE::TYPE::FLOAT, NOTATION::SPICE>>
: std::true_type {};
struct PARSE_RESULT
{
bool isEmpty = true;
std::string significand;
OPT<long> intPart;
OPT<long> fracPart;
OPT<long> exponent;
OPT<long> metricSuffixExponent;
};
bool IsValid( const wxString& aString,
SIM_VALUE_BASE::TYPE aValueType = SIM_VALUE_BASE::TYPE::FLOAT,
NOTATION aNotation = NOTATION::SI );
PARSE_RESULT Parse( const wxString& aString,
SIM_VALUE_BASE::TYPE aValueType = SIM_VALUE_BASE::TYPE::FLOAT,
NOTATION aNotation = NOTATION::SI );
long MetricSuffixToExponent( std::string aMetricSuffix, NOTATION aNotation = NOTATION::SI );
wxString ExponentToMetricSuffix( double aExponent, long& aReductionExponent,
NOTATION aNotation = NOTATION::SI );
}
#endif // SIM_VALUE_H

View File

@ -73,10 +73,10 @@ BOOST_AUTO_TEST_CASE( Models )
BOOST_CHECK_EQUAL( instanceParamCount, 5 );
break;
case NGSPICE::MODEL_TYPE::TRANSLINE:
/*case NGSPICE::MODEL_TYPE::TRANSLINE:
BOOST_CHECK_EQUAL( modelParamCount, 6 );
BOOST_CHECK_EQUAL( instanceParamCount, 3 );
break;
break;*/
case NGSPICE::MODEL_TYPE::DIODE:
BOOST_CHECK_EQUAL( modelParamCount, 76 );