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
{
m_minX = -1;
m_maxX = 1;
m_minY = -1;
m_maxY = 1;
m_minX = 0;
m_maxX = 0;
m_minY = 0;
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>
class LOG_SCALE : public parent
{
@ -511,7 +538,7 @@ void SIM_PLOT_PANEL::updateAxes( int aNewTraceType )
case ST_TRANSIENT:
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_plotWin->AddLayer( m_axis_x );
@ -793,7 +820,7 @@ void SIM_PLOT_PANEL::DeleteTrace( TRACE* aTrace )
}
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();
if( m_axis_y1 )

View File

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

View File

@ -741,7 +741,7 @@ void SIMULATOR_FRAME::onSimFinished( wxCommandEvent& aEvent )
m_simFinished = true;
m_panel->OnSimFinished();
m_panel->OnSimRefresh( true );
m_schematicFrame->RefreshOperatingPointDisplay();
m_schematicFrame->GetCanvas()->Refresh();
@ -765,8 +765,8 @@ void SIMULATOR_FRAME::onSimUpdate( wxCommandEvent& aEvent )
if( m_panel->GetCurrentPlotWindow() != m_lastSimPlot )
{
// We need to rerun simulation, as the simulator currently stores
// results for another plot
// We need to rerun simulation, as the simulator currently stores results for another
// plot
StartSimulation();
}
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,
SCH_EDIT_FRAME* aSchematicFrame ) :
SIMULATOR_PANEL_BASE( aSimulatorFrame ),
@ -409,7 +413,8 @@ SIMULATOR_PANEL::SIMULATOR_PANEL( SIMULATOR_FRAME* aSimulatorFrame,
m_simulatorFrame( aSimulatorFrame ),
m_schematicFrame( aSchematicFrame ),
m_darkMode( true ),
m_plotNumber( 0 )
m_plotNumber( 0 ),
m_refreshTimer( this, ID_SIM_REFRESH )
{
// Get the previous size and position of windows:
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_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
// Default non-native tab art has ugly gradients we don't want
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,
SIM_PLOT_PANEL* aPlotPanel )
SIM_PLOT_PANEL* aPlotPanel )
{
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_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() );
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:
case ST_AC:
if( aTraceType & SPT_AC_MAG )
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:
wxFAIL_MSG( wxT( "Unhandled plot type" ) );
}
break;
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();
@ -2316,11 +2328,15 @@ void SIMULATOR_PANEL::onPlotCursorUpdate( wxCommandEvent& aEvent )
void SIMULATOR_PANEL::OnSimUpdate()
{
// Incremental update
if( SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotWindow() ) )
plotPanel->ResetScales( true );
m_simConsole->Clear();
// Do not export netlist, it is already stored in the simulator
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_PLOT_PANEL_BASE* plotPanelWindow = GetCurrentPlotWindow();
@ -2397,7 +2413,10 @@ void SIMULATOR_PANEL::OnSimFinished()
updateSignalsGrid();
plotPanel->GetPlotWin()->UpdateAll();
plotPanel->ResetScales();
if( aFinal )
plotPanel->ResetScales( true );
plotPanel->GetPlotWin()->Fit();
}
else if( simType == ST_OP )

View File

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

View File

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