Simulator code formatting and clean up

This commit is contained in:
Maciej Suminski 2016-08-11 14:42:17 +02:00
parent 957c6ec417
commit eeeb3e0a9a
13 changed files with 443 additions and 299 deletions

View File

@ -44,8 +44,6 @@ wxString NETLIST_EXPORTER_PSPICE_SIM::GetSpiceVector( const wxString& aName, SIM
return wxString::Format( "V(%d)", it->second );
}
/// @todo check is Lower() is required
else if( aType & SPT_CURRENT )
{
return wxString::Format( "@%s[%s]", GetSpiceDevice( aName ).Lower(),
@ -183,5 +181,4 @@ void NETLIST_EXPORTER_PSPICE_SIM::writeDirectives( OUTPUTFORMATTER* aFormatter,
// Finish with our custom simulation command
aFormatter->Print( 0, "%s\n", (const char*) m_simCommand.c_str() );
}
}

View File

@ -64,30 +64,53 @@ public:
*/
static const std::vector<wxString>& GetCurrents( SPICE_PRIMITIVE aPrimitive );
/**
* @brief Overrides the simulation command directive.
*/
void SetSimCommand( const wxString& aCmd )
{
m_simCommand = aCmd;
}
/**
* @brief Returns the simulation command directive.
*/
const wxString& GetSimCommand() const
{
return m_simCommand;
}
/**
* @brief Clears the simulation command directive.
*/
void ClearSimCommand()
{
m_simCommand.Clear();
}
/**
* @brief Returns simulation type basing on the simulation command directives.
* Simulation directives set using SetSimCommand() have priority over the ones placed in
* schematic sheets.
*/
SIM_TYPE GetSimType();
/**
* @brief Returns simulation command directives placed in schematic sheets (if any).
*/
wxString GetSheetSimCommand();
/**
* @brief Determines if a directive is a simulation command.
*/
static bool IsSimCommand( const wxString& aCmd )
{
return CommandToSimType( aCmd ) != ST_UNKNOWN;
}
/**
* @brief Returns simulation type basing on a simulation command directive.
*/
static SIM_TYPE CommandToSimType( const wxString& aCmd );
protected:
@ -95,7 +118,7 @@ protected:
private:
///> Overridden simulation command
///> Custom simulation command (has priority over the schematic sheet simulation commands)
wxString m_simCommand;
};

View File

@ -52,7 +52,6 @@ NGSPICE::NGSPICE()
m_ngSpice_AllPlots = (ngSpice_AllPlots) m_dll->GetSymbol( "ngSpice_AllPlots" );
m_ngSpice_AllVecs = (ngSpice_AllVecs) m_dll->GetSymbol( "ngSpice_AllVecs" );
m_ngSpice_Running = (ngSpice_Running) m_dll->GetSymbol( "ngSpice_running" );
}
@ -243,7 +242,7 @@ bool NGSPICE::LoadNetlist( const string& aNetlist )
bool NGSPICE::Run()
{
setlocale( LC_ALL, "C" );
bool rv = Command( "bg_run" );
bool rv = Command( "bg_run" ); // bg_* commands execute in a separate thread
setlocale( LC_ALL, "" );
return rv;
}
@ -252,7 +251,7 @@ bool NGSPICE::Run()
bool NGSPICE::Stop()
{
setlocale( LC_ALL, "C" );
bool rv = Command( "bg_halt" );
bool rv = Command( "bg_halt" ); // bg_* commands execute in a separate thread
setlocale( LC_ALL, "" );
return rv;
}
@ -301,10 +300,11 @@ string NGSPICE::GetXAxis( SIM_TYPE aType ) const
return string( "" );
}
int NGSPICE::cbControlledExit ( int status, bool immediate, bool exit_upon_quit, int id, void *user )
int NGSPICE::cbControlledExit( int status, bool immediate, bool exit_upon_quit, int id, void* user )
{
printf("stat %d immed %d quit %d\n", status, !!immediate, !!exit_upon_quit);
return 0;
//printf("stat %d immed %d quit %d\n", status, !!immediate, !!exit_upon_quit);
return 0;
}

View File

@ -36,32 +36,54 @@ public:
NGSPICE();
virtual ~NGSPICE();
///> @copydoc SPICE_SIMULATOR::Init()
void Init() override;
///> @copydoc SPICE_SIMULATOR::LoadNetlist()
bool LoadNetlist( const std::string& aNetlist ) override;
///> @copydoc SPICE_SIMULATOR::Run()
bool Run() override;
///> @copydoc SPICE_SIMULATOR::Stop()
bool Stop() override;
///> @copydoc SPICE_SIMULATOR::IsRunning()
bool IsRunning() override;
///> @copydoc SPICE_SIMULATOR::Command()
bool Command( const std::string& aCmd ) override;
///> @copydoc SPICE_SIMULATOR::GetXAxis()
std::string GetXAxis( SIM_TYPE aType ) const override;
///> @copydoc SPICE_SIMULATOR::GetPlot()
std::vector<COMPLEX> GetPlot( const std::string& aName, int aMaxLen = -1 ) override;
///> @copydoc SPICE_SIMULATOR::GetRealPlot()
std::vector<double> GetRealPlot( const std::string& aName, int aMaxLen = -1 ) override;
///> @copydoc SPICE_SIMULATOR::GetImagPlot()
std::vector<double> GetImagPlot( const std::string& aName, int aMaxLen = -1 ) override;
///> @copydoc SPICE_SIMULATOR::GetMagPlot()
std::vector<double> GetMagPlot( const std::string& aName, int aMaxLen = -1 ) override;
///> @copydoc SPICE_SIMULATOR::GetPhasePlot()
std::vector<double> GetPhasePlot( const std::string& aName, int aMaxLen = -1 ) override;
private:
// ngspice library functions
typedef void (*ngSpice_Init)( SendChar*, SendStat*, ControlledExit*,
SendData*, SendInitData*, BGThreadRunning*, void* );
typedef int (*ngSpice_Circ)( char** circarray );
typedef int (*ngSpice_Command)( char* command );
typedef pvector_info (*ngGet_Vec_Info)( char* vecname );
typedef char** (*ngSpice_AllPlots)( void );
typedef char** (*ngSpice_AllVecs)( char* plotname );
typedef bool (*ngSpice_Running)( void );
// ngspice library functions
typedef int (*ngSpice_Circ)(char** circarray);
typedef int (*ngSpice_Command)(char* command);
typedef pvector_info (*ngGet_Vec_Info)(char* vecname);
typedef char** (*ngSpice_AllPlots)(void);
typedef char** (*ngSpice_AllVecs)(char* plotname);
typedef bool (*ngSpice_Running)(void);
///> Handles to DLL functions
ngSpice_Init m_ngSpice_Init;
ngSpice_Circ m_ngSpice_Circ;
ngSpice_Command m_ngSpice_Command;
@ -72,10 +94,11 @@ private:
wxDynamicLibrary* m_dll;
// Callback functions
static int cbSendChar( char* what, int id, void* user );
static int cbSendStat( char* what, int id, void* user );
static int cbBGThreadRunning( bool is_running, int id, void* user );
static int cbControlledExit ( int status, bool immediate, bool exit_upon_quit, int id, void *user );
static int cbControlledExit( int status, bool immediate, bool exit_upon_quit, int id, void* user );
void dump();
};

View File

@ -45,6 +45,7 @@ SIM_PLOT_TYPE operator|( SIM_PLOT_TYPE aFirst, SIM_PLOT_TYPE aSecond )
return (SIM_PLOT_TYPE) res;
}
class SIM_THREAD_REPORTER : public SPICE_REPORTER
{
public:
@ -117,11 +118,17 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
Connect( EVT_SIM_FINISHED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimFinished ), NULL, this );
Connect( EVT_SIM_CURSOR_UPDATE, wxCommandEventHandler( SIM_PLOT_FRAME::onCursorUpdate ), NULL, this );
m_toolSimulate = m_toolBar->AddTool( ID_SIM_RUN, _("Run/Stop Simulation"), KiBitmap( sim_run_xpm ), _("Run Simulation"), wxITEM_NORMAL );
m_toolAddSignals = m_toolBar->AddTool( ID_SIM_ADD_SIGNALS, _("Add Signals"), KiBitmap( sim_add_signal_xpm ), _("Add signals to plot"), wxITEM_NORMAL );
m_toolProbe = m_toolBar->AddTool( ID_SIM_PROBE, _("Probe"), KiBitmap( sim_probe_xpm ),_("Probe signals on the schematic"), wxITEM_NORMAL );
m_toolTune = m_toolBar->AddTool( ID_SIM_TUNE, _("Tune"), KiBitmap( sim_tune_xpm ), _("Tune component values"), wxITEM_NORMAL );
m_toolSettings = m_toolBar->AddTool( wxID_ANY, _("Settings"), KiBitmap( sim_settings_xpm ), _("Simulation settings"), wxITEM_NORMAL );
// Toolbar buttons
m_toolSimulate = m_toolBar->AddTool( ID_SIM_RUN, _( "Run/Stop Simulation" ),
KiBitmap( sim_run_xpm ), _( "Run Simulation" ), wxITEM_NORMAL );
m_toolAddSignals = m_toolBar->AddTool( ID_SIM_ADD_SIGNALS, _( "Add Signals" ),
KiBitmap( sim_add_signal_xpm ), _( "Add signals to plot" ), wxITEM_NORMAL );
m_toolProbe = m_toolBar->AddTool( ID_SIM_PROBE, _( "Probe" ),
KiBitmap( sim_probe_xpm ), _( "Probe signals on the schematic" ), wxITEM_NORMAL );
m_toolTune = m_toolBar->AddTool( ID_SIM_TUNE, _( "Tune" ),
KiBitmap( sim_tune_xpm ), _( "Tune component values" ), wxITEM_NORMAL );
m_toolSettings = m_toolBar->AddTool( wxID_ANY, _( "Settings" ),
KiBitmap( sim_settings_xpm ), _( "Simulation settings" ), wxITEM_NORMAL );
Connect( m_toolSimulate->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( SIM_PLOT_FRAME::onSimulate ), NULL, this );
Connect( m_toolAddSignals->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( SIM_PLOT_FRAME::onAddSignal ), NULL, this );
@ -129,6 +136,7 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
Connect( m_toolTune->GetId(), wxEVT_COMMAND_TOOL_CLICKED, wxCommandEventHandler( SIM_PLOT_FRAME::onTune ), NULL, this );
Connect( m_toolSettings->GetId(), wxEVT_COMMAND_TOOL_CLICKED, 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() );
@ -136,7 +144,7 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSettings, this, m_settings->GetId() );
m_toolBar->Realize();
m_plotNotebook->SetPageText(0, _("Welcome!") );
m_plotNotebook->SetPageText( 0, _( "Welcome!" ) );
}
@ -180,8 +188,6 @@ void SIM_PLOT_FRAME::StartSimulation()
updateTuners();
applyTuners();
m_simulator->Run();
Layout();
}
@ -746,21 +752,6 @@ void SIM_PLOT_FRAME::menuShowLegendUpdate( wxUpdateUIEvent& event )
event.Check( plot ? plot->IsLegendShown() : false );
}
#if 0
void SIM_PLOT_FRAME::menuShowCoords( wxCommandEvent& event )
{
SIM_PLOT_PANEL* plot = CurrentPlot();
plot->ShowCoords( !plot->IsCoordsShown() );
}
void SIM_PLOT_FRAME::menuShowCoordsUpdate( wxUpdateUIEvent& event )
{
SIM_PLOT_PANEL* plot = CurrentPlot();
event.Check( plot ? plot->IsCoordsShown() : false );
}
#endif
void SIM_PLOT_FRAME::onPlotClose( wxAuiNotebookEvent& event )
{

View File

@ -27,7 +27,8 @@
#define __sim_plot_frame__
/**
@file Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder. */
* @file Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder.
*/
#include "sim_plot_frame_base.h"
#include "sim_types.h"
@ -49,7 +50,7 @@ class NETLIST_EXPORTER_PSPICE_SIM;
class SIM_PLOT_PANEL;
class TUNER_SLIDER;
/// @todo description
///> Trace descriptor class
class TRACE_DESC
{
public:
@ -102,191 +103,218 @@ private:
/** Implementing SIM_PLOT_FRAME_BASE */
class SIM_PLOT_FRAME : public SIM_PLOT_FRAME_BASE
{
public:
/** Constructor */
SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent );
~SIM_PLOT_FRAME();
public:
/** Constructor */
SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent );
~SIM_PLOT_FRAME();
void StartSimulation();
void StopSimulation();
bool IsSimulationRunning();
void StartSimulation();
void StopSimulation();
bool IsSimulationRunning();
/**
* @brief Creates a new plot panel for a given simulation type and adds it to the main
* notebook.
* @param aSimType is requested simulation type.
* @return The new plot panel.
*/
SIM_PLOT_PANEL* NewPlotPanel( SIM_TYPE aSimType );
/**
* @brief Creates a new plot panel for a given simulation type and adds it to the main
* notebook.
* @param aSimType is requested simulation type.
* @return The new plot panel.
*/
SIM_PLOT_PANEL* NewPlotPanel( SIM_TYPE aSimType );
void AddVoltagePlot( const wxString& aNetName );
void AddCurrentPlot( const wxString& aDeviceName, const wxString& aParam );
/**
* @brief Adds a voltage plot for a given net name.
* @param aNetName is the net name for which a voltage plot should be created.
*/
void AddVoltagePlot( const wxString& aNetName );
void AddTuner( SCH_COMPONENT* aComponent );
void RemoveTuner( TUNER_SLIDER* aTuner, bool aErase = true );
/**
* @brief Adds a current plot for a particular device.
* @param aDeviceName is the device name (e.g. R1, C1).
* @param aParam is the current type (e.g. I, Ic, Id).
*/
void AddCurrentPlot( const wxString& aDeviceName, const wxString& aParam );
SIM_PLOT_PANEL* CurrentPlot() const;
/**
* @brief Adds a tuner for a component.
*/
void AddTuner( SCH_COMPONENT* aComponent );
private:
void relayout();
/**
* @brief Adds a new plot to the current panel.
* @param aName is the device/net name.
* @param aType describes the type of plot.
* @param aParam is the parameter for the device/net (e.g. I, Id, V).
*/
void addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam );
/**
* @brief Removes an existing tuner.
* @param aTuner is the tuner to be removed.
* @param aErase decides whether the tuner should be also removed from the tuners list.
* Otherwise it is removed only from the SIM_PLOT_FRAME pane.
*/
void RemoveTuner( TUNER_SLIDER* aTuner, bool aErase = true );
/**
* @brief Removes a plot with a specific title.
* @param aPlotName is the full plot title (e.g. I(Net-C1-Pad1)).
* @param aErase decides if plot should be removed from corresponding TRACE_MAP (see m_plots).
*/
void removePlot( const wxString& aPlotName, bool aErase = true );
/**
* @brief Returns the currently opened plot panel (or NULL if there is none).
*/
SIM_PLOT_PANEL* CurrentPlot() const;
void updateNetlistExporter();
private:
/**
* @brief Adds a new plot to the current panel.
* @param aName is the device/net name.
* @param aType describes the type of plot.
* @param aParam is the parameter for the device/net (e.g. I, Id, V).
*/
void addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam );
/**
* @brief Updates plot in a particular SIM_PLOT_PANEL. If the panel does not contain
* the plot, it will be added.
* @param aDescriptor contains the plot description.
* @param aPanel is the panel that should receive the update.
* @return True if a plot was successfully added/updated.
*/
bool updatePlot( const TRACE_DESC& aDescriptor, SIM_PLOT_PANEL* aPanel );
/**
* @brief Removes a plot with a specific title.
* @param aPlotName is the full plot title (e.g. I(Net-C1-Pad1)).
* @param aErase decides if plot should be removed from corresponding TRACE_MAP (see m_plots).
*/
void removePlot( const wxString& aPlotName, bool aErase = true );
/**
* @brief Updates the list of currently plotted signals.
*/
void updateSignalList();
/**
* @brief Reloads the current schematic for the netlist exporter.
*/
void updateNetlistExporter();
/**
* @brief Updates the cursor values list.
*/
void updateCursors();
/**
* @brief Updates plot in a particular SIM_PLOT_PANEL. If the panel does not contain
* the plot, it will be added.
* @param aDescriptor contains the plot description.
* @param aPanel is the panel that should receive the update.
* @return True if a plot was successfully added/updated.
*/
bool updatePlot( const TRACE_DESC& aDescriptor, SIM_PLOT_PANEL* aPanel );
/**
* @brief Filters out tuners for components that do not exist anymore.
* Decisions are based on the current NETLIST_EXPORTER data.
*/
void updateTuners();
/**
* @brief Updates the list of currently plotted signals.
*/
void updateSignalList();
/**
* @brief Applies component values specified using tunder sliders to the current netlist.
*/
void applyTuners();
/**
* @brief Updates the cursor values list.
*/
void updateCursors();
/**
* @brief Loads plot settings from a file.
* @param aPath is the file name.
* @return True if successful.
*/
bool loadWorkbook( const wxString& aPath );
/**
* @brief Filters out tuners for components that do not exist anymore.
* Decisions are based on the current NETLIST_EXPORTER data.
*/
void updateTuners();
/**
* @brief Saves plot settings to a file.
* @param aPath is the file name.
* @return True if successful.
*/
bool saveWorkbook( const wxString& aPath );
/**
* @brief Applies component values specified using tunder sliders to the current netlist.
*/
void applyTuners();
SIM_PLOT_TYPE GetXAxisType( SIM_TYPE aType ) const;
/**
* @brief Loads plot settings from a file.
* @param aPath is the file name.
* @return True if successful.
*/
bool loadWorkbook( const wxString& aPath );
// Menu handlers
void menuNewPlot( wxCommandEvent& aEvent ) override;
void menuOpenWorkbook( wxCommandEvent& event ) override;
void menuSaveWorkbook( wxCommandEvent& event ) override;
/**
* @brief Saves plot settings to a file.
* @param aPath is the file name.
* @return True if successful.
*/
bool saveWorkbook( const wxString& aPath );
void menuExit( wxCommandEvent& event ) override
{
Close();
}
/**
* @brief Returns X axis for a given simulation type.
*/
SIM_PLOT_TYPE GetXAxisType( SIM_TYPE aType ) const;
void menuSaveImage( wxCommandEvent& event ) override;
void menuSaveCsv( wxCommandEvent& event ) override;
void menuZoomIn( wxCommandEvent& event ) override;
void menuZoomOut( wxCommandEvent& event ) override;
void menuZoomFit( wxCommandEvent& event ) override;
void menuShowGrid( wxCommandEvent& event ) override;
void menuShowGridUpdate( wxUpdateUIEvent& event ) override;
void menuShowLegend( wxCommandEvent& event ) override;
void menuShowLegendUpdate( wxUpdateUIEvent& event ) override;
//void menuShowCoords( wxCommandEvent& event ) override;
//void menuShowCoordsUpdate( wxUpdateUIEvent& event ) override;
// Menu handlers
void menuNewPlot( wxCommandEvent& aEvent ) override;
void menuOpenWorkbook( wxCommandEvent& event ) override;
void menuSaveWorkbook( wxCommandEvent& event ) override;
// Event handlers
void onPlotChanged( wxAuiNotebookEvent& event ) override;
void onPlotClose( wxAuiNotebookEvent& event ) override;
void menuExit( wxCommandEvent& event ) override
{
Close();
}
void onSignalDblClick( wxCommandEvent& event ) override;
void onSignalRClick( wxMouseEvent& event ) override;
void menuSaveImage( wxCommandEvent& event ) override;
void menuSaveCsv( wxCommandEvent& event ) override;
void menuZoomIn( wxCommandEvent& event ) override;
void menuZoomOut( wxCommandEvent& event ) override;
void menuZoomFit( wxCommandEvent& event ) override;
void menuShowGrid( wxCommandEvent& event ) override;
void menuShowGridUpdate( wxUpdateUIEvent& event ) override;
void menuShowLegend( wxCommandEvent& event ) override;
void menuShowLegendUpdate( wxUpdateUIEvent& event ) override;
void onSimulate( wxCommandEvent& event );
void onSettings( wxCommandEvent& event );
void onAddSignal( wxCommandEvent& event );
void onProbe( wxCommandEvent& event );
void onTune( wxCommandEvent& event );
// Event handlers
void onPlotChanged( wxAuiNotebookEvent& event ) override;
void onPlotClose( wxAuiNotebookEvent& event ) override;
void onClose( wxCloseEvent& aEvent );
void onSignalDblClick( wxCommandEvent& event ) override;
void onSignalRClick( wxMouseEvent& event ) override;
void onCursorUpdate( wxCommandEvent& aEvent );
void onSimUpdate( wxCommandEvent& aEvent );
void onSimReport( wxCommandEvent& aEvent );
void onSimStarted( wxCommandEvent& aEvent );
void onSimFinished( wxCommandEvent& aEvent );
void onSimulate( wxCommandEvent& event );
void onSettings( wxCommandEvent& event );
void onAddSignal( wxCommandEvent& event );
void onProbe( wxCommandEvent& event );
void onTune( wxCommandEvent& event );
wxToolBarToolBase* m_toolSimulate;
wxToolBarToolBase* m_toolAddSignals;
wxToolBarToolBase* m_toolProbe;
wxToolBarToolBase* m_toolTune;
wxToolBarToolBase* m_toolSettings;
void onClose( wxCloseEvent& aEvent );
SCH_EDIT_FRAME* m_schematicFrame;
std::unique_ptr<NETLIST_EXPORTER_PSPICE_SIM> m_exporter;
std::unique_ptr<SPICE_SIMULATOR> m_simulator;
void onCursorUpdate( wxCommandEvent& aEvent );
void onSimUpdate( wxCommandEvent& aEvent );
void onSimReport( wxCommandEvent& aEvent );
void onSimStarted( wxCommandEvent& aEvent );
void onSimFinished( wxCommandEvent& aEvent );
typedef std::map<wxString, TRACE_DESC> TRACE_MAP;
// Toolbar buttons
wxToolBarToolBase* m_toolSimulate;
wxToolBarToolBase* m_toolAddSignals;
wxToolBarToolBase* m_toolProbe;
wxToolBarToolBase* m_toolTune;
wxToolBarToolBase* m_toolSettings;
struct PLOT_INFO
{
///> Map of the traces displayed on the plot
TRACE_MAP m_traces;
SCH_EDIT_FRAME* m_schematicFrame;
std::unique_ptr<NETLIST_EXPORTER_PSPICE_SIM> m_exporter;
std::unique_ptr<SPICE_SIMULATOR> m_simulator;
///> Spice directive used to execute the simulation
wxString m_simCommand;
};
typedef std::map<wxString, TRACE_DESC> TRACE_MAP;
///> Map of plot panels and associated data
std::map<SIM_PLOT_PANEL*, PLOT_INFO> m_plots;
struct PLOT_INFO
{
///> Map of the traces displayed on the plot
TRACE_MAP m_traces;
///> List of currently displayed tuners
std::list<TUNER_SLIDER*> m_tuners;
///> Spice directive used to execute the simulation
wxString m_simCommand;
};
// Trick to preserve settings between runs
DIALOG_SIM_SETTINGS m_settingsDlg;
///> Map of plot panels and associated data
std::map<SIM_PLOT_PANEL*, PLOT_INFO> m_plots;
// Right click context menu for signals in the listbox
class SIGNAL_CONTEXT_MENU : public wxMenu
{
public:
SIGNAL_CONTEXT_MENU( const wxString& aSignal, SIM_PLOT_FRAME* aPlotFrame );
///> List of currently displayed tuners
std::list<TUNER_SLIDER*> m_tuners;
private:
void onMenuEvent( wxMenuEvent& aEvent );
// Trick to preserve settings between runs
DIALOG_SIM_SETTINGS m_settingsDlg;
const wxString& m_signal;
SIM_PLOT_FRAME* m_plotFrame;
// Right click context menu for signals in the listbox
class SIGNAL_CONTEXT_MENU : public wxMenu
{
public:
SIGNAL_CONTEXT_MENU( const wxString& aSignal, SIM_PLOT_FRAME* aPlotFrame );
enum SIGNAL_CONTEXT_MENU_EVENTS
{
HIDE_SIGNAL,
SHOW_CURSOR,
HIDE_CURSOR
};
};
private:
void onMenuEvent( wxMenuEvent& aEvent );
///> Panel that was used as the most recent one for simulations
SIM_PLOT_PANEL* m_lastSimPlot;
const wxString& m_signal;
SIM_PLOT_FRAME* m_plotFrame;
enum SIGNAL_CONTEXT_MENU_EVENTS
{
HIDE_SIGNAL,
SHOW_CURSOR,
HIDE_CURSOR
};
};
///> Panel that was used as the most recent one for simulations
SIM_PLOT_PANEL* m_lastSimPlot;
};
// Commands

View File

@ -28,80 +28,88 @@
#include <algorithm>
#include <limits>
static wxString formatFloat (double x, int nDigits)
static wxString formatFloat( double x, int nDigits )
{
wxString rv, fmt;
if(nDigits)
if( nDigits )
{
fmt = wxT("%.0Nf");
fmt = wxT( "%.0Nf" );
fmt[3] = '0' + nDigits;
} else {
fmt = wxT("%.0f");
}
else
{
fmt = wxT( "%.0f" );
}
rv.Printf(fmt, x);
rv.Printf( fmt, x );
return rv;
}
static void getSISuffix ( double x, const wxString& unit, int& power, wxString& suffix )
static void getSISuffix( double x, const wxString& unit, int& power, wxString& suffix )
{
const int n_powers = 11;
const struct {
const struct
{
double exponent;
char suffix;
} powers[] = {
{-18,'a'},
{-15,'f'},
{-12,'p'},
{-9,'n'},
{-6,'u'},
{-3,'m'},
{0, 0},
{3, 'k'},
{6, 'M'},
{9, 'G'},
{12, 'T'},
{15, 'P'}
} powers[] =
{
{ -18, 'a' },
{ -15, 'f' },
{ -12, 'p' },
{ -9, 'n' },
{ -6, 'u' },
{ -3, 'm' },
{ 0, 0 },
{ 3, 'k' },
{ 6, 'M' },
{ 9, 'G' },
{ 12, 'T' },
{ 14, 'P' }
};
power = 0;
suffix = unit;
if (x == 0.0)
if( x == 0.0 )
return;
for ( int i = 0; i <n_powers - 1;i++)
for( int i = 0; i < n_powers - 1; i++ )
{
double r_cur = pow(10, powers[i].exponent);
double r_cur = pow( 10, powers[i].exponent );
if( fabs(x) >= r_cur && fabs(x) < r_cur * 1000.0 )
if( fabs( x ) >= r_cur && fabs( x ) < r_cur * 1000.0 )
{
power = powers[i].exponent;
if ( powers[i].suffix )
suffix = wxString(powers[i].suffix) + unit;
if( powers[i].suffix )
suffix = wxString( powers[i].suffix ) + unit;
else
suffix = unit;
return;
}
}
}
static int countDecimalDigits ( double x, int maxDigits )
static int countDecimalDigits( double x, int maxDigits )
{
int64_t k = (int) ( ( x - floor(x)) * pow ( 10.0, (double) maxDigits ));
int64_t k = (int)( ( x - floor( x ) ) * pow( 10.0, (double) maxDigits ) );
int n = 0;
while(k && ((k % 10LL) == 0LL || (k % 10LL) == 9LL))
while( k && ( ( k % 10LL ) == 0LL || ( k % 10LL ) == 9LL ) )
{
k /= 10LL;
}
n = 0;
while (k != 0LL)
while( k != 0LL )
{
n++;
k /= 10LL;
@ -111,64 +119,66 @@ static int countDecimalDigits ( double x, int maxDigits )
}
static void formatSILabels( mpScaleBase *scale, const wxString& aUnit, int nDigits )
static void formatSILabels( mpScaleBase* scale, const wxString& aUnit, int nDigits )
{
double maxVis = scale->AbsVisibleMaxValue();
wxString suffix;
int power, digits = 0;
getSISuffix( maxVis, aUnit, power, suffix);
getSISuffix( maxVis, aUnit, power, suffix );
double sf = pow(10.0, power);
double sf = pow( 10.0, power );
for ( auto &l : scale->TickLabels() )
for( auto &l : scale->TickLabels() )
{
int k = countDecimalDigits( l.pos / sf, nDigits );
digits = std::max(digits, k);
digits = std::max( digits, k );
}
for ( auto &l : scale->TickLabels() )
for( auto &l : scale->TickLabels() )
{
l.label = formatFloat ( l.pos / sf, digits ) + suffix;
l.visible = true;
}
}
class FREQUENCY_LOG_SCALE : public mpScaleXLog
{
public:
FREQUENCY_LOG_SCALE(wxString name, int flags) :
FREQUENCY_LOG_SCALE( wxString name, int flags ) :
mpScaleXLog( name, flags ) {};
void formatLabels()
{
const wxString unit = wxT("Hz");
const wxString unit = wxT( "Hz" );
wxString suffix;
int power;
for ( auto &l : TickLabels() )
for( auto &l : TickLabels() )
{
getSISuffix( l.pos, unit, power, suffix);
double sf = pow(10.0, power);
getSISuffix( l.pos, unit, power, suffix );
double sf = pow( 10.0, power );
int k = countDecimalDigits( l.pos / sf, 3 );
l.label = formatFloat ( l.pos / sf, k ) + suffix;
l.label = formatFloat( l.pos / sf, k ) + suffix;
l.visible = true;
}
}
};
class FREQUENCY_LIN_SCALE : public mpScaleX
{
public:
FREQUENCY_LIN_SCALE(wxString name, int flags) :
FREQUENCY_LIN_SCALE( wxString name, int flags ) :
mpScaleX( name, flags, false , 0 ) {};
void formatLabels()
{
formatSILabels( this, wxT("Hz"), 3 );
formatSILabels( this, wxT( "Hz" ), 3 );
}
};
@ -176,74 +186,78 @@ public:
class TIME_SCALE : public mpScaleX
{
public:
TIME_SCALE(wxString name, int flags) :
mpScaleX ( name, flags, false, 0) {};
TIME_SCALE( wxString name, int flags ) :
mpScaleX( name, flags, false, 0 ) {};
void formatLabels()
{
formatSILabels( this, wxT("s"), 3 );
formatSILabels( this, wxT( "s" ), 3 );
}
};
class VOLTAGE_SCALE_X : public mpScaleX
{
public:
VOLTAGE_SCALE_X(wxString name, int flags) :
mpScaleX ( name, flags, false, 0 ) {};
VOLTAGE_SCALE_X( wxString name, int flags ) :
mpScaleX( name, flags, false, 0 ) {};
void formatLabels()
{
formatSILabels( this, wxT("V"), 3 );
formatSILabels( this, wxT( "V" ), 3 );
}
};
class GAIN_SCALE : public mpScaleY
{
public:
GAIN_SCALE( wxString name, int flags ) :
mpScaleY ( name, flags, false) {};
mpScaleY( name, flags, false ) {};
void formatLabels()
{
formatSILabels( this, wxT("dB"), 3 );
formatSILabels( this, wxT( "dB" ), 3 );
}
};
class PHASE_SCALE : public mpScaleY
{
public:
PHASE_SCALE(wxString name, int flags) :
mpScaleY ( name, flags, false ) {};
PHASE_SCALE( wxString name, int flags ) :
mpScaleY( name, flags, false ) {};
void formatLabels()
{
formatSILabels( this, wxT("\u00B0"), 3 );
formatSILabels( this, wxT( "\u00B0" ), 3 ); // degree sign
}
};
class VOLTAGE_SCALE_Y : public mpScaleY
{
public:
VOLTAGE_SCALE_Y(wxString name, int flags) :
mpScaleY ( name, flags, false ) {};
VOLTAGE_SCALE_Y( wxString name, int flags ) :
mpScaleY( name, flags, false ) {};
void formatLabels()
{
formatSILabels( this, wxT("V"), 3 );
formatSILabels( this, wxT( "V" ), 3 );
}
};
class CURRENT_SCALE : public mpScaleY
{
public:
CURRENT_SCALE(wxString name, int flags ) :
mpScaleY ( name, flags, false ) {};
CURRENT_SCALE( wxString name, int flags ) :
mpScaleY( name, flags, false ) {};
void formatLabels()
{
formatSILabels( this, wxT("A"), 3 );
formatSILabels( this, wxT( "A" ), 3 );
}
};
@ -366,7 +380,7 @@ SIM_PLOT_PANEL::SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, wxWindowID id,
m_axis_x = new FREQUENCY_LOG_SCALE( wxT( "Frequency" ), mpALIGN_BOTTOM );
m_axis_y1 = new GAIN_SCALE( wxT( "Gain" ), mpALIGN_LEFT );
m_axis_y2 = new PHASE_SCALE( wxT( "Phase" ), mpALIGN_RIGHT );
m_axis_y2->SetMasterScale(m_axis_y1);
m_axis_y2->SetMasterScale( m_axis_y1 );
break;
case ST_DC:
@ -383,7 +397,7 @@ SIM_PLOT_PANEL::SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, wxWindowID id,
m_axis_x = new TIME_SCALE( wxT( "Time" ), mpALIGN_BOTTOM );
m_axis_y1 = new VOLTAGE_SCALE_Y( wxT( "Voltage" ), mpALIGN_LEFT );
m_axis_y2 = new CURRENT_SCALE( wxT( "Current" ), mpALIGN_RIGHT );
m_axis_y2->SetMasterScale(m_axis_y1);
m_axis_y2->SetMasterScale( m_axis_y1 );
break;
default:
@ -416,9 +430,9 @@ SIM_PLOT_PANEL::SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, wxWindowID id,
m_legend = new mpInfoLegend( wxRect( 0, 40, 200, 40 ), wxTRANSPARENT_BRUSH );
AddLayer( m_legend );
m_topLevel.push_back( m_legend );
SetColourTheme(*wxBLACK, *wxWHITE, grey);
SetColourTheme( *wxBLACK, *wxWHITE, grey );
EnableDoubleBuffer(true);
EnableDoubleBuffer( true );
UpdateAll();
}
@ -455,20 +469,20 @@ bool SIM_PLOT_PANEL::AddTrace( const wxString& aName, int aPoints,
if( addedNewEntry )
{
if ( m_type == ST_TRANSIENT )
if( m_type == ST_TRANSIENT )
{
bool hasVoltageTraces = false;
for( auto t : m_traces )
{
if ( ! (t.second->GetFlags() & SPT_CURRENT ) )
if( !( t.second->GetFlags() & SPT_CURRENT ) )
{
hasVoltageTraces = true;
break;
}
}
if ( !hasVoltageTraces )
if( !hasVoltageTraces )
m_axis_y2->SetMasterScale( nullptr );
else
m_axis_y2->SetMasterScale( m_axis_y1 );
@ -499,12 +513,12 @@ bool SIM_PLOT_PANEL::AddTrace( const wxString& aName, int aPoints,
{
if( aFlags & SPT_AC_PHASE )
{
for(int i = 0; i < aPoints; i++ )
for( int i = 0; i < aPoints; i++ )
tmp[i] = tmp[i] * 180.0 / M_PI; // convert to degrees
}
else
{
for(int i = 0; i < aPoints; i++ )
for( int i = 0; i < aPoints; i++ )
tmp[i] = 20 * log( tmp[i] ) / log( 10.0 ); // convert to dB
}
}
@ -553,6 +567,7 @@ void SIM_PLOT_PANEL::DeleteAllTraces()
DeleteTrace( t.first );
}
m_colorIdx = 0;
m_traces.clear();
}

View File

@ -32,6 +32,7 @@
class TRACE;
///> Cursor attached to a trace to follow its values:
class CURSOR : public mpInfoLayer
{
public:
@ -86,14 +87,18 @@ class TRACE : public mpFXYVector
{
public:
TRACE( const wxString& aName ) :
mpFXYVector( aName ), m_cursor( nullptr ), m_flags(0)
{
SetContinuity( true );
SetDrawOutsideMargins( false );
ShowName( false );
}
mpFXYVector( aName ), m_cursor( nullptr ), m_flags( 0 )
{
SetContinuity( true );
SetDrawOutsideMargins( false );
ShowName( false );
}
/**
* @brief Assigns new data set for the trace. aX and aY need to have the same length.
* @param aX are the X axis values.
* @param aY are the Y axis values.
*/
void SetData( const std::vector<double>& aX, const std::vector<double>& aY ) override
{
if( m_cursor )
@ -127,7 +132,7 @@ public:
return m_cursor;
}
void SetFlags ( int aFlags )
void SetFlags( int aFlags )
{
m_flags = aFlags;
}
@ -222,26 +227,20 @@ public:
return m_legend->IsVisible();
}
void ShowCoords( bool aEnable )
{
m_coords->SetVisible( aEnable );
UpdateAll();
}
bool IsCoordsShown() const
{
return m_coords->IsVisible();
}
///> Returns true if the trace has cursor shown.
bool HasCursorEnabled( const wxString& aName ) const;
///> Toggles cursor for a particular trace.
void EnableCursor( const wxString& aName, bool aEnable );
///> Resets scale ranges to fit the current traces
void ResetScales();
private:
///> Returns a new color from the palette
wxColour generateColor();
// Color index to get a new color from the palette
unsigned int m_colorIdx;
// Traces to be plotted
@ -251,7 +250,6 @@ private:
mpScaleY* m_axis_y1;
mpScaleY* m_axis_y2;
mpInfoLegend* m_legend;
mpInfoCoords* m_coords;
std::vector<mpLayer*> m_topLevel;

View File

@ -39,6 +39,7 @@ enum SIM_PLOT_TYPE {
SPT_AC_PHASE = 0x04,
SPT_AC_MAG = 0x08,
// X axis
SPT_TIME = 0x10,
SPT_LIN_FREQUENCY = 0x20,
SPT_LOG_FREQUENCY = 0x20,

View File

@ -1,11 +0,0 @@
#include <schframe.h>
void SCH_EDIT_FRAME::OnSimulationRun( wxCommandEvent& event )
{}
void SCH_EDIT_FRAME::OnSimulationStop( wxCommandEvent& event )
{}
void SCH_EDIT_FRAME::OnSimulationAddProbe( wxCommandEvent& event )
{}

View File

@ -41,31 +41,91 @@ public:
SPICE_SIMULATOR() : m_reporter( NULL ) {}
virtual ~SPICE_SIMULATOR() {}
///> Creates a simulator instance of particular type (currently only ngspice is handled)
static SPICE_SIMULATOR* CreateInstance( const std::string& aName );
///> Intializes the simulator
virtual void Init() = 0;
/*
* @brief Loads a netlist for the simulation.
* @return True in case of success, false otherwise.
*/
virtual bool LoadNetlist( const std::string& aNetlist ) = 0;
/**
* @brief Executes the simulation with currently loaded netlist.
* @return True in case of success, false otherwise.
*/
virtual bool Run() = 0;
/**
* @brief Halts the simulation.
* @return True in case of success, false otherwise.
*/
virtual bool Stop() = 0;
/**
* @brief Checks if simulation is running at the moment.
* @return True if simulation is currently executed.
*/
virtual bool IsRunning() = 0;
/**
* @brief Executes a Spice command as if it was typed into console.
* @param aCmd is the command to be issued.
*/
virtual bool Command( const std::string& aCmd ) = 0;
///> Returns X axis name for a given simulation type
virtual std::string GetXAxis( SIM_TYPE aType ) const = 0;
///> Sets a SPICE_REPORTER object to receive the simulation log.
virtual void SetReporter( SPICE_REPORTER* aReporter )
{
m_reporter = aReporter;
}
/**
* @brief Returns a requested vector with complex values. If the vector is real, then
* the imaginary part is set to 0 in all values.
* @param aName is the vector named in Spice convention (e.g. V(3), I(R1)).
* @return Requested vector. It might be empty if there is no vector with requested name.
*/
virtual std::vector<COMPLEX> GetPlot( const std::string& aName, int aMaxLen = -1 ) = 0;
/**
* @brief Returns a requested vector with real values. If the vector is complex, then
* the real part is returned.
* @param aName is the vector named in Spice convention (e.g. V(3), I(R1)).
* @return Requested vector. It might be empty if there is no vector with requested name.
*/
virtual std::vector<double> GetRealPlot( const std::string& aName, int aMaxLen = -1 ) = 0;
/**
* @brief Returns a requested vector with imaginary values. If the vector is complex, then
* the imaginary part is returned. If the vector is reql, then only zeroes are returned.
* @param aName is the vector named in Spice convention (e.g. V(3), I(R1)).
* @return Requested vector. It might be empty if there is no vector with requested name.
*/
virtual std::vector<double> GetImagPlot( const std::string& aName, int aMaxLen = -1 ) = 0;
/**
* @brief Returns a requested vector with magnitude values.
* @param aName is the vector named in Spice convention (e.g. V(3), I(R1)).
* @return Requested vector. It might be empty if there is no vector with requested name.
*/
virtual std::vector<double> GetMagPlot( const std::string& aName, int aMaxLen = -1 ) = 0;
/**
* @brief Returns a requested vector with phase values.
* @param aName is the vector named in Spice convention (e.g. V(3), I(R1)).
* @return Requested vector. It might be empty if there is no vector with requested name.
*/
virtual std::vector<double> GetPhasePlot( const std::string& aName, int aMaxLen = -1 ) = 0;
protected:
///> Reporter object to receive simulation log
SPICE_REPORTER* m_reporter;
};

View File

@ -221,13 +221,13 @@ SPICE_VALUE SPICE_VALUE::operator/( const SPICE_VALUE& aOther ) const
void SPICE_VALUE::stripZeros( wxString& aString )
{
if ( aString.Find(',') >= 0 || aString.Find('.') >= 0 )
if ( aString.Find( ',' ) >= 0 || aString.Find( '.' ) >= 0 )
{
while( aString.EndsWith( '0' ) )
aString.RemoveLast();
if( aString.EndsWith( '.' ) || aString.EndsWith( ',' ) )
aString.RemoveLast();
aString.RemoveLast();
}
}

View File

@ -51,6 +51,7 @@ public:
{
}
///> Parses the string to create a Spice value (e.g. 100n)
SPICE_VALUE( const wxString& aString );
SPICE_VALUE( int aInt, UNIT_PREFIX aPrefix = PFX_NONE )
@ -65,19 +66,35 @@ public:
Normalize();
}
/**
* @brief Normalizes the value. The unit prefix is picked so the base is (0.001 <= base < 1000).
*/
void Normalize();
double ToDouble() const;
/**
* @brief Returns string value as when converting double to string (e.g. 123456.789).
*/
wxString ToString() const;
/**
* @brief Returns string value in Spice format (e.g. 123.3456789k).
*/
wxString ToSpiceString() const;
/**
* @brief Returns either a normal string or Spice format string, depending on the original
* value format.
*/
wxString ToOrigString() const
{
return m_spiceStr ? ToSpiceString() : ToString();
}
/**
* Returns true if the object was initiated with a Spice formatted string value.
*/
bool IsSpiceString() const
{
return m_spiceStr;
@ -120,6 +137,7 @@ private:
///> Was the value defined using the Spice notation?
bool m_spiceStr;
///> Removes redundant zeros from the end of a string.
static void stripZeros( wxString& aString );
};
@ -141,6 +159,7 @@ public:
bool Validate( wxWindow* aParent ) override;
private:
///> Is it valid to get an empty value?
bool m_emptyAllowed;
};