7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-18 20:09:18 +00:00

Sim Model Editor improvements

- Tab-switching,
- Automatic expansion of categories on tab-switch,
- Various minor simulation improvements,
- Various new simulation-related bugfixes.
This commit is contained in:
Mikolaj Wielgus 2022-06-12 05:39:13 +02:00
parent 6984f63af8
commit 739b9255d9
56 changed files with 85981 additions and 991 deletions

View File

@ -1,337 +0,0 @@
{
"board": {
"design_settings": {
"defaults": {
"board_outline_line_width": 0.1,
"copper_line_width": 0.2,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"other_line_width": 0.15,
"silk_line_width": 0.15,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.15
},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"rules": {
"min_copper_edge_clearance": 0.0,
"solder_mask_clearance": 0.0,
"solder_mask_min_width": 0.0
},
"track_widths": [],
"via_dimensions": []
},
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_label_syntax": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "subsheets.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12.0,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6.0
}
],
"meta": {
"version": 2
},
"net_colors": null
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"specctra_dsn": "",
"step": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"ngspice": {
"fix_include_paths": true,
"fix_passive_vals": false,
"meta": {
"version": 0
},
"model_mode": 0,
"workbook_filename": ""
},
"page_layout_descr_file": "",
"plot_directory": "",
"spice_adjust_passive_values": false,
"spice_external_command": "spice \"%I\"",
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"e63e39d7-6ac0-4ffd-8aa3-1841a4541b55",
""
],
[
"51ab3a6c-36b1-4056-a2d2-39c83ee99c02",
"subsheet1"
],
[
"cd8140cb-ee2c-44d2-bab6-19a75f861228",
"subsheet2"
]
],
"text_variables": {}
}

View File

@ -327,7 +327,6 @@ if( KICAD_SPICE )
sim/sim_model_xspice.cpp
sim/sim_model_ideal.cpp
sim/sim_model_ngspice.cpp
sim/sim_model_passive.cpp
sim/sim_model_spice.cpp
sim/sim_model_source.cpp
sim/sim_model_subckt.cpp

View File

@ -46,8 +46,11 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
m_fields( aFields ),
m_library( std::make_shared<SIM_LIBRARY_SPICE>() ),
m_prevModel( nullptr ),
m_firstCategory( nullptr )
m_firstCategory( nullptr ),
m_prevParamGridSelection( nullptr )
{
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
m_models.push_back( SIM_MODEL::Create( type, m_symbol.GetAllPins().size() ) );
@ -67,7 +70,8 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
m_scintillaTricks = std::make_unique<SCINTILLA_TRICKS>( m_codePreview, wxT( "{}" ), false );
m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onSelectionChange, this );
m_paramGridMgr->Bind( wxEVT_PG_SELECTED, &DIALOG_SIM_MODEL::onParamGridSelectionChange,
this );
m_paramGrid->SetValidationFailureBehavior( wxPG_VFB_STAY_IN_PROPERTY
| wxPG_VFB_BEEP
@ -81,17 +85,14 @@ DIALOG_SIM_MODEL<T>::DIALOG_SIM_MODEL( wxWindow* aParent, SCH_SYMBOL& aSymbol,
if( wxPropertyGrid* grid = m_paramGrid->GetGrid() )
{
grid->Bind( wxEVT_SET_FOCUS, &DIALOG_SIM_MODEL::onParamGridSetFocus, this );
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;
@ -191,25 +192,29 @@ void DIALOG_SIM_MODEL<T>::updateModelParamsTab()
if( &curModel() != m_prevModel )
{
SIM_MODEL::DEVICE_TYPE deviceType = SIM_MODEL::TypeInfo( curModel().GetType() ).deviceType;
m_deviceTypeChoice->SetSelection( static_cast<int>( deviceType ) );
m_typeChoice->Clear();
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
// Change the Type choice to match the current device type.
if( !m_prevModel || deviceType != m_prevModel->GetDeviceType() )
{
if( SIM_MODEL::TypeInfo( type ).deviceType == deviceType )
m_deviceTypeChoice->SetSelection( static_cast<int>( deviceType ) );
m_typeChoice->Clear();
for( SIM_MODEL::TYPE type : SIM_MODEL::TYPE_ITERATOR() )
{
wxString description = SIM_MODEL::TypeInfo( type ).description;
if( SIM_MODEL::TypeInfo( type ).deviceType == deviceType )
{
wxString description = SIM_MODEL::TypeInfo( type ).description;
if( !description.IsEmpty() )
m_typeChoice->Append( description );
if( !description.IsEmpty() )
m_typeChoice->Append( description );
if( type == curModel().GetType() )
m_typeChoice->SetSelection( m_typeChoice->GetCount() - 1 );
if( type == curModel().GetType() )
m_typeChoice->SetSelection( m_typeChoice->GetCount() - 1 );
}
}
}
// This wxPropertyGridManager column and header stuff has to be here because it segfaults in
// the constructor.
@ -224,7 +229,10 @@ void DIALOG_SIM_MODEL<T>::updateModelParamsTab()
m_paramGrid->Clear();
m_firstCategory = m_paramGrid->Append( new wxPropertyCategory( "DC" ) );
m_firstCategory = m_paramGrid->Append( new wxPropertyCategory( "AC" ) );
m_paramGrid->HideProperty( "AC" );
m_paramGrid->Append( new wxPropertyCategory( "DC" ) );
m_paramGrid->HideProperty( "DC" );
m_paramGrid->Append( new wxPropertyCategory( "Capacitance" ) );
@ -251,10 +259,10 @@ void DIALOG_SIM_MODEL<T>::updateModelParamsTab()
m_paramGrid->Append( new wxPropertyCategory( "Flags" ) );
m_paramGrid->HideProperty( "Flags" );
m_paramGrid->CollapseAll();
for( unsigned i = 0; i < curModel().GetParamCount(); ++i )
addParamPropertyIfRelevant( i );
m_paramGrid->CollapseAll();
}
// Either enable all properties or disable all except the principal ones.
@ -397,11 +405,15 @@ void DIALOG_SIM_MODEL<T>::loadLibrary( const wxString& aFilePath )
{
const wxString absolutePath = Prj().AbsolutePath( aFilePath );
if( !m_library->ReadFile( Prj().AbsolutePath( aFilePath ) ) )
try
{
DisplayErrorMessage( this, wxString::Format( _( "Error loading model library '%s'" ),
Prj().AbsolutePath( aFilePath ), aFilePath ),
m_library->GetErrorMessage() );
m_library->ReadFile( absolutePath );
}
catch( const IO_ERROR& e )
{
DisplayErrorMessage( this, wxString::Format( _( "Failed reading model library '%s'." ),
absolutePath ),
e.What() );
}
m_libraryPathInput->SetValue( aFilePath );
@ -427,6 +439,12 @@ void DIALOG_SIM_MODEL<T>::addParamPropertyIfRelevant( int aParamIndex )
switch( curModel().GetParam( aParamIndex ).info.category )
{
case CATEGORY::AC:
m_paramGrid->HideProperty( "AC", false );
m_paramGrid->AppendIn( "AC", newParamProperty( aParamIndex ) );
m_paramGrid->Expand( "AC" );
break;
case CATEGORY::DC:
m_paramGrid->HideProperty( "DC", false );
m_paramGrid->AppendIn( "DC", newParamProperty( aParamIndex ) );
@ -790,9 +808,10 @@ void DIALOG_SIM_MODEL<T>::onTypeChoiceUpdate( wxUpdateUIEvent& aEvent )
template <typename T>
void DIALOG_SIM_MODEL<T>::onSelectionChange( wxPropertyGridEvent& aEvent )
void DIALOG_SIM_MODEL<T>::onParamGridSetFocus( wxFocusEvent& aEvent )
{
// TODO: Activate also when the whole property grid is selected with tab key.
// By default, when a property grid is focused, the textbox is not immediately focused, until
// Tab key is pressed. This is inconvenient, so we fix that here.
wxPropertyGrid* grid = m_paramGrid->GetGrid();
if( !grid )
@ -801,35 +820,81 @@ void DIALOG_SIM_MODEL<T>::onSelectionChange( wxPropertyGridEvent& aEvent )
return;
}
wxWindow* editorControl = grid->GetEditorControl();
if( !editorControl )
wxPGProperty* selected = grid->GetSelection();
if( !selected )
selected = grid->wxPropertyGridInterface::GetFirst();
if( selected )
grid->DoSelectProperty( selected, wxPG_SEL_FOCUS );
aEvent.Skip();
}
template <typename T>
void DIALOG_SIM_MODEL<T>::onParamGridSelectionChange( wxPropertyGridEvent& aEvent )
{
wxPropertyGrid* grid = m_paramGrid->GetGrid();
if( !grid )
{
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() )
// Jump over categories.
if( grid->GetSelection() && grid->GetSelection()->IsCategory() )
{
if( param.info.name == name )
wxPGProperty* selection = grid->GetSelection();
// If the new selection is immediately above the previous selection, we jump up. Otherwise
// we jump down. We do this by simulating up or down arrow keys.
wxPropertyGridIterator it = grid->GetIterator( wxPG_ITERATE_VISIBLE, selection );
it.Next();
wxKeyEvent* keyEvent = new wxKeyEvent( wxEVT_KEY_DOWN );
if( *it == m_prevParamGridSelection )
{
try
if( !selection->IsExpanded() )
{
param.value->FromString( m_paramGrid->GetPropertyValueAsString( param.info.name ) );
grid->Expand( selection );
keyEvent->m_keyCode = WXK_DOWN;
wxQueueEvent( grid, keyEvent );
// Does not work for some reason.
/*m_paramGrid->DoSelectProperty( selection->Item( selection->GetChildCount() - 1 ),
wxPG_SEL_FOCUS );*/
}
catch( KI_PARAM_ERROR& e )
else
{
DisplayErrorMessage( this, e.What() );
keyEvent->m_keyCode = WXK_UP;
wxQueueEvent( grid, keyEvent );
}
}
else
{
if( !selection->IsExpanded() )
grid->Expand( selection );
keyEvent->m_keyCode = WXK_DOWN;
wxQueueEvent( grid, keyEvent );
}
m_prevParamGridSelection = grid->GetSelection();
return;
}
}*/
wxWindow* editorControl = grid->GetEditorControl();
if( !editorControl )
{
wxFAIL;
m_prevParamGridSelection = grid->GetSelection();
return;
}
// Without this the user had to press tab before they could edit the field.
editorControl->SetFocus();
m_prevParamGridSelection = grid->GetSelection();
}

View File

@ -86,8 +86,8 @@ private:
void onDeviceTypeChoiceUpdate( wxUpdateUIEvent& aEvent ) override;
void onTypeChoiceUpdate( wxUpdateUIEvent& aEvent ) override;
virtual void onSelectionChange( wxPropertyGridEvent& aEvent );
//void onPropertyChanged( wxPropertyGridEvent& aEvent ) override;
void onParamGridSetFocus( wxFocusEvent& aEvent );
void onParamGridSelectionChange( wxPropertyGridEvent& aEvent );
SCH_SYMBOL& m_symbol;
@ -101,8 +101,10 @@ private:
std::vector<std::shared_ptr<SIM_MODEL>> m_libraryModels;
const SIM_MODEL* m_prevModel;
wxPGProperty* m_firstCategory; // Used to add principal parameters to root (any better ideas?)
wxPGProperty* m_firstCategory; // Used to add principal parameters to root.
std::unique_ptr<SCINTILLA_TRICKS> m_scintillaTricks;
wxPGProperty* m_prevParamGridSelection;
};
#endif /* DIALOG_SPICE_MODEL_H */

View File

@ -24,9 +24,8 @@
*/
#include "netlist_exporter_spice.h"
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
#include <sim/sim_model_spice.h>
#include <sim/spice_grammar.h>
#include <common.h>
#include <confirm.h>
#include <pgm_base.h>
@ -36,6 +35,8 @@
#include <sch_text.h>
#include <sch_textbox.h>
#include <string_utils.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
namespace NETLIST_EXPORTER_SPICE_PARSER
@ -197,8 +198,20 @@ void NETLIST_EXPORTER_SPICE::ReadDirectives()
if( node->is_type<NETLIST_EXPORTER_SPICE_PARSER::dotTitle>() )
m_title = node->children.at( 0 )->string();
else if( node->is_type<NETLIST_EXPORTER_SPICE_PARSER::dotInclude>() )
m_libraries[node->children.at( 0 )->string()] =
SIM_LIBRARY::Create( node->children.at( 0 )->string() );
{
wxString path = node->children.at( 0 )->string();
try
{
m_libraries.try_emplace( path, SIM_LIBRARY::Create( path ) );
}
catch( const IO_ERROR& e )
{
DisplayErrorMessage( nullptr,
wxString::Format( "Failed reading model library '%s'.", path ),
e.What() );
}
}
else
m_directives.emplace_back( node->string() );
}
@ -219,13 +232,26 @@ void NETLIST_EXPORTER_SPICE::readLibraryField( SCH_SYMBOL& aSymbol, SPICE_ITEM&
// Special case for legacy models.
unsigned libParamIndex = static_cast<unsigned>( SIM_MODEL_SPICE::SPICE_PARAM::LIB );
path = model->GetParam( libParamIndex ).value->ToString();
m_rawIncludes.push_back( path );
return;
}
if( path.IsEmpty() )
return;
if( auto library = SIM_LIBRARY::Create( m_schematic->Prj().AbsolutePath( path ) ) )
m_libraries.try_emplace( path, std::move( library ) );
wxString absolutePath = m_schematic->Prj().AbsolutePath( path );
try
{
m_libraries.try_emplace( path, SIM_LIBRARY::Create( absolutePath ) );
}
catch( const IO_ERROR& e )
{
DisplayErrorMessage( nullptr, wxString::Format( "Failed reading model library '%s'.",
absolutePath ),
e.What() );
}
aItem.libraryPath = path;
}
@ -306,32 +332,41 @@ void NETLIST_EXPORTER_SPICE::readPins( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem,
}
void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter,
unsigned aNetlistOptions )
void NETLIST_EXPORTER_SPICE::writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
const wxString& aPath )
{
for( auto&& [libraryPath, library] : m_libraries )
// First, expand env vars, if any.
wxString expandedPath = ExpandEnvVarSubstitutions( aPath, &m_schematic->Prj() );
wxString fullPath;
if( aNetlistOptions & OPTION_ADJUST_INCLUDE_PATHS )
{
// First, expand env vars, if any.
wxString libName = ExpandEnvVarSubstitutions( libraryPath, &m_schematic->Prj() );
wxString fullPath;
if( aNetlistOptions & OPTION_ADJUST_INCLUDE_PATHS )
// Look for the library in known search locations.
fullPath = ResolveFile( expandedPath, &Pgm().GetLocalEnvVariables(),
&m_schematic->Prj() );
if( fullPath.IsEmpty() )
{
// Look for the library in known search locations.
fullPath = ResolveFile( libName, &Pgm().GetLocalEnvVariables(), &m_schematic->Prj() );
if( fullPath.IsEmpty() )
{
DisplayErrorMessage( nullptr,
wxString::Format( _( "Could not find library file '%s'" ), libName ) );
fullPath = libName;
}
DisplayErrorMessage( nullptr,
wxString::Format( _( "Could not find library file '%s'" ),
expandedPath ) );
fullPath = expandedPath;
}
else
fullPath = libName;
aFormatter.Print( 0, ".include \"%s\"\n", TO_UTF8( fullPath ) );
}
else
fullPath = expandedPath;
aFormatter.Print( 0, ".include \"%s\"\n", TO_UTF8( fullPath ) );
}
void NETLIST_EXPORTER_SPICE::writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions )
{
for( auto&& [path, library] : m_libraries )
writeInclude( aFormatter, aNetlistOptions, path );
for( const wxString& path : m_rawIncludes )
writeInclude( aFormatter, aNetlistOptions, path );
}

View File

@ -130,6 +130,9 @@ private:
std::set<wxString>& aRefNames );
void readPins( SCH_SYMBOL& aSymbol, SPICE_ITEM& aItem, int& notConnectedCounter );
void writeInclude( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions,
const wxString& aPath );
void writeIncludes( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions );
void writeModels( OUTPUTFORMATTER& aFormatter );
void writeItems( OUTPUTFORMATTER& aFormatter );
@ -137,6 +140,7 @@ private:
wxString m_title; ///< Spice simulation title found in the schematic sheet
std::vector<wxString> m_directives; ///< Spice directives found in the schematic sheet
std::map<wxString, std::unique_ptr<SIM_LIBRARY>> m_libraries; ///< Spice libraries
std::vector<wxString> m_rawIncludes;
std::set<wxString> m_nets;
std::list<SPICE_ITEM> m_items; ///< Items representing schematic symbols in Spice world
};

View File

@ -307,9 +307,7 @@ bool NGSPICE::LoadNetlist( const string& aNetlist )
bool NGSPICE::Run()
{
wxBusyCursor dummy;
LOCALE_IO c_locale; // ngspice works correctly only with C locale
LOCALE_IO toggle; // ngspice works correctly only with C locale
bool success = Command( "bg_run" ); // bg_* commands execute in a separate thread
if( success )

View File

@ -83,15 +83,9 @@ wxString NGSPICE_CIRCUIT_MODEL::GetSheetSimCommand()
}
wxString NGSPICE_CIRCUIT_MODEL::GetUsedSimCommand()
{
return m_simCommand.IsEmpty() ? GetSheetSimCommand() : m_simCommand;
}
SIM_TYPE NGSPICE_CIRCUIT_MODEL::GetSimType()
{
return CommandToSimType( GetUsedSimCommand() );
return CommandToSimType( GetSimCommand() );
}
@ -122,7 +116,7 @@ SIM_TYPE NGSPICE_CIRCUIT_MODEL::CommandToSimType( const wxString& aCmd )
bool NGSPICE_CIRCUIT_MODEL::ParseDCCommand( const wxString& aCmd, SPICE_DC_PARAMS* aSource1,
SPICE_DC_PARAMS* aSource2 )
SPICE_DC_PARAMS* aSource2 )
{
if( !aCmd.Lower().StartsWith( ".dc" ) )
return false;
@ -157,5 +151,7 @@ void NGSPICE_CIRCUIT_MODEL::WriteDirectives( OUTPUTFORMATTER& aFormatter,
unsigned aNetlistOptions ) const
{
NETLIST_EXPORTER_SPICE::WriteDirectives( aFormatter, aNetlistOptions );
aFormatter.Print( 0, "%s\n", TO_UTF8( GetSimCommand() ) );
if( GetUnderlyingSimCommand() != "" )
aFormatter.Print( 0, "%s\n", TO_UTF8( GetUnderlyingSimCommand() ) );
}

View File

@ -82,13 +82,19 @@ public:
}
/**
* Return the simulation command directive.
* Return the command directive that is in use (either from the sheet or from m_simCommand)
* @return
*/
const wxString& GetSimCommand() const
wxString GetSimCommand()
{
return m_simCommand;
return m_simCommand.IsEmpty() ? GetSheetSimCommand() : m_simCommand;
}
/**
* Return the simulation command directive if stored separately (not as a sheet directive).
*/
wxString GetUnderlyingSimCommand() const { return m_simCommand; }
/**
* Clear the simulation command directive.
*/
@ -97,12 +103,6 @@ public:
m_simCommand.Clear();
}
/**
* Return the command directive that is in use (either from the sheet or from m_simCommand
* @return
*/
wxString GetUsedSimCommand();
/**
* Return simulation type basing on the simulation command directives.
*

View File

@ -29,18 +29,15 @@
std::unique_ptr<SIM_LIBRARY> SIM_LIBRARY::Create( wxString aFilePath )
{
std::unique_ptr<SIM_LIBRARY> library = std::make_unique<SIM_LIBRARY_SPICE>();
if( !library->ReadFile( aFilePath ) )
return nullptr;
library->ReadFile( aFilePath );
return library;
}
bool SIM_LIBRARY::ReadFile( const wxString& aFilePath )
void SIM_LIBRARY::ReadFile( const wxString& aFilePath )
{
m_filePath = aFilePath;
return true;
}

View File

@ -37,9 +37,30 @@ public:
virtual ~SIM_LIBRARY() = default;
SIM_LIBRARY() = default;
/**
* Read library from a source file (e.g. in Spice format), and return a newly constructed
* object of an appropriate subclass.
*
* @param aFilePath Path to the file.
* @return The library loaded in a newly constructed object.
*/
static std::unique_ptr<SIM_LIBRARY> Create( wxString aFilePath );
virtual bool ReadFile( const wxString& aFilePath ) = 0;
/**
* Read library from a source file. Must be in the format appropriate to the subclass, e.g.
* Spice for SIM_LIBRARY_SPICE).
*
* @param aFilePath Path to the file.
* @throw IO_ERROR on read or parsing error.
*/
virtual void ReadFile( const wxString& aFilePath ) = 0;
/**
* Write library to a source file (e.g. in Spice format).
*
* @param aFilePath Path to the file.
* @throw IO_ERROR on write error.
*/
virtual void WriteFile( const wxString& aFilePath ) = 0;
SIM_MODEL* FindModel( const wxString& aModelName ) const;
@ -48,14 +69,14 @@ public:
const std::vector<wxString>& GetModelNames() const { return m_modelNames; }
wxString GetFilePath() const { return m_filePath; }
wxString GetErrorMessage() const { return m_errorMessage; }
wxString GetError() const { return m_error; }
protected:
std::vector<std::unique_ptr<SIM_MODEL>> m_models;
std::vector<wxString> m_modelNames;
wxString m_filePath;
wxString m_errorMessage;
wxString m_error;
};

View File

@ -24,6 +24,7 @@
#include <sim/sim_library_spice.h>
#include <sim/spice_grammar.h>
#include <ki_exception.h>
#include <locale_io.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
@ -48,12 +49,11 @@ namespace SIM_LIBRARY_SPICE_PARSER
};
bool SIM_LIBRARY_SPICE::ReadFile( const wxString& aFilePath )
void SIM_LIBRARY_SPICE::ReadFile( const wxString& aFilePath )
{
LOCALE_IO toggle;
if( !SIM_LIBRARY::ReadFile( aFilePath ) )
return false;
SIM_LIBRARY::ReadFile( aFilePath );
m_models.clear();
m_modelNames.clear();
@ -73,11 +73,10 @@ bool SIM_LIBRARY_SPICE::ReadFile( const wxString& aFilePath )
{
m_models.push_back( SIM_MODEL::Create( node->string() ) );
if( node->children.size() != 1 )
if( node->children.size() < 1
|| !node->children.at( 0 )->is_type<SIM_LIBRARY_SPICE_PARSER::modelName>() )
{
m_errorMessage = wxString::Format(
"Captured %d name tokens, expected one", node->children.size() );
return false;
THROW_IO_ERROR( wxString::Format( "Model name token not found" ) );
}
m_modelNames.emplace_back( node->children.at( 0 )->string() );
@ -88,27 +87,23 @@ bool SIM_LIBRARY_SPICE::ReadFile( const wxString& aFilePath )
}
else
{
m_errorMessage = wxString::Format( "Unhandled parse tree node: '%s'", node->string() );
return false;
THROW_IO_ERROR( wxString::Format( "Unhandled parse tree node: '%s'",
node->string() ) );
}
}
return true;
}
catch( const std::filesystem::filesystem_error& e )
{
m_errorMessage = wxString::Format( "Parsing failed: %s", e.what() );
return false;
THROW_IO_ERROR( e.what() );
}
catch( const tao::pegtl::parse_error& e )
{
m_errorMessage = wxString::Format( "Parsing failed: %s", e.what() );
return false;
THROW_IO_ERROR( e.what() );
}
}
void SIM_LIBRARY_SPICE::WriteFile( const wxString& aFilePath )
{
// Not implemented yet.
}

View File

@ -33,7 +33,10 @@ class SIM_LIBRARY_SPICE : public SIM_LIBRARY
// We'll make SIM_LIBRARY have no subclasses probably.
public:
bool ReadFile( const wxString& aFilePath ) override;
// @copydoc SIM_LIBRARY::ReadFile()
void ReadFile( const wxString& aFilePath ) override;
// @copydoc SIM_LIBRARY::WriteFile()
void WriteFile( const wxString& aFilePath ) override;
};

View File

@ -28,17 +28,17 @@
#include <sim/sim_model_behavioral.h>
#include <sim/sim_model_ideal.h>
#include <sim/sim_model_ngspice.h>
#include <sim/sim_model_passive.h>
#include <sim/sim_model_source.h>
#include <sim/sim_model_spice.h>
#include <sim/sim_model_subckt.h>
#include <sim/sim_model_tline.h>
#include <sim/sim_model_xspice.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
#include <sim/spice_grammar.h>
#include <locale_io.h>
#include <lib_symbol.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>
using DEVICE_TYPE = SIM_MODEL::DEVICE_TYPE;
using TYPE = SIM_MODEL::TYPE;
@ -126,15 +126,15 @@ SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType )
case TYPE::NONE: return { DEVICE_TYPE::NONE, "", "" };
case TYPE::R: return { DEVICE_TYPE::R, "", "Ideal" };
case TYPE::R_ADV: return { DEVICE_TYPE::R, "ADV", "Advanced" };
//case TYPE::R_ADV: return { DEVICE_TYPE::R, "ADV", "Advanced" };
case TYPE::R_BEHAVIORAL: return { DEVICE_TYPE::R, "=", "Behavioral" };
case TYPE::C: return { DEVICE_TYPE::C, "", "Ideal" };
case TYPE::C_ADV: return { DEVICE_TYPE::C, "ADV", "Advanced" };
//case TYPE::C_ADV: return { DEVICE_TYPE::C, "ADV", "Advanced" };
case TYPE::C_BEHAVIORAL: return { DEVICE_TYPE::C, "=", "Behavioral" };
case TYPE::L: return { DEVICE_TYPE::L, "", "Ideal" };
case TYPE::L_ADV: return { DEVICE_TYPE::L, "ADV", "Advanced" };
//case TYPE::L_ADV: return { DEVICE_TYPE::L, "ADV", "Advanced" };
case TYPE::L_BEHAVIORAL: return { DEVICE_TYPE::L, "=", "Behavioral" };
case TYPE::TLINE_Z0: return { DEVICE_TYPE::TLINE, "Z0", "Characteristic impedance" };
@ -150,8 +150,8 @@ SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType )
case TYPE::NPN_VBIC: return { DEVICE_TYPE::NPN, "VBIC", "VBIC" };
case TYPE::PNP_VBIC: return { DEVICE_TYPE::PNP, "VBIC", "VBIC" };
//case TYPE::BJT_MEXTRAM: return {};
case TYPE::NPN_HICUML2: return { DEVICE_TYPE::NPN, "HICUML2", "HICUM Level 2" };
case TYPE::PNP_HICUML2: return { DEVICE_TYPE::PNP, "HICUML2", "HICUM Level 2" };
case TYPE::NPN_HICUML2: return { DEVICE_TYPE::NPN, "HICUML2", "HICUM level 2" };
case TYPE::PNP_HICUML2: return { DEVICE_TYPE::PNP, "HICUML2", "HICUM level 2" };
//case TYPE::BJT_HICUM_L0: return {};
case TYPE::NJFET_SHICHMANHODGES: return { DEVICE_TYPE::NJFET, "SHICHMANHODGES", "Shichman-Hodges" };
@ -211,12 +211,12 @@ SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType )
case TYPE::V_SIN: return { DEVICE_TYPE::V, "SIN", "Sine" };
case TYPE::V_PULSE: return { DEVICE_TYPE::V, "PULSE", "Pulse" };
case TYPE::V_EXP: return { DEVICE_TYPE::V, "EXP", "Exponential" };
case TYPE::V_SFAM: return { DEVICE_TYPE::V, "SFAM", "Single-frequency AM" };
case TYPE::V_SFFM: return { DEVICE_TYPE::V, "SFFM", "Single-frequency FM" };
/*case TYPE::V_SFAM: return { DEVICE_TYPE::V, "SFAM", "Single-frequency AM" };
case TYPE::V_SFFM: return { DEVICE_TYPE::V, "SFFM", "Single-frequency FM" };*/
case TYPE::V_PWL: return { DEVICE_TYPE::V, "PWL", "Piecewise linear" };
case TYPE::V_WHITENOISE: return { DEVICE_TYPE::V, "WHITENOISE", "White Noise" };
case TYPE::V_PINKNOISE: return { DEVICE_TYPE::V, "PINKNOISE", "Pink Noise (1/f)" };
case TYPE::V_BURSTNOISE: return { DEVICE_TYPE::V, "BURSTNOISE", "Burst Noise" };
case TYPE::V_WHITENOISE: return { DEVICE_TYPE::V, "WHITENOISE", "White noise" };
case TYPE::V_PINKNOISE: return { DEVICE_TYPE::V, "PINKNOISE", "Pink noise (1/f)" };
case TYPE::V_BURSTNOISE: return { DEVICE_TYPE::V, "BURSTNOISE", "Burst noise" };
case TYPE::V_RANDUNIFORM: return { DEVICE_TYPE::V, "RANDUNIFORM", "Random uniform" };
case TYPE::V_RANDNORMAL: return { DEVICE_TYPE::V, "RANDNORMAL", "Random normal" };
case TYPE::V_RANDEXP: return { DEVICE_TYPE::V, "RANDEXP", "Random exponential" };
@ -227,8 +227,8 @@ SIM_MODEL::INFO SIM_MODEL::TypeInfo( TYPE aType )
case TYPE::I_SIN: return { DEVICE_TYPE::I, "SIN", "Sine" };
case TYPE::I_PULSE: return { DEVICE_TYPE::I, "PULSE", "Pulse" };
case TYPE::I_EXP: return { DEVICE_TYPE::I, "EXP", "Exponential" };
case TYPE::I_SFAM: return { DEVICE_TYPE::I, "SFAM", "Single-frequency AM" };
case TYPE::I_SFFM: return { DEVICE_TYPE::I, "SFFM", "Single-frequency FM" };
/*case TYPE::I_SFAM: return { DEVICE_TYPE::I, "SFAM", "Single-frequency AM" };
case TYPE::I_SFFM: return { DEVICE_TYPE::I, "SFFM", "Single-frequency FM" };*/
case TYPE::I_PWL: return { DEVICE_TYPE::I, "PWL", "Piecewise linear" };
case TYPE::I_WHITENOISE: return { DEVICE_TYPE::I, "WHITENOISE", "White Noise" };
case TYPE::I_PINKNOISE: return { DEVICE_TYPE::I, "PINKNOISE", "Pink Noise (1/f)" };
@ -256,15 +256,15 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType )
switch( aType )
{
case TYPE::R: return { "R", "" };
case TYPE::R_ADV: return { "R", "r" };
//case TYPE::R_ADV: return { "R", "r" };
case TYPE::R_BEHAVIORAL: return { "R", "", "", "0", false, true };
case TYPE::C: return { "C", "" };
case TYPE::C_ADV: return { "C", "c", };
//case TYPE::C_ADV: return { "C", "c", };
case TYPE::C_BEHAVIORAL: return { "C", "", "", "0", false, true };
case TYPE::L: return { "L", "" };
case TYPE::L_ADV: return { "L", "l" };
//case TYPE::L_ADV: return { "L", "l" };
case TYPE::L_BEHAVIORAL: return { "L", "", "", "0", false, true };
case TYPE::TLINE_Z0: return { "T" };
@ -341,8 +341,8 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType )
case TYPE::V_SIN: return { "V", "", "SIN" };
case TYPE::V_PULSE: return { "V", "", "PULSE" };
case TYPE::V_EXP: return { "V", "", "EXP" };
case TYPE::V_SFAM: return { "V", "", "AM" };
case TYPE::V_SFFM: return { "V", "", "SFFM" };
/*case TYPE::V_SFAM: return { "V", "", "AM" };
case TYPE::V_SFFM: return { "V", "", "SFFM" };*/
case TYPE::V_PWL: return { "V", "", "PWL" };
case TYPE::V_WHITENOISE: return { "V", "", "TRNOISE" };
case TYPE::V_PINKNOISE: return { "V", "", "TRNOISE" };
@ -357,8 +357,8 @@ SIM_MODEL::SPICE_INFO SIM_MODEL::SpiceInfo( TYPE aType )
case TYPE::I_PULSE: return { "V", "", "PULSE" };
case TYPE::I_SIN: return { "V", "", "SIN" };
case TYPE::I_EXP: return { "V", "", "EXP" };
case TYPE::I_SFAM: return { "V", "", "AM" };
case TYPE::I_SFFM: return { "V", "", "SFFM" };
/*case TYPE::I_SFAM: return { "V", "", "AM" };
case TYPE::I_SFFM: return { "V", "", "SFFM" };*/
case TYPE::I_PWL: return { "V", "", "PWL" };
case TYPE::I_WHITENOISE: return { "V", "", "TRNOISE" };
case TYPE::I_PINKNOISE: return { "V", "", "TRNOISE" };
@ -492,7 +492,8 @@ TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<T>& aFields )
return TYPE::NONE;
// No type information. For passives we infer the model from the mandatory fields in this case.
TYPE typeFromRef = InferTypeFromRef( GetFieldValue( &aFields, REFERENCE_FIELD ) );
TYPE typeFromRef = InferTypeFromRefAndValue( GetFieldValue( &aFields, REFERENCE_FIELD ),
GetFieldValue( &aFields, VALUE_FIELD ) );
if( typeFromRef != TYPE::NONE )
return typeFromRef;
@ -501,18 +502,19 @@ TYPE SIM_MODEL::ReadTypeFromFields( const std::vector<T>& aFields )
}
TYPE SIM_MODEL::InferTypeFromRef( const wxString& aRef )
TYPE SIM_MODEL::InferTypeFromRefAndValue( const wxString& aRef, const wxString& aValue )
{
static std::map<wxString, TYPE> refPrefixToType = {
{ "R", TYPE::R },
{ "C", TYPE::C },
{ "L", TYPE::L },
{ "TLINE", TYPE::TLINE_Z0 },
{ "VDC", TYPE::V_DC },
{ "VSIN", TYPE::V_SIN },
{ "VPULSE", TYPE::V_PULSE },
{ "VEXP", TYPE::V_EXP },
{ "VSFAM", TYPE::V_SFAM },
{ "VSFFM", TYPE::V_SFFM },
/*{ "VSFAM", TYPE::V_SFAM },
{ "VSFFM", TYPE::V_SFFM },*/
{ "VPWL", TYPE::V_PWL },
{ "VWHITENOISE", TYPE::V_WHITENOISE },
{ "VPINKNOISE", TYPE::V_PINKNOISE },
@ -526,8 +528,8 @@ TYPE SIM_MODEL::InferTypeFromRef( const wxString& aRef )
{ "ISIN", TYPE::I_SIN },
{ "IPULSE", TYPE::I_PULSE },
{ "IEXP", TYPE::I_EXP },
{ "ISFAM", TYPE::I_SFAM },
{ "ISFFM", TYPE::I_SFFM },
/*{ "ISFAM", TYPE::I_SFAM },
{ "ISFFM", TYPE::I_SFFM },*/
{ "IPWL", TYPE::I_PWL },
{ "IWHITENOISE", TYPE::I_WHITENOISE },
{ "IPINKNOISE", TYPE::I_PINKNOISE },
@ -539,13 +541,69 @@ TYPE SIM_MODEL::InferTypeFromRef( const wxString& aRef )
{ "IBEHAVIORAL", TYPE::I_BEHAVIORAL }
};
for( auto&& [prefix, type] : refPrefixToType )
TYPE type = TYPE::NONE;
for( auto&& [curPrefix, curType] : refPrefixToType )
{
if( aRef.StartsWith( prefix ) )
return type;
if( aRef.StartsWith( curPrefix ) )
{
type = curType;
break;
}
}
return TYPE::NONE;
wxString value = aValue;
// Some types have to be inferred from Value field.
switch( type )
{
case TYPE::R:
if( value.Trim( false ).StartsWith( "=" ) )
type = TYPE::R_BEHAVIORAL;
break;
case TYPE::C:
if( value.Trim( false ).StartsWith( "=" ) )
type = TYPE::C_BEHAVIORAL;
break;
case TYPE::L:
if( value.Trim( false ).StartsWith( "=" ) )
type = TYPE::L_BEHAVIORAL;
break;
case TYPE::TLINE_Z0:
try
{
tao::pegtl::string_input<> in( aValue.ToStdString(), "from_content" );
auto root = tao::pegtl::parse_tree::parse<
SIM_MODEL_PARSER::fieldParamValuePairsGrammar,
SIM_MODEL_PARSER::fieldParamValuePairsSelector>
( in );
for( const auto& node : root->children )
{
if( node->is_type<SIM_MODEL_PARSER::param>()
&& (node->string() == "r" || node->string() == "R"
|| node->string() == "c" || node->string() == "C"
|| node->string() == "l" || node->string() == "L" ) )
{
type = TYPE::TLINE_RLGC;
break;
}
}
}
catch( const tao::pegtl::parse_error& e )
{
}
break;
default:
break;
}
return type;
}
@ -868,7 +926,7 @@ wxString SIM_MODEL::GenerateSpiceModelLine( const wxString& aModelName ) const
wxString SIM_MODEL::GenerateSpiceItemName( const wxString& aRefName ) const
{
if( !aRefName.IsEmpty() && aRefName.StartsWith( GetSpiceInfo().itemType ) )
if( aRefName != "" && aRefName.StartsWith( GetSpiceInfo().itemType ) )
return aRefName;
else
return GetSpiceInfo().itemType + aRefName;
@ -1265,11 +1323,6 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::create( TYPE aType )
case TYPE::L:
return std::make_unique<SIM_MODEL_IDEAL>( aType );
case TYPE::R_ADV:
case TYPE::C_ADV:
case TYPE::L_ADV:
return std::make_unique<SIM_MODEL_PASSIVE>( aType );
case TYPE::R_BEHAVIORAL:
case TYPE::C_BEHAVIORAL:
case TYPE::L_BEHAVIORAL:
@ -1289,10 +1342,10 @@ std::unique_ptr<SIM_MODEL> SIM_MODEL::create( TYPE aType )
case TYPE::I_PULSE:
case TYPE::V_EXP:
case TYPE::I_EXP:
case TYPE::V_SFAM:
/*case TYPE::V_SFAM:
case TYPE::I_SFAM:
case TYPE::V_SFFM:
case TYPE::I_SFFM:
case TYPE::I_SFFM:*/
case TYPE::V_PWL:
case TYPE::I_PWL:
case TYPE::V_WHITENOISE:

View File

@ -25,7 +25,7 @@
#ifndef SIM_MODEL_H
#define SIM_MODEL_H
#include <sim/spice_grammar.h>
#include <sim/sim_value.h>
#include <enum_vector.h>
#include <sch_field.h>
#include <lib_field.h>
@ -133,15 +133,15 @@ public:
NONE,
R,
R_ADV,
//R_ADV,
R_BEHAVIORAL,
C,
C_ADV,
//C_ADV,
C_BEHAVIORAL,
L,
L_ADV,
//L_ADV,
L_BEHAVIORAL,
TLINE_Z0,
@ -245,8 +245,8 @@ public:
V_SIN,
V_PULSE,
V_EXP,
V_SFAM,
V_SFFM,
/*V_SFAM,
V_SFFM,*/
V_PWL,
V_WHITENOISE,
V_PINKNOISE,
@ -261,8 +261,8 @@ public:
I_SIN,
I_PULSE,
I_EXP,
I_SFAM,
I_SFFM,
/*I_SFAM,
I_SFFM,*/
I_PWL,
I_WHITENOISE,
I_PINKNOISE,
@ -320,6 +320,7 @@ public:
enum class CATEGORY
{
PRINCIPAL,
AC,
DC,
CAPACITANCE,
TEMPERATURE,
@ -373,7 +374,7 @@ public:
template <typename T>
static TYPE ReadTypeFromFields( const std::vector<T>& aFields );
static TYPE InferTypeFromRef( const wxString& aRef );
static TYPE InferTypeFromRefAndValue( const wxString& aRef, const wxString& aValue );
template <typename T>
static TYPE InferTypeFromLegacyFields( const std::vector<T>& aFields );

View File

@ -27,7 +27,8 @@
SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType )
: SIM_MODEL( aType )
: SIM_MODEL( aType ),
m_isInferred( false )
{
static PARAM::INFO resistor = makeParams( "r", "Expression for resistance", "Ω" );
static PARAM::INFO capacitor = makeParams( "c", "Expression for capacitance", "F" );
@ -48,6 +49,44 @@ SIM_MODEL_BEHAVIORAL::SIM_MODEL_BEHAVIORAL( TYPE aType )
}
void SIM_MODEL_BEHAVIORAL::ReadDataSchFields( unsigned aSymbolPinCount,
const std::vector<SCH_FIELD>* aFields )
{
if( GetFieldValue( aFields, PARAMS_FIELD ) != "" )
SIM_MODEL::ReadDataSchFields( aSymbolPinCount, aFields );
else
inferredReadDataFields( aSymbolPinCount, aFields );
}
void SIM_MODEL_BEHAVIORAL::ReadDataLibFields( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>* aFields )
{
if( GetFieldValue( aFields, PARAMS_FIELD ) != "" )
SIM_MODEL::ReadDataLibFields( aSymbolPinCount, aFields );
else
inferredReadDataFields( aSymbolPinCount, aFields );
}
void SIM_MODEL_BEHAVIORAL::WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const
{
SIM_MODEL::WriteDataSchFields( aFields );
if( m_isInferred )
inferredWriteDataFields( aFields );
}
void SIM_MODEL_BEHAVIORAL::WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const
{
SIM_MODEL::WriteDataLibFields( aFields );
if( m_isInferred )
inferredWriteDataFields( aFields );
}
wxString SIM_MODEL_BEHAVIORAL::GenerateSpiceModelLine( const wxString& aModelName ) const
{
return "";
@ -84,6 +123,35 @@ wxString SIM_MODEL_BEHAVIORAL::GenerateSpiceItemLine( const wxString& aRefName,
}
template <typename T>
void SIM_MODEL_BEHAVIORAL::inferredReadDataFields( unsigned aSymbolPinCount,
const std::vector<T>* aFields )
{
ParsePinsField( aSymbolPinCount, PINS_FIELD );
if( ( InferTypeFromRefAndValue( GetFieldValue( aFields, REFERENCE_FIELD ),
GetFieldValue( aFields, VALUE_FIELD ) ) == GetType()
&& ParseParamsField( GetFieldValue( aFields, VALUE_FIELD ) ) )
// If Value is device type, this is an empty model
|| GetFieldValue( aFields, VALUE_FIELD ) == DeviceTypeInfo( GetDeviceType() ).fieldValue )
{
m_isInferred = true;
}
}
template <typename T>
void SIM_MODEL_BEHAVIORAL::inferredWriteDataFields( std::vector<T>& aFields ) const
{
wxString value = GetFieldValue( &aFields, PARAMS_FIELD );
if( value == "" )
value = GetDeviceTypeInfo().fieldValue;
WriteInferredDataFields( aFields, value );
}
SIM_MODEL::PARAM::INFO SIM_MODEL_BEHAVIORAL::makeParams( wxString aName, wxString aDescription,
wxString aUnit )
{

View File

@ -33,6 +33,14 @@ class SIM_MODEL_BEHAVIORAL : public SIM_MODEL
public:
SIM_MODEL_BEHAVIORAL( TYPE aType );
void ReadDataSchFields( unsigned aSymbolPinCount,
const std::vector<SCH_FIELD>* aFields ) override;
void ReadDataLibFields( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>* aFields ) override;
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,
@ -40,9 +48,17 @@ public:
const std::vector<wxString>& aPinNetNames ) const override;
private:
template <typename T>
void inferredReadDataFields( unsigned aSymbolPinCount, const std::vector<T>* aFields );
template <typename T>
void inferredWriteDataFields( std::vector<T>& aFields ) const;
std::vector<wxString> getPinNames() const override { return { "+", "-" }; }
static PARAM::INFO makeParams( wxString aName, wxString aDescription, wxString aUnit );
bool m_isInferred;
};
#endif // SIM_MODEL_BEHAVIORAL_H

View File

@ -49,7 +49,7 @@ SIM_MODEL_IDEAL::SIM_MODEL_IDEAL( TYPE aType )
void SIM_MODEL_IDEAL::ReadDataSchFields( unsigned aSymbolPinCount,
const std::vector<SCH_FIELD>* aFields )
{
if( !GetFieldValue( aFields, PARAMS_FIELD ).IsEmpty() )
if( GetFieldValue( aFields, PARAMS_FIELD ) != "" )
SIM_MODEL::ReadDataSchFields( aSymbolPinCount, aFields );
else
inferredReadDataFields( aSymbolPinCount, aFields );
@ -59,7 +59,7 @@ void SIM_MODEL_IDEAL::ReadDataSchFields( unsigned aSymbolPinCount,
void SIM_MODEL_IDEAL::ReadDataLibFields( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>* aFields )
{
if( !GetFieldValue( aFields, PARAMS_FIELD ).IsEmpty() )
if( GetFieldValue( aFields, PARAMS_FIELD ) != "" )
SIM_MODEL::ReadDataLibFields( aSymbolPinCount, aFields );
else
inferredReadDataFields( aSymbolPinCount, aFields );
@ -94,9 +94,12 @@ wxString SIM_MODEL_IDEAL::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aPinNetNames ) const
{
return SIM_MODEL::GenerateSpiceItemLine( aRefName,
GetParam( 0 ).value->ToString( SIM_VALUE::NOTATION::SPICE ),
aPinNetNames );
wxString valueStr = GetParam( 0 ).value->ToString( SIM_VALUE::NOTATION::SPICE );
if( valueStr != "" )
return SIM_MODEL::GenerateSpiceItemLine( aRefName, valueStr, aPinNetNames );
else
return "";
}
@ -105,8 +108,10 @@ void SIM_MODEL_IDEAL::inferredReadDataFields( unsigned aSymbolPinCount, const st
{
ParsePinsField( aSymbolPinCount, PINS_FIELD );
if( ( InferTypeFromRef( GetFieldValue( aFields, REFERENCE_FIELD ) ) == GetType()
if( ( InferTypeFromRefAndValue( GetFieldValue( aFields, REFERENCE_FIELD ),
GetFieldValue( aFields, VALUE_FIELD ) ) == GetType()
&& SetParamValue( 0, GetFieldValue( aFields, VALUE_FIELD ) ) )
// If Value is device type, this is an empty model
|| GetFieldValue( aFields, VALUE_FIELD ) == DeviceTypeInfo( GetDeviceType() ).fieldValue )
{
m_isInferred = true;

View File

@ -1,177 +0,0 @@
/*
* 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_model_passive.h>
using PARAM = SIM_MODEL::PARAM;
SIM_MODEL_PASSIVE::SIM_MODEL_PASSIVE( TYPE aType )
: SIM_MODEL( aType )
{
static std::vector<PARAM::INFO> resistor = makeParamInfos( "r", "Resistance", "Ω" );
static std::vector<PARAM::INFO> capacitor = makeParamInfos( "c", "Capacitance", "F" );
static std::vector<PARAM::INFO> inductor = makeParamInfos( "l", "Inductance", "H" );
switch( aType )
{
case TYPE::R_ADV:
for( const PARAM::INFO& paramInfo : resistor )
AddParam( paramInfo );
break;
case TYPE::C_ADV:
for( const PARAM::INFO& paramInfo : capacitor )
AddParam( paramInfo );
break;
case TYPE::L_ADV:
for( const PARAM::INFO& paramInfo : inductor )
AddParam( paramInfo );
break;
default:
wxFAIL_MSG( "Unhandled SIM_MODEL type in SIM_MODEL_PASSIVE" );
}
}
bool SIM_MODEL_PASSIVE::SetParamFromSpiceCode( const wxString& aParamName,
const wxString& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation )
{
if( aParamName.Lower() == "tc" )
return SetParamFromSpiceCode( "tc1", aParamValue, aNotation );
switch( GetType() )
{
case TYPE::R_ADV:
if( aParamName.Lower() == "tc1r" )
return SIM_MODEL::SetParamFromSpiceCode( "tc1", aParamValue, aNotation );
/*if( aParamName.Lower() == "tc2r" )
return SIM_MODEL::SetParamFromSpiceCode( "tc2", aParamValue, aNotation );*/
if( aParamName.Lower() == "res" )
return SIM_MODEL::SetParamFromSpiceCode( "r", aParamValue, aNotation );
break;
case TYPE::C_ADV:
if( aParamName.Lower() == "cap" )
return SIM_MODEL::SetParamFromSpiceCode( "c", aParamValue, aNotation );
break;
case TYPE::L_ADV:
if( aParamName.Lower() == "ind" )
return SIM_MODEL::SetParamFromSpiceCode( "l", aParamValue, aNotation );
break;
default:
break;
}
return SIM_MODEL::SetParamFromSpiceCode( aParamName, aParamValue, aNotation );
}
std::vector<PARAM::INFO> SIM_MODEL_PASSIVE::makeParamInfos( wxString aName,
wxString aDescription,
wxString aUnit )
{
std::vector<PARAM::INFO> paramInfos;
PARAM::INFO paramInfo = {};
paramInfo.name = "temp";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = "°C";
paramInfo.category = PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "27";
paramInfo.description = "Temperature";
paramInfo.isInstanceParam = true;
paramInfos.push_back( paramInfo );
paramInfo.name = aName;
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = aUnit;
paramInfo.category = PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "";
paramInfo.description = aDescription;
paramInfo.isInstanceParam = false;
paramInfos.push_back( paramInfo );
paramInfo.name = "tnom";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = "°C";
paramInfo.category = PARAM::CATEGORY::TEMPERATURE;
paramInfo.defaultValue = "27";
paramInfo.description = "Nominal temperature";
paramInfo.isInstanceParam = false;
paramInfos.push_back( paramInfo );
paramInfo.name = "tc1";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = aUnit;
paramInfo.category = PARAM::CATEGORY::TEMPERATURE;
paramInfo.defaultValue = "0";
paramInfo.description = "Temperature coefficient";
paramInfo.isInstanceParam = false;
paramInfos.push_back( paramInfo );
/*paramInfo.name = "tc2";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = aUnit;
paramInfo.category = PARAM::CATEGORY::TEMPERATURE;
paramInfo.defaultValue = "0";
paramInfo.description = "2nd order temperature coefficient";
paramInfo.isInstanceParam = false;
paramInfos.push_back( paramInfo );*/
/*if( aName != "l" )
{
paramInfo.name = "bv_max";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = aUnit;
paramInfo.category = PARAM::CATEGORY::LIMITING_VALUES;
paramInfo.defaultValue = "";
paramInfo.description = "Max. safe operating voltage";
paramInfos.push_back( paramInfo );
}*/
if( aName == "r" )
{
paramInfo.name = "noisy";
paramInfo.type = SIM_VALUE::TYPE::BOOL;
paramInfo.unit = "";
paramInfo.category = PARAM::CATEGORY::NOISE;
paramInfo.defaultValue = "True";
paramInfo.description = "Enable thermal noise";
paramInfo.isInstanceParam = false;
paramInfos.push_back( paramInfo );
}
return paramInfos;
}

View File

@ -1,48 +0,0 @@
/*
* 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_MODEL_PASSIVE_H
#define SIM_MODEL_PASSIVE_H
#include <sim/sim_model.h>
class SIM_MODEL_PASSIVE : public SIM_MODEL
{
public:
SIM_MODEL_PASSIVE( TYPE aType );
bool SetParamFromSpiceCode( const wxString& aParamName, const wxString& aParamValue,
SIM_VALUE_GRAMMAR::NOTATION aNotation
= SIM_VALUE_GRAMMAR::NOTATION::SPICE ) override;
private:
static std::vector<PARAM::INFO> makeParamInfos( wxString aName, wxString aDescription,
wxString aUnit );
std::vector<wxString> getPinNames() const override { return { "+", "-" }; }
};
#endif // SIM_MODEL_PASSIVE_H

View File

@ -39,7 +39,7 @@ SIM_MODEL_SOURCE::SIM_MODEL_SOURCE( TYPE aType )
void SIM_MODEL_SOURCE::ReadDataSchFields( unsigned aSymbolPinCount,
const std::vector<SCH_FIELD>* aFields )
{
if( !GetFieldValue( aFields, PARAMS_FIELD ).IsEmpty() )
if( GetFieldValue( aFields, PARAMS_FIELD ) != "" )
SIM_MODEL::ReadDataSchFields( aSymbolPinCount, aFields );
else
inferredReadDataFields( aSymbolPinCount, aFields );
@ -49,7 +49,7 @@ void SIM_MODEL_SOURCE::ReadDataSchFields( unsigned aSymbolPinCount,
void SIM_MODEL_SOURCE::ReadDataLibFields( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>* aFields )
{
if( !GetFieldValue( aFields, PARAMS_FIELD ).IsEmpty() )
if( GetFieldValue( aFields, PARAMS_FIELD ) != "" )
SIM_MODEL::ReadDataLibFields( aSymbolPinCount, aFields );
else
inferredReadDataFields( aSymbolPinCount, aFields );
@ -84,17 +84,30 @@ wxString SIM_MODEL_SOURCE::GenerateSpiceItemLine( const wxString& aRefName,
const wxString& aModelName,
const std::vector<wxString>& aPinNetNames ) const
{
wxString argList = "";
for( const PARAM& param : GetParams() )
wxString model;
wxString ac = FindParam( "ac" )->value->ToString( SIM_VALUE_GRAMMAR::NOTATION::SPICE );
wxString ph = FindParam( "ph" )->value->ToString( SIM_VALUE_GRAMMAR::NOTATION::SPICE );
if( ac != "" )
model << wxString::Format( "AC %s %s ", ac, ph );
if( GetSpiceInfo().inlineTypeString != "" )
{
wxString argStr = param.value->ToString( SIM_VALUE_GRAMMAR::NOTATION::SPICE );
wxString argList = "";
for( const PARAM& param : GetParams() )
{
wxString argStr = param.value->ToString( SIM_VALUE_GRAMMAR::NOTATION::SPICE );
if( argStr != "" )
argList << argStr << " ";
if( argStr != "" )
argList << argStr << " ";
}
model << wxString::Format( "%s( %s)", GetSpiceInfo().inlineTypeString, argList );
}
wxString model = wxString::Format( GetSpiceInfo().inlineTypeString + "( %s)", argList );
else
model << GetParam( 0 ).value->ToString( SIM_VALUE_GRAMMAR::NOTATION::SPICE );
return SIM_MODEL::GenerateSpiceItemLine( aRefName, model, aPinNetNames );
}
@ -114,11 +127,11 @@ const std::vector<PARAM::INFO>& SIM_MODEL_SOURCE::makeParamInfos( TYPE aType )
static std::vector<PARAM::INFO> vexp = makeExpParamInfos( "v", "V" );
static std::vector<PARAM::INFO> iexp = makeExpParamInfos( "i", "A" );
static std::vector<PARAM::INFO> vsfam = makeSfamParamInfos( "v", "V" );
/*static std::vector<PARAM::INFO> vsfam = makeSfamParamInfos( "v", "V" );
static std::vector<PARAM::INFO> isfam = makeSfamParamInfos( "i", "A" );
static std::vector<PARAM::INFO> vsffm = makeSffmParamInfos( "v", "V" );
static std::vector<PARAM::INFO> isffm = makeSffmParamInfos( "i", "A" );
static std::vector<PARAM::INFO> isffm = makeSffmParamInfos( "i", "A" );*/
static std::vector<PARAM::INFO> vpwl = makePwlParamInfos( "v", "Voltage", "V" );
static std::vector<PARAM::INFO> ipwl = makePwlParamInfos( "i", "Current", "A" );
@ -154,10 +167,10 @@ const std::vector<PARAM::INFO>& SIM_MODEL_SOURCE::makeParamInfos( TYPE aType )
case TYPE::I_PULSE: return ipulse;
case TYPE::V_EXP: return vexp;
case TYPE::I_EXP: return iexp;
case TYPE::V_SFAM: return vsfam;
/*case TYPE::V_SFAM: return vsfam;
case TYPE::I_SFAM: return isfam;
case TYPE::V_SFFM: return vsffm;
case TYPE::I_SFFM: return isffm;
case TYPE::I_SFFM: return isffm;*/
case TYPE::V_PWL: return vpwl;
case TYPE::I_PWL: return ipwl;
case TYPE::V_WHITENOISE: return vwhitenoise;
@ -187,7 +200,7 @@ bool SIM_MODEL_SOURCE::SetParamValue( unsigned aParamIndex, const wxString& aVal
{
// Sources are special. All preceding parameter values must be filled. If they are not, fill
// them out automatically. If a value is nulled, delete everything after it.
if( aValue.IsEmpty() )
if( aValue == "" )
{
for( unsigned i = aParamIndex; i < GetParamCount(); ++i )
SIM_MODEL::SetParamValue( i, "", aNotation );
@ -196,7 +209,7 @@ bool SIM_MODEL_SOURCE::SetParamValue( unsigned aParamIndex, const wxString& aVal
{
for( unsigned i = 0; i < aParamIndex; ++i )
{
if( GetParam( i ).value->ToString().IsEmpty() )
if( GetParam( i ).value->ToString() == "" )
SIM_MODEL::SetParamValue( i, "0", aNotation );
}
}
@ -215,11 +228,13 @@ wxString SIM_MODEL_SOURCE::GenerateParamValuePair( const PARAM& aParam, bool& aI
template <typename T>
void SIM_MODEL_SOURCE::inferredReadDataFields( unsigned aSymbolPinCount, const std::vector<T>* aFields )
void SIM_MODEL_SOURCE::inferredReadDataFields( unsigned aSymbolPinCount,
const std::vector<T>* aFields )
{
ParsePinsField( aSymbolPinCount, PINS_FIELD );
if( ( InferTypeFromRef( GetFieldValue( aFields, REFERENCE_FIELD ) ) == GetType()
if( ( InferTypeFromRefAndValue( GetFieldValue( aFields, REFERENCE_FIELD ),
GetFieldValue( aFields, VALUE_FIELD ) ) == GetType()
&& ParseParamsField( GetFieldValue( aFields, VALUE_FIELD ) ) )
|| GetFieldValue( aFields, VALUE_FIELD ) == DeviceTypeInfo( GetDeviceType() ).fieldValue )
{
@ -233,8 +248,8 @@ void SIM_MODEL_SOURCE::inferredWriteDataFields( std::vector<T>& aFields ) const
{
wxString value = GetFieldValue( &aFields, PARAMS_FIELD );
if( value.IsEmpty() )
value = DeviceTypeInfo( GetDeviceType() ).fieldValue;
if( value == "" )
value = GetDeviceTypeInfo().fieldValue;
WriteInferredDataFields( aFields, value );
}
@ -259,6 +274,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeDcParamInfos( wxString aPrefix, w
paramInfo.description = "DC value";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -308,14 +324,17 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeSinParamInfos( wxString aPrefix,
paramInfo.description = "Damping factor";
paramInfos.push_back( paramInfo );
paramInfo.name = "phase";
// "phase" is not needed. "td" is enough.
/*paramInfo.name = "phase";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = "deg";
paramInfo.unit = "°";
paramInfo.category = SIM_MODEL::PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "0";
paramInfo.description = "Phase";
paramInfos.push_back( paramInfo );
paramInfos.push_back( paramInfo );*/
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -365,7 +384,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makePulseParamInfos( wxString aPrefix
paramInfo.description = "Fall time";
paramInfos.push_back( paramInfo );
paramInfo.name = "pw";
paramInfo.name = "tw"; // Ngspice calls it "pw".
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = "s";
paramInfo.category = PARAM::CATEGORY::PRINCIPAL;
@ -381,14 +400,17 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makePulseParamInfos( wxString aPrefix
paramInfo.description = "Period";
paramInfos.push_back( paramInfo );
paramInfo.name = "phase";
// "phase" is not needed. "td" is enough.
/*paramInfo.name = "phase";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = "deg";
paramInfo.unit = "°";
paramInfo.category = PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "0";
paramInfo.description = "Phase";
paramInfos.push_back( paramInfo );
paramInfos.push_back( paramInfo );*/
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -446,11 +468,12 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeExpParamInfos( wxString aPrefix,
paramInfo.description = "Fall time constant";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeSfamParamInfos( wxString aPrefix, wxString aUnit )
/*std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeSfamParamInfos( wxString aPrefix, wxString aUnit )
{
std::vector<PARAM::INFO> paramInfos;
PARAM::INFO paramInfo;
@ -494,6 +517,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeSfamParamInfos( wxString aPrefix,
paramInfo.description = "Modulating frequency";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -545,7 +569,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeSffmParamInfos( wxString aPrefix,
paramInfo.name = "phasec";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = "deg";
paramInfo.unit = "°";
paramInfo.category = SIM_MODEL::PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "0";
paramInfo.description = "Carrier phase";
@ -553,14 +577,15 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeSffmParamInfos( wxString aPrefix,
paramInfo.name = "phases";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = "deg";
paramInfo.unit = "°";
paramInfo.category = SIM_MODEL::PARAM::CATEGORY::PRINCIPAL;
paramInfo.defaultValue = "0";
paramInfo.description = "Signal phase";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
}*/
std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makePwlParamInfos( wxString aPrefix, wxString aQuantity,
@ -601,6 +626,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makePwlParamInfos( wxString aPrefix,
paramInfo.description = "Delay";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -635,6 +661,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeWhiteNoiseParamInfos( wxString aP
paramInfo.description = "Time step";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -677,6 +704,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makePinkNoiseParamInfos( wxString aPr
paramInfo.description = "Time step";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -719,6 +747,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeBurstNoiseParamInfos( wxString aP
paramInfo.description = "Time step";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -753,6 +782,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeRandomUniformParamInfos( wxString
paramInfo.description = "Delay";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -787,6 +817,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeRandomNormalParamInfos( wxString
paramInfo.description = "Delay";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -821,6 +852,7 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeRandomExpParamInfos( wxString aPr
paramInfo.description = "Delay";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
@ -855,5 +887,27 @@ std::vector<PARAM::INFO> SIM_MODEL_SOURCE::makeRandomPoissonParamInfos( wxString
paramInfo.description = "Delay";
paramInfos.push_back( paramInfo );
appendAcParamInfos( paramInfos, aUnit );
return paramInfos;
}
void SIM_MODEL_SOURCE::appendAcParamInfos( std::vector<PARAM::INFO>& aParamInfos, wxString aUnit )
{
PARAM::INFO paramInfo;
paramInfo.name = "ac";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = aUnit;
paramInfo.category = SIM_MODEL::PARAM::CATEGORY::AC;
paramInfo.defaultValue = "0";
paramInfo.description = "AC magnitude";
aParamInfos.push_back( paramInfo );
paramInfo.name = "ph";
paramInfo.type = SIM_VALUE::TYPE::FLOAT;
paramInfo.unit = "°";
paramInfo.category = SIM_MODEL::PARAM::CATEGORY::AC;
paramInfo.defaultValue = "0";
paramInfo.description = "AC phase";
aParamInfos.push_back( paramInfo );
}

View File

@ -33,8 +33,10 @@ class SIM_MODEL_SOURCE : public SIM_MODEL
public:
SIM_MODEL_SOURCE( TYPE aType );
void ReadDataSchFields( unsigned aSymbolPinCount, const std::vector<SCH_FIELD>* aFields ) override;
void ReadDataLibFields( unsigned aSymbolPinCount, const std::vector<LIB_FIELD>* aFields ) override;
void ReadDataSchFields( unsigned aSymbolPinCount,
const std::vector<SCH_FIELD>* aFields ) override;
void ReadDataLibFields( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>* aFields ) override;
void WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const override;
void WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const override;
@ -67,8 +69,8 @@ private:
static std::vector<PARAM::INFO> makeSinParamInfos( wxString aPrefix, wxString aUnit );
static std::vector<PARAM::INFO> makePulseParamInfos( wxString aPrefix, wxString aUnit );
static std::vector<PARAM::INFO> makeExpParamInfos( wxString aPrefix, wxString aUnit );
static std::vector<PARAM::INFO> makeSfamParamInfos( wxString aPrefix, wxString aUnit );
static std::vector<PARAM::INFO> makeSffmParamInfos( wxString aPrefix, wxString aUnit );
//static std::vector<PARAM::INFO> makeSfamParamInfos( wxString aPrefix, wxString aUnit );
//static std::vector<PARAM::INFO> makeSffmParamInfos( wxString aPrefix, wxString aUnit );
static std::vector<PARAM::INFO> makePwlParamInfos( wxString aPrefix, wxString aQuantity,
wxString aUnit );
static std::vector<PARAM::INFO> makeWhiteNoiseParamInfos( wxString aPrefix, wxString aUnit );
@ -79,6 +81,8 @@ private:
static std::vector<PARAM::INFO> makeRandomExpParamInfos( wxString aPrefix, wxString aUnit );
static std::vector<PARAM::INFO> makeRandomPoissonParamInfos( wxString aPrefix, wxString aUnit );
static void appendAcParamInfos( std::vector<PARAM::INFO>& aParamInfos, wxString aUnit );
bool m_isInferred;
};

View File

@ -23,6 +23,7 @@
*/
#include <sim/sim_model_subckt.h>
#include <sim/spice_grammar.h>
#include <pegtl.hpp>
#include <pegtl/contrib/parse_tree.hpp>

View File

@ -28,7 +28,8 @@ using PARAM = SIM_MODEL::PARAM;
SIM_MODEL_TLINE::SIM_MODEL_TLINE( TYPE aType )
: SIM_MODEL( aType )
: SIM_MODEL( aType ),
m_isInferred( false )
{
static std::vector<PARAM::INFO> z0 = makeZ0ParamInfo();
static std::vector<PARAM::INFO> rlgc = makeRlgcParamInfo();
@ -51,10 +52,70 @@ SIM_MODEL_TLINE::SIM_MODEL_TLINE( TYPE aType )
}
/*wxString SIM_MODEL_TLINE::GenerateSpiceItemName( const wxString& aRefName ) const
void SIM_MODEL_TLINE::ReadDataSchFields( unsigned aSymbolPinCount,
const std::vector<SCH_FIELD>* aFields )
{
}*/
if( GetFieldValue( aFields, PARAMS_FIELD ) != "" )
SIM_MODEL::ReadDataSchFields( aSymbolPinCount, aFields );
else
inferredReadDataFields( aSymbolPinCount, aFields );
}
void SIM_MODEL_TLINE::ReadDataLibFields( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>* aFields )
{
if( GetFieldValue( aFields, PARAMS_FIELD ) != "" )
SIM_MODEL::ReadDataLibFields( aSymbolPinCount, aFields );
else
inferredReadDataFields( aSymbolPinCount, aFields );
}
void SIM_MODEL_TLINE::WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const
{
SIM_MODEL::WriteDataSchFields( aFields );
if( m_isInferred )
inferredWriteDataFields( aFields );
}
void SIM_MODEL_TLINE::WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const
{
SIM_MODEL::WriteDataLibFields( aFields );
if( m_isInferred )
inferredWriteDataFields( aFields );
}
template <typename T>
void SIM_MODEL_TLINE::inferredReadDataFields( unsigned aSymbolPinCount,
const std::vector<T>* aFields )
{
ParsePinsField( aSymbolPinCount, PINS_FIELD );
if( ( InferTypeFromRefAndValue( GetFieldValue( aFields, REFERENCE_FIELD ),
GetFieldValue( aFields, VALUE_FIELD ) ) == GetType()
&& ParseParamsField( GetFieldValue( aFields, VALUE_FIELD ) ) )
// If Value is device type, this is an empty model
|| GetFieldValue( aFields, VALUE_FIELD ) == DeviceTypeInfo( GetDeviceType() ).fieldValue )
{
m_isInferred = true;
}
}
template <typename T>
void SIM_MODEL_TLINE::inferredWriteDataFields( std::vector<T>& aFields ) const
{
wxString value = GetFieldValue( &aFields, PARAMS_FIELD );
if( value == "" )
value = GetDeviceTypeInfo().fieldValue;
WriteInferredDataFields( aFields, value );
}
std::vector<PARAM::INFO> SIM_MODEL_TLINE::makeZ0ParamInfo()

View File

@ -33,7 +33,21 @@ class SIM_MODEL_TLINE : public SIM_MODEL
public:
SIM_MODEL_TLINE( TYPE aType );
void ReadDataSchFields( unsigned aSymbolPinCount,
const std::vector<SCH_FIELD>* aFields ) override;
void ReadDataLibFields( unsigned aSymbolPinCount,
const std::vector<LIB_FIELD>* aFields ) override;
void WriteDataSchFields( std::vector<SCH_FIELD>& aFields ) const override;
void WriteDataLibFields( std::vector<LIB_FIELD>& aFields ) const override;
private:
template <typename T>
void inferredReadDataFields( unsigned aSymbolPinCount, const std::vector<T>* aFields );
template <typename T>
void inferredWriteDataFields( std::vector<T>& aFields ) const;
static std::vector<PARAM::INFO> makeZ0ParamInfo();
static std::vector<PARAM::INFO> makeRlgcParamInfo();
@ -41,6 +55,8 @@ private:
// Subcircuits require models even when they have no Spice instance parameters.
bool requiresSpiceModel() const override;
bool m_isInferred;
};
#endif // SIM_MODEL_TLINE_H

Some files were not shown because too many files have changed in this diff Show More