KiCad PCB EDA Suite
netlist_exporter_pspice_sim.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2016 CERN
5  * @author Maciej Suminski <maciej.suminski@cern.ch>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 3
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * https://www.gnu.org/licenses/gpl-3.0.html
20  * or you may search the http://www.gnu.org website for the version 3 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
26 
27 wxString NETLIST_EXPORTER_PSPICE_SIM::GetSpiceVector( const wxString& aName, SIM_PLOT_TYPE aType,
28  const wxString& aParam ) const
29 {
30  wxString res;
31 
32  // Some of the flags should exclude mutually
33  assert( ( ( aType & SPT_VOLTAGE ) == 0 ) != ( ( aType & SPT_CURRENT ) == 0 ) );
34  assert( ( ( aType & SPT_AC_PHASE ) == 0 ) || ( ( aType & SPT_AC_MAG ) == 0 ) );
35 
36  if( aType & SPT_VOLTAGE )
37  {
38  // Spice netlist netnames does not accept some chars, whicyh are replaced
39  // by eeschema netlist generator.
40  // Replace these forbidden chars to find the actual spice net name
41  wxString spicenet = aName;
43 
44  return wxString::Format( "V(%s)", spicenet.GetData() );
45  }
46 
47  else if( aType & SPT_CURRENT )
48  {
49  return wxString::Format( "@%s[%s]", GetSpiceDevice( aName ).Lower(),
50  aParam.IsEmpty() ? "i" : aParam.Lower() );
51  }
52 
53  return res;
54 }
55 
56 
57 const std::vector<wxString>& NETLIST_EXPORTER_PSPICE_SIM::GetCurrents( SPICE_PRIMITIVE aPrimitive )
58 {
59  static const std::vector<wxString> passive = { "I" };
60  static const std::vector<wxString> diode = { "Id" };
61  static const std::vector<wxString> bjt = { "Ib", "Ic", "Ie" };
62  static const std::vector<wxString> mos = { "Ig", "Id", "Is" };
63  static const std::vector<wxString> empty;
64 
65  switch( aPrimitive )
66  {
67  case SP_RESISTOR:
68  case SP_CAPACITOR:
69  case SP_INDUCTOR:
70  case SP_VSOURCE:
71  return passive;
72 
73  case SP_DIODE:
74  return diode;
75 
76  case SP_BJT:
77  return bjt;
78 
79  case SP_MOSFET:
80  return mos;
81 
82  default:
83  return empty;
84  }
85 }
86 
87 
88 wxString NETLIST_EXPORTER_PSPICE_SIM::GetSpiceDevice( const wxString& aComponent ) const
89 {
90  const auto& spiceItems = GetSpiceItems();
91 
92  auto it = std::find_if( spiceItems.begin(), spiceItems.end(), [&]( const SPICE_ITEM& item ) {
93  return item.m_refName == aComponent;
94  } );
95 
96  if( it == spiceItems.end() )
97  return wxEmptyString;
98 
99  return wxString( it->m_primitive + it->m_refName );
100 }
101 
102 
104 {
105  wxString simCmd;
106 
108 
109  for( const auto& dir : GetDirectives() )
110  {
111  if( IsSimCommand( dir ) )
112  simCmd += wxString::Format( "%s\r\n", dir );
113  }
114 
115  return simCmd;
116 }
117 
118 
120 {
122 }
123 
124 
126 {
127  const std::map<wxString, SIM_TYPE> simCmds = {
128  { ".ac", ST_AC }, { ".dc", ST_DC }, { ".disto", ST_DISTORTION }, { ".noise", ST_NOISE },
129  { ".op", ST_OP }, { ".pz", ST_POLE_ZERO }, { ".sens", ST_SENSITIVITY }, { ".tf", ST_TRANS_FUNC },
130  { ".tran", ST_TRANSIENT }
131  };
132  wxString lcaseCmd = aCmd.Lower();
133 
134  for( const auto& c : simCmds )
135  {
136  if( lcaseCmd.StartsWith( c.first ) )
137  return c.second;
138  }
139 
140  return ST_UNKNOWN;
141 }
142 
143 
144 void NETLIST_EXPORTER_PSPICE_SIM::writeDirectives( OUTPUTFORMATTER* aFormatter, unsigned aCtl ) const
145 {
146  // Add a directive to obtain currents
147  //aFormatter->Print( 0, ".options savecurrents\n" ); // does not work :(
148 
149  for( const auto& item : GetSpiceItems() )
150  {
151  for( const auto& current :
153  {
154  if( !item.m_enabled )
155  continue;
156 
158  aFormatter->Print( 0, ".save %s\n",
159  (const char*) GetSpiceVector( item.m_refName, SPT_CURRENT, current ).c_str() );
160  }
161  }
162 
163  // If we print out .save directives for currents, then it needs to be done for voltages as well
164  for( const auto& netMap : GetNetIndexMap() )
165  {
166  aFormatter->Print( 0, ".save %s\n",
167  (const char*) GetSpiceVector( netMap.first, SPT_VOLTAGE ).c_str() );
168  }
169 
170  if( m_simCommand.IsEmpty() )
171  {
172  // Fallback to the default behavior and just write all directives
173  NETLIST_EXPORTER_PSPICE::writeDirectives( aFormatter, aCtl );
174  }
175  else
176  {
177  // Dump all directives but simulation commands
178  for( const auto& dir : GetDirectives() )
179  {
180  if( !IsSimCommand( dir ) )
181  aFormatter->Print( 0, "%s\n", (const char*) dir.c_str() );
182  }
183 
184  // Finish with our custom simulation command
185  aFormatter->Print( 0, "%s\n", (const char*) m_simCommand.c_str() );
186  }
187 }
const std::vector< wxString > GetDirectives() const
Returnss a vector of Spice directives found in the schematics.
wxString m_simCommand
Custom simulation command (has priority over the schematic sheet simulation commands) ...
const NET_INDEX_MAP & GetNetIndexMap() const
Returns a map of circuit nodes to net names.
wxString GetSpiceDevice(const wxString &aComponent) const
Returns name of Spice device corresponding to a schematic component.
Structure to represent a schematic component in the Spice simulation.
wxString GetSpiceVector(const wxString &aName, SIM_PLOT_TYPE aType, const wxString &aParam=wxEmptyString) const
Returns name of Spice dataset for a specific plot.
Class OUTPUTFORMATTER is an important interface (abstract class) used to output 8 bit text in a conve...
Definition: richio.h:327
static bool IsSimCommand(const wxString &aCmd)
Determines if a directive is a simulation command.
static SIM_TYPE CommandToSimType(const wxString &aCmd)
Returns simulation type basing on a simulation command directive.
void writeDirectives(OUTPUTFORMATTER *aFormatter, unsigned aCtl) const override
Saves the Spice directives.
static const std::vector< wxString > & GetCurrents(SPICE_PRIMITIVE aPrimitive)
Returns a list of currents that can be probed in a Spice primitive.
wxString GetSheetSimCommand()
Returns simulation command directives placed in schematic sheets (if any).
SIM_TYPE
Possible simulation types
Definition: sim_types.h:29
void UpdateDirectives(unsigned aCtl)
Updates the vector of Spice directives placed in the schematics.
const SPICE_ITEM_LIST & GetSpiceItems() const
Returns list of items representing schematic components in the Spice world.
static void ReplaceForbiddenChars(wxString &aNetName)
some chars are not accepted in netnames in spice netlists.
virtual void writeDirectives(OUTPUTFORMATTER *aFormatter, unsigned aCtl) const
Saves the Spice directives.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
SPICE_PRIMITIVE
Basic Spice component primitives
static bool empty(const wxTextEntryBase *aCtrl)
int PRINTF_FUNC Print(int nestLevel, const char *fmt,...)
Function Print formats and writes text to the output stream.
Definition: richio.cpp:404
SIM_PLOT_TYPE
Possible plot types
Definition: sim_types.h:35
SIM_TYPE GetSimType()
Returns simulation type basing on the simulation command directives.