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( const SIM_MODEL::PARAM& param : m_model.GetParams() )
66 {
67 if( param.info.isSpiceInstanceParam )
68 continue;
69
70 std::string name;
71 std::string value;
72
73 if( !param.info.spiceModelName.empty() )
74 {
75 name = param.info.spiceModelName;
76 }
77 else
78 {
79 // Because of collisions with instance parameters, we append some model parameters
80 // with "_".
81 if( boost::ends_with( param.info.name, "_" ) )
82 name = param.info.name.substr( 0, param.info.name.length() - 1 );
83 else
84 name = param.info.name;
85 }
86
87 value = SIM_VALUE::ToSpice( param.value );
88
89 if( value == "" )
90 continue;
91
92 if( param.info.category == SIM_MODEL::PARAM::CATEGORY::FLAGS )
93 {
94 if( value == "1" )
95 result.append( fmt::format( "+{}\n", name ) );
96 }
97 else
98 {
99 result.append( fmt::format( "+{}{}={}\n",
100 std::string( indentLength - 1, ' ' ),
101 name,
102 value ) );
103 }
104 }
105
106 // Don't send SPICE empty models.
107 if( result.length() == indentLength + 1 /* line ending */ )
108 result.clear();
109
110 return result;
111}
112
113
114std::string SPICE_GENERATOR::ItemLine( const SPICE_ITEM& aItem ) const
115{
116 SPICE_ITEM item = aItem;
117
118 if( item.pinNumbers.empty() )
119 {
120 for( int i = 0; i < m_model.GetPinCount(); ++i )
121 item.pinNumbers.push_back( fmt::format( "{}", i + 1 ) );
122 }
123
124 if( item.pinNetNames.empty() )
125 {
126 for( const SIM_MODEL::PIN& pin : GetPins() )
127 item.pinNetNames.push_back( pin.name );
128 }
129
130 std::string result;
131 result.append( ItemName( aItem ) );
132 result.append( ItemPins( aItem ) );
133 result.append( ItemModelName( aItem ) );
134 result.append( ItemParams() );
135 result.append( "\n" );
136 return result;
137}
138
139
140std::string SPICE_GENERATOR::ItemName( const SPICE_ITEM& aItem ) const
141{
142 if( aItem.refName != "" && boost::starts_with( aItem.refName, m_model.GetSpiceInfo().itemType ) )
143 return aItem.refName;
144 else
145 return fmt::format( "{}{}", m_model.GetSpiceInfo().itemType, aItem.refName );
146}
147
148
149std::string SPICE_GENERATOR::ItemPins( const SPICE_ITEM& aItem ) const
150{
151 std::string result;
152 int ncCounter = 0;
153
154 for( const SIM_MODEL::PIN& pin : GetPins() )
155 {
156 auto it = std::find( aItem.pinNumbers.begin(), aItem.pinNumbers.end(),
157 pin.symbolPinNumber );
158
159 if( it == aItem.pinNumbers.end() )
160 {
161 result.append( fmt::format( " NC-{}-{}", aItem.refName, ncCounter++ ) );
162 }
163 else
164 {
165 long symbolPinIndex = std::distance( aItem.pinNumbers.begin(), it );
166 result.append( fmt::format( " {}", aItem.pinNetNames.at( symbolPinIndex ) ) );
167 }
168 }
169
170 return result;
171}
172
173
174std::string SPICE_GENERATOR::ItemModelName( const SPICE_ITEM& aItem ) const
175{
176 return fmt::format( " {}", aItem.modelName );
177}
178
179
181{
182 std::string result;
183
184 for( const SIM_MODEL::PARAM& param : GetInstanceParams() )
185 {
186 std::string name = param.info.spiceInstanceName.empty() ? param.info.name
187 : param.info.spiceInstanceName;
188 std::string value = SIM_VALUE::ToSpice( param.value );
189
190 if( param.info.category == SIM_MODEL::PARAM::CATEGORY::FLAGS )
191 {
192 if( value == "1" )
193 result.append( fmt::format( " {}", name ) );
194 }
195 else
196 {
197 if( value != "" )
198 result.append( fmt::format( " {}={}", name, value ) );
199 }
200 }
201
202 return result;
203}
204
205
206std::string SPICE_GENERATOR::TunerCommand( const SPICE_ITEM& aItem, double aValue ) const
207{
208 // No tuning available by default.
209 return "";
210}
211
212
213std::vector<std::string> SPICE_GENERATOR::CurrentNames( const SPICE_ITEM& aItem ) const
214{
215 return { fmt::format( "I({})", ItemName( aItem ) ) };
216}
217
218
219std::string SPICE_GENERATOR::Preview( const SPICE_ITEM& aItem ) const
220{
221 std::string spiceCode = ModelLine( aItem );
222
223 std::string itemLine = ItemLine( aItem );
224
225 if( spiceCode != "" )
226 spiceCode.append( "\n" );
227
228 spiceCode.append( itemLine );
229 return boost::trim_copy( spiceCode );
230}
231
232
233std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> SPICE_GENERATOR::GetInstanceParams() const
234{
235 std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> instanceParams;
236
237 for( const SIM_MODEL::PARAM& param : m_model.GetParams() )
238 {
239 if( param.info.isSpiceInstanceParam )
240 instanceParams.emplace_back( param );
241 }
242
243 return instanceParams;
244}
245
246
const char * name
Definition: DXF_plotter.cpp:57
virtual bool requiresSpiceModelLine(const SPICE_ITEM &aItem) const
Definition: sim_model.cpp:1018
int GetPinCount() const
Definition: sim_model.h:472
SPICE_INFO GetSpiceInfo() const
Definition: sim_model.h:453
std::vector< std::reference_wrapper< const PARAM > > GetParams() const
Definition: sim_model.cpp:816
static std::string ToSpice(const std::string &aString)
Definition: sim_value.h:84
virtual std::string ItemName(const SPICE_ITEM &aItem) const
virtual std::vector< std::reference_wrapper< const SIM_MODEL::PARAM > > GetInstanceParams() 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 itemType
Definition: sim_model.h:296
std::string modelType
Definition: sim_model.h:297
std::string level
Definition: sim_model.h:299
std::string version
Definition: sim_model.h:302
std::string refName
std::string modelName
std::vector< std::string > pinNetNames
std::string baseModelName
std::vector< std::string > pinNumbers