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

View File

@ -462,9 +462,7 @@ void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
m_simConsole->Clear();
if( aSimCommand.IsEmpty() )
m_circuitModel->SetSimCommand( getCurrentSimCommand() );
else
if( aSimCommand != "" )
m_circuitModel->SetSimCommand( aSimCommand );
// Make .save all and .probe alli permanent for now.
@ -482,6 +480,8 @@ void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
if( simulatorLock.owns_lock() )
{
wxBusyCursor toggle;
updateTuners();
applyTuners();
// Prevents memory leak on succeding simulations by deleting old vectors
@ -663,7 +663,7 @@ void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType )
if( !plotPanel || plotPanel->GetType() != simType )
{
plotPanel =
dynamic_cast<SIM_PLOT_PANEL*>( NewPlotPanel( m_circuitModel->GetUsedSimCommand() ) );
dynamic_cast<SIM_PLOT_PANEL*>( NewPlotPanel( m_circuitModel->GetSimCommand() ) );
}
wxASSERT( plotPanel );
@ -778,8 +778,8 @@ bool SIM_PLOT_FRAME::updatePlot( const wxString& aName, SIM_PLOT_TYPE aType,
// for each input step
SPICE_DC_PARAMS source1, source2;
if( m_circuitModel->GetSimType() == ST_DC &&
m_circuitModel->ParseDCCommand( m_circuitModel->GetUsedSimCommand(), &source1, &source2 ) )
if( m_circuitModel->GetSimType() == ST_DC
&& m_circuitModel->ParseDCCommand( m_circuitModel->GetSimCommand(), &source1, &source2 ) )
{
if( !source2.m_source.IsEmpty() )
{
@ -1151,7 +1151,7 @@ void SIM_PLOT_FRAME::menuNewPlot( wxCommandEvent& aEvent )
SIM_TYPE type = m_circuitModel->GetSimType();
if( SIM_PANEL_BASE::IsPlottable( type ) )
NewPlotPanel( m_circuitModel->GetUsedSimCommand() );
NewPlotPanel( m_circuitModel->GetSimCommand() );
}
@ -1739,7 +1739,7 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
SIM_PANEL_BASE* plotPanelWindow = getCurrentPlotWindow();
if( !plotPanelWindow || plotPanelWindow->GetType() != simType )
plotPanelWindow = NewPlotPanel( m_circuitModel->GetUsedSimCommand() );
plotPanelWindow = NewPlotPanel( m_circuitModel->GetSimCommand() );
if( m_simulator->IsRunning() )
return;

View File

@ -28,11 +28,13 @@
#include <confirm.h>
#include <wx/combo.h>
#include <wx/combobox.h>
#include <wx/gtk/notebook.h>
wxBEGIN_EVENT_TABLE( SIM_VALIDATOR, wxValidator )
EVT_TEXT( wxID_ANY, SIM_VALIDATOR::onText )
EVT_CHAR( SIM_VALIDATOR::onChar )
EVT_KEY_DOWN( SIM_VALIDATOR::onKeyDown )
EVT_MOUSE_EVENTS( SIM_VALIDATOR::onMouse )
wxEND_EVENT_TABLE()
@ -83,6 +85,82 @@ bool SIM_VALIDATOR::TransferFromWindow()
}
void SIM_VALIDATOR::navigate( int flags )
{
wxWindow* textCtrl = GetWindow();
if( !textCtrl )
return;
wxPropertyGrid* paramGrid = dynamic_cast<wxPropertyGrid*>( textCtrl->GetParent() );
if( !paramGrid )
return;
wxPropertyGridManager* paramGridMgr =
dynamic_cast<wxPropertyGridManager*>( paramGrid->GetParent() );
if( !paramGridMgr )
return;
#ifdef __WXGTK__
// Workaround for wxWindow::Navigate() working differently on GTK. Same workaround is
// in the WxWidgets source code.
if( flags == wxNavigationKeyEvent::IsBackward )
{
if( wxWindow* sibling = paramGridMgr->GetPrevSibling() )
{
sibling->SetFocusFromKbd();
return;
}
}
else if( flags == wxNavigationKeyEvent::IsForward )
{
if( wxWindow* sibling = paramGridMgr->GetNextSibling() )
{
sibling->SetFocusFromKbd();
return;
}
}
// We didn't find the sibling, so instead we try another workaround by by finding the notebook
// we are in, and jumping out of it.
for( wxWindow* window = paramGridMgr; window; window = window->GetParent() )
{
if( wxNotebook* notebook = dynamic_cast<wxNotebook*>( window ) )
{
if( flags == wxNavigationKeyEvent::IsBackward )
{
for( wxWindow* sibling = notebook->GetNextSibling();
sibling;
sibling = sibling->GetNextSibling() )
{
if( sibling->IsFocusable() )
{
sibling->SetFocusFromKbd();
return;
}
}
}
else if( flags == wxNavigationKeyEvent::IsForward )
{
for( wxWindow* sibling = notebook->GetNextSibling();
sibling;
sibling = sibling->GetNextSibling() )
{
if( sibling->IsFocusable() )
{
sibling->SetFocusFromKbd();
return;
}
}
}
}
}
#else
paramGridMgr->Navigate( flags );
#endif
}
bool SIM_VALIDATOR::isValid( const wxString& aString )
{
return SIM_VALUE_GRAMMAR::IsValid( aString, m_valueType, m_notation );
@ -138,6 +216,65 @@ void SIM_VALIDATOR::onChar( wxKeyEvent& aEvent )
m_prevInsertionPoint = textEntry->GetInsertionPoint();
}
void SIM_VALIDATOR::onKeyDown( wxKeyEvent& aEvent )
{
// Because wxPropertyGrid has special handling for the tab key, wxPropertyGrid::DedicateKey()
// and wxPropertyGrid::AddActionTrigger() don't work for it. So instead we translate it to an
// (up or down) arrow key, which has proper handling (select next or previous property) defined
// by the aforementioned functions.
if( aEvent.GetKeyCode() == WXK_TAB )
{
// However, before that, if this is the first or last property, we instead want to navigate
// to the next or previous widget.
wxWindow* textCtrl = GetWindow();
if( !textCtrl )
{
aEvent.Skip();
return;
}
wxPropertyGrid* paramGrid = dynamic_cast<wxPropertyGrid*>( textCtrl->GetParent() );
if( !paramGrid )
{
aEvent.Skip();
return;
}
wxPropertyGridIterator it = paramGrid->GetIterator( wxPG_ITERATE_VISIBLE,
paramGrid->GetSelection() );
if( !it.AtEnd() )
it.Next();
bool isFirst = paramGrid->GetSelection() == paramGrid->wxPropertyGridInterface::GetFirst();
bool isLast = it.AtEnd();
if( isFirst && aEvent.ShiftDown() )
{
navigate( wxNavigationKeyEvent::IsBackward );
return;
}
if( isLast && !aEvent.ShiftDown() )
{
navigate( wxNavigationKeyEvent::IsForward );
return;
}
if( aEvent.GetModifiers() == wxMOD_SHIFT )
{
aEvent.m_shiftDown = false;
aEvent.m_keyCode = WXK_UP;
}
else
aEvent.m_keyCode = WXK_DOWN;
}
aEvent.Skip();
}
void SIM_VALIDATOR::onMouse( wxMouseEvent& aEvent )
{
aEvent.Skip();
@ -188,9 +325,7 @@ bool SIM_PROPERTY::StringToValue( wxVariant& aVariant, const wxString& aText, in
}
else
{
if( !m_model->SetParamValue( m_paramIndex, aText ) )
return false;
m_model->SetParamValue( m_paramIndex, aText );
aVariant = GetParam().value->ToString();
}

View File

@ -27,6 +27,9 @@
#include <sim/sim_model.h>
#include <wx/window.h>
#include <wx/notebook.h>
#include <wx/propgrid/propgrid.h>
#include <wx/propgrid/manager.h>
#include <wx/propgrid/props.h>
@ -43,12 +46,15 @@ public:
bool TransferFromWindow() override;
private:
void navigate( int flags );
bool isValid( const wxString& aString );
wxTextEntry* getTextEntry();
void onText( wxCommandEvent& aEvent );
void onChar( wxKeyEvent& aEvent );
void onKeyDown( wxKeyEvent& aEvent );
void onMouse( wxMouseEvent& aEvent );
SIM_VALUE::TYPE m_valueType;

View File

@ -163,12 +163,12 @@ namespace SIM_VALUE_GRAMMAR
template <SIM_VALUE::TYPE ValueType, NOTATION Notation>
struct number : seq<significand<ValueType>,
struct number : seq<opt<significand<ValueType>>,
opt<exponentWithPrefix>,
sor<metricSuffix<ValueType, Notation>, not_at<alnum>>> {};
template <SIM_VALUE::TYPE ValueType, NOTATION Notation>
struct numberGrammar : must<opt<number<ValueType, Notation>>, eof> {};
struct numberGrammar : must<number<ValueType, Notation>, eof> {};
bool IsValid( const wxString& aString,

View File

@ -160,8 +160,8 @@ namespace SPICE_GRAMMAR
star<sep,
dotSubcktPinName>>> {};
struct dotSubcktEnd : seq<TAO_PEGTL_ISTRING( ".ends" ),
opt<sep>,
newline> {};
until<newline>> {};
struct spiceUnit;
struct dotSubckt : seq<opt<sep>,
TAO_PEGTL_ISTRING( ".subckt" ),
sep,
@ -174,7 +174,7 @@ namespace SPICE_GRAMMAR
paramValuePairs>,
opt<sep>,
newline,
until<dotSubcktEnd>> {};
until<dotSubcktEnd, spiceUnit>> {};
struct modelUnit : sor<dotModel,

View File

@ -791,9 +791,20 @@ int SCH_EDITOR_CONTROL::SimProbe( const TOOL_EVENT& aEvent )
if( libraryField )
{
wxString path = m_frame->Prj().AbsolutePath( libraryField->GetShownText() );
library = SIM_LIBRARY::Create( path );
if( !library || !nameField )
try
{
library = SIM_LIBRARY::Create( path );
}
catch( const IO_ERROR& e )
{
DisplayErrorMessage( m_frame,
wxString::Format( "Failed reading model library '%s'", path ),
e.What() );
return true;
}
if( !nameField )
return true;
SIM_MODEL* baseModel = library->FindModel( nameField->GetShownText() );

View File

@ -1,9 +0,0 @@
.title KiCad schematic
.include "chirp.lib"
.save all
.probe alli
.tran 10u 100m
XV1 Net-_V1-E1_ Net-_V1-E2_ chirp bf=1k ef=3k bt=30m et=70m
R1 Net-_V1-E1_ Net-_V1-E2_ 10k
.end

File diff suppressed because it is too large Load Diff

View File

@ -103,75 +103,80 @@
)
(wire (pts (xy 182.88 107.315) (xy 182.88 111.125))
(wire (pts (xy 190.5 111.76) (xy 190.5 115.57))
(stroke (width 0) (type default))
(uuid 3c643958-d112-4743-bed0-8d4c351efeca)
)
(wire (pts (xy 160.655 122.555) (xy 182.88 122.555))
(wire (pts (xy 165.1 127) (xy 190.5 127))
(stroke (width 0) (type default))
(uuid 6db20978-f158-409d-9385-faa8f9fe7ead)
)
(wire (pts (xy 160.655 107.315) (xy 182.88 107.315))
(wire (pts (xy 165.1 111.76) (xy 190.5 111.76))
(stroke (width 0) (type default))
(uuid acb257ff-7594-49b9-9b47-4538b18772b4)
)
(wire (pts (xy 182.88 122.555) (xy 182.88 118.745))
(wire (pts (xy 190.5 127) (xy 190.5 123.19))
(stroke (width 0) (type default))
(uuid ec6dd29a-008b-4f48-a33d-2f2833709a39)
)
(text ".tran 10u 100m" (at 160.655 103.505 0)
(text ".tran 10u 100m" (at 165.1 107.95 0)
(effects (font (size 1.27 1.27)) (justify left bottom))
(uuid 49e11e6d-285a-4b97-85e2-04ad8798efbd)
)
(symbol (lib_id "pspice:VSOURCE") (at 160.655 114.935 0) (unit 1)
(label "out" (at 190.5 111.76 0) (fields_autoplaced)
(effects (font (size 1.27 1.27)) (justify left bottom))
(uuid 59cd1c14-c2af-41cd-a9c3-45021dc6ff40)
)
(symbol (lib_id "pspice:VSOURCE") (at 165.1 119.38 0) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid b47ba90e-d24f-47fa-967d-97f9b9ef4e05)
(property "Reference" "V1" (id 0) (at 166.37 114.3 0)
(property "Reference" "V1" (id 0) (at 170.815 118.745 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "VSOURCE" (id 1) (at 166.37 116.84 0)
(property "Value" "" (id 1) (at 170.815 121.285 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 160.655 114.935 0)
(property "Footprint" "" (id 2) (at 165.1 119.38 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 160.655 114.935 0)
(property "Datasheet" "~" (id 3) (at 165.1 119.38 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Name" "chirp" (id 4) (at 160.655 114.935 0)
(property "Model_Name" "chirp" (id 4) (at 165.1 119.38 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Library" "chirp.lib" (id 5) (at 160.655 114.935 0)
(property "Model_Library" "chirp.lib.spice" (id 5) (at 165.1 119.38 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Device" "SUBCKT" (id 6) (at 160.655 114.935 0)
(property "Model_Device" "SUBCKT" (id 6) (at 165.1 119.38 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Params" "bf=1k ef=3k bt=30m et=70m" (id 7) (at 160.655 114.935 0)
(property "Model_Params" "bf=1k ef=3k bt=30m et=70m" (id 7) (at 165.1 119.38 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Pins" "1 2" (id 8) (at 160.655 114.935 0)
(property "Model_Pins" "1 2" (id 8) (at 165.1 119.38 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid 69509f58-8756-4cec-83fa-cd042c171c7a))
(pin "2" (uuid ef1a7634-c4c3-4c75-a241-106a391dae71))
)
(symbol (lib_id "Device:R") (at 182.88 114.935 0) (unit 1)
(symbol (lib_id "Device:R") (at 190.5 119.38 0) (unit 1)
(in_bom yes) (on_board yes) (fields_autoplaced)
(uuid f7b25816-e4a8-4219-9402-57c23b1eba25)
(property "Reference" "R1" (id 0) (at 185.42 114.3 0)
(property "Reference" "R1" (id 0) (at 193.04 118.745 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "10k" (id 1) (at 185.42 116.84 0)
(property "Value" "10k" (id 1) (at 193.04 121.285 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 181.102 114.935 90)
(property "Footprint" "" (id 2) (at 188.722 119.38 90)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (id 3) (at 182.88 114.935 0)
(property "Datasheet" "~" (id 3) (at 190.5 119.38 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid 18fc09e3-d2b3-42f5-a1b2-442e588408fb))

View File

@ -0,0 +1,9 @@
.title KiCad schematic
.include "/home/mikolaj/my/src/kicad/qa/data/eeschema/spice_netlists/chirp/chirp.lib.spice"
.save all
.probe alli
.tran 10u 100m
XV1 /out Net-_V1-E2_ chirp bf=1k ef=3k bt=30m et=70m
R1 /out Net-_V1-E2_ 10k
.end

File diff suppressed because it is too large Load Diff

View File

@ -425,6 +425,10 @@
(uuid d9f81d0b-eee9-4ffb-83bb-dfeab4cb8e24)
)
(label "in" (at 114.3 88.9 0) (fields_autoplaced)
(effects (font (size 1.27 1.27)) (justify left bottom))
(uuid 043cfb29-d22f-4479-a066-20cf3638e487)
)
(label "out" (at 152.4 80.01 0) (fields_autoplaced)
(effects (font (size 1.27 1.27)) (justify left bottom))
(uuid 8829145d-f83c-4c92-bedf-89385f7a7a60)
@ -509,7 +513,7 @@
(property "Reference" "Q1" (id 0) (at 140.97 88.265 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "QNPN" (id 1) (at 140.97 90.805 0)
(property "Value" "" (id 1) (at 140.97 90.805 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 135.89 88.9 0)
@ -521,7 +525,7 @@
(property "Model_Name" "NPN" (id 4) (at 142.875 92.71 0)
(effects (font (size 1.27 1.27)))
)
(property "Model_Library" "npn.lib" (id 5) (at 135.89 88.9 0)
(property "Model_Library" "npn.lib.spice" (id 5) (at 135.89 88.9 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Device" "NPN" (id 6) (at 135.89 88.9 0)

View File

@ -1,17 +1,17 @@
.title KiCad schematic
.include "npn.lib"
.include "npn.lib.spice"
.save all
.probe alli
.tran 1u 1m
R1 Net-_R1-Pad1_ Net-_Q1-B_ 1k
R2 Net-_Q1-B_ GND 1k
Q1 /out Net-_Q1-B_ Net-_Q1-E_ NPN
R4 Net-_Q1-E_ Net-_C2-Pad2_ 100
C2 Net-_Q1-E_ Net-_C2-Pad2_ 10u
R5 Net-_C2-Pad2_ GND 1
R2 Net-_Q1-B_ GND 1k
R1 Net-_R1-Pad1_ Net-_Q1-B_ 1k
C1 /in Net-_Q1-B_ 10u
V1 Net-_R1-Pad1_ GND 9
R3 Net-_R1-Pad1_ /out 100
V2 Net-_C1-Pad1_ GND SIN( 0 10m 10k )
C1 Net-_C1-Pad1_ Net-_Q1-B_ 10u
V1 Net-_R1-Pad1_ GND ( 9 )
C2 Net-_Q1-E_ Net-_C2-Pad2_ 10u
R4 Net-_Q1-E_ Net-_C2-Pad2_ 100
R5 Net-_C2-Pad2_ GND 1
V2 /in GND SIN( 0 10m 10k )
.end

View File

@ -1,13 +0,0 @@
.title KiCad schematic
.include "opamp.lib"
.save all
.probe alli
.tran 10u 10m
R1 GND Net-_U1--_ 10k
R2 Net-_U1--_ /out 10k
V3 GND Net-_U1-V-_ ( 5 )
VSIN1 /in GND SIN( 0 100m 1k )
V2 Net-_U1-V+_ GND ( 5 )
XU1 /in Net-_U1--_ Net-_U1-V+_ Net-_U1-V-_ /out uopamp_lvl2
.end

File diff suppressed because it is too large Load Diff

View File

@ -431,16 +431,16 @@
(property "Datasheet" "~" (id 3) (at 160.02 91.44 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Name" "uopamp_lvl2" (id 6) (at 160.02 91.44 0)
(property "Model_Name" "uopamp_lvl1" (id 6) (at 160.02 91.44 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Library" "opamp.lib" (id 7) (at 160.02 91.44 0)
(property "Model_Library" "opamp.lib.spice" (id 7) (at 160.02 91.44 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Device" "SUBCKT" (id 8) (at 160.02 91.44 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Pins" "1 2 4 5 3" (id 9) (at 160.02 91.44 0)
(property "Model_Pins" "1 2 3" (id 9) (at 160.02 91.44 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid bd8261ed-4ec3-466d-a593-de8cc22438a4))

View File

@ -0,0 +1,13 @@
.title KiCad schematic
.include "opamp.lib.spice"
.save all
.probe alli
.tran 10u 10m
R1 GND Net-_U1--_ 10k
R2 Net-_U1--_ /out 10k
V3 GND Net-_U1-V-_ AC ( 5 )
VSIN1 /in GND AC SIN( 0 100m 1k )
V2 Net-_U1-V+_ GND AC ( 5 )
XU1 /in Net-_U1--_ /out uopamp_lvl1
.end

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -235,6 +235,10 @@
(stroke (width 0) (type default))
(uuid 2ba860d8-4c67-4b9e-85f2-068d29a33da8)
)
(wire (pts (xy 153.67 76.2) (xy 165.1 76.2))
(stroke (width 0) (type default))
(uuid 32ef0900-be90-4745-84e4-eff29463f742)
)
(wire (pts (xy 153.67 114.3) (xy 165.1 114.3))
(stroke (width 0) (type default))
(uuid 3668df94-f0a6-4370-aa0d-9f77618594f1)
@ -243,10 +247,6 @@
(stroke (width 0) (type default))
(uuid b00425c7-fc25-4d52-86ca-c25504c4afd0)
)
(wire (pts (xy 153.67 76.2) (xy 165.1 76.2))
(stroke (width 0) (type default))
(uuid b49a2030-2a38-4ee5-93a8-9e5f491987d4)
)
(wire (pts (xy 127 114.3) (xy 138.43 114.3))
(stroke (width 0) (type default))
(uuid c54361d7-984a-4956-9835-91d4c78f3499)
@ -325,10 +325,10 @@
(symbol (lib_id "Transmission_Line:TLINE") (at 146.05 114.3 0) (unit 1)
(in_bom no) (on_board no) (fields_autoplaced)
(uuid 34b3fec2-c790-40cf-bb63-dd642fff2299)
(property "Reference" "T2" (id 0) (at 146.0509 109.22 0)
(property "Reference" "TLINE2" (id 0) (at 146.0509 109.22 0)
(effects (font (size 1.27 1.27)))
)
(property "Value" "TLINE" (id 1) (at 146.0509 111.76 0)
(property "Value" "len=1 r=0 l=1.25m g=0 c=500n" (id 1) (at 146.0509 111.76 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (id 2) (at 146.05 114.3 0)
@ -337,18 +337,6 @@
(property "Datasheet" "http://ngspice.sourceforge.net/docs/ngspice-36-manual.pdf#7f" (id 3) (at 146.05 109.22 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Device" "TLINE" (id 4) (at 146.05 114.3 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Type" "RLGC" (id 5) (at 146.05 114.3 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Pins" "1 2 3 4" (id 6) (at 146.05 114.3 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Params" "len=1 r=0 l=1.25m g=0 c=500n" (id 7) (at 146.05 114.3 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid 3ba94ccd-338c-44da-afd8-322313c0ff13))
(pin "2" (uuid ed81258e-3e5d-4a2d-8e04-b3182f9c51c0))
(pin "3" (uuid 443d9994-dd5c-4f22-b64a-7cbede1ad619))
@ -361,7 +349,7 @@
(property "Reference" "VPULSE1" (id 0) (at 87.63 80.01 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "v2=1 tr=1u tf=1u pw=50u per=100u" (id 1) (at 87.63 82.55 0)
(property "Value" "v2=1 tr=1u tf=1u tw=50u per=100u" (id 1) (at 87.63 82.55 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 127 81.28 0)
@ -468,10 +456,10 @@
(symbol (lib_id "Transmission_Line:TLINE") (at 146.05 76.2 0) (unit 1)
(in_bom no) (on_board no) (fields_autoplaced)
(uuid b320600b-eef1-4883-916c-38700f3f43d4)
(property "Reference" "T1" (id 0) (at 146.0509 71.12 0)
(property "Reference" "TLINE1" (id 0) (at 146.0509 71.12 0)
(effects (font (size 1.27 1.27)))
)
(property "Value" "TLINE" (id 1) (at 146.0509 73.66 0)
(property "Value" "z0=50 td=25u" (id 1) (at 146.0509 73.66 0)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (id 2) (at 146.05 76.2 0)
@ -480,18 +468,6 @@
(property "Datasheet" "http://ngspice.sourceforge.net/docs/ngspice-36-manual.pdf#7f" (id 3) (at 146.05 71.12 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Device" "TLINE" (id 4) (at 146.05 76.2 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Type" "Z0" (id 5) (at 146.05 76.2 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Pins" "1 2 3 4" (id 6) (at 146.05 76.2 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Model_Params" "z0=50 td=25u" (id 7) (at 146.05 76.2 0)
(effects (font (size 1.27 1.27)) hide)
)
(pin "1" (uuid ea050e5c-1246-4281-a897-0695b0c28888))
(pin "2" (uuid 6a849f27-b16c-48cb-80be-7504707e9e4a))
(pin "3" (uuid a8652546-dd2b-4f4f-874e-abb58500b88a))
@ -541,7 +517,7 @@
(property "Reference" "VPULSE2" (id 0) (at 87.63 118.11 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Value" "v2=1 tr=1u tf=1u pw=50u per=100u" (id 1) (at 87.63 120.65 0)
(property "Value" "v2=1 tr=1u tf=1u tw=50u per=100u" (id 1) (at 87.63 120.65 0)
(effects (font (size 1.27 1.27)) (justify left))
)
(property "Footprint" "" (id 2) (at 127 119.38 0)
@ -608,16 +584,16 @@
(reference "R2") (unit 1) (value "50") (footprint "")
)
(path "/b320600b-eef1-4883-916c-38700f3f43d4"
(reference "T1") (unit 1) (value "TLINE") (footprint "")
(reference "TLINE1") (unit 1) (value "z0=50 td=25u") (footprint "")
)
(path "/34b3fec2-c790-40cf-bb63-dd642fff2299"
(reference "T2") (unit 1) (value "TLINE") (footprint "")
(reference "TLINE2") (unit 1) (value "len=1 r=0 l=1.25m g=0 c=500n") (footprint "")
)
(path "/56fc236a-df5f-49ef-9b92-3227f86197b4"
(reference "VPULSE1") (unit 1) (value "v2=1 tr=1u tf=1u pw=50u per=100u") (footprint "")
(reference "VPULSE1") (unit 1) (value "v2=1 tr=1u tf=1u tw=50u per=100u") (footprint "")
)
(path "/fcc0dfa9-c624-4a32-a3d3-4c36ee7b0fe6"
(reference "VPULSE2") (unit 1) (value "v2=1 tr=1u tf=1u pw=50u per=100u") (footprint "")
(reference "VPULSE2") (unit 1) (value "v2=1 tr=1u tf=1u tw=50u per=100u") (footprint "")
)
)
)

View File

@ -62,47 +62,11 @@ wxFileName KI_TEST::GetEeschemaTestDataDir()
}
std::unique_ptr<SCHEMATIC> ReadSchematicFromFile( const std::string& aFilename )
void KI_TEST::SCHEMATIC_TEST_FIXTURE::LoadSchematic( const wxString& aBaseName )
{
auto pi = SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD );
std::unique_ptr<SCHEMATIC> schematic = std::make_unique<SCHEMATIC>( nullptr );
wxFileName fn = GetSchematicPath( aBaseName );
schematic->Reset();
schematic->SetRoot( pi->Load( aFilename, schematic.get() ) );
schematic->CurrentSheet().push_back( &schematic->Root() );
SCH_SCREENS screens( schematic->Root() );
for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
screen->UpdateLocalLibSymbolLinks();
SCH_SHEET_LIST sheets = schematic->GetSheets();
// Restore all of the loaded symbol instances from the root sheet screen.
sheets.UpdateSymbolInstances( schematic->RootScreen()->GetSymbolInstances() );
sheets.AnnotatePowerSymbols();
// NOTE: This is required for multi-unit symbols to be correct
// Normally called from SCH_EDIT_FRAME::FixupJunctions() but could be refactored
for( SCH_SHEET_PATH& sheet : sheets )
sheet.UpdateAllScreenReferences();
// NOTE: SchematicCleanUp is not called; QA schematics must already be clean or else
// SchematicCleanUp must be freed from its UI dependencies.
schematic->ConnectionGraph()->Recalculate( sheets, true );
return schematic;
}
template <typename Exporter>
void TEST_NETLIST_EXPORTER_FIXTURE<Exporter>::LoadSchematic( const wxString& aBaseName )
{
wxString fn = GetSchematicPath( aBaseName );
BOOST_TEST_MESSAGE( fn );
BOOST_TEST_MESSAGE( fn.GetFullPath() );
wxFileName pro( fn );
pro.SetExt( ProjectFileExtension );
@ -113,7 +77,7 @@ void TEST_NETLIST_EXPORTER_FIXTURE<Exporter>::LoadSchematic( const wxString& aBa
m_schematic.Reset();
m_schematic.SetProject( &m_manager.Prj() );
m_schematic.SetRoot( m_pi->Load( fn, &m_schematic ) );
m_schematic.SetRoot( m_pi->Load( fn.GetFullPath(), &m_schematic ) );
BOOST_REQUIRE_EQUAL( m_pi->GetError().IsEmpty(), true );
@ -128,6 +92,7 @@ void TEST_NETLIST_EXPORTER_FIXTURE<Exporter>::LoadSchematic( const wxString& aBa
// Restore all of the loaded symbol instances from the root sheet screen.
sheets.UpdateSymbolInstances( m_schematic.RootScreen()->GetSymbolInstances() );
sheets.UpdateSheetInstances( m_schematic.RootScreen()->GetSheetInstances() );
sheets.AnnotatePowerSymbols();
@ -143,8 +108,7 @@ void TEST_NETLIST_EXPORTER_FIXTURE<Exporter>::LoadSchematic( const wxString& aBa
}
template <typename Exporter>
wxString TEST_NETLIST_EXPORTER_FIXTURE<Exporter>::GetSchematicPath( const wxString& aBaseName )
wxFileName KI_TEST::SCHEMATIC_TEST_FIXTURE::GetSchematicPath( const wxString& aBaseName )
{
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
fn.AppendDir( "netlists" );
@ -152,7 +116,7 @@ wxString TEST_NETLIST_EXPORTER_FIXTURE<Exporter>::GetSchematicPath( const wxStri
fn.SetName( aBaseName );
fn.SetExt( KiCadSchematicFileExtension );
return fn.GetFullPath();
return fn;
}

View File

@ -60,21 +60,22 @@ wxFileName GetEeschemaTestDataDir();
class SCHEMATIC_TEST_FIXTURE
{
public:
SCHEMATIC_TEST_FIXTURE() : m_schematic( nullptr ), m_manager( true )
SCHEMATIC_TEST_FIXTURE()
: m_schematic( nullptr ),
m_pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) ),
m_manager( true )
{
m_pi = SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD );
}
virtual ~SCHEMATIC_TEST_FIXTURE()
{
m_schematic.Reset();
delete m_pi;
SCH_IO_MGR::ReleasePlugin( m_pi );
}
protected:
virtual void loadSchematic( const wxString& aRelativePath );
virtual wxFileName getSchematicFile( const wxString& aBaseName );
virtual void LoadSchematic( const wxString& aRelativePath );
virtual wxFileName GetSchematicPath( const wxString& aBaseName );
///> Schematic to load
SCHEMATIC m_schematic;
@ -89,26 +90,9 @@ protected:
template <typename Exporter>
class TEST_NETLIST_EXPORTER_FIXTURE
class TEST_NETLIST_EXPORTER_FIXTURE : public KI_TEST::SCHEMATIC_TEST_FIXTURE
{
public:
TEST_NETLIST_EXPORTER_FIXTURE() :
m_schematic( nullptr ),
m_pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) ),
m_manager( true )
{
}
virtual ~TEST_NETLIST_EXPORTER_FIXTURE()
{
m_schematic.Reset();
SCH_IO_MGR::ReleasePlugin( m_pi );
}
void LoadSchematic( const wxString& aBaseName );
virtual wxString GetSchematicPath( const wxString& aBaseName );
virtual wxString GetNetlistPath( bool aTest = false );
virtual unsigned GetNetlistOptions() { return 0; }
@ -119,13 +103,6 @@ public:
void Cleanup();
void TestNetlist( const wxString& aBaseName );
///> Schematic to load
SCHEMATIC m_schematic;
SCH_PLUGIN* m_pi;
SETTINGS_MANAGER m_manager;
};
template class TEST_NETLIST_EXPORTER_FIXTURE<NETLIST_EXPORTER_KICAD>;

View File

@ -44,7 +44,7 @@ public:
{
wxString path = GetLibraryPath( aBaseName );
m_library = std::make_unique<SIM_LIBRARY_SPICE>();
BOOST_CHECK( m_library->ReadFile( path ) );
m_library->ReadFile( path );
}
void CompareToUsualDiodeModel( const SIM_MODEL& aModel, const wxString& aModelName, int aModelIndex )

View File

@ -24,12 +24,39 @@
#include <qa_utils/wx_utils/unit_test_utils.h>
#include <eeschema_test_utils.h>
#include <netlist_exporter_spice.h>
#include <sim/ngspice.h>
#include <sim/spice_reporter.h>
#include <wx/ffile.h>
#include <mock_pgm_base.h>
class TEST_NETLIST_EXPORTER_SPICE_FIXTURE : public TEST_NETLIST_EXPORTER_FIXTURE<NETLIST_EXPORTER_SPICE>
{
public:
wxString GetSchematicPath( const wxString& aBaseName ) override
class SPICE_TEST_REPORTER : public SPICE_REPORTER
{
REPORTER& Report( const wxString& aText,
SEVERITY aSeverity = RPT_SEVERITY_UNDEFINED ) override
{
return *this;
}
bool HasMessage() const override { return false; }
void OnSimStateChange( SPICE_SIMULATOR* aObject, SIM_STATE aNewState ) override
{
}
};
TEST_NETLIST_EXPORTER_SPICE_FIXTURE() :
TEST_NETLIST_EXPORTER_FIXTURE<NETLIST_EXPORTER_SPICE>(),
m_simulator( SPICE_SIMULATOR::CreateInstance( "ngspice" ) ),
m_reporter( std::make_unique<SPICE_TEST_REPORTER>() )
{
}
wxFileName GetSchematicPath( const wxString& aBaseName ) override
{
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
fn.AppendDir( "spice_netlists" );
@ -37,7 +64,7 @@ public:
fn.SetName( aBaseName );
fn.SetExt( KiCadSchematicFileExtension );
return fn.GetFullPath();
return fn;
}
wxString GetNetlistPath( bool aTest = false ) override
@ -47,14 +74,37 @@ public:
if( aTest )
netFile.SetName( netFile.GetName() + "_test" );
netFile.SetExt( "cir" );
netFile.SetExt( "spice" );
return netFile.GetFullPath();
}
void CompareNetlists() override
{
FILE_LINE_READER refReader( GetNetlistPath() );
FILE_LINE_READER resultReader( GetNetlistPath( true ) );
// Our simulator is actually Ngspice.
NGSPICE* ngspice = dynamic_cast<NGSPICE*>( m_simulator.get() );
ngspice->SetReporter( m_reporter.get() );
wxFFile file( GetNetlistPath( true ), "rt" );
wxString netlist;
file.ReadAll( &netlist );
//ngspice->Init();
ngspice->Command( "set ngbehavior=ps" );
ngspice->LoadNetlist( netlist.ToStdString() );
ngspice->Run();
ngspice->Command( "set filetype=ascii" );
wxString vectors;
for( const wxString& vector : m_plottedVectors )
vectors << vector << " ";
ngspice->Command( wxString::Format( "write %s %s", GetResultsPath( true ),
vectors ).ToStdString() );
FILE_LINE_READER refReader( GetResultsPath() );
FILE_LINE_READER resultReader( GetResultsPath( true ) );
char* refLine = nullptr;
char* resultLine = nullptr;
@ -63,6 +113,10 @@ public:
refLine = refReader.ReadLine();
resultLine = resultReader.ReadLine();
// Ignore the date.
if( wxString( resultLine ).StartsWith( "Date: " ) )
continue;
if( !refLine || !resultReader )
break;
@ -74,11 +128,30 @@ public:
std::string( resultReader.Line() ) );
}
void TestNetlist( const wxString& aBaseName, const std::vector<wxString> aPlottedVectors )
{
m_plottedVectors = aPlottedVectors;
TEST_NETLIST_EXPORTER_FIXTURE<NETLIST_EXPORTER_SPICE>::TestNetlist( aBaseName );
}
wxString GetResultsPath( bool aTest = false )
{
wxFileName netlistPath( GetNetlistPath( aTest ) );
netlistPath.SetExt( "csv" );
return netlistPath.GetFullPath();
}
unsigned GetNetlistOptions() override
{
return NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES
| NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS;
| NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS
| NETLIST_EXPORTER_SPICE::OPTION_ADJUST_INCLUDE_PATHS;
}
std::unique_ptr<SPICE_TEST_REPORTER> m_reporter;
std::shared_ptr<SPICE_SIMULATOR> m_simulator;
std::vector<wxString> m_plottedVectors;
};
@ -87,37 +160,46 @@ BOOST_FIXTURE_TEST_SUITE( NetlistExporterSpice, TEST_NETLIST_EXPORTER_SPICE_FIXT
BOOST_AUTO_TEST_CASE( Rectifier )
{
TestNetlist( "rectifier" );
const MOCK_PGM_BASE& program = static_cast<MOCK_PGM_BASE&>( Pgm() );
MOCK_EXPECT( program.GetLocalEnvVariables ).returns( ENV_VAR_MAP() );
TestNetlist( "rectifier", { "V(/in)", "V(/out)" } );
}
BOOST_AUTO_TEST_CASE( Chirp )
// FIXME: Fails due to some nondeterminism, seems related to convergence problems.
/*BOOST_AUTO_TEST_CASE( Chirp )
{
TestNetlist( "chirp" );
}
TestNetlist( "chirp", { "V(/out)" } );
}*/
BOOST_AUTO_TEST_CASE( Opamp )
{
TestNetlist( "opamp" );
const MOCK_PGM_BASE& program = static_cast<MOCK_PGM_BASE&>( Pgm() );
MOCK_EXPECT( program.GetLocalEnvVariables ).returns( ENV_VAR_MAP() );
TestNetlist( "opamp", { "V(/in)", "V(/out)" } );
}
BOOST_AUTO_TEST_CASE( NpnCeAmp )
{
TestNetlist( "npn_ce_amp" );
TestNetlist( "npn_ce_amp", { "V(/in)", "V(/out)" } );
}
// Incomplete.
BOOST_AUTO_TEST_CASE( Passives )
/*BOOST_AUTO_TEST_CASE( Passives )
{
TestNetlist( "passives" );
}
}*/
BOOST_AUTO_TEST_CASE( Tlines )
{
TestNetlist( "tlines" );
TestNetlist( "tlines", { "V(/z0_in)", "V(/z0_out)", "V(/rlgc_in)", "V(/rlgc_out)" } );
}

View File

@ -56,7 +56,7 @@ void TEST_SCH_REFERENCE_LIST_FIXTURE::loadTestCase( wxString aSchematicRelativeP
m_refsToReannotate.Clear();
m_lockedRefs.clear();
loadSchematic( aSchematicRelativePath );
LoadSchematic( aSchematicRelativePath );
// Create list of references to reannotate
for( REANNOTATED_REFERENCE ref : aRefs )

View File

@ -26,11 +26,11 @@
class TEST_SCH_SHEET_LIST_FIXTURE : public KI_TEST::SCHEMATIC_TEST_FIXTURE
{
protected:
wxFileName getSchematicFile( const wxString& aRelativePath ) override;
wxFileName GetSchematicPath( const wxString& aRelativePath ) override;
};
wxFileName TEST_SCH_SHEET_LIST_FIXTURE::getSchematicFile( const wxString& aRelativePath )
wxFileName TEST_SCH_SHEET_LIST_FIXTURE::GetSchematicPath( const wxString& aRelativePath )
{
wxFileName fn = KI_TEST::GetEeschemaTestDataDir();
fn.AppendDir( "netlists" );
@ -47,7 +47,7 @@ BOOST_FIXTURE_TEST_SUITE( SchSheetList, TEST_SCH_SHEET_LIST_FIXTURE )
BOOST_AUTO_TEST_CASE( TestSheetListPageProperties )
{
loadSchematic( "complex_hierarchy/complex_hierarchy" );
LoadSchematic( "complex_hierarchy/complex_hierarchy" );
SCH_SHEET_LIST sheets = m_schematic.GetSheets();
@ -67,7 +67,7 @@ BOOST_AUTO_TEST_CASE( TestEditPageNumbersInSharedDesign )
BOOST_TEST_CONTEXT( "Read Sub-Sheet, prior to modification" )
{
// Check the Sub Sheet has the expected page numbers
loadSchematic( "complex_hierarchy_shared/ampli_ht/ampli_ht" );
LoadSchematic( "complex_hierarchy_shared/ampli_ht/ampli_ht" );
SCH_SHEET_LIST sheets = m_schematic.GetSheets();
@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE( TestEditPageNumbersInSharedDesign )
BOOST_TEST_CONTEXT( "Read Root Sheet, prior to modification" )
{
// Check the parent sheet has the expected page numbers
loadSchematic( "complex_hierarchy_shared/complex_hierarchy" );
LoadSchematic( "complex_hierarchy_shared/complex_hierarchy" );
SCH_SHEET_LIST sheets = m_schematic.GetSheets();
@ -104,9 +104,9 @@ BOOST_AUTO_TEST_CASE( TestEditPageNumbersInSharedDesign )
// Save and reload
wxString tempName = "complex_hierarchy_shared/complex_hierarchy_modified";
wxFileName tempFn = getSchematicFile( tempName );
wxFileName tempFn = GetSchematicPath( tempName );
m_pi->Save( tempFn.GetFullPath(), &m_schematic.Root(), &m_schematic );
loadSchematic( tempName );
LoadSchematic( tempName );
sheets = m_schematic.GetSheets();
@ -125,7 +125,7 @@ BOOST_AUTO_TEST_CASE( TestEditPageNumbersInSharedDesign )
{
// Check the Sub Sheet has the expected page numbers
// (This should not have been modified after editing the root sheet)
loadSchematic( "complex_hierarchy_shared/ampli_ht/ampli_ht" );
LoadSchematic( "complex_hierarchy_shared/ampli_ht/ampli_ht" );
SCH_SHEET_LIST sheets = m_schematic.GetSheets();