Update simulation results as the sim runs.

Also adds a time axis which grows by 2X at a time rather than to the
size of the current data.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/11255
This commit is contained in:
Jeff Young 2023-06-18 16:23:38 +01:00
parent 9447c3d455
commit 9199d7a781
7 changed files with 89 additions and 42 deletions

View File

@ -2980,10 +2980,10 @@ void mpFXYVector::SetData( const std::vector<double>& xs, const std::vector<doub
} }
else else
{ {
m_minX = -1; m_minX = 0;
m_maxX = 1; m_maxX = 0;
m_minY = -1; m_minY = 0;
m_maxY = 1; m_maxY = 0;
} }
} }

View File

@ -170,6 +170,33 @@ private:
}; };
class TIME_SCALE : public LIN_SCALE<mpScaleX>
{
public:
TIME_SCALE( const wxString& name, const wxString& unit, int flags ) :
LIN_SCALE( name, unit, flags )
{};
void ExtendDataRange( double minV, double maxV ) override
{
if( !m_rangeSet )
{
m_minV = 0;
m_maxV = 0;
m_rangeSet = true;
}
else
{
if( minV < m_minV )
m_minV -= abs( maxV - minV );
if( maxV > m_maxV )
m_maxV += abs( maxV - minV );
}
}
};
template <typename parent> template <typename parent>
class LOG_SCALE : public parent class LOG_SCALE : public parent
{ {
@ -511,7 +538,7 @@ void SIM_PLOT_PANEL::updateAxes( int aNewTraceType )
case ST_TRANSIENT: case ST_TRANSIENT:
if( !m_axis_x ) if( !m_axis_x )
{ {
m_axis_x = new LIN_SCALE<mpScaleX>( wxEmptyString, wxT( "s" ), mpALIGN_BOTTOM ); m_axis_x = new TIME_SCALE( wxEmptyString, wxT( "s" ), mpALIGN_BOTTOM );
m_axis_x->SetNameAlign( mpALIGN_BOTTOM ); m_axis_x->SetNameAlign( mpALIGN_BOTTOM );
m_plotWin->AddLayer( m_axis_x ); m_plotWin->AddLayer( m_axis_x );
@ -793,7 +820,7 @@ void SIM_PLOT_PANEL::DeleteTrace( TRACE* aTrace )
} }
m_plotWin->DelLayer( aTrace, true, true ); m_plotWin->DelLayer( aTrace, true, true );
ResetScales(); ResetScales( false );
} }
@ -843,9 +870,9 @@ void SIM_PLOT_PANEL::EnableCursor( const wxString& aVectorName, int aType, int a
} }
void SIM_PLOT_PANEL::ResetScales() void SIM_PLOT_PANEL::ResetScales( bool aIncludeX )
{ {
if( m_axis_x ) if( m_axis_x && aIncludeX )
m_axis_x->ResetDataRange(); m_axis_x->ResetDataRange();
if( m_axis_y1 ) if( m_axis_y1 )

View File

@ -300,7 +300,7 @@ public:
const wxString& aSignalName ); const wxString& aSignalName );
///< Reset scale ranges to fit the current traces. ///< Reset scale ranges to fit the current traces.
void ResetScales(); void ResetScales( bool aIncludeX );
///< Update trace line style ///< Update trace line style
void UpdateTraceStyle( TRACE* trace ); void UpdateTraceStyle( TRACE* trace );

View File

@ -741,7 +741,7 @@ void SIMULATOR_FRAME::onSimFinished( wxCommandEvent& aEvent )
m_simFinished = true; m_simFinished = true;
m_panel->OnSimFinished(); m_panel->OnSimRefresh( true );
m_schematicFrame->RefreshOperatingPointDisplay(); m_schematicFrame->RefreshOperatingPointDisplay();
m_schematicFrame->GetCanvas()->Refresh(); m_schematicFrame->GetCanvas()->Refresh();
@ -765,8 +765,8 @@ void SIMULATOR_FRAME::onSimUpdate( wxCommandEvent& aEvent )
if( m_panel->GetCurrentPlotWindow() != m_lastSimPlot ) if( m_panel->GetCurrentPlotWindow() != m_lastSimPlot )
{ {
// We need to rerun simulation, as the simulator currently stores // We need to rerun simulation, as the simulator currently stores results for another
// results for another plot // plot
StartSimulation(); StartSimulation();
} }
else else

View File

@ -402,6 +402,10 @@ private:
}; };
#define ID_SIM_REFRESH 10207
#define REFRESH_INTERVAL 50 // 20 frames/second.
SIMULATOR_PANEL::SIMULATOR_PANEL( SIMULATOR_FRAME* aSimulatorFrame, SIMULATOR_PANEL::SIMULATOR_PANEL( SIMULATOR_FRAME* aSimulatorFrame,
SCH_EDIT_FRAME* aSchematicFrame ) : SCH_EDIT_FRAME* aSchematicFrame ) :
SIMULATOR_PANEL_BASE( aSimulatorFrame ), SIMULATOR_PANEL_BASE( aSimulatorFrame ),
@ -409,7 +413,8 @@ SIMULATOR_PANEL::SIMULATOR_PANEL( SIMULATOR_FRAME* aSimulatorFrame,
m_simulatorFrame( aSimulatorFrame ), m_simulatorFrame( aSimulatorFrame ),
m_schematicFrame( aSchematicFrame ), m_schematicFrame( aSchematicFrame ),
m_darkMode( true ), m_darkMode( true ),
m_plotNumber( 0 ) m_plotNumber( 0 ),
m_refreshTimer( this, ID_SIM_REFRESH )
{ {
// Get the previous size and position of windows: // Get the previous size and position of windows:
LoadSettings( m_schematicFrame->eeconfig() ); LoadSettings( m_schematicFrame->eeconfig() );
@ -456,6 +461,16 @@ SIMULATOR_PANEL::SIMULATOR_PANEL( SIMULATOR_FRAME* aSimulatorFrame,
Bind( EVT_SIM_CURSOR_UPDATE, &SIMULATOR_PANEL::onPlotCursorUpdate, this ); Bind( EVT_SIM_CURSOR_UPDATE, &SIMULATOR_PANEL::onPlotCursorUpdate, this );
Bind( EVT_WORKBOOK_MODIFIED, &SIMULATOR_PANEL::onNotebookModified, this ); Bind( EVT_WORKBOOK_MODIFIED, &SIMULATOR_PANEL::onNotebookModified, this );
Bind( wxEVT_TIMER,
[&]( wxTimerEvent& aEvent )
{
OnSimRefresh( false );
if( m_simulatorFrame->GetSimulator()->IsRunning() )
m_refreshTimer.Start( REFRESH_INTERVAL, wxTIMER_ONE_SHOT );
},
m_refreshTimer.GetId() );
#ifndef wxHAS_NATIVE_TABART #ifndef wxHAS_NATIVE_TABART
// Default non-native tab art has ugly gradients we don't want // Default non-native tab art has ugly gradients we don't want
m_plotNotebook->SetArtProvider( new wxAuiSimpleTabArt() ); m_plotNotebook->SetArtProvider( new wxAuiSimpleTabArt() );
@ -1373,7 +1388,7 @@ void SIMULATOR_PANEL::SetUserDefinedSignals( const std::map<int, wxString>& aNew
void SIMULATOR_PANEL::updateTrace( const wxString& aVectorName, int aTraceType, void SIMULATOR_PANEL::updateTrace( const wxString& aVectorName, int aTraceType,
SIM_PLOT_PANEL* aPlotPanel ) SIM_PLOT_PANEL* aPlotPanel )
{ {
SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( aPlotPanel->GetSimCommand() ); SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( aPlotPanel->GetSimCommand() );
@ -1402,31 +1417,28 @@ void SIMULATOR_PANEL::updateTrace( const wxString& aVectorName, int aTraceType,
std::vector<double> data_x; std::vector<double> data_x;
std::vector<double> data_y; std::vector<double> data_y;
if( m_simulatorFrame->SimFinished() ) data_x = simulator()->GetMagPlot( (const char*) xAxisName.c_str() );
switch( simType )
{ {
data_x = simulator()->GetMagPlot( (const char*) xAxisName.c_str() ); case ST_AC:
if( aTraceType & SPT_AC_MAG )
switch( simType )
{
case ST_AC:
if( aTraceType & SPT_AC_MAG )
data_y = simulator()->GetMagPlot( (const char*) simVectorName.c_str() );
else if( aTraceType & SPT_AC_PHASE )
data_y = simulator()->GetPhasePlot( (const char*) simVectorName.c_str() );
else
wxFAIL_MSG( wxT( "Plot type missing AC_PHASE or AC_MAG bit" ) );
break;
case ST_NOISE:
case ST_DC:
case ST_TRANSIENT:
data_y = simulator()->GetMagPlot( (const char*) simVectorName.c_str() ); data_y = simulator()->GetMagPlot( (const char*) simVectorName.c_str() );
break; else if( aTraceType & SPT_AC_PHASE )
data_y = simulator()->GetPhasePlot( (const char*) simVectorName.c_str() );
else
wxFAIL_MSG( wxT( "Plot type missing AC_PHASE or AC_MAG bit" ) );
default: break;
wxFAIL_MSG( wxT( "Unhandled plot type" ) );
} case ST_NOISE:
case ST_DC:
case ST_TRANSIENT:
data_y = simulator()->GetMagPlot( (const char*) simVectorName.c_str() );
break;
default:
wxFAIL_MSG( wxT( "Unhandled plot type" ) );
} }
unsigned int size = data_x.size(); unsigned int size = data_x.size();
@ -2316,11 +2328,15 @@ void SIMULATOR_PANEL::onPlotCursorUpdate( wxCommandEvent& aEvent )
void SIMULATOR_PANEL::OnSimUpdate() void SIMULATOR_PANEL::OnSimUpdate()
{ {
// Incremental update if( SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotWindow() ) )
plotPanel->ResetScales( true );
m_simConsole->Clear(); m_simConsole->Clear();
// Do not export netlist, it is already stored in the simulator // Do not export netlist, it is already stored in the simulator
applyTuners(); applyTuners();
m_refreshTimer.Start( REFRESH_INTERVAL, wxTIMER_ONE_SHOT );
} }
@ -2331,7 +2347,7 @@ void SIMULATOR_PANEL::OnSimReport( const wxString& aMsg )
} }
void SIMULATOR_PANEL::OnSimFinished() void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
{ {
SIM_TYPE simType = circuitModel()->GetSimType(); SIM_TYPE simType = circuitModel()->GetSimType();
SIM_PLOT_PANEL_BASE* plotPanelWindow = GetCurrentPlotWindow(); SIM_PLOT_PANEL_BASE* plotPanelWindow = GetCurrentPlotWindow();
@ -2397,7 +2413,10 @@ void SIMULATOR_PANEL::OnSimFinished()
updateSignalsGrid(); updateSignalsGrid();
plotPanel->GetPlotWin()->UpdateAll(); plotPanel->GetPlotWin()->UpdateAll();
plotPanel->ResetScales();
if( aFinal )
plotPanel->ResetScales( true );
plotPanel->GetPlotWin()->Fit(); plotPanel->GetPlotWin()->Fit();
} }
else if( simType == ST_OP ) else if( simType == ST_OP )

View File

@ -228,7 +228,7 @@ public:
void OnSimUpdate(); void OnSimUpdate();
void OnSimReport( const wxString& aMsg ); void OnSimReport( const wxString& aMsg );
void OnSimFinished(); void OnSimRefresh( bool aFinal );
private: private:
/** /**
@ -331,6 +331,7 @@ private:
int m_splitterTuneValuesSashPosition; int m_splitterTuneValuesSashPosition;
bool m_darkMode; bool m_darkMode;
unsigned int m_plotNumber; unsigned int m_plotNumber;
wxTimer m_refreshTimer;
}; };
#endif // SIMULATOR_PANEL_H #endif // SIMULATOR_PANEL_H

View File

@ -748,7 +748,7 @@ public:
maxV = m_maxV; maxV = m_maxV;
} }
void ExtendDataRange( double minV, double maxV ) virtual void ExtendDataRange( double minV, double maxV )
{ {
if( !m_rangeSet ) if( !m_rangeSet )
{ {
@ -771,7 +771,7 @@ public:
void ResetDataRange() void ResetDataRange()
{ {
m_rangeSet = 0; m_rangeSet = false;
} }
double AbsMaxValue() const double AbsMaxValue() const