KiCad PCB EDA Suite
Loading...
Searching...
No Matches
spice_generator.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) 2022 Mikolaj Wielgus
5 * Copyright (C) 2022-2023 KiCad Developers, see AUTHORS.txt for contributors.
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
25#include <sim/spice_generator.h>
26
27#include <boost/algorithm/string/predicate.hpp>
28#include <boost/algorithm/string/trim.hpp>
29#include <fmt/core.h>
30
31
32std::string SPICE_GENERATOR::ModelName( const SPICE_ITEM& aItem ) const
33{
34 if( aItem.baseModelName == "" )
35 return fmt::format( "__{}", aItem.refName );
36
37 if( m_model.requiresSpiceModelLine( aItem ) )
38 return fmt::format( "{}.{}", aItem.refName, aItem.baseModelName );
39
40 return aItem.baseModelName;
41}
42
43
44std::string SPICE_GENERATOR::ModelLine( const SPICE_ITEM& aItem ) const
45{
46 if( !m_model.requiresSpiceModelLine( aItem ) )
47 return "";
48
49 std::string result;
50
51 result.append( fmt::format( ".model {} ", aItem.modelName ) );
52 size_t indentLength = result.length();
53
54 const SIM_MODEL::SPICE_INFO& spiceInfo = m_model.GetSpiceInfo();
55 result.append( spiceInfo.modelType );
56
57 if ( !spiceInfo.isDefaultLevel && !spiceInfo.level.empty() )
58 result.append( fmt::format( " level={}", spiceInfo.level ) );
59
60 if ( !spiceInfo.version.empty() )
61 result.append( fmt::format( " version={}", spiceInfo.version ) );
62
63 result.append( "\n" );
64
65 for( int ii = 0; ii < m_model.GetParamCount(); ++ii )
66 {
67 const SIM_MODEL::PARAM& param = m_model.GetParam( ii );
68
69 if( param.info.isSpiceInstanceParam )
70 continue;
71
72 std::string name;
73 std::string value;
74
75 if( !param.info.spiceModelName.empty() )
76 {
77 name = param.info.spiceModelName;
78 }
79 else
80 {
81 // Because of collisions with instance parameters, we append some model parameters
82 // with "_".
83 if( boost::ends_with( param.info.name, "_" ) )
84 name = param.info.name.substr( 0, param.info.name.length() - 1 );
85 else
86 name = param.info.name;
87 }
88
89 value = SIM_VALUE::ToSpice( param.value );
90
91 if( value == "" )
92 continue;
93
95 {
96 if( value == "1" )
97 result.append( fmt::format( "+{}\n", name ) );
98 }
99 else
100 {
101 result.append( fmt::format( "+{}{}={}\n",
102 std::string( indentLength - 1, ' ' ),
103 name,
104 value ) );
105 }
106 }
107
108 // Don't send SPICE empty models.
109 if( result.length() == indentLength + 1 /* line ending */ )
110 result.clear();
111
112 return result;
113}
114
115
116std::string SPICE_GENERATOR::ItemLine( const SPICE_ITEM& aItem ) const
117{
118 SPICE_ITEM item = aItem;
119
120 if( item.pinNumbers.empty() )
121 {
122 for( int i = 0; i < m_model.GetPinCount(); ++i )
123 item.pinNumbers.push_back( fmt::format( "{}", i + 1 ) );
124 }
125
126 if( item.pinNetNames.empty() )
127 {
128 for( const SIM_MODEL_PIN& pin : GetPins() )
129 item.pinNetNames.push_back( pin.modelPinName );
130 }
131
132 std::string result;
133 result.append( ItemName( aItem ) );
134 result.append( ItemPins( aItem ) );
135 result.append( ItemModelName( aItem ) );
136 result.append( ItemParams() );
137 result.append( "\n" );
138 return result;
139}
140
141
142std::string SPICE_GENERATOR::ItemName( const SPICE_ITEM& aItem ) const
143{
144 if( aItem.refName != "" && boost::starts_with( aItem.refName, m_model.GetSpiceInfo().itemType ) )
145 return aItem.refName;
146 else
147 return fmt::format( "{}{}", m_model.GetSpiceInfo().itemType, aItem.refName );
148}
149
150
151std::string SPICE_GENERATOR::ItemPins( const SPICE_ITEM& aItem ) const
152{
153 std::string result;
154 int ncCounter = 0;
155
156 for( const SIM_MODEL_PIN& pin : GetPins() )
157 {
158 auto it = std::find( aItem.pinNumbers.begin(), aItem.pinNumbers.end(),
159 pin.symbolPinNumber );
160
161 if( it == aItem.pinNumbers.end() )
162 {
163 result.append( fmt::format( " NC-{}-{}", aItem.refName, ncCounter++ ) );
164 }
165 else
166 {
167 long symbolPinIndex = std::distance( aItem.pinNumbers.begin(), it );
168 result.append( fmt::format( " {}", aItem.pinNetNames.at( symbolPinIndex ) ) );
169 }
170 }
171
172 return result;
173}
174
175
176std::string SPICE_GENERATOR::ItemModelName( const SPICE_ITEM& aItem ) const
177{
178 return fmt::format( " {}", aItem.modelName );
179}
180
181
183{
184 std::string result;
185
186 for( int ii = 0; ii < m_model.GetParamCount(); ++ii )
187 {
188 const SIM_MODEL::PARAM& param = m_model.GetParam( ii );
189
190 if( !param.info.isSpiceInstanceParam )
191 continue;
192
193 std::string name = param.info.spiceInstanceName.empty() ? param.info.name
194 : param.info.spiceInstanceName;
195 std::string value = SIM_VALUE::ToSpice( param.value );
196
198 {
199 if( value == "1" )
200 result.append( fmt::format( " {}", name ) );
201 }
202 else
203 {
204 if( value != "" )
205 result.append( fmt::format( " {}={}", name, value ) );
206 }
207 }
208
209 return result;
210}
211
212
213std::string SPICE_GENERATOR::TunerCommand( const SPICE_ITEM& aItem, double aValue ) const
214{
215 // No tuning available by default.
216 return "";
217}
218
219
220std::vector<std::string> SPICE_GENERATOR::CurrentNames( const SPICE_ITEM& aItem ) const
221{
222 return { fmt::format( "I({})", ItemName( aItem ) ) };
223}
224
225
226std::string SPICE_GENERATOR::Preview( const SPICE_ITEM& aItem ) const
227{
228 std::string spiceCode = ModelLine( aItem );
229
230 std::string itemLine = ItemLine( aItem );
231
232 if( spiceCode != "" )
233 spiceCode.append( "\n" );
234
235 spiceCode.append( itemLine );
236 return boost::trim_copy( spiceCode );
237}
238
239
const char * name
Definition: DXF_plotter.cpp:57
virtual bool requiresSpiceModelLine(const SPICE_ITEM &aItem) const
Definition: sim_model.cpp:1038
int GetPinCount() const
Definition: sim_model.h:471
virtual const PARAM & GetParam(unsigned aParamIndex) const
Definition: sim_model.cpp:789
int GetParamCount() const
Definition: sim_model.h:481
SPICE_INFO GetSpiceInfo() const
Definition: sim_model.h:452
static std::string ToSpice(const std::string &aString)
Definition: sim_value.cpp:419
virtual std::string ItemName(const SPICE_ITEM &aItem) const
virtual std::string ItemPins(const SPICE_ITEM &aItem) const
virtual std::string ItemLine(const SPICE_ITEM &aItem) const
virtual std::string ModelLine(const SPICE_ITEM &aItem) const
virtual std::vector< std::reference_wrapper< const SIM_MODEL_PIN > > GetPins() const
virtual std::string ItemParams() const
const SIM_MODEL & m_model
virtual std::string Preview(const SPICE_ITEM &aItem) const
virtual std::string ItemModelName(const SPICE_ITEM &aItem) const
virtual std::string TunerCommand(const SPICE_ITEM &aItem, double aValue) const
virtual std::string ModelName(const SPICE_ITEM &aItem) const
virtual std::vector< std::string > CurrentNames(const SPICE_ITEM &aItem) const
std::string spiceModelName
Definition: sim_model.h:386
std::string spiceInstanceName
Definition: sim_model.h:387
std::string value
Definition: sim_model.h:400
const INFO & info
Definition: sim_model.h:401
std::string itemType
Definition: sim_model.h:304
std::string modelType
Definition: sim_model.h:305
std::string level
Definition: sim_model.h:307
std::string version
Definition: sim_model.h:310
std::string refName
std::string modelName
std::vector< std::string > pinNetNames
std::string baseModelName
std::vector< std::string > pinNumbers