New type of simulation opens a new plot
This commit is contained in:
parent
fe92630f16
commit
e90fcaa6d9
|
@ -83,8 +83,6 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
|
|||
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 );
|
||||
|
||||
NewPlotPanel();
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,9 +119,9 @@ void SIM_PLOT_FRAME::StopSimulation()
|
|||
}
|
||||
|
||||
|
||||
void SIM_PLOT_FRAME::NewPlotPanel()
|
||||
void SIM_PLOT_FRAME::NewPlotPanel( SIM_TYPE aSimType )
|
||||
{
|
||||
SIM_PLOT_PANEL* plot = new SIM_PLOT_PANEL( m_plotNotebook, wxID_ANY );
|
||||
SIM_PLOT_PANEL* plot = new SIM_PLOT_PANEL( aSimType, m_plotNotebook, wxID_ANY );
|
||||
|
||||
m_plotNotebook->AddPage( plot,
|
||||
wxString::Format( wxT( "Plot%lu" ), m_plotNotebook->GetPageCount() + 1 ), true );
|
||||
|
@ -140,6 +138,7 @@ void SIM_PLOT_FRAME::AddVoltagePlot( const wxString& aNetName )
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
SIM_PLOT_PANEL* SIM_PLOT_FRAME::CurrentPlot() const
|
||||
{
|
||||
return static_cast<SIM_PLOT_PANEL*>( m_plotNotebook->GetCurrentPage() );
|
||||
|
@ -161,13 +160,71 @@ void SIM_PLOT_FRAME::updateNetlistExporter()
|
|||
|
||||
void SIM_PLOT_FRAME::updatePlot( const wxString& aSpiceName, const wxString& aName, SIM_PLOT_PANEL* aPanel )
|
||||
{
|
||||
auto data_y = m_simulator->GetPlot( (const char*) aSpiceName.c_str() );
|
||||
auto data_t = m_simulator->GetPlot( "time" );
|
||||
// First, handle the x axis
|
||||
wxString xAxisName;
|
||||
SIM_TYPE simType = m_exporter->GetSimType();
|
||||
|
||||
if( data_y.empty() || data_t.empty() )
|
||||
if( !SIM_PLOT_PANEL::IsPlottable( simType ) )
|
||||
{
|
||||
// There is no plot to be shown
|
||||
m_simulator->Command( wxString::Format( "print %s", aSpiceName ).ToStdString() );
|
||||
return;
|
||||
}
|
||||
|
||||
switch( simType )
|
||||
{
|
||||
/// @todo x axis names should be moved to simulator iface, so they are not hardcoded for ngspice
|
||||
case ST_AC:
|
||||
case ST_NOISE:
|
||||
xAxisName = "frequency";
|
||||
break;
|
||||
|
||||
case ST_DC:
|
||||
xAxisName = "v-sweep";
|
||||
break;
|
||||
|
||||
case ST_TRANSIENT:
|
||||
xAxisName = "time";
|
||||
break;
|
||||
|
||||
case ST_OP:
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
auto data_x = m_simulator->GetMagPlot( (const char*) xAxisName.c_str() );
|
||||
int size = data_x.size();
|
||||
|
||||
if( data_x.empty() )
|
||||
return;
|
||||
|
||||
aPanel->AddTrace( aSpiceName, aName, data_t.size(), data_t.data(), data_y.data(), 0 );
|
||||
// Now, Y axis data
|
||||
switch( m_exporter->GetSimType() )
|
||||
{
|
||||
/// @todo x axis names should be moved to simulator iface
|
||||
case ST_AC:
|
||||
{
|
||||
auto data_mag = m_simulator->GetMagPlot( (const char*) aSpiceName.c_str() );
|
||||
auto data_phase = m_simulator->GetPhasePlot( (const char*) aSpiceName.c_str() );
|
||||
aPanel->AddTrace( aSpiceName, aName + " (mag)", size, data_x.data(), data_mag.data(), 0 );
|
||||
aPanel->AddTrace( aSpiceName, aName + " (phase)", size, data_x.data(), data_phase.data(), 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
case ST_NOISE:
|
||||
case ST_DC:
|
||||
case ST_TRANSIENT:
|
||||
{
|
||||
auto data_y = m_simulator->GetMagPlot( (const char*) aSpiceName.c_str() );
|
||||
aPanel->AddTrace( aSpiceName, aName, size, data_x.data(), data_y.data(), 0 );
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -186,10 +243,22 @@ int SIM_PLOT_FRAME::getNodeNumber( const wxString& aNetName )
|
|||
}
|
||||
|
||||
|
||||
void SIM_PLOT_FRAME::menuNewPlot( wxCommandEvent& aEvent )
|
||||
{
|
||||
if( m_exporter )
|
||||
{
|
||||
SIM_TYPE type = m_exporter->GetSimType();
|
||||
|
||||
if( SIM_PLOT_PANEL::IsPlottable( type ) )
|
||||
NewPlotPanel( type );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SIM_PLOT_FRAME::menuSaveImage( wxCommandEvent& event )
|
||||
{
|
||||
wxFileDialog saveDlg( this, wxT( "Save plot as image" ), "", "",
|
||||
"PNG file (*.png)|*.png", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
||||
"PNG file (*.png)|*.png", wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
||||
|
||||
if( saveDlg.ShowModal() == wxID_CANCEL )
|
||||
return;
|
||||
|
@ -203,7 +272,7 @@ void SIM_PLOT_FRAME::menuSaveCsv( wxCommandEvent& event )
|
|||
const wxChar SEPARATOR = ';';
|
||||
|
||||
wxFileDialog saveDlg( this, wxT( "Save plot data" ), "", "",
|
||||
"CSV file (*.csv)|*.csv", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
|
||||
"CSV file (*.csv)|*.csv", wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
||||
|
||||
if( saveDlg.ShowModal() == wxID_CANCEL )
|
||||
return;
|
||||
|
@ -308,6 +377,14 @@ void SIM_PLOT_FRAME::onSignalDblClick( wxCommandEvent& event )
|
|||
{
|
||||
int idx = m_signals->GetSelection();
|
||||
SIM_PLOT_PANEL* plot = CurrentPlot();
|
||||
SIM_TYPE simType = m_exporter->GetSimType();
|
||||
|
||||
// Create a new plot if the current one displays a different type
|
||||
if( SIM_PLOT_PANEL::IsPlottable( simType ) && ( plot == nullptr || plot->GetType() != simType ) )
|
||||
{
|
||||
NewPlotPanel( simType );
|
||||
plot = CurrentPlot();
|
||||
}
|
||||
|
||||
if( idx != wxNOT_FOUND )
|
||||
{
|
||||
|
@ -388,7 +465,7 @@ void SIM_PLOT_FRAME::onCursorUpdate( wxCommandEvent& event )
|
|||
|
||||
const long SIGNAL_COL = m_cursors->AppendColumn( wxT( "Signal" ), wxLIST_FORMAT_LEFT, size.x / 2 );
|
||||
const long X_COL = m_cursors->AppendColumn( CurrentPlot()->GetLabelX(), wxLIST_FORMAT_LEFT, size.x / 4 );
|
||||
const long Y_COL = m_cursors->AppendColumn( CurrentPlot()->GetLabelY(), wxLIST_FORMAT_LEFT, size.x / 4 );
|
||||
const long Y_COL = m_cursors->AppendColumn( CurrentPlot()->GetLabelY1(), wxLIST_FORMAT_LEFT, size.x / 4 );
|
||||
|
||||
// Update cursor values
|
||||
for( const auto& trace : CurrentPlot()->GetTraces() )
|
||||
|
@ -416,6 +493,8 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
|
|||
m_simulateBtn->SetLabel( wxT( "Simulate" ) );
|
||||
SetCursor( wxCURSOR_ARROW );
|
||||
|
||||
SIM_TYPE simType = m_exporter->GetSimType();
|
||||
|
||||
// Fill the signals listbox
|
||||
m_signals->Clear();
|
||||
|
||||
|
@ -426,12 +505,28 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
|
|||
}
|
||||
|
||||
// If there are any signals plotted, update them
|
||||
SIM_PLOT_PANEL* plotPanel = CurrentPlot();
|
||||
if( SIM_PLOT_PANEL::IsPlottable( simType ) )
|
||||
{
|
||||
SIM_PLOT_PANEL* plotPanel = CurrentPlot();
|
||||
|
||||
for( const auto& trace : plotPanel->GetTraces() )
|
||||
updatePlot( trace.second->GetSpiceName(), trace.second->GetName(), plotPanel );
|
||||
if( plotPanel == nullptr )
|
||||
return;
|
||||
|
||||
plotPanel->UpdateAll();
|
||||
for( const auto& trace : plotPanel->GetTraces() )
|
||||
updatePlot( trace.second->GetSpiceName(), trace.second->GetName(), plotPanel );
|
||||
|
||||
plotPanel->UpdateAll();
|
||||
}
|
||||
else
|
||||
{
|
||||
/// @todo do not make it hardcoded for ngspice
|
||||
for( const auto& net : m_exporter->GetNetIndexMap() )
|
||||
{
|
||||
int node = net.second;
|
||||
if( node > 0 )
|
||||
m_simulator->Command( wxString::Format( "print v(%d)", node ).ToStdString() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
@file Subclass of SIM_PLOT_FRAME_BASE, which is generated by wxFormBuilder. */
|
||||
|
||||
#include "sim_plot_frame_base.h"
|
||||
#include "sim_types.h"
|
||||
#include "kiway_player.h"
|
||||
#include <netlist_exporters/netlist_exporter_pspice.h>
|
||||
#include <dialogs/dialog_sim_settings.h>
|
||||
|
@ -56,7 +57,7 @@ class SIM_PLOT_FRAME : public SIM_PLOT_FRAME_BASE
|
|||
void StartSimulation();
|
||||
void StopSimulation();
|
||||
|
||||
void NewPlotPanel();
|
||||
void NewPlotPanel( SIM_TYPE aSimType );
|
||||
void AddVoltagePlot( const wxString& aNetName );
|
||||
|
||||
SIM_PLOT_PANEL* CurrentPlot() const;
|
||||
|
@ -84,17 +85,13 @@ class SIM_PLOT_FRAME : public SIM_PLOT_FRAME_BASE
|
|||
int getNodeNumber( const wxString& aNetName );
|
||||
|
||||
// Menu handlers
|
||||
void menuNewPlot( wxCommandEvent& aEvent ) override
|
||||
{
|
||||
NewPlotPanel();
|
||||
}
|
||||
void menuNewPlot( wxCommandEvent& aEvent ) override;
|
||||
|
||||
void menuExit( wxCommandEvent& event ) override
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
// Event handlers
|
||||
void menuSaveImage( wxCommandEvent& event ) override;
|
||||
void menuSaveCsv( wxCommandEvent& event ) override;
|
||||
void menuZoomIn( wxCommandEvent& event ) override;
|
||||
|
@ -107,6 +104,7 @@ class SIM_PLOT_FRAME : public SIM_PLOT_FRAME_BASE
|
|||
void menuShowCoords( wxCommandEvent& event ) override;
|
||||
void menuShowCoordsUpdate( wxUpdateUIEvent& event ) override;
|
||||
|
||||
// Event handlers
|
||||
void onPlotChanged( wxNotebookEvent& event ) override;
|
||||
|
||||
void onSignalDblClick( wxCommandEvent& event ) override;
|
||||
|
|
|
@ -95,17 +95,58 @@ void CURSOR::Plot( wxDC& aDC, mpWindow& aWindow )
|
|||
}
|
||||
|
||||
|
||||
SIM_PLOT_PANEL::SIM_PLOT_PANEL( wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
||||
SIM_PLOT_PANEL::SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, wxWindowID id, const wxPoint& pos,
|
||||
const wxSize& size, long style, const wxString& name )
|
||||
: mpWindow( parent, id, pos, size, style ), m_colorIdx( 0 )
|
||||
: mpWindow( parent, id, pos, size, style ), m_colorIdx( 0 ),
|
||||
m_axis_x( nullptr ), m_axis_y1( nullptr ), m_axis_y2( nullptr ), m_type( aType )
|
||||
{
|
||||
m_axis_x = new mpScaleX( wxT( "T [s]" ) );
|
||||
m_axis_x->SetTicks( false );
|
||||
AddLayer( m_axis_x );
|
||||
SetMargins( 10, 10, 10, 10 );
|
||||
|
||||
m_axis_y = new mpScaleY( wxT( "U [V]" ) );
|
||||
m_axis_y->SetTicks( false );
|
||||
AddLayer( m_axis_y );
|
||||
switch( m_type )
|
||||
{
|
||||
case ST_AC:
|
||||
m_axis_x = new mpScaleX( wxT( "frequency [Hz]" ), mpALIGN_BORDER_BOTTOM );
|
||||
m_axis_y1 = new mpScaleY( wxT( "magnitude [V]" ), mpALIGN_BORDER_LEFT );
|
||||
m_axis_y2 = new mpScaleY( wxT( "phase [rad]" ), mpALIGN_BORDER_RIGHT );
|
||||
break;
|
||||
|
||||
case ST_DC:
|
||||
m_axis_x = new mpScaleX( wxT( "voltage [V]" ), mpALIGN_BORDER_BOTTOM );
|
||||
m_axis_y1 = new mpScaleY( wxT( "voltage [V]" ), mpALIGN_BORDER_LEFT );
|
||||
break;
|
||||
|
||||
case ST_NOISE:
|
||||
m_axis_x = new mpScaleX( wxT( "frequency [Hz]" ), mpALIGN_BORDER_BOTTOM );
|
||||
m_axis_y1 = new mpScaleY( wxT( "noise [(V or A)^2/Hz]" ), mpALIGN_BORDER_LEFT );
|
||||
break;
|
||||
|
||||
case ST_TRANSIENT:
|
||||
m_axis_x = new mpScaleX( wxT( "time [s]" ), mpALIGN_BORDER_BOTTOM );
|
||||
m_axis_y1 = new mpScaleY( wxT( "voltage [V]" ), mpALIGN_BORDER_LEFT );
|
||||
break;
|
||||
|
||||
default:
|
||||
// suppress warnings
|
||||
break;
|
||||
}
|
||||
|
||||
if( m_axis_x )
|
||||
{
|
||||
m_axis_x->SetTicks( false );
|
||||
AddLayer( m_axis_x );
|
||||
}
|
||||
|
||||
if( m_axis_y1 )
|
||||
{
|
||||
m_axis_y1->SetTicks( false );
|
||||
AddLayer( m_axis_y1 );
|
||||
}
|
||||
|
||||
if( m_axis_y2 )
|
||||
{
|
||||
m_axis_y2->SetTicks( false );
|
||||
AddLayer( m_axis_y2 );
|
||||
}
|
||||
|
||||
m_coords = new mpInfoCoords( wxRect( 0, 0, 100, 40 ), wxWHITE_BRUSH );
|
||||
AddLayer( m_coords );
|
||||
|
@ -123,6 +164,21 @@ SIM_PLOT_PANEL::~SIM_PLOT_PANEL()
|
|||
}
|
||||
|
||||
|
||||
bool SIM_PLOT_PANEL::IsPlottable( SIM_TYPE aSimType )
|
||||
{
|
||||
switch( aSimType )
|
||||
{
|
||||
case ST_AC:
|
||||
case ST_DC:
|
||||
case ST_TRANSIENT:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SIM_PLOT_PANEL::AddTrace( const wxString& aSpiceName, const wxString& aName, int aPoints,
|
||||
const double* aT, const double* aY, int aFlags )
|
||||
{
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#include <widgets/mathplot.h>
|
||||
#include <map>
|
||||
#include "sim_types.h"
|
||||
|
||||
class TRACE;
|
||||
|
||||
|
@ -143,19 +144,31 @@ private:
|
|||
class SIM_PLOT_PANEL : public mpWindow
|
||||
{
|
||||
public:
|
||||
SIM_PLOT_PANEL( wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition,
|
||||
SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, wxWindowID id, const wxPoint& pos = wxDefaultPosition,
|
||||
const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxPanelNameStr );
|
||||
|
||||
~SIM_PLOT_PANEL();
|
||||
|
||||
const wxString& GetLabelX() const
|
||||
SIM_TYPE GetType() const
|
||||
{
|
||||
return m_axis_x->GetName();
|
||||
return m_type;
|
||||
}
|
||||
|
||||
const wxString& GetLabelY() const
|
||||
static bool IsPlottable( SIM_TYPE aSimType );
|
||||
|
||||
wxString GetLabelX() const
|
||||
{
|
||||
return m_axis_y->GetName();
|
||||
return m_axis_x ? m_axis_x->GetName() : "";
|
||||
}
|
||||
|
||||
wxString GetLabelY1() const
|
||||
{
|
||||
return m_axis_y1 ? m_axis_y1->GetName() : "";
|
||||
}
|
||||
|
||||
wxString GetLabelY2() const
|
||||
{
|
||||
return m_axis_y2 ? m_axis_y2->GetName() : "";
|
||||
}
|
||||
|
||||
bool AddTrace( const wxString& aSpiceName, const wxString& aName, int aPoints,
|
||||
|
@ -185,13 +198,14 @@ public:
|
|||
void ShowGrid( bool aEnable )
|
||||
{
|
||||
m_axis_x->SetTicks( !aEnable );
|
||||
m_axis_y->SetTicks( !aEnable );
|
||||
m_axis_y1->SetTicks( !aEnable );
|
||||
m_axis_y2->SetTicks( !aEnable );
|
||||
UpdateAll();
|
||||
}
|
||||
|
||||
bool IsGridShown() const
|
||||
{
|
||||
assert( m_axis_x->GetTicks() == m_axis_y->GetTicks() );
|
||||
assert( m_axis_x->GetTicks() == m_axis_y1->GetTicks() );
|
||||
return !m_axis_x->GetTicks();
|
||||
}
|
||||
|
||||
|
@ -230,11 +244,14 @@ private:
|
|||
std::map<wxString, TRACE*> m_traces;
|
||||
|
||||
mpScaleX* m_axis_x;
|
||||
mpScaleY* m_axis_y;
|
||||
mpScaleY* m_axis_y1;
|
||||
mpScaleY* m_axis_y2;
|
||||
mpInfoLegend* m_legend;
|
||||
mpInfoCoords* m_coords;
|
||||
|
||||
std::vector<mpLayer*> m_topLevel;
|
||||
|
||||
const SIM_TYPE m_type;
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT( EVT_SIM_CURSOR_UPDATE, wxCommandEvent );
|
||||
|
|
Loading…
Reference in New Issue