ADDED FFT analyses.

CHANGED abandon the unpredictable behaviour of the Simulation Command
dialog.  You now separately add simulation tabs (which have invariant
command types once created), and the dialog edits the current tab.

Also a bunch of bug fixes to make multiple simulation plots actually
work.
This commit is contained in:
Jeff Young 2023-07-05 18:25:52 +01:00
parent d5d2800b03
commit bde9c2cbc5
41 changed files with 3057 additions and 2528 deletions

View File

@ -481,6 +481,7 @@ void BuildBitmapInfo( std::unordered_map<BITMAPS, std::vector<BITMAP_INFO>>& aBi
aBitmapInfoCache[BITMAPS::shape_3d_back].emplace_back( BITMAPS::shape_3d_back, wxT( "shape_3d_back_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::shape_3d_back].emplace_back( BITMAPS::shape_3d_back, wxT( "shape_3d_back_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::sheetset].emplace_back( BITMAPS::sheetset, wxT( "sheetset_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::sheetset].emplace_back( BITMAPS::sheetset, wxT( "sheetset_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::simulator].emplace_back( BITMAPS::simulator, wxT( "simulator_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::simulator].emplace_back( BITMAPS::simulator, wxT( "simulator_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::sim_add_plot].emplace_back( BITMAPS::sim_add_plot, wxT( "sim_add_plot_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::sim_command].emplace_back( BITMAPS::sim_command, wxT( "sim_command_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::sim_command].emplace_back( BITMAPS::sim_command, wxT( "sim_command_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::sim_run].emplace_back( BITMAPS::sim_run, wxT( "sim_run_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::sim_run].emplace_back( BITMAPS::sim_run, wxT( "sim_run_24.png" ), 24, wxT( "light" ) );
aBitmapInfoCache[BITMAPS::sim_stop].emplace_back( BITMAPS::sim_stop, wxT( "sim_stop_24.png" ), 24, wxT( "light" ) ); aBitmapInfoCache[BITMAPS::sim_stop].emplace_back( BITMAPS::sim_stop, wxT( "sim_stop_24.png" ), 24, wxT( "light" ) );

View File

@ -1676,12 +1676,8 @@ mpWindow::mpWindow() :
} }
} }
mpWindow::mpWindow( wxWindow* parent, mpWindow::mpWindow( wxWindow* parent, wxWindowID id ) :
wxWindowID id, wxWindow( parent, id, wxDefaultPosition, wxDefaultSize, 0, wxT( "mathplot" ) )
const wxPoint& pos,
const wxSize& size,
long flag )
: wxWindow( parent, id, pos, size, flag, wxT( "mathplot" ) )
{ {
m_zooming = false; m_zooming = false;
m_scaleX = m_scaleY = 1.0; m_scaleX = m_scaleY = 1.0;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application. * This program source code file is part of KiCad, a free EDA CAD application.
* *
* Copyright (C) 2016-2022 CERN * Copyright (C) 2016-2022 CERN
* Copyright (C) 2016-2022 KiCad Developers, see AUTHORS.txt for contributors. * Copyright (C) 2016-2023 KiCad Developers, see AUTHORS.txt for contributors.
* @author Maciej Suminski <maciej.suminski@cern.ch> * @author Maciej Suminski <maciej.suminski@cern.ch>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
@ -26,6 +26,7 @@
#include "dialog_sim_command.h" #include "dialog_sim_command.h"
#include <sim/ngspice_circuit_model.h> #include <sim/ngspice_circuit_model.h>
#include <sim/ngspice.h> #include <sim/ngspice.h>
#include <sim/simulator_frame.h>
#include <confirm.h> #include <confirm.h>
@ -56,10 +57,11 @@ static wxString getStringSelection( const wxChoice* aCtrl )
} }
DIALOG_SIM_COMMAND::DIALOG_SIM_COMMAND( wxWindow* aParent, DIALOG_SIM_COMMAND::DIALOG_SIM_COMMAND( SIMULATOR_FRAME* aParent,
std::shared_ptr<NGSPICE_CIRCUIT_MODEL> aCircuitModel, std::shared_ptr<NGSPICE_CIRCUIT_MODEL> aCircuitModel,
std::shared_ptr<SPICE_SIMULATOR_SETTINGS>& aSettings ) : std::shared_ptr<SPICE_SIMULATOR_SETTINGS>& aSettings ) :
DIALOG_SIM_COMMAND_BASE( aParent ), DIALOG_SIM_COMMAND_BASE( aParent ),
m_simulatorFrame( aParent ),
m_circuitModel( aCircuitModel ), m_circuitModel( aCircuitModel ),
m_settings( aSettings ), m_settings( aSettings ),
m_spiceEmptyValidator( true ) m_spiceEmptyValidator( true )
@ -91,6 +93,8 @@ DIALOG_SIM_COMMAND::DIALOG_SIM_COMMAND( wxWindow* aParent,
m_transInitial->SetValidator( m_spiceEmptyValidator ); m_transInitial->SetValidator( m_spiceEmptyValidator );
m_transMaxStep->SetValidator( m_spiceEmptyValidator ); m_transMaxStep->SetValidator( m_spiceEmptyValidator );
m_inputSignalsFilter->SetDescriptiveText( _( "Filter" ) );
wxChar type1 = getStringSelection( m_dcSourceType1 ).Upper().GetChar( 0 ); wxChar type1 = getStringSelection( m_dcSourceType1 ).Upper().GetChar( 0 );
updateDCSources( type1, m_dcSource1 ); updateDCSources( type1, m_dcSource1 );
@ -112,15 +116,6 @@ DIALOG_SIM_COMMAND::DIALOG_SIM_COMMAND( wxWindow* aParent,
m_noiseSrc->Append( item.refName ); m_noiseSrc->Append( item.refName );
} }
refreshUIControls();
// Hide pages that aren't fully implemented yet
// wxPanel::Hide() isn't enough on some platforms
m_simPages->RemovePage( m_simPages->FindPage( m_pgDistortion ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgPoleZero ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgSensitivity ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgTransferFunction ) );
if( !dynamic_cast<NGSPICE_SIMULATOR_SETTINGS*>( aSettings.get() ) ) if( !dynamic_cast<NGSPICE_SIMULATOR_SETTINGS*>( aSettings.get() ) )
m_compatibilityMode->Show( false ); m_compatibilityMode->Show( false );
@ -158,6 +153,7 @@ bool DIALOG_SIM_COMMAND::TransferDataToWindow()
if( m_simCommand.IsEmpty() && !empty( m_customTxt ) ) if( m_simCommand.IsEmpty() && !empty( m_customTxt ) )
parseCommand( m_customTxt->GetValue() ); parseCommand( m_customTxt->GetValue() );
refreshUIControls();
return true; return true;
} }
@ -225,7 +221,7 @@ bool DIALOG_SIM_COMMAND::TransferDataFromWindow()
wxString previousSimCommand = m_simCommand; wxString previousSimCommand = m_simCommand;
wxWindow* page = m_simPages->GetCurrentPage(); wxWindow* page = m_simPages->GetCurrentPage();
if( page == m_pgAC ) // AC analysis if( page == m_pgAC ) // AC small-signal analysis
{ {
if( !m_pgAC->Validate() ) if( !m_pgAC->Validate() )
return false; return false;
@ -236,7 +232,7 @@ bool DIALOG_SIM_COMMAND::TransferDataFromWindow()
SPICE_VALUE( m_acFreqStart->GetValue() ).ToSpiceString(), SPICE_VALUE( m_acFreqStart->GetValue() ).ToSpiceString(),
SPICE_VALUE( m_acFreqStop->GetValue() ).ToSpiceString() ); SPICE_VALUE( m_acFreqStop->GetValue() ).ToSpiceString() );
} }
else if( page == m_pgSP ) // S-params analysis else if( page == m_pgSP ) // S-params analysis
{ {
if( !m_pgSP->Validate() ) if( !m_pgSP->Validate() )
return false; return false;
@ -276,7 +272,22 @@ bool DIALOG_SIM_COMMAND::TransferDataFromWindow()
m_simCommand = simCmd; m_simCommand = simCmd;
} }
else if( page == m_pgNoise ) // Noise analysis else if( page == m_pgFFT ) // Fast Fourier transform
{
wxString vectors;
for( int ii = 0; ii < (int) m_inputSignalsList->GetCount(); ++ii )
{
if( m_inputSignalsList->IsChecked( ii ) )
vectors += wxS( " " ) + m_inputSignalsList->GetString( ii );
}
if( m_linearize->IsChecked() )
m_simCommand = wxT( "linearize" ) + vectors + wxS( "\n" );
m_simCommand = wxT( "fft" ) + vectors;
}
else if( page == m_pgNOISE ) // Noise analysis
{ {
wxString output = m_noiseMeas->GetStringSelection(); wxString output = m_noiseMeas->GetStringSelection();
wxString ref = m_noiseRef->GetStringSelection(); wxString ref = m_noiseRef->GetStringSelection();
@ -305,9 +316,9 @@ bool DIALOG_SIM_COMMAND::TransferDataFromWindow()
{ {
m_simCommand = wxString( ".op" ); m_simCommand = wxString( ".op" );
} }
else if( page == m_pgTransient ) // Transient analysis else if( page == m_pgTRAN ) // Transient analysis
{ {
if( !m_pgTransient->Validate() ) if( !m_pgTRAN->Validate() )
return false; return false;
const wxString spc = wxS( " " ); const wxString spc = wxS( " " );
@ -430,11 +441,37 @@ void DIALOG_SIM_COMMAND::parseCommand( const wxString& aCommand )
if( aCommand.IsEmpty() ) if( aCommand.IsEmpty() )
return; return;
wxStringTokenizer tokenizer( aCommand, " " ); if( aCommand == wxT( "*" ) )
{
SetTitle( _( "New Simulation" ) );
m_commandType->Clear();
for( SIM_TYPE type : { ST_AC, ST_DC, ST_NOISE, ST_OP, ST_TRAN, ST_SP, ST_FFT } )
{
m_commandType->Append( SPICE_SIMULATOR::TypeToName( type, true )
+ wxT( " \u2014 " )
+ SPICE_SIMULATOR::TypeToName( type, false ) );
}
m_commandTypeSizer->Show( true );
return;
}
SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( aCommand );
SetTitle( SPICE_SIMULATOR::TypeToName( simType, true )
+ wxT( " \u2014 " )
+ SPICE_SIMULATOR::TypeToName( simType, false ) );
m_commandTypeSizer->Show( false );
wxStringTokenizer tokenizer( aCommand, wxS( " \t\n\r" ), wxTOKEN_STRTOK );
wxString token = tokenizer.GetNextToken().Lower(); wxString token = tokenizer.GetNextToken().Lower();
if( token == ".ac" ) switch( simType )
{ {
case ST_AC:
m_simPages->SetSelection( m_simPages->FindPage( m_pgAC ) ); m_simPages->SetSelection( m_simPages->FindPage( m_pgAC ) );
token = tokenizer.GetNextToken().Lower(); token = tokenizer.GetNextToken().Lower();
@ -451,9 +488,9 @@ void DIALOG_SIM_COMMAND::parseCommand( const wxString& aCommand )
m_acPointsNumber->SetValue( tokenizer.GetNextToken() ); m_acPointsNumber->SetValue( tokenizer.GetNextToken() );
m_acFreqStart->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() ); m_acFreqStart->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
m_acFreqStop->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() ); m_acFreqStop->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
} break;
else if( token == ".sp" )
{ case ST_SP:
m_simPages->SetSelection( m_simPages->FindPage( m_pgSP ) ); m_simPages->SetSelection( m_simPages->FindPage( m_pgSP ) );
token = tokenizer.GetNextToken().Lower(); token = tokenizer.GetNextToken().Lower();
@ -472,11 +509,11 @@ void DIALOG_SIM_COMMAND::parseCommand( const wxString& aCommand )
m_spFreqStop->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() ); m_spFreqStop->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
if( tokenizer.HasMoreTokens() ) if( tokenizer.HasMoreTokens() )
m_spDoNoise->SetValue( m_spDoNoise->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() == "1" );
SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() == "1" ? true
: false ); break;
}
else if( token == ".dc" ) case ST_DC:
{ {
m_simPages->SetSelection( m_simPages->FindPage( m_pgDC ) ); m_simPages->SetSelection( m_simPages->FindPage( m_pgDC ) );
@ -512,11 +549,12 @@ void DIALOG_SIM_COMMAND::parseCommand( const wxString& aCommand )
m_dcEnable2->SetValue( true ); m_dcEnable2->SetValue( true );
} }
refreshUIControls(); break;
} }
else if( token == ".noise" )
case ST_NOISE:
{ {
m_simPages->SetSelection( m_simPages->FindPage( m_pgNoise ) ); m_simPages->SetSelection( m_simPages->FindPage( m_pgNOISE ) );
wxString output; wxString output;
wxString ref; wxString ref;
@ -548,10 +586,11 @@ void DIALOG_SIM_COMMAND::parseCommand( const wxString& aCommand )
m_noiseFreqStop->SetValue( fStop.ToSpiceString() ); m_noiseFreqStop->SetValue( fStop.ToSpiceString() );
m_saveAllNoise->SetValue( saveAll ); m_saveAllNoise->SetValue( saveAll );
break;
} }
else if( token == ".tran" )
{ case ST_TRAN:
m_simPages->SetSelection( m_simPages->FindPage( m_pgTransient ) ); m_simPages->SetSelection( m_simPages->FindPage( m_pgTRAN ) );
// If the fields below are empty, it will be caught by the exception handler // If the fields below are empty, it will be caught by the exception handler
m_transStep->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() ); m_transStep->SetValue( SPICE_VALUE( tokenizer.GetNextToken() ).ToSpiceString() );
@ -574,14 +613,51 @@ void DIALOG_SIM_COMMAND::parseCommand( const wxString& aCommand )
if( token.IsSameAs( wxS( "uic" ) ) ) if( token.IsSameAs( wxS( "uic" ) ) )
m_useInitialConditions->SetValue( true ); m_useInitialConditions->SetValue( true );
}
else if( token == ".op" ) break;
{
case ST_OP:
m_simPages->SetSelection( m_simPages->FindPage( m_pgOP ) ); m_simPages->SetSelection( m_simPages->FindPage( m_pgOP ) );
} break;
else if( !empty( m_customTxt ) ) // Custom directives
case ST_FFT:
{ {
m_simPages->SetSelection( m_simPages->FindPage( m_pgFFT ) );
while( tokenizer.HasMoreTokens() )
m_fftInputSignals.insert( tokenizer.GetNextToken() );
break;
}
default:
m_simPages->SetSelection( m_simPages->FindPage( m_pgCustom ) ); m_simPages->SetSelection( m_simPages->FindPage( m_pgCustom ) );
break;
}
}
void DIALOG_SIM_COMMAND::OnCommandType( wxCommandEvent& event )
{
int sel = ST_UNKNOWN;
wxString str = m_commandType->GetString( event.GetSelection() );
for( int type = ST_UNKNOWN; type < ST_LAST; ++type )
{
if( str.StartsWith( SPICE_SIMULATOR::TypeToName( (SIM_TYPE) type, true ) ) )
sel = type;
}
switch( sel )
{
case ST_AC: m_simPages->SetSelection( m_simPages->FindPage( m_pgAC ) ); break;
case ST_SP: m_simPages->SetSelection( m_simPages->FindPage( m_pgSP ) ); break;
case ST_DC: m_simPages->SetSelection( m_simPages->FindPage( m_pgDC ) ); break;
case ST_NOISE: m_simPages->SetSelection( m_simPages->FindPage( m_pgNOISE ) ); break;
case ST_TRAN: m_simPages->SetSelection( m_simPages->FindPage( m_pgTRAN ) ); break;
case ST_OP: m_simPages->SetSelection( m_simPages->FindPage( m_pgOP ) ); break;
case ST_FFT: m_simPages->SetSelection( m_simPages->FindPage( m_pgFFT ) ); break;
default: m_simPages->SetSelection( m_simPages->FindPage( m_pgCustom ) ); break;
} }
} }
@ -619,6 +695,22 @@ void DIALOG_SIM_COMMAND::onSwapDCSources( wxCommandEvent& event )
} }
void DIALOG_SIM_COMMAND::onDCSource1Selected( wxCommandEvent& event )
{
wxChar type = m_dcSourceType1->GetString( m_dcSourceType1->GetSelection() ).Upper()[ 0 ];
updateDCSources( type, m_dcSource1 );
updateDCUnits( type, m_dcSource1, m_src1DCStartValUnit, m_src1DCEndValUnit, m_src1DCStepUnit );
}
void DIALOG_SIM_COMMAND::onDCSource2Selected( wxCommandEvent& event )
{
wxChar type = m_dcSourceType2->GetString( m_dcSourceType2->GetSelection() ).Upper()[ 0 ];
updateDCSources( type, m_dcSource2 );
updateDCUnits( type, m_dcSource2, m_src2DCStartValUnit, m_src2DCEndValUnit, m_src2DCStepUnit );
}
void DIALOG_SIM_COMMAND::onDCEnableSecondSource( wxCommandEvent& event ) void DIALOG_SIM_COMMAND::onDCEnableSecondSource( wxCommandEvent& event )
{ {
bool is2ndSrcEnabled = m_dcEnable2->IsChecked(); bool is2ndSrcEnabled = m_dcEnable2->IsChecked();
@ -661,3 +753,50 @@ void DIALOG_SIM_COMMAND::loadDirectives()
} }
void DIALOG_SIM_COMMAND::OnFilterText( wxCommandEvent& aEvent )
{
for( int ii = 0; ii < (int) m_inputSignalsList->GetCount(); ++ii )
{
if( m_inputSignalsList->IsChecked( ii ) )
m_fftInputSignals.insert( m_inputSignalsList->GetString( ii ) );
else
m_fftInputSignals.erase( m_inputSignalsList->GetString( ii ) );
}
m_inputSignalsList->Clear();
wxString aFilter = m_inputSignalsFilter->GetValue();
if( aFilter.IsEmpty() )
aFilter = wxS( "*" );
EDA_COMBINED_MATCHER matcher( aFilter.Upper(), CTX_SIGNAL );
for( const wxString& signal : m_simulatorFrame->Signals() )
{
if( matcher.Find( signal.Upper() ) )
{
m_inputSignalsList->Append( signal );
if( m_fftInputSignals.count( signal ) )
m_inputSignalsList->Check( m_inputSignalsList->GetCount() - 1 );
}
}
}
void DIALOG_SIM_COMMAND::OnFilterMouseMoved( wxMouseEvent& aEvent )
{
wxPoint pos = aEvent.GetPosition();
wxRect ctrlRect = m_inputSignalsFilter->GetScreenRect();
int buttonWidth = ctrlRect.GetHeight(); // Presume buttons are square
if( m_inputSignalsFilter->IsSearchButtonVisible() && pos.x < buttonWidth )
SetCursor( wxCURSOR_ARROW );
else if( m_inputSignalsFilter->IsCancelButtonVisible() && pos.x > ctrlRect.GetWidth() - buttonWidth )
SetCursor( wxCURSOR_ARROW );
else
SetCursor( wxCURSOR_IBEAM );
}

View File

@ -35,12 +35,13 @@
class NGSPICE_CIRCUIT_MODEL; class NGSPICE_CIRCUIT_MODEL;
class SPICE_SIMULATOR_SETTINGS; class SPICE_SIMULATOR_SETTINGS;
class SIMULATOR_FRAME;
class DIALOG_SIM_COMMAND : public DIALOG_SIM_COMMAND_BASE class DIALOG_SIM_COMMAND : public DIALOG_SIM_COMMAND_BASE
{ {
public: public:
DIALOG_SIM_COMMAND( wxWindow* aParent, std::shared_ptr<NGSPICE_CIRCUIT_MODEL> aCircuitModel, DIALOG_SIM_COMMAND( SIMULATOR_FRAME* aParent, std::shared_ptr<NGSPICE_CIRCUIT_MODEL> aCircuitModel,
std::shared_ptr<SPICE_SIMULATOR_SETTINGS>& aSettings ); std::shared_ptr<SPICE_SIMULATOR_SETTINGS>& aSettings );
const wxString& GetSimCommand() const const wxString& GetSimCommand() const
@ -52,6 +53,7 @@ public:
{ {
parseCommand( aCommand ); parseCommand( aCommand );
m_simCommand = aCommand; m_simCommand = aCommand;
refreshUIControls();
} }
int GetSimOptions() const int GetSimOptions() const
@ -107,6 +109,7 @@ private:
wxQueueEvent( m_dcEnable2, new wxCommandEvent( wxEVT_CHECKBOX ) ); wxQueueEvent( m_dcEnable2, new wxCommandEvent( wxEVT_CHECKBOX ) );
wxQueueEvent( m_dcSourceType1, new wxCommandEvent( wxEVT_RADIOBOX ) ); wxQueueEvent( m_dcSourceType1, new wxCommandEvent( wxEVT_RADIOBOX ) );
wxQueueEvent( m_dcSourceType2, new wxCommandEvent( wxEVT_RADIOBOX ) ); wxQueueEvent( m_dcSourceType2, new wxCommandEvent( wxEVT_RADIOBOX ) );
wxQueueEvent( m_inputSignalsFilter, new wxCommandEvent( wxEVT_TEXT ) );
} }
/** /**
@ -151,23 +154,8 @@ private:
void onDCEnableSecondSource( wxCommandEvent& event ) override; void onDCEnableSecondSource( wxCommandEvent& event ) override;
void onSwapDCSources( wxCommandEvent& event ) override; void onSwapDCSources( wxCommandEvent& event ) override;
void onDCSource1Selected( wxCommandEvent& event ) override void onDCSource1Selected( wxCommandEvent& event ) override;
{ void onDCSource2Selected( wxCommandEvent& event ) override;
wxChar type =
m_dcSourceType1->GetString( m_dcSourceType1->GetSelection() ).Upper().GetChar( 0 );
updateDCSources( type, m_dcSource1 );
updateDCUnits( type, m_dcSource1, m_src1DCStartValUnit, m_src1DCEndValUnit,
m_src1DCStepUnit );
}
void onDCSource2Selected( wxCommandEvent& event ) override
{
wxChar type =
m_dcSourceType2->GetString( m_dcSourceType2->GetSelection() ).Upper().GetChar( 0 );
updateDCSources( type, m_dcSource2 );
updateDCUnits( type, m_dcSource2, m_src2DCStartValUnit, m_src2DCEndValUnit,
m_src2DCStepUnit );
}
static wxString scaleToString( int aOption ) static wxString scaleToString( int aOption )
{ {
@ -180,15 +168,21 @@ private:
} }
} }
void OnCommandType( wxCommandEvent& event ) override;
void OnFilterMouseMoved( wxMouseEvent& event ) override;
void OnFilterText( wxCommandEvent& event ) override;
void loadDirectives(); void loadDirectives();
private: private:
SIMULATOR_FRAME* m_simulatorFrame;
wxString m_simCommand; wxString m_simCommand;
std::shared_ptr<NGSPICE_CIRCUIT_MODEL> m_circuitModel; std::shared_ptr<NGSPICE_CIRCUIT_MODEL> m_circuitModel;
std::shared_ptr<SPICE_SIMULATOR_SETTINGS> m_settings; std::shared_ptr<SPICE_SIMULATOR_SETTINGS> m_settings;
SPICE_VALIDATOR m_spiceValidator; SPICE_VALIDATOR m_spiceValidator;
SPICE_VALIDATOR m_spiceEmptyValidator; SPICE_VALIDATOR m_spiceEmptyValidator;
wxIntegerValidator<int> m_posIntValidator; wxIntegerValidator<int> m_posIntValidator;
std::set<wxString> m_fftInputSignals;
}; };
#endif /* DIALOG_SIM_COMMAND_H */ #endif /* DIALOG_SIM_COMMAND_H */

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-88b0f50) // C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -16,7 +16,22 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
wxBoxSizer* bSizer1; wxBoxSizer* bSizer1;
bSizer1 = new wxBoxSizer( wxVERTICAL ); bSizer1 = new wxBoxSizer( wxVERTICAL );
m_simPages = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 ); m_commandTypeSizer = new wxBoxSizer( wxHORIZONTAL );
m_commandTypeLabel = new wxStaticText( this, wxID_ANY, _("Simulation type:"), wxDefaultPosition, wxDefaultSize, 0 );
m_commandTypeLabel->Wrap( -1 );
m_commandTypeSizer->Add( m_commandTypeLabel, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
wxString m_commandTypeChoices[] = { _("AC"), _("DC"), _("OP"), _("TRAN"), _("FFT"), _("NOISE"), _("SP"), _("Custom") };
int m_commandTypeNChoices = sizeof( m_commandTypeChoices ) / sizeof( wxString );
m_commandType = new wxChoice( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_commandTypeNChoices, m_commandTypeChoices, 0 );
m_commandType->SetSelection( 0 );
m_commandTypeSizer->Add( m_commandType, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
bSizer1->Add( m_commandTypeSizer, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 );
m_simPages = new wxSimplebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
m_pgAC = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_pgAC = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer3; wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxVERTICAL ); bSizer3 = new wxBoxSizer( wxVERTICAL );
@ -75,69 +90,7 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
m_pgAC->SetSizer( bSizer3 ); m_pgAC->SetSizer( bSizer3 );
m_pgAC->Layout(); m_pgAC->Layout();
bSizer3->Fit( m_pgAC ); bSizer3->Fit( m_pgAC );
m_simPages->AddPage( m_pgAC, _("AC"), false ); m_simPages->AddPage( m_pgAC, _("a page"), false );
m_pgSP = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer31;
bSizer31 = new wxBoxSizer( wxVERTICAL );
wxString m_spScaleChoices[] = { _("Decade"), _("Octave"), _("Linear") };
int m_spScaleNChoices = sizeof( m_spScaleChoices ) / sizeof( wxString );
m_spScale = new wxRadioBox( m_pgSP, wxID_ANY, _("Frequency scale"), wxDefaultPosition, wxDefaultSize, m_spScaleNChoices, m_spScaleChoices, 1, wxRA_SPECIFY_COLS );
m_spScale->SetSelection( 0 );
m_spScale->Hide();
bSizer31->Add( m_spScale, 0, wxALL|wxEXPAND, 5 );
wxFlexGridSizer* fgSizer12;
fgSizer12 = new wxFlexGridSizer( 0, 3, 5, 0 );
fgSizer12->SetFlexibleDirection( wxHORIZONTAL );
fgSizer12->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText12 = new wxStaticText( m_pgSP, wxID_ANY, _("Number of points per decade:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText12->Wrap( -1 );
fgSizer12->Add( m_staticText12, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spPointsNumber = new wxTextCtrl( m_pgSP, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer12->Add( m_spPointsNumber, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
fgSizer12->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticText22 = new wxStaticText( m_pgSP, wxID_ANY, _("Start frequency:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText22->Wrap( -1 );
fgSizer12->Add( m_staticText22, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spFreqStart = new wxTextCtrl( m_pgSP, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_spFreqStart->SetMinSize( wxSize( 100,-1 ) );
fgSizer12->Add( m_spFreqStart, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_staticText191 = new wxStaticText( m_pgSP, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText191->Wrap( -1 );
fgSizer12->Add( m_staticText191, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_staticText32 = new wxStaticText( m_pgSP, wxID_ANY, _("Stop frequency:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText32->Wrap( -1 );
fgSizer12->Add( m_staticText32, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spFreqStop = new wxTextCtrl( m_pgSP, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer12->Add( m_spFreqStop, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_staticText1101 = new wxStaticText( m_pgSP, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1101->Wrap( -1 );
fgSizer12->Add( m_staticText1101, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_spDoNoise = new wxCheckBox( m_pgSP, wxID_ANY, _("Compute noise current correlation matrix"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer12->Add( m_spDoNoise, 0, wxALL, 5 );
bSizer31->Add( fgSizer12, 0, wxEXPAND|wxALL, 5 );
m_pgSP->SetSizer( bSizer31 );
m_pgSP->Layout();
bSizer31->Fit( m_pgSP );
m_simPages->AddPage( m_pgSP, _("S-params"), false );
m_pgDC = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_pgDC = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer82; wxBoxSizer* bSizer82;
bSizer82 = new wxBoxSizer( wxVERTICAL ); bSizer82 = new wxBoxSizer( wxVERTICAL );
@ -267,10 +220,126 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
m_pgDC->SetSizer( bSizer82 ); m_pgDC->SetSizer( bSizer82 );
m_pgDC->Layout(); m_pgDC->Layout();
bSizer82->Fit( m_pgDC ); bSizer82->Fit( m_pgDC );
m_simPages->AddPage( m_pgDC, _("DC Transfer"), false ); m_simPages->AddPage( m_pgDC, _("a page"), false );
m_pgDistortion = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_pgOP = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_simPages->AddPage( m_pgDistortion, _("Distortion"), false ); wxBoxSizer* bSizer8;
m_pgNoise = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); bSizer8 = new wxBoxSizer( wxVERTICAL );
m_pgOP->SetSizer( bSizer8 );
m_pgOP->Layout();
bSizer8->Fit( m_pgOP );
m_simPages->AddPage( m_pgOP, _("a page"), false );
m_pgTRAN = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer81;
bSizer81 = new wxBoxSizer( wxVERTICAL );
wxGridBagSizer* gbSizer2;
gbSizer2 = new wxGridBagSizer( 4, 0 );
gbSizer2->SetFlexibleDirection( wxBOTH );
gbSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
gbSizer2->SetEmptyCellSize( wxSize( -1,8 ) );
m_timeLabel = new wxStaticText( m_pgTRAN, wxID_ANY, _("Time step:"), wxDefaultPosition, wxDefaultSize, 0 );
m_timeLabel->Wrap( -1 );
gbSizer2->Add( m_timeLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transStep = new wxTextCtrl( m_pgTRAN, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_transStep->SetMinSize( wxSize( 100,-1 ) );
gbSizer2->Add( m_transStep, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_timeUnits = new wxStaticText( m_pgTRAN, wxID_ANY, _("seconds"), wxDefaultPosition, wxDefaultSize, 0 );
m_timeUnits->Wrap( -1 );
gbSizer2->Add( m_timeUnits, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transFinalLabel = new wxStaticText( m_pgTRAN, wxID_ANY, _("Final time:"), wxDefaultPosition, wxDefaultSize, 0 );
m_transFinalLabel->Wrap( -1 );
gbSizer2->Add( m_transFinalLabel, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transFinal = new wxTextCtrl( m_pgTRAN, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_transFinal, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_transFinalUnits = new wxStaticText( m_pgTRAN, wxID_ANY, _("seconds"), wxDefaultPosition, wxDefaultSize, 0 );
m_transFinalUnits->Wrap( -1 );
gbSizer2->Add( m_transFinalUnits, wxGBPosition( 1, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transInitialLabel = new wxStaticText( m_pgTRAN, wxID_ANY, _("Initial time:"), wxDefaultPosition, wxDefaultSize, 0 );
m_transInitialLabel->Wrap( -1 );
gbSizer2->Add( m_transInitialLabel, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transInitial = new wxTextCtrl( m_pgTRAN, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_transInitial, wxGBPosition( 2, 1 ), wxGBSpan( 1, 1 ), wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
m_transInitialUnits = new wxStaticText( m_pgTRAN, wxID_ANY, _("seconds"), wxDefaultPosition, wxDefaultSize, 0 );
m_transInitialUnits->Wrap( -1 );
gbSizer2->Add( m_transInitialUnits, wxGBPosition( 2, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transInitialHelp = new wxStaticText( m_pgTRAN, wxID_ANY, _("(optional; default 0)"), wxDefaultPosition, wxDefaultSize, 0 );
m_transInitialHelp->Wrap( -1 );
gbSizer2->Add( m_transInitialHelp, wxGBPosition( 2, 3 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_maxStepLabel = new wxStaticText( m_pgTRAN, wxID_ANY, _("Max time step:"), wxDefaultPosition, wxDefaultSize, 0 );
m_maxStepLabel->Wrap( -1 );
gbSizer2->Add( m_maxStepLabel, wxGBPosition( 3, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transMaxStep = new wxTextCtrl( m_pgTRAN, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_transMaxStep, wxGBPosition( 3, 1 ), wxGBSpan( 1, 1 ), wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
m_transMaxStepUnit = new wxStaticText( m_pgTRAN, wxID_ANY, _("seconds"), wxDefaultPosition, wxDefaultSize, 0 );
m_transMaxStepUnit->Wrap( -1 );
gbSizer2->Add( m_transMaxStepUnit, wxGBPosition( 3, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transMaxHelp = new wxStaticText( m_pgTRAN, wxID_ANY, _("(optional; default min{tstep, (tstop-tstart)/50})"), wxDefaultPosition, wxDefaultSize, 0 );
m_transMaxHelp->Wrap( -1 );
gbSizer2->Add( m_transMaxHelp, wxGBPosition( 3, 3 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_useInitialConditions = new wxCheckBox( m_pgTRAN, wxID_ANY, _("Use initial conditions"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_useInitialConditions, wxGBPosition( 5, 0 ), wxGBSpan( 1, 3 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
bSizer81->Add( gbSizer2, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_pgTRAN->SetSizer( bSizer81 );
m_pgTRAN->Layout();
bSizer81->Fit( m_pgTRAN );
m_simPages->AddPage( m_pgTRAN, _("a page"), false );
m_pgFFT = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer151;
bSizer151 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSizer14;
bSizer14 = new wxBoxSizer( wxVERTICAL );
m_signalsLabel = new wxStaticText( m_pgFFT, wxID_ANY, _("Input signals:"), wxDefaultPosition, wxDefaultSize, 0 );
m_signalsLabel->Wrap( -1 );
bSizer14->Add( m_signalsLabel, 0, wxBOTTOM|wxLEFT, 5 );
m_inputSignalsFilter = new wxSearchCtrl( m_pgFFT, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
#ifndef __WXMAC__
m_inputSignalsFilter->ShowSearchButton( true );
#endif
m_inputSignalsFilter->ShowCancelButton( true );
bSizer14->Add( m_inputSignalsFilter, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
wxArrayString m_inputSignalsListChoices;
m_inputSignalsList = new wxCheckListBox( m_pgFFT, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_inputSignalsListChoices, 0 );
bSizer14->Add( m_inputSignalsList, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_linearize = new wxCheckBox( m_pgFFT, wxID_ANY, _("Linearize inputs before performing FFT"), wxDefaultPosition, wxDefaultSize, 0 );
m_linearize->SetValue(true);
bSizer14->Add( m_linearize, 0, wxALL, 5 );
bSizer151->Add( bSizer14, 1, wxTOP|wxRIGHT|wxLEFT, 5 );
m_pgFFT->SetSizer( bSizer151 );
m_pgFFT->Layout();
bSizer151->Fit( m_pgFFT );
m_simPages->AddPage( m_pgFFT, _("a page"), false );
m_pgNOISE = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer15; wxBoxSizer* bSizer15;
bSizer15 = new wxBoxSizer( wxVERTICAL ); bSizer15 = new wxBoxSizer( wxVERTICAL );
@ -279,37 +348,37 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
fgSizer7->SetFlexibleDirection( wxBOTH ); fgSizer7->SetFlexibleDirection( wxBOTH );
fgSizer7->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); fgSizer7->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText14 = new wxStaticText( m_pgNoise, wxID_ANY, _("Measured node:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText14 = new wxStaticText( m_pgNOISE, wxID_ANY, _("Measured node:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText14->Wrap( -1 ); m_staticText14->Wrap( -1 );
fgSizer7->Add( m_staticText14, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); fgSizer7->Add( m_staticText14, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
wxArrayString m_noiseMeasChoices; wxArrayString m_noiseMeasChoices;
m_noiseMeas = new wxChoice( m_pgNoise, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_noiseMeasChoices, 0 ); m_noiseMeas = new wxChoice( m_pgNOISE, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_noiseMeasChoices, 0 );
m_noiseMeas->SetSelection( 0 ); m_noiseMeas->SetSelection( 0 );
fgSizer7->Add( m_noiseMeas, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 ); fgSizer7->Add( m_noiseMeas, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 );
fgSizer7->Add( 0, 0, 1, wxEXPAND, 5 ); fgSizer7->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticText15 = new wxStaticText( m_pgNoise, wxID_ANY, _("Reference node:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText15 = new wxStaticText( m_pgNOISE, wxID_ANY, _("Reference node:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText15->Wrap( -1 ); m_staticText15->Wrap( -1 );
fgSizer7->Add( m_staticText15, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); fgSizer7->Add( m_staticText15, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
wxArrayString m_noiseRefChoices; wxArrayString m_noiseRefChoices;
m_noiseRef = new wxChoice( m_pgNoise, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_noiseRefChoices, 0 ); m_noiseRef = new wxChoice( m_pgNOISE, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_noiseRefChoices, 0 );
m_noiseRef->SetSelection( 0 ); m_noiseRef->SetSelection( 0 );
fgSizer7->Add( m_noiseRef, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 ); fgSizer7->Add( m_noiseRef, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 );
m_staticText23 = new wxStaticText( m_pgNoise, wxID_ANY, _("(optional; default GND)"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText23 = new wxStaticText( m_pgNOISE, wxID_ANY, _("(optional; default GND)"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText23->Wrap( -1 ); m_staticText23->Wrap( -1 );
fgSizer7->Add( m_staticText23, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); fgSizer7->Add( m_staticText23, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_staticText16 = new wxStaticText( m_pgNoise, wxID_ANY, _("Noise source:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText16 = new wxStaticText( m_pgNOISE, wxID_ANY, _("Noise source:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText16->Wrap( -1 ); m_staticText16->Wrap( -1 );
fgSizer7->Add( m_staticText16, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); fgSizer7->Add( m_staticText16, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
wxArrayString m_noiseSrcChoices; wxArrayString m_noiseSrcChoices;
m_noiseSrc = new wxChoice( m_pgNoise, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_noiseSrcChoices, 0 ); m_noiseSrc = new wxChoice( m_pgNOISE, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_noiseSrcChoices, 0 );
m_noiseSrc->SetSelection( 0 ); m_noiseSrc->SetSelection( 0 );
fgSizer7->Add( m_noiseSrc, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 ); fgSizer7->Add( m_noiseSrc, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT|wxEXPAND, 5 );
@ -324,7 +393,7 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
wxString m_noiseScaleChoices[] = { _("Decade"), _("Octave"), _("Linear") }; wxString m_noiseScaleChoices[] = { _("Decade"), _("Octave"), _("Linear") };
int m_noiseScaleNChoices = sizeof( m_noiseScaleChoices ) / sizeof( wxString ); 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 = new wxRadioBox( m_pgNOISE, wxID_ANY, _("Frequency scale"), wxDefaultPosition, wxDefaultSize, m_noiseScaleNChoices, m_noiseScaleChoices, 1, wxRA_SPECIFY_COLS );
m_noiseScale->SetSelection( 0 ); m_noiseScale->SetSelection( 0 );
m_noiseScale->Hide(); m_noiseScale->Hide();
@ -335,11 +404,11 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
fgSizer11->SetFlexibleDirection( wxBOTH ); fgSizer11->SetFlexibleDirection( wxBOTH );
fgSizer11->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED ); fgSizer11->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText11 = new wxStaticText( m_pgNoise, wxID_ANY, _("Number of points per decade:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText11 = new wxStaticText( m_pgNOISE, wxID_ANY, _("Number of points per decade:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText11->Wrap( -1 ); m_staticText11->Wrap( -1 );
fgSizer11->Add( m_staticText11, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT, 5 ); fgSizer11->Add( m_staticText11, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxRIGHT|wxLEFT, 5 );
m_noisePointsNumber = new wxTextCtrl( m_pgNoise, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_noisePointsNumber = new wxTextCtrl( m_pgNOISE, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_noisePointsNumber->SetMinSize( wxSize( 80,-1 ) ); m_noisePointsNumber->SetMinSize( wxSize( 80,-1 ) );
fgSizer11->Add( m_noisePointsNumber, 1, wxALIGN_CENTER_VERTICAL|wxTOP, 5 ); fgSizer11->Add( m_noisePointsNumber, 1, wxALIGN_CENTER_VERTICAL|wxTOP, 5 );
@ -347,29 +416,29 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
fgSizer11->Add( 0, 0, 1, wxEXPAND, 5 ); fgSizer11->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticText21 = new wxStaticText( m_pgNoise, wxID_ANY, _("Start frequency:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText21 = new wxStaticText( m_pgNOISE, wxID_ANY, _("Start frequency:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText21->Wrap( -1 ); m_staticText21->Wrap( -1 );
fgSizer11->Add( m_staticText21, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 ); fgSizer11->Add( m_staticText21, 0, wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_noiseFreqStart = new wxTextCtrl( m_pgNoise, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_noiseFreqStart = new wxTextCtrl( m_pgNOISE, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_noiseFreqStart->SetMinSize( wxSize( 80,-1 ) ); m_noiseFreqStart->SetMinSize( wxSize( 80,-1 ) );
fgSizer11->Add( m_noiseFreqStart, 1, wxALIGN_CENTER_VERTICAL, 5 ); fgSizer11->Add( m_noiseFreqStart, 1, wxALIGN_CENTER_VERTICAL, 5 );
m_noiseFreqStartUnits = new wxStaticText( m_pgNoise, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 ); m_noiseFreqStartUnits = new wxStaticText( m_pgNOISE, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 );
m_noiseFreqStartUnits->Wrap( -1 ); m_noiseFreqStartUnits->Wrap( -1 );
fgSizer11->Add( m_noiseFreqStartUnits, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 ); fgSizer11->Add( m_noiseFreqStartUnits, 0, wxRIGHT|wxLEFT|wxALIGN_CENTER_VERTICAL, 5 );
m_staticText31 = new wxStaticText( m_pgNoise, wxID_ANY, _("Stop frequency:"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText31 = new wxStaticText( m_pgNOISE, wxID_ANY, _("Stop frequency:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText31->Wrap( -1 ); m_staticText31->Wrap( -1 );
fgSizer11->Add( m_staticText31, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); fgSizer11->Add( m_staticText31, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
m_noiseFreqStop = new wxTextCtrl( m_pgNoise, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 ); m_noiseFreqStop = new wxTextCtrl( m_pgNOISE, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_noiseFreqStop->SetMinSize( wxSize( 80,-1 ) ); m_noiseFreqStop->SetMinSize( wxSize( 80,-1 ) );
fgSizer11->Add( m_noiseFreqStop, 1, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 ); fgSizer11->Add( m_noiseFreqStop, 1, wxALIGN_CENTER_VERTICAL|wxBOTTOM, 5 );
m_noiseFreqStopUnits = new wxStaticText( m_pgNoise, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 ); m_noiseFreqStopUnits = new wxStaticText( m_pgNOISE, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 );
m_noiseFreqStopUnits->Wrap( -1 ); m_noiseFreqStopUnits->Wrap( -1 );
fgSizer11->Add( m_noiseFreqStopUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); fgSizer11->Add( m_noiseFreqStopUnits, 0, wxALIGN_CENTER_VERTICAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
@ -379,120 +448,77 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
bSizer15->Add( bSizer10, 0, wxEXPAND|wxTOP, 5 ); bSizer15->Add( bSizer10, 0, wxEXPAND|wxTOP, 5 );
m_saveAllNoise = new wxCheckBox( m_pgNoise, wxID_ANY, _("Save contributions from all noise generators"), wxDefaultPosition, wxDefaultSize, 0 ); m_saveAllNoise = new wxCheckBox( m_pgNOISE, wxID_ANY, _("Save contributions from all noise generators"), wxDefaultPosition, wxDefaultSize, 0 );
m_saveAllNoise->SetValue(true);
bSizer15->Add( m_saveAllNoise, 0, wxALL, 10 ); bSizer15->Add( m_saveAllNoise, 0, wxALL, 10 );
m_pgNoise->SetSizer( bSizer15 ); m_pgNOISE->SetSizer( bSizer15 );
m_pgNoise->Layout(); m_pgNOISE->Layout();
bSizer15->Fit( m_pgNoise ); bSizer15->Fit( m_pgNOISE );
m_simPages->AddPage( m_pgNoise, _("Noise"), false ); m_simPages->AddPage( m_pgNOISE, _("a page"), false );
m_pgOP = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_pgSP = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer8; wxBoxSizer* bSizer31;
bSizer8 = new wxBoxSizer( wxVERTICAL ); bSizer31 = new wxBoxSizer( wxVERTICAL );
wxString m_spScaleChoices[] = { _("Decade"), _("Octave"), _("Linear") };
int m_spScaleNChoices = sizeof( m_spScaleChoices ) / sizeof( wxString );
m_spScale = new wxRadioBox( m_pgSP, wxID_ANY, _("Frequency scale"), wxDefaultPosition, wxDefaultSize, m_spScaleNChoices, m_spScaleChoices, 1, wxRA_SPECIFY_COLS );
m_spScale->SetSelection( 0 );
m_spScale->Hide();
bSizer31->Add( m_spScale, 0, wxALL|wxEXPAND, 5 );
wxFlexGridSizer* fgSizer12;
fgSizer12 = new wxFlexGridSizer( 0, 3, 5, 0 );
fgSizer12->SetFlexibleDirection( wxHORIZONTAL );
fgSizer12->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
m_staticText12 = new wxStaticText( m_pgSP, wxID_ANY, _("Number of points per decade:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText12->Wrap( -1 );
fgSizer12->Add( m_staticText12, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spPointsNumber = new wxTextCtrl( m_pgSP, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer12->Add( m_spPointsNumber, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
bSizer8->Add( 0, 0, 1, wxEXPAND, 5 ); fgSizer12->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticText13 = new wxStaticText( m_pgOP, wxID_ANY, _("This tab has no settings"), wxDefaultPosition, wxDefaultSize, 0 ); m_staticText22 = new wxStaticText( m_pgSP, wxID_ANY, _("Start frequency:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText13->Wrap( -1 ); m_staticText22->Wrap( -1 );
bSizer8->Add( m_staticText13, 0, wxALIGN_CENTER, 5 ); fgSizer12->Add( m_staticText22, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spFreqStart = new wxTextCtrl( m_pgSP, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_spFreqStart->SetMinSize( wxSize( 100,-1 ) );
fgSizer12->Add( m_spFreqStart, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_staticText191 = new wxStaticText( m_pgSP, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText191->Wrap( -1 );
fgSizer12->Add( m_staticText191, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_staticText32 = new wxStaticText( m_pgSP, wxID_ANY, _("Stop frequency:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText32->Wrap( -1 );
fgSizer12->Add( m_staticText32, 0, wxALIGN_CENTER_VERTICAL|wxLEFT, 5 );
m_spFreqStop = new wxTextCtrl( m_pgSP, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
fgSizer12->Add( m_spFreqStop, 0, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_staticText1101 = new wxStaticText( m_pgSP, wxID_ANY, _("Hz"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText1101->Wrap( -1 );
fgSizer12->Add( m_staticText1101, 0, wxALIGN_CENTER_VERTICAL|wxALIGN_LEFT, 5 );
m_spDoNoise = new wxCheckBox( m_pgSP, wxID_ANY, _("Compute noise current correlation matrix"), wxDefaultPosition, wxDefaultSize, 0 );
fgSizer12->Add( m_spDoNoise, 0, wxALL, 5 );
bSizer8->Add( 0, 0, 1, wxEXPAND, 5 ); bSizer31->Add( fgSizer12, 0, wxEXPAND|wxALL, 5 );
m_pgOP->SetSizer( bSizer8 ); m_pgSP->SetSizer( bSizer31 );
m_pgOP->Layout(); m_pgSP->Layout();
bSizer8->Fit( m_pgOP ); bSizer31->Fit( m_pgSP );
m_simPages->AddPage( m_pgOP, _("Operating Point"), false ); m_simPages->AddPage( m_pgSP, _("a page"), false );
m_pgPoleZero = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_pgPoleZero->Hide();
m_simPages->AddPage( m_pgPoleZero, _("Pole-Zero"), false );
m_pgSensitivity = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_pgSensitivity->Hide();
m_simPages->AddPage( m_pgSensitivity, _("Sensitivity"), false );
m_pgTransferFunction = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_pgTransferFunction->Hide();
m_simPages->AddPage( m_pgTransferFunction, _("Transfer Function"), false );
m_pgTransient = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer81;
bSizer81 = new wxBoxSizer( wxVERTICAL );
wxGridBagSizer* gbSizer2;
gbSizer2 = new wxGridBagSizer( 4, 0 );
gbSizer2->SetFlexibleDirection( wxBOTH );
gbSizer2->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
gbSizer2->SetEmptyCellSize( wxSize( -1,8 ) );
m_timeLabel = new wxStaticText( m_pgTransient, wxID_ANY, _("Time step:"), wxDefaultPosition, wxDefaultSize, 0 );
m_timeLabel->Wrap( -1 );
gbSizer2->Add( m_timeLabel, wxGBPosition( 0, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transStep = new wxTextCtrl( m_pgTransient, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
m_transStep->SetMinSize( wxSize( 100,-1 ) );
gbSizer2->Add( m_transStep, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_timeUnits = new wxStaticText( m_pgTransient, wxID_ANY, _("seconds"), wxDefaultPosition, wxDefaultSize, 0 );
m_timeUnits->Wrap( -1 );
gbSizer2->Add( m_timeUnits, wxGBPosition( 0, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transFinalLabel = new wxStaticText( m_pgTransient, wxID_ANY, _("Final time:"), wxDefaultPosition, wxDefaultSize, 0 );
m_transFinalLabel->Wrap( -1 );
gbSizer2->Add( m_transFinalLabel, wxGBPosition( 1, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transFinal = new wxTextCtrl( m_pgTransient, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_transFinal, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxEXPAND, 5 );
m_transFinalUnits = new wxStaticText( m_pgTransient, wxID_ANY, _("seconds"), wxDefaultPosition, wxDefaultSize, 0 );
m_transFinalUnits->Wrap( -1 );
gbSizer2->Add( m_transFinalUnits, wxGBPosition( 1, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transInitialLabel = new wxStaticText( m_pgTransient, wxID_ANY, _("Initial time:"), wxDefaultPosition, wxDefaultSize, 0 );
m_transInitialLabel->Wrap( -1 );
gbSizer2->Add( m_transInitialLabel, wxGBPosition( 2, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transInitial = new wxTextCtrl( m_pgTransient, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_transInitial, wxGBPosition( 2, 1 ), wxGBSpan( 1, 1 ), wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
m_transInitialUnits = new wxStaticText( m_pgTransient, wxID_ANY, _("seconds"), wxDefaultPosition, wxDefaultSize, 0 );
m_transInitialUnits->Wrap( -1 );
gbSizer2->Add( m_transInitialUnits, wxGBPosition( 2, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transInitialHelp = new wxStaticText( m_pgTransient, wxID_ANY, _("(optional; default 0)"), wxDefaultPosition, wxDefaultSize, 0 );
m_transInitialHelp->Wrap( -1 );
gbSizer2->Add( m_transInitialHelp, wxGBPosition( 2, 3 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_maxStepLabel = new wxStaticText( m_pgTransient, wxID_ANY, _("Max time step:"), wxDefaultPosition, wxDefaultSize, 0 );
m_maxStepLabel->Wrap( -1 );
gbSizer2->Add( m_maxStepLabel, wxGBPosition( 3, 0 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transMaxStep = new wxTextCtrl( m_pgTransient, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_transMaxStep, wxGBPosition( 3, 1 ), wxGBSpan( 1, 1 ), wxEXPAND|wxALIGN_CENTER_VERTICAL, 5 );
m_transMaxStepUnit = new wxStaticText( m_pgTransient, wxID_ANY, _("seconds"), wxDefaultPosition, wxDefaultSize, 0 );
m_transMaxStepUnit->Wrap( -1 );
gbSizer2->Add( m_transMaxStepUnit, wxGBPosition( 3, 2 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_transMaxHelp = new wxStaticText( m_pgTransient, wxID_ANY, _("(optional; default min{tstep, (tstop-tstart)/50})"), wxDefaultPosition, wxDefaultSize, 0 );
m_transMaxHelp->Wrap( -1 );
gbSizer2->Add( m_transMaxHelp, wxGBPosition( 3, 3 ), wxGBSpan( 1, 1 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
m_useInitialConditions = new wxCheckBox( m_pgTransient, wxID_ANY, _("Use initial conditions"), wxDefaultPosition, wxDefaultSize, 0 );
gbSizer2->Add( m_useInitialConditions, wxGBPosition( 5, 0 ), wxGBSpan( 1, 3 ), wxALIGN_CENTER_VERTICAL|wxRIGHT|wxLEFT, 5 );
bSizer81->Add( gbSizer2, 1, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 5 );
m_pgTransient->SetSizer( bSizer81 );
m_pgTransient->Layout();
bSizer81->Fit( m_pgTransient );
m_simPages->AddPage( m_pgTransient, _("Transient"), true );
m_pgCustom = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL ); m_pgCustom = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
wxBoxSizer* bSizer2; wxBoxSizer* bSizer2;
bSizer2 = new wxBoxSizer( wxVERTICAL ); bSizer2 = new wxBoxSizer( wxVERTICAL );
@ -513,9 +539,9 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
m_pgCustom->SetSizer( bSizer2 ); m_pgCustom->SetSizer( bSizer2 );
m_pgCustom->Layout(); m_pgCustom->Layout();
bSizer2->Fit( m_pgCustom ); bSizer2->Fit( m_pgCustom );
m_simPages->AddPage( m_pgCustom, _("Custom"), false ); m_simPages->AddPage( m_pgCustom, _("a page"), false );
bSizer1->Add( m_simPages, 1, wxALL|wxEXPAND, 10 ); bSizer1->Add( m_simPages, 1, wxEXPAND | wxALL, 5 );
wxBoxSizer* bSizer88; wxBoxSizer* bSizer88;
bSizer88 = new wxBoxSizer( wxVERTICAL ); bSizer88 = new wxBoxSizer( wxVERTICAL );
@ -570,10 +596,13 @@ DIALOG_SIM_COMMAND_BASE::DIALOG_SIM_COMMAND_BASE( wxWindow* parent, wxWindowID i
// Connect Events // Connect Events
this->Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_SIM_COMMAND_BASE::onInitDlg ) ); this->Connect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_SIM_COMMAND_BASE::onInitDlg ) );
m_commandType->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::OnCommandType ), NULL, this );
m_dcEnable2->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCEnableSecondSource ), NULL, this ); m_dcEnable2->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCEnableSecondSource ), NULL, this );
m_dcSourceType1->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCSource1Selected ), NULL, this ); m_dcSourceType1->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCSource1Selected ), NULL, this );
m_dcSourceType2->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCSource2Selected ), NULL, this ); m_dcSourceType2->Connect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCSource2Selected ), NULL, this );
m_swapDCSources->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onSwapDCSources ), NULL, this ); m_swapDCSources->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onSwapDCSources ), NULL, this );
m_inputSignalsFilter->Connect( wxEVT_MOTION, wxMouseEventHandler( DIALOG_SIM_COMMAND_BASE::OnFilterMouseMoved ), NULL, this );
m_inputSignalsFilter->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::OnFilterText ), NULL, this );
m_loadDirectives->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onLoadDirectives ), NULL, this ); m_loadDirectives->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onLoadDirectives ), NULL, this );
} }
@ -581,10 +610,13 @@ DIALOG_SIM_COMMAND_BASE::~DIALOG_SIM_COMMAND_BASE()
{ {
// Disconnect Events // Disconnect Events
this->Disconnect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_SIM_COMMAND_BASE::onInitDlg ) ); this->Disconnect( wxEVT_INIT_DIALOG, wxInitDialogEventHandler( DIALOG_SIM_COMMAND_BASE::onInitDlg ) );
m_commandType->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::OnCommandType ), NULL, this );
m_dcEnable2->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCEnableSecondSource ), NULL, this ); m_dcEnable2->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCEnableSecondSource ), NULL, this );
m_dcSourceType1->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCSource1Selected ), NULL, this ); m_dcSourceType1->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCSource1Selected ), NULL, this );
m_dcSourceType2->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCSource2Selected ), NULL, this ); m_dcSourceType2->Disconnect( wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onDCSource2Selected ), NULL, this );
m_swapDCSources->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onSwapDCSources ), NULL, this ); m_swapDCSources->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onSwapDCSources ), NULL, this );
m_inputSignalsFilter->Disconnect( wxEVT_MOTION, wxMouseEventHandler( DIALOG_SIM_COMMAND_BASE::OnFilterMouseMoved ), NULL, this );
m_inputSignalsFilter->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::OnFilterText ), NULL, this );
m_loadDirectives->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onLoadDirectives ), NULL, this ); m_loadDirectives->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_SIM_COMMAND_BASE::onLoadDirectives ), NULL, this );
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version 3.10.1-88b0f50) // C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b)
// http://www.wxformbuilder.org/ // http://www.wxformbuilder.org/
// //
// PLEASE DO *NOT* EDIT THIS FILE! // PLEASE DO *NOT* EDIT THIS FILE!
@ -12,24 +12,26 @@
#include <wx/intl.h> #include <wx/intl.h>
#include "dialog_shim.h" #include "dialog_shim.h"
#include <wx/string.h> #include <wx/string.h>
#include <wx/radiobox.h> #include <wx/stattext.h>
#include <wx/gdicmn.h> #include <wx/gdicmn.h>
#include <wx/font.h> #include <wx/font.h>
#include <wx/colour.h> #include <wx/colour.h>
#include <wx/settings.h> #include <wx/settings.h>
#include <wx/stattext.h> #include <wx/choice.h>
#include <wx/sizer.h>
#include <wx/radiobox.h>
#include <wx/textctrl.h> #include <wx/textctrl.h>
#include <wx/valtext.h> #include <wx/valtext.h>
#include <wx/sizer.h>
#include <wx/panel.h> #include <wx/panel.h>
#include <wx/checkbox.h>
#include <wx/gbsizer.h>
#include <wx/button.h>
#include <wx/bitmap.h> #include <wx/bitmap.h>
#include <wx/image.h> #include <wx/image.h>
#include <wx/icon.h> #include <wx/icon.h>
#include <wx/checkbox.h> #include <wx/srchctrl.h>
#include <wx/choice.h> #include <wx/checklst.h>
#include <wx/gbsizer.h> #include <wx/simplebook.h>
#include <wx/button.h>
#include <wx/notebook.h>
#include <wx/dialog.h> #include <wx/dialog.h>
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@ -43,7 +45,10 @@ class DIALOG_SIM_COMMAND_BASE : public DIALOG_SHIM
private: private:
protected: protected:
wxNotebook* m_simPages; wxBoxSizer* m_commandTypeSizer;
wxStaticText* m_commandTypeLabel;
wxChoice* m_commandType;
wxSimplebook* m_simPages;
wxPanel* m_pgAC; wxPanel* m_pgAC;
wxRadioBox* m_acScale; wxRadioBox* m_acScale;
wxStaticText* m_staticText1; wxStaticText* m_staticText1;
@ -54,17 +59,6 @@ class DIALOG_SIM_COMMAND_BASE : public DIALOG_SHIM
wxStaticText* m_staticText3; wxStaticText* m_staticText3;
wxTextCtrl* m_acFreqStop; wxTextCtrl* m_acFreqStop;
wxStaticText* m_staticText110; wxStaticText* m_staticText110;
wxPanel* m_pgSP;
wxRadioBox* m_spScale;
wxStaticText* m_staticText12;
wxTextCtrl* m_spPointsNumber;
wxStaticText* m_staticText22;
wxTextCtrl* m_spFreqStart;
wxStaticText* m_staticText191;
wxStaticText* m_staticText32;
wxTextCtrl* m_spFreqStop;
wxStaticText* m_staticText1101;
wxCheckBox* m_spDoNoise;
wxPanel* m_pgDC; wxPanel* m_pgDC;
wxCheckBox* m_dcEnable2; wxCheckBox* m_dcEnable2;
wxChoice* m_dcSourceType1; wxChoice* m_dcSourceType1;
@ -90,8 +84,29 @@ class DIALOG_SIM_COMMAND_BASE : public DIALOG_SHIM
wxTextCtrl* m_dcIncr2; wxTextCtrl* m_dcIncr2;
wxStaticText* m_src2DCStepUnit; wxStaticText* m_src2DCStepUnit;
wxButton* m_swapDCSources; wxButton* m_swapDCSources;
wxPanel* m_pgDistortion; wxPanel* m_pgOP;
wxPanel* m_pgNoise; wxPanel* m_pgTRAN;
wxStaticText* m_timeLabel;
wxTextCtrl* m_transStep;
wxStaticText* m_timeUnits;
wxStaticText* m_transFinalLabel;
wxTextCtrl* m_transFinal;
wxStaticText* m_transFinalUnits;
wxStaticText* m_transInitialLabel;
wxTextCtrl* m_transInitial;
wxStaticText* m_transInitialUnits;
wxStaticText* m_transInitialHelp;
wxStaticText* m_maxStepLabel;
wxTextCtrl* m_transMaxStep;
wxStaticText* m_transMaxStepUnit;
wxStaticText* m_transMaxHelp;
wxCheckBox* m_useInitialConditions;
wxPanel* m_pgFFT;
wxStaticText* m_signalsLabel;
wxSearchCtrl* m_inputSignalsFilter;
wxCheckListBox* m_inputSignalsList;
wxCheckBox* m_linearize;
wxPanel* m_pgNOISE;
wxStaticText* m_staticText14; wxStaticText* m_staticText14;
wxChoice* m_noiseMeas; wxChoice* m_noiseMeas;
wxStaticText* m_staticText15; wxStaticText* m_staticText15;
@ -109,27 +124,17 @@ class DIALOG_SIM_COMMAND_BASE : public DIALOG_SHIM
wxTextCtrl* m_noiseFreqStop; wxTextCtrl* m_noiseFreqStop;
wxStaticText* m_noiseFreqStopUnits; wxStaticText* m_noiseFreqStopUnits;
wxCheckBox* m_saveAllNoise; wxCheckBox* m_saveAllNoise;
wxPanel* m_pgOP; wxPanel* m_pgSP;
wxStaticText* m_staticText13; wxRadioBox* m_spScale;
wxPanel* m_pgPoleZero; wxStaticText* m_staticText12;
wxPanel* m_pgSensitivity; wxTextCtrl* m_spPointsNumber;
wxPanel* m_pgTransferFunction; wxStaticText* m_staticText22;
wxPanel* m_pgTransient; wxTextCtrl* m_spFreqStart;
wxStaticText* m_timeLabel; wxStaticText* m_staticText191;
wxTextCtrl* m_transStep; wxStaticText* m_staticText32;
wxStaticText* m_timeUnits; wxTextCtrl* m_spFreqStop;
wxStaticText* m_transFinalLabel; wxStaticText* m_staticText1101;
wxTextCtrl* m_transFinal; wxCheckBox* m_spDoNoise;
wxStaticText* m_transFinalUnits;
wxStaticText* m_transInitialLabel;
wxTextCtrl* m_transInitial;
wxStaticText* m_transInitialUnits;
wxStaticText* m_transInitialHelp;
wxStaticText* m_maxStepLabel;
wxTextCtrl* m_transMaxStep;
wxStaticText* m_transMaxStepUnit;
wxStaticText* m_transMaxHelp;
wxCheckBox* m_useInitialConditions;
wxPanel* m_pgCustom; wxPanel* m_pgCustom;
wxStaticText* m_staticText18; wxStaticText* m_staticText18;
wxTextCtrl* m_customTxt; wxTextCtrl* m_customTxt;
@ -146,10 +151,13 @@ class DIALOG_SIM_COMMAND_BASE : public DIALOG_SHIM
// Virtual event handlers, override them in your derived class // Virtual event handlers, override them in your derived class
virtual void onInitDlg( wxInitDialogEvent& event ) { event.Skip(); } virtual void onInitDlg( wxInitDialogEvent& event ) { event.Skip(); }
virtual void OnCommandType( wxCommandEvent& event ) { event.Skip(); }
virtual void onDCEnableSecondSource( wxCommandEvent& event ) { event.Skip(); } virtual void onDCEnableSecondSource( wxCommandEvent& event ) { event.Skip(); }
virtual void onDCSource1Selected( wxCommandEvent& event ) { event.Skip(); } virtual void onDCSource1Selected( wxCommandEvent& event ) { event.Skip(); }
virtual void onDCSource2Selected( wxCommandEvent& event ) { event.Skip(); } virtual void onDCSource2Selected( wxCommandEvent& event ) { event.Skip(); }
virtual void onSwapDCSources( wxCommandEvent& event ) { event.Skip(); } virtual void onSwapDCSources( wxCommandEvent& event ) { event.Skip(); }
virtual void OnFilterMouseMoved( wxMouseEvent& event ) { event.Skip(); }
virtual void OnFilterText( wxCommandEvent& event ) { event.Skip(); }
virtual void onLoadDirectives( wxCommandEvent& event ) { event.Skip(); } virtual void onLoadDirectives( wxCommandEvent& event ) { event.Skip(); }

View File

@ -743,6 +743,7 @@ void DIALOG_SYMBOL_FIELDS_TABLE::OnFilterMouseMoved( wxMouseEvent& aEvent )
SetCursor( wxCURSOR_IBEAM ); SetCursor( wxCURSOR_IBEAM );
} }
void DIALOG_SYMBOL_FIELDS_TABLE::OnFieldsCtrlSelectionChanged( wxDataViewEvent& event ) void DIALOG_SYMBOL_FIELDS_TABLE::OnFieldsCtrlSelectionChanged( wxDataViewEvent& event )
{ {
int row = m_fieldsCtrl->GetSelectedRow(); int row = m_fieldsCtrl->GetSelectedRow();

View File

@ -143,7 +143,7 @@ void DIALOG_USER_DEFINED_SIGNALS::onScintillaCharAdded( wxStyledTextEvent &aEven
wxStyledTextCtrl* textCtrl = aTricks->Scintilla(); wxStyledTextCtrl* textCtrl = aTricks->Scintilla();
wxArrayString tokens; wxArrayString tokens;
for( const wxString& signal : m_frame->Signals() ) for( const wxString& signal : m_frame->SimPlotVectors() )
tokens.push_back( signal ); tokens.push_back( signal );
tokens.push_back( wxS( "sqrt(x)" ) ); tokens.push_back( wxS( "sqrt(x)" ) );

View File

@ -106,32 +106,32 @@ bool NETLIST_EXPORTER_SPICE::WriteNetlist( const wxString& aOutFileName, unsigne
{ {
m_libMgr.SetReporter( &aReporter ); m_libMgr.SetReporter( &aReporter );
FILE_OUTPUTFORMATTER formatter( aOutFileName, wxT( "wt" ), '\'' ); FILE_OUTPUTFORMATTER formatter( aOutFileName, wxT( "wt" ), '\'' );
return DoWriteNetlist( formatter, aNetlistOptions, aReporter ); return DoWriteNetlist( wxEmptyString, aNetlistOptions, formatter, aReporter );
} }
bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions, bool NETLIST_EXPORTER_SPICE::DoWriteNetlist( const wxString& aSimCommand, unsigned aSimOptions,
REPORTER& aReporter ) OUTPUTFORMATTER& aFormatter, REPORTER& aReporter )
{ {
LOCALE_IO dummy; LOCALE_IO dummy;
// Cleanup list to avoid duplicate if the netlist exporter is run more than once. // Cleanup list to avoid duplicate if the netlist exporter is run more than once.
m_rawIncludes.clear(); m_rawIncludes.clear();
bool result = ReadSchematicAndLibraries( aNetlistOptions, aReporter ); bool result = ReadSchematicAndLibraries( aSimOptions, aReporter );
WriteHead( aFormatter, aNetlistOptions ); WriteHead( aFormatter, aSimOptions );
writeIncludes( aFormatter, aNetlistOptions ); writeIncludes( aFormatter, aSimOptions );
writeModels( aFormatter ); writeModels( aFormatter );
// Skip this if there is no netlist to avoid an ngspice segfault // Skip this if there is no netlist to avoid an ngspice segfault
if( !m_items.empty() ) if( !m_items.empty() )
WriteDirectives( aFormatter, aNetlistOptions ); WriteDirectives( aSimCommand, aSimOptions, aFormatter );
writeItems( aFormatter ); writeItems( aFormatter );
WriteTail( aFormatter, aNetlistOptions ); WriteTail( aFormatter, aSimOptions );
return result; return result;
} }
@ -588,16 +588,16 @@ void NETLIST_EXPORTER_SPICE::writeItems( OUTPUTFORMATTER& aFormatter )
} }
void NETLIST_EXPORTER_SPICE::WriteDirectives( OUTPUTFORMATTER& aFormatter, void NETLIST_EXPORTER_SPICE::WriteDirectives( const wxString& aSimCommand, unsigned aSimOptions,
unsigned aNetlistOptions ) const OUTPUTFORMATTER& aFormatter ) const
{ {
if( aNetlistOptions & OPTION_SAVE_ALL_VOLTAGES ) if( aSimOptions & OPTION_SAVE_ALL_VOLTAGES )
aFormatter.Print( 0, ".save all\n" ); aFormatter.Print( 0, ".save all\n" );
if( aNetlistOptions & OPTION_SAVE_ALL_CURRENTS ) if( aSimOptions & OPTION_SAVE_ALL_CURRENTS )
aFormatter.Print( 0, ".probe alli\n" ); aFormatter.Print( 0, ".probe alli\n" );
if( aNetlistOptions & OPTION_SAVE_ALL_DISSIPATIONS ) if( aSimOptions & OPTION_SAVE_ALL_DISSIPATIONS )
{ {
for( const SPICE_ITEM& item : m_items ) for( const SPICE_ITEM& item : m_items )
{ {
@ -638,7 +638,7 @@ void NETLIST_EXPORTER_SPICE::WriteDirectives( OUTPUTFORMATTER& aFormatter,
|| isSimCommand( candidate, wxS( ".TF" ) ) ); || isSimCommand( candidate, wxS( ".TF" ) ) );
} }
if( !simCommand || ( aNetlistOptions & OPTION_SIM_COMMAND ) ) if( !simCommand || ( aSimOptions & OPTION_SIM_COMMAND ) )
aFormatter.Print( 0, "%s\n", UTF8( directive ).c_str() ); aFormatter.Print( 0, "%s\n", UTF8( directive ).c_str() );
} }
} }

View File

@ -76,8 +76,8 @@ public:
/** /**
* Write the netlist in aFormatter. * Write the netlist in aFormatter.
*/ */
bool DoWriteNetlist( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions, bool DoWriteNetlist( const wxString& aSimCommand, unsigned aSimOptions,
REPORTER& aReporter ); OUTPUTFORMATTER& aFormatter, REPORTER& aReporter );
/** /**
* Write the netlist head (title and so on). * Write the netlist head (title and so on).
@ -132,7 +132,8 @@ public:
protected: protected:
void ReadDirectives( unsigned aNetlistOptions ); void ReadDirectives( unsigned aNetlistOptions );
virtual void WriteDirectives( OUTPUTFORMATTER& candidate, unsigned aNetlistOptions ) const; virtual void WriteDirectives( const wxString& aSimCommand, unsigned aSimOptions,
OUTPUTFORMATTER& candidate ) const;
virtual std::string GenerateItemPinNetName( const std::string& aNetName, virtual std::string GenerateItemPinNetName( const std::string& aNetName,
int& aNcCounter ) const; int& aNcCounter ) const;

View File

@ -251,23 +251,21 @@ std::vector<double> NGSPICE::GetPhaseVector( const std::string& aName, int aMaxL
} }
bool NGSPICE::Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel, REPORTER& aReporter ) bool NGSPICE::Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel, const wxString& aSimCommand,
unsigned aSimOptions, REPORTER& aReporter )
{ {
NGSPICE_CIRCUIT_MODEL* model = dynamic_cast<NGSPICE_CIRCUIT_MODEL*>( aModel.get() ); NGSPICE_CIRCUIT_MODEL* model = dynamic_cast<NGSPICE_CIRCUIT_MODEL*>( aModel.get() );
STRING_FORMATTER formatter; STRING_FORMATTER formatter;
if( model && model->GetNetlist( &formatter, aReporter ) ) if( model && model->GetNetlist( aSimCommand, aSimOptions, &formatter, aReporter ) )
{ {
SIMULATOR::Attach( aModel, aReporter ); SIMULATOR::Attach( aModel, aSimCommand, aSimOptions, aReporter );
LoadNetlist( formatter.GetString() ); LoadNetlist( formatter.GetString() );
return true; return true;
} }
else else
{ {
SIMULATOR::Attach( nullptr, aReporter ); SIMULATOR::Attach( nullptr, wxEmptyString, 0, aReporter );
return false; return false;
} }
} }
@ -335,11 +333,10 @@ wxString NGSPICE::GetXAxis( SIM_TYPE aType ) const
switch( aType ) switch( aType )
{ {
case ST_AC: case ST_AC:
case ST_S_PARAM: case ST_SP:
return wxS( "frequency" );
case ST_NOISE: case ST_NOISE:
return wxS( "noise1.frequency" ); case ST_FFT:
return wxS( "frequency" );
case ST_DC: case ST_DC:
// find plot, which ends with "-sweep" // find plot, which ends with "-sweep"
@ -351,7 +348,7 @@ wxString NGSPICE::GetXAxis( SIM_TYPE aType ) const
return wxS( "sweep" ); return wxS( "sweep" );
case ST_TRANSIENT: case ST_TRAN:
return wxS( "time" ); return wxS( "time" );
default: default:

View File

@ -59,8 +59,8 @@ public:
void Init( const SPICE_SIMULATOR_SETTINGS* aSettings = nullptr ) override final; void Init( const SPICE_SIMULATOR_SETTINGS* aSettings = nullptr ) override final;
///< @copydoc SPICE_SIMULATOR::Attach() ///< @copydoc SPICE_SIMULATOR::Attach()
bool Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel, bool Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel, const wxString& aSimCommand,
REPORTER& aReporter ) override final; unsigned aSimOptions, REPORTER& aReporter ) override final;
///< Load a netlist for the simulation ///< Load a netlist for the simulation
bool LoadNetlist( const std::string& aNetlist ) override final; bool LoadNetlist( const std::string& aNetlist ) override final;

View File

@ -84,13 +84,7 @@ wxString NGSPICE_CIRCUIT_MODEL::GetSchTextSimCommand()
simCmd += wxString::Format( wxT( "%s\r\n" ), directive ); simCmd += wxString::Format( wxT( "%s\r\n" ), directive );
} }
return simCmd; return simCmd.Trim();
}
SIM_TYPE NGSPICE_CIRCUIT_MODEL::GetSimType()
{
return CommandToSimType( GetSimCommand() );
} }
@ -98,28 +92,18 @@ SIM_TYPE NGSPICE_CIRCUIT_MODEL::CommandToSimType( const wxString& aCmd )
{ {
wxString cmd = aCmd.Lower().Trim(); wxString cmd = aCmd.Lower().Trim();
if( cmd.StartsWith( wxT( ".ac" ) ) ) if( cmd == wxT( ".op" ) ) return ST_OP;
return ST_AC; else if( cmd.StartsWith( wxT( ".ac" ) ) ) return ST_AC;
else if( cmd.StartsWith( wxT( ".dc" ) ) ) else if( cmd.StartsWith( wxT( ".dc" ) ) ) return ST_DC;
return ST_DC; else if( cmd.StartsWith( wxT( ".tran" ) ) ) return ST_TRAN;
else if( cmd.StartsWith( wxT( ".tran" ) ) ) else if( cmd.StartsWith( wxT( ".disto" ) ) ) return ST_DISTO;
return ST_TRANSIENT; else if( cmd.StartsWith( wxT( ".noise" ) ) ) return ST_NOISE;
else if( cmd == wxT( ".op" ) ) else if( cmd.StartsWith( wxT( ".pz" ) ) ) return ST_PZ;
return ST_OP; else if( cmd.StartsWith( wxT( ".sens" ) ) ) return ST_SENS;
else if( cmd.StartsWith( wxT( ".disto" ) ) ) else if( cmd.StartsWith( wxT( ".sp" ) ) ) return ST_SP;
return ST_DISTORTION; else if( cmd.StartsWith( wxT( ".tf" ) ) ) return ST_TF;
else if( cmd.StartsWith( wxT( ".noise" ) ) ) else if( cmd.StartsWith( wxT( "fft" ) ) ) return ST_FFT;
return ST_NOISE; else return ST_UNKNOWN;
else if( cmd.StartsWith( wxT( ".pz" ) ) )
return ST_POLE_ZERO;
else if( cmd.StartsWith( wxT( ".sens" ) ) )
return ST_SENSITIVITY;
else if( cmd.StartsWith( wxT( ".sp" ) ) )
return ST_S_PARAM;
else if( cmd.StartsWith( wxT( ".tf" ) ) )
return ST_TRANS_FUNC;
else
return ST_UNKNOWN;
} }
@ -211,14 +195,14 @@ bool NGSPICE_CIRCUIT_MODEL::ParseNoiseCommand( const wxString& aCmd, wxString* a
} }
void NGSPICE_CIRCUIT_MODEL::WriteDirectives( OUTPUTFORMATTER& aFormatter, void NGSPICE_CIRCUIT_MODEL::WriteDirectives( const wxString& aSimCommand, unsigned aSimOptions,
unsigned aNetlistOptions ) const OUTPUTFORMATTER& aFormatter ) const
{ {
if( GetSimCommandOverride().IsEmpty() ) if( aSimCommand.IsEmpty() )
aNetlistOptions |= OPTION_SIM_COMMAND; aSimOptions |= OPTION_SIM_COMMAND;
NETLIST_EXPORTER_SPICE::WriteDirectives( aFormatter, aNetlistOptions ); NETLIST_EXPORTER_SPICE::WriteDirectives( aSimCommand, aSimOptions, aFormatter );
if( !GetSimCommandOverride().IsEmpty() ) if( !aSimCommand.IsEmpty() )
aFormatter.Print( 0, "%s\n", TO_UTF8( GetSimCommandOverride() ) ); aFormatter.Print( 0, "%s\n", TO_UTF8( aSimCommand ) );
} }

View File

@ -48,8 +48,7 @@ class NGSPICE_CIRCUIT_MODEL : public NETLIST_EXPORTER_SPICE, public SIMULATION_M
{ {
public: public:
NGSPICE_CIRCUIT_MODEL( SCHEMATIC_IFACE* aSchematic, wxWindow* aDialogParent = nullptr ) : NGSPICE_CIRCUIT_MODEL( SCHEMATIC_IFACE* aSchematic, wxWindow* aDialogParent = nullptr ) :
NETLIST_EXPORTER_SPICE( aSchematic, aDialogParent ), NETLIST_EXPORTER_SPICE( aSchematic, aDialogParent )
m_options( NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS )
{} {}
virtual ~NGSPICE_CIRCUIT_MODEL() {} virtual ~NGSPICE_CIRCUIT_MODEL() {}
@ -64,60 +63,18 @@ public:
*/ */
SIM_TRACE_TYPE VectorToSignal( const std::string& aVector, wxString& aSignal ) const; SIM_TRACE_TYPE VectorToSignal( const std::string& aVector, wxString& aSignal ) const;
void SetSimOptions( int aOptions ) { m_options = aOptions; } bool GetNetlist( const wxString& aSimCommand, unsigned aSimOptions,
int GetSimOptions() const { return m_options; } OUTPUTFORMATTER* aFormatter, REPORTER& aReporter )
bool GetNetlist( OUTPUTFORMATTER* aFormatter, REPORTER& aReporter )
{ {
return NGSPICE_CIRCUIT_MODEL::DoWriteNetlist( *aFormatter, m_options, aReporter ); return NGSPICE_CIRCUIT_MODEL::DoWriteNetlist( aSimCommand, aSimOptions, *aFormatter,
aReporter );
} }
/**
* Override the simulation command directive.
*/
void SetSimCommandOverride( const wxString& aCmd )
{
if( aCmd != m_simCommand )
{
m_lastSchTextSimCommand = GetSchTextSimCommand();
m_simCommand = aCmd;
}
}
/**
* Return the command directive that is in use (either from the sheet or from m_simCommand)
* @return
*/
wxString GetSimCommand()
{
return m_simCommand.IsEmpty() ? GetSchTextSimCommand() : m_simCommand;
}
/**
* Return the simulation command directive if stored separately (not as a sheet directive).
*/
wxString GetSimCommandOverride() const { return m_simCommand; }
/**
* Return simulation type basing on the simulation command directives.
*
* Simulation directives set using SetSimCommandOverride() have priority over the ones placed in
* schematic sheets.
*/
SIM_TYPE GetSimType();
/** /**
* Return simulation command directives placed in schematic sheets (if any). * Return simulation command directives placed in schematic sheets (if any).
*/ */
wxString GetSchTextSimCommand(); wxString GetSchTextSimCommand();
/**
* Return the sim command present as a sheet directive when the sim command override was last
* updated.
* @return
*/
wxString GetLastSchTextSimCommand() const { return m_lastSchTextSimCommand; }
/** /**
* Parse a two-source .dc command directive into its symbols. * Parse a two-source .dc command directive into its symbols.
* *
@ -145,16 +102,8 @@ public:
static SIM_TYPE CommandToSimType( const wxString& aCmd ); static SIM_TYPE CommandToSimType( const wxString& aCmd );
protected: protected:
void WriteDirectives( OUTPUTFORMATTER& aFormatter, unsigned aNetlistOptions ) const override; void WriteDirectives( const wxString& aSimCommand, unsigned aSimOptions,
OUTPUTFORMATTER& aFormatter ) const override;
private:
///< Custom simulation command (has priority over the schematic sheet simulation commands)
wxString m_simCommand;
///< Value of schematic sheet simulation command when override was last updated
wxString m_lastSchTextSimCommand;
int m_options;
}; };
#endif /* NGSPICE_CIRCUIT_MODEL_H */ #endif /* NGSPICE_CIRCUIT_MODEL_H */

View File

@ -405,10 +405,9 @@ void CURSOR::UpdateReference()
} }
SIM_PLOT_PANEL::SIM_PLOT_PANEL( const wxString& aCommand, int aOptions, wxWindow* parent, SIM_PLOT_PANEL::SIM_PLOT_PANEL( const wxString& aSimCommand, unsigned aSimOptions,
wxWindowID id, const wxPoint& pos, const wxSize& size, long style, wxWindow* parent ) :
const wxString& name ) : SIM_PLOT_PANEL_BASE( aSimCommand, aSimOptions, parent ),
SIM_PLOT_PANEL_BASE( aCommand, aOptions, parent, id, pos, size, style, name ),
m_axis_x( nullptr ), m_axis_x( nullptr ),
m_axis_y1( nullptr ), m_axis_y1( nullptr ),
m_axis_y2( nullptr ), m_axis_y2( nullptr ),
@ -416,7 +415,7 @@ SIM_PLOT_PANEL::SIM_PLOT_PANEL( const wxString& aCommand, int aOptions, wxWindow
m_dotted_cp( false ) m_dotted_cp( false )
{ {
m_sizer = new wxBoxSizer( wxVERTICAL ); m_sizer = new wxBoxSizer( wxVERTICAL );
m_plotWin = new mpWindow( this, wxID_ANY, pos, size, style ); m_plotWin = new mpWindow( this, wxID_ANY );
m_plotWin->LimitView( true ); m_plotWin->LimitView( true );
m_plotWin->SetMargins( 35, 70, 35, 70 ); m_plotWin->SetMargins( 35, 70, 35, 70 );
@ -517,7 +516,7 @@ void SIM_PLOT_PANEL::updateAxes( int aNewTraceType )
m_axis_y2->SetName( _( "Phase" ) ); m_axis_y2->SetName( _( "Phase" ) );
break; break;
case ST_S_PARAM: case ST_SP:
if( !m_axis_x ) if( !m_axis_x )
{ {
m_axis_x = new LOG_SCALE<mpScaleXLog>( wxEmptyString, wxT( "Hz" ), mpALIGN_BOTTOM ); m_axis_x = new LOG_SCALE<mpScaleXLog>( wxEmptyString, wxT( "Hz" ), mpALIGN_BOTTOM );
@ -574,7 +573,23 @@ void SIM_PLOT_PANEL::updateAxes( int aNewTraceType )
break; break;
case ST_TRANSIENT: case ST_FFT:
if( !m_axis_x )
{
m_axis_x = new LOG_SCALE<mpScaleXLog>( wxEmptyString, wxT( "Hz" ), mpALIGN_BOTTOM );
m_axis_x->SetNameAlign( mpALIGN_BOTTOM );
m_plotWin->AddLayer( m_axis_x );
m_axis_y1 = new LIN_SCALE<mpScaleY>( wxEmptyString, wxT( "dB" ), mpALIGN_LEFT );
m_axis_y1->SetNameAlign( mpALIGN_LEFT );
m_plotWin->AddLayer( m_axis_y1 );
}
m_axis_x->SetName( _( "Frequency" ) );
m_axis_y1->SetName( _( "Intensity" ) );
break;
case ST_TRAN:
if( !m_axis_x ) if( !m_axis_x )
{ {
m_axis_x = new TIME_SCALE( wxEmptyString, wxT( "s" ), mpALIGN_BOTTOM ); m_axis_x = new TIME_SCALE( wxEmptyString, wxT( "s" ), mpALIGN_BOTTOM );
@ -777,7 +792,7 @@ TRACE* SIM_PLOT_PANEL::AddTrace( const wxString& aVectorName, int aType )
{ {
updateAxes( aType ); updateAxes( aType );
if( GetSimType() == ST_TRANSIENT || GetSimType() == ST_DC ) if( GetSimType() == ST_TRAN || GetSimType() == ST_DC )
{ {
bool hasVoltageTraces = false; bool hasVoltageTraces = false;
@ -815,27 +830,37 @@ TRACE* SIM_PLOT_PANEL::AddTrace( const wxString& aVectorName, int aType )
void SIM_PLOT_PANEL::SetTraceData( TRACE* trace, unsigned int aPoints, const double* aX, void SIM_PLOT_PANEL::SetTraceData( TRACE* trace, unsigned int aPoints, const double* aX,
const double* aY ) const double* aY )
{ {
std::vector<double> tmp( aY, aY + aPoints ); std::vector<double> x( aX, aX + aPoints );
std::vector<double> y( aY, aY + aPoints );
if( GetSimType() == ST_AC ) if( GetSimType() == ST_AC || GetSimType() == ST_SP || GetSimType() == ST_FFT )
{
// log( 0 ) is not valid.
{
x.erase( x.begin() );
y.erase( y.begin() );
}
}
if( GetSimType() == ST_AC || GetSimType() == ST_FFT )
{ {
if( trace->GetType() & SPT_AC_PHASE ) if( trace->GetType() & SPT_AC_PHASE )
{ {
for( unsigned int i = 0; i < aPoints; i++ ) for( unsigned int i = 0; i < aPoints; i++ )
tmp[i] = tmp[i] * 180.0 / M_PI; // convert to degrees y[i] = y[i] * 180.0 / M_PI; // convert to degrees
} }
else else
{ {
for( unsigned int i = 0; i < aPoints; i++ ) for( unsigned int i = 0; i < aPoints; i++ )
{ {
// log( 0 ) is not valid. // log( 0 ) is not valid.
if( tmp[i] != 0 ) if( y[i] != 0 )
tmp[i] = 20 * log( tmp[i] ) / log( 10.0 ); // convert to dB y[i] = 20 * log( y[i] ) / log( 10.0 ); // convert to dB
} }
} }
} }
trace->SetData( std::vector<double>( aX, aX + aPoints ), tmp ); trace->SetData( x, y );
if( ( trace->GetType() & SPT_AC_PHASE ) || ( trace->GetType() & SPT_CURRENT ) ) if( ( trace->GetType() & SPT_AC_PHASE ) || ( trace->GetType() & SPT_CURRENT ) )
trace->SetScale( m_axis_x, m_axis_y2 ); trace->SetScale( m_axis_x, m_axis_y2 );

View File

@ -194,9 +194,7 @@ protected:
class SIM_PLOT_PANEL : public SIM_PLOT_PANEL_BASE class SIM_PLOT_PANEL : public SIM_PLOT_PANEL_BASE
{ {
public: public:
SIM_PLOT_PANEL( const wxString& aCommand, int aOptions, wxWindow* parent, wxWindowID id, SIM_PLOT_PANEL( const wxString& aSimCommand, unsigned aSimOptions, wxWindow* parent );
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = 0, const wxString& name = wxPanelNameStr );
virtual ~SIM_PLOT_PANEL(); virtual ~SIM_PLOT_PANEL();
@ -239,10 +237,18 @@ public:
void ShowGrid( bool aEnable ) void ShowGrid( bool aEnable )
{ {
m_axis_x->SetTicks( !aEnable ); if( m_axis_x )
m_axis_y1->SetTicks( !aEnable ); m_axis_x->SetTicks( !aEnable );
m_axis_y2->SetTicks( !aEnable );
m_axis_y3->SetTicks( !aEnable ); if( m_axis_y1 )
m_axis_y1->SetTicks( !aEnable );
if( m_axis_y2 )
m_axis_y2->SetTicks( !aEnable );
if( m_axis_y3 )
m_axis_y3->SetTicks( !aEnable );
m_plotWin->UpdateAll(); m_plotWin->UpdateAll();
} }
@ -320,6 +326,8 @@ public:
bool DeleteTrace( const wxString& aVectorName, int aTraceType ); bool DeleteTrace( const wxString& aVectorName, int aTraceType );
void DeleteTrace( TRACE* aTrace ); void DeleteTrace( TRACE* aTrace );
std::vector<std::pair<wxString, wxString>>& Measurements() { return m_measurements; }
private: private:
wxString getTraceId( const wxString& aVectorName, int aType ) const wxString getTraceId( const wxString& aVectorName, int aType ) const
{ {
@ -349,6 +357,9 @@ private:
mpInfoLegend* m_legend; mpInfoLegend* m_legend;
bool m_dotted_cp; bool m_dotted_cp;
// Measurements (and their format strings)
std::vector<std::pair<wxString, wxString>> m_measurements;
}; };
wxDECLARE_EVENT( EVT_SIM_CURSOR_UPDATE, wxCommandEvent ); wxDECLARE_EVENT( EVT_SIM_CURSOR_UPDATE, wxCommandEvent );

View File

@ -37,12 +37,11 @@ SIM_PLOT_PANEL_BASE::SIM_PLOT_PANEL_BASE() :
} }
SIM_PLOT_PANEL_BASE::SIM_PLOT_PANEL_BASE( const wxString& aCommand, int aOptions, wxWindow* parent, SIM_PLOT_PANEL_BASE::SIM_PLOT_PANEL_BASE( const wxString& aSimCommand, unsigned aSimOptions,
wxWindowID id, const wxPoint& pos, const wxSize& size, wxWindow* parent ) :
long style, const wxString& name ) : wxWindow( parent, wxID_ANY ),
wxWindow( parent, id, pos, size, style, name ), m_simCommand( aSimCommand ),
m_simCommand( aCommand ), m_simOptions( aSimOptions )
m_simOptions( aOptions )
{ {
} }
@ -58,9 +57,10 @@ bool SIM_PLOT_PANEL_BASE::IsPlottable( SIM_TYPE aSimType )
{ {
case ST_AC: case ST_AC:
case ST_DC: case ST_DC:
case ST_S_PARAM: case ST_SP:
case ST_TRANSIENT: case ST_TRAN:
case ST_NOISE: case ST_NOISE:
case ST_FFT:
return true; return true;
default: default:
@ -75,10 +75,9 @@ SIM_TYPE SIM_PLOT_PANEL_BASE::GetSimType() const
} }
SIM_NOPLOT_PANEL::SIM_NOPLOT_PANEL( const wxString& aCommand, int aOptions, wxWindow* parent, SIM_NOPLOT_PANEL::SIM_NOPLOT_PANEL( const wxString& aSimCommand, unsigned aSimOptions,
wxWindowID id, const wxPoint& pos, const wxSize& size, wxWindow* parent ) :
long style, const wxString& name ) : SIM_PLOT_PANEL_BASE( aSimCommand, aSimOptions, parent )
SIM_PLOT_PANEL_BASE( aCommand, aOptions, parent, id, pos, size, style, name )
{ {
m_sizer = new wxBoxSizer( wxVERTICAL ); m_sizer = new wxBoxSizer( wxVERTICAL );
m_sizer->Add( 0, 1, 1, wxEXPAND, 5 ); m_sizer->Add( 0, 1, 1, wxEXPAND, 5 );

View File

@ -26,8 +26,8 @@
#ifndef __SIM_PLOT_PANEL_BASE_H #ifndef __SIM_PLOT_PANEL_BASE_H
#define __SIM_PLOT_PANEL_BASE_H #define __SIM_PLOT_PANEL_BASE_H
#include "sim_types.h" #include <sim/sim_types.h>
#include "ngspice_circuit_model.h" #include <sim/ngspice_circuit_model.h>
#include <wx/panel.h> #include <wx/panel.h>
#include <wx/sizer.h> #include <wx/sizer.h>
#include <wx/stattext.h> #include <wx/stattext.h>
@ -37,9 +37,7 @@ class SIM_PLOT_PANEL_BASE : public wxWindow
{ {
public: public:
SIM_PLOT_PANEL_BASE(); SIM_PLOT_PANEL_BASE();
SIM_PLOT_PANEL_BASE( const wxString& aCommand, int aOptions, wxWindow* parent, wxWindowID id, SIM_PLOT_PANEL_BASE( const wxString& aSimCommand, unsigned aSimOptions, wxWindow* parent );
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = 0, const wxString& name = wxPanelNameStr );
virtual ~SIM_PLOT_PANEL_BASE(); virtual ~SIM_PLOT_PANEL_BASE();
static bool IsPlottable( SIM_TYPE aSimType ); static bool IsPlottable( SIM_TYPE aSimType );
@ -49,29 +47,29 @@ public:
SIM_TYPE GetSimType() const; SIM_TYPE GetSimType() const;
const wxString& GetSimCommand() const { return m_simCommand; } const wxString& GetSimCommand() const { return m_simCommand; }
void SetSimCommand( const wxString& aSimCommand ) void SetSimCommand( const wxString& aSimCommand ) { m_simCommand = aSimCommand; }
{
wxCHECK_RET( GetSimType() == NGSPICE_CIRCUIT_MODEL::CommandToSimType( aSimCommand ),
"Cannot change the type of simulation of the existing plot panel" );
m_simCommand = aSimCommand;
}
int GetSimOptions() const { return m_simOptions; } int GetSimOptions() const { return m_simOptions; }
void SetSimOptions( int aOptions ) { m_simOptions = aOptions; } void SetSimOptions( int aOptions ) { m_simOptions = aOptions; }
wxString GetLastSchTextSimCommand() const { return m_lastSchTextSimCommand; }
void SetLastSchTextSimCommand( const wxString& aCmd ) { m_lastSchTextSimCommand = aCmd; }
const wxString& GetSpicePlotName() const { return m_spicePlotName; }
void SetSpicePlotName( const wxString& aPlotName ) { m_spicePlotName = aPlotName; }
private: private:
wxString m_simCommand; wxString m_simCommand;
int m_simOptions; unsigned m_simOptions;
wxString m_lastSchTextSimCommand;
wxString m_spicePlotName;
}; };
class SIM_NOPLOT_PANEL : public SIM_PLOT_PANEL_BASE class SIM_NOPLOT_PANEL : public SIM_PLOT_PANEL_BASE
{ {
public: public:
SIM_NOPLOT_PANEL( const wxString& aCommand, int aOptions, wxWindow* parent, wxWindowID id, SIM_NOPLOT_PANEL( const wxString& aSimCommand, unsigned aSimOptions, wxWindow* parent );
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = 0, const wxString& name = wxPanelNameStr );
virtual ~SIM_NOPLOT_PANEL(); virtual ~SIM_NOPLOT_PANEL();

View File

@ -33,14 +33,16 @@ enum SIM_TYPE
ST_UNKNOWN, ST_UNKNOWN,
ST_AC, ST_AC,
ST_DC, ST_DC,
ST_DISTORTION, ST_DISTO,
ST_NOISE, ST_NOISE,
ST_OP, ST_OP,
ST_POLE_ZERO, ST_PZ,
ST_SENSITIVITY, ST_SENS,
ST_TRANS_FUNC, ST_TF,
ST_TRANSIENT, ST_TRAN,
ST_S_PARAM ST_SP,
ST_FFT,
ST_LAST
}; };
///< Possible trace types ///< Possible trace types

View File

@ -58,7 +58,8 @@ public:
* *
* @return True in case of success, false otherwise. * @return True in case of success, false otherwise.
*/ */
virtual bool Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel, REPORTER& aReporter ) virtual bool Attach( const std::shared_ptr<SIMULATION_MODEL>& aModel,
const wxString& aSimCommand, unsigned aSimOptions, REPORTER& aReporter )
{ {
m_simModel = aModel; m_simModel = aModel;
return true; return true;

View File

@ -113,7 +113,6 @@ SIMULATOR_FRAME::SIMULATOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
m_schematicFrame( nullptr ), m_schematicFrame( nullptr ),
m_toolBar( nullptr ), m_toolBar( nullptr ),
m_panel( nullptr ), m_panel( nullptr ),
m_lastSimPlot( nullptr ),
m_simFinished( false ), m_simFinished( false ),
m_workbookModified( false ) m_workbookModified( false )
{ {
@ -168,7 +167,7 @@ SIMULATOR_FRAME::SIMULATOR_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
Bind( wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( SIMULATOR_FRAME::onExit ), this, Bind( wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler( SIMULATOR_FRAME::onExit ), this,
wxID_EXIT ); wxID_EXIT );
Bind( EVT_SIM_UPDATE, &SIMULATOR_FRAME::onSimUpdate, this ); Bind( EVT_SIM_UPDATE, &SIMULATOR_FRAME::onUpdateSim, this );
Bind( EVT_SIM_REPORT, &SIMULATOR_FRAME::onSimReport, this ); Bind( EVT_SIM_REPORT, &SIMULATOR_FRAME::onSimReport, this );
Bind( EVT_SIM_STARTED, &SIMULATOR_FRAME::onSimStarted, this ); Bind( EVT_SIM_STARTED, &SIMULATOR_FRAME::onSimStarted, this );
Bind( EVT_SIM_FINISHED, &SIMULATOR_FRAME::onSimFinished, this ); Bind( EVT_SIM_FINISHED, &SIMULATOR_FRAME::onSimFinished, this );
@ -196,7 +195,7 @@ SIMULATOR_FRAME::~SIMULATOR_FRAME()
{ {
NULL_REPORTER devnull; NULL_REPORTER devnull;
m_simulator->Attach( nullptr, devnull ); m_simulator->Attach( nullptr, wxEmptyString, 0, devnull );
m_simulator->SetReporter( nullptr ); m_simulator->SetReporter( nullptr );
delete m_reporter; delete m_reporter;
} }
@ -285,8 +284,8 @@ WINDOW_SETTINGS* SIMULATOR_FRAME::GetWindowSettings( APP_SETTINGS_BASE* aCfg )
wxString SIMULATOR_FRAME::GetCurrentSimCommand() const wxString SIMULATOR_FRAME::GetCurrentSimCommand() const
{ {
if( m_panel->GetCurrentPlotWindow() ) if( m_panel->GetCurrentPlotPanel() )
return m_panel->GetCurrentPlotWindow()->GetSimCommand(); return m_panel->GetCurrentPlotPanel()->GetSimCommand();
else else
return m_circuitModel->GetSchTextSimCommand(); return m_circuitModel->GetSchTextSimCommand();
} }
@ -300,10 +299,10 @@ SIM_TYPE SIMULATOR_FRAME::GetCurrentSimType() const
int SIMULATOR_FRAME::GetCurrentOptions() const int SIMULATOR_FRAME::GetCurrentOptions() const
{ {
if( m_panel->GetCurrentPlotWindow() ) if( SIM_PLOT_PANEL_BASE* plotPanel = m_panel->GetCurrentPlotPanel() )
return m_panel->GetCurrentPlotWindow()->GetSimOptions(); return plotPanel->GetSimOptions();
else else
return m_circuitModel->GetSimOptions(); return NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS;
} }
@ -338,7 +337,7 @@ void SIMULATOR_FRAME::UpdateTitle()
bool SIMULATOR_FRAME::LoadSimulator() bool SIMULATOR_FRAME::LoadSimulator( const wxString& aSimCommand, unsigned aSimOptions )
{ {
wxString errors; wxString errors;
WX_STRING_REPORTER reporter( &errors ); WX_STRING_REPORTER reporter( &errors );
@ -350,7 +349,7 @@ bool SIMULATOR_FRAME::LoadSimulator()
if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity ) if( ADVANCED_CFG::GetCfg().m_IncrementalConnectivity )
m_schematicFrame->RecalculateConnections( nullptr, GLOBAL_CLEANUP ); m_schematicFrame->RecalculateConnections( nullptr, GLOBAL_CLEANUP );
if( !m_simulator->Attach( m_circuitModel, reporter ) ) if( !m_simulator->Attach( m_circuitModel, aSimCommand, aSimOptions, reporter ) )
{ {
DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" ) + errors ); DisplayErrorMessage( this, _( "Errors during netlist generation.\n\n" ) + errors );
return false; return false;
@ -362,56 +361,69 @@ bool SIMULATOR_FRAME::LoadSimulator()
void SIMULATOR_FRAME::StartSimulation() void SIMULATOR_FRAME::StartSimulation()
{ {
if( m_circuitModel->CommandToSimType( GetCurrentSimCommand() ) == ST_UNKNOWN ) SIM_PLOT_PANEL_BASE* plotPanel = m_panel->GetCurrentPlotPanel();
if( !plotPanel )
return;
if( plotPanel->GetSimCommand().Upper().StartsWith( wxT( "FFT" ) ) )
{ {
if( !EditSimCommand() ) wxString tranSpicePlot;
return;
if( m_circuitModel->CommandToSimType( GetCurrentSimCommand() ) == ST_UNKNOWN ) if( SIM_PLOT_PANEL_BASE* tranPlotPanel = m_panel->GetPlotPanel( ST_TRAN ) )
return; tranSpicePlot = tranPlotPanel->GetSpicePlotName();
}
wxString schTextSimCommand = m_circuitModel->GetSchTextSimCommand(); if( tranSpicePlot.IsEmpty() )
SIM_TYPE schTextSimType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( schTextSimCommand ); {
SIM_PLOT_PANEL_BASE* plotWindow = m_panel->GetCurrentPlotWindow(); DisplayErrorMessage( this, _( "You must run a TRAN simulation first; its results"
"will be used for the fast Fourier transform." ) );
}
else
{
m_simulator->Command( "setplot " + tranSpicePlot.ToStdString() );
if( !plotWindow ) wxArrayString commands = wxSplit( plotPanel->GetSimCommand(), '\n' );
{
NewPlotPanel( schTextSimCommand, m_circuitModel->GetSimOptions() ); for( const wxString& command : commands )
OnModify(); {
wxBusyCursor wait;
m_simulator->Command( command.ToStdString() );
}
plotPanel->SetSpicePlotName( m_simulator->CurrentPlotName() );
m_panel->OnSimRefresh( true );
#if 0
m_simulator->Command( "setplot" ); // Print available plots to console
m_simulator->Command( "display" ); // Print vectors in current plot to console
#endif
}
return;
} }
else else
{ {
m_circuitModel->SetSimCommandOverride( plotWindow->GetSimCommand() ); if( m_panel->GetPlotIndex( plotPanel ) == 0
&& m_circuitModel->GetSchTextSimCommand() != plotPanel->GetLastSchTextSimCommand() )
if( plotWindow->GetSimType() == schTextSimType
&& schTextSimCommand != m_circuitModel->GetLastSchTextSimCommand() )
{ {
if( IsOK( this, _( "Schematic sheet simulation command directive has changed. " if( IsOK( this, _( "Schematic sheet simulation command directive has changed. "
"Do you wish to update the Simulation Command?" ) ) ) "Do you wish to update the Simulation Command?" ) ) )
{ {
m_circuitModel->SetSimCommandOverride( wxEmptyString ); plotPanel->SetSimCommand( m_circuitModel->GetSchTextSimCommand() );
plotWindow->SetSimCommand( schTextSimCommand ); plotPanel->SetLastSchTextSimCommand( plotPanel->GetSimCommand() );
OnModify(); OnModify();
} }
} }
} }
m_circuitModel->SetSimOptions( GetCurrentOptions() ); if( !LoadSimulator( plotPanel->GetSimCommand(), plotPanel->GetSimOptions() ) )
if( !LoadSimulator() )
return; return;
std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock ); std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
if( simulatorLock.owns_lock() ) if( simulatorLock.owns_lock() )
{ {
wxBusyCursor toggle;
m_panel->OnSimUpdate(); m_panel->OnSimUpdate();
// Prevents memory leak on succeding simulations by deleting old vectors
m_simulator->Clean();
m_simulator->Run(); m_simulator->Run();
} }
else else
@ -421,12 +433,18 @@ void SIMULATOR_FRAME::StartSimulation()
} }
void SIMULATOR_FRAME::NewPlotPanel( const wxString& aSimCommand, int aOptions ) void SIMULATOR_FRAME::NewPlotPanel( const wxString& aSimCommand, unsigned aOptions )
{ {
m_panel->NewPlotPanel( aSimCommand, aOptions ); m_panel->NewPlotPanel( aSimCommand, aOptions );
} }
const std::vector<wxString> SIMULATOR_FRAME::SimPlotVectors()
{
return m_panel->SimPlotVectors();
}
const std::vector<wxString> SIMULATOR_FRAME::Signals() const std::vector<wxString> SIMULATOR_FRAME::Signals()
{ {
return m_panel->Signals(); return m_panel->Signals();
@ -463,9 +481,9 @@ void SIMULATOR_FRAME::AddTuner( const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aS
} }
SIM_PLOT_PANEL* SIMULATOR_FRAME::GetCurrentPlot() const SIM_PLOT_PANEL_BASE* SIMULATOR_FRAME::GetCurrentPlotPanel() const
{ {
return m_panel->GetCurrentPlot(); return m_panel->GetCurrentPlotPanel();
} }
@ -511,11 +529,14 @@ void SIMULATOR_FRAME::ToggleDarkModePlots()
bool SIMULATOR_FRAME::EditSimCommand() bool SIMULATOR_FRAME::EditSimCommand()
{ {
SIM_PLOT_PANEL_BASE* plotPanelWindow = m_panel->GetCurrentPlotWindow(); SIM_PLOT_PANEL_BASE* plotPanel = m_panel->GetCurrentPlotPanel();
DIALOG_SIM_COMMAND dlg( this, m_circuitModel, m_simulator->Settings() ); DIALOG_SIM_COMMAND dlg( this, m_circuitModel, m_simulator->Settings() );
wxString errors; wxString errors;
WX_STRING_REPORTER reporter( &errors ); WX_STRING_REPORTER reporter( &errors );
if( !plotPanel )
return false;
if( !m_circuitModel->ReadSchematicAndLibraries( NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS, if( !m_circuitModel->ReadSchematicAndLibraries( NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS,
reporter ) ) reporter ) )
{ {
@ -523,55 +544,15 @@ bool SIMULATOR_FRAME::EditSimCommand()
+ errors ); + errors );
} }
if( m_panel->GetPlotIndex( plotPanelWindow ) != wxNOT_FOUND ) dlg.SetSimCommand( plotPanel->GetSimCommand() );
{ dlg.SetSimOptions( plotPanel->GetSimOptions() );
dlg.SetSimCommand( plotPanelWindow->GetSimCommand() );
dlg.SetSimOptions( plotPanelWindow->GetSimOptions() );
}
else
{
dlg.SetSimOptions( NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS );
}
if( dlg.ShowModal() == wxID_OK ) if( dlg.ShowModal() == wxID_OK )
{ {
wxString oldCommand; plotPanel->SetSimCommand( dlg.GetSimCommand() );
plotPanel->SetSimOptions( dlg.GetSimOptions() );
if( m_panel->GetPlotIndex( plotPanelWindow ) != wxNOT_FOUND ) m_panel->OnPlotSettingsChanged();
oldCommand = plotPanelWindow->GetSimCommand();
else
oldCommand = wxString();
const wxString& newCommand = dlg.GetSimCommand();
int newOptions = dlg.GetSimOptions();
SIM_TYPE newSimType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( newCommand );
if( !plotPanelWindow )
{
m_circuitModel->SetSimCommandOverride( newCommand );
m_circuitModel->SetSimOptions( newOptions );
NewPlotPanel( newCommand, newOptions );
}
// If it is a new simulation type, open a new plot. For the DC sim, check if sweep
// source type has changed (char 4 will contain 'v', 'i', 'r' or 't'.
else if( plotPanelWindow->GetSimType() != newSimType
|| ( newSimType == ST_DC
&& oldCommand.Lower().GetChar( 4 ) != newCommand.Lower().GetChar( 4 ) ) )
{
NewPlotPanel( newCommand, newOptions );
}
else
{
if( m_panel->GetPlotIndex( plotPanelWindow ) == 0 )
m_circuitModel->SetSimCommandOverride( newCommand );
// Update simulation command in the current plot
plotPanelWindow->SetSimCommand( newCommand );
plotPanelWindow->SetSimOptions( newOptions );
}
OnModify(); OnModify();
m_simulator->Init();
return true; return true;
} }
@ -633,22 +614,22 @@ void SIMULATOR_FRAME::setupUIConditions()
auto showGridCondition = auto showGridCondition =
[this]( const SELECTION& aSel ) [this]( const SELECTION& aSel )
{ {
SIM_PLOT_PANEL* plot = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
return plot && plot->IsGridShown(); return plotPanel && plotPanel->IsGridShown();
}; };
auto showLegendCondition = auto showLegendCondition =
[this]( const SELECTION& aSel ) [this]( const SELECTION& aSel )
{ {
SIM_PLOT_PANEL* plot = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
return plot && plot->IsLegendShown(); return plotPanel && plotPanel->IsLegendShown();
}; };
auto showDottedCondition = auto showDottedCondition =
[this]( const SELECTION& aSel ) [this]( const SELECTION& aSel )
{ {
SIM_PLOT_PANEL* plot = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
return plot && plot->GetDottedSecondary(); return plotPanel && plotPanel->GetDottedSecondary();
}; };
auto darkModePlotCondition = auto darkModePlotCondition =
@ -669,10 +650,16 @@ void SIMULATOR_FRAME::setupUIConditions()
return m_simFinished; return m_simFinished;
}; };
auto haveSim =
[this]( const SELECTION& aSel )
{
return GetCurrentPlotPanel() != nullptr;
};
auto havePlot = auto havePlot =
[this]( const SELECTION& aSel ) [this]( const SELECTION& aSel )
{ {
return GetCurrentPlot() != nullptr; return dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() ) != nullptr;
}; };
#define ENABLE( x ) ACTION_CONDITIONS().Enable( x ) #define ENABLE( x ) ACTION_CONDITIONS().Enable( x )
@ -690,7 +677,8 @@ void SIMULATOR_FRAME::setupUIConditions()
mgr->SetConditions( EE_ACTIONS::toggleDottedSecondary, CHECK( showDottedCondition ) ); mgr->SetConditions( EE_ACTIONS::toggleDottedSecondary, CHECK( showDottedCondition ) );
mgr->SetConditions( EE_ACTIONS::toggleDarkModePlots, CHECK( darkModePlotCondition ) ); mgr->SetConditions( EE_ACTIONS::toggleDarkModePlots, CHECK( darkModePlotCondition ) );
mgr->SetConditions( EE_ACTIONS::simCommand, ENABLE( SELECTION_CONDITIONS::ShowAlways ) ); mgr->SetConditions( EE_ACTIONS::newPlot, ENABLE( SELECTION_CONDITIONS::ShowAlways ) );
mgr->SetConditions( EE_ACTIONS::simCommand, ENABLE( haveSim ) );
mgr->SetConditions( EE_ACTIONS::runSimulation, ENABLE( !simRunning ) ); mgr->SetConditions( EE_ACTIONS::runSimulation, ENABLE( !simRunning ) );
mgr->SetConditions( EE_ACTIONS::stopSimulation, ENABLE( simRunning ) ); mgr->SetConditions( EE_ACTIONS::stopSimulation, ENABLE( simRunning ) );
mgr->SetConditions( EE_ACTIONS::simProbe, ENABLE( simFinished ) ); mgr->SetConditions( EE_ACTIONS::simProbe, ENABLE( simFinished ) );
@ -710,13 +698,6 @@ void SIMULATOR_FRAME::onSimStarted( wxCommandEvent& aEvent )
void SIMULATOR_FRAME::onSimFinished( wxCommandEvent& aEvent ) void SIMULATOR_FRAME::onSimFinished( wxCommandEvent& aEvent )
{ {
SetCursor( wxCURSOR_ARROW );
SIM_TYPE simType = m_circuitModel->GetSimType();
if( simType == ST_UNKNOWN )
return;
// Sometimes (for instance with a directive like wrdata my_file.csv "my_signal") // Sometimes (for instance with a directive like wrdata my_file.csv "my_signal")
// the simulator is in idle state (simulation is finished), but still running, during // the simulator is in idle state (simulation is finished), but still running, during
// the time the file is written. So gives a slice of time to fully finish the work: // the time the file is written. So gives a slice of time to fully finish the work:
@ -745,12 +726,10 @@ void SIMULATOR_FRAME::onSimFinished( wxCommandEvent& aEvent )
m_schematicFrame->RefreshOperatingPointDisplay(); m_schematicFrame->RefreshOperatingPointDisplay();
m_schematicFrame->GetCanvas()->Refresh(); m_schematicFrame->GetCanvas()->Refresh();
m_lastSimPlot = m_panel->GetCurrentPlotWindow();
} }
void SIMULATOR_FRAME::onSimUpdate( wxCommandEvent& aEvent ) void SIMULATOR_FRAME::onUpdateSim( wxCommandEvent& aEvent )
{ {
static bool updateInProgress = false; static bool updateInProgress = false;
@ -763,25 +742,16 @@ void SIMULATOR_FRAME::onSimUpdate( wxCommandEvent& aEvent )
if( m_simulator->IsRunning() ) if( m_simulator->IsRunning() )
m_simulator->Stop(); m_simulator->Stop();
if( m_panel->GetCurrentPlotWindow() != m_lastSimPlot ) std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock );
if( simulatorLock.owns_lock() )
{ {
// We need to rerun simulation, as the simulator currently stores results for another m_panel->OnSimUpdate();
// plot m_simulator->Run();
StartSimulation();
} }
else else
{ {
std::unique_lock<std::mutex> simulatorLock( m_simulator->GetMutex(), std::try_to_lock ); DisplayErrorMessage( this, _( "Another simulation is already running." ) );
if( simulatorLock.owns_lock() )
{
m_panel->OnSimUpdate();
m_simulator->Run();
}
else
{
DisplayErrorMessage( this, _( "Another simulation is already running." ) );
}
} }
updateInProgress = false; updateInProgress = false;

View File

@ -77,7 +77,7 @@ public:
* Check and load the current netlist into the simulator. * Check and load the current netlist into the simulator.
* @return true if document is fully annotated and netlist was loaded successfully. * @return true if document is fully annotated and netlist was loaded successfully.
*/ */
bool LoadSimulator(); bool LoadSimulator( const wxString& aSimCommand, unsigned aSimOptions );
void StartSimulation(); void StartSimulation();
@ -87,7 +87,7 @@ public:
* @param aSimCommand is requested simulation command. * @param aSimCommand is requested simulation command.
* @param aSimOptions netlisting options * @param aSimOptions netlisting options
*/ */
void NewPlotPanel( const wxString& aSimCommand, int aSimOptions ); void NewPlotPanel( const wxString& aSimCommand, unsigned aSimOptions );
/** /**
* Shows a dialog for editing the current tab's simulation command, or creating a new tab * Shows a dialog for editing the current tab's simulation command, or creating a new tab
@ -96,7 +96,12 @@ public:
bool EditSimCommand(); bool EditSimCommand();
/** /**
* @return the list of signals in the current simulation results. * @return the list of vectors (signals) in the current simulation results.
*/
const std::vector<wxString> SimPlotVectors();
/**
* @return the list of schematic signals + any user defined signals.
*/ */
const std::vector<wxString> Signals(); const std::vector<wxString> Signals();
@ -127,7 +132,7 @@ public:
/** /**
* Return the current tab (or NULL if there is none). * Return the current tab (or NULL if there is none).
*/ */
SIM_PLOT_PANEL* GetCurrentPlot() const; SIM_PLOT_PANEL_BASE* GetCurrentPlotPanel() const;
/** /**
* Toggle dark-mode of the plot tabs. * Toggle dark-mode of the plot tabs.
@ -187,7 +192,7 @@ private:
bool canCloseWindow( wxCloseEvent& aEvent ) override; bool canCloseWindow( wxCloseEvent& aEvent ) override;
void doCloseWindow() override; void doCloseWindow() override;
void onSimUpdate( wxCommandEvent& aEvent ); void onUpdateSim( wxCommandEvent& aEvent );
void onSimReport( wxCommandEvent& aEvent ); void onSimReport( wxCommandEvent& aEvent );
void onSimStarted( wxCommandEvent& aEvent ); void onSimStarted( wxCommandEvent& aEvent );
void onSimFinished( wxCommandEvent& aEvent ); void onSimFinished( wxCommandEvent& aEvent );
@ -203,7 +208,6 @@ private:
SIM_THREAD_REPORTER* m_reporter; SIM_THREAD_REPORTER* m_reporter;
std::shared_ptr<NGSPICE_CIRCUIT_MODEL> m_circuitModel; std::shared_ptr<NGSPICE_CIRCUIT_MODEL> m_circuitModel;
SIM_PLOT_PANEL_BASE* m_lastSimPlot;
bool m_simFinished; bool m_simFinished;
bool m_workbookModified; bool m_workbookModified;
}; };

View File

@ -37,13 +37,12 @@
#include <eda_pattern_match.h> #include <eda_pattern_match.h>
#include <string_utils.h> #include <string_utils.h>
#include <pgm_base.h> #include <pgm_base.h>
#include "ngspice.h" #include <sim/simulator_panel.h>
#include "simulator_panel.h"
#include <sim/simulator_frame.h> #include <sim/simulator_frame.h>
#include <sim/sim_plot_panel.h> #include <sim/sim_plot_panel.h>
#include <sim/spice_simulator.h> #include <sim/spice_simulator.h>
#include "fmt/format.h" #include "fmt/format.h"
#include "dialogs/dialog_text_entry.h" #include <dialogs/dialog_text_entry.h>
#include <dialogs/dialog_sim_format_value.h> #include <dialogs/dialog_sim_format_value.h>
#include <eeschema_settings.h> #include <eeschema_settings.h>
@ -135,26 +134,29 @@ void SIGNALS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
m_grid->SetGridCursor( m_menuRow, m_menuCol ); m_grid->SetGridCursor( m_menuRow, m_menuCol );
wxString msg = m_grid->GetCellValue( m_menuRow, m_menuCol ); if( SIM_PLOT_PANEL_BASE* panel = m_parent->GetCurrentPlotPanel() )
menu.Append( MYID_MEASURE_MIN, _( "Measure Min" ) );
menu.Append( MYID_MEASURE_MAX, _( "Measure Max" ) );
menu.Append( MYID_MEASURE_AVG, _( "Measure Average" ) );
menu.Append( MYID_MEASURE_RMS, _( "Measure RMS" ) );
menu.Append( MYID_MEASURE_PP, _( "Measure Peak-to-peak" ) );
menu.Append( MYID_MEASURE_MIN_AT, _( "Measure Time of Min" ) );
menu.Append( MYID_MEASURE_MAX_AT, _( "Measure Time of Max" ) );
menu.Append( MYID_MEASURE_INTEGRAL, _( "Measure Integral" ) );
SIM_PLOT_PANEL* panel = m_parent->GetCurrentPlot();
if( panel && panel->GetSimType() == ST_TRANSIENT )
{ {
menu.AppendSeparator(); if( panel->GetSimType() == ST_TRAN || panel->GetSimType() == ST_AC
menu.Append( MYID_FOURIER, _( "Perform Fourier Analysis..." ) ); || panel->GetSimType() == ST_DC || panel->GetSimType() == ST_SP )
} {
menu.Append( MYID_MEASURE_MIN, _( "Measure Min" ) );
menu.Append( MYID_MEASURE_MAX, _( "Measure Max" ) );
menu.Append( MYID_MEASURE_AVG, _( "Measure Average" ) );
menu.Append( MYID_MEASURE_RMS, _( "Measure RMS" ) );
menu.Append( MYID_MEASURE_PP, _( "Measure Peak-to-peak" ) );
menu.Append( MYID_MEASURE_MIN_AT, _( "Measure Time of Min" ) );
menu.Append( MYID_MEASURE_MAX_AT, _( "Measure Time of Max" ) );
menu.Append( MYID_MEASURE_INTEGRAL, _( "Measure Integral" ) );
menu.AppendSeparator(); if( panel->GetSimType() == ST_TRAN )
{
menu.AppendSeparator();
menu.Append( MYID_FOURIER, _( "Perform Fourier Analysis..." ) );
}
menu.AppendSeparator();
}
}
} }
GRID_TRICKS::showPopupMenu( menu, aEvent ); GRID_TRICKS::showPopupMenu( menu, aEvent );
@ -588,10 +590,12 @@ void SIMULATOR_PANEL::InitWorkbook()
if( !LoadWorkbook( filename.GetFullPath() ) ) if( !LoadWorkbook( filename.GetFullPath() ) )
simulator()->Settings()->SetWorkbookFilename( "" ); simulator()->Settings()->SetWorkbookFilename( "" );
} }
else if( m_simulatorFrame->LoadSimulator() ) else if( m_simulatorFrame->LoadSimulator( wxEmptyString, 0 ) )
{ {
if( !circuitModel()->GetSchTextSimCommand().IsEmpty() ) wxString schTextSimCommand = circuitModel()->GetSchTextSimCommand();
NewPlotPanel( circuitModel()->GetSchTextSimCommand(), circuitModel()->GetSimOptions() );
if( !schTextSimCommand.IsEmpty() )
NewPlotPanel( schTextSimCommand, NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS );
rebuildSignalsList(); rebuildSignalsList();
rebuildSignalsGrid( m_filter->GetValue() ); rebuildSignalsGrid( m_filter->GetValue() );
@ -627,16 +631,34 @@ void SIMULATOR_PANEL::rebuildSignalsGrid( wxString aFilter )
if( aFilter.IsEmpty() ) if( aFilter.IsEmpty() )
aFilter = wxS( "*" ); aFilter = wxS( "*" );
EDA_COMBINED_MATCHER matcher( aFilter, CTX_SIGNAL ); EDA_COMBINED_MATCHER matcher( aFilter.Upper(), CTX_SIGNAL );
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
int row = 0; std::vector<wxString> signals;
int row = 0;
for( const wxString& signal : m_signals ) wxCHECK( plotPanel, /* void */ );
if( plotPanel->GetSimType() == ST_FFT )
{ {
if( matcher.StartsWith( signal ) ) wxStringTokenizer tokenizer( plotPanel->GetSimCommand(), wxT( " \t\r\n" ), wxTOKEN_STRTOK );
while( tokenizer.HasMoreTokens() && tokenizer.GetNextToken().Lower() != wxT( "fft" ) )
{};
while( tokenizer.HasMoreTokens() )
signals.emplace_back( tokenizer.GetNextToken() );
}
else
{
signals.insert( signals.end(), m_signals.begin(), m_signals.end() );
}
for( const wxString& signal : signals )
{
if( matcher.Find( signal.Upper() ) )
{ {
int traceType = SPT_UNKNOWN; int traceType = SPT_UNKNOWN;
wxString vectorName = vectorNameFromSignalName( signal, &traceType ); wxString vectorName = vectorNameFromSignalName( plotPanel, signal, &traceType );
TRACE* trace = plotPanel ? plotPanel->GetTrace( vectorName, traceType ) : nullptr; TRACE* trace = plotPanel ? plotPanel->GetTrace( vectorName, traceType ) : nullptr;
m_signalsGrid->AppendRows( 1 ); m_signalsGrid->AppendRows( 1 );
@ -714,7 +736,7 @@ void SIMULATOR_PANEL::rebuildSignalsList()
wxString unconnected = wxString( wxS( "unconnected-(" ) ); wxString unconnected = wxString( wxS( "unconnected-(" ) );
if( simType == ST_UNKNOWN ) if( simType == ST_UNKNOWN )
simType = ST_TRANSIENT; simType = ST_TRAN;
unconnected.Replace( '(', '_' ); // Convert to SPICE markup unconnected.Replace( '(', '_' ); // Convert to SPICE markup
@ -726,7 +748,7 @@ void SIMULATOR_PANEL::rebuildSignalsList()
m_signals.push_back( aSignalName + _( " (gain)" ) ); m_signals.push_back( aSignalName + _( " (gain)" ) );
m_signals.push_back( aSignalName + _( " (phase)" ) ); m_signals.push_back( aSignalName + _( " (phase)" ) );
} }
else if( simType == ST_S_PARAM ) else if( simType == ST_SP )
{ {
m_signals.push_back( aSignalName + _( " (amplitude)" ) ); m_signals.push_back( aSignalName + _( " (amplitude)" ) );
m_signals.push_back( aSignalName + _( " (phase)" ) ); m_signals.push_back( aSignalName + _( " (phase)" ) );
@ -738,7 +760,7 @@ 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 ) ) && ( simType == ST_TRAN || simType == ST_DC || simType == ST_AC || simType == ST_FFT) )
{ {
for( const std::string& net : circuitModel()->GetNets() ) for( const std::string& net : circuitModel()->GetNets() )
{ {
@ -754,7 +776,7 @@ void SIMULATOR_PANEL::rebuildSignalsList()
} }
if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS ) if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_CURRENTS )
&& ( simType == ST_TRANSIENT || simType == ST_DC ) ) && ( simType == ST_TRAN || simType == ST_DC ) )
{ {
for( const SPICE_ITEM& item : circuitModel()->GetItems() ) for( const SPICE_ITEM& item : circuitModel()->GetItems() )
{ {
@ -765,7 +787,7 @@ void SIMULATOR_PANEL::rebuildSignalsList()
} }
if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS ) if( ( options & NETLIST_EXPORTER_SPICE::OPTION_SAVE_ALL_DISSIPATIONS )
&& ( simType == ST_TRANSIENT || simType == ST_DC ) ) && ( simType == ST_TRAN || simType == ST_DC ) )
{ {
for( const SPICE_ITEM& item : circuitModel()->GetItems() ) for( const SPICE_ITEM& item : circuitModel()->GetItems() )
{ {
@ -783,7 +805,7 @@ void SIMULATOR_PANEL::rebuildSignalsList()
addSignal( wxS( "onoise_spectrum" ) ); addSignal( wxS( "onoise_spectrum" ) );
} }
if( simType == ST_S_PARAM ) if( simType == ST_SP )
{ {
std::vector<std::string> portnums; std::vector<std::string> portnums;
@ -845,14 +867,15 @@ void SIMULATOR_PANEL::rebuildSignalsList()
} }
SIM_PLOT_PANEL_BASE* SIMULATOR_PANEL::NewPlotPanel( const wxString& aSimCommand, int aOptions ) SIM_PLOT_PANEL_BASE* SIMULATOR_PANEL::NewPlotPanel( const wxString& aSimCommand,
unsigned aSimOptions )
{ {
SIM_PLOT_PANEL_BASE* plotPanel = nullptr; SIM_PLOT_PANEL_BASE* plotPanel = nullptr;
SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( aSimCommand ); SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( aSimCommand );
if( SIM_PLOT_PANEL_BASE::IsPlottable( simType ) ) if( SIM_PLOT_PANEL_BASE::IsPlottable( simType ) )
{ {
SIM_PLOT_PANEL* panel = new SIM_PLOT_PANEL( aSimCommand, aOptions, m_plotNotebook, wxID_ANY ); SIM_PLOT_PANEL* panel = new SIM_PLOT_PANEL( aSimCommand, aSimOptions, m_plotNotebook );
plotPanel = panel; plotPanel = panel;
COMMON_SETTINGS::INPUT cfg = Pgm().GetCommonSettings()->m_Input; COMMON_SETTINGS::INPUT cfg = Pgm().GetCommonSettings()->m_Input;
@ -860,7 +883,7 @@ SIM_PLOT_PANEL_BASE* SIMULATOR_PANEL::NewPlotPanel( const wxString& aSimCommand,
} }
else else
{ {
plotPanel = new SIM_NOPLOT_PANEL( aSimCommand, aOptions, m_plotNotebook, wxID_ANY ); plotPanel = new SIM_NOPLOT_PANEL( aSimCommand, aSimOptions, m_plotNotebook );
} }
wxString pageTitle( simulator()->TypeToName( simType, true ) ); wxString pageTitle( simulator()->TypeToName( simType, true ) );
@ -904,7 +927,8 @@ wxString vectorNameFromSignalId( int aUserDefinedSignalId )
* For user-defined signals we display the user-oriented signal name such as "V(out)-V(in)", * For user-defined signals we display the user-oriented signal name such as "V(out)-V(in)",
* but the simulator vector we actually have to plot will be "user0" or some-such. * but the simulator vector we actually have to plot will be "user0" or some-such.
*/ */
wxString SIMULATOR_PANEL::vectorNameFromSignalName( const wxString& aSignalName, int* aTraceType ) wxString SIMULATOR_PANEL::vectorNameFromSignalName( SIM_PLOT_PANEL* aPlotPanel,
const wxString& aSignalName, int* aTraceType )
{ {
std::map<wxString, int> suffixes; std::map<wxString, int> suffixes;
suffixes[ _( " (amplitude)" ) ] = SPT_SP_AMP; suffixes[ _( " (amplitude)" ) ] = SPT_SP_AMP;
@ -913,7 +937,7 @@ wxString SIMULATOR_PANEL::vectorNameFromSignalName( const wxString& aSignalName,
if( aTraceType ) if( aTraceType )
{ {
if( circuitModel()->GetSimType() == ST_NOISE ) if( aPlotPanel && aPlotPanel->GetSimType() == ST_NOISE )
{ {
if( getNoiseSource().Upper().StartsWith( 'I' ) ) if( getNoiseSource().Upper().StartsWith( 'I' ) )
*aTraceType = SPT_CURRENT; *aTraceType = SPT_CURRENT;
@ -967,17 +991,17 @@ void SIMULATOR_PANEL::onSignalsGridCellChanged( wxGridEvent& aEvent )
int row = aEvent.GetRow(); int row = aEvent.GetRow();
int col = aEvent.GetCol(); int col = aEvent.GetCol();
wxString text = m_signalsGrid->GetCellValue( row, col ); wxString text = m_signalsGrid->GetCellValue( row, col );
SIM_PLOT_PANEL* plot = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
wxString signalName = m_signalsGrid->GetCellValue( row, COL_SIGNAL_NAME ); wxString signalName = m_signalsGrid->GetCellValue( row, COL_SIGNAL_NAME );
int traceType = SPT_UNKNOWN; int traceType = SPT_UNKNOWN;
wxString vectorName = vectorNameFromSignalName( signalName, &traceType ); wxString vectorName = vectorNameFromSignalName( plotPanel, signalName, &traceType );
if( col == COL_SIGNAL_SHOW ) if( col == COL_SIGNAL_SHOW )
{ {
if( text == wxS( "1" ) ) if( text == wxS( "1" ) )
updateTrace( vectorName, traceType, plot ); updateTrace( vectorName, traceType, plotPanel );
else else
plot->DeleteTrace( vectorName, traceType ); plotPanel->DeleteTrace( vectorName, traceType );
// Update enabled/visible states of other controls // Update enabled/visible states of other controls
updateSignalsGrid(); updateSignalsGrid();
@ -987,13 +1011,13 @@ void SIMULATOR_PANEL::onSignalsGridCellChanged( wxGridEvent& aEvent )
else if( col == COL_SIGNAL_COLOR ) else if( col == COL_SIGNAL_COLOR )
{ {
KIGFX::COLOR4D color( m_signalsGrid->GetCellValue( row, COL_SIGNAL_COLOR ) ); KIGFX::COLOR4D color( m_signalsGrid->GetCellValue( row, COL_SIGNAL_COLOR ) );
TRACE* trace = plot->GetTrace( vectorName, traceType ); TRACE* trace = plotPanel->GetTrace( vectorName, traceType );
if( trace ) if( trace )
{ {
trace->SetTraceColour( color.ToColour() ); trace->SetTraceColour( color.ToColour() );
plot->UpdateTraceStyle( trace ); plotPanel->UpdateTraceStyle( trace );
plot->UpdatePlotColors(); plotPanel->UpdatePlotColors();
m_simulatorFrame->OnModify(); m_simulatorFrame->OnModify();
} }
} }
@ -1002,12 +1026,12 @@ void SIMULATOR_PANEL::onSignalsGridCellChanged( wxGridEvent& aEvent )
for( int ii = 0; ii < m_signalsGrid->GetNumberRows(); ++ii ) for( int ii = 0; ii < m_signalsGrid->GetNumberRows(); ++ii )
{ {
signalName = m_signalsGrid->GetCellValue( ii, COL_SIGNAL_NAME ); signalName = m_signalsGrid->GetCellValue( ii, COL_SIGNAL_NAME );
vectorName = vectorNameFromSignalName( signalName, &traceType ); vectorName = vectorNameFromSignalName( plotPanel, signalName, &traceType );
int id = col == COL_CURSOR_1 ? 1 : 2; int id = col == COL_CURSOR_1 ? 1 : 2;
bool enable = ii == row && text == wxS( "1" ); bool enable = ii == row && text == wxS( "1" );
plot->EnableCursor( vectorName, traceType, id, enable, signalName ); plotPanel->EnableCursor( vectorName, traceType, id, enable, signalName );
m_simulatorFrame->OnModify(); m_simulatorFrame->OnModify();
} }
@ -1022,7 +1046,7 @@ void SIMULATOR_PANEL::onCursorsGridCellChanged( wxGridEvent& aEvent )
if( m_SuppressGridEvents > 0 ) if( m_SuppressGridEvents > 0 )
return; return;
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
if( !plotPanel ) if( !plotPanel )
return; return;
@ -1092,7 +1116,7 @@ void SIMULATOR_PANEL::DeleteMeasurement( int aRow )
void SIMULATOR_PANEL::onMeasurementsGridCellChanged( wxGridEvent& aEvent ) void SIMULATOR_PANEL::onMeasurementsGridCellChanged( wxGridEvent& aEvent )
{ {
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
if( !plotPanel ) if( !plotPanel )
return; return;
@ -1158,7 +1182,7 @@ void SIMULATOR_PANEL::UpdateMeasurement( int aRow )
" +" " +"
"([a-zA-Z])\\(([^\\)]+)\\)" ) ); "([a-zA-Z])\\(([^\\)]+)\\)" ) );
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
if( !plotPanel ) if( !plotPanel )
return; return;
@ -1200,23 +1224,24 @@ void SIMULATOR_PANEL::UpdateMeasurement( int aRow )
{ {
switch( plotPanel->GetSimType() ) switch( plotPanel->GetSimType() )
{ {
case SIM_TYPE::ST_TRANSIENT: case SIM_TYPE::ST_TRAN:
if ( signalType == 'P' ) if ( signalType == 'P' )
units = wxS( "J" ); units = wxS( "J" );
else else
units += wxS( ".s" ); units += wxS( ".s" );
break; break;
case SIM_TYPE::ST_AC: case SIM_TYPE::ST_AC:
case SIM_TYPE::ST_S_PARAM: case SIM_TYPE::ST_SP:
case SIM_TYPE::ST_DISTORTION: case SIM_TYPE::ST_DISTO:
case SIM_TYPE::ST_NOISE: case SIM_TYPE::ST_NOISE:
case SIM_TYPE::ST_SENSITIVITY: // If there is a vector, it is frequency case SIM_TYPE::ST_FFT:
case SIM_TYPE::ST_SENS: // If there is a vector, it is frequency
units += wxS( "·Hz" ); units += wxS( "·Hz" );
break; break;
case SIM_TYPE::ST_DC: // Could be a lot of things : V, A, deg C, ohm, ... case SIM_TYPE::ST_DC: // Could be a lot of things : V, A, deg C, ohm, ...
case SIM_TYPE::ST_OP: // There is no vector for integration case SIM_TYPE::ST_OP: // There is no vector for integration
case SIM_TYPE::ST_POLE_ZERO: // There is no vector for integration case SIM_TYPE::ST_PZ: // There is no vector for integration
case SIM_TYPE::ST_TRANS_FUNC: // There is no vector for integration case SIM_TYPE::ST_TF: // There is no vector for integration
default: default:
units += wxS( "·?" ); units += wxS( "·?" );
@ -1246,7 +1271,7 @@ void SIMULATOR_PANEL::UpdateMeasurement( int aRow )
void SIMULATOR_PANEL::AddTuner( const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aSymbol ) void SIMULATOR_PANEL::AddTuner( const SCH_SHEET_PATH& aSheetPath, SCH_SYMBOL* aSymbol )
{ {
SIM_PLOT_PANEL_BASE* plotPanel = GetCurrentPlotWindow(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
if( !plotPanel ) if( !plotPanel )
return; return;
@ -1332,7 +1357,7 @@ void SIMULATOR_PANEL::AddMeasurement( const wxString& aCmd )
return; // Don't create duplicates return; // Don't create duplicates
} }
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
if( !plotPanel ) if( !plotPanel )
return; return;
@ -1384,16 +1409,14 @@ const NGSPICE_CIRCUIT_MODEL* SIMULATOR_PANEL::GetExporter() const
void SIMULATOR_PANEL::AddTrace( const wxString& aName, SIM_TRACE_TYPE aType ) void SIMULATOR_PANEL::AddTrace( const wxString& aName, SIM_TRACE_TYPE aType )
{ {
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); if( !GetCurrentPlotPanel() )
if( !plotPanel )
{ {
m_simConsole->AppendText( _( "Error: no current simulation.\n" ) ); m_simConsole->AppendText( _( "Error: no current simulation.\n" ) );
m_simConsole->SetInsertionPointEnd(); m_simConsole->SetInsertionPointEnd();
return; return;
} }
SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( plotPanel->GetSimCommand() ); SIM_TYPE simType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( GetCurrentPlotPanel()->GetSimCommand() );
if( simType == ST_UNKNOWN ) if( simType == ST_UNKNOWN )
{ {
@ -1408,12 +1431,15 @@ void SIMULATOR_PANEL::AddTrace( const wxString& aName, SIM_TRACE_TYPE aType )
return; return;
} }
SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
wxCHECK( plotPanel, /* void */ );
if( simType == ST_AC ) if( simType == ST_AC )
{ {
updateTrace( aName, aType | SPT_AC_GAIN, plotPanel ); updateTrace( aName, aType | SPT_AC_GAIN, plotPanel );
updateTrace( aName, aType | SPT_AC_PHASE, plotPanel ); updateTrace( aName, aType | SPT_AC_PHASE, plotPanel );
} }
if( simType == ST_S_PARAM ) else if( simType == ST_SP )
{ {
updateTrace( aName, aType | SPT_AC_GAIN, plotPanel ); updateTrace( aName, aType | SPT_AC_GAIN, plotPanel );
updateTrace( aName, aType | SPT_AC_PHASE, plotPanel ); updateTrace( aName, aType | SPT_AC_PHASE, plotPanel );
@ -1440,7 +1466,7 @@ void SIMULATOR_PANEL::SetUserDefinedSignals( const std::map<int, wxString>& aNew
for( const auto& [ id, existingSignal ] : m_userDefinedSignals ) for( const auto& [ id, existingSignal ] : m_userDefinedSignals )
{ {
int traceType = SPT_UNKNOWN; int traceType = SPT_UNKNOWN;
wxString vectorName = vectorNameFromSignalName( existingSignal, &traceType ); wxString vectorName = vectorNameFromSignalName( plotPanel, existingSignal, &traceType );
if( aNewSignals.count( id ) == 0 ) if( aNewSignals.count( id ) == 0 )
{ {
@ -1449,7 +1475,7 @@ void SIMULATOR_PANEL::SetUserDefinedSignals( const std::map<int, wxString>& aNew
for( int subType : { SPT_AC_GAIN, SPT_AC_PHASE } ) for( int subType : { SPT_AC_GAIN, SPT_AC_PHASE } )
plotPanel->DeleteTrace( vectorName, traceType | subType ); plotPanel->DeleteTrace( vectorName, traceType | subType );
} }
else if( plotPanel->GetSimType() == ST_S_PARAM ) else if( plotPanel->GetSimType() == ST_SP )
{ {
for( int subType : { SPT_SP_AMP, SPT_AC_PHASE } ) for( int subType : { SPT_SP_AMP, SPT_AC_PHASE } )
plotPanel->DeleteTrace( vectorName, traceType | subType ); plotPanel->DeleteTrace( vectorName, traceType | subType );
@ -1469,7 +1495,7 @@ void SIMULATOR_PANEL::SetUserDefinedSignals( const std::map<int, wxString>& aNew
trace->SetName( aNewSignals.at( id ) ); trace->SetName( aNewSignals.at( id ) );
} }
} }
else if( plotPanel->GetSimType() == ST_S_PARAM ) else if( plotPanel->GetSimType() == ST_SP )
{ {
for( int subType : { SPT_SP_AMP, SPT_AC_PHASE } ) for( int subType : { SPT_SP_AMP, SPT_AC_PHASE } )
{ {
@ -1542,7 +1568,7 @@ void SIMULATOR_PANEL::updateTrace( const wxString& aVectorName, int aTraceType,
wxFAIL_MSG( wxT( "Plot type missing AC_PHASE or AC_MAG bit" ) ); wxFAIL_MSG( wxT( "Plot type missing AC_PHASE or AC_MAG bit" ) );
break; break;
case ST_S_PARAM: case ST_SP:
if( aTraceType & SPT_SP_AMP ) if( aTraceType & SPT_SP_AMP )
data_y = simulator()->GetGainVector( (const char*) simVectorName.c_str() ); data_y = simulator()->GetGainVector( (const char*) simVectorName.c_str() );
else if( aTraceType & SPT_AC_PHASE ) else if( aTraceType & SPT_AC_PHASE )
@ -1554,7 +1580,8 @@ void SIMULATOR_PANEL::updateTrace( const wxString& aVectorName, int aTraceType,
case ST_NOISE: case ST_NOISE:
case ST_DC: case ST_DC:
case ST_TRANSIENT: case ST_TRAN:
case ST_FFT:
data_y = simulator()->GetGainVector( (const char*) simVectorName.c_str() ); data_y = simulator()->GetGainVector( (const char*) simVectorName.c_str() );
break; break;
@ -1569,7 +1596,7 @@ void SIMULATOR_PANEL::updateTrace( const wxString& aVectorName, int aTraceType,
SPICE_DC_PARAMS source1, source2; SPICE_DC_PARAMS source1, source2;
if( simType == ST_DC if( simType == ST_DC
&& circuitModel()->ParseDCCommand( circuitModel()->GetSimCommand(), &source1, &source2 ) && circuitModel()->ParseDCCommand( aPlotPanel->GetSimCommand(), &source1, &source2 )
&& !source2.m_source.IsEmpty() ) && !source2.m_source.IsEmpty() )
{ {
// Source 1 is the inner loop, so lets add traces for each Source 2 (outer loop) step // Source 1 is the inner loop, so lets add traces for each Source 2 (outer loop) step
@ -1610,15 +1637,15 @@ void SIMULATOR_PANEL::updateTrace( const wxString& aVectorName, int aTraceType,
void SIMULATOR_PANEL::updateSignalsGrid() void SIMULATOR_PANEL::updateSignalsGrid()
{ {
SIM_PLOT_PANEL* plot = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
for( int row = 0; row < m_signalsGrid->GetNumberRows(); ++row ) for( int row = 0; row < m_signalsGrid->GetNumberRows(); ++row )
{ {
wxString signalName = m_signalsGrid->GetCellValue( row, COL_SIGNAL_NAME ); wxString signalName = m_signalsGrid->GetCellValue( row, COL_SIGNAL_NAME );
int traceType = SPT_UNKNOWN; int traceType = SPT_UNKNOWN;
wxString vectorName = vectorNameFromSignalName( signalName, &traceType ); wxString vectorName = vectorNameFromSignalName( plotPanel, signalName, &traceType );
if( TRACE* trace = plot ? plot->GetTrace( vectorName, traceType ) : nullptr ) if( TRACE* trace = plotPanel ? plotPanel->GetTrace( vectorName, traceType ) : nullptr )
{ {
m_signalsGrid->SetCellValue( row, COL_SIGNAL_SHOW, wxS( "1" ) ); m_signalsGrid->SetCellValue( row, COL_SIGNAL_SHOW, wxS( "1" ) );
@ -1941,26 +1968,30 @@ bool SIMULATOR_PANEL::LoadWorkbook( const wxString& aPath )
if( plotPanel ) if( plotPanel )
traceInfo[ plotPanel ].emplace_back( std::make_tuple( traceType, name, param ) ); traceInfo[ plotPanel ].emplace_back( std::make_tuple( traceType, name, param ) );
} }
if( version > 4 )
{
long measurementCount;
file.GetNextLine().ToLong( &measurementCount );
for( int ii = 0; ii < (int) measurementCount; ++ ii )
{
wxString measurement = file.GetNextLine();
wxString format = file.GetNextLine();
if( plotPanel )
plotPanel->Measurements().emplace_back( measurement, format );
}
}
} }
long userDefinedSignalCount; long userDefinedSignalCount;
long measurementCount;
if( file.GetNextLine().ToLong( &userDefinedSignalCount ) ) if( file.GetNextLine().ToLong( &userDefinedSignalCount ) )
{ {
for( int ii = 0; ii < (int) userDefinedSignalCount; ++ii ) for( int ii = 0; ii < (int) userDefinedSignalCount; ++ii )
m_userDefinedSignals[ ii ] = file.GetNextLine(); m_userDefinedSignals[ ii ] = file.GetNextLine();
file.GetNextLine().ToLong( &measurementCount );
m_measurementsGrid->ClearRows();
m_measurementsGrid->AppendRows( (int) measurementCount + 1 /* empty row at end */ );
for( int row = 0; row < (int) measurementCount; ++row )
{
m_measurementsGrid->SetCellValue( row, COL_MEASUREMENT, file.GetNextLine() );
m_measurementsGrid->SetCellValue( row, COL_MEASUREMENT_FORMAT, file.GetNextLine() );
}
} }
for( const auto& [ plotPanel, traceInfoVector ] : traceInfo ) for( const auto& [ plotPanel, traceInfoVector ] : traceInfo )
@ -1985,7 +2016,7 @@ bool SIMULATOR_PANEL::LoadWorkbook( const wxString& aPath )
} }
else else
{ {
wxString vectorName = vectorNameFromSignalName( signalName, nullptr ); wxString vectorName = vectorNameFromSignalName( plotPanel, signalName, nullptr );
TRACE* trace = plotPanel->AddTrace( vectorName, (int) traceType ); TRACE* trace = plotPanel->AddTrace( vectorName, (int) traceType );
if( version >= 4 && trace ) if( version >= 4 && trace )
@ -1996,35 +2027,15 @@ bool SIMULATOR_PANEL::LoadWorkbook( const wxString& aPath )
plotPanel->UpdatePlotColors(); plotPanel->UpdatePlotColors();
} }
m_simulatorFrame->LoadSimulator(); if( SIM_PLOT_PANEL_BASE* plotPanel = GetCurrentPlotPanel() )
wxString schTextSimCommand = circuitModel()->GetSchTextSimCommand().Lower();
SIM_TYPE schTextSimType = NGSPICE_CIRCUIT_MODEL::CommandToSimType( schTextSimCommand );
if( schTextSimType != ST_UNKNOWN )
{ {
bool found = false; m_simulatorFrame->LoadSimulator( plotPanel->GetSimCommand(), plotPanel->GetSimOptions() );
for( int ii = 0; ii < (int) m_plotNotebook->GetPageCount(); ++ii ) if( version >= 5 )
{ {
auto* plot = dynamic_cast<const SIM_PLOT_PANEL_BASE*>( m_plotNotebook->GetPage( ii ) ); plotPanel = dynamic_cast<SIM_PLOT_PANEL_BASE*>( m_plotNotebook->GetPage( 0 ) );
plotPanel->SetLastSchTextSimCommand( file.GetNextLine() );
if( plot && plot->GetSimType() == schTextSimType )
{
if( schTextSimType == ST_DC )
{
wxString plotSimCommand = plot->GetSimCommand().Lower();
found = plotSimCommand.GetChar( 4 ) == schTextSimCommand.GetChar( 4 );
}
else
{
found = true;
}
}
} }
if( !found )
NewPlotPanel( schTextSimCommand, circuitModel()->GetSimOptions() );
} }
rebuildSignalsList(); rebuildSignalsList();
@ -2032,6 +2043,7 @@ bool SIMULATOR_PANEL::LoadWorkbook( const wxString& aPath )
rebuildSignalsGrid( m_filter->GetValue() ); rebuildSignalsGrid( m_filter->GetValue() );
updateSignalsGrid(); updateSignalsGrid();
updatePlotCursors(); updatePlotCursors();
rebuildMeasurementsGrid();
file.Close(); file.Close();
@ -2064,13 +2076,13 @@ bool SIMULATOR_PANEL::SaveWorkbook( const wxString& aPath )
file.Create(); file.Create();
} }
file.AddLine( wxT( "version 4" ) ); file.AddLine( wxT( "version 5" ) );
file.AddLine( wxString::Format( wxT( "%llu" ), m_plotNotebook->GetPageCount() ) ); file.AddLine( wxString::Format( wxT( "%llu" ), m_plotNotebook->GetPageCount() ) );
for( size_t i = 0; i < m_plotNotebook->GetPageCount(); i++ ) for( size_t i = 0; i < m_plotNotebook->GetPageCount(); i++ )
{ {
auto* basePanel = dynamic_cast<const SIM_PLOT_PANEL_BASE*>( m_plotNotebook->GetPage( i ) ); auto* basePanel = dynamic_cast<SIM_PLOT_PANEL_BASE*>( m_plotNotebook->GetPage( i ) );
if( !basePanel ) if( !basePanel )
{ {
@ -2097,7 +2109,7 @@ bool SIMULATOR_PANEL::SaveWorkbook( const wxString& aPath )
file.AddLine( EscapeString( command, CTX_LINE ) ); file.AddLine( EscapeString( command, CTX_LINE ) );
const SIM_PLOT_PANEL* plotPanel = dynamic_cast<const SIM_PLOT_PANEL*>( basePanel ); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( basePanel );
if( !plotPanel ) if( !plotPanel )
{ {
@ -2171,6 +2183,14 @@ bool SIMULATOR_PANEL::SaveWorkbook( const wxString& aPath )
plotPanel->GetLegendPosition().x, plotPanel->GetLegendPosition().x,
plotPanel->GetLegendPosition().y - 40 ) ); plotPanel->GetLegendPosition().y - 40 ) );
} }
file.AddLine( wxString::Format( wxT( "%llu" ), plotPanel->Measurements().size() ) );
for( const auto& [ measurement, format ] : plotPanel->Measurements() )
{
file.AddLine( measurement );
file.AddLine( format );
}
} }
file.AddLine( wxString::Format( wxT( "%llu" ), m_userDefinedSignals.size() ) ); file.AddLine( wxString::Format( wxT( "%llu" ), m_userDefinedSignals.size() ) );
@ -2178,25 +2198,18 @@ bool SIMULATOR_PANEL::SaveWorkbook( const wxString& aPath )
for( const auto& [ id, signal ] : m_userDefinedSignals ) for( const auto& [ id, signal ] : m_userDefinedSignals )
file.AddLine( signal ); file.AddLine( signal );
std::vector<wxString> measurements; // Store the value of any simulation command found on the schematic sheet in a SCH_TEXT
std::vector<wxString> formats; // object. If this changes we want to warn the user and ask them if they want to update
// the corresponding panel's sim command.
wxString lastSchTextSimCommand;
for( int i = 0; i < m_measurementsGrid->GetNumberRows(); ++i ) if( m_plotNotebook->GetPageCount() > 0 )
{ {
if( !m_measurementsGrid->GetCellValue( i, COL_MEASUREMENT ).IsEmpty() ) auto* basePanel = dynamic_cast<SIM_PLOT_PANEL_BASE*>( m_plotNotebook->GetPage( 0 ) );
{ lastSchTextSimCommand = basePanel->GetLastSchTextSimCommand();
measurements.push_back( m_measurementsGrid->GetCellValue( i, COL_MEASUREMENT ) );
formats.push_back( m_measurementsGrid->GetCellValue( i, COL_MEASUREMENT_FORMAT ) );
}
} }
file.AddLine( wxString::Format( wxT( "%llu" ), measurements.size() ) ); file.AddLine( lastSchTextSimCommand );
for( size_t i = 0; i < measurements.size(); i++ )
{
file.AddLine( measurements[i] );
file.AddLine( formats[i] );
}
bool res = file.Write(); bool res = file.Write();
file.Close(); file.Close();
@ -2217,12 +2230,13 @@ SIM_TRACE_TYPE SIMULATOR_PANEL::getXAxisType( SIM_TYPE aType ) const
switch( aType ) switch( aType )
{ {
/// @todo SPT_LOG_FREQUENCY /// @todo SPT_LOG_FREQUENCY
case ST_AC: return SPT_LIN_FREQUENCY; case ST_AC: return SPT_LIN_FREQUENCY;
case ST_S_PARAM: return SPT_LIN_FREQUENCY; case ST_SP: return SPT_LIN_FREQUENCY;
case ST_DC: return SPT_SWEEP; case ST_FFT: return SPT_LIN_FREQUENCY;
case ST_TRANSIENT: return SPT_TIME; case ST_DC: return SPT_SWEEP;
case ST_NOISE: return SPT_LIN_FREQUENCY; case ST_TRAN: return SPT_TIME;
default: wxFAIL_MSG( wxS( "Unhandled simulation type" ) ); return SPT_UNKNOWN; case ST_NOISE: return SPT_LIN_FREQUENCY;
default: wxFAIL_MSG( wxS( "Unhandled simulation type" ) ); return SPT_UNKNOWN;
} }
} }
@ -2238,8 +2252,11 @@ wxString SIMULATOR_PANEL::getNoiseSource() const
SPICE_VALUE fStop; SPICE_VALUE fStop;
bool saveAll; bool saveAll;
circuitModel()->ParseNoiseCommand( circuitModel()->GetSimCommand(), &output, &ref, &source, if( GetCurrentPlotPanel() )
&scale, &pts, &fStart, &fStop, &saveAll ); {
circuitModel()->ParseNoiseCommand( GetCurrentPlotPanel()->GetSimCommand(), &output, &ref,
&source, &scale, &pts, &fStart, &fStop, &saveAll );
}
return source; return source;
} }
@ -2280,7 +2297,7 @@ void SIMULATOR_PANEL::onPlotClosed( wxAuiNotebookEvent& event )
rebuildSignalsGrid( m_filter->GetValue() ); rebuildSignalsGrid( m_filter->GetValue() );
updatePlotCursors(); updatePlotCursors();
SIM_PLOT_PANEL_BASE* panel = GetCurrentPlotWindow(); SIM_PLOT_PANEL_BASE* panel = GetCurrentPlotPanel();
if( !panel || panel->GetSimType() != ST_OP ) if( !panel || panel->GetSimType() != ST_OP )
{ {
@ -2293,11 +2310,72 @@ void SIMULATOR_PANEL::onPlotClosed( wxAuiNotebookEvent& event )
} }
void SIMULATOR_PANEL::onPlotChanged( wxAuiNotebookEvent& event ) void SIMULATOR_PANEL::onPlotChanging( wxAuiNotebookEvent& event )
{
if( SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() ) )
{
std::vector<std::pair<wxString, wxString>>& measurements = plotPanel->Measurements();
measurements.clear();
for( int row = 0; row < m_measurementsGrid->GetNumberRows(); ++row )
{
if( !m_measurementsGrid->GetCellValue( row, COL_MEASUREMENT ).IsEmpty() )
{
measurements.emplace_back( m_measurementsGrid->GetCellValue( row, COL_MEASUREMENT ),
m_measurementsGrid->GetCellValue( row, COL_MEASUREMENT_FORMAT ) );
}
}
}
event.Skip();
}
void SIMULATOR_PANEL::OnPlotSettingsChanged()
{ {
rebuildSignalsList(); rebuildSignalsList();
rebuildSignalsGrid( m_filter->GetValue() ); rebuildSignalsGrid( m_filter->GetValue() );
updatePlotCursors(); updatePlotCursors();
rebuildMeasurementsGrid();
for( int row = 0; row < m_measurementsGrid->GetNumberRows(); ++row )
UpdateMeasurement( row );
}
void SIMULATOR_PANEL::onPlotChanged( wxAuiNotebookEvent& event )
{
if( SIM_PLOT_PANEL_BASE* plotWindow = GetCurrentPlotPanel() )
simulator()->Command( "setplot " + plotWindow->GetSpicePlotName().ToStdString() );
OnPlotSettingsChanged();
event.Skip();
}
void SIMULATOR_PANEL::rebuildMeasurementsGrid()
{
m_measurementsGrid->ClearRows();
if( SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() ) )
{
for( const auto& [ measurement, format ] : plotPanel->Measurements() )
{
int row = m_measurementsGrid->GetNumberRows();
m_measurementsGrid->AppendRows();
m_measurementsGrid->SetCellValue( row, COL_MEASUREMENT, measurement );
m_measurementsGrid->SetCellValue( row, COL_MEASUREMENT_FORMAT, format );
}
if( plotPanel->GetSimType() == ST_TRAN || plotPanel->GetSimType() == ST_AC
|| plotPanel->GetSimType() == ST_DC || plotPanel->GetSimType() == ST_SP )
{
m_measurementsGrid->AppendRows(); // Empty row at end
}
}
} }
@ -2331,7 +2409,7 @@ void SIMULATOR_PANEL::updatePlotCursors()
m_cursorsGrid->ClearRows(); m_cursorsGrid->ClearRows();
SIM_PLOT_PANEL* plotPanel = GetCurrentPlot(); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() );
if( !plotPanel ) if( !plotPanel )
return; return;
@ -2469,7 +2547,7 @@ void SIMULATOR_PANEL::onPlotCursorUpdate( wxCommandEvent& aEvent )
void SIMULATOR_PANEL::OnSimUpdate() void SIMULATOR_PANEL::OnSimUpdate()
{ {
if( SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotWindow() ) ) if( SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( GetCurrentPlotPanel() ) )
plotPanel->ResetScales( true ); plotPanel->ResetScales( true );
m_simConsole->Clear(); m_simConsole->Clear();
@ -2488,7 +2566,7 @@ void SIMULATOR_PANEL::OnSimReport( const wxString& aMsg )
} }
std::vector<wxString> SIMULATOR_PANEL::Signals() const std::vector<wxString> SIMULATOR_PANEL::SimPlotVectors() const
{ {
std::vector<wxString> signals; std::vector<wxString> signals;
@ -2499,20 +2577,32 @@ std::vector<wxString> SIMULATOR_PANEL::Signals() const
} }
std::vector<wxString> SIMULATOR_PANEL::Signals() const
{
std::vector<wxString> signals;
for( const wxString& signal : m_signals )
signals.emplace_back( signal );
for( const auto& [ id, signal ] : m_userDefinedSignals )
signals.emplace_back( signal );
return signals;
}
void SIMULATOR_PANEL::OnSimRefresh( bool aFinal ) void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
{ {
SIM_TYPE simType = circuitModel()->GetSimType(); SIM_PLOT_PANEL_BASE* plotPanelBase = GetCurrentPlotPanel();
SIM_PLOT_PANEL_BASE* plotPanelWindow = GetCurrentPlotWindow();
if( !plotPanelWindow || plotPanelWindow->GetSimType() != simType ) if( !plotPanelBase )
{ return;
plotPanelWindow = NewPlotPanel( circuitModel()->GetSimCommand(),
circuitModel()->GetSimOptions() );
}
SIM_TYPE simType = plotPanelBase->GetSimType();
std::vector<wxString> oldSignals = m_signals; std::vector<wxString> oldSignals = m_signals;
wxString msg; wxString msg;
plotPanelBase->SetSpicePlotName( simulator()->CurrentPlotName() );
applyUserDefinedSignals(); applyUserDefinedSignals();
rebuildSignalsList(); rebuildSignalsList();
@ -2527,7 +2617,8 @@ void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
// The simulator will create noise1 & noise2 on the first run, noise3 and noise4 // The simulator will create noise1 & noise2 on the first run, noise3 and noise4
// on the second, etc. The first plot for each run contains the spectral density // on the second, etc. The first plot for each run contains the spectral density
// noise vectors and second contains the integrated noise. // noise vectors and second contains the integrated noise.
simulator()->Command( "setplot noise2" ); long number;
simulator()->CurrentPlotName().Mid( 5 ).ToLong( &number );
for( const std::string& vec : simulator()->AllVectors() ) for( const std::string& vec : simulator()->AllVectors() )
{ {
@ -2540,10 +2631,11 @@ void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
m_simConsole->SetInsertionPointEnd(); m_simConsole->SetInsertionPointEnd();
} }
simulator()->Command( "setplot noise1" ); simulator()->Command( fmt::format( "setplot noise{}", number - 1 ) );
plotPanelBase->SetSpicePlotName( simulator()->CurrentPlotName() );
} }
SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( plotPanelWindow ); SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( plotPanelBase );
wxCHECK_RET( plotPanel, wxT( "not a SIM_PLOT_PANEL" ) ); wxCHECK_RET( plotPanel, wxT( "not a SIM_PLOT_PANEL" ) );
// Map of TRACE* to { vectorName, traceType } // Map of TRACE* to { vectorName, traceType }
@ -2555,7 +2647,7 @@ void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
for( const wxString& signal : m_signals ) for( const wxString& signal : m_signals )
{ {
int traceType = SPT_UNKNOWN; int traceType = SPT_UNKNOWN;
wxString vectorName = vectorNameFromSignalName( signal, &traceType ); wxString vectorName = vectorNameFromSignalName( plotPanel, signal, &traceType );
if( simType == ST_AC ) if( simType == ST_AC )
{ {
@ -2565,7 +2657,7 @@ void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
traceMap[ trace ] = { vectorName, traceType }; traceMap[ trace ] = { vectorName, traceType };
} }
} }
if( simType == ST_S_PARAM ) else if( simType == ST_SP )
{ {
for( int subType : { SPT_SP_AMP, SPT_AC_PHASE } ) for( int subType : { SPT_SP_AMP, SPT_AC_PHASE } )
{ {
@ -2603,6 +2695,11 @@ void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
plotPanel->ResetScales( true ); plotPanel->ResetScales( true );
plotPanel->GetPlotWin()->Fit(); plotPanel->GetPlotWin()->Fit();
updatePlotCursors();
for( int row = 0; row < m_measurementsGrid->GetNumberRows(); ++row )
UpdateMeasurement( row );
} }
else if( simType == ST_OP ) else if( simType == ST_OP )
{ {
@ -2634,11 +2731,6 @@ void SIMULATOR_PANEL::OnSimRefresh( bool aFinal )
m_schematicFrame->Schematic().SetOperatingPoint( signal, val_list.at( 0 ) ); m_schematicFrame->Schematic().SetOperatingPoint( signal, val_list.at( 0 ) );
} }
} }
updatePlotCursors();
for( int row = 0; row < m_measurementsGrid->GetNumberRows(); ++row )
UpdateMeasurement( row );
} }

View File

@ -79,7 +79,9 @@ public:
* @param aSimOptions netlisting options * @param aSimOptions netlisting options
* @return The new plot panel. * @return The new plot panel.
*/ */
SIM_PLOT_PANEL_BASE* NewPlotPanel( const wxString& aSimCommand, int aSimOptions ); SIM_PLOT_PANEL_BASE* NewPlotPanel( const wxString& aSimCommand, unsigned aSimOptions );
std::vector<wxString> SimPlotVectors() const;
std::vector<wxString> Signals() const; std::vector<wxString> Signals() const;
@ -194,23 +196,22 @@ public:
/** /**
* Return the currently opened plot panel (or NULL if there is none). * Return the currently opened plot panel (or NULL if there is none).
*/ */
SIM_PLOT_PANEL_BASE* GetCurrentPlotWindow() const SIM_PLOT_PANEL_BASE* GetCurrentPlotPanel() const
{ {
return dynamic_cast<SIM_PLOT_PANEL_BASE*>( m_plotNotebook->GetCurrentPage() ); return dynamic_cast<SIM_PLOT_PANEL_BASE*>( m_plotNotebook->GetCurrentPage() );
} }
/** SIM_PLOT_PANEL_BASE* GetPlotPanel( SIM_TYPE aType ) const
* Return the current tab (or NULL if there is none).
*/
SIM_PLOT_PANEL* GetCurrentPlot() const
{ {
SIM_PLOT_PANEL_BASE* plotWindow = GetCurrentPlotWindow(); for( int ii = 0; ii < (int) m_plotNotebook->GetPageCount(); ++ii )
{
auto* candidate = dynamic_cast<SIM_PLOT_PANEL_BASE*>( m_plotNotebook->GetPage( ii ) );
if( !plotWindow ) if( candidate && candidate->GetSimType() == aType )
return nullptr; return candidate;
}
return plotWindow->GetSimType() == ST_UNKNOWN ? nullptr return nullptr;
: dynamic_cast<SIM_PLOT_PANEL*>( plotWindow );
} }
int GetPlotIndex( SIM_PLOT_PANEL_BASE* aPlot ) const int GetPlotIndex( SIM_PLOT_PANEL_BASE* aPlot ) const
@ -218,6 +219,8 @@ public:
return m_plotNotebook->GetPageIndex( aPlot ); return m_plotNotebook->GetPageIndex( aPlot );
} }
void OnPlotSettingsChanged();
void OnSimUpdate(); void OnSimUpdate();
void OnSimReport( const wxString& aMsg ); void OnSimReport( const wxString& aMsg );
void OnSimRefresh( bool aFinal ); void OnSimRefresh( bool aFinal );
@ -226,7 +229,8 @@ private:
/** /**
* Get the simulator output vector name for a given signal name and type. * Get the simulator output vector name for a given signal name and type.
*/ */
wxString vectorNameFromSignalName( const wxString& aSignalName, int* aTraceType ); wxString vectorNameFromSignalName( SIM_PLOT_PANEL* aPlotPanel, const wxString& aSignalName,
int* aTraceType );
/** /**
* Update a trace in a particular SIM_PLOT_PANEL. If the panel does not contain the given * Update a trace in a particular SIM_PLOT_PANEL. If the panel does not contain the given
@ -265,6 +269,11 @@ private:
*/ */
void applyUserDefinedSignals(); void applyUserDefinedSignals();
/**
* Rebuild the measurements grid for the current plot.
*/
void rebuildMeasurementsGrid();
/** /**
* Apply component values specified using tuner sliders to the current netlist. * Apply component values specified using tuner sliders to the current netlist.
*/ */
@ -286,6 +295,7 @@ private:
// Event handlers // Event handlers
void onPlotClose( wxAuiNotebookEvent& event ) override; void onPlotClose( wxAuiNotebookEvent& event ) override;
void onPlotClosed( wxAuiNotebookEvent& event ) override; void onPlotClosed( wxAuiNotebookEvent& event ) override;
void onPlotChanging( wxAuiNotebookEvent& event ) override;
void onPlotChanged( wxAuiNotebookEvent& event ) override; void onPlotChanged( wxAuiNotebookEvent& event ) override;
void onPlotDragged( wxAuiNotebookEvent& event ) override; void onPlotDragged( wxAuiNotebookEvent& event ) override;

View File

@ -280,6 +280,7 @@ SIMULATOR_PANEL_BASE::SIMULATOR_PANEL_BASE( wxWindow* parent, wxWindowID id, con
// Connect Events // Connect Events
m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotDragged ), NULL, this ); m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotDragged ), NULL, this );
m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotChanged ), NULL, this ); m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotChanged ), NULL, this );
m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotChanging ), NULL, this );
m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotClose ), NULL, this ); m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotClose ), NULL, this );
m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotClosed ), NULL, this ); m_plotNotebook->Connect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotClosed ), NULL, this );
m_filter->Connect( wxEVT_MOTION, wxMouseEventHandler( SIMULATOR_PANEL_BASE::OnFilterMouseMoved ), NULL, this ); m_filter->Connect( wxEVT_MOTION, wxMouseEventHandler( SIMULATOR_PANEL_BASE::OnFilterMouseMoved ), NULL, this );
@ -294,6 +295,7 @@ SIMULATOR_PANEL_BASE::~SIMULATOR_PANEL_BASE()
// Disconnect Events // Disconnect Events
m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotDragged ), NULL, this ); m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotDragged ), NULL, this );
m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotChanged ), NULL, this ); m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotChanged ), NULL, this );
m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotChanging ), NULL, this );
m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotClose ), NULL, this ); m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotClose ), NULL, this );
m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotClosed ), NULL, this ); m_plotNotebook->Disconnect( wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, wxAuiNotebookEventHandler( SIMULATOR_PANEL_BASE::onPlotClosed ), NULL, this );
m_filter->Disconnect( wxEVT_MOTION, wxMouseEventHandler( SIMULATOR_PANEL_BASE::OnFilterMouseMoved ), NULL, this ); m_filter->Disconnect( wxEVT_MOTION, wxMouseEventHandler( SIMULATOR_PANEL_BASE::OnFilterMouseMoved ), NULL, this );

View File

@ -118,8 +118,8 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style">wxBORDER_NONE</property> <property name="window_style">wxBORDER_NONE</property>
<object class="splitteritem" expanded="0"> <object class="splitteritem" expanded="1">
<object class="wxPanel" expanded="0"> <object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -170,16 +170,16 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property> <property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="0"> <object class="wxBoxSizer" expanded="1">
<property name="minimum_size">-1,-1</property> <property name="minimum_size">-1,-1</property>
<property name="name">m_sizer11</property> <property name="name">m_sizer11</property>
<property name="orient">wxVERTICAL</property> <property name="orient">wxVERTICAL</property>
<property name="permission">protected</property> <property name="permission">protected</property>
<object class="sizeritem" expanded="0"> <object class="sizeritem" expanded="1">
<property name="border">5</property> <property name="border">5</property>
<property name="flag">wxEXPAND</property> <property name="flag">wxEXPAND</property>
<property name="proportion">1</property> <property name="proportion">1</property>
<object class="wxSplitterWindow" expanded="0"> <object class="wxSplitterWindow" expanded="1">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -236,8 +236,8 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style"></property> <property name="window_style"></property>
<object class="splitteritem" expanded="0"> <object class="splitteritem" expanded="1">
<object class="wxPanel" expanded="0"> <object class="wxPanel" expanded="1">
<property name="BottomDockable">1</property> <property name="BottomDockable">1</property>
<property name="LeftDockable">1</property> <property name="LeftDockable">1</property>
<property name="RightDockable">1</property> <property name="RightDockable">1</property>
@ -288,7 +288,7 @@
<property name="window_extra_style"></property> <property name="window_extra_style"></property>
<property name="window_name"></property> <property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property> <property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="0"> <object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property> <property name="minimum_size"></property>
<property name="name">m_sizerPlot</property> <property name="name">m_sizerPlot</property>
<property name="orient">wxHORIZONTAL</property> <property name="orient">wxHORIZONTAL</property>
@ -353,6 +353,7 @@
<property name="window_style"></property> <property name="window_style"></property>
<event name="OnAuiNotebookEndDrag">onPlotDragged</event> <event name="OnAuiNotebookEndDrag">onPlotDragged</event>
<event name="OnAuiNotebookPageChanged">onPlotChanged</event> <event name="OnAuiNotebookPageChanged">onPlotChanged</event>
<event name="OnAuiNotebookPageChanging">onPlotChanging</event>
<event name="OnAuiNotebookPageClose">onPlotClose</event> <event name="OnAuiNotebookPageClose">onPlotClose</event>
<event name="OnAuiNotebookPageClosed">onPlotClosed</event> <event name="OnAuiNotebookPageClosed">onPlotClosed</event>
</object> </object>

View File

@ -67,6 +67,7 @@ class SIMULATOR_PANEL_BASE : public wxPanel
// Virtual event handlers, override them in your derived class // Virtual event handlers, override them in your derived class
virtual void onPlotDragged( wxAuiNotebookEvent& event ) { event.Skip(); } virtual void onPlotDragged( wxAuiNotebookEvent& event ) { event.Skip(); }
virtual void onPlotChanged( wxAuiNotebookEvent& event ) { event.Skip(); } virtual void onPlotChanged( wxAuiNotebookEvent& event ) { event.Skip(); }
virtual void onPlotChanging( wxAuiNotebookEvent& event ) { event.Skip(); }
virtual void onPlotClose( wxAuiNotebookEvent& event ) { event.Skip(); } virtual void onPlotClose( wxAuiNotebookEvent& event ) { event.Skip(); }
virtual void onPlotClosed( wxAuiNotebookEvent& event ) { event.Skip(); } virtual void onPlotClosed( wxAuiNotebookEvent& event ) { event.Skip(); }
virtual void OnFilterMouseMoved( wxMouseEvent& event ) { event.Skip(); } virtual void OnFilterMouseMoved( wxMouseEvent& event ) { event.Skip(); }

View File

@ -54,18 +54,19 @@ wxString SPICE_SIMULATOR::TypeToName( SIM_TYPE aType, bool aShortName )
{ {
switch( aType ) switch( aType )
{ {
case ST_OP: return aShortName ? wxString( wxT( "OP" ) ) : _( "Operating Point" ); case ST_OP: return aShortName ? wxString( wxT( "OP" ) ) : _( "DC Operating Point" );
case ST_AC: return aShortName ? wxString( wxT( "AC" ) ) : _( "AC" ); case ST_AC: return aShortName ? wxString( wxT( "AC" ) ) : _( "Small-Signal Analysis" );
case ST_DC: return aShortName ? wxString( wxT( "DC" ) ) : _( "DC Sweep" ); case ST_DC: return aShortName ? wxString( wxT( "DC" ) ) : _( "DC Sweep Analysis" );
case ST_TRANSIENT: return aShortName ? wxString( wxT( "TRAN" ) ) : _( "Transient" ); case ST_TRAN: return aShortName ? wxString( wxT( "TRAN" ) ) : _( "Transient Analysis" );
case ST_DISTORTION: return aShortName ? wxString( wxT( "DISTO" ) ) : _( "Distortion" ); case ST_DISTO: return aShortName ? wxString( wxT( "DISTO" ) ) : _( "Small-Signal Distortion Analysis" );
case ST_NOISE: return aShortName ? wxString( wxT( "NOISE" ) ) : _( "Noise" ); case ST_NOISE: return aShortName ? wxString( wxT( "NOISE" ) ) : _( "Noise Analysis" );
case ST_POLE_ZERO: return aShortName ? wxString( wxT( "PZ" ) ) : _( "Pole-zero" ); case ST_PZ: return aShortName ? wxString( wxT( "PZ" ) ) : _( "Pole-Zero Analysis" );
case ST_SENSITIVITY: return aShortName ? wxString( wxT( "SENS" ) ) : _( "Sensitivity" ); case ST_SENS: return aShortName ? wxString( wxT( "SENS" ) ) : _( "Sensitivity Analysis" );
case ST_TRANS_FUNC: return aShortName ? wxString( wxT( "TF" ) ) : _( "Transfer function" ); case ST_TF: return aShortName ? wxString( wxT( "TF" ) ) : _( "Transfer Function Analysis" );
case ST_S_PARAM: return aShortName ? wxString( wxT( "SP" ) ) : _( "S-Parameters" ); case ST_SP: return aShortName ? wxString( wxT( "SP" ) ) : _( "S-Parameter Analysis" );
case ST_FFT: return aShortName ? wxString( wxT( "FFT" ) ) : _( "Frequency Content Analysis" );
default: default:
case ST_UNKNOWN: return aShortName ? wxString( wxT( "??" ) ) : _( "Unknown" ); case ST_UNKNOWN: return aShortName ? wxString( wxT( "??" ) ) : _( "Unknown" );
} }
} }

View File

@ -49,6 +49,7 @@ void SIMULATOR_FRAME::ReCreateHToolbar()
m_toolBar->Add( EE_ACTIONS::saveWorkbook ); m_toolBar->Add( EE_ACTIONS::saveWorkbook );
m_toolBar->AddScaledSeparator( this ); m_toolBar->AddScaledSeparator( this );
m_toolBar->Add( EE_ACTIONS::newPlot );
m_toolBar->Add( EE_ACTIONS::simCommand ); m_toolBar->Add( EE_ACTIONS::simCommand );
m_toolBar->AddScaledSeparator( this ); m_toolBar->AddScaledSeparator( this );
@ -134,6 +135,7 @@ void SIMULATOR_FRAME::doReCreateMenuBar()
simulationMenu->Add( EE_ACTIONS::simTune ); simulationMenu->Add( EE_ACTIONS::simTune );
simulationMenu->AppendSeparator(); simulationMenu->AppendSeparator();
simulationMenu->Add( EE_ACTIONS::editUserDefinedSignals );
simulationMenu->Add( EE_ACTIONS::showNetlist ); simulationMenu->Add( EE_ACTIONS::showNetlist );

View File

@ -1,5 +1,7 @@
// Do not edit this file, it is autogenerated by CMake from the .md file // Do not edit this file, it is autogenerated by CMake from the .md file
_HKI( " sqrt(x)\n" _HKI( "SPICE functions:\n"
"\n"
" sqrt(x)\n"
" sin(x)\n" " sin(x)\n"
" cos(x)\n" " cos(x)\n"
" tan(x)\n" " tan(x)\n"

View File

@ -1121,7 +1121,7 @@ TOOL_ACTION EE_ACTIONS::newPlot( "eeschema.Simulation.newPlot",
AS_GLOBAL, AS_GLOBAL,
MD_CTRL + 'N', LEGACY_HK_NAME( "New" ), MD_CTRL + 'N', LEGACY_HK_NAME( "New" ),
_( "New Plot" ), "", _( "New Plot" ), "",
BITMAPS::new_generic ); BITMAPS::sim_add_plot );
TOOL_ACTION EE_ACTIONS::openWorkbook( "eeschema.Simulation.openWorkbook", TOOL_ACTION EE_ACTIONS::openWorkbook( "eeschema.Simulation.openWorkbook",
AS_GLOBAL, AS_GLOBAL,
@ -1201,12 +1201,6 @@ TOOL_ACTION EE_ACTIONS::editUserDefinedSignals( "eeschema.Simulation.editUserDef
_( "Add, edit or delete user-defined simulation signals" ), _( "Add, edit or delete user-defined simulation signals" ),
BITMAPS::sim_add_signal ); BITMAPS::sim_add_signal );
TOOL_ACTION EE_ACTIONS::showFFT( "eeschema.Simulation.showFFT",
AS_GLOBAL, 0, "",
_( "Show FFT" ),
_( "Show frequency distribution of transient analysis data using fast Fourier transform" ),
BITMAPS::mw_add_shape );
TOOL_ACTION EE_ACTIONS::showNetlist( "eeschema.Simulation.showNetlist", TOOL_ACTION EE_ACTIONS::showNetlist( "eeschema.Simulation.showNetlist",
AS_GLOBAL, 0, "", AS_GLOBAL, 0, "",
_( "Show SPICE Netlist" ), "", _( "Show SPICE Netlist" ), "",

View File

@ -277,7 +277,6 @@ public:
static TOOL_ACTION runSimulation; static TOOL_ACTION runSimulation;
static TOOL_ACTION stopSimulation; static TOOL_ACTION stopSimulation;
static TOOL_ACTION editUserDefinedSignals; static TOOL_ACTION editUserDefinedSignals;
static TOOL_ACTION showFFT;
static TOOL_ACTION showNetlist; static TOOL_ACTION showNetlist;
// Net highlighting // Net highlighting

View File

@ -62,14 +62,23 @@ void SIMULATOR_CONTROL::Reset( RESET_REASON aReason )
int SIMULATOR_CONTROL::NewPlot( const TOOL_EVENT& aEvent ) int SIMULATOR_CONTROL::NewPlot( const TOOL_EVENT& aEvent )
{ {
SIM_TYPE type = m_circuitModel->GetSimType(); DIALOG_SIM_COMMAND dlg( m_simulatorFrame, m_circuitModel, m_simulator->Settings() );
wxString errors;
WX_STRING_REPORTER reporter( &errors );
if( SIM_PLOT_PANEL_BASE::IsPlottable( type ) ) if( !m_circuitModel->ReadSchematicAndLibraries( NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS,
reporter ) )
{ {
m_simulatorFrame->NewPlotPanel( m_circuitModel->GetSimCommand(), DisplayErrorMessage( m_simulatorFrame,
m_circuitModel->GetSimOptions() ); _( "Errors during netlist generation.\n\n" ) + errors );
} }
dlg.SetSimCommand( wxS( "*" ) );
dlg.SetSimOptions( NETLIST_EXPORTER_SPICE::OPTION_DEFAULT_FLAGS );
if( dlg.ShowModal() == wxID_OK )
m_simulatorFrame->NewPlotPanel( dlg.GetSimCommand(), dlg.GetSimOptions() );
return 0; return 0;
} }
@ -145,71 +154,77 @@ int SIMULATOR_CONTROL::SaveWorkbook( const TOOL_EVENT& aEvent )
int SIMULATOR_CONTROL::ExportPlotAsPNG( const TOOL_EVENT& aEvent ) int SIMULATOR_CONTROL::ExportPlotAsPNG( const TOOL_EVENT& aEvent )
{ {
if( !m_simulatorFrame->GetCurrentPlot() ) if( SIM_PLOT_PANEL* plotPanel = GetCurrentPlotPanel() )
return -1; {
wxFileDialog saveDlg( m_simulatorFrame, _( "Save Plot as Image" ), "", "",
PngFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
wxFileDialog saveDlg( m_simulatorFrame, _( "Save Plot as Image" ), "", "", PngFileWildcard(), if( saveDlg.ShowModal() == wxID_CANCEL )
wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); return -1;
if( saveDlg.ShowModal() == wxID_CANCEL ) plotPanel->GetPlotWin()->SaveScreenshot( saveDlg.GetPath(), wxBITMAP_TYPE_PNG );
return -1; }
m_simulatorFrame->GetCurrentPlot()->GetPlotWin()->SaveScreenshot( saveDlg.GetPath(),
wxBITMAP_TYPE_PNG );
return 0; return 0;
} }
SIM_PLOT_PANEL* SIMULATOR_CONTROL::GetCurrentPlotPanel()
{
return dynamic_cast<SIM_PLOT_PANEL*>( m_simulatorFrame->GetCurrentPlotPanel() );
}
int SIMULATOR_CONTROL::ExportPlotAsCSV( const TOOL_EVENT& aEvent ) int SIMULATOR_CONTROL::ExportPlotAsCSV( const TOOL_EVENT& aEvent )
{ {
if( !m_simulatorFrame->GetCurrentPlot() ) if( SIM_PLOT_PANEL* plotPanel = GetCurrentPlotPanel() )
return -1;
const wxChar SEPARATOR = ';';
wxFileDialog saveDlg( m_simulatorFrame, _( "Save Plot Data" ), "", "", CsvFileWildcard(),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
if( saveDlg.ShowModal() == wxID_CANCEL )
return -1;
wxFFile out( saveDlg.GetPath(), "wb" );
std::map<wxString, TRACE*> traces = m_simulatorFrame->GetCurrentPlot()->GetTraces();
if( traces.size() == 0 )
return -1;
SIM_TYPE simType = m_circuitModel->GetSimType();
std::size_t rowCount = traces.begin()->second->GetDataX().size();
// write column header names on the first row
wxString xAxisName( m_simulator->GetXAxis( simType ) );
out.Write( wxString::Format( wxT( "%s%c" ), xAxisName, SEPARATOR ) );
for( const auto& [name, trace] : traces )
out.Write( wxString::Format( wxT( "%s%c" ), name, SEPARATOR ) );
out.Write( wxS( "\r\n" ) );
// write each row's numerical value
for ( std::size_t curRow=0; curRow < rowCount; curRow++ )
{ {
double xAxisValue = traces.begin()->second->GetDataX().at( curRow ); const wxChar SEPARATOR = ';';
out.Write( wxString::Format( wxT( "%g%c" ), xAxisValue, SEPARATOR ) );
wxFileDialog saveDlg( m_simulatorFrame, _( "Save Plot Data" ), "", "", CsvFileWildcard(),
wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
if( saveDlg.ShowModal() == wxID_CANCEL )
return -1;
wxFFile out( saveDlg.GetPath(), "wb" );
std::map<wxString, TRACE*> traces = plotPanel->GetTraces();
if( traces.size() == 0 )
return -1;
SIM_TYPE simType = plotPanel->GetSimType();
std::size_t rowCount = traces.begin()->second->GetDataX().size();
// write column header names on the first row
wxString xAxisName( m_simulator->GetXAxis( simType ) );
out.Write( wxString::Format( wxT( "%s%c" ), xAxisName, SEPARATOR ) );
for( const auto& [name, trace] : traces ) for( const auto& [name, trace] : traces )
{ out.Write( wxString::Format( wxT( "%s%c" ), name, SEPARATOR ) );
double yAxisValue = trace->GetDataY().at( curRow );
out.Write( wxString::Format( wxT( "%g%c" ), yAxisValue, SEPARATOR ) );
}
out.Write( wxS( "\r\n" ) ); out.Write( wxS( "\r\n" ) );
// write each row's numerical value
for ( std::size_t curRow=0; curRow < rowCount; curRow++ )
{
double xAxisValue = traces.begin()->second->GetDataX().at( curRow );
out.Write( wxString::Format( wxT( "%g%c" ), xAxisValue, SEPARATOR ) );
for( const auto& [name, trace] : traces )
{
double yAxisValue = trace->GetDataY().at( curRow );
out.Write( wxString::Format( wxT( "%g%c" ), yAxisValue, SEPARATOR ) );
}
out.Write( wxS( "\r\n" ) );
}
out.Close();
} }
out.Close();
return 0; return 0;
} }
@ -223,14 +238,11 @@ int SIMULATOR_CONTROL::Close( const TOOL_EVENT& aEvent )
int SIMULATOR_CONTROL::Zoom( const TOOL_EVENT& aEvent ) int SIMULATOR_CONTROL::Zoom( const TOOL_EVENT& aEvent )
{ {
if( m_simulatorFrame->GetCurrentPlot() ) if( SIM_PLOT_PANEL* plotPanel = GetCurrentPlotPanel() )
{ {
if( aEvent.IsAction( &ACTIONS::zoomInCenter ) ) if( aEvent.IsAction( &ACTIONS::zoomInCenter ) ) plotPanel->GetPlotWin()->ZoomIn();
m_simulatorFrame->GetCurrentPlot()->GetPlotWin()->ZoomIn(); else if( aEvent.IsAction( &ACTIONS::zoomOutCenter ) ) plotPanel->GetPlotWin()->ZoomOut();
else if( aEvent.IsAction( &ACTIONS::zoomOutCenter ) ) else if( aEvent.IsAction( &ACTIONS::zoomFitScreen ) ) plotPanel->GetPlotWin()->Fit();
m_simulatorFrame->GetCurrentPlot()->GetPlotWin()->ZoomOut();
else if( aEvent.IsAction( &ACTIONS::zoomFitScreen ) )
m_simulatorFrame->GetCurrentPlot()->GetPlotWin()->Fit();
} }
return 0; return 0;
@ -239,11 +251,9 @@ int SIMULATOR_CONTROL::Zoom( const TOOL_EVENT& aEvent )
int SIMULATOR_CONTROL::ToggleGrid( const TOOL_EVENT& aEvent ) int SIMULATOR_CONTROL::ToggleGrid( const TOOL_EVENT& aEvent )
{ {
SIM_PLOT_PANEL* plot = m_simulatorFrame->GetCurrentPlot(); if( SIM_PLOT_PANEL* plotPanel = GetCurrentPlotPanel() )
if( plot )
{ {
plot->ShowGrid( !plot->IsGridShown() ); plotPanel->ShowGrid( !plotPanel->IsGridShown() );
m_simulatorFrame->OnModify(); m_simulatorFrame->OnModify();
} }
@ -253,11 +263,9 @@ int SIMULATOR_CONTROL::ToggleGrid( const TOOL_EVENT& aEvent )
int SIMULATOR_CONTROL::ToggleLegend( const TOOL_EVENT& aEvent ) int SIMULATOR_CONTROL::ToggleLegend( const TOOL_EVENT& aEvent )
{ {
SIM_PLOT_PANEL* plot = m_simulatorFrame->GetCurrentPlot(); if( SIM_PLOT_PANEL* plotPanel = GetCurrentPlotPanel() )
if( plot )
{ {
plot->ShowLegend( !plot->IsLegendShown() ); plotPanel->ShowLegend( !plotPanel->IsLegendShown() );
m_simulatorFrame->OnModify(); m_simulatorFrame->OnModify();
} }
@ -267,11 +275,9 @@ int SIMULATOR_CONTROL::ToggleLegend( const TOOL_EVENT& aEvent )
int SIMULATOR_CONTROL::ToggleDottedSecondary( const TOOL_EVENT& aEvent ) int SIMULATOR_CONTROL::ToggleDottedSecondary( const TOOL_EVENT& aEvent )
{ {
SIM_PLOT_PANEL* plot = m_simulatorFrame->GetCurrentPlot(); if( SIM_PLOT_PANEL* plotPanel = GetCurrentPlotPanel() )
if( plot )
{ {
plot->SetDottedSecondary( !plot->GetDottedSecondary() ); plotPanel->SetDottedSecondary( !plotPanel->GetDottedSecondary() );
m_simulatorFrame->OnModify(); m_simulatorFrame->OnModify();
} }
@ -296,9 +302,18 @@ int SIMULATOR_CONTROL::EditSimCommand( const TOOL_EVENT& aEvent )
int SIMULATOR_CONTROL::RunSimulation( const TOOL_EVENT& aEvent ) int SIMULATOR_CONTROL::RunSimulation( const TOOL_EVENT& aEvent )
{ {
if( m_simulator->IsRunning() ) if( m_simulator->IsRunning() )
{
m_simulator->Stop(); m_simulator->Stop();
else return 0;
m_simulatorFrame->StartSimulation(); }
if( !GetCurrentPlotPanel() )
NewPlot( aEvent );
if( !GetCurrentPlotPanel() )
return 0;
m_simulatorFrame->StartSimulation();
return 0; return 0;
} }
@ -444,8 +459,9 @@ int SIMULATOR_CONTROL::ShowNetlist( const TOOL_EVENT& aEvent )
STRING_FORMATTER formatter; STRING_FORMATTER formatter;
NETLIST_VIEW_DIALOG dlg( m_simulatorFrame ); NETLIST_VIEW_DIALOG dlg( m_simulatorFrame );
m_circuitModel->SetSimOptions( m_simulatorFrame->GetCurrentOptions() ); m_circuitModel->GetNetlist( m_simulatorFrame->GetCurrentSimCommand(),
m_circuitModel->GetNetlist( &formatter, *dlg.GetReporter() ); m_simulatorFrame->GetCurrentOptions(),
&formatter, *dlg.GetReporter() );
dlg.SetNetlist( wxString( formatter.GetString() ) ); dlg.SetNetlist( wxString( formatter.GetString() ) );
dlg.ShowModal(); dlg.ShowModal();

View File

@ -30,6 +30,7 @@
class SIMULATOR_FRAME; class SIMULATOR_FRAME;
class NGSPICE_CIRCUIT_MODEL; class NGSPICE_CIRCUIT_MODEL;
class SPICE_SIMULATOR; class SPICE_SIMULATOR;
class SIM_PLOT_PANEL;
/** /**
@ -84,6 +85,8 @@ private:
*/ */
wxString getDefaultPath(); wxString getDefaultPath();
SIM_PLOT_PANEL* GetCurrentPlotPanel();
///< Set up handlers for various events. ///< Set up handlers for various events.
void setTransitions() override; void setTransitions() override;

View File

@ -525,6 +525,7 @@ enum class BITMAPS : unsigned int
show_zone_outline_only, show_zone_outline_only,
show_zone_triangulation, show_zone_triangulation,
showtrack, showtrack,
sim_add_plot,
sim_add_signal, sim_add_signal,
sim_command, sim_command,
sim_probe, sim_probe,

View File

@ -1060,10 +1060,7 @@ class WXDLLIMPEXP_MATHPLOT mpWindow : public wxWindow
{ {
public: public:
mpWindow(); mpWindow();
mpWindow( wxWindow* parent, wxWindowID id, mpWindow( wxWindow* parent, wxWindowID id );
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long flags = 0 );
~mpWindow(); ~mpWindow();
/** Get reference to context menu of the plot canvas. /** Get reference to context menu of the plot canvas.

View File

@ -83,8 +83,8 @@ BOOST_AUTO_TEST_CASE( CommandToSimType )
std::vector<struct TEST_DATA> testData = { std::vector<struct TEST_DATA> testData = {
{ ".op", ST_OP }, { ".op", ST_OP },
{ ".option TEMP=27", ST_UNKNOWN }, { ".option TEMP=27", ST_UNKNOWN },
{ ".tran 0 1 0.1", ST_TRANSIENT }, { ".tran 0 1 0.1", ST_TRAN },
{ ".tran 0 1 0.1 UIC", ST_TRANSIENT }, { ".tran 0 1 0.1 UIC", ST_TRAN },
{ ".ac dec 10 1 10K", ST_AC }, { ".ac dec 10 1 10K", ST_AC },
{ ".ac dec 10 1K 100MEG", ST_AC }, { ".ac dec 10 1K 100MEG", ST_AC },
{ ".ac lin 100 1 100HZ", ST_AC }, { ".ac lin 100 1 100HZ", ST_AC },
@ -93,18 +93,18 @@ BOOST_AUTO_TEST_CASE( CommandToSimType )
{ ".dc VCE 0 10 .25 IB 0 10u 1u", ST_DC }, { ".dc VCE 0 10 .25 IB 0 10u 1u", ST_DC },
{ ".dc RLoad 1k 2k 100", ST_DC }, { ".dc RLoad 1k 2k 100", ST_DC },
{ ".dc TEMP -15 75 5", ST_DC }, { ".dc TEMP -15 75 5", ST_DC },
{ ".disto dec 10 1kHz 100MEG", ST_DISTORTION }, { ".disto dec 10 1kHz 100MEG", ST_DISTO },
{ ".disto dec 10 1kHz 100MEG 0.9", ST_DISTORTION }, { ".disto dec 10 1kHz 100MEG 0.9", ST_DISTO },
{ ".noise v(5) VIN dec 10 1kHz 100MEG", ST_NOISE }, { ".noise v(5) VIN dec 10 1kHz 100MEG", ST_NOISE },
{ ".noise v(5,3) V1 oct 8 1.0 1.0e6 1", ST_NOISE }, { ".noise v(5,3) V1 oct 8 1.0 1.0e6 1", ST_NOISE },
{ ".pz 1 0 3 0 cur pol", ST_POLE_ZERO }, { ".pz 1 0 3 0 cur pol", ST_PZ },
{ ".pz 2 3 5 0 vol zer", ST_POLE_ZERO }, { ".pz 2 3 5 0 vol zer", ST_PZ },
{ ".pz 4 1 4 1 cur pz", ST_POLE_ZERO }, { ".pz 4 1 4 1 cur pz", ST_PZ },
{ ".SENS V(1,OUT)", ST_SENSITIVITY }, { ".SENS V(1,OUT)", ST_SENS },
{ ".SENS V(OUT) AC DEC 10 100 100k", ST_SENSITIVITY }, { ".SENS V(OUT) AC DEC 10 100 100k", ST_SENS },
{ ".SENS I(VTEST)", ST_SENSITIVITY }, { ".SENS I(VTEST)", ST_SENS },
{ ".tf v(5, 3) VIN", ST_TRANS_FUNC }, { ".tf v(5, 3) VIN", ST_TF },
{ ".tf i(VLOAD) VIN", ST_TRANS_FUNC }, { ".tf i(VLOAD) VIN", ST_TF },
}; };
for( auto& step : testData ) for( auto& step : testData )

View File

@ -458,6 +458,7 @@ set( BMAPS_MID
shape_3d_back shape_3d_back
sheetset sheetset
simulator simulator
sim_add_plot
sim_command sim_command
sim_run sim_run
sim_stop sim_stop

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
id="Слой_1"
data-name="Слой 1"
viewBox="0 0 24 24"
version="1.1"
sodipodi:docname="sim_add_plot.svg"
inkscape:version="1.2.1 (9c6d41e, 2022-07-14)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1728"
inkscape:window-height="987"
id="namedview30"
showgrid="true"
inkscape:zoom="39.543586"
inkscape:cx="12.03735"
inkscape:cy="15.286929"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="0"
inkscape:document-rotation="0"
inkscape:current-layer="Слой_1"
inkscape:showpageshadow="2"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid
type="xygrid"
id="grid_kicad"
spacingx="0.5"
spacingy="0.5"
color="#9999ff"
opacity="0.13"
empspacing="2" />
</sodipodi:namedview>
<metadata
id="metadata43">
<rdf:RDF>
<cc:Work
rdf:about="">
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>simulator</dc:title>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<defs
id="defs159987">
<style
id="style159985">.cls-1{fill:#b9b9b9;}.cls-2,.cls-3{fill:none;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.25px;}.cls-2{stroke:#bf2641;}.cls-3{stroke:#1a81c4;}</style>
</defs>
<title
id="title159989">simulator</title>
<circle
style="fill:#ffffff;fill-opacity:1;stroke:#545454;stroke-width:1.37198;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path841"
cx="11.987356"
cy="11.987356"
r="10.289825" />
<path
style="fill:none;stroke:#545454;stroke-width:0.953986;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 2.251549,12.5 H 19.543938"
id="path843"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#545454;stroke-width:0.898072;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 5.5,16.008526 V 4.7248423"
id="path845"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#1a81c4;stroke-width:1.4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 3.5,14.5 c 0,0 1.3518787,-7 2.8518787,-7 1.5,0 1.6002744,8.070806 3.0698938,8.060622 C 11.421725,15.546763 10.617219,4.5 12.617219,4.5 c 2,0 1.314653,14.512198 2.814653,14.512198 1.201824,0 1.002258,-3.266618 1.988097,-4.624305 C 17.831854,13.820649 18.5,13 19,13"
id="path865"
sodipodi:nodetypes="cssssac" />
<ellipse
style="fill:none;fill-opacity:1;stroke:#545454;stroke-width:1.37119;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="circle851"
cx="12"
cy="12.012644"
rx="10.277575"
ry="10.290219" />
<g
id="g856"
style="display:inline"
transform="translate(-0.00609355,0.0252947)">
<circle
class="cls-5"
cx="16.800095"
cy="16.793707"
id="circle27864"
style="fill:#bf2641;stroke-width:0.971428"
r="6.8000002" />
<line
class="cls-6"
x1="17.094093"
y1="13.593705"
x2="17.094093"
y2="20.593706"
id="line27866"
style="fill:none;stroke:#f5f5f5;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
<line
class="cls-6"
x1="20.594093"
y1="17.093706"
x2="13.594093"
y2="17.093706"
id="line27868"
style="fill:none;stroke:#f5f5f5;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none" />
</g>
<ellipse
style="fill:none;stroke:#ffffff;stroke-width:0.93712;stroke-dasharray:none;stroke-opacity:1"
id="path693"
cx="17.08"
cy="17.130001"
rx="6.8064399"
ry="6.8064404" />
</svg>

After

Width:  |  Height:  |  Size: 5.3 KiB