KiCad PCB EDA Suite
Loading...
Searching...
No Matches
spice_circuit_model.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-2022 CERN
5 * Copyright The KiCad Developers, see AUTHORS.TXT for contributors.
6 * @author Maciej Suminski <[email protected]>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 3
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#include "spice_circuit_model.h"
23
24#include <wx/regex.h>
25#include <wx/tokenzr.h>
26
27#include <locale_io.h>
28#include <richio.h>
29#include <string_utils.h>
30
32 wxString& aSignal ) const
33{
34 static wxString BRANCH( wxS( "#branch" ) );
35 static wxString POWER( wxS( ":power" ) );
36
37 // See ngspice manual chapt. 31.1 "Accessing internal device parameters"
38 static wxRegEx internalDevParameter( wxS( "^@(\\w*[\\.\\w+]*)\\[(\\w*)\\]$" ), wxRE_ADVANCED );
39
40 wxString vector( aVector );
41
42 if( !internalDevParameter.Matches( vector ) )
43 {
44 if( vector.EndsWith( BRANCH ) )
45 {
46 aSignal = wxT( "I(" ) + vector.Left( vector.Length() - BRANCH.Length() ) + wxT( ")" );
47 return SPT_CURRENT;
48 }
49 else if( vector.EndsWith( POWER ) )
50 {
51 aSignal = wxT( "P(" ) + vector.Left( vector.Length() - POWER.Length() ) + wxT( ")" );
52 return SPT_POWER;
53 }
54 else
55 {
56 aSignal = wxT( "V(" ) + vector + wxT( ")" );
57 return SPT_VOLTAGE;
58 }
59 }
60 else
61 {
62 wxString paramType = internalDevParameter.GetMatch( vector, 2 );
63
64 if( paramType.Lower()[0] == 'i' )
65 {
66 // this is a branch current
67 paramType[0] = 'I';
68 aSignal = paramType + wxT( "(" );
69 aSignal += internalDevParameter.GetMatch( vector, 1 ).Upper() + wxT( ")" );
70 return SPT_CURRENT;
71 }
72 else
73 {
74 return SPT_UNKNOWN;
75 }
76 }
77}
78
79
81{
82 wxString simCmd;
83
84 ReadDirectives( 0 );
85
86 for( const wxString& directive : GetDirectives() )
87 {
88 if( IsSimCommand( directive ) )
89 simCmd += wxString::Format( wxT( "%s\r\n" ), directive );
90 }
91
92 return simCmd.Trim();
93}
94
95
97{
98 wxString cmd = aCmd.Lower().Trim();
99
100 if( cmd == wxT( ".op" ) ) return ST_OP;
101 else if( cmd.StartsWith( wxT( ".ac" ) ) ) return ST_AC;
102 else if( cmd.StartsWith( wxT( ".dc" ) ) ) return ST_DC;
103 else if( cmd.StartsWith( wxT( ".tran" ) ) ) return ST_TRAN;
104 else if( cmd.StartsWith( wxT( ".disto" ) ) ) return ST_DISTO;
105 else if( cmd.StartsWith( wxT( ".noise" ) ) ) return ST_NOISE;
106 else if( cmd.StartsWith( wxT( ".pz" ) ) ) return ST_PZ;
107 else if( cmd.StartsWith( wxT( ".sens" ) ) ) return ST_SENS;
108 else if( cmd.StartsWith( wxT( ".sp" ) ) ) return ST_SP;
109 else if( cmd.StartsWith( wxT( ".tf" ) ) ) return ST_TF;
110
111 else if( cmd.StartsWith( wxT( "fft" ) ) || cmd.Contains( wxT( "\nfft" ) ) )
112 return ST_FFT;
113 else
114 return ST_UNKNOWN;
115}
116
117
118bool SPICE_CIRCUIT_MODEL::ParseDCCommand( const wxString& aCmd, SPICE_DC_PARAMS* aSource1,
119 SPICE_DC_PARAMS* aSource2 )
120{
121 if( !aCmd.Lower().StartsWith( ".dc" ) )
122 return false;
123
124 wxString cmd = aCmd.Mid( 3 );
125 wxStringTokenizer tokens( cmd, " \t", wxTOKEN_STRTOK );
126
127 aSource1->m_source = tokens.GetNextToken();
128 aSource1->m_vstart = SPICE_VALUE( tokens.GetNextToken() );
129 aSource1->m_vend = SPICE_VALUE( tokens.GetNextToken() );
130 aSource1->m_vincrement = SPICE_VALUE( tokens.GetNextToken() );
131
132 if( tokens.HasMoreTokens() )
133 {
134 aSource2->m_source = tokens.GetNextToken();
135 aSource2->m_vstart = SPICE_VALUE( tokens.GetNextToken() );
136 aSource2->m_vend = SPICE_VALUE( tokens.GetNextToken() );
137 aSource2->m_vincrement = SPICE_VALUE( tokens.GetNextToken() );
138 }
139
140 return true;
141}
142
143
144bool SPICE_CIRCUIT_MODEL::ParsePZCommand( const wxString& aCmd, wxString* transferFunction,
145 wxString* input, wxString* inputRef, wxString* output,
146 wxString* outputRef, SPICE_PZ_ANALYSES* analyses )
147{
148 if( !aCmd.Lower().StartsWith( wxS( ".pz" ) ) )
149 return false;
150
151 *transferFunction = "vol";
152 analyses->m_Poles = true;
153 analyses->m_Zeros = true;
154
155 wxStringTokenizer tokens( aCmd.Mid( 3 ), " \t", wxTOKEN_STRTOK );
156
157 if( tokens.HasMoreTokens() )
158 *input = tokens.GetNextToken();
159
160 if( tokens.HasMoreTokens() )
161 *inputRef = tokens.GetNextToken();
162
163 if( tokens.HasMoreTokens() )
164 *output = tokens.GetNextToken();
165
166 if( tokens.HasMoreTokens() )
167 *outputRef = tokens.GetNextToken();
168
169 if( tokens.HasMoreTokens() )
170 *transferFunction = tokens.GetNextToken();
171
172 if( tokens.HasMoreTokens() )
173 {
174 wxString token = tokens.GetNextToken().Lower();
175
176 if( token == wxS( "pol" ) )
177 analyses->m_Zeros = false;
178 else if( token == wxS( "zer" ) )
179 analyses->m_Poles = false;
180 }
181
182 return true;
183}
184
185bool SPICE_CIRCUIT_MODEL::ParseNoiseCommand( const wxString& aCmd, wxString* aOutput,
186 wxString* aRef, wxString* aSource, wxString* aScale,
187 SPICE_VALUE* aPts, SPICE_VALUE* aFStart,
188 SPICE_VALUE* aFStop, bool* aSaveAll )
189{
190 if( !aCmd.Lower().StartsWith( wxS( ".noise" ) ) )
191 return false;
192
193 wxString cmd = aCmd.Mid( 6 );
194
195 cmd.Trim( false );
196
197 if( !cmd.Lower().StartsWith( wxS( "v(" ) ) )
198 return false;
199
200 cmd = cmd.Mid( 2 );
201
202 wxString function = cmd.Before( ')' );
203 wxString params = cmd.After( ')' );
204
205 wxStringTokenizer func_tokens( function, " ,\t", wxTOKEN_STRTOK );
206
207 *aOutput = func_tokens.GetNextToken();
208 *aRef = func_tokens.GetNextToken();
209
210 wxStringTokenizer tokens( params, " \t", wxTOKEN_STRTOK );
211 wxString token = tokens.GetNextToken();
212
213 if( !token.IsEmpty() )
214 {
215 *aSource = token;
216 token = tokens.GetNextToken();
217 }
218
219 if( token.Lower() == "dec" || token.Lower() == "oct" || token.Lower() == "lin" )
220 {
221 *aScale = token;
222 token = tokens.GetNextToken();
223 }
224
225 if( !token.IsEmpty() )
226 {
227 *aPts = token;
228 token = tokens.GetNextToken();
229 }
230
231 if( !token.IsEmpty() )
232 {
233 *aFStart = SPICE_VALUE( token );
234 token = tokens.GetNextToken();
235 }
236
237 if( !token.IsEmpty() )
238 {
239 *aFStop = SPICE_VALUE( token );
240 token = tokens.GetNextToken();
241 }
242
243 if( !token.IsEmpty() )
244 *aSaveAll = true;
245
246 return true;
247}
248
249
250void SPICE_CIRCUIT_MODEL::WriteDirectives( const wxString& aSimCommand, unsigned aSimOptions,
251 OUTPUTFORMATTER& aFormatter ) const
252{
253 if( aSimCommand.IsEmpty() )
254 aSimOptions |= OPTION_SIM_COMMAND;
255
256 NETLIST_EXPORTER_SPICE::WriteDirectives( aSimCommand, aSimOptions, aFormatter );
257
258 if( !aSimCommand.IsEmpty() )
259 aFormatter.Print( 0, "%s\n", TO_UTF8( aSimCommand ) );
260}
void ReadDirectives(unsigned aNetlistOptions)
const std::vector< wxString > & GetDirectives()
virtual void WriteDirectives(const wxString &aSimCommand, unsigned aSimOptions, OUTPUTFORMATTER &candidate) const
An interface used to output 8 bit text in a convenient way.
Definition richio.h:291
int PRINTF_FUNC_N Print(int nestLevel, const char *fmt,...)
Format and write text to the output stream.
Definition richio.cpp:422
bool ParsePZCommand(const wxString &aCmd, wxString *transferFunction, wxString *input, wxString *inputRef, wxString *output, wxString *outputRef, SPICE_PZ_ANALYSES *analyses)
static bool IsSimCommand(const wxString &aCmd)
Determine if a directive is a simulation command.
bool ParseDCCommand(const wxString &aCmd, SPICE_DC_PARAMS *aSource1, SPICE_DC_PARAMS *aSource2)
Parse a two-source .dc command directive into its symbols.
static SIM_TYPE CommandToSimType(const wxString &aCmd)
Return simulation type basing on a simulation command directive.
bool ParseNoiseCommand(const wxString &aCmd, wxString *aOutput, wxString *aRef, wxString *aSource, wxString *aScale, SPICE_VALUE *aPts, SPICE_VALUE *aFStart, SPICE_VALUE *aFStop, bool *aSaveAll)
void WriteDirectives(const wxString &aSimCommand, unsigned aSimOptions, OUTPUTFORMATTER &aFormatter) const override
wxString GetSchTextSimCommand()
Return simulation command directives placed in schematic sheets (if any).
SIM_TRACE_TYPE VectorToSignal(const std::string &aVector, wxString &aSignal) const
Return name of Spice dataset for a specific trace.
Helper class to recognize Spice formatted values.
Definition spice_value.h:52
SIM_TRACE_TYPE
Definition sim_types.h:46
@ SPT_UNKNOWN
Definition sim_types.h:63
@ SPT_VOLTAGE
Definition sim_types.h:48
@ SPT_POWER
Definition sim_types.h:52
@ SPT_CURRENT
Definition sim_types.h:49
SIM_TYPE
< Possible simulation types
Definition sim_types.h:28
@ ST_SP
Definition sim_types.h:39
@ ST_TRAN
Definition sim_types.h:38
@ ST_UNKNOWN
Definition sim_types.h:29
@ ST_NOISE
Definition sim_types.h:33
@ ST_AC
Definition sim_types.h:30
@ ST_DISTO
Definition sim_types.h:32
@ ST_TF
Definition sim_types.h:37
@ ST_SENS
Definition sim_types.h:36
@ ST_DC
Definition sim_types.h:31
@ ST_OP
Definition sim_types.h:34
@ ST_FFT
Definition sim_types.h:40
@ ST_PZ
Definition sim_types.h:35
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
nlohmann::json output