From 356ccd0314a51d7c23751695a4eba444de979520 Mon Sep 17 00:00:00 2001 From: Jon Evans Date: Mon, 27 May 2019 18:13:00 -0400 Subject: [PATCH] Eeschema: improve simulator behavior for two-source DC analysis Fixes: lp:1830478 * https://bugs.launchpad.net/kicad/+bug/1830478 --- eeschema/dialogs/dialog_sim_settings.cpp | 6 +++ eeschema/sim/netlist_exporter_pspice_sim.cpp | 41 ++++++++++++++++++- eeschema/sim/netlist_exporter_pspice_sim.h | 25 ++++++++++++ eeschema/sim/sim_plot_frame.cpp | 43 ++++++++++++++++++++ eeschema/sim/sim_plot_panel.cpp | 2 +- 5 files changed, 115 insertions(+), 2 deletions(-) diff --git a/eeschema/dialogs/dialog_sim_settings.cpp b/eeschema/dialogs/dialog_sim_settings.cpp index 61b848c09d..7010807b90 100644 --- a/eeschema/dialogs/dialog_sim_settings.cpp +++ b/eeschema/dialogs/dialog_sim_settings.cpp @@ -158,6 +158,12 @@ bool DIALOG_SIM_SETTINGS::TransferDataFromWindow() return false; } + if( m_dcEnable1->IsChecked() && m_dcSource1->GetValue() == m_dcSource2->GetValue() ) + { + DisplayError( this, _( "Source 1 and Source 2 must be different" ) ); + return false; + } + /// @todo for some reason it does not trigger the assigned SPICE_VALIDATOR, // hence try..catch below if( !m_dcStart2->Validate() || !m_dcStop2->Validate() || !m_dcIncr2->Validate() ) diff --git a/eeschema/sim/netlist_exporter_pspice_sim.cpp b/eeschema/sim/netlist_exporter_pspice_sim.cpp index 2fdc043e99..3178c8dd1a 100644 --- a/eeschema/sim/netlist_exporter_pspice_sim.cpp +++ b/eeschema/sim/netlist_exporter_pspice_sim.cpp @@ -23,6 +23,7 @@ */ #include "netlist_exporter_pspice_sim.h" +#include wxString NETLIST_EXPORTER_PSPICE_SIM::GetSpiceVector( const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam ) const @@ -101,9 +102,15 @@ wxString NETLIST_EXPORTER_PSPICE_SIM::GetSheetSimCommand() } +wxString NETLIST_EXPORTER_PSPICE_SIM::GetUsedSimCommand() +{ + return m_simCommand.IsEmpty() ? GetSheetSimCommand() : m_simCommand; +} + + SIM_TYPE NETLIST_EXPORTER_PSPICE_SIM::GetSimType() { - return CommandToSimType( m_simCommand.IsEmpty() ? GetSheetSimCommand() : m_simCommand ); + return CommandToSimType( GetUsedSimCommand() ); } @@ -126,6 +133,38 @@ SIM_TYPE NETLIST_EXPORTER_PSPICE_SIM::CommandToSimType( const wxString& aCmd ) } +bool NETLIST_EXPORTER_PSPICE_SIM::ParseDCCommand( const wxString& aCmd, SPICE_DC_PARAMS* aSource1, + SPICE_DC_PARAMS* aSource2 ) +{ + if( !aCmd.Lower().StartsWith( ".dc" ) ) + return false; + + wxString cmd = aCmd.Mid( 3 ).Trim().Trim( false ); + + wxStringTokenizer tokens( cmd ); + + size_t num = tokens.CountTokens(); + + if( num != 4 && num != 8 ) + return false; + + aSource1->m_source = tokens.GetNextToken(); + aSource1->m_vstart = SPICE_VALUE( tokens.GetNextToken() ); + aSource1->m_vend = SPICE_VALUE( tokens.GetNextToken() ); + aSource1->m_vincrement = SPICE_VALUE( tokens.GetNextToken() ); + + if( num == 8 ) + { + aSource2->m_source = tokens.GetNextToken(); + aSource2->m_vstart = SPICE_VALUE( tokens.GetNextToken() ); + aSource2->m_vend = SPICE_VALUE( tokens.GetNextToken() ); + aSource2->m_vincrement = SPICE_VALUE( tokens.GetNextToken() ); + } + + return true; +} + + void NETLIST_EXPORTER_PSPICE_SIM::writeDirectives( OUTPUTFORMATTER* aFormatter, unsigned aCtl ) const { // Add a directive to obtain currents diff --git a/eeschema/sim/netlist_exporter_pspice_sim.h b/eeschema/sim/netlist_exporter_pspice_sim.h index 31093dd552..aeacbb7987 100644 --- a/eeschema/sim/netlist_exporter_pspice_sim.h +++ b/eeschema/sim/netlist_exporter_pspice_sim.h @@ -31,6 +31,16 @@ #include #include "sim_types.h" +#include "spice_value.h" + + +struct SPICE_DC_PARAMS +{ + wxString m_source; + SPICE_VALUE m_vstart; + SPICE_VALUE m_vend; + SPICE_VALUE m_vincrement; +}; /// Special netlist exporter flavor that allows one to override simulation commands class NETLIST_EXPORTER_PSPICE_SIM : public NETLIST_EXPORTER_PSPICE @@ -82,6 +92,12 @@ public: m_simCommand.Clear(); } + /** + * Returns the command directive that is in use (either from the sheet or from m_simCommand + * @return + */ + wxString GetUsedSimCommand(); + /** * @brief Returns simulation type basing on the simulation command directives. * Simulation directives set using SetSimCommand() have priority over the ones placed in @@ -94,6 +110,15 @@ public: */ wxString GetSheetSimCommand(); + /** + * Parses a two-source .dc command directive into its components + * + * @param aCmd is the input command string + * @return true if the command was parsed successfully + */ + bool ParseDCCommand( const wxString& aCmd, SPICE_DC_PARAMS* aSource1, + SPICE_DC_PARAMS* aSource2 ); + /** * @brief Determines if a directive is a simulation command. */ diff --git a/eeschema/sim/sim_plot_frame.cpp b/eeschema/sim/sim_plot_frame.cpp index 3812d0c3bd..ffceefa3df 100644 --- a/eeschema/sim/sim_plot_frame.cpp +++ b/eeschema/sim/sim_plot_frame.cpp @@ -547,6 +547,49 @@ bool SIM_PLOT_FRAME::updatePlot( const TRACE_DESC& aDescriptor, SIM_PLOT_PANEL* if( data_y.size() != size ) return false; + // If we did a two-source DC analysis, we need to split the resulting vector and add traces + // for each input step + SPICE_DC_PARAMS source1, source2; + + if( m_exporter->GetSimType() == ST_DC && + m_exporter->ParseDCCommand( m_exporter->GetUsedSimCommand(), &source1, &source2 ) ) + { + if( !source2.m_source.IsEmpty() ) + { + // Source 1 is the inner loop, so lets add traces for each Source 2 (outer loop) step + SPICE_VALUE v = source2.m_vstart; + wxString name; + + size_t offset = 0; + size_t outer = ( size_t )( ( source2.m_vend - v ) / source2.m_vincrement ).ToDouble(); + size_t inner = data_x.size() / ( outer + 1 ); + + wxASSERT( data_x.size() % ( outer + 1 ) == 0 ); + + for( size_t idx = 0; idx <= outer; idx++ ) + { + name = wxString::Format( "%s (%s = %s V)", aDescriptor.GetTitle(), + source2.m_source, v.ToString() ); + + std::vector sub_x( data_x.begin() + offset, + data_x.begin() + offset + inner ); + std::vector sub_y( data_y.begin() + offset, + data_y.begin() + offset + inner ); + + if( aPanel->AddTrace( name, inner, + sub_x.data(), sub_y.data(), aDescriptor.GetType() ) ) + { + m_plots[aPanel].m_traces.insert( std::make_pair( name, aDescriptor ) ); + } + + v = v + source2.m_vincrement; + offset += inner; + } + + return true; + } + } + if( aPanel->AddTrace( aDescriptor.GetTitle(), size, data_x.data(), data_y.data(), aDescriptor.GetType() ) ) { diff --git a/eeschema/sim/sim_plot_panel.cpp b/eeschema/sim/sim_plot_panel.cpp index d6b0e368f8..70b1e05a75 100644 --- a/eeschema/sim/sim_plot_panel.cpp +++ b/eeschema/sim/sim_plot_panel.cpp @@ -384,7 +384,7 @@ SIM_PLOT_PANEL::SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, wxWindowID id, break; case ST_DC: - m_axis_x = new VOLTAGE_SCALE_X( _( "Voltage (sweeped)" ), mpALIGN_BOTTOM ); + m_axis_x = new VOLTAGE_SCALE_X( _( "Voltage (swept)" ), mpALIGN_BOTTOM ); m_axis_y1 = new VOLTAGE_SCALE_Y( _( "Voltage (measured)" ), mpALIGN_LEFT ); m_axis_y2 = new CURRENT_SCALE( _( "Current" ), mpALIGN_RIGHT ); break;