Eeschema: adding .op SPICE simulation support

ADDED new tab on simulation settings dialog, which allows to run .op analysis.

Fixes https://gitlab.com/kicad/code/kicad/-/issues/2368
This commit is contained in:
Sylwester Kocjan 2020-04-15 01:51:58 +00:00 committed by Ian McInerney
parent 6a8ace55c4
commit fdccdd5cb9
24 changed files with 5923 additions and 7415 deletions

View File

@ -272,6 +272,7 @@ if( KICAD_SPICE )
sim/sim_plot_frame.cpp
sim/sim_plot_frame_base.cpp
sim/sim_plot_panel.cpp
sim/sim_panel_base.cpp
sim/spice_simulator.cpp
sim/spice_value.cpp
simulation_cursors.cpp

View File

@ -67,7 +67,6 @@ DIALOG_SIM_SETTINGS::DIALOG_SIM_SETTINGS( wxWindow* aParent )
// wxPanel::Hide() isn't enough on some platforms
m_simPages->RemovePage( m_simPages->FindPage( m_pgDistortion ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgNoise ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgOP ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgPoleZero ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgSensitivity ) );
m_simPages->RemovePage( m_simPages->FindPage( m_pgTransferFunction ) );

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Dec 30 2017)
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -317,8 +317,6 @@ DIALOG_SIM_SETTINGS_BASE::DIALOG_SIM_SETTINGS_BASE( wxWindow* parent, wxWindowID
bSizer15->Fit( m_pgNoise );
m_simPages->AddPage( m_pgNoise, _("Noise"), false );
m_pgOP = new wxPanel( m_simPages, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_pgOP->Hide();
wxBoxSizer* bSizer8;
bSizer8 = new wxBoxSizer( wxVERTICAL );

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,11 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Dec 30 2017)
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __DIALOG_SIM_SETTINGS_BASE_H__
#define __DIALOG_SIM_SETTINGS_BASE_H__
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
@ -134,4 +133,3 @@ class DIALOG_SIM_SETTINGS_BASE : public DIALOG_SHIM
};
#endif //__DIALOG_SIM_SETTINGS_BASE_H__

View File

@ -443,9 +443,7 @@ void NETLIST_EXPORTER_PSPICE::UpdateDirectives( unsigned aCtl )
|| couplingK.Matches( line ) // K## L## L## coupling constant
|| ( directiveStarted && line.StartsWith( '+' ) ) ) // multiline directives
{
// Pad the directive to ensure we distinguish between short directives
// and the start of a longer directive
m_directives.emplace_back( line + " " );
m_directives.push_back( line );
}

View File

@ -23,10 +23,11 @@
*/
#include "netlist_exporter_pspice_sim.h"
#include <wx/regex.h>
#include <wx/tokenzr.h>
wxString NETLIST_EXPORTER_PSPICE_SIM::GetSpiceVector( const wxString& aName, SIM_PLOT_TYPE aType,
const wxString& aParam ) const
wxString NETLIST_EXPORTER_PSPICE_SIM::ComponentToVector(
const wxString& aName, SIM_PLOT_TYPE aType, const wxString& aParam ) const
{
wxString res;
@ -68,6 +69,41 @@ wxString NETLIST_EXPORTER_PSPICE_SIM::GetSpiceVector( const wxString& aName, SIM
}
SIM_PLOT_TYPE NETLIST_EXPORTER_PSPICE_SIM::VectorToSignal(
const std::string& aVector, wxString& aSignal ) const
{
using namespace std;
// See ngspice manual chapt. 31.1 "Accessing internal device parameters"
wxRegEx internalDevParameter( "^@(\\w*[\\.\\w+]*)\\[(\\w*)\\]$", wxRE_ADVANCED );
wxString vector( aVector );
if( !internalDevParameter.Matches( vector ) )
{
// any text is a node name, which returns voltage
aSignal = "V(" + aVector + ")";
return SPT_VOLTAGE;
}
else
{
wxString paramType = internalDevParameter.GetMatch( vector, 2 );
if( paramType.Lower()[0] == 'i' )
{
// this is a branch current
paramType[0] = 'I';
aSignal = paramType + "(";
aSignal += internalDevParameter.GetMatch( vector, 1 ).Upper() + ")";
return SPT_CURRENT;
}
else
{
return SPT_UNKNOWN;
}
}
}
const std::vector<wxString>& NETLIST_EXPORTER_PSPICE_SIM::GetCurrents( SPICE_PRIMITIVE aPrimitive )
{
static const std::vector<wxString> passive = { "I" };
@ -129,16 +165,23 @@ SIM_TYPE NETLIST_EXPORTER_PSPICE_SIM::GetSimType()
SIM_TYPE NETLIST_EXPORTER_PSPICE_SIM::CommandToSimType( const wxString& aCmd )
{
const std::map<wxString, SIM_TYPE> simCmds = {
{ ".ac ", ST_AC }, { ".dc ", ST_DC }, { ".disto ", ST_DISTORTION }, { ".noise ", ST_NOISE },
{ ".op ", ST_OP }, { ".pz ", ST_POLE_ZERO }, { ".sens ", ST_SENSITIVITY }, { ".tf ", ST_TRANS_FUNC },
{ ".tran ", ST_TRANSIENT }
};
wxString lcaseCmd = aCmd.Lower();
const std::vector<std::pair<wxString, SIM_TYPE>> simCmds = {
{ "^.ac\\M.*", ST_AC },
{ "^.dc\\M.*", ST_DC },
{ "^.tran\\M.*", ST_TRANSIENT },
{ "^.op\\M.*", ST_OP },
{ "^.disto\\M.*", ST_DISTORTION },
{ "^.noise\\M.*", ST_NOISE },
{ "^.pz\\M.*", ST_POLE_ZERO },
{ "^.sens\\M.*", ST_SENSITIVITY },
{ "^.tf\\M.*", ST_TRANS_FUNC } };
wxRegEx simCmd;
for( const auto& c : simCmds )
{
if( lcaseCmd.StartsWith( c.first ) )
simCmd.Compile( c.first, wxRE_ADVANCED | wxRE_NOSUB | wxRE_ICASE );
if( simCmd.Matches( aCmd ) )
return c.second;
}
@ -193,7 +236,8 @@ void NETLIST_EXPORTER_PSPICE_SIM::writeDirectives( OUTPUTFORMATTER* aFormatter,
/// @todo is it required to switch to lowercase
aFormatter->Print( 0, ".save %s\n",
(const char*) GetSpiceVector( item.m_refName, SPT_CURRENT, current ).c_str() );
(const char*) ComponentToVector( item.m_refName, SPT_CURRENT, current )
.c_str() );
}
}
@ -202,7 +246,7 @@ void NETLIST_EXPORTER_PSPICE_SIM::writeDirectives( OUTPUTFORMATTER* aFormatter,
{
// the "0" and the "GND" nets are automaticallly saved internally by ngspice.
// Skip them
wxString netname = GetSpiceVector( netMap.first, SPT_VOLTAGE );
wxString netname = ComponentToVector( netMap.first, SPT_VOLTAGE );
if( netname == "V(0)" || netname == "V(GND)" )
continue;

View File

@ -60,9 +60,18 @@ public:
* @return Empty string if query is invalid, otherwise a plot name that
* can be requested from the simulator.
*/
wxString GetSpiceVector( const wxString& aName, SIM_PLOT_TYPE aType,
wxString ComponentToVector( const wxString& aName, SIM_PLOT_TYPE aType,
const wxString& aParam = wxEmptyString ) const;
/**
* @brief Returns name of Spice dataset for a specific plot.
* @param aVector is name of the vector produced by ngspice
* @param [out] aSignal is output in form: V(R1), Ib(Q2), I(L8)
* @return [SPT_VOLTAGE, SPT_CURRENT]. Otherwise SPT_UNKNOWN if vector is
* of different, unsupported type.
*/
SIM_PLOT_TYPE VectorToSignal( const std::string& aVector, wxString& aSignal ) const;
/**
* @brief Returns a list of currents that can be probed in a Spice primitive.
*/

View File

@ -41,15 +41,16 @@ using namespace std;
static const wxChar* const traceNgspice = wxT( "KICAD_NGSPICE" );
NGSPICE::NGSPICE() :
m_ngSpice_Init( nullptr ),
m_ngSpice_Circ( nullptr ),
m_ngSpice_Command( nullptr ),
m_ngGet_Vec_Info( nullptr ),
m_ngSpice_AllPlots( nullptr ),
m_ngSpice_AllVecs( nullptr ),
m_ngSpice_Running( nullptr ),
m_error( false )
NGSPICE::NGSPICE()
: m_ngSpice_Init( nullptr ),
m_ngSpice_Circ( nullptr ),
m_ngSpice_Command( nullptr ),
m_ngGet_Vec_Info( nullptr ),
m_ngSpice_CurPlot( nullptr ),
m_ngSpice_AllPlots( nullptr ),
m_ngSpice_AllVecs( nullptr ),
m_ngSpice_Running( nullptr ),
m_error( false )
{
init_dll();
}
@ -66,6 +67,28 @@ void NGSPICE::Init()
}
vector<string> NGSPICE::AllPlots()
{
LOCALE_IO c_locale; // ngspice works correctly only with C locale
char* currentPlot = m_ngSpice_CurPlot();
char** allPlots = m_ngSpice_AllVecs( currentPlot );
int noOfPlots = 0;
if( allPlots != nullptr )
for( char** plot = allPlots; *plot != nullptr; plot++ )
noOfPlots++;
vector<string> retVal( noOfPlots );
for( int i = 0; i < noOfPlots; i++, allPlots++ )
{
string vec = *allPlots;
retVal.at( i ) = vec;
}
return retVal;
}
vector<COMPLEX> NGSPICE::GetPlot( const string& aName, int aMaxLen )
{
LOCALE_IO c_locale; // ngspice works correctly only with C locale
@ -361,6 +384,7 @@ void NGSPICE::init_dll()
m_ngSpice_Circ = (ngSpice_Circ) m_dll.GetSymbol( "ngSpice_Circ" );
m_ngSpice_Command = (ngSpice_Command) m_dll.GetSymbol( "ngSpice_Command" );
m_ngGet_Vec_Info = (ngGet_Vec_Info) m_dll.GetSymbol( "ngGet_Vec_Info" );
m_ngSpice_CurPlot = (ngSpice_CurPlot) m_dll.GetSymbol( "ngSpice_CurPlot" );
m_ngSpice_AllPlots = (ngSpice_AllPlots) m_dll.GetSymbol( "ngSpice_AllPlots" );
m_ngSpice_AllVecs = (ngSpice_AllVecs) m_dll.GetSymbol( "ngSpice_AllVecs" );
m_ngSpice_Running = (ngSpice_Running) m_dll.GetSymbol( "ngSpice_running" ); // it is not a typo

View File

@ -59,6 +59,9 @@ public:
///> @copydoc SPICE_SIMULATOR::GetXAxis()
std::string GetXAxis( SIM_TYPE aType ) const override;
///> @copydoc SPICE_SIMULATOR::AllPlots()
std::vector<std::string> AllPlots() override;
///> @copydoc SPICE_SIMULATOR::GetPlot()
std::vector<COMPLEX> GetPlot( const std::string& aName, int aMaxLen = -1 ) override;
@ -89,6 +92,7 @@ private:
typedef int (*ngSpice_Circ)( char** circarray );
typedef int (*ngSpice_Command)( char* command );
typedef pvector_info (*ngGet_Vec_Info)( char* vecname );
typedef char* ( *ngSpice_CurPlot )( void );
typedef char** (*ngSpice_AllPlots)( void );
typedef char** (*ngSpice_AllVecs)( char* plotname );
typedef bool (*ngSpice_Running)( void );
@ -98,6 +102,7 @@ private:
ngSpice_Circ m_ngSpice_Circ;
ngSpice_Command m_ngSpice_Command;
ngGet_Vec_Info m_ngGet_Vec_Info;
ngSpice_CurPlot m_ngSpice_CurPlot;
ngSpice_AllPlots m_ngSpice_AllPlots;
ngSpice_AllVecs m_ngSpice_AllVecs;
ngSpice_Running m_ngSpice_Running;

View File

@ -0,0 +1,97 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* @author Sylwester Kocjan <s.kocjan@o2.pl>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "sim_panel_base.h"
#include "sim_plot_frame.h"
#include <wx/sizer.h>
SIM_PANEL_BASE::SIM_PANEL_BASE() : m_type( ST_UNKNOWN )
{
}
SIM_PANEL_BASE::SIM_PANEL_BASE( SIM_TYPE aType ) : m_type( aType )
{
}
SIM_PANEL_BASE::SIM_PANEL_BASE( SIM_TYPE aType, wxWindow* parent, wxWindowID id,
const wxPoint& pos, const wxSize& size, long style, const wxString& name )
: wxWindow( parent, id, pos, size, style, name ), m_type( aType )
{
}
SIM_PANEL_BASE::~SIM_PANEL_BASE()
{
}
bool SIM_PANEL_BASE::IsPlottable( SIM_TYPE aSimType )
{
switch( aSimType )
{
case ST_AC:
case ST_DC:
case ST_TRANSIENT:
return true;
default:
return false;
}
}
SIM_NOPLOT_PANEL::SIM_NOPLOT_PANEL( SIM_TYPE aType, wxWindow* parent, wxWindowID id,
const wxPoint& pos, const wxSize& size, long style, const wxString& name )
: SIM_PANEL_BASE( aType, parent, id, pos, size, style, name )
{
m_sizer = new wxBoxSizer( wxVERTICAL );
m_sizer->Add( 0, 1, 1, wxEXPAND, 5 );
m_textInfo = new wxStaticText( dynamic_cast<wxWindow*>( this ), wxID_ANY, "", wxDefaultPosition,
wxDefaultSize, wxALL | wxEXPAND | wxALIGN_CENTER_HORIZONTAL );
m_textInfo->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT,
wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
m_textInfo->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
//ST_UNKNOWN serves purpose of a welcome panel
m_textInfo->SetLabel(
( aType == ST_UNKNOWN ) ?
_( "Start the simulation by clicking the Run Simulation button" ) :
_( "This simulation provide no plots. Please refer to console window for results" ) );
m_sizer->Add( m_textInfo, 1, wxALL | wxEXPAND, 5 );
m_sizer->Add( 0, 1, 1, wxEXPAND, 5 );
dynamic_cast<wxWindow*>( this )->SetSizer( m_sizer );
}
SIM_NOPLOT_PANEL::~SIM_NOPLOT_PANEL()
{
}

View File

@ -0,0 +1,72 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 CERN
* Copyright (C) 2016-2017 KiCad Developers, see AUTHORS.txt for contributors.
* @author Sylwester Kocjan <s.kocjan@o2.pl>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* https://www.gnu.org/licenses/gpl-3.0.html
* or you may search the http://www.gnu.org website for the version 3 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __SIM_PLOT_PANEL_BASE_H
#define __SIM_PLOT_PANEL_BASE_H
#include "sim_types.h"
#include <wx/panel.h>
#include <wx/sizer.h>
#include <wx/stattext.h>
class SIM_PANEL_BASE : public wxWindow
{
public:
SIM_PANEL_BASE();
SIM_PANEL_BASE( SIM_TYPE );
SIM_PANEL_BASE( SIM_TYPE aType, wxWindow* parent, wxWindowID id,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = 0, const wxString& name = wxPanelNameStr );
virtual ~SIM_PANEL_BASE();
static bool IsPlottable( SIM_TYPE aSimType );
SIM_TYPE GetType() const
{
return m_type;
}
private:
const SIM_TYPE m_type;
};
class SIM_NOPLOT_PANEL : public SIM_PANEL_BASE
{
public:
SIM_NOPLOT_PANEL( SIM_TYPE aType, wxWindow* parent, wxWindowID id,
const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
long style = 0, const wxString& name = wxPanelNameStr );
virtual ~SIM_NOPLOT_PANEL();
private:
wxSizer* m_sizer;
wxStaticText* m_textInfo;
};
#endif

View File

@ -118,7 +118,10 @@ TRACE_DESC::TRACE_DESC( const NETLIST_EXPORTER_PSPICE_SIM& aExporter, const wxSt
wxString SIM_PLOT_FRAME::m_savedWorkbooksPath;
SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
: SIM_PLOT_FRAME_BASE( aParent ), m_lastSimPlot( nullptr )
: SIM_PLOT_FRAME_BASE( aParent ),
m_lastSimPlot( nullptr ),
m_welcomePanel( nullptr ),
m_plotNumber( 0 )
{
SetKiway( this, aKiway );
m_signalsIconColorList = NULL;
@ -204,7 +207,9 @@ SIM_PLOT_FRAME::SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent )
Bind( wxEVT_COMMAND_MENU_SELECTED, &SIM_PLOT_FRAME::onSettings, this, m_settings->GetId() );
m_toolBar->Realize();
m_plotNotebook->SetPageText( 0, _( "Welcome!" ) );
m_welcomePanel = new SIM_PANEL_BASE( ST_UNKNOWN, m_plotNotebook, wxID_ANY );
m_plotNotebook->AddPage( m_welcomePanel, _( "Welcome!" ), 1, true );
// the settings dialog will be created later, on demand.
// if created in the ctor, for some obscure reason, there is an issue
@ -419,10 +424,9 @@ void SIM_PLOT_FRAME::fillDefaultColorList( bool aWhiteBg )
}
void SIM_PLOT_FRAME::StartSimulation()
void SIM_PLOT_FRAME::StartSimulation( const wxString& aSimCommand )
{
STRING_FORMATTER formatter;
SIM_PLOT_PANEL* plotPanel = CurrentPlot();
if( !m_settingsDlg )
m_settingsDlg = new DIALOG_SIM_SETTINGS( this );
@ -430,8 +434,16 @@ void SIM_PLOT_FRAME::StartSimulation()
m_simConsole->Clear();
updateNetlistExporter();
if( plotPanel )
m_exporter->SetSimCommand( m_plots[plotPanel].m_simCommand );
if( aSimCommand.IsEmpty() )
{
SIM_PANEL_BASE* plotPanel = currentPlotWindow();
if( plotPanel )
m_exporter->SetSimCommand( m_plots[plotPanel].m_simCommand );
}
else
{
m_exporter->SetSimCommand( aSimCommand );
}
if( !m_exporter->Format( &formatter, m_settingsDlg->GetNetlistOptions() ) )
{
@ -464,12 +476,26 @@ bool SIM_PLOT_FRAME::IsSimulationRunning()
}
SIM_PLOT_PANEL* SIM_PLOT_FRAME::NewPlotPanel( SIM_TYPE aSimType )
SIM_PANEL_BASE* SIM_PLOT_FRAME::NewPlotPanel( SIM_TYPE aSimType )
{
SIM_PLOT_PANEL* plotPanel = new SIM_PLOT_PANEL( aSimType, m_plotNotebook, this, wxID_ANY );
SIM_PANEL_BASE* plotPanel;
plotPanel->EnableMouseWheelPan(
m_schematicFrame->GetCanvas()->GetViewControls()->IsMousewheelPanEnabled() );
if( SIM_PANEL_BASE::IsPlottable( aSimType ) )
{
SIM_PLOT_PANEL* panel;
panel = new SIM_PLOT_PANEL( aSimType, m_plotNotebook, this, wxID_ANY );
panel->GetPlotWin()->EnableMouseWheelPan(
m_schematicFrame->GetCanvas()->GetViewControls()->IsMousewheelPanEnabled() );
plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
}
else
{
SIM_NOPLOT_PANEL* panel;
panel = new SIM_NOPLOT_PANEL( aSimType, m_plotNotebook, wxID_ANY );
plotPanel = dynamic_cast<SIM_PANEL_BASE*>( panel );
}
if( m_welcomePanel )
{
@ -477,9 +503,10 @@ SIM_PLOT_PANEL* SIM_PLOT_FRAME::NewPlotPanel( SIM_TYPE aSimType )
m_welcomePanel = nullptr;
}
m_plotNotebook->AddPage( plotPanel, wxString::Format( _( "Plot%u" ),
(unsigned int) m_plotNotebook->GetPageCount() + 1 ), true );
wxString pageTitle( m_simulator->TypeToName( aSimType, true ) );
pageTitle.Prepend( wxString::Format( _( "Plot%u - " ), (unsigned int) ++m_plotNumber ) );
m_plotNotebook->AddPage( dynamic_cast<wxWindow*>( plotPanel ), pageTitle, true );
m_plots[plotPanel] = PLOT_INFO();
return plotPanel;
@ -500,9 +527,9 @@ void SIM_PLOT_FRAME::AddCurrentPlot( const wxString& aDeviceName, const wxString
void SIM_PLOT_FRAME::AddTuner( SCH_COMPONENT* aComponent )
{
SIM_PLOT_PANEL* plotPanel = CurrentPlot();
SIM_PANEL_BASE* plotPanel = currentPlotWindow();
if( !plotPanel )
if( !plotPanel || plotPanel == m_welcomePanel )
return;
// For now limit the tuner tool to RLC components
@ -550,9 +577,11 @@ void SIM_PLOT_FRAME::RemoveTuner( TUNER_SLIDER* aTuner, bool aErase )
SIM_PLOT_PANEL* SIM_PLOT_FRAME::CurrentPlot() const
{
wxWindow* curPage = m_plotNotebook->GetCurrentPage();
SIM_PANEL_BASE* curPage = currentPlotWindow();
return ( curPage == m_welcomePanel ) ? nullptr : static_cast<SIM_PLOT_PANEL*>( curPage );
return ( ( !curPage || curPage->GetType() == ST_UNKNOWN ) ?
nullptr :
dynamic_cast<SIM_PLOT_PANEL*>( curPage ) );
}
@ -572,7 +601,7 @@ void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const
m_simConsole->SetInsertionPointEnd();
return;
}
else if( !SIM_PLOT_PANEL::IsPlottable( simType ) )
else if( !SIM_PANEL_BASE::IsPlottable( simType ) )
{
m_simConsole->AppendText( _( "Error: simulation type doesn't support plotting!\n" ) );
m_simConsole->SetInsertionPointEnd();
@ -583,7 +612,7 @@ void SIM_PLOT_FRAME::addPlot( const wxString& aName, SIM_PLOT_TYPE aType, const
SIM_PLOT_PANEL* plotPanel = CurrentPlot();
if( !plotPanel || plotPanel->GetType() != simType )
plotPanel = NewPlotPanel( simType );
plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( NewPlotPanel( simType ) );
TRACE_DESC descriptor( *m_exporter, aName, aType, aParam );
@ -630,10 +659,11 @@ void SIM_PLOT_FRAME::removePlot( const wxString& aPlotName, bool aErase )
wxASSERT( plotPanel->TraceShown( aPlotName ) );
plotPanel->DeleteTrace( aPlotName );
plotPanel->Fit();
plotPanel->GetPlotWin()->Fit();
updateSignalList();
updateCursors();
wxCommandEvent dummy;
onCursorUpdate( dummy );
}
@ -646,10 +676,10 @@ void SIM_PLOT_FRAME::updateNetlistExporter()
bool SIM_PLOT_FRAME::updatePlot( const TRACE_DESC& aDescriptor, SIM_PLOT_PANEL* aPanel )
{
SIM_TYPE simType = m_exporter->GetSimType();
wxString spiceVector = m_exporter->GetSpiceVector( aDescriptor.GetName(),
aDescriptor.GetType(), aDescriptor.GetParam() );
wxString spiceVector = m_exporter->ComponentToVector(
aDescriptor.GetName(), aDescriptor.GetType(), aDescriptor.GetParam() );
if( !SIM_PLOT_PANEL::IsPlottable( simType ) )
if( !SIM_PANEL_BASE::IsPlottable( simType ) )
{
// There is no plot to be shown
m_simulator->Command( wxString::Format( "print %s", spiceVector ).ToStdString() );
@ -760,13 +790,13 @@ bool SIM_PLOT_FRAME::updatePlot( const TRACE_DESC& aDescriptor, SIM_PLOT_PANEL*
void SIM_PLOT_FRAME::updateSignalList()
{
m_signals->ClearAll();
SIM_PLOT_PANEL* plotPanel = CurrentPlot();
if( !plotPanel )
return;
m_signals->ClearAll();
wxSize size = m_signals->GetClientSize();
m_signals->AppendColumn( _( "Signal" ), wxLIST_FORMAT_LEFT, size.x );
@ -824,12 +854,6 @@ void SIM_PLOT_FRAME::updateSignalList()
}
void SIM_PLOT_FRAME::updateCursors()
{
wxQueueEvent( this, new wxCommandEvent( EVT_SIM_CURSOR_UPDATE ) );
}
void SIM_PLOT_FRAME::updateTuners()
{
const auto& spiceItems = m_exporter->GetSpiceItems();
@ -891,9 +915,9 @@ bool SIM_PLOT_FRAME::loadWorkbook( const wxString& aPath )
if( !file.GetNextLine().ToLong( &plotType ) )
return false;
SIM_PLOT_PANEL* plotPanel = NewPlotPanel( (SIM_TYPE) plotType );
SIM_PANEL_BASE* plotPanel = NewPlotPanel( (SIM_TYPE) plotType );
m_plots[plotPanel].m_simCommand = file.GetNextLine();
StartSimulation();
StartSimulation( m_plots[plotPanel].m_simCommand );
// Perform simulation, so plots can be added with values
do
@ -952,19 +976,22 @@ bool SIM_PLOT_FRAME::saveWorkbook( const wxString& aPath )
file.Create();
}
file.AddLine( wxString::Format( "%lu", m_plots.size() ) );
file.AddLine( wxString::Format( "%llu", m_plots.size() ) );
for( const auto& plot : m_plots )
{
file.AddLine( wxString::Format( "%d", plot.first->GetType() ) );
file.AddLine( plot.second.m_simCommand );
file.AddLine( wxString::Format( "%lu", plot.second.m_traces.size() ) );
for( const auto& trace : plot.second.m_traces )
if( plot.first )
{
file.AddLine( wxString::Format( "%d", trace.second.GetType() ) );
file.AddLine( trace.second.GetName() );
file.AddLine( trace.second.GetParam() );
file.AddLine( wxString::Format( "%d", plot.first->GetType() ) );
file.AddLine( plot.second.m_simCommand );
file.AddLine( wxString::Format( "%llu", plot.second.m_traces.size() ) );
for( const auto& trace : plot.second.m_traces )
{
file.AddLine( wxString::Format( "%d", trace.second.GetType() ) );
file.AddLine( trace.second.GetName() );
file.AddLine( trace.second.GetParam() );
}
}
}
@ -1000,10 +1027,10 @@ void SIM_PLOT_FRAME::menuNewPlot( wxCommandEvent& aEvent )
{
SIM_TYPE type = m_exporter->GetSimType();
if( SIM_PLOT_PANEL::IsPlottable( type ) )
if( SIM_PANEL_BASE::IsPlottable( type ) )
{
SIM_PLOT_PANEL* prevPlot = CurrentPlot();
SIM_PLOT_PANEL* newPlot = NewPlotPanel( type );
SIM_PLOT_PANEL* newPlot = dynamic_cast<SIM_PLOT_PANEL*>( NewPlotPanel( type ) );
// If the previous plot had the same type, copy the simulation command
if( prevPlot )
@ -1056,7 +1083,7 @@ void SIM_PLOT_FRAME::menuSaveImage( wxCommandEvent& event )
if( saveDlg.ShowModal() == wxID_CANCEL )
return;
CurrentPlot()->SaveScreenshot( saveDlg.GetPath(), wxBITMAP_TYPE_PNG );
CurrentPlot()->GetPlotWin()->SaveScreenshot( saveDlg.GetPath(), wxBITMAP_TYPE_PNG );
}
@ -1106,21 +1133,21 @@ void SIM_PLOT_FRAME::menuSaveCsv( wxCommandEvent& event )
void SIM_PLOT_FRAME::menuZoomIn( wxCommandEvent& event )
{
if( CurrentPlot() )
CurrentPlot()->ZoomIn();
CurrentPlot()->GetPlotWin()->ZoomIn();
}
void SIM_PLOT_FRAME::menuZoomOut( wxCommandEvent& event )
{
if( CurrentPlot() )
CurrentPlot()->ZoomOut();
CurrentPlot()->GetPlotWin()->ZoomOut();
}
void SIM_PLOT_FRAME::menuZoomFit( wxCommandEvent& event )
{
if( CurrentPlot() )
CurrentPlot()->Fit();
CurrentPlot()->GetPlotWin()->Fit();
}
@ -1201,21 +1228,21 @@ void SIM_PLOT_FRAME::onPlotClose( wxAuiNotebookEvent& event )
if( idx == wxNOT_FOUND )
return;
SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( m_plotNotebook->GetPage( idx ) );
if( !plotPanel )
return;
SIM_PANEL_BASE* plotPanel =
dynamic_cast<SIM_PANEL_BASE*>( m_plotNotebook->GetPage( idx ) );
m_plots.erase( plotPanel );
updateSignalList();
updateCursors();
wxCommandEvent dummy;
onCursorUpdate( dummy );
}
void SIM_PLOT_FRAME::onPlotChanged( wxAuiNotebookEvent& event )
{
updateSignalList();
updateCursors();
wxCommandEvent dummy;
onCursorUpdate( dummy );
}
@ -1258,7 +1285,7 @@ void SIM_PLOT_FRAME::onSimulate( wxCommandEvent& event )
void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
{
SIM_PLOT_PANEL* plotPanel = CurrentPlot();
SIM_PANEL_BASE* plotPanelWindow = currentPlotWindow();
// Initial processing is required to e.g. display a list of power sources
updateNetlistExporter();
@ -1272,8 +1299,8 @@ void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
if( !m_settingsDlg )
m_settingsDlg = new DIALOG_SIM_SETTINGS( this );
if( plotPanel )
m_settingsDlg->SetSimCommand( m_plots[plotPanel].m_simCommand );
if( plotPanelWindow != m_welcomePanel )
m_settingsDlg->SetSimCommand( m_plots[plotPanelWindow].m_simCommand );
m_settingsDlg->SetNetlistExporter( m_exporter.get() );
@ -1283,12 +1310,12 @@ void SIM_PLOT_FRAME::onSettings( wxCommandEvent& event )
SIM_TYPE newSimType = NETLIST_EXPORTER_PSPICE_SIM::CommandToSimType( newCommand );
// If it is a new simulation type, open a new plot
if( !plotPanel || ( plotPanel && plotPanel->GetType() != newSimType ) )
if( !plotPanelWindow || ( plotPanelWindow && plotPanelWindow->GetType() != newSimType ) )
{
plotPanel = NewPlotPanel( newSimType );
plotPanelWindow = NewPlotPanel( newSimType );
}
m_plots[plotPanel].m_simCommand = newCommand;
m_plots[plotPanelWindow].m_simCommand = newCommand;
}
}
@ -1299,7 +1326,7 @@ void SIM_PLOT_FRAME::onAddSignal( wxCommandEvent& event )
if( !plotPanel || !m_exporter || plotPanel->GetType() != m_exporter->GetSimType() )
{
DisplayInfoMessage( this, _( "You need to run simulation first." ) );
DisplayInfoMessage( this, _( "You need to run plot-providing simulation first." ) );
return;
}
@ -1455,18 +1482,19 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
if( simType == ST_UNKNOWN )
return;
SIM_PLOT_PANEL* plotPanel = CurrentPlot();
SIM_PANEL_BASE* plotPanelWindow = currentPlotWindow();
if( !plotPanel || plotPanel->GetType() != simType )
plotPanel = NewPlotPanel( simType );
if( !plotPanelWindow || plotPanelWindow->GetType() != simType )
plotPanelWindow = NewPlotPanel( simType );
if( IsSimulationRunning() )
return;
// If there are any signals plotted, update them
if( SIM_PLOT_PANEL::IsPlottable( simType ) )
if( SIM_PANEL_BASE::IsPlottable( simType ) )
{
TRACE_MAP& traceMap = m_plots[plotPanel].m_traces;
TRACE_MAP& traceMap = m_plots[plotPanelWindow].m_traces;
SIM_PLOT_PANEL* plotPanel = dynamic_cast<SIM_PLOT_PANEL*>( plotPanelWindow );
for( auto it = traceMap.begin(); it != traceMap.end(); /* iteration occurs in the loop */)
{
@ -1482,18 +1510,33 @@ void SIM_PLOT_FRAME::onSimFinished( wxCommandEvent& aEvent )
}
updateSignalList();
plotPanel->UpdateAll();
plotPanel->GetPlotWin()->UpdateAll();
plotPanel->ResetScales();
}
else
else if( simType == ST_OP )
{
/// @todo do not make it hardcoded for ngspice
for( const auto& net : m_exporter->GetNetIndexMap() )
{
int node = net.second;
m_simConsole->AppendText( _( "\n\nSimulation results:\n\n" ) );
m_simConsole->SetInsertionPointEnd();
if( node > 0 )
m_simulator->Command( wxString::Format( "print v(%d)", node ).ToStdString() );
for( const auto& vec : m_simulator->AllPlots() )
{
double val = m_simulator->GetRealPlot( vec, 1 ).at( 0 );
wxString outLine, signal;
SIM_PLOT_TYPE type = m_exporter->VectorToSignal( vec, signal );
const size_t tab = 25; //characters
size_t padding = ( signal.length() < tab ) ? ( tab - signal.length() ) : 1;
outLine.Printf( wxT( "%s%s" ), ( signal + wxT( ":" ) ).Pad( padding, wxUniChar( ' ' ) ),
SPICE_VALUE( val ).ToSpiceString() );
outLine.Append( type == SPT_CURRENT ? "A\n" : "V\n" );
m_simConsole->AppendText( outLine );
m_simConsole->SetInsertionPointEnd();
// @todo display calculated values on the schematic
}
}
}

View File

@ -51,7 +51,10 @@ class SCH_COMPONENT;
class SPICE_SIMULATOR;
class NETLIST_EXPORTER_PSPICE_SIM;
class SIM_PLOT_PANEL;
#include "sim_plot_panel.h"
#include "sim_panel_base.h"
class SIM_THREAD_REPORTER;
class TUNER_SLIDER;
@ -117,6 +120,7 @@ private:
wxString m_title;
};
/** Implementing SIM_PLOT_FRAME_BASE */
class SIM_PLOT_FRAME : public SIM_PLOT_FRAME_BASE
{
@ -125,7 +129,7 @@ public:
SIM_PLOT_FRAME( KIWAY* aKiway, wxWindow* aParent );
~SIM_PLOT_FRAME();
void StartSimulation();
void StartSimulation( const wxString& aSimCommand = wxEmptyString );
void StopSimulation();
bool IsSimulationRunning();
@ -135,7 +139,7 @@ public:
* @param aSimType is requested simulation type.
* @return The new plot panel.
*/
SIM_PLOT_PANEL* NewPlotPanel( SIM_TYPE aSimType );
SIM_PANEL_BASE* NewPlotPanel( SIM_TYPE aSimType );
/**
* @brief Adds a voltage plot for a given net name.
@ -211,6 +215,14 @@ private:
*/
void fillDefaultColorList( bool aWhiteBg );
/**
* @brief Returns the currently opened plot panel (or NULL if there is none).
*/
SIM_PANEL_BASE* currentPlotWindow() const
{
return dynamic_cast<SIM_PANEL_BASE*>( m_plotNotebook->GetCurrentPage() );
}
/**
* @brief Adds a new plot to the current panel.
* @param aName is the device/net name.
@ -245,11 +257,6 @@ private:
*/
void updateSignalList();
/**
* @brief Updates the cursor values list.
*/
void updateCursors();
/**
* @brief Filters out tuners for components that do not exist anymore.
* Decisions are based on the current NETLIST_EXPORTER data.
@ -359,7 +366,7 @@ private:
};
///> Map of plot panels and associated data
std::map<SIM_PLOT_PANEL*, PLOT_INFO> m_plots;
std::map<SIM_PANEL_BASE*, PLOT_INFO> m_plots;
///> List of currently displayed tuners
std::list<TUNER_SLIDER*> m_tuners;
@ -400,12 +407,16 @@ private:
///> A string to store the path of saved workbooks during a session
static wxString m_savedWorkbooksPath;
///> Info panel
SIM_PANEL_BASE* m_welcomePanel;
// Variables for temporary storage:
int m_splitterLeftRightSashPosition;
int m_splitterPlotAndConsoleSashPosition;
int m_splitterSignalsSashPosition;
int m_splitterTuneValuesSashPosition;
bool m_plotUseWhiteBg;
unsigned int m_plotNumber;
///> The color list to draw traces, bg, fg, axis...
std::vector<wxColour> m_colorList;

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jul 10 2019)
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -141,39 +141,6 @@ SIM_PLOT_FRAME_BASE::SIM_PLOT_FRAME_BASE( wxWindow* parent, wxWindowID id, const
m_plotNotebook = new wxAuiNotebook( m_plotPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_NB_CLOSE_ON_ALL_TABS|wxAUI_NB_MIDDLE_CLICK_CLOSE|wxAUI_NB_TAB_MOVE|wxAUI_NB_TAB_SPLIT|wxAUI_NB_TOP );
m_plotNotebook->SetMinSize( wxSize( 200,-1 ) );
m_welcomePanel = new wxPanel( m_plotNotebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
m_sizer8 = new wxBoxSizer( wxVERTICAL );
m_sizer8->Add( 0, 0, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer81;
bSizer81 = new wxBoxSizer( wxHORIZONTAL );
bSizer81->Add( 0, 0, 1, wxEXPAND, 5 );
m_staticTextInfo = new wxStaticText( m_welcomePanel, wxID_ANY, _("Start the simulation by clicking the Run Simulation button"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticTextInfo->Wrap( -1 );
m_staticTextInfo->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD, false, wxEmptyString ) );
m_staticTextInfo->SetForegroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
bSizer81->Add( m_staticTextInfo, 0, wxALL|wxEXPAND, 5 );
bSizer81->Add( 0, 0, 1, wxEXPAND, 5 );
m_sizer8->Add( bSizer81, 0, wxEXPAND, 5 );
m_sizer8->Add( 0, 0, 1, wxEXPAND, 5 );
m_welcomePanel->SetSizer( m_sizer8 );
m_welcomePanel->Layout();
m_sizer8->Fit( m_welcomePanel );
m_plotNotebook->AddPage( m_welcomePanel, _("a page"), false, wxNullBitmap );
m_sizerPlot->Add( m_plotNotebook, 1, wxEXPAND, 5 );

View File

@ -14,7 +14,6 @@
<property name="file">sim_plot_frame_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="image_path_wrapper_function_name"></property>
<property name="indent_with_spaces"></property>
<property name="internationalize">1</property>
<property name="name">SpiceWindow</property>
@ -26,7 +25,6 @@
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_array_enum">0</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Frame" expanded="1">
@ -753,181 +751,6 @@
<property name="window_style"></property>
<event name="OnAuiNotebookPageChanged">onPlotChanged</event>
<event name="OnAuiNotebookPageClose">onPlotClose</event>
<object class="auinotebookpage" expanded="0">
<property name="bitmap"></property>
<property name="label">a page</property>
<property name="select">0</property>
<object class="wxPanel" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_welcomePanel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style">wxTAB_TRAVERSAL</property>
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">m_sizer8</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">protected</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bSizer81</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg">wxSYS_COLOUR_GRAYTEXT</property>
<property name="floatable">1</property>
<property name="font">,90,92,-1,70,0</property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Start the simulation by clicking the Run Simulation button</property>
<property name="markup">0</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_staticTextInfo</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="spacer" expanded="0">
<property name="height">0</property>
<property name="permission">protected</property>
<property name="width">0</property>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</object>

View File

@ -1,5 +1,5 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Jul 10 2019)
// C++ code generated with wxFormBuilder (version Oct 26 2018)
// http://www.wxformbuilder.org/
//
// PLEASE DO *NOT* EDIT THIS FILE!
@ -7,30 +7,28 @@
#pragma once
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
#include <wx/intl.h>
class wxListView;
#include "kiway_player.h"
#include <wx/string.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/menu.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/toolbar.h>
#include <wx/stattext.h>
#include <wx/sizer.h>
#include <wx/panel.h>
#include <wx/artprov.h>
#include <wx/aui/auibook.h>
#include <wx/textctrl.h>
#include <wx/splitter.h>
#include <wx/listctrl.h>
#include <wx/bitmap.h>
#include <wx/colour.h>
#include <wx/font.h>
#include <wx/frame.h>
#include <wx/gdicmn.h>
#include <wx/icon.h>
#include <wx/image.h>
#include <wx/intl.h>
#include <wx/listctrl.h>
#include <wx/menu.h>
#include <wx/panel.h>
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/splitter.h>
#include <wx/stattext.h>
#include <wx/string.h>
#include <wx/textctrl.h>
#include <wx/toolbar.h>
#include <wx/xrc/xmlres.h>
///////////////////////////////////////////////////////////////////////////
@ -74,9 +72,6 @@ class SIM_PLOT_FRAME_BASE : public KIWAY_PLAYER
wxPanel* m_plotPanel;
wxBoxSizer* m_sizerPlot;
wxAuiNotebook* m_plotNotebook;
wxPanel* m_welcomePanel;
wxBoxSizer* m_sizer8;
wxStaticText* m_staticTextInfo;
wxPanel* m_panelConsole;
wxBoxSizer* m_sizerConsole;
wxTextCtrl* m_simConsole;

View File

@ -364,25 +364,25 @@ void CURSOR::UpdateReference()
SIM_PLOT_PANEL::SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, SIM_PLOT_FRAME* aMainFrame,
wxWindowID id, const wxPoint& pos,
const wxSize& size, long style, const wxString& name )
: mpWindow( parent, id, pos, size, style ),
wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name )
: SIM_PANEL_BASE( aType, parent, id, pos, size, style, name ),
m_colorIdx( 0 ),
m_axis_x( nullptr ),
m_axis_y1( nullptr ),
m_axis_y2( nullptr ),
m_dotted_cp( false ),
m_type( aType ),
m_masterFrame( aMainFrame )
{
LimitView( true );
SetMargins( 50, 80, 50, 80 );
m_sizer = new wxBoxSizer( wxVERTICAL );
m_plotWin = new mpWindow( this, wxID_ANY, pos, size, style );
SetColourTheme( GetPlotColor( SIM_BG_COLOR ),
GetPlotColor( SIM_FG_COLOR ),
GetPlotColor( SIM_AXIS_COLOR ) );
m_plotWin->LimitView( true );
m_plotWin->SetMargins( 50, 80, 50, 80 );
switch( m_type )
m_plotWin->SetColourTheme( GetPlotColor( SIM_BG_COLOR ), GetPlotColor( SIM_FG_COLOR ),
GetPlotColor( SIM_AXIS_COLOR ) );
switch( GetType() )
{
case ST_AC:
m_axis_x = new FREQUENCY_LOG_SCALE( _( "Frequency" ), mpALIGN_BOTTOM );
@ -419,30 +419,33 @@ SIM_PLOT_PANEL::SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, SIM_PLOT_FRAME
m_axis_x->SetTicks( false );
m_axis_x->SetNameAlign ( mpALIGN_BOTTOM );
AddLayer( m_axis_x );
m_plotWin->AddLayer( m_axis_x );
}
if( m_axis_y1 )
{
m_axis_y1->SetTicks( false );
m_axis_y1->SetNameAlign ( mpALIGN_LEFT );
AddLayer( m_axis_y1 );
m_plotWin->AddLayer( m_axis_y1 );
}
if( m_axis_y2 )
{
m_axis_y2->SetTicks( false );
m_axis_y2->SetNameAlign ( mpALIGN_RIGHT );
AddLayer( m_axis_y2 );
m_plotWin->AddLayer( m_axis_y2 );
}
// a mpInfoLegend displays le name of traces on the left top panel corner:
m_legend = new mpInfoLegend( wxRect( 0, 40, 200, 40 ), wxTRANSPARENT_BRUSH );
m_legend->SetVisible( false );
AddLayer( m_legend );
m_plotWin->AddLayer( m_legend );
EnableDoubleBuffer( true );
UpdateAll();
m_plotWin->EnableDoubleBuffer( true );
m_plotWin->UpdateAll();
m_sizer->Add( m_plotWin, 1, wxALL | wxEXPAND, 1 );
SetSizer( m_sizer );
}
@ -455,11 +458,10 @@ SIM_PLOT_PANEL::~SIM_PLOT_PANEL()
void SIM_PLOT_PANEL::UpdatePlotColors()
{
// Update bg and fg colors:
SetColourTheme( GetPlotColor( SIM_BG_COLOR ),
GetPlotColor( SIM_FG_COLOR ),
GetPlotColor( SIM_AXIS_COLOR ) );
m_plotWin->SetColourTheme( GetPlotColor( SIM_BG_COLOR ), GetPlotColor( SIM_FG_COLOR ),
GetPlotColor( SIM_AXIS_COLOR ) );
UpdateAll();
m_plotWin->UpdateAll();
}
@ -469,21 +471,6 @@ wxColour SIM_PLOT_PANEL::GetPlotColor( int aIndex )
}
bool SIM_PLOT_PANEL::IsPlottable( SIM_TYPE aSimType )
{
switch( aSimType )
{
case ST_AC:
case ST_DC:
case ST_TRANSIENT:
return true;
default:
return false;
}
}
void SIM_PLOT_PANEL::UpdateTraceStyle( TRACE* trace )
{
int flags = trace->GetFlags();
@ -505,7 +492,7 @@ bool SIM_PLOT_PANEL::AddTrace( const wxString& aName, int aPoints,
if( addedNewEntry )
{
if( m_type == ST_TRANSIENT )
if( GetType() == ST_TRANSIENT )
{
bool hasVoltageTraces = false;
@ -532,12 +519,12 @@ bool SIM_PLOT_PANEL::AddTrace( const wxString& aName, int aPoints,
// It is a trick to keep legend & coords always on the top
for( mpLayer* l : m_topLevel )
DelLayer( l );
m_plotWin->DelLayer( l );
AddLayer( (mpLayer*) trace );
m_plotWin->AddLayer( (mpLayer*) trace );
for( mpLayer* l : m_topLevel )
AddLayer( l );
m_plotWin->AddLayer( l );
}
else
{
@ -546,7 +533,7 @@ bool SIM_PLOT_PANEL::AddTrace( const wxString& aName, int aPoints,
std::vector<double> tmp( aY, aY + aPoints );
if( m_type == ST_AC )
if( GetType() == ST_AC )
{
if( aFlags & SPT_AC_PHASE )
{
@ -569,7 +556,7 @@ bool SIM_PLOT_PANEL::AddTrace( const wxString& aName, int aPoints,
trace->SetFlags( aFlags );
UpdateAll();
m_plotWin->UpdateAll();
return addedNewEntry;
}
@ -585,9 +572,9 @@ bool SIM_PLOT_PANEL::DeleteTrace( const wxString& aName )
m_traces.erase( it );
if( CURSOR* cursor = trace->GetCursor() )
DelLayer( cursor, true );
m_plotWin->DelLayer( cursor, true );
DelLayer( trace, true, true );
m_plotWin->DelLayer( trace, true, true );
ResetScales();
return true;
@ -627,16 +614,19 @@ void SIM_PLOT_PANEL::EnableCursor( const wxString& aName, bool aEnable )
if( aEnable )
{
CURSOR* c = new CURSOR( t, this );
int plotCenter = GetMarginLeft() + ( GetXScreen() - GetMarginLeft() - GetMarginRight() ) / 2;
int plotCenter = GetPlotWin()->GetMarginLeft()
+ ( GetPlotWin()->GetXScreen() - GetPlotWin()->GetMarginLeft()
- GetPlotWin()->GetMarginRight() )
/ 2;
c->SetX( plotCenter );
t->SetCursor( c );
AddLayer( c );
m_plotWin->AddLayer( c );
}
else
{
CURSOR* c = t->GetCursor();
t->SetCursor( NULL );
DelLayer( c, true );
m_plotWin->DelLayer( c, true );
}
// Notify the parent window about the changes

View File

@ -27,9 +27,11 @@
#ifndef __SIM_PLOT_PANEL_H
#define __SIM_PLOT_PANEL_H
#include <widgets/mathplot.h>
#include <map>
#include "sim_types.h"
#include <map>
#include <widgets/mathplot.h>
#include <wx/sizer.h>
#include "sim_panel_base.h"
class SIM_PLOT_FRAME;
class SIM_PLOT_PANEL;
@ -163,14 +165,14 @@ protected:
};
class SIM_PLOT_PANEL : public mpWindow
class SIM_PLOT_PANEL : public SIM_PANEL_BASE
{
public:
SIM_PLOT_PANEL( SIM_TYPE aType, wxWindow* parent, SIM_PLOT_FRAME* aMainFrame,
wxWindowID id, const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize, long style = 0, const wxString& name = wxPanelNameStr );
~SIM_PLOT_PANEL();
virtual ~SIM_PLOT_PANEL();
///> set the pointer to the sim plot frame
void SetMasterFrame( SIM_PLOT_FRAME* aFrame )
@ -178,13 +180,6 @@ public:
m_masterFrame = aFrame;
}
SIM_TYPE GetType() const
{
return m_type;
}
static bool IsPlottable( SIM_TYPE aSimType );
wxString GetLabelX() const
{
return m_axis_x ? m_axis_x->GetName() : "";
@ -229,7 +224,7 @@ public:
m_axis_x->SetTicks( !aEnable );
m_axis_y1->SetTicks( !aEnable );
m_axis_y2->SetTicks( !aEnable );
UpdateAll();
m_plotWin->UpdateAll();
}
bool IsGridShown() const
@ -244,7 +239,7 @@ public:
void ShowLegend( bool aEnable )
{
m_legend->SetVisible( aEnable );
UpdateAll();
m_plotWin->UpdateAll();
}
bool IsLegendShown() const
@ -261,7 +256,7 @@ public:
UpdateTraceStyle( tr.second );
}
UpdateAll();
m_plotWin->UpdateAll();
}
bool GetDottedCurrentPhase() const
@ -291,6 +286,12 @@ public:
///> Update plot colors
void UpdatePlotColors();
///> Getter for math plot window
mpWindow* GetPlotWin() const
{
return m_plotWin;
}
private:
///> @return a new color from the palette
wxColour generateColor();
@ -298,6 +299,10 @@ private:
// Color index to get a new color from the palette
unsigned int m_colorIdx;
// Top-level plot window
mpWindow* m_plotWin;
wxBoxSizer* m_sizer;
// Traces to be plotted
std::map<wxString, TRACE*> m_traces;
@ -310,8 +315,6 @@ private:
std::vector<mpLayer*> m_topLevel;
const SIM_TYPE m_type;
SIM_PLOT_FRAME* m_masterFrame;
};

View File

@ -26,24 +26,36 @@
#define SIM_TYPES_H
///> Possible simulation types
enum SIM_TYPE {
ST_UNKNOWN, ST_AC, ST_DC, ST_DISTORTION, ST_NOISE, ST_OP,
ST_POLE_ZERO, ST_SENSITIVITY, ST_TRANS_FUNC, ST_TRANSIENT
enum SIM_TYPE
{
ST_UNKNOWN,
ST_AC,
ST_DC,
ST_DISTORTION,
ST_NOISE,
ST_OP,
ST_POLE_ZERO,
ST_SENSITIVITY,
ST_TRANS_FUNC,
ST_TRANSIENT
};
///> Possible plot types
enum SIM_PLOT_TYPE {
enum SIM_PLOT_TYPE
{
// Y axis
SPT_VOLTAGE = 0x01,
SPT_CURRENT = 0x02,
SPT_AC_PHASE = 0x04,
SPT_AC_MAG = 0x08,
SPT_VOLTAGE = 0x01,
SPT_CURRENT = 0x02,
SPT_AC_PHASE = 0x04,
SPT_AC_MAG = 0x08,
// X axis
SPT_TIME = 0x10,
SPT_LIN_FREQUENCY = 0x20,
SPT_LOG_FREQUENCY = 0x20,
SPT_SWEEP = 0x40
SPT_TIME = 0x10,
SPT_LIN_FREQUENCY = 0x20,
SPT_LOG_FREQUENCY = 0x20,
SPT_SWEEP = 0x40,
SPT_UNKNOWN = 0x00
};
#endif /* SIM_TYPES_H */

View File

@ -45,3 +45,39 @@ std::shared_ptr<SPICE_SIMULATOR> SPICE_SIMULATOR::CreateInstance( const std::str
return NULL;
}
wxString SPICE_SIMULATOR::TypeToName( SIM_TYPE aType, bool aShortName )
{
switch( aType )
{
case ST_OP:
return aShortName ? wxT( "OP" ) : _( "Operating Point" );
case ST_AC:
return "AC";
case ST_DC:
return aShortName ? wxT( "DC" ) : _( "DC Sweep" );
case ST_TRANSIENT:
return aShortName ? wxT( "TRAN" ) : _( "Transient" );
case ST_DISTORTION:
return aShortName ? wxT( "DISTO" ) : _( "Distortion" );
case ST_NOISE:
return aShortName ? wxT( "NOISE" ) : _( "Noise" );
case ST_POLE_ZERO:
return aShortName ? wxT( "PZ" ) : _( "Pole-zero" );
case ST_SENSITIVITY:
return aShortName ? wxT( "SENS" ) : _( "Sensitivity" );
case ST_TRANS_FUNC:
return aShortName ? wxT( "TF" ) : _( "Transfer function" );
default:
case ST_UNKNOWN:
return aShortName ? _( "UNKNOWN!" ) : _( "Unknown" );
}
}

View File

@ -32,6 +32,8 @@
#include <complex>
#include <memory>
#include <wx/string.h>
class SPICE_REPORTER;
class SPICE_SIMULATOR;
@ -88,6 +90,13 @@ public:
m_reporter = aReporter;
}
/**
* @brief Returns a list with all vectors generated in current simulation.
* @param none
* @return List of vector names. ?May not match to the net name elements.
*/
virtual std::vector<std::string> AllPlots() = 0;
/**
* @brief Returns a requested vector with complex values. If the vector is real, then
* the imaginary part is set to 0 in all values.
@ -142,6 +151,15 @@ public:
*/
virtual const std::string GetNetlist() const = 0;
/**
* @brief Returns a string with simulation name based on enum.
* @param aType is the enum describing simulation type
* @param aShortName if true - return is in format "TRAN", "OP".
* if false - return is in format "Transient", "Operating Point".
* @return String with requested name as described above.
*/
static wxString TypeToName( SIM_TYPE aType, bool aShortName );
protected:
///> Reporter object to receive simulation log
SPICE_REPORTER* m_reporter;

View File

@ -52,6 +52,9 @@ add_executable( qa_eeschema
test_sch_sheet.cpp
test_sch_sheet_path.cpp
# Simulation tests
sim/test_netlist_exporter_pspice_sim.cpp
# Older CMakes cannot link OBJECT libraries
# https://cmake.org/pipermail/cmake/2013-November/056263.html
$<TARGET_OBJECTS:eeschema_kiface_objects>

View File

@ -0,0 +1,162 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2020 S.Kocjan <s.kocjan@o2.pl>
* Copyright (C) 2020 KiCad Developers, see CHANGELOG.TXT for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file
* Test suite for NETLIST_EXPORTER_PSPICE_SIM
*/
#include <string.h>
#include <unit_test_utils/unit_test_utils.h>
#include <vector>
#include <wx/string.h>
// Code under test
#include <sim/netlist_exporter_pspice_sim.h>
class TEST_NETLIST_EXPORTER_PSPICE_SIM
{
public:
TEST_NETLIST_EXPORTER_PSPICE_SIM()
: m_netlist( new NETLIST_OBJECT_LIST ), m_exporter( m_netlist )
{
}
NETLIST_OBJECT_LIST* m_netlist;
NETLIST_EXPORTER_PSPICE_SIM m_exporter;
};
/**
* Declare the test suite
*/
BOOST_FIXTURE_TEST_SUITE( NetlistExporterPspiceSim, TEST_NETLIST_EXPORTER_PSPICE_SIM )
/**
* Check if simulation command is recognised properly
*/
BOOST_AUTO_TEST_CASE( CommandToSimType )
{
struct TEST_DATA
{
wxString command;
SIM_TYPE type;
};
std::vector<struct TEST_DATA> testData = {
{ ".op", ST_OP },
{ ".option TEMP=27", ST_UNKNOWN },
{ ".tran 0 1 0.1", ST_TRANSIENT },
{ ".tran 0 1 0.1 UIC", ST_TRANSIENT },
{ ".ac dec 10 1 10K", ST_AC },
{ ".ac dec 10 1K 100MEG", ST_AC },
{ ".ac lin 100 1 100HZ", ST_AC },
{ ".dc VIN 0.25 5.0 0.25", ST_DC },
{ ".dc VDS 0 10 .5 VGS 0 5 1", ST_DC },
{ ".dc VCE 0 10 .25 IB 0 10u 1u", ST_DC },
{ ".dc RLoad 1k 2k 100", ST_DC },
{ ".dc TEMP -15 75 5", ST_DC },
{ ".disto dec 10 1kHz 100MEG", ST_DISTORTION },
{ ".disto dec 10 1kHz 100MEG 0.9", ST_DISTORTION },
{ ".noise v(5) VIN dec 10 1kHz 100MEG", 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 2 3 5 0 vol zer", ST_POLE_ZERO },
{ ".pz 4 1 4 1 cur pz", ST_POLE_ZERO },
{ ".SENS V(1,OUT)", ST_SENSITIVITY },
{ ".SENS V(OUT) AC DEC 10 100 100k", ST_SENSITIVITY },
{ ".SENS I(VTEST)", ST_SENSITIVITY },
{ ".tf v(5, 3) VIN", ST_TRANS_FUNC },
{ ".tf i(VLOAD) VIN", ST_TRANS_FUNC },
};
for( auto& step : testData )
{
BOOST_CHECK_EQUAL( m_exporter.CommandToSimType( wxString( step.command ) ), step.type );
}
for( auto& step : testData )
{
step.command.Append( "\n" );
BOOST_CHECK_EQUAL( m_exporter.CommandToSimType( wxString( step.command ) ), step.type );
}
}
/**
* Check conversion from internal spice vector name to eeschema format
*/
BOOST_AUTO_TEST_CASE( VectorToSignal )
{
struct TEST_DATA
{
std::string vector;
wxString signal;
SIM_PLOT_TYPE type;
};
std::vector<struct TEST_DATA> testData = { { "@c3[i]", "I(C3)", SPT_CURRENT },
{ "@r12[i]", "I(R12)", SPT_CURRENT }, { "@r7[i]", "I(R7)", SPT_CURRENT },
{ "@l2[i]", "I(L2)", SPT_CURRENT }, { "@c2[i]", "I(C2)", SPT_CURRENT },
{ "@r6[i]", "I(R6)", SPT_CURRENT }, { "@r5[i]", "I(R5)", SPT_CURRENT },
{ "@r10[i]", "I(R10)", SPT_CURRENT }, { "@q3[ie]", "Ie(Q3)", SPT_CURRENT },
{ "@q3[ic]", "Ic(Q3)", SPT_CURRENT }, { "@q3[ib]", "Ib(Q3)", SPT_CURRENT },
{ "@r11[i]", "I(R11)", SPT_CURRENT }, { "@r8[i]", "I(R8)", SPT_CURRENT },
{ "@q1[ie]", "Ie(Q1)", SPT_CURRENT }, { "@q1[ic]", "Ic(Q1)", SPT_CURRENT },
{ "@q1[ib]", "Ib(Q1)", SPT_CURRENT }, { "@r1[i]", "I(R1)", SPT_CURRENT },
{ "@l1[i]", "I(L1)", SPT_CURRENT }, { "@c4[i]", "I(C4)", SPT_CURRENT },
{ "@r2[i]", "I(R2)", SPT_CURRENT }, { "@q2[ig]", "Ig(Q2)", SPT_CURRENT },
{ "@q2[id]", "Id(Q2)", SPT_CURRENT }, { "@q2[is]", "Is(Q2)", SPT_CURRENT },
{ "@v2[i]", "I(V2)", SPT_CURRENT }, { "@r9[i]", "I(R9)", SPT_CURRENT },
{ "@c1[i]", "I(C1)", SPT_CURRENT }, { "@v1[i]", "I(V1)", SPT_CURRENT },
{ "@r3[i]", "I(R3)", SPT_CURRENT }, { "@r4[i]", "I(R4)", SPT_CURRENT },
{ "vout", "V(vout)", SPT_VOLTAGE }, { "net-_q3-pad2_", "V(net-_q3-pad2_)", SPT_VOLTAGE },
{ "net-_q2-pad3_", "V(net-_q2-pad3_)", SPT_VOLTAGE },
{ "net-_q2-pad1_", "V(net-_q2-pad1_)", SPT_VOLTAGE },
{ "net-_q1-pad3_", "V(net-_q1-pad3_)", SPT_VOLTAGE },
{ "net-_l2-pad1_", "V(net-_l2-pad1_)", SPT_VOLTAGE },
{ "net-_c4-pad2_", "V(net-_c4-pad2_)", SPT_VOLTAGE },
{ "net-_c3-pad1_", "V(net-_c3-pad1_)", SPT_VOLTAGE },
{ "net-_c1-pad2_", "V(net-_c1-pad2_)", SPT_VOLTAGE }, { "/vin", "V(/vin)", SPT_VOLTAGE },
{ "/vbase", "V(/vbase)", SPT_VOLTAGE }, { "+12v", "V(+12v)", SPT_VOLTAGE },
{ "@m1[cgs]", "", SPT_UNKNOWN }, { "@d1[g11]", "", SPT_UNKNOWN },
{ "@d1[c12]", "", SPT_UNKNOWN }, { "@d1[y21]", "", SPT_UNKNOWN },
{ "@n1[vth0]", "", SPT_UNKNOWN }, { "@mn1[gm]", "", SPT_UNKNOWN },
{ "@m.xmos1.xmos2.m1[vdsat]", "", SPT_UNKNOWN } };
for( auto& step : testData )
{
wxString outputSignalName;
SIM_PLOT_TYPE retVal;
retVal = m_exporter.VectorToSignal( step.vector, outputSignalName );
BOOST_CHECK_EQUAL( retVal, step.type );
BOOST_CHECK_EQUAL( outputSignalName.Cmp( step.signal ), 0 );
}
}
BOOST_AUTO_TEST_SUITE_END()