KiCad PCB EDA Suite
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 result.append( fmt::format( "+{}{}={}\n",
93 std::string( indentLength - 1, ' ' ),
94 name,
95 value ) );
96 }
97
98 return result;
99}
100
101
102std::string SPICE_GENERATOR::ItemLine( const SPICE_ITEM& aItem ) const
103{
104 SPICE_ITEM item = aItem;
105
106 if( item.pinNumbers.empty() )
107 {
108 for( int i = 0; i < m_model.GetPinCount(); ++i )
109 item.pinNumbers.push_back( fmt::format( "{}", i + 1 ) );
110 }
111
112 if( item.pinNetNames.empty() )
113 {
114 for( const SIM_MODEL::PIN& pin : GetPins() )
115 item.pinNetNames.push_back( pin.name );
116 }
117
118 std::string result;
119 result.append( ItemName( aItem ) );
120 result.append( ItemPins( aItem ) );
121 result.append( ItemModelName( aItem ) );
122 result.append( ItemParams() );
123 result.append( "\n" );
124 return result;
125}
126
127
128std::string SPICE_GENERATOR::ItemName( const SPICE_ITEM& aItem ) const
129{
130 if( aItem.refName != "" && boost::starts_with( aItem.refName, m_model.GetSpiceInfo().itemType ) )
131 return aItem.refName;
132 else
133 return fmt::format( "{}{}", m_model.GetSpiceInfo().itemType, aItem.refName );
134}
135
136
137std::string SPICE_GENERATOR::ItemPins( const SPICE_ITEM& aItem ) const
138{
139 std::string result;
140 int ncCounter = 0;
141
142 for( const SIM_MODEL::PIN& pin : GetPins() )
143 {
144 auto it = std::find( aItem.pinNumbers.begin(), aItem.pinNumbers.end(),
145 pin.symbolPinNumber );
146
147 if( it == aItem.pinNumbers.end() )
148 {
149 result.append( fmt::format( " NC-{}-{}", aItem.refName, ncCounter++ ) );
150 }
151 else
152 {
153 long symbolPinIndex = std::distance( aItem.pinNumbers.begin(), it );
154 result.append( fmt::format( " {}", aItem.pinNetNames.at( symbolPinIndex ) ) );
155 }
156 }
157
158 return result;
159}
160
161
162std::string SPICE_GENERATOR::ItemModelName( const SPICE_ITEM& aItem ) const
163{
164 return fmt::format( " {}", aItem.modelName );
165}
166
167
169{
170 std::string result;
171
172 for( const SIM_MODEL::PARAM& param : GetInstanceParams() )
173 {
174 std::string name = param.info.spiceInstanceName.empty() ? param.info.name
175 : param.info.spiceInstanceName;
176 std::string value = SIM_VALUE::ToSpice( param.value );
177
178 if( value != "" )
179 result.append( fmt::format( " {}={}", name, value ) );
180 }
181
182 return result;
183}
184
185
186std::string SPICE_GENERATOR::TunerCommand( const SPICE_ITEM& aItem, double aValue ) const
187{
188 // No tuning available by default.
189 return "";
190}
191
192
193std::vector<std::string> SPICE_GENERATOR::CurrentNames( const SPICE_ITEM& aItem ) const
194{
195 return { fmt::format( "I({})", ItemName( aItem ) ) };
196}
197
198
199std::string SPICE_GENERATOR::Preview( const SPICE_ITEM& aItem ) const
200{
201 std::string spiceCode = ModelLine( aItem );
202
203 std::string itemLine = ItemLine( aItem );
204
205 if( spiceCode != "" )
206 spiceCode.append( "\n" );
207
208 spiceCode.append( itemLine );
209 return boost::trim_copy( spiceCode );
210}
211
212
213std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> SPICE_GENERATOR::GetInstanceParams() const
214{
215 std::vector<std::reference_wrapper<const SIM_MODEL::PARAM>> instanceParams;
216
217 for( const SIM_MODEL::PARAM& param : m_model.GetParams() )
218 {
219 if( param.info.isSpiceInstanceParam )
220 instanceParams.emplace_back( param );
221 }
222
223 return instanceParams;
224}
225
226
const char * name
Definition: DXF_plotter.cpp:56
virtual bool requiresSpiceModelLine(const SPICE_ITEM &aItem) const
Definition: sim_model.cpp:1055
int GetPinCount() const
Definition: sim_model.h:456
SPICE_INFO GetSpiceInfo() const
Definition: sim_model.h:437
std::vector< std::reference_wrapper< const PARAM > > GetParams() const
Definition: sim_model.cpp:822
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
static float distance(const SFVEC2UI &a, const SFVEC2UI &b)
std::string itemType
Definition: sim_model.h:279
std::string modelType
Definition: sim_model.h:280
std::string level
Definition: sim_model.h:282
std::string version
Definition: sim_model.h:285
std::string refName
std::string modelName
std::vector< std::string > pinNetNames
std::string baseModelName
std::vector< std::string > pinNumbers