Eeschema: improve simulator behavior for two-source DC analysis
Fixes: lp:1830478 * https://bugs.launchpad.net/kicad/+bug/1830478
This commit is contained in:
parent
4adf89b40b
commit
356ccd0314
|
@ -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() )
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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() ) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue