Spice simulator: add Ngspce model behavior mode settings.
ADDED: Ngspice simulator model behavior mode settings for PSpice, LTSpice,
PSpice and LTSpice, and HSpice.
Fixes https://gitlab.com/kicad/code/kicad/issues/5810
This commit is contained in:
+113
-73
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <wx/stc/stc.h>
|
||||
|
||||
#include <project/project_file.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <eeschema_id.h>
|
||||
#include <kiway.h>
|
||||
@@ -36,6 +37,7 @@
|
||||
#include <dialogs/dialog_signal_list.h>
|
||||
#include "netlist_exporter_pspice_sim.h"
|
||||
#include <pgm_base.h>
|
||||
#include "ngspice.h"
|
||||
#include "sim_plot_colors.h"
|
||||
#include "sim_plot_frame.h"
|
||||
#include "sim_plot_panel.h"
|
||||
@@ -59,8 +61,8 @@ SIM_PLOT_TYPE operator|( SIM_PLOT_TYPE aFirst, SIM_PLOT_TYPE aSecond )
|
||||
class SIM_THREAD_REPORTER : public SPICE_REPORTER
|
||||
{
|
||||
public:
|
||||
SIM_THREAD_REPORTER( SIM_PLOT_FRAME* aParent )
|
||||
: m_parent( aParent )
|
||||
SIM_THREAD_REPORTER( SIM_PLOT_FRAME* aParent ) :
|
||||
m_parent( aParent )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -83,17 +85,17 @@ public:
|
||||
|
||||
switch( aNewState )
|
||||
{
|
||||
case SIM_IDLE:
|
||||
event = new wxCommandEvent( EVT_SIM_FINISHED );
|
||||
break;
|
||||
case SIM_IDLE:
|
||||
event = new wxCommandEvent( EVT_SIM_FINISHED );
|
||||
break;
|
||||
|
||||
case SIM_RUNNING:
|
||||
event = new wxCommandEvent( EVT_SIM_STARTED );
|
||||
break;
|
||||
case SIM_RUNNING:
|
||||
event = new wxCommandEvent( EVT_SIM_STARTED );
|
||||
break;
|
||||
|
||||
default:
|
||||
wxFAIL;
|
||||
return;
|
||||
default:
|
||||
wxFAIL;
|
||||
return;
|
||||
}
|
||||
|
||||
wxQueueEvent( m_parent, event );
|
||||
@@ -105,8 +107,10 @@ private:
|
||||
|
||||
|
||||
TRACE_DESC::TRACE_DESC( const NETLIST_EXPORTER_PSPICE_SIM& aExporter, const wxString& aName,
|
||||
SIM_PLOT_TYPE aType, const wxString& aParam )
|
||||
: m_name( aName ), m_type( aType ), m_param( aParam )
|
||||
SIM_PLOT_TYPE aType, const wxString& aParam ) :
|
||||
m_name( aName ),
|
||||
m_type( aType ),
|
||||
m_param( aParam )
|
||||
{
|
||||
// Title generation
|
||||
m_title = wxString::Format( "%s(%s)", aParam, aName );
|
||||
@@ -117,14 +121,16 @@ TRACE_DESC::TRACE_DESC( const NETLIST_EXPORTER_PSPICE_SIM& aExporter, const wxSt
|
||||
m_title += " (phase)";
|
||||
}
|
||||
|
||||
|
||||
// Store the path of saved workbooks during the session
|
||||
wxString SIM_PLOT_FRAME::m_savedWorkbooksPath;
|
||||
|
||||
SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
|
||||
: SIM_PLOT_FRAME_BASE( aParent ),
|
||||
m_lastSimPlot( nullptr ),
|
||||
m_welcomePanel( nullptr ),
|
||||
m_plotNumber( 0 )
|
||||
|
||||
SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
|
||||
SIM_PLOT_FRAME_BASE( aParent ),
|
||||
m_lastSimPlot( nullptr ),
|
||||
m_welcomePanel( nullptr ),
|
||||
m_plotNumber( 0 )
|
||||
{
|
||||
SetKiway( this, aKiway );
|
||||
m_signalsIconColorList = NULL;
|
||||
@@ -139,6 +145,14 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
|
||||
icon.CopyFromBitmap( KiBitmap( BITMAPS::simulator ) );
|
||||
SetIcon( icon );
|
||||
|
||||
m_simulator = SPICE_SIMULATOR::CreateInstance( "ngspice" );
|
||||
|
||||
if( !m_simulator )
|
||||
{
|
||||
throw std::runtime_error( "Could not create simulator instance" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the previous size and position of windows:
|
||||
LoadSettings( config() );
|
||||
|
||||
@@ -148,14 +162,6 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
|
||||
// Give icons to menuitems
|
||||
setIconsForMenuItems();
|
||||
|
||||
m_simulator = SPICE_SIMULATOR::CreateInstance( "ngspice" );
|
||||
|
||||
if( !m_simulator )
|
||||
{
|
||||
throw std::runtime_error( "Could not create simulator instance" );
|
||||
return;
|
||||
}
|
||||
|
||||
m_simulator->Init();
|
||||
|
||||
if( m_savedWorkbooksPath.IsEmpty() )
|
||||
@@ -178,7 +184,8 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
|
||||
Connect( EVT_SIM_REPORT, wxCommandEventHandler( SIM_PLOT_FRAME::onSimReport ), NULL, this );
|
||||
Connect( EVT_SIM_STARTED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimStarted ), NULL, this );
|
||||
Connect( EVT_SIM_FINISHED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimFinished ), NULL, this );
|
||||
Connect( EVT_SIM_CURSOR_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onCursorUpdate ), NULL, this );
|
||||
Connect( EVT_SIM_CURSOR_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onCursorUpdate ),
|
||||
NULL, this );
|
||||
|
||||
// Toolbar buttons
|
||||
m_toolSimulate = m_toolBar->AddTool( ID_SIM_RUN, _( "Run/Stop Simulation" ),
|
||||
@@ -204,12 +211,14 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
|
||||
wxCommandEventHandler( SIM_PLOT_FRAME::onSettings ), NULL, this );
|
||||
|
||||
// Bind toolbar buttons event to existing menu event handlers, so they behave the same
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSimulate, this, m_runSimulation->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onAddSignal, this, m_addSignals->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onProbe, this, m_probeSignals->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onTune, this, m_tuneValue->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onShowNetlist, this, m_showNetlist->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSettings, this, m_settings->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSimulate, this,
|
||||
m_runSimulation->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onAddSignal, this, m_addSignals->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onProbe, this, m_probeSignals->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onTune, this, m_tuneValue->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onShowNetlist, this,
|
||||
m_showNetlist->GetId() );
|
||||
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSettings, this, m_settings->GetId() );
|
||||
|
||||
m_toolBar->Realize();
|
||||
|
||||
@@ -258,6 +267,14 @@ void SIM_PLOT_FRAME::SaveSettings( APP_SETTINGS_BASE* aCfg )
|
||||
cfg->m_Simulator.cursors_panel_height = m_splitterTuneValues->GetSashPosition();
|
||||
cfg->m_Simulator.white_background = m_plotUseWhiteBg;
|
||||
}
|
||||
|
||||
if( m_schematicFrame )
|
||||
{
|
||||
PROJECT_FILE& project = Prj().GetProjectFile();
|
||||
|
||||
project.m_SchematicSettings->m_NgspiceSimulatorSettings->SaveToFile();
|
||||
m_schematicFrame->SaveProjectSettings();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -277,6 +294,13 @@ void SIM_PLOT_FRAME::LoadSettings( APP_SETTINGS_BASE* aCfg )
|
||||
m_splitterTuneValuesSashPosition = cfg->m_Simulator.cursors_panel_height;
|
||||
m_plotUseWhiteBg = cfg->m_Simulator.white_background;
|
||||
}
|
||||
|
||||
PROJECT_FILE& project = Prj().GetProjectFile();
|
||||
|
||||
NGSPICE* currentSim = dynamic_cast<NGSPICE*>( m_simulator.get() );
|
||||
|
||||
if( currentSim )
|
||||
m_simulator->Settings() = project.m_SchematicSettings->m_NgspiceSimulatorSettings;
|
||||
}
|
||||
|
||||
|
||||
@@ -345,7 +369,8 @@ void SIM_PLOT_FRAME::setIconsForMenuItems()
|
||||
continue;
|
||||
|
||||
wxMenu* menu = item->GetMenu();
|
||||
// Calculate the initial index of item inside the wxMenu parent
|
||||
|
||||
// Calculate the initial index of item inside the wxMenu parent.
|
||||
wxMenuItemList& mlist = menu->GetMenuItems();
|
||||
int mpos = mlist.IndexOf( item );
|
||||
|
||||
@@ -354,6 +379,7 @@ void SIM_PLOT_FRAME::setIconsForMenuItems()
|
||||
// Modify the bitmap
|
||||
menu->Remove( item );
|
||||
AddBitmapToMenuItem( item, KiBitmap( bm_list[ii].m_Bitmap ) );
|
||||
|
||||
// Insert item to its the initial index
|
||||
menu->Insert( mpos, item );
|
||||
}
|
||||
@@ -382,7 +408,7 @@ void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
|
||||
STRING_FORMATTER formatter;
|
||||
|
||||
if( !m_settingsDlg )
|
||||
m_settingsDlg = new DIALOG_SIM_SETTINGS( this );
|
||||
m_settingsDlg = new DIALOG_SIM_SETTINGS( this, m_simulator->Settings() );
|
||||
|
||||
m_simConsole->Clear();
|
||||
updateNetlistExporter();
|
||||
@@ -490,7 +516,8 @@ void SIM_PLOT_FRAME::AddTuner( SCH_COMPONENT* aComponent )
|
||||
// For now limit the tuner tool to RLC components
|
||||
char primitiveType = NETLIST_EXPORTER_PSPICE::GetSpiceField( SF_PRIMITIVE, aComponent, 0 )[0];
|
||||
|
||||
if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR && primitiveType != SP_INDUCTOR )
|
||||
if( primitiveType != SP_RESISTOR && primitiveType != SP_CAPACITOR
|
||||
&& primitiveType != SP_INDUCTOR )
|
||||
return;
|
||||
|
||||
const wxString componentName = aComponent->GetField( REFERENCE_FIELD )->GetText();
|
||||
@@ -546,6 +573,14 @@ const NETLIST_EXPORTER_PSPICE_SIM* SIM_PLOT_FRAME::GetExporter() const
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<SPICE_SIMULATOR_SETTINGS>& SIM_PLOT_FRAME::GetSimulatorSettings()
|
||||
{
|
||||
wxASSERT( m_simulator->Settings() );
|
||||
|
||||
return m_simulator->Settings();
|
||||
}
|
||||
|
||||
|
||||
void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam )
|
||||
{
|
||||
SIM_TYPE simType = m_exporter->GetSimType();
|
||||
@@ -586,7 +621,8 @@ void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const
|
||||
|
||||
// Add two plots: magnitude & phase
|
||||
TRACE_DESC mag_desc( *m_exporter, descriptor, (SIM_PLOT_TYPE)( baseType | SPT_AC_MAG ) );
|
||||
TRACE_DESC phase_desc( *m_exporter, descriptor, (SIM_PLOT_TYPE)( baseType | SPT_AC_PHASE ) );
|
||||
TRACE_DESC phase_desc( *m_exporter, descriptor,
|
||||
(SIM_PLOT_TYPE)( baseType | SPT_AC_PHASE ) );
|
||||
|
||||
updated |= updatePlot( mag_desc, plotPanel );
|
||||
updated |= updatePlot( phase_desc, plotPanel );
|
||||
@@ -631,6 +667,7 @@ void SIM_PLOT_FRAME::removePlot( const wxString& aPlotName, bool aErase )
|
||||
void SIM_PLOT_FRAME::updateNetlistExporter()
|
||||
{
|
||||
m_exporter.reset( new NETLIST_EXPORTER_PSPICE_SIM( &m_schematicFrame->Schematic() ) );
|
||||
|
||||
if( m_settingsDlg )
|
||||
m_settingsDlg->SetNetlistExporter( m_exporter.get() );
|
||||
}
|
||||
@@ -668,31 +705,28 @@ bool SIM_PLOT_FRAME::updatePlot( const TRACE_DESC& aDescriptor, SIM_PLOT_PANEL*
|
||||
// Now, Y axis data
|
||||
switch( m_exporter->GetSimType() )
|
||||
{
|
||||
case ST_AC:
|
||||
{
|
||||
wxASSERT_MSG( !( ( plotType & SPT_AC_MAG ) && ( plotType & SPT_AC_PHASE ) ),
|
||||
"Cannot set both AC_PHASE and AC_MAG bits" );
|
||||
case ST_AC:
|
||||
wxASSERT_MSG( !( ( plotType & SPT_AC_MAG ) && ( plotType & SPT_AC_PHASE ) ),
|
||||
"Cannot set both AC_PHASE and AC_MAG bits" );
|
||||
|
||||
if( plotType & SPT_AC_MAG )
|
||||
data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
|
||||
else if( plotType & SPT_AC_PHASE )
|
||||
data_y = m_simulator->GetPhasePlot( (const char*) spiceVector.c_str() );
|
||||
else
|
||||
wxASSERT_MSG( false, "Plot type missing AC_PHASE or AC_MAG bit" );
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_NOISE:
|
||||
case ST_DC:
|
||||
case ST_TRANSIENT:
|
||||
{
|
||||
if( plotType & SPT_AC_MAG )
|
||||
data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
|
||||
}
|
||||
else if( plotType & SPT_AC_PHASE )
|
||||
data_y = m_simulator->GetPhasePlot( (const char*) spiceVector.c_str() );
|
||||
else
|
||||
wxASSERT_MSG( false, "Plot type missing AC_PHASE or AC_MAG bit" );
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
wxASSERT_MSG( false, "Unhandled plot type" );
|
||||
return false;
|
||||
case ST_NOISE:
|
||||
case ST_DC:
|
||||
case ST_TRANSIENT:
|
||||
data_y = m_simulator->GetMagPlot( (const char*) spiceVector.c_str() );
|
||||
break;
|
||||
|
||||
default:
|
||||
wxASSERT_MSG( false, "Unhandled plot type" );
|
||||
return false;
|
||||
}
|
||||
|
||||
if( data_y.size() != size )
|
||||
@@ -1177,7 +1211,7 @@ void SIM_PLOT_FRAME::menuWhiteBackground( wxCommandEvent& event )
|
||||
if( curPage == m_welcomePanel )
|
||||
continue;
|
||||
|
||||
// ensure it is truely a plot panel and not the (zero plots) placeholder
|
||||
// ensure it is truly a plot panel and not the (zero plots) placeholder
|
||||
// which is only SIM_PLOT_PANEL_BASE
|
||||
SIM_PLOT_PANEL* panel = dynamic_cast<SIM_PLOT_PANEL*>( curPage );
|
||||
|
||||
@@ -1256,7 +1290,7 @@ void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
|
||||
SIM_PANEL_BASE* plotPanelWindow = currentPlotWindow();
|
||||
|
||||
if( !m_settingsDlg )
|
||||
m_settingsDlg = new DIALOG_SIM_SETTINGS( this );
|
||||
m_settingsDlg = new DIALOG_SIM_SETTINGS( this, m_simulator->Settings() );
|
||||
|
||||
// Initial processing is required to e.g. display a list of power sources
|
||||
updateNetlistExporter();
|
||||
@@ -1277,7 +1311,8 @@ void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
|
||||
SIM_TYPE newSimType = NETLIST_EXPORTER_PSPICE_SIM::CommandToSimType( newCommand );
|
||||
|
||||
// If it is a new simulation type, open a new plot
|
||||
// For the DC sim, check if sweep source type has changed (char 4 will contain 'v', 'i', 'r' or 't'
|
||||
// For the DC sim, check if sweep source type has changed (char 4 will contain 'v',
|
||||
// 'i', 'r' or 't'.
|
||||
if( !plotPanelWindow
|
||||
|| ( plotPanelWindow && plotPanelWindow->GetType() != newSimType )
|
||||
|| ( newSimType == ST_DC
|
||||
@@ -1287,6 +1322,7 @@ void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
|
||||
}
|
||||
|
||||
m_plots[plotPanelWindow].m_simCommand = newCommand;
|
||||
m_simulator->Init();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1325,6 +1361,7 @@ void SIM_PLOT_FRAME::onTune( wxCommandEvent& event )
|
||||
m_schematicFrame->Raise();
|
||||
}
|
||||
|
||||
|
||||
void SIM_PLOT_FRAME::onShowNetlist( wxCommandEvent& event )
|
||||
{
|
||||
class NETLIST_VIEW_DIALOG : public DIALOG_SHIM
|
||||
@@ -1369,7 +1406,7 @@ void SIM_PLOT_FRAME::onShowNetlist( wxCommandEvent& event )
|
||||
SetSizer( sizer );
|
||||
|
||||
Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( NETLIST_VIEW_DIALOG::onClose ), NULL,
|
||||
this );
|
||||
this );
|
||||
|
||||
finishDialogSettings();
|
||||
}
|
||||
@@ -1411,7 +1448,8 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
|
||||
|
||||
// Fill the signals listctrl
|
||||
m_cursors->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x / 2 );
|
||||
const long X_COL = m_cursors->AppendColumn( plotPanel->GetLabelX(), wxLIST_FORMAT_LEFT, size.x / 4 );
|
||||
const long X_COL = m_cursors->AppendColumn( plotPanel->GetLabelX(), wxLIST_FORMAT_LEFT,
|
||||
size.x / 4 );
|
||||
|
||||
wxString labelY1 = plotPanel->GetLabelY1();
|
||||
wxString labelY2 = plotPanel->GetLabelY2();
|
||||
@@ -1570,7 +1608,8 @@ SIM_PLOT_FRAME::SIGNAL_CONTEXT_MENU::SIGNAL_CONTEXT_MENU( const wxString& aSigna
|
||||
else
|
||||
AddMenuItem( this, SHOW_CURSOR, _( "Show Cursor" ), KiBitmap( BITMAPS::pcb_target ) );
|
||||
|
||||
Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( SIGNAL_CONTEXT_MENU::onMenuEvent ), NULL, this );
|
||||
Connect( wxEVT_COMMAND_MENU_SELECTED, wxMenuEventHandler( SIGNAL_CONTEXT_MENU::onMenuEvent ),
|
||||
NULL, this );
|
||||
}
|
||||
|
||||
|
||||
@@ -1580,20 +1619,21 @@ void SIM_PLOT_FRAME::SIGNAL_CONTEXT_MENU::onMenuEvent( wxMenuEvent& aEvent )
|
||||
|
||||
switch( aEvent.GetId() )
|
||||
{
|
||||
case HIDE_SIGNAL:
|
||||
m_plotFrame->removePlot( m_signal );
|
||||
break;
|
||||
case HIDE_SIGNAL:
|
||||
m_plotFrame->removePlot( m_signal );
|
||||
break;
|
||||
|
||||
case SHOW_CURSOR:
|
||||
plot->EnableCursor( m_signal, true );
|
||||
break;
|
||||
case SHOW_CURSOR:
|
||||
plot->EnableCursor( m_signal, true );
|
||||
break;
|
||||
|
||||
case HIDE_CURSOR:
|
||||
plot->EnableCursor( m_signal, false );
|
||||
break;
|
||||
case HIDE_CURSOR:
|
||||
plot->EnableCursor( m_signal, false );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
wxDEFINE_EVENT( EVT_SIM_UPDATE, wxCommandEvent );
|
||||
wxDEFINE_EVENT( EVT_SIM_REPORT, wxCommandEvent );
|
||||
|
||||
|
||||
Reference in New Issue
Block a user