Plotting for noise simulations.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/2369
This commit is contained in:
Jeff Young 2023-07-03 23:11:43 +01:00
parent 67c9d3932b
commit 7d3fa8fb4e
7 changed files with 104 additions and 41 deletions

View File

@ -264,17 +264,16 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
int m_noiseScaleNChoices = sizeof( m_noiseScaleChoices ) / sizeof( wxString );
m_noiseScale = new wxRadioBox( m_pgNoise, wxID_ANY, _("Frequency scale"), wxDefaultPosition, wxDefaultSize, m_noiseScaleNChoices, m_noiseScaleChoices, 1, wxRA_SPECIFY_COLS );
m_noiseScale->SetSelection( 0 );
m_noiseScale->Hide();
bSizer10->Add( m_noiseScale, 0, wxALL, 5 );
bSizer10->Add( 30, 0, 0, wxEXPAND, 5 );
wxFlexGridSizer* fgSizer11;
fgSizer11 = new wxFlexGridSizer( 0, 3, 3, 0 );
fgSizer11->SetFlexibleDirection( wxBOTH );
fgSizer11->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText11 = new wxStaticText( m_pgNoise, wxID_ANY, _("Number of points:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText11 = new wxStaticText( m_pgNoise, wxID_ANY, _("Number of points per decade:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText11->Wrap( -1 );
fgSizer11->Add( m_staticText11, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT, 5 );
@ -313,7 +312,7 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
fgSizer11->Add( m_noiseFreqStopUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
bSizer10->Add( fgSizer11, 0, wxALIGN_BOTTOM|wxBOTTOM|wxLEFT, 4 );
bSizer10->Add( fgSizer11, 0, wxALIGN_BOTTOM|wxTOP|wxBOTTOM|wxLEFT, 5 );
bSizer15->Add( bSizer10, 0, wxEXPAND|wxTOP, 5 );

View File

@ -3076,7 +3076,7 @@
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="hidden">1</property>
<property name="id">wxID_ANY</property>
<property name="label">Frequency scale</property>
<property name="majorDimension">1</property>
@ -3113,17 +3113,7 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="spacer" expanded="1">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">30</property>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">4</property>
<property name="flag">wxALIGN_BOTTOM|wxBOTTOM|wxLEFT</property>
<property name="flag">wxALIGN_BOTTOM|wxTOP|wxBOTTOM|wxLEFT</property>
<property name="proportion">0</property>
<object class="wxFlexGridSizer" expanded="1">
<property name="cols">3</property>
@ -3169,7 +3159,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Number of points:</property>
<property name="label">Number of points per decade:</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>

View File

@ -329,9 +329,11 @@ wxString NGSPICE::GetXAxis( SIM_TYPE aType ) const
switch( aType )
{
case ST_AC:
case ST_NOISE:
return wxS( "frequency" );
case ST_NOISE:
return wxS( "noise1.frequency" );
case ST_DC:
// find plot, which ends with "-sweep"
for( wxString plot : AllPlots() )

View File

@ -528,13 +528,28 @@ void SIM_PLOT_PANEL::updateAxes( int aNewTraceType )
m_axis_x->SetNameAlign( mpALIGN_BOTTOM );
m_plotWin->AddLayer( m_axis_x );
m_axis_y1 = new mpScaleY( wxEmptyString, mpALIGN_LEFT, false );
m_axis_y1->SetNameAlign( mpALIGN_LEFT );
m_plotWin->AddLayer( m_axis_y1 );
if( ( aNewTraceType & SPT_CURRENT ) == 0 )
{
m_axis_y1 = new LIN_SCALE<mpScaleY>( wxEmptyString, wxT( "" ), mpALIGN_LEFT );
m_axis_y1->SetNameAlign( mpALIGN_LEFT );
m_plotWin->AddLayer( m_axis_y1 );
}
else
{
m_axis_y2 = new LIN_SCALE<mpScaleY>( wxEmptyString, wxT( "" ), mpALIGN_RIGHT );
m_axis_y2->SetNameAlign( mpALIGN_RIGHT );
m_plotWin->AddLayer( m_axis_y2 );
}
}
m_axis_x->SetName( _( "Frequency" ) );
m_axis_y1->SetName( _( "noise [(V or A)^2/Hz]" ) );
if( m_axis_y1 )
m_axis_y1->SetName( _( "Noise (V/√Hz)" ) );
if( m_axis_y2 )
m_axis_y2->SetName( _( "Noise (A/√Hz)" ) );
break;
case ST_TRANSIENT:

View File

@ -59,6 +59,7 @@ bool SIM_PLOT_PANEL_BASE::IsPlottable( SIM_TYPE aSimType )
case ST_AC:
case ST_DC:
case ST_TRANSIENT:
case ST_NOISE:
return true;
default:

View File

@ -699,7 +699,8 @@ void SIMULATOR_PANEL::rebuildSignalsList()
}
};
if( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES )
if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_VOLTAGES )
&& ( simType == ST_TRANSIENT || simType == ST_DC || simType == ST_AC ) )
{
for( const std::string& net : circuitModel()->GetNets() )
{
@ -738,6 +739,12 @@ void SIMULATOR_PANEL::rebuildSignalsList()
}
}
if( simType == ST_NOISE )
{
addSignal( wxS( "inoise" ) );
addSignal( wxS( "onoise" ) );
}
// Add .PROBE directives
for( const wxString& directive : circuitModel()->GetDirectives() )
{
@ -840,14 +847,26 @@ wxString SIMULATOR_PANEL::vectorNameFromSignalName( const wxString& aSignalName,
if( aTraceType )
{
wxUniChar firstChar = aSignalName.Upper()[0];
wxString name = aSignalName.Upper();
if( firstChar == 'V' )
*aTraceType = SPT_VOLTAGE;
else if( firstChar == 'I' )
*aTraceType = SPT_CURRENT;
else if( firstChar == 'P' )
*aTraceType = SPT_POWER;
if( name == wxS( "INOISE" ) || name == wxS( "ONOISE" ) )
{
if( getNoiseSource().Upper().StartsWith( 'I' ) )
*aTraceType = SPT_CURRENT;
else
*aTraceType = SPT_VOLTAGE;
}
else if( !name.IsEmpty() )
{
wxUniChar firstChar = name[0];
if( firstChar == 'V' )
*aTraceType = SPT_VOLTAGE;
else if( firstChar == 'I' )
*aTraceType = SPT_CURRENT;
else if( firstChar == 'P' )
*aTraceType = SPT_POWER;
}
}
wxString suffix;
@ -1432,6 +1451,10 @@ void SIMULATOR_PANEL::updateTrace( const wxString& aVectorName, int aTraceType,
break;
case ST_NOISE:
simVectorName = wxString::Format( wxS( "noise1.%s_spectrum" ), simVectorName );
data_y = simulator()->GetMagPlot( (const char*) simVectorName.c_str() );
break;
case ST_DC:
case ST_TRANSIENT:
data_y = simulator()->GetMagPlot( (const char*) simVectorName.c_str() );
@ -2099,11 +2122,29 @@ SIM_TRACE_TYPE SIMULATOR_PANEL::getXAxisType( SIM_TYPE aType ) const
case ST_AC: return SPT_LIN_FREQUENCY;
case ST_DC: return SPT_SWEEP;
case ST_TRANSIENT: return SPT_TIME;
case ST_NOISE: return SPT_LIN_FREQUENCY;
default: wxFAIL_MSG( wxS( "Unhandled simulation type" ) ); return SPT_UNKNOWN;
}
}
wxString SIMULATOR_PANEL::getNoiseSource() const
{
wxString output;
wxString ref;
wxString source;
wxString scale;
SPICE_VALUE pts;
SPICE_VALUE fStart;
SPICE_VALUE fStop;
circuitModel()->ParseNoiseCommand( circuitModel()->GetSimCommand(), &output, &ref, &source,
&scale, &pts, &fStart, &fStop );
return source;
}
void SIMULATOR_PANEL::ToggleDarkModePlots()
{
m_darkMode = !m_darkMode;
@ -2359,6 +2400,7 @@ void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
}
std::vector<wxString> oldSignals = m_signals;
wxString msg;
applyUserDefinedSignals();
rebuildSignalsList();
@ -2366,6 +2408,23 @@ void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
// If there are any signals plotted, update them
if( SIM_PLOT_PANEL_BASE::IsPlottable( simType ) )
{
if( simType == ST_NOISE && aFinal )
{
m_simConsole->AppendText( _( "\n\nSimulation results:\n\n" ) );
m_simConsole->SetInsertionPointEnd();
for( const std::string& vec : simulator()->AllPlots() )
{
std::vector<double> val_list = simulator()->GetRealPlot( vec, 1 );
wxString value = SPICE_VALUE( val_list[ 0 ] ).ToSpiceString();
msg.Printf( wxS( "%s: %sV\n" ), vec, value );
m_simConsole->AppendText( msg );
m_simConsole->SetInsertionPointEnd();
}
}
SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( plotPanelWindow );
wxCHECK_RET( plotPanel, wxT( "not a SIM_PLOT_PANEL" ) );
@ -2427,17 +2486,12 @@ void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
for( const std::string& vec : simulator()->AllPlots() )
{
std::vector<double> val_list = simulator()->GetRealPlot( vec, 1 );
wxString value = SPICE_VALUE( val_list[ 0 ] ).ToSpiceString();
wxString signal;
SIM_TRACE_TYPE type = circuitModel()->VectorToSignal( vec, signal );
if( val_list.size() == 0 ) // The list of values can be empty!
continue;
wxString value = SPICE_VALUE( val_list.at( 0 ) ).ToSpiceString();
wxString msg;
wxString signal;
SIM_TRACE_TYPE type = circuitModel()->VectorToSignal( vec, signal );
const size_t tab = 25; //characters
size_t padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1;
const size_t tab = 25; //characters
size_t padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1;
value.Append( type == SPT_CURRENT ? wxS( "A" ) : wxS( "V" ) );

View File

@ -283,6 +283,8 @@ private:
*/
SIM_TRACE_TYPE getXAxisType( SIM_TYPE aType ) const;
wxString getNoiseSource() const;
void parseTraceParams( SIM_PLOT_PANEL* aPlotPanel, TRACE* aTrace, const wxString& aSignalName,
const wxString& aParams );