KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_sim_model_ngspice.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 The KiCad Developers, see AUTHORS.TXT for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
22#include <boost/algorithm/string/predicate.hpp>
23
24
26{
27public:
31
32 static std::string defaultOf( MODEL_TYPE aType, const std::string& aName )
33 {
34 for( const SIM_MODEL::PARAM::INFO& param : ModelInfo( aType ).instanceParams )
35 {
36 if( param.name == aName )
37 return param.defaultValue;
38 }
39
40 BOOST_FAIL( ModelInfo( aType ).name << " instance parameter not found: " << aName );
41 return {};
42 }
43};
44
45
46BOOST_FIXTURE_TEST_SUITE( SimModelNgspice, TEST_SIM_MODEL_NGSPICE_FIXTURE )
47
48
49BOOST_AUTO_TEST_CASE( ParamDuplicates )
50{
51 for( MODEL_TYPE type : MODEL_TYPE_ITERATOR() )
52 {
53 BOOST_TEST_CONTEXT( "Model name: " << ModelInfo( type ).name )
54 {
55 const std::vector<SIM_MODEL::PARAM::INFO> modelParams = ModelInfo( type ).modelParams;
56 const std::vector<SIM_MODEL::PARAM::INFO> instanceParams = ModelInfo( type ).instanceParams;
57
58 for( const SIM_MODEL::PARAM::INFO& modelParam : modelParams )
59 {
60 BOOST_TEST_CONTEXT( "Model param name: " << modelParam.name )
61 {
62 // Ensure there's no model parameters that have the same name.
63 BOOST_CHECK( std::none_of( modelParams.begin(), modelParams.end(),
64 [&modelParam]( const auto& aOtherModelParam )
65 {
66 return modelParam.id != aOtherModelParam.id
67 && modelParam.name == aOtherModelParam.name;
68 } ) );
69
70 // Ensure there's no model parameters that have the same name as an
71 // instance parameter.
72 BOOST_CHECK( std::none_of( instanceParams.begin(), instanceParams.end(),
73 [&modelParam]( const auto& aInstanceParam )
74 {
75 return modelParam.name == aInstanceParam.name;
76 } ) );
77
78 if( boost::ends_with( modelParam.name, "_" ) )
79 {
80 // Ensure that for each model parameter ending with a "_" there exists an
81 // instance parameter with the same name but without this final character.
82 // We append an "_" to model parameters to disambiguate from these
83 // corresponding instance parameters.
84 BOOST_CHECK( std::any_of( instanceParams.begin(), instanceParams.end(),
85 [&modelParam]( const auto& aInstanceParam )
86 {
87 return modelParam.name.substr( 0, modelParam.name.length() - 1 )
88 == aInstanceParam.name;
89 } ) );
90 }
91 }
92 }
93
94 // Ensure there's no instance parameters that have the same name.
95 for( const SIM_MODEL::PARAM::INFO& instanceParam : instanceParams )
96 {
97 BOOST_TEST_CONTEXT( "Instance param name: " << instanceParam.name )
98 {
99 BOOST_CHECK( std::none_of( instanceParams.begin(), instanceParams.end(),
100 [&instanceParam]( const auto& aOtherInstanceParam )
101 {
102 return instanceParam.id != aOtherInstanceParam.id
103 && instanceParam.dir != SIM_MODEL::PARAM::DIR_OUT
104 && aOtherInstanceParam.dir != SIM_MODEL::PARAM::DIR_OUT
105 && instanceParam.name == aOtherInstanceParam.name;
106 } ) );
107 }
108 }
109 }
110 }
111}
112
113
114BOOST_AUTO_TEST_CASE( HfetInstanceParamDefaults )
115{
116 // Guards the HFET1 defaults restored from the ngspice 46 source after they had been lost
117 // to empty strings; the per-parameter rationale lives in sim_model_ngspice_data_hfet.cpp.
118
119 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET1, "l" ), "1e-06" );
120 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET1, "w" ), "2e-05" );
121 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET1, "m" ), "1" );
122 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET1, "dtemp" ), "0" );
123
124 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET1, "off" ), "" );
125 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET1, "icvds" ), "" );
126 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET1, "icvgs" ), "" );
127 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET1, "temp" ), "" );
128}
129
130
131BOOST_AUTO_TEST_CASE( FetInstanceParamDefaults )
132{
133 // Guards the geometry/multiplier/dtemp defaults sourced from the ngspice 46 setup/temp code for
134 // the remaining FET devices, mirroring the HFET1 guard above. Per-parameter rationale lives in
135 // the sim_model_ngspice_data_{hfet,mes,jfet}.cpp files.
136
137 // HFET2 tracks the HFET1 geometry defaults (hfet2setup.c, hfet2temp.c).
138 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET2, "l" ), "1e-06" );
139 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET2, "w" ), "2e-05" );
140 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET2, "m" ), "1" );
141 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET2, "dtemp" ), "0" );
142 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET2, "icvds" ), "" );
143 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::HFET2, "temp" ), "" );
144
145 // MES is area-scaled (messetup.c).
146 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::MES, "area" ), "1" );
147 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::MES, "m" ), "1" );
148 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::MES, "icvds" ), "" );
149
150 // The MES m id must be the mesdefs.h MES_M value, distinct from area's id, or id-keyed lookups
151 // conflate the multiplier with the area factor.
152 const std::vector<SIM_MODEL::PARAM::INFO>& mesParams = ModelInfo( MODEL_TYPE::MES ).instanceParams;
153
154 auto mesM = std::find_if( mesParams.begin(), mesParams.end(),
155 []( const SIM_MODEL::PARAM::INFO& aParam )
156 {
157 return aParam.name == "m";
158 } );
159
160 BOOST_REQUIRE( mesM != mesParams.end() );
161 BOOST_CHECK_EQUAL( mesM->id, 8u );
162
163 // MESA restores geometry/dtemp and the instance multiplier (mesasetup.c).
164 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::MESA, "l" ), "1e-06" );
165 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::MESA, "w" ), "2e-05" );
166 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::MESA, "m" ), "1" );
167 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::MESA, "dtemp" ), "0" );
168 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::MESA, "td" ), "" );
169 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::MESA, "ts" ), "" );
170
171 // JFET/JFET2 are area-scaled (jfetset.c/jfet2set.c, jfettemp.c/jfet2temp.c).
172 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::JFET, "area" ), "1" );
173 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::JFET, "m" ), "1" );
174 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::JFET, "dtemp" ), "0" );
175 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::JFET, "temp" ), "" );
176
177 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::JFET2, "area" ), "1" );
178 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::JFET2, "m" ), "1" );
179 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::JFET2, "dtemp" ), "0" );
180 BOOST_CHECK_EQUAL( defaultOf( MODEL_TYPE::JFET2, "temp" ), "" );
181}
182
183
185{
186 // Count the total number of model and instance parameters for each model so that there will be
187 // an error if someone accidentally removes a parameter.
188
189 for( MODEL_TYPE type : MODEL_TYPE_ITERATOR() )
190 {
191 const std::vector<SIM_MODEL::PARAM::INFO> modelParams = ModelInfo( type ).modelParams;
192 const std::vector<SIM_MODEL::PARAM::INFO> instanceParams = ModelInfo( type ).instanceParams;
193
194 switch( type )
195 {
196 case MODEL_TYPE::NONE:
197 case MODEL_TYPE::_ENUM_END:
198 break;
199
200 /*case MODEL_TYPE::RESISTOR:
201 BOOST_CHECK_EQUAL( modelParams.size(), 22 );
202 BOOST_CHECK_EQUAL( instanceParams.size(), 25 );
203 break;
204
205 case MODEL_TYPE::CAPACITOR:
206 BOOST_CHECK_EQUAL( modelParams.size(), 19 );
207 BOOST_CHECK_EQUAL( instanceParams.size(), 22 );
208 break;
209
210 case MODEL_TYPE::INDUCTOR:
211 BOOST_CHECK_EQUAL( modelParams.size(), 9 );
212 BOOST_CHECK_EQUAL( instanceParams.size(), 20 );
213 break;*/
214
215 /*case MODEL_TYPE::LTRA:
216 BOOST_CHECK_EQUAL( modelParams.size(), 18 );
217 BOOST_CHECK_EQUAL( instanceParams.size(), 9 );
218 break;
219
220 case MODEL_TYPE::TRANLINE:
221 BOOST_CHECK_EQUAL( modelParams.size(), 0 );
222 BOOST_CHECK_EQUAL( instanceParams.size(), 17 );
223 break;
224
225 case MODEL_TYPE::URC:
226 BOOST_CHECK_EQUAL( modelParams.size(), 7 );
227 BOOST_CHECK_EQUAL( instanceParams.size(), 5 );
228 break;*/
229
230 /*case MODEL_TYPE::TRANSLINE:
231 BOOST_CHECK_EQUAL( modelParams.size(), 6 );
232 BOOST_CHECK_EQUAL( instanceParams.size(), 3 );
233 break;*/
234
235 /*case MODEL_TYPE::SWITCH:
236 BOOST_CHECK_EQUAL( modelParams.size(), 7 );
237 BOOST_CHECK_EQUAL( instanceParams.size(), 8 );
238 break;
239
240 case MODEL_TYPE::CSWITCH:
241 BOOST_CHECK_EQUAL( modelParams.size(), 7 );
242 BOOST_CHECK_EQUAL( instanceParams.size(), 7 );
243 break;*/
244
245 case MODEL_TYPE::DIODE:
246 BOOST_CHECK_EQUAL( modelParams.size(), 76 );
247 BOOST_CHECK_EQUAL( instanceParams.size(), 30 );
248 break;
249
250 case MODEL_TYPE::BJT:
251 BOOST_CHECK_EQUAL( modelParams.size(), 152 );
252 BOOST_CHECK_EQUAL( instanceParams.size(), 53 );
253 break;
254
255 case MODEL_TYPE::VBIC:
256 BOOST_CHECK_EQUAL( modelParams.size(), 117 );
257 BOOST_CHECK_EQUAL( instanceParams.size(), 45 );
258 break;
259
260 case MODEL_TYPE::HICUM2:
261 BOOST_CHECK_EQUAL( modelParams.size(), 149 );
262 BOOST_CHECK_EQUAL( instanceParams.size(), 61 );
263 break;
264
265 case MODEL_TYPE::JFET:
266 BOOST_CHECK_EQUAL( modelParams.size(), 34 );
267 BOOST_CHECK_EQUAL( instanceParams.size(), 28 );
268 break;
269
270 case MODEL_TYPE::JFET2:
271 BOOST_CHECK_EQUAL( modelParams.size(), 46 );
272 BOOST_CHECK_EQUAL( instanceParams.size(), 30 );
273 break;
274
275 case MODEL_TYPE::MES:
276 BOOST_CHECK_EQUAL( modelParams.size(), 22 );
277 BOOST_CHECK_EQUAL( instanceParams.size(), 25 );
278 break;
279
280 case MODEL_TYPE::MESA:
281 BOOST_CHECK_EQUAL( modelParams.size(), 71 );
282 BOOST_CHECK_EQUAL( instanceParams.size(), 30 );
283 break;
284
285 case MODEL_TYPE::HFET1:
286 BOOST_CHECK_EQUAL( modelParams.size(), 68 );
287 BOOST_CHECK_EQUAL( instanceParams.size(), 28 );
288 break;
289
290 case MODEL_TYPE::HFET2:
291 BOOST_CHECK_EQUAL( modelParams.size(), 40 );
292 BOOST_CHECK_EQUAL( instanceParams.size(), 28 );
293 break;
294
295 case MODEL_TYPE::VDMOS:
296 BOOST_CHECK_EQUAL( modelParams.size(), 69 );
297 BOOST_CHECK_EQUAL( instanceParams.size(), 36 );
298 break;
299
300 case MODEL_TYPE::MOS1:
301 BOOST_CHECK_EQUAL( modelParams.size(), 35 );
302 BOOST_CHECK_EQUAL( instanceParams.size(), 76 );
303 break;
304
305 case MODEL_TYPE::MOS2:
306 BOOST_CHECK_EQUAL( modelParams.size(), 42 );
307 BOOST_CHECK_EQUAL( instanceParams.size(), 76 );
308 break;
309
310 case MODEL_TYPE::MOS3:
311 BOOST_CHECK_EQUAL( modelParams.size(), 48 );
312 BOOST_CHECK_EQUAL( instanceParams.size(), 81 );
313 break;
314
315 case MODEL_TYPE::BSIM1:
316 BOOST_CHECK_EQUAL( modelParams.size(), 81 );
317 BOOST_CHECK_EQUAL( instanceParams.size(), 14 );
318 break;
319
320 case MODEL_TYPE::BSIM2:
321 BOOST_CHECK_EQUAL( modelParams.size(), 137 );
322 BOOST_CHECK_EQUAL( instanceParams.size(), 14 );
323 break;
324
325 case MODEL_TYPE::MOS6:
326 BOOST_CHECK_EQUAL( modelParams.size(), 42 );
327 BOOST_CHECK_EQUAL( instanceParams.size(), 78 );
328 break;
329
330 case MODEL_TYPE::BSIM3:
331 BOOST_CHECK_EQUAL( modelParams.size(), 429 );
332 BOOST_CHECK_EQUAL( instanceParams.size(), 46 );
333 break;
334
335 case MODEL_TYPE::MOS9:
336 BOOST_CHECK_EQUAL( modelParams.size(), 48 );
337 BOOST_CHECK_EQUAL( instanceParams.size(), 81 );
338 break;
339
340 case MODEL_TYPE::B4SOI:
341 BOOST_CHECK_EQUAL( modelParams.size(), 915 );
342 BOOST_CHECK_EQUAL( instanceParams.size(), 74 );
343 break;
344
345 case MODEL_TYPE::BSIM4:
346 BOOST_CHECK_EQUAL( modelParams.size(), 892 );
347 BOOST_CHECK_EQUAL( instanceParams.size(), 84 );
348 break;
349
350 case MODEL_TYPE::B3SOIFD:
351 BOOST_CHECK_EQUAL( modelParams.size(), 393 );
352 BOOST_CHECK_EQUAL( instanceParams.size(), 27 );
353 break;
354
355 case MODEL_TYPE::B3SOIDD:
356 BOOST_CHECK_EQUAL( modelParams.size(), 393 );
357 BOOST_CHECK_EQUAL( instanceParams.size(), 27 );
358 break;
359
360 case MODEL_TYPE::B3SOIPD:
361 BOOST_CHECK_EQUAL( modelParams.size(), 470 );
362 BOOST_CHECK_EQUAL( instanceParams.size(), 36 );
363 break;
364
365 case MODEL_TYPE::HISIM2:
366 BOOST_CHECK_EQUAL( modelParams.size(), 486 );
367 BOOST_CHECK_EQUAL( instanceParams.size(), 59 );
368 break;
369
370 case MODEL_TYPE::HISIMHV1:
371 BOOST_CHECK_EQUAL( modelParams.size(), 610 );
372 BOOST_CHECK_EQUAL( instanceParams.size(), 72 );
373 break;
374
375 case MODEL_TYPE::HISIMHV2:
376 BOOST_CHECK_EQUAL( modelParams.size(), 730 );
377 BOOST_CHECK_EQUAL( instanceParams.size(), 74 );
378 break;
379
380 default:
381 BOOST_FAIL( wxString::Format(
382 "Unhandled type: %d "
383 "(if you created a new type you need to handle it in this switch "
384 "statement)",
385 type ) );
386 }
387 }
388}
389
390
const char * name
static const MODEL_INFO & ModelInfo(MODEL_TYPE aType)
SIM_MODEL_NGSPICE(TYPE aType)
static std::string defaultOf(MODEL_TYPE aType, const std::string &aName)
@ NONE
Definition eda_shape.h:72
SIM_MODEL::TYPE TYPE
Definition sim_model.cpp:54
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_TEST_CONTEXT("Test Clearance")
BOOST_AUTO_TEST_CASE(ParamDuplicates)
BOOST_CHECK_EQUAL(result, "25.4")