Eeschema: improve simulator behavior for two-source DC analysis

Fixes: lp:1830478
* https://bugs.launchpad.net/kicad/+bug/1830478
This commit is contained in:
Jon Evans 2019-05-27 18:13:00 -04:00
parent 4adf89b40b
commit 356ccd0314
5 changed files with 115 additions and 2 deletions

View File

@ -158,6 +158,12 @@ bool DIALOG_SIM_SETTINGS::TransferDataFromWindow()
return false; 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, /// @todo for some reason it does not trigger the assigned SPICE_VALIDATOR,
// hence try..catch below // hence try..catch below
if( !m_dcStart2->Validate() || !m_dcStop2->Validate() || !m_dcIncr2->Validate() ) if( !m_dcStart2->Validate() || !m_dcStop2->Validate() || !m_dcIncr2->Validate() )

View File

@ -23,6 +23,7 @@
*/ */
#include "netlist_exporter_pspice_sim.h" #include "netlist_exporter_pspice_sim.h"
#include <wx/tokenzr.h>
wxString NETLIST_EXPORTER_PSPICE_SIM::GetSpiceVector( const wxString& aName, SIM_PLOT_TYPE aType, wxString NETLIST_EXPORTER_PSPICE_SIM::GetSpiceVector( const wxString& aName, SIM_PLOT_TYPE aType,
const wxString& aParam ) const 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() 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 void NETLIST_EXPORTER_PSPICE_SIM::writeDirectives( OUTPUTFORMATTER* aFormatter, unsigned aCtl ) const
{ {
// Add a directive to obtain currents // Add a directive to obtain currents

View File

@ -31,6 +31,16 @@
#include <vector> #include <vector>
#include "sim_types.h" #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 /// Special netlist exporter flavor that allows one to override simulation commands
class NETLIST_EXPORTER_PSPICE_SIM : public NETLIST_EXPORTER_PSPICE class NETLIST_EXPORTER_PSPICE_SIM : public NETLIST_EXPORTER_PSPICE
@ -82,6 +92,12 @@ public:
m_simCommand.Clear(); 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. * @brief Returns simulation type basing on the simulation command directives.
* Simulation directives set using SetSimCommand() have priority over the ones placed in * Simulation directives set using SetSimCommand() have priority over the ones placed in
@ -94,6 +110,15 @@ public:
*/ */
wxString GetSheetSimCommand(); 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. * @brief Determines if a directive is a simulation command.
*/ */

View File

@ -547,6 +547,49 @@ bool SIM_PLOT_FRAME::updatePlot( const TRACE_DESC& aDescriptor, SIM_PLOT_PANEL*
if( data_y.size() != size ) if( data_y.size() != size )
return false; 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<double> sub_x( data_x.begin() + offset,
data_x.begin() + offset + inner );
std::vector<double> 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, if( aPanel->AddTrace( aDescriptor.GetTitle(), size,
data_x.data(), data_y.data(), aDescriptor.GetType() ) ) data_x.data(), data_y.data(), aDescriptor.GetType() ) )
{ {

View File

@ -384,7 +384,7 @@ SIM_PLOT_PANEL::SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, wxWindowID id,
break; break;
case ST_DC: 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_y1 = new VOLTAGE_SCALE_Y( _( "Voltage (measured)" ), mpALIGN_LEFT );
m_axis_y2 = new CURRENT_SCALE( _( "Current" ), mpALIGN_RIGHT ); m_axis_y2 = new CURRENT_SCALE( _( "Current" ), mpALIGN_RIGHT );
break; break;