├── .gitignore ├── LICENSE.txt ├── README.md ├── examples └── butterworth │ ├── LMH6624.MOD │ ├── LMH6624.txt │ ├── butterworth-cache.lib │ ├── butterworth-opamp.png │ ├── butterworth.ipynb │ ├── butterworth.kicad_pcb │ ├── butterworth.md │ ├── butterworth.pdf │ ├── butterworth.png │ ├── butterworth.pro │ ├── butterworth.sch │ └── butterworth.svg ├── kicad ├── __init__.py ├── matplotlib_renderer.py ├── schema.py └── spice_converter.py ├── models_source ├── diodes │ ├── LICENSE │ ├── diodes │ │ ├── BAV99.spice.diff │ │ ├── BAV99.spice.txt │ │ └── index.py │ └── mosfets │ │ ├── DMG2301LK.spice.txt │ │ ├── DMN2005UFG.spice.txt │ │ ├── DMN2230U.spice.txt │ │ ├── DMP2078LCA3.spice.txt │ │ └── index.py ├── onsemi │ └── bjt │ │ ├── 50A02CH-SPICE-D.diff │ │ ├── 50A02CH-SPICE-D.txt │ │ ├── 50C02CH_SPICE-D.LIB │ │ ├── 50C02CH_SPICE-D.diff │ │ └── index.py └── ti │ └── op_amp │ ├── LMH6624.MOD │ ├── LMH6624.txt │ ├── LMH6702.MOD │ ├── LMH6702.txt │ ├── LMV981.MOD │ ├── LMV981.txt │ ├── OPA695_PSPICE_MODEL.diff │ ├── OPA695_PSPICE_MODEL.txt │ └── index.py ├── spice ├── __init__.py ├── circuit.py ├── ltspice.py ├── models.py ├── ngspice.py ├── patch.py ├── preprocessor.py ├── rawfile.py ├── simulator.py ├── unit.py └── xyce.py ├── test-ltspice.py ├── test-ngspice.py ├── test-preprocessor.py ├── test-render.py ├── test-schema.py ├── test-xyce.py └── update-models.py /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.bak 3 | *.bck 4 | *-bak 5 | *.net 6 | *.pyc 7 | *.pyo 8 | .ipynb_checkpoints/ 9 | #*# 10 | .#* 11 | models 12 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 2.1, February 1999 3 | 4 | Copyright (C) 1991, 1999 Free Software Foundation, Inc. 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | [This is the first released version of the Lesser GPL. It also counts 10 | as the successor of the GNU Library Public License, version 2, hence 11 | the version number 2.1.] 12 | 13 | Preamble 14 | 15 | The licenses for most software are designed to take away your 16 | freedom to share and change it. By contrast, the GNU General Public 17 | Licenses are intended to guarantee your freedom to share and change 18 | free software--to make sure the software is free for all its users. 19 | 20 | This license, the Lesser General Public License, applies to some 21 | specially designated software packages--typically libraries--of the 22 | Free Software Foundation and other authors who decide to use it. You 23 | can use it too, but we suggest you first think carefully about whether 24 | this license or the ordinary General Public License is the better 25 | strategy to use in any particular case, based on the explanations below. 26 | 27 | When we speak of free software, we are referring to freedom of use, 28 | not price. Our General Public Licenses are designed to make sure that 29 | you have the freedom to distribute copies of free software (and charge 30 | for this service if you wish); that you receive source code or can get 31 | it if you want it; that you can change the software and use pieces of 32 | it in new free programs; and that you are informed that you can do 33 | these things. 34 | 35 | To protect your rights, we need to make restrictions that forbid 36 | distributors to deny you these rights or to ask you to surrender these 37 | rights. These restrictions translate to certain responsibilities for 38 | you if you distribute copies of the library or if you modify it. 39 | 40 | For example, if you distribute copies of the library, whether gratis 41 | or for a fee, you must give the recipients all the rights that we gave 42 | you. You must make sure that they, too, receive or can get the source 43 | code. If you link other code with the library, you must provide 44 | complete object files to the recipients, so that they can relink them 45 | with the library after making changes to the library and recompiling 46 | it. And you must show them these terms so they know their rights. 47 | 48 | We protect your rights with a two-step method: (1) we copyright the 49 | library, and (2) we offer you this license, which gives you legal 50 | permission to copy, distribute and/or modify the library. 51 | 52 | To protect each distributor, we want to make it very clear that 53 | there is no warranty for the free library. Also, if the library is 54 | modified by someone else and passed on, the recipients should know 55 | that what they have is not the original version, so that the original 56 | author's reputation will not be affected by problems that might be 57 | introduced by others. 58 | 59 | Finally, software patents pose a constant threat to the existence of 60 | any free program. We wish to make sure that a company cannot 61 | effectively restrict the users of a free program by obtaining a 62 | restrictive license from a patent holder. Therefore, we insist that 63 | any patent license obtained for a version of the library must be 64 | consistent with the full freedom of use specified in this license. 65 | 66 | Most GNU software, including some libraries, is covered by the 67 | ordinary GNU General Public License. This license, the GNU Lesser 68 | General Public License, applies to certain designated libraries, and 69 | is quite different from the ordinary General Public License. We use 70 | this license for certain libraries in order to permit linking those 71 | libraries into non-free programs. 72 | 73 | When a program is linked with a library, whether statically or using 74 | a shared library, the combination of the two is legally speaking a 75 | combined work, a derivative of the original library. The ordinary 76 | General Public License therefore permits such linking only if the 77 | entire combination fits its criteria of freedom. The Lesser General 78 | Public License permits more lax criteria for linking other code with 79 | the library. 80 | 81 | We call this license the "Lesser" General Public License because it 82 | does Less to protect the user's freedom than the ordinary General 83 | Public License. It also provides other free software developers Less 84 | of an advantage over competing non-free programs. These disadvantages 85 | are the reason we use the ordinary General Public License for many 86 | libraries. However, the Lesser license provides advantages in certain 87 | special circumstances. 88 | 89 | For example, on rare occasions, there may be a special need to 90 | encourage the widest possible use of a certain library, so that it becomes 91 | a de-facto standard. To achieve this, non-free programs must be 92 | allowed to use the library. A more frequent case is that a free 93 | library does the same job as widely used non-free libraries. In this 94 | case, there is little to gain by limiting the free library to free 95 | software only, so we use the Lesser General Public License. 96 | 97 | In other cases, permission to use a particular library in non-free 98 | programs enables a greater number of people to use a large body of 99 | free software. For example, permission to use the GNU C Library in 100 | non-free programs enables many more people to use the whole GNU 101 | operating system, as well as its variant, the GNU/Linux operating 102 | system. 103 | 104 | Although the Lesser General Public License is Less protective of the 105 | users' freedom, it does ensure that the user of a program that is 106 | linked with the Library has the freedom and the wherewithal to run 107 | that program using a modified version of the Library. 108 | 109 | The precise terms and conditions for copying, distribution and 110 | modification follow. Pay close attention to the difference between a 111 | "work based on the library" and a "work that uses the library". The 112 | former contains code derived from the library, whereas the latter must 113 | be combined with the library in order to run. 114 | 115 | GNU LESSER GENERAL PUBLIC LICENSE 116 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 117 | 118 | 0. This License Agreement applies to any software library or other 119 | program which contains a notice placed by the copyright holder or 120 | other authorized party saying it may be distributed under the terms of 121 | this Lesser General Public License (also called "this License"). 122 | Each licensee is addressed as "you". 123 | 124 | A "library" means a collection of software functions and/or data 125 | prepared so as to be conveniently linked with application programs 126 | (which use some of those functions and data) to form executables. 127 | 128 | The "Library", below, refers to any such software library or work 129 | which has been distributed under these terms. A "work based on the 130 | Library" means either the Library or any derivative work under 131 | copyright law: that is to say, a work containing the Library or a 132 | portion of it, either verbatim or with modifications and/or translated 133 | straightforwardly into another language. (Hereinafter, translation is 134 | included without limitation in the term "modification".) 135 | 136 | "Source code" for a work means the preferred form of the work for 137 | making modifications to it. For a library, complete source code means 138 | all the source code for all modules it contains, plus any associated 139 | interface definition files, plus the scripts used to control compilation 140 | and installation of the library. 141 | 142 | Activities other than copying, distribution and modification are not 143 | covered by this License; they are outside its scope. The act of 144 | running a program using the Library is not restricted, and output from 145 | such a program is covered only if its contents constitute a work based 146 | on the Library (independent of the use of the Library in a tool for 147 | writing it). Whether that is true depends on what the Library does 148 | and what the program that uses the Library does. 149 | 150 | 1. You may copy and distribute verbatim copies of the Library's 151 | complete source code as you receive it, in any medium, provided that 152 | you conspicuously and appropriately publish on each copy an 153 | appropriate copyright notice and disclaimer of warranty; keep intact 154 | all the notices that refer to this License and to the absence of any 155 | warranty; and distribute a copy of this License along with the 156 | Library. 157 | 158 | You may charge a fee for the physical act of transferring a copy, 159 | and you may at your option offer warranty protection in exchange for a 160 | fee. 161 | 162 | 2. You may modify your copy or copies of the Library or any portion 163 | of it, thus forming a work based on the Library, and copy and 164 | distribute such modifications or work under the terms of Section 1 165 | above, provided that you also meet all of these conditions: 166 | 167 | a) The modified work must itself be a software library. 168 | 169 | b) You must cause the files modified to carry prominent notices 170 | stating that you changed the files and the date of any change. 171 | 172 | c) You must cause the whole of the work to be licensed at no 173 | charge to all third parties under the terms of this License. 174 | 175 | d) If a facility in the modified Library refers to a function or a 176 | table of data to be supplied by an application program that uses 177 | the facility, other than as an argument passed when the facility 178 | is invoked, then you must make a good faith effort to ensure that, 179 | in the event an application does not supply such function or 180 | table, the facility still operates, and performs whatever part of 181 | its purpose remains meaningful. 182 | 183 | (For example, a function in a library to compute square roots has 184 | a purpose that is entirely well-defined independent of the 185 | application. Therefore, Subsection 2d requires that any 186 | application-supplied function or table used by this function must 187 | be optional: if the application does not supply it, the square 188 | root function must still compute square roots.) 189 | 190 | These requirements apply to the modified work as a whole. If 191 | identifiable sections of that work are not derived from the Library, 192 | and can be reasonably considered independent and separate works in 193 | themselves, then this License, and its terms, do not apply to those 194 | sections when you distribute them as separate works. But when you 195 | distribute the same sections as part of a whole which is a work based 196 | on the Library, the distribution of the whole must be on the terms of 197 | this License, whose permissions for other licensees extend to the 198 | entire whole, and thus to each and every part regardless of who wrote 199 | it. 200 | 201 | Thus, it is not the intent of this section to claim rights or contest 202 | your rights to work written entirely by you; rather, the intent is to 203 | exercise the right to control the distribution of derivative or 204 | collective works based on the Library. 205 | 206 | In addition, mere aggregation of another work not based on the Library 207 | with the Library (or with a work based on the Library) on a volume of 208 | a storage or distribution medium does not bring the other work under 209 | the scope of this License. 210 | 211 | 3. You may opt to apply the terms of the ordinary GNU General Public 212 | License instead of this License to a given copy of the Library. To do 213 | this, you must alter all the notices that refer to this License, so 214 | that they refer to the ordinary GNU General Public License, version 2, 215 | instead of to this License. (If a newer version than version 2 of the 216 | ordinary GNU General Public License has appeared, then you can specify 217 | that version instead if you wish.) Do not make any other change in 218 | these notices. 219 | 220 | Once this change is made in a given copy, it is irreversible for 221 | that copy, so the ordinary GNU General Public License applies to all 222 | subsequent copies and derivative works made from that copy. 223 | 224 | This option is useful when you wish to copy part of the code of 225 | the Library into a program that is not a library. 226 | 227 | 4. You may copy and distribute the Library (or a portion or 228 | derivative of it, under Section 2) in object code or executable form 229 | under the terms of Sections 1 and 2 above provided that you accompany 230 | it with the complete corresponding machine-readable source code, which 231 | must be distributed under the terms of Sections 1 and 2 above on a 232 | medium customarily used for software interchange. 233 | 234 | If distribution of object code is made by offering access to copy 235 | from a designated place, then offering equivalent access to copy the 236 | source code from the same place satisfies the requirement to 237 | distribute the source code, even though third parties are not 238 | compelled to copy the source along with the object code. 239 | 240 | 5. A program that contains no derivative of any portion of the 241 | Library, but is designed to work with the Library by being compiled or 242 | linked with it, is called a "work that uses the Library". Such a 243 | work, in isolation, is not a derivative work of the Library, and 244 | therefore falls outside the scope of this License. 245 | 246 | However, linking a "work that uses the Library" with the Library 247 | creates an executable that is a derivative of the Library (because it 248 | contains portions of the Library), rather than a "work that uses the 249 | library". The executable is therefore covered by this License. 250 | Section 6 states terms for distribution of such executables. 251 | 252 | When a "work that uses the Library" uses material from a header file 253 | that is part of the Library, the object code for the work may be a 254 | derivative work of the Library even though the source code is not. 255 | Whether this is true is especially significant if the work can be 256 | linked without the Library, or if the work is itself a library. The 257 | threshold for this to be true is not precisely defined by law. 258 | 259 | If such an object file uses only numerical parameters, data 260 | structure layouts and accessors, and small macros and small inline 261 | functions (ten lines or less in length), then the use of the object 262 | file is unrestricted, regardless of whether it is legally a derivative 263 | work. (Executables containing this object code plus portions of the 264 | Library will still fall under Section 6.) 265 | 266 | Otherwise, if the work is a derivative of the Library, you may 267 | distribute the object code for the work under the terms of Section 6. 268 | Any executables containing that work also fall under Section 6, 269 | whether or not they are linked directly with the Library itself. 270 | 271 | 6. As an exception to the Sections above, you may also combine or 272 | link a "work that uses the Library" with the Library to produce a 273 | work containing portions of the Library, and distribute that work 274 | under terms of your choice, provided that the terms permit 275 | modification of the work for the customer's own use and reverse 276 | engineering for debugging such modifications. 277 | 278 | You must give prominent notice with each copy of the work that the 279 | Library is used in it and that the Library and its use are covered by 280 | this License. You must supply a copy of this License. If the work 281 | during execution displays copyright notices, you must include the 282 | copyright notice for the Library among them, as well as a reference 283 | directing the user to the copy of this License. Also, you must do one 284 | of these things: 285 | 286 | a) Accompany the work with the complete corresponding 287 | machine-readable source code for the Library including whatever 288 | changes were used in the work (which must be distributed under 289 | Sections 1 and 2 above); and, if the work is an executable linked 290 | with the Library, with the complete machine-readable "work that 291 | uses the Library", as object code and/or source code, so that the 292 | user can modify the Library and then relink to produce a modified 293 | executable containing the modified Library. (It is understood 294 | that the user who changes the contents of definitions files in the 295 | Library will not necessarily be able to recompile the application 296 | to use the modified definitions.) 297 | 298 | b) Use a suitable shared library mechanism for linking with the 299 | Library. A suitable mechanism is one that (1) uses at run time a 300 | copy of the library already present on the user's computer system, 301 | rather than copying library functions into the executable, and (2) 302 | will operate properly with a modified version of the library, if 303 | the user installs one, as long as the modified version is 304 | interface-compatible with the version that the work was made with. 305 | 306 | c) Accompany the work with a written offer, valid for at 307 | least three years, to give the same user the materials 308 | specified in Subsection 6a, above, for a charge no more 309 | than the cost of performing this distribution. 310 | 311 | d) If distribution of the work is made by offering access to copy 312 | from a designated place, offer equivalent access to copy the above 313 | specified materials from the same place. 314 | 315 | e) Verify that the user has already received a copy of these 316 | materials or that you have already sent this user a copy. 317 | 318 | For an executable, the required form of the "work that uses the 319 | Library" must include any data and utility programs needed for 320 | reproducing the executable from it. However, as a special exception, 321 | the materials to be distributed need not include anything that is 322 | normally distributed (in either source or binary form) with the major 323 | components (compiler, kernel, and so on) of the operating system on 324 | which the executable runs, unless that component itself accompanies 325 | the executable. 326 | 327 | It may happen that this requirement contradicts the license 328 | restrictions of other proprietary libraries that do not normally 329 | accompany the operating system. Such a contradiction means you cannot 330 | use both them and the Library together in an executable that you 331 | distribute. 332 | 333 | 7. You may place library facilities that are a work based on the 334 | Library side-by-side in a single library together with other library 335 | facilities not covered by this License, and distribute such a combined 336 | library, provided that the separate distribution of the work based on 337 | the Library and of the other library facilities is otherwise 338 | permitted, and provided that you do these two things: 339 | 340 | a) Accompany the combined library with a copy of the same work 341 | based on the Library, uncombined with any other library 342 | facilities. This must be distributed under the terms of the 343 | Sections above. 344 | 345 | b) Give prominent notice with the combined library of the fact 346 | that part of it is a work based on the Library, and explaining 347 | where to find the accompanying uncombined form of the same work. 348 | 349 | 8. You may not copy, modify, sublicense, link with, or distribute 350 | the Library except as expressly provided under this License. Any 351 | attempt otherwise to copy, modify, sublicense, link with, or 352 | distribute the Library is void, and will automatically terminate your 353 | rights under this License. However, parties who have received copies, 354 | or rights, from you under this License will not have their licenses 355 | terminated so long as such parties remain in full compliance. 356 | 357 | 9. You are not required to accept this License, since you have not 358 | signed it. However, nothing else grants you permission to modify or 359 | distribute the Library or its derivative works. These actions are 360 | prohibited by law if you do not accept this License. Therefore, by 361 | modifying or distributing the Library (or any work based on the 362 | Library), you indicate your acceptance of this License to do so, and 363 | all its terms and conditions for copying, distributing or modifying 364 | the Library or works based on it. 365 | 366 | 10. Each time you redistribute the Library (or any work based on the 367 | Library), the recipient automatically receives a license from the 368 | original licensor to copy, distribute, link with or modify the Library 369 | subject to these terms and conditions. You may not impose any further 370 | restrictions on the recipients' exercise of the rights granted herein. 371 | You are not responsible for enforcing compliance by third parties with 372 | this License. 373 | 374 | 11. If, as a consequence of a court judgment or allegation of patent 375 | infringement or for any other reason (not limited to patent issues), 376 | conditions are imposed on you (whether by court order, agreement or 377 | otherwise) that contradict the conditions of this License, they do not 378 | excuse you from the conditions of this License. If you cannot 379 | distribute so as to satisfy simultaneously your obligations under this 380 | License and any other pertinent obligations, then as a consequence you 381 | may not distribute the Library at all. For example, if a patent 382 | license would not permit royalty-free redistribution of the Library by 383 | all those who receive copies directly or indirectly through you, then 384 | the only way you could satisfy both it and this License would be to 385 | refrain entirely from distribution of the Library. 386 | 387 | If any portion of this section is held invalid or unenforceable under any 388 | particular circumstance, the balance of the section is intended to apply, 389 | and the section as a whole is intended to apply in other circumstances. 390 | 391 | It is not the purpose of this section to induce you to infringe any 392 | patents or other property right claims or to contest validity of any 393 | such claims; this section has the sole purpose of protecting the 394 | integrity of the free software distribution system which is 395 | implemented by public license practices. Many people have made 396 | generous contributions to the wide range of software distributed 397 | through that system in reliance on consistent application of that 398 | system; it is up to the author/donor to decide if he or she is willing 399 | to distribute software through any other system and a licensee cannot 400 | impose that choice. 401 | 402 | This section is intended to make thoroughly clear what is believed to 403 | be a consequence of the rest of this License. 404 | 405 | 12. If the distribution and/or use of the Library is restricted in 406 | certain countries either by patents or by copyrighted interfaces, the 407 | original copyright holder who places the Library under this License may add 408 | an explicit geographical distribution limitation excluding those countries, 409 | so that distribution is permitted only in or among countries not thus 410 | excluded. In such case, this License incorporates the limitation as if 411 | written in the body of this License. 412 | 413 | 13. The Free Software Foundation may publish revised and/or new 414 | versions of the Lesser General Public License from time to time. 415 | Such new versions will be similar in spirit to the present version, 416 | but may differ in detail to address new problems or concerns. 417 | 418 | Each version is given a distinguishing version number. If the Library 419 | specifies a version number of this License which applies to it and 420 | "any later version", you have the option of following the terms and 421 | conditions either of that version or of any later version published by 422 | the Free Software Foundation. If the Library does not specify a 423 | license version number, you may choose any version ever published by 424 | the Free Software Foundation. 425 | 426 | 14. If you wish to incorporate parts of the Library into other free 427 | programs whose distribution conditions are incompatible with these, 428 | write to the author to ask for permission. For software which is 429 | copyrighted by the Free Software Foundation, write to the Free 430 | Software Foundation; we sometimes make exceptions for this. Our 431 | decision will be guided by the two goals of preserving the free status 432 | of all derivatives of our free software and of promoting the sharing 433 | and reuse of software generally. 434 | 435 | NO WARRANTY 436 | 437 | 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO 438 | WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. 439 | EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR 440 | OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY 441 | KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE 442 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 443 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE 444 | LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME 445 | THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 446 | 447 | 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN 448 | WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY 449 | AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU 450 | FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR 451 | CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE 452 | LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING 453 | RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A 454 | FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF 455 | SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 456 | DAMAGES. 457 | 458 | END OF TERMS AND CONDITIONS 459 | 460 | How to Apply These Terms to Your New Libraries 461 | 462 | If you develop a new library, and you want it to be of the greatest 463 | possible use to the public, we recommend making it free software that 464 | everyone can redistribute and change. You can do so by permitting 465 | redistribution under these terms (or, alternatively, under the terms of the 466 | ordinary General Public License). 467 | 468 | To apply these terms, attach the following notices to the library. It is 469 | safest to attach them to the start of each source file to most effectively 470 | convey the exclusion of warranty; and each file should have at least the 471 | "copyright" line and a pointer to where the full notice is found. 472 | 473 | 474 | Copyright (C) 475 | 476 | This library is free software; you can redistribute it and/or 477 | modify it under the terms of the GNU Lesser General Public 478 | License as published by the Free Software Foundation; either 479 | version 2.1 of the License, or (at your option) any later version. 480 | 481 | This library is distributed in the hope that it will be useful, 482 | but WITHOUT ANY WARRANTY; without even the implied warranty of 483 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 484 | Lesser General Public License for more details. 485 | 486 | You should have received a copy of the GNU Lesser General Public 487 | License along with this library; if not, write to the Free Software 488 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 489 | USA 490 | 491 | Also add information on how to contact you by electronic and paper mail. 492 | 493 | You should also get your employer (if you work as a programmer) or your 494 | school, if any, to sign a "copyright disclaimer" for the library, if 495 | necessary. Here is a sample; alter the names: 496 | 497 | Yoyodyne, Inc., hereby disclaims all copyright interest in the 498 | library `Frob' (a library for tweaking knobs) written by James Random 499 | Hacker. 500 | 501 | , 1 April 1990 502 | Ty Coon, President of Vice 503 | 504 | That's all there is to it! 505 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Python library for simulation KiCad schematics using Spice 2 | 3 | ## Overview 4 | 5 | This libray is at a very early stage of development. There are 6 | probably lots of bugs, and only Device:R, Device:C, Device:L and 7 | Spice-enabled components have been tested so far. 8 | 9 | ## Example 10 | 11 | [test-ngspice.py](test-ngspice.py) shows how to run a simulation using 12 | Ngspice from the command line. 13 | 14 | For a more advanced example on how to use this library, see the output 15 | from this [Jupyter Notebook](examples/butterworth/butterworth.ipynb). 16 | Just about anything in the notebook can also be run directly from 17 | Python and produce output in an interactive matplotlib window instead. 18 | 19 | If you want to out the notebook yourself, follow the install 20 | instructions below and then start the Jupyter notebook with: 21 | 22 | ``` 23 | jupyter notebook 24 | ``` 25 | 26 | If this doesn't work, try teling Jupyter not to start a browser and 27 | then open the link that is printed in your preferred browser: 28 | 29 | ``` 30 | jupyter notebook --no-browser 31 | ``` 32 | 33 | ## Prerequisites 34 | 35 | I've been using the following libraries to run this: 36 | 37 | * KiCad Version 5.0.0-rc2 nightly build as of 16 aug 2018 38 | * Python 3.5 or Python 3.6 with pip 39 | * Matplotlib 1.5.1 or 2.1.1 40 | * Ngspice 26-1 or 27-1 41 | * Jupyter Notebook =1.0.0 42 | 43 | All this is running on Ubuntu 16.04 LTS or 18.04 LTS. 44 | 45 | I don't see any reasons why this shouldn't work on other Linux 46 | distributions or even on Windows, but I haven't tried it myself. 47 | 48 | ## The Xyce and LTspice simulation engines 49 | 50 | There is also some support for the Xyce and LTspice engines. 51 | 52 | I downloaded and installed the Xyce binaries for Ubuntu 16.04 (they 53 | won't work on Ubuntu 18.04) from here: 54 | 55 | > https://knowm.org/comparing-simulation-results-of-the-knowm-m-mss-model-in-xyce-and-jspice-using-qucs-s/ 56 | 57 | Note that the butterworth schematic will not work with Xyce as is. 58 | For some reason the LMV981 OP-amp model causes a "timestamp too small" 59 | error when trying to simulate the circuit. Switching to a different 60 | OP-amp model such as the LMH6624 does work though. 61 | 62 | LTspiceXVII was installed using Wine on Ubuntu 16.04. 63 | 64 | ## Installation 65 | 66 | Follow the instructions here on how to install the nightly build of 67 | KiCad on Ubuntu: 68 | 69 | > http://kicad-pcb.org/download/ubuntu/ 70 | 71 | Python, matplotlib and Ngspice, pip are the versionsions that come 72 | with Ubunutu and can be installed with: 73 | 74 | ``` 75 | apt-get install python3 python3-pip python3-matplotlib ngspice 76 | ``` 77 | 78 | Jupyter notebook was installed using pip with: 79 | 80 | ``` 81 | python3 -m pip install jupyter 82 | ``` 83 | 84 | ## LICENSING 85 | 86 | ### Main libraries 87 | 88 | Unless otherwise specified all files are licensed under the following 89 | terms: 90 | 91 | Copyright (C) 2018 Christer Weinigel 92 | 93 | This library is free software; you can redistribute it and/or 94 | modify it under the terms of the GNU Lesser General Public 95 | License as published by the Free Software Foundation; either 96 | version 2.1 of the License, or (at your option) any later version. 97 | 98 | This library is distributed in the hope that it will be useful, 99 | but WITHOUT ANY WARRANTY; without even the implied warranty of 100 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the [GNU 101 | Lesser General Public License](LICENSE.txt) for more details. 102 | 103 | In plain english: If you use these libraries in your application, you 104 | do not have to publish the source to your application. But if you 105 | make modifications to the spice or kicard libraries themselves you 106 | have give publish those changes. 107 | 108 | ### Example code 109 | 110 | You can use the source code in the Jupyter notebooks (*.ipynb) and 111 | test applications (test-*.py) any way you like. They are meant to be 112 | used as examples and can be treated as public domain. If your 113 | jurisdiction will not recognise public domain, you can choose to treat 114 | these files as licensed under the terms of the MIT License: 115 | 116 | Copyright (c) 2018 Christer Weinigel 117 | 118 | Permission is hereby granted, free of charge, to any person 119 | obtaining a copy of this software and associated documentation 120 | files (the "Software"), to deal in the Software without 121 | restriction, including without limitation the rights to use, copy, 122 | modify, merge, publish, distribute, sublicense, and/or sell copies 123 | of the Software, and to permit persons to whom the Software is 124 | furnished to do so, subject to the following conditions: 125 | 126 | The above copyright notice and this permission notice shall be 127 | included in all copies or substantial portions of the Software. 128 | 129 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 130 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 131 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 132 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 133 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 134 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 135 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 136 | DEALINGS IN THE SOFTWARE. 137 | 138 | ### spice/patch.py 139 | 140 | The file spice/patch.py was originally written by the user techtonik 141 | on github and is available here: 142 | 143 | https://github.com/techtonik/python-patch 144 | 145 | This file is licensed under the following terms: 146 | 147 | MIT License 148 | ----------- 149 | 150 | Copyright (c) 2008-2016 anatoly techtonik 151 | 152 | Permission is hereby granted, free of charge, to any person 153 | obtaining a copy of this software and associated documentation 154 | files (the "Software"), to deal in the Software without 155 | restriction, including without limitation the rights to use, copy, 156 | modify, merge, publish, distribute, sublicense, and/or sell copies 157 | of the Software, and to permit persons to whom the Software is 158 | furnished to do so, subject to the following conditions: 159 | 160 | The above copyright notice and this permission notice shall be 161 | included in all copies or substantial portions of the Software. 162 | 163 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 164 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 165 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 166 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 167 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 168 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 169 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 170 | DEALINGS IN THE SOFTWARE. 171 | 172 | The file has since been modified slightly by Christer Weinigel to 173 | allow for in patching of files in memory. 174 | 175 | ### Spice models 176 | 177 | The vendor spice models found in models_source are copyrighted by the 178 | respective vendors. More information on licensing can be found in 179 | each file. 180 | 181 | As far as I know I am following all the license requirements for 182 | distributing these files. If I have inadvertly failed to do so and 183 | you want me to remove a file, please send me a mail at 184 | and I will do so promptly. 185 | -------------------------------------------------------------------------------- /examples/butterworth/LMH6624.MOD: -------------------------------------------------------------------------------- 1 | *////////////////////////////////////////////////////////////////////// 2 | * (C) National Semiconductor, Corporation. 3 | * Models developed and under copyright by: 4 | * National Semiconductor, Corporation. 5 | *///////////////////////////////////////////////////////////////////// 6 | * Legal Notice: 7 | * The model may be copied, and distributed without any modifications; 8 | * however, reselling or licensing the material is illegal. 9 | * We reserve the right to make changes to the model without prior notice. 10 | * Pspice Models are provided "AS IS, WITH NO WARRANTY OF ANY KIND" 11 | *//////////////////////////////////////////////////////////////////// 12 | * For more information, and our latest models, 13 | * please visit the models section of our website at 14 | * http://www.national.com/models/ 15 | *//////////////////////////////////////////////////////////////////// 16 | * BEGIN MODEL LMH6624 17 | * PINOUT ORDER +IN -IN +V -V OUT 18 | * PINOUT ORDER 1 2 3 4 5 19 | .SUBCKT LMH6624 1 2 3 4 5 20 | * BEGIN MODEL PROGRAMMING 21 | * R40 SETS SLEW FOR +- 6.0 VOLT OPERATION 22 | R40 39 31 164 23 | * R40 SETS SLEW FOR +- 2.5 VOLT OPERATION 24 | *R40 39 31 183 25 | * TO PROGRAM FOR OTHER TOTAL SUPPLY VOLTAGES, 26 | * PROPORTION THE VALUE OF R40 BETWEEN THE 27 | * VALUES ABOVE 28 | * END MODEL PROGRAMMING 29 | Q17 4 6 7 QOP 30 | Q21 3 8 7 QON 31 | D5 5 3 DD 32 | D6 4 5 DD 33 | D7 9 0 DIN 34 | D8 10 0 DIN 35 | I8 0 9 0.1E-3 36 | I9 0 10 0.1E-3 37 | E2 11 0 4 0 1 38 | E3 12 0 3 0 1 39 | D9 13 0 DVN 40 | D10 14 0 DVN 41 | I10 0 13 2E-3 42 | I11 0 14 2E-3 43 | E4 15 2 13 14 0.4 44 | G2 1 15 9 10 1.05E-4 45 | R22 4 3 11.67E3 46 | E5 16 0 12 0 1 47 | E6 17 0 11 0 1 48 | E7 18 0 19 0 1 49 | R30 16 20 1E5 50 | R31 17 21 1E5 51 | R32 18 22 1E5 52 | R33 0 20 10 53 | R34 0 21 10 54 | R35 0 22 10 55 | E10 23 1 22 0 0.5 56 | R36 24 19 1E3 57 | R37 19 25 1E3 58 | C6 16 20 100E-12 59 | C7 17 21 2E-12 60 | C8 18 22 0.7E-12 61 | E11 26 23 21 0 0.095 62 | E12 27 26 20 0 0.02 63 | Q22 11 28 8 QDP 64 | Q23 12 28 6 QDN 65 | I12 3 4 10.37E-3 66 | I13 12 8 0.6E-3 67 | I14 6 11 0.6E-3 68 | R38 0 29 10 69 | R39 0 28 10 70 | C9 29 0 36E-12 71 | C10 28 0 12E-12 72 | E15 30 31 32 0 1 73 | E16 31 33 32 0 1 74 | E17 34 0 31 0 1 75 | D11 35 12 DD 76 | D12 11 36 DD 77 | V11 33 36 1.397 78 | V12 35 30 1.417 79 | I15 0 37 1E-3 80 | D13 37 0 DD 81 | V13 32 37 -0.6551 82 | C11 31 0 8.5E-12 83 | D14 38 39 DD 84 | D15 39 40 DD 85 | R41 0 39 225E3 86 | C12 15 0 1.8E-12 87 | C13 27 0 1.8E-12 88 | R43 7 41 3.5 89 | G3 29 0 31 0 0.1 90 | G4 28 0 29 0 0.1 91 | L1 41 5 4E-9 92 | R45 41 5 100 93 | E20 38 34 32 0 1 94 | E21 40 34 32 0 -1 95 | C15 15 27 2E-12 96 | G5 39 0 42 43 -7.5E-3 97 | R49 44 45 0.1 98 | R50 44 46 0.1 99 | I16 12 47 2E-3 100 | R51 42 48 333 101 | R52 43 48 333 102 | V14 44 49 0.65 103 | V15 12 48 -0.2 104 | C17 42 43 0.2E-12 105 | D18 50 51 DIC 106 | D19 27 51 DIC 107 | E25 25 0 1 0 1 108 | E26 24 0 15 0 1 109 | C18 5 0 0.1E-12 110 | R58 31 30 1E9 111 | R59 33 31 1E9 112 | R60 2 15 1E9 113 | R61 1 23 1E9 114 | R62 23 26 1E9 115 | R63 26 27 1E9 116 | V16 15 50 0.04E-3 117 | R64 34 40 1E9 118 | R65 34 38 1E9 119 | Q28 42 50 45 QIN 120 | Q29 43 27 46 QIN 121 | Q30 49 47 11 QIN 122 | Q31 47 47 11 QIN 123 | D20 11 50 DIC 124 | D21 11 27 DIC 125 | V17 12 51 1.0 126 | RN1 32 0 1E9 127 | .MODEL DD D 128 | .MODEL DVN D KF=1E-14 129 | .MODEL DIN D KF=26E-14 130 | .MODEL DIC D RS=50 131 | .MODEL QDP PNP 132 | .MODEL QDN NPN 133 | .MODEL QON NPN VAF=150 BF=250 IKF=1 RE=1 RC=9 134 | .MODEL QOP PNP VAF=150 BF=250 IKF=1 RE=1 RC=9 135 | .MODEL QIN NPN VAF=150 BF=90 IKF=0.005 RE=1 RC=1 136 | .ENDS 137 | * END MODEL LMH6624 138 | -------------------------------------------------------------------------------- /examples/butterworth/LMH6624.txt: -------------------------------------------------------------------------------- 1 | LMH6624 SPICE MODEL PERFORMANCE 2 | 3 | THIS FILE BEST VIEWED WITH WINDOWS NOTEPAD. 4 | 5 | MODEL FEATURES INCLUDE OUTPUT SWING, OUTPUT CURRENT THRU 6 | THE SUPPLY RAILS, GAIN AND PHASE, SLEW RATE, SLEW RATE 7 | VARIATION WITH GAIN, BODE PLOT VARIATION WITH TEMPER- 8 | ATURE, HIGH CLOAD DRIVE TO 33 PF, COMMON MODE REJECTION, 9 | POWER SUPPLY REJECTION ON BOTH RAILS, INPUT VOLTAGE 10 | NOISE WITH 1/F, INPUT CURRENT NOISE WITH 1/F, OUPUT 11 | IMPEDANCE, INPUT CAPACITANCE, INPUT BIAS CURRENT, 12 | INPUT COMMON MODE RANGE, INPUT OFFSET, INPUT CLAMPS 13 | TO THE RAIL, OUTPUT CLAMPS TO THE RAIL, AND QUIESCENT 14 | SUPPLY CURRENT. 15 | 16 | MODEL TEMP RANGE IS -40 TO +125 DEG C. 17 | 18 | NOTE THAT MODEL IS FUNCTIONAL OVER THIS RANGE BUT NOT ALL 19 | PARAMETERS TRACK THOSE OF THE REAL PART. 20 | 21 | SPEC MACRO DATA 22 | MODEL SHEET 23 | 24 | AVOL @ DC 82 82 DB 25 | 26 | AVOL/PHSE @ 1 MHZ 61/-84 62/-80 DB/DEG 27 | 28 | AVOL/PHSE @ 10 MHZ 41/-92 42/-92 DB/DEG 29 | 30 | AVOL/PHSE @ 100 MHZ 21/-113 22/-115 DB/DEG 31 | 32 | AVOL/PHSE @ 200 MHZ 14/-135 13/-139 DB/DEG 33 | 34 | 35 | INPUT V NOISE 10 HZ 10.4 11.0 NV/RHZ 36 | INPUT V NOISE 1 KHZ 1.4 1.3 NV/RHZ 37 | INPUT V NOISE 100 KHZ 0.9 0.9 NV/RHZ 38 | 39 | INPUT I NOISE 10 HZ 62 60 PA/RHZ 40 | INPUT I NOISE 1 KHZ 6.5 6.7 PA/RHZ 41 | INPUT I NOISE 100 KHZ 2.1 2.1 PA/RHZ 42 | 43 | 44 | SLEW RATE @ V= +- 6 398 400 V/US 45 | AND AVCL = +10 46 | 47 | SLEW RATE @ V= +-2.5 360 360 V/US 48 | AND AVCL = +10 49 | 50 | SLEW RATE @ V= +- 6 347 350 V/US 51 | AND AVCL = +20 52 | 53 | SLEW RATE @ V= +-2.5 308 300 V/US 54 | AND AVCL = +20 55 | 56 | 57 | RF=500: 58 | 59 | BANDWIDTH @ AVCL= +10 209 200 MHZ 60 | PEAKING @ AVCL= +10 0.4 0.8 DB 61 | 62 | BANDWIDTH @ AVCL= +20 79 100 MHZ 63 | 64 | BANDWIDTH @ AVCL= +30 46 57 MHZ 65 | 66 | BANDWIDTH @ AVCL=+200 5.8 6 MHZ 67 | 68 | 69 | AVCL=+10: 70 | 71 | PEAKING @ RF = 511 0.4 0.4 DB 72 | 73 | PEAKING @ RF = 750 1.0 0.9 DB 74 | 75 | PEAKING @ RF = 1000 1.5 2.0 DB 76 | 77 | PEAKING @ RF = 1500 2.5 2.5 DB 78 | 79 | PEAKING @ RF = 2000 3.3 2.8 DB 80 | 81 | 82 | CLOAD: 83 | 84 | PEAKING @ CL= 0 PF 0.6 1.0 DB 85 | 86 | PEAKING @ CL= 15 PF 2.5 2.0 DB 87 | 88 | PEAKING @ CL= 33 PF 3.1 3.0 DB 89 | 90 | 91 | INPUT BIAS CURRENT 12.6 13 UA 92 | 93 | VOS 0.1 0.1 MV 94 | 95 | SWING AT RL=100 OHM +-4.9 +-4.9 V 96 | 97 | SWING AT IO=100 MA +-4.3 +-4.3 V 98 | 99 | IOUT MAX 140 150 MA 100 | 101 | IQ @ +- 6.0V 12.0 12.0 MA 102 | 103 | IQ @ +- 2.5V 11.4 11.4 MA 104 | 105 | CMRR , F ZERO 80,1 80,1 DB,MHZ 106 | 107 | PSRRP , F ZERO 92,30 94,30 DB,KHZ 108 | 109 | PSRRN , F ZERO 86,300 86,300 DB,KHZ 110 | -------------------------------------------------------------------------------- /examples/butterworth/butterworth-cache.lib: -------------------------------------------------------------------------------- 1 | EESchema-LIBRARY Version 2.4 2 | #encoding utf-8 3 | # 4 | # Amplifier_Operational_AD8603 5 | # 6 | DEF Amplifier_Operational_AD8603 U 0 5 Y Y 1 F N 7 | F0 "U" 0 200 50 H V L CNN 8 | F1 "Amplifier_Operational_AD8603" 0 -200 50 H V L CNN 9 | F2 "Package_TO_SOT_SMD:TSOT-23-5" 0 0 50 H I C CNN 10 | F3 "" 0 200 50 H I C CNN 11 | $FPLIST 12 | TSOT*23* 13 | $ENDFPLIST 14 | DRAW 15 | P 4 0 1 10 -200 200 200 0 -200 -200 -200 200 f 16 | X V- 2 -100 -300 150 U 50 50 0 1 W 17 | X V+ 5 -100 300 150 D 50 50 0 1 W 18 | X ~ 1 300 0 100 L 50 50 1 1 O 19 | X + 3 -300 100 100 R 50 50 1 1 I 20 | X - 4 -300 -100 100 R 50 50 1 1 I 21 | ENDDRAW 22 | ENDDEF 23 | # 24 | # Device_C 25 | # 26 | DEF Device_C C 0 10 N Y 1 F N 27 | F0 "C" 25 100 50 H V L CNN 28 | F1 "Device_C" 25 -100 50 H V L CNN 29 | F2 "" 38 -150 50 H I C CNN 30 | F3 "" 0 0 50 H I C CNN 31 | $FPLIST 32 | C_* 33 | $ENDFPLIST 34 | DRAW 35 | P 2 0 1 20 -80 -30 80 -30 N 36 | P 2 0 1 20 -80 30 80 30 N 37 | X ~ 1 0 150 110 D 50 50 1 1 P 38 | X ~ 2 0 -150 110 U 50 50 1 1 P 39 | ENDDRAW 40 | ENDDEF 41 | # 42 | # Device_R 43 | # 44 | DEF Device_R R 0 0 N Y 1 F N 45 | F0 "R" 80 0 50 V V C CNN 46 | F1 "Device_R" 0 0 50 V V C CNN 47 | F2 "" -70 0 50 V I C CNN 48 | F3 "" 0 0 50 H I C CNN 49 | $FPLIST 50 | R_* 51 | $ENDFPLIST 52 | DRAW 53 | S -40 -100 40 100 0 1 10 N 54 | X ~ 1 0 150 50 D 50 50 1 1 P 55 | X ~ 2 0 -150 50 U 50 50 1 1 P 56 | ENDDRAW 57 | ENDDEF 58 | # 59 | # power_+2V5 60 | # 61 | DEF power_+2V5 #PWR 0 0 Y Y 1 F P 62 | F0 "#PWR" 0 -150 50 H I C CNN 63 | F1 "power_+2V5" 0 140 50 H V C CNN 64 | F2 "" 0 0 50 H I C CNN 65 | F3 "" 0 0 50 H I C CNN 66 | DRAW 67 | P 2 0 1 0 -30 50 0 100 N 68 | P 2 0 1 0 0 0 0 100 N 69 | P 2 0 1 0 0 100 30 50 N 70 | X +2V5 1 0 0 0 U 50 50 1 1 W N 71 | ENDDRAW 72 | ENDDEF 73 | # 74 | # power_-2V5 75 | # 76 | DEF power_-2V5 #PWR 0 0 Y Y 1 F P 77 | F0 "#PWR" 0 100 50 H I C CNN 78 | F1 "power_-2V5" 0 150 50 H V C CNN 79 | F2 "" 0 0 50 H I C CNN 80 | F3 "" 0 0 50 H I C CNN 81 | DRAW 82 | P 6 0 1 0 0 0 0 50 30 50 0 100 -30 50 0 50 F 83 | X -2V5 1 0 0 0 U 50 50 0 0 W N 84 | ENDDRAW 85 | ENDDEF 86 | # 87 | # power_GND 88 | # 89 | DEF power_GND #PWR 0 0 Y Y 1 F P 90 | F0 "#PWR" 0 -250 50 H I C CNN 91 | F1 "power_GND" 0 -150 50 H V C CNN 92 | F2 "" 0 0 50 H I C CNN 93 | F3 "" 0 0 50 H I C CNN 94 | DRAW 95 | P 6 0 1 0 0 0 0 -50 50 -50 0 -100 -50 -50 0 -50 N 96 | X GND 1 0 0 0 D 50 50 1 1 W N 97 | ENDDRAW 98 | ENDDEF 99 | # 100 | # pspice_VSOURCE 101 | # 102 | DEF pspice_VSOURCE V 0 40 Y Y 1 F N 103 | F0 "V" -250 300 50 H V C CNN 104 | F1 "pspice_VSOURCE" 0 0 50 H V C CNN 105 | F2 "" 0 0 50 H I C CNN 106 | F3 "" 0 0 50 H I C CNN 107 | DRAW 108 | C 0 0 200 0 1 0 N 109 | T 0 -320 -10 50 0 0 1 V Normal 0 C C 110 | P 2 0 1 0 -250 -250 -250 150 F 111 | P 3 0 1 0 -300 150 -250 250 -200 150 F 112 | X E1 1 0 300 100 D 50 50 1 1 I 113 | X E2 2 0 -300 100 U 50 50 1 1 I 114 | ENDDRAW 115 | ENDDEF 116 | # 117 | #End Library 118 | -------------------------------------------------------------------------------- /examples/butterworth/butterworth-opamp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wingel/simulation/6231113fb981a483c71455fd9a0c6dea2efb7115/examples/butterworth/butterworth-opamp.png -------------------------------------------------------------------------------- /examples/butterworth/butterworth.kicad_pcb: -------------------------------------------------------------------------------- 1 | (kicad_pcb (version 4) (host kicad "dummy file") ) 2 | -------------------------------------------------------------------------------- /examples/butterworth/butterworth.md: -------------------------------------------------------------------------------- 1 | 2 | # Simulating KiCad schematics with Ngspice 3 | This project is a small set of Python modules to simulate KiCad schematics using Ngspice. 4 | 5 | Design a schematic as usual in KiCad using KiCad's normal R, C, L and spice simulation components. Load the schematic and use Ngspice to do AC, DC, transient or noise simulations and get the results back as numpy arrays. You can then perform calculations or plot the arrays using any tool you'd like. In this demo I'm using matplotlib. 6 | 7 | There's one more good reason to use matplotlib: one of these modules can render the KiCad schematic to a matplotlib plot which is rather nice if you want to show the schematic in a Jupyter notebook like this. 8 | 9 | If you are looking at the read only copy of this notebook you can find the actual [Jupyter 10 | Notebook here](butterworth.ipynb). 11 | 12 | ### Basic stuff 13 | 14 | 15 | ```python 16 | # Just the normal prequisites for using matplotlib and numpy in a Jupyter notebook 17 | %matplotlib inline 18 | # Use the svg backend, in my opinion it just makes better looking plots 19 | %config InlineBackend.figure_format = 'svg' 20 | import matplotlib.pyplot as plt 21 | import numpy as np 22 | # The spice and kicad modules are located above us 23 | import sys 24 | sys.path.append('../..') 25 | from imp import reload 26 | ``` 27 | 28 | ### Load a kicad schematic 29 | 30 | 31 | ```python 32 | from kicad import schema 33 | fn = 'butterworth.sch' 34 | sch = schema.Sch(fn) 35 | ``` 36 | 37 | ### Render the kicad schematic in a matplotlib plot 38 | Yes, using matplotlib as a drawing backend is a bit ugly, but it works and it means that we can display it using every backend supported by matplotlib, such as in a Jupyter notebook. And having the schematic available directly in the notebook when working with it is rather nice. 39 | 40 | 41 | ```python 42 | from kicad import matplotlib_renderer 43 | reload(matplotlib_renderer) 44 | fig, ax = plt.subplots(figsize = (8, 6)) 45 | # Add a bit of margin since matplotlib chops off the text otherwise 46 | ax.set_xmargin(0.1) 47 | ax.set_ymargin(0.1) 48 | matplotlib_renderer.render_to_ax(ax, sch) 49 | plt.show() 50 | ``` 51 | 52 | ... or save the figure in any file format supported by matplotlib. 53 | 54 | 55 | ```python 56 | # Make the plot fill the whole image 57 | fig.subplots_adjust(left = 0, right = 1.0, top = 1.0, bottom = 0.0) 58 | fig.savefig('butterworth.png') 59 | fig.savefig('butterworth.svg') 60 | fig.savefig('butterworth.pdf') 61 | ``` 62 | 63 | You can check out the resulting [PNG](./butterworth.png), [SVG](./butterworth.svg), and [PDF](./butterworth.pdf) files here. 64 | 65 | Also note that the "plt.show()" command at the end really isn't needed in a Jupyter notebook, but if you want to try this directly in Python you will need it. 66 | 67 | The schematic contains R and C symbols from the Device library and the component values are extracted from the normal value field. 68 | 69 | The power symbols have names of the form "+iVf" or "-iVf" where i is the integer part and f is the fractional part of the voltage; e.g. "-2V5" will add a -2.5V DC voltage supply between the symbol and ground. 70 | 71 | Symbols from the Spice library ought to work, but I have only tested the voltage and current sources. 72 | 73 | It should be possible to annotate any other symbols with Spice models and make them work too. For an example on how to do this, look at how the [OP-amp in the butterworth schematic has been set up](./butterworth-opamp.png). 74 | 75 | ### Convert the kicad schematic to a spice circuit 76 | 77 | 78 | ```python 79 | from kicad import spice_converter 80 | reload(spice_converter) 81 | circuit = spice_converter.sch_to_circuit(sch) 82 | ``` 83 | 84 | ### Set up the Ngspice simulator 85 | 86 | 87 | ```python 88 | from spice import ngspice, xyce, ltspice 89 | reload(ngspice) 90 | reload(xyce) 91 | reload(ltspice) 92 | sim = ngspice.Simulator() 93 | # sim = xyce.Simulator() 94 | # sim = ltspice.Simulator() 95 | 96 | # Print the Ngspice circuit 97 | print(sim.circuit_to_spice(circuit).strip()) 98 | ``` 99 | 100 | ### Perform a DC simulation and plot it 101 | 102 | 103 | ```python 104 | # Import some convenient SI prefixes and a decibel converter 105 | from spice.unit import M, k, m, u, n, p, dBa 106 | 107 | # Run the DC simulation 108 | dc_data = sim.dc(circuit, 'V101', -2, 2, 1 * m) 109 | 110 | # Plot the results 111 | plt.plot(dc_data['SWEEP'], dc_data['V(VOUT)']); 112 | 113 | # Show the plot 114 | plt.show() 115 | ``` 116 | 117 | We can see that vout is limited by the supply voltage to the OP-amp. 118 | 119 | ### Perform multiple AC simulations varying the capacitor values 120 | 121 | 122 | ```python 123 | # The capacitor names and values we want to use 124 | cap_refs = [ 'C101', 'C102', 'C103' ] 125 | cap_values = [ 35 * n, 350 * n, 3500 * n ] 126 | 127 | # Run the simulations and save the results in ac_data 128 | ac_data = [] 129 | for v in cap_values: 130 | for ref in cap_refs: 131 | circuit[ref].value = v 132 | ac_data.append((v, sim.ac(circuit, 'dec', 10, 1, 100 * k))) 133 | 134 | # Show all the results from ac_data in one plot 135 | for v, data in ac_data: 136 | # The Y values are converted to dB 137 | plt.plot(data['SWEEP'].real, dBa(data['V(VOUT)']), label = str(v)) 138 | 139 | # Change the X axis scale to logarithmic 140 | plt.xscale('log') 141 | 142 | # Add a legend and labels for the axes 143 | plt.legend() 144 | plt.xlabel("Frequency (Hz)") 145 | plt.ylabel("VOUT (dBV)") 146 | 147 | # Show the plot 148 | plt.show() 149 | ``` 150 | 151 | ### Do transient simulations 152 | 153 | 154 | ```python 155 | # Run simulations with all the values 156 | tran_data = [] 157 | for v in cap_values: 158 | for ref in cap_refs: 159 | circuit[ref].value = v 160 | tran_data.append((v, sim.tran(circuit, 100 * u, 50 * m))) 161 | 162 | # Plot the results 163 | for v, data in tran_data: 164 | plt.plot(data['TIME'].real, data['V(VOUT)'], label = str(v)) 165 | 166 | # Plot vin for the last simulation so that we can see the stimuli 167 | plt.plot(data['TIME'].real, data['V(VIN)'], label = "VIN", color = 'black') 168 | 169 | # Add a legend and labels for the axes 170 | plt.legend() 171 | plt.xlabel("Time (s)") 172 | plt.ylabel("VOUT (dbV)"); 173 | 174 | # Show the plot 175 | plt.show() 176 | ``` 177 | 178 | ### Pretty figures 179 | Matplotlib can have multiple subplots in one figure. Which can make for some rather nice "datasheet"-like figures. 180 | 181 | 182 | 183 | ```python 184 | fig = plt.figure(figsize = (8, 6)) 185 | 186 | ax = fig.add_subplot(2, 2, 1) 187 | ax.set_title("Schematic used for simulation") 188 | ax.set_xmargin(0.1) 189 | ax.set_ymargin(0.1) 190 | matplotlib_renderer.render_to_ax(ax, sch) 191 | 192 | ax = fig.add_subplot(2, 2, 2) 193 | ax.set_title("DC Simulation") 194 | ax.plot(dc_data['SWEEP'], dc_data['V(VOUT)']) 195 | plt.xlabel("Frequency (Hz)") 196 | plt.ylabel("VOUT (V)") 197 | 198 | ax = fig.add_subplot(2, 2, 3) 199 | for v, data in ac_data: 200 | ax.plot(data['SWEEP'].real, dBa(data['V(VOUT)']), label = str(v)) 201 | ax.set_xscale('log') 202 | ax.set_title("AC Simulation") 203 | ax.legend() 204 | plt.xlabel("Frequency (Hz)") 205 | plt.ylabel("VOUT (dBV)") 206 | 207 | ax = fig.add_subplot(2, 2, 4) 208 | for v, data in tran_data: 209 | ax.plot(data['TIME'].real, data['V(VOUT)'], label = str(v)) 210 | ax.plot(data['TIME'].real, data['V(VIN)'], label = "VIN", color = 'black') 211 | ax.set_title("Transient Simulation") 212 | ax.legend() 213 | plt.xlabel("Time (s)") 214 | plt.ylabel("VOUT (V)") 215 | 216 | # Stop the figures from overlapping 217 | fig.tight_layout() 218 | 219 | # Show the plot 220 | plt.show() 221 | ``` 222 | -------------------------------------------------------------------------------- /examples/butterworth/butterworth.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wingel/simulation/6231113fb981a483c71455fd9a0c6dea2efb7115/examples/butterworth/butterworth.pdf -------------------------------------------------------------------------------- /examples/butterworth/butterworth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wingel/simulation/6231113fb981a483c71455fd9a0c6dea2efb7115/examples/butterworth/butterworth.png -------------------------------------------------------------------------------- /examples/butterworth/butterworth.pro: -------------------------------------------------------------------------------- 1 | update=22/05/2015 07:44:53 2 | version=1 3 | last_client=kicad 4 | [general] 5 | version=1 6 | RootSch= 7 | BoardNm= 8 | [pcbnew] 9 | version=1 10 | LastNetListRead= 11 | UseCmpFile=1 12 | PadDrill=0.600000000000 13 | PadDrillOvalY=0.600000000000 14 | PadSizeH=1.500000000000 15 | PadSizeV=1.500000000000 16 | PcbTextSizeV=1.500000000000 17 | PcbTextSizeH=1.500000000000 18 | PcbTextThickness=0.300000000000 19 | ModuleTextSizeV=1.000000000000 20 | ModuleTextSizeH=1.000000000000 21 | ModuleTextSizeThickness=0.150000000000 22 | SolderMaskClearance=0.000000000000 23 | SolderMaskMinWidth=0.000000000000 24 | DrawSegmentWidth=0.200000000000 25 | BoardOutlineThickness=0.100000000000 26 | ModuleOutlineThickness=0.150000000000 27 | [cvpcb] 28 | version=1 29 | NetIExt=net 30 | [eeschema] 31 | version=1 32 | LibDir= 33 | [eeschema/libraries] 34 | -------------------------------------------------------------------------------- /examples/butterworth/butterworth.sch: -------------------------------------------------------------------------------- 1 | EESchema Schematic File Version 4 2 | LIBS:butterworth-cache 3 | EELAYER 26 0 4 | EELAYER END 5 | $Descr A4 11693 8268 6 | encoding utf-8 7 | Sheet 1 1 8 | Title "" 9 | Date "" 10 | Rev "" 11 | Comp "" 12 | Comment1 "" 13 | Comment2 "" 14 | Comment3 "" 15 | Comment4 "" 16 | $EndDescr 17 | $Comp 18 | L Device:R R105 19 | U 1 1 5B70B1CC 20 | P 6750 3800 21 | F 0 "R105" V 6957 3800 50 0000 C CNN 22 | F 1 "10k" V 6866 3800 50 0000 C CNN 23 | F 2 "" V 6680 3800 50 0001 C CNN 24 | F 3 "~" H 6750 3800 50 0001 C CNN 25 | 1 6750 3800 26 | 0 -1 -1 0 27 | $EndComp 28 | $Comp 29 | L Device:R R103 30 | U 1 1 5B70B22E 31 | P 5500 4850 32 | F 0 "R103" H 5570 4896 50 0000 L CNN 33 | F 1 "1k" H 5570 4805 50 0000 L CNN 34 | F 2 "" V 5430 4850 50 0001 C CNN 35 | F 3 "~" H 5500 4850 50 0001 C CNN 36 | 1 5500 4850 37 | 1 0 0 -1 38 | $EndComp 39 | $Comp 40 | L Device:R R104 41 | U 1 1 5B70B3AC 42 | P 5950 4600 43 | F 0 "R104" V 6157 4600 50 0000 C CNN 44 | F 1 "1k" V 6066 4600 50 0000 C CNN 45 | F 2 "" V 5880 4600 50 0001 C CNN 46 | F 3 "~" H 5950 4600 50 0001 C CNN 47 | 1 5950 4600 48 | 0 -1 -1 0 49 | $EndComp 50 | Wire Wire Line 51 | 6100 4600 6400 4600 52 | Wire Wire Line 53 | 6400 4600 6400 3800 54 | Wire Wire Line 55 | 6400 3800 6200 3800 56 | Connection ~ 6400 3800 57 | Wire Wire Line 58 | 6600 3800 6400 3800 59 | Wire Wire Line 60 | 5800 4600 5500 4600 61 | Wire Wire Line 62 | 5500 4600 5500 3900 63 | Wire Wire Line 64 | 5500 3900 5600 3900 65 | Wire Wire Line 66 | 5500 4700 5500 4600 67 | Connection ~ 5500 4600 68 | $Comp 69 | L power:GND #PWR0101 70 | U 1 1 5B70B5B2 71 | P 5500 5200 72 | F 0 "#PWR0101" H 5500 4950 50 0001 C CNN 73 | F 1 "GND" H 5505 5027 50 0000 C CNN 74 | F 2 "" H 5500 5200 50 0001 C CNN 75 | F 3 "" H 5500 5200 50 0001 C CNN 76 | 1 5500 5200 77 | 1 0 0 -1 78 | $EndComp 79 | $Comp 80 | L Device:R R102 81 | U 1 1 5B70B6AD 82 | P 4750 3700 83 | F 0 "R102" V 4957 3700 50 0000 C CNN 84 | F 1 "10k" V 4866 3700 50 0000 C CNN 85 | F 2 "" V 4680 3700 50 0001 C CNN 86 | F 3 "~" H 4750 3700 50 0001 C CNN 87 | 1 4750 3700 88 | 0 -1 -1 0 89 | $EndComp 90 | $Comp 91 | L Device:R R101 92 | U 1 1 5B70B71B 93 | P 4250 3700 94 | F 0 "R101" V 4043 3700 50 0000 C CNN 95 | F 1 "10k" V 4134 3700 50 0000 C CNN 96 | F 2 "" V 4180 3700 50 0001 C CNN 97 | F 3 "~" H 4250 3700 50 0001 C CNN 98 | 1 4250 3700 99 | 0 1 1 0 100 | $EndComp 101 | Wire Wire Line 102 | 4900 3700 5000 3700 103 | Wire Wire Line 104 | 4600 3700 4500 3700 105 | Text GLabel 7300 3800 2 50 Output ~ 0 106 | VOUT 107 | Wire Wire Line 108 | 7300 3800 7100 3800 109 | $Comp 110 | L Device:C C102 111 | U 1 1 5B70BACC 112 | P 5950 3100 113 | F 0 "C102" V 5698 3100 50 0000 C CNN 114 | F 1 "352n" V 5789 3100 50 0000 C CNN 115 | F 2 "" H 5988 2950 50 0001 C CNN 116 | F 3 "~" H 5950 3100 50 0001 C CNN 117 | 1 5950 3100 118 | 0 1 1 0 119 | $EndComp 120 | Wire Wire Line 121 | 6100 3100 6400 3100 122 | Wire Wire Line 123 | 6400 3100 6400 3800 124 | Wire Wire Line 125 | 4500 3100 4500 3700 126 | Connection ~ 4500 3700 127 | Wire Wire Line 128 | 4500 3700 4400 3700 129 | $Comp 130 | L Device:C C101 131 | U 1 1 5B70BDE6 132 | P 5000 4550 133 | F 0 "C101" H 5115 4596 50 0000 L CNN 134 | F 1 "352n" H 5115 4505 50 0000 L CNN 135 | F 2 "" H 5038 4400 50 0001 C CNN 136 | F 3 "~" H 5000 4550 50 0001 C CNN 137 | 1 5000 4550 138 | 1 0 0 -1 139 | $EndComp 140 | Wire Wire Line 141 | 5000 4400 5000 3700 142 | Wire Wire Line 143 | 5000 3700 5600 3700 144 | Wire Wire Line 145 | 5000 4700 5000 5100 146 | Wire Wire Line 147 | 5000 5100 5500 5100 148 | Connection ~ 5500 5100 149 | Wire Wire Line 150 | 5500 5100 5500 5000 151 | $Comp 152 | L Device:C C103 153 | U 1 1 5B70C301 154 | P 7100 4550 155 | F 0 "C103" H 7215 4596 50 0000 L CNN 156 | F 1 "352n" H 7215 4505 50 0000 L CNN 157 | F 2 "" H 7138 4400 50 0001 C CNN 158 | F 3 "~" H 7100 4550 50 0001 C CNN 159 | 1 7100 4550 160 | 1 0 0 -1 161 | $EndComp 162 | Wire Wire Line 163 | 7100 4400 7100 3800 164 | Connection ~ 7100 3800 165 | Wire Wire Line 166 | 7100 3800 6900 3800 167 | Wire Wire Line 168 | 7100 4700 7100 5100 169 | Wire Wire Line 170 | 7100 5100 5500 5100 171 | Wire Wire Line 172 | 5500 5200 5500 5100 173 | Wire Wire Line 174 | 4500 3100 5800 3100 175 | Connection ~ 5000 3700 176 | $Comp 177 | L power:+2V5 #PWR0102 178 | U 1 1 5B70F2A1 179 | P 5800 3500 180 | F 0 "#PWR0102" H 5800 3350 50 0001 C CNN 181 | F 1 "+2V5" H 5815 3673 50 0000 C CNN 182 | F 2 "" H 5800 3500 50 0001 C CNN 183 | F 3 "" H 5800 3500 50 0001 C CNN 184 | 1 5800 3500 185 | 1 0 0 -1 186 | $EndComp 187 | $Comp 188 | L power:-2V5 #PWR0103 189 | U 1 1 5B70F347 190 | P 5800 4100 191 | F 0 "#PWR0103" H 5800 4200 50 0001 C CNN 192 | F 1 "-2V5" H 5815 4273 50 0000 C CNN 193 | F 2 "" H 5800 4100 50 0001 C CNN 194 | F 3 "" H 5800 4100 50 0001 C CNN 195 | 1 5800 4100 196 | -1 0 0 1 197 | $EndComp 198 | $Comp 199 | L pspice:VSOURCE V101 200 | U 1 1 5B747B28 201 | P 3800 4400 202 | F 0 "V101" H 4028 4446 50 0000 L CNN 203 | F 1 "VSOURCE" H 4028 4355 50 0000 L CNN 204 | F 2 "" H 3800 4400 50 0001 C CNN 205 | F 3 "" H 3800 4400 50 0001 C CNN 206 | F 4 "V" H 3800 4400 50 0001 C CNN "Spice_Primitive" 207 | F 5 "dc 0 ac 1 pulse(0 1 1m 1m 1m 17m 50m)" H 3800 4400 50 0001 C CNN "Spice_Model" 208 | F 6 "Y" H 3800 4400 50 0001 C CNN "Spice_Netlist_Enabled" 209 | 1 3800 4400 210 | 1 0 0 -1 211 | $EndComp 212 | Wire Wire Line 213 | 3800 3700 3800 4100 214 | Wire Wire Line 215 | 3800 3700 4100 3700 216 | Wire Wire Line 217 | 3800 4700 3800 5100 218 | Wire Wire Line 219 | 3800 5100 5000 5100 220 | Connection ~ 5000 5100 221 | Text Label 3800 3700 0 50 ~ 0 222 | VIN 223 | $Comp 224 | L Amplifier_Operational:AD8603 U101 225 | U 1 1 5B861DA4 226 | P 5900 3800 227 | F 0 "U101" H 6000 4100 50 0000 L CNN 228 | F 1 "LMH6624" H 6000 4000 50 0000 L CNN 229 | F 2 "Package_TO_SOT_SMD:TSOT-23-5" H 5900 3800 50 0001 C CNN 230 | F 3 "http://www.analog.com/media/en/technical-documentation/data-sheets/AD8603_8607_8609.pdf" H 5900 4000 50 0001 C CNN 231 | F 4 "X" H 5900 3800 50 0001 C CNN "Spice_Primitive" 232 | F 5 "LMH6624" H 5900 3800 50 0001 C CNN "Spice_Model" 233 | F 6 "Y" H 5900 3800 50 0001 C CNN "Spice_Netlist_Enabled" 234 | F 7 "3 4 5 2 1" H 5900 3800 50 0001 C CNN "Spice_Node_Sequence" 235 | F 8 "LMH6624.MOD" H 5900 3800 50 0001 C CNN "Spice_Lib_File" 236 | 1 5900 3800 237 | 1 0 0 -1 238 | $EndComp 239 | $EndSCHEMATC 240 | -------------------------------------------------------------------------------- /kicad/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | -------------------------------------------------------------------------------- /kicad/matplotlib_renderer.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import math 5 | import numpy as np 6 | 7 | from matplotlib.collections import LineCollection 8 | from matplotlib.collections import EllipseCollection 9 | from matplotlib.collections import PathCollection 10 | from matplotlib.path import Path 11 | 12 | from . import schema 13 | 14 | PIN_ORIENTATION = { 15 | 'L': np.array((-1, 0)), 16 | 'R': np.array(( 1, 0)), 17 | 'U': np.array(( 0, 1)), 18 | 'D': np.array(( 0, -1)), 19 | } 20 | 21 | TEXT_ORIENTATION = { 22 | 0: np.array(( 1, 0)), 23 | 1: np.array(( 0, 1)), 24 | 2: np.array((-1, 0)), 25 | 3: np.array(( 0, -1)), 26 | } 27 | 28 | COMP_ORIENTATION = { 29 | # Not mirrored 30 | ( 1, 0, 0, -1 ): np.array(( ( 1, 0), ( 0, -1) )), # 0 deg 31 | ( 0, -1, -1, 0 ): np.array(( ( 0, -1), (-1, 0) )), # 90 deg 32 | ( 1, 0, 0, 1 ): np.array(( ( 1, 0), ( 0, 1) )), # 180 deg 33 | ( 0, 1, 1, 0 ): np.array(( ( 0, 1), ( 1, 0) )), # 270 deg 34 | 35 | # X mirrored 36 | ( 1, 0, 0, 1 ): np.array(( ( 1, 0), ( 0, 1) )), # 0 deg 37 | ( 0, -1, 1, 0 ): np.array(( ( 0, -1), ( 1, 0) )), # 90 deg 38 | ( 1, 0, 0, -1 ): np.array(( ( 1, 0), ( 0, -1) )), # 180 deg 39 | ( 0, 1, -1, 0 ): np.array(( ( 0, 1), ( -1, 0) )), # 270 deg 40 | 41 | # Should not happen 42 | ( -1, 0, 0, -1 ): np.array(( (-1, 0), ( 0, -1) )), 43 | ( -1, 0, 0, 1 ): np.array(( (-1, 0), ( 0, 1) )), 44 | 45 | } 46 | 47 | Y_TRANS = np.array([ 1, -1 ]) 48 | 49 | class PathList(): 50 | def __init__(self): 51 | self.paths = [] 52 | 53 | self.texts = [] 54 | 55 | def path(self, path, linewidth, edgecolor, facecolor): 56 | self.paths.append((path, linewidth, edgecolor, facecolor)) 57 | 58 | def arc(self, offset, radius, start, end, linewidth, edgecolor, facecolor): 59 | verts = [] 60 | codes = [] 61 | 62 | d = end - start 63 | if d > 180: 64 | d -= 360 65 | elif d < -180: 66 | d += 360 67 | d /= 4 68 | while abs(d) > 5: 69 | d /= 2 70 | 71 | a = start 72 | codes.append(Path.MOVETO) 73 | 74 | print("YY", start, end, a) 75 | 76 | while 1: 77 | verts.append((math.cos(a * math.pi / 180), 78 | math.sin(a * math.pi / 180))) 79 | if abs(a - end) < abs(d / 2): 80 | break 81 | a += d 82 | if a > 180: 83 | a -= 360 84 | elif a < -180: 85 | a += 360 86 | print("XX", start, end, a) 87 | codes.append(Path.LINETO) 88 | 89 | verts = np.array(verts) 90 | 91 | print(start, end, verts, codes) 92 | verts = verts * radius + offset 93 | 94 | path = Path(verts, codes) 95 | self.path(path, linewidth, edgecolor, facecolor) 96 | 97 | def circle(self, offset, radius, linewidth, edgecolor, facecolor): 98 | path = Path.circle(offset, radius) 99 | self.path(path, linewidth, edgecolor, facecolor) 100 | 101 | def text(self, offset, normal, text, size, 102 | halign = 'left', valign = 'center', color = 'green'): 103 | self.texts.append((offset, normal, text, size, halign, valign, color)) 104 | 105 | def on_ax(self, ax, pos, orientation): 106 | trans = np.reshape(orientation, (2,2)).T 107 | 108 | for offset, normal, text, size, halign, valign, color in self.texts: 109 | normal = np.matmul(normal, trans) 110 | angle = math.atan2(-normal[1], normal[0]) * 180 / math.pi 111 | 112 | x, y = (pos + np.matmul(offset, trans)) * Y_TRANS 113 | 114 | if angle >= 180 or angle < 0: 115 | if halign == 'right': 116 | halign = 'left' 117 | elif halign == 'left': 118 | halign = 'right' 119 | if valign == 'top': 120 | valign = 'bottom' 121 | elif valign == 'bottom': 122 | valign = 'top' 123 | angle -= 180 124 | 125 | kw = { 'x': x, 126 | 'y': y, 127 | 'color': color, 128 | # 'font': 'sans-serif', 129 | 'fontsize': size, 130 | 's': text, 131 | 'rotation': angle, 132 | 'rotation_mode': 'anchor', 133 | 'horizontalalignment': halign, 134 | 'verticalalignment': valign, 135 | 'clip_on': True, 136 | } 137 | 138 | ax.text(**kw) 139 | 140 | if self.paths: 141 | d = {} 142 | d['paths'] = [] 143 | d['linewidths'] = [] 144 | d['edgecolors'] = [] 145 | d['facecolors'] = [] 146 | 147 | for path, linewidth, edgecolor, facecolor in self.paths: 148 | verts = path.vertices 149 | verts = np.matmul(verts, trans) 150 | verts = (pos + verts) * Y_TRANS 151 | path.vertices = verts 152 | 153 | d['paths'].append(path) 154 | d['linewidths'].append(linewidth) 155 | d['edgecolors'].append(edgecolor) 156 | d['facecolors'].append(facecolor) 157 | 158 | pc = PathCollection(offset_position = 'data', **d) 159 | ax.add_collection(pc) 160 | 161 | # A bit of an ugly hack which scales the line with and font size for 162 | # everything we have drawn on an axis 163 | def scale_ax(ax, scale_factor): 164 | for c in ax.collections: 165 | if isinstance(c, LineCollection): 166 | lw = c.get_linewidth() 167 | if isinstance(lw, tuple): 168 | assert len(lw) == 1 169 | lw = lw[0] 170 | c.set_linewidth(lw * scale_factor) 171 | elif isinstance(c, PathCollection): 172 | c.set_linewidths(np.array(c.get_linewidths()) * scale_factor) 173 | for t in ax.texts: 174 | t.set_fontsize(t.get_fontsize() * scale_factor) 175 | 176 | def render_to_ax(ax, sch): 177 | base_width = 1 178 | 179 | wires = [] 180 | notes = [] 181 | for wire in sch.wire: 182 | seg = np.array([(wire.x0, -wire.y0), (wire.x1, -wire.y1)]) 183 | if wire.layer == 'Wire': 184 | wires.append(seg) 185 | elif wire.layer == 'Notes': 186 | notes.append(seg) 187 | else: 188 | assert 0 189 | 190 | line_segments = LineCollection(wires, linewidths = base_width, 191 | colors = 'green', 192 | linestyle = 'solid') 193 | ax.add_collection(line_segments) 194 | 195 | note_segments = LineCollection(notes, linewidths = base_width, 196 | colors = 'blue', 197 | linestyle = '--') 198 | ax.add_collection(note_segments) 199 | 200 | conns = [] 201 | for conn in sch.conn: 202 | xy = np.array((conn.x, -conn.y)) 203 | conns.append(xy) 204 | 205 | conn_ellipses = EllipseCollection(50, 50, 0, 206 | units = 'x', 207 | offsets = conns, 208 | edgecolor = None, 209 | facecolor = 'green', 210 | transOffset = ax.transData) 211 | ax.add_collection(conn_ellipses) 212 | 213 | noconns = [] 214 | o = 0.025 215 | for noconn in sch.noconn: 216 | xy = np.array((noconn.x, -noconn.y)) 217 | noconns.append([ xy + (-o,-o), xy + ( o,o)]) 218 | noconns.append([ xy + ( o,-o), xy + (-o,o)]) 219 | 220 | noconn_segments = LineCollection(noconns, linewidths = base_width, 221 | colors = 'green', 222 | linestyle = 'solid') 223 | ax.add_collection(noconn_segments) 224 | 225 | for comp in sch.comp: 226 | # for some components the rotation is wrong. but it only 227 | # happens every now and then, for example a ground symbol 228 | # that should be turned to the right is on the left side 229 | # in _some_ positions. 230 | 231 | for lib in sch.libs: 232 | sym = lib.get_sym(comp.name) 233 | if sym: 234 | break 235 | else: 236 | print("Symbol not found %s" % comp.name) 237 | continue 238 | 239 | pl = PathList() 240 | 241 | for draw in sym.children: 242 | if draw.part != 0: 243 | if comp.part != draw.part: 244 | # print('nv', draw.part, comp.part, draw.unit) 245 | continue 246 | 247 | linewidth = base_width 248 | if draw.pen_width: 249 | linewidth *= draw.pen_width / 10 250 | 251 | edgecolor = 'brown' 252 | if draw.filled: 253 | facecolor = 'yellow' 254 | facecolor = 'none' 255 | else: 256 | facecolor = 'none' 257 | 258 | if draw.__class__ == schema.SymArc: 259 | dp = np.array([ draw.x, draw.y ]) 260 | pl.arc(dp, draw.r, draw.start * 0.1, draw.end * 0.1, 261 | linewidth, edgecolor, facecolor) 262 | 263 | elif draw.__class__ == schema.SymCircle: 264 | dp = np.array([ draw.x, draw.y ]) 265 | pl.circle(dp, draw.r, linewidth, edgecolor, facecolor) 266 | 267 | elif draw.__class__ == schema.SymPin: 268 | dp = np.array([ draw.x, draw.y ]) 269 | normal = PIN_ORIENTATION[draw.orientation] 270 | 271 | if draw.length: 272 | verts = np.array([ dp, dp + normal * draw.length ]) 273 | 274 | edgecolor = 'brown' 275 | 276 | pl.path(Path(verts), base_width, edgecolor, facecolor) 277 | 278 | if not sym.power and (0 or sym.pin_numbers_shown): 279 | o = np.matmul(((0,1),(1,0)), normal) * 25 280 | o[0] = -abs(o[0]) 281 | o[1] = abs(o[1]) 282 | pl.text(dp + normal * 75 + o, 283 | -normal, draw.pin, draw.sizenum / 10, 284 | color = 'brown') 285 | 286 | if not sym.power and sym.pin_names_shown and draw.name != '~': 287 | pl.text(dp + normal * (draw.length + sym.pin_name_offs), normal, draw.name, draw.sizename / 10, 288 | color = 'green') 289 | 290 | elif draw.__class__ == schema.SymPoly: 291 | verts = draw.vertices 292 | 293 | pl.path(Path(verts), linewidth, edgecolor, facecolor) 294 | 295 | elif draw.__class__ == schema.SymRect: 296 | verts = [ 297 | (draw.x0, draw.y0), 298 | (draw.x0, draw.y1), 299 | (draw.x1, draw.y1), 300 | (draw.x1, draw.y0), 301 | (draw.x0, draw.y0), 302 | ] 303 | 304 | pl.path(Path(verts), linewidth, edgecolor, facecolor) 305 | 306 | for field in comp.fields.values(): 307 | if field.flags & 1: 308 | # Invisible 309 | continue 310 | 311 | if field.text == '~': 312 | # Nothing to show 313 | continue 314 | 315 | if field.halign == 'C': 316 | halign = 'center' 317 | elif field.halign == 'L': 318 | halign = 'left' 319 | elif field.halign == 'R': 320 | halign = 'right' 321 | else: 322 | halign = None 323 | 324 | if field.valign == 'C': 325 | valign = 'center' 326 | elif field.valign == 'B': 327 | valign = 'bottom' 328 | elif field.valign == 'T': 329 | valign = 'top' 330 | else: 331 | valign = None 332 | 333 | if field.orientation == 'H': 334 | normal = (1,0) 335 | elif field.orientation == 'V': 336 | normal = (0,1) 337 | else: 338 | normal = None 339 | 340 | pl.text((field.x - comp.posx, field.y - comp.posy), normal, 341 | field.text, field.size / 10, 342 | halign = halign, valign = valign, color = 'brown') 343 | 344 | pl.on_ax(ax, np.array((comp.posx, comp.posy)), comp.orientation) 345 | 346 | for text in sch.text: 347 | pl = PathList() 348 | normal = TEXT_ORIENTATION[text.orientation] 349 | if text.sub == 'GLabel': 350 | halign = 'right' 351 | valign = 'center' 352 | color = 'brown' 353 | else: 354 | halign = 'left' 355 | valign = 'bottom' 356 | if text.sub == 'Label': 357 | color = 'black' 358 | else: 359 | color = 'blue' 360 | pl.text((text.x, text.y), normal, 361 | text.text, text.size / 10, 362 | halign = halign, valign = valign, color = color) 363 | pl.on_ax(ax, np.array((0,0)), (1,0,0,1)) 364 | 365 | if 1: 366 | ax.get_xaxis().set_visible(False) 367 | ax.get_yaxis().set_visible(False) 368 | 369 | ax.axis('equal') 370 | 371 | fig = ax.get_figure() 372 | x_scale = fig.bbox_inches.width * ax.get_position().width * 72 / float(np.diff(ax.get_xlim())) 373 | y_scale = fig.bbox_inches.height * ax.get_position().width * 72 / float(np.diff(ax.get_ylim())) 374 | 375 | scale_ax(ax, min(x_scale, y_scale) * 16) 376 | -------------------------------------------------------------------------------- /kicad/schema.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | from collections import OrderedDict 5 | 6 | import os 7 | import sys 8 | 9 | VERBOSE = 0 10 | 11 | class AttributeDict(dict): 12 | def __getattr__(self, attr): 13 | return self[attr] 14 | def __setattr__(self, attr, value): 15 | self[attr] = value 16 | 17 | def _encode_string(s): 18 | return '"%s"' % s 19 | 20 | class Parser(object): 21 | def __init__(self, lines): 22 | self.lines = lines 23 | self.index = 0 24 | 25 | def eof(self): 26 | return self.index >= len(self.lines) 27 | 28 | def readline(self): 29 | if not self.eof(): 30 | l = self.lines[self.index] 31 | self.index += 1 32 | l = l.strip() 33 | return l 34 | return None 35 | 36 | def back(self): 37 | assert self.index > 0 38 | self.index -= 1 39 | 40 | def parse_line(self): 41 | while True: 42 | l = self.readline() 43 | if l is None: 44 | return None 45 | if l.startswith('#'): 46 | continue 47 | break 48 | 49 | i = 0 50 | a = [] 51 | while i < len(l): 52 | if l[i].isspace(): 53 | i += 1 54 | continue 55 | 56 | if l[i] == '"': 57 | j = l.index('"', i + 1) 58 | s = l[i+1:j] 59 | i = j + 1 60 | else: 61 | j = l.find(' ', i) 62 | if j == -1: 63 | j = len(l) 64 | s = l[i:j] 65 | i = j 66 | a.append(s) 67 | 68 | if VERBOSE: 69 | print(len(a), a) 70 | 71 | return a 72 | 73 | class Element(object): 74 | def __init__(self): 75 | self.kind = None 76 | 77 | self.pen_width = 0 78 | self.filled = False 79 | 80 | class SchDescr(Element): 81 | def __init__(self, parser): 82 | super(SchDescr, self).__init__() 83 | self.parse(parser) 84 | 85 | def parse(self, parser): 86 | # $Descr A3 16535 11700 87 | parts = parser.parse_line() 88 | assert len(parts) >= 4 89 | assert parts[0] == '$Descr' 90 | self.size = parts[1] 91 | assert self.size in [ 'A0', 'A1', 'A2', 'A3', 'A4', 92 | 'A', 'B', 'C', 'D', 'E', 'User' ] 93 | self.w = int(parts[2]) 94 | self.h = int(parts[3]) 95 | self.flags = parts[4:] 96 | 97 | parts = parser.parse_line() 98 | if parts[0] == 'encoding': 99 | assert len(parts) == 2 100 | assert parts[1] == 'utf-8' 101 | self.encoding = parts[1] 102 | else: 103 | parser.back() 104 | self.encoding = None 105 | 106 | # Sheet 1 4 107 | parts = parser.parse_line() 108 | assert len(parts) == 3 109 | assert parts[0] == 'Sheet' 110 | self.sheet_num = int(parts[1]) 111 | self.sheet_max = int(parts[2]) 112 | 113 | # "title" 114 | parts = parser.parse_line() 115 | if len(parts) == 1: 116 | self.title = parts[0] 117 | else: 118 | assert len(parts) == 2 119 | assert parts[0] == 'Title' 120 | self.title = parts[1] 121 | 122 | # Date "28 dec 1996" 123 | parts = parser.parse_line() 124 | assert len(parts) == 2 125 | assert parts[0] == 'Date' 126 | self.date = parts[1] 127 | 128 | # Rev "revision" 129 | parts = parser.parse_line() 130 | assert len(parts) == 2 131 | assert parts[0] == 'Rev' 132 | self.rev = parts[1] 133 | 134 | # Comp "company" 135 | parts = parser.parse_line() 136 | assert len(parts) == 2 137 | assert parts[0] == 'Comp' 138 | self.comp = parts[1] 139 | 140 | # Comment1 "comment" 141 | # Comment2 "comment" 142 | # Comment3 "comment" 143 | # Comment4 "comment" 144 | self.comments = [] 145 | while 1: 146 | parts = parser.parse_line() 147 | if not parts[0].startswith('Comment'): 148 | parser.back() 149 | break 150 | assert int(parts[0][7:]) == len(self.comments) + 1 151 | assert len(parts) == 2 152 | self.comments.append(parts[1]) 153 | assert len(self.comments) == 4 154 | 155 | # $EndDescr 156 | parts = parser.parse_line() 157 | assert len(parts) == 1 158 | assert parts[0] == '$EndDescr' 159 | 160 | def format(self, outf): 161 | extra = ' '.join(self.flags) 162 | if extra: 163 | extra = ' ' + extra 164 | outf.write('$Descr %s %u %u%s\n' % ( 165 | self.size, self.w, self.h, extra)) 166 | if self.encoding is not None: 167 | outf.write('encoding %s\n' % self.encoding) 168 | outf.write('Sheet %u %u\n' % (self.sheet_num, self.sheet_max)) 169 | outf.write('Title %s\n' % _encode_string(self.title)) 170 | outf.write('Date %s\n' % _encode_string(self.date)) 171 | outf.write('Rev %s\n' % _encode_string(self.rev)) 172 | outf.write('Comp %s\n' % _encode_string(self.comp)) 173 | for i, s in enumerate(self.comments): 174 | outf.write('Comment%u %s\n' % (i + 1, _encode_string(s))) 175 | outf.write('$EndDescr\n') 176 | 177 | class SchSheet(Element): 178 | def __init__(self, parser): 179 | super(SchSheet, self).__init__() 180 | self.parse(parser) 181 | 182 | def parse(self, parser): 183 | # $Sheet 184 | parts = parser.parse_line() 185 | assert len(parts) == 1 186 | assert parts[0] == '$Sheet' 187 | 188 | # S posx posy dimx dimy 189 | parts = parser.parse_line() 190 | assert len(parts) == 5 191 | assert parts[0] == 'S' 192 | self.posx = int(parts[1]) 193 | self.posy = int(parts[2]) 194 | self.dimx = int(parts[3]) 195 | self.dimy = int(parts[4]) 196 | 197 | # U DEADBEEF 198 | parts = parser.parse_line() 199 | assert len(parts) == 2 200 | assert parts[0] == 'U' 201 | self.uuid = parts[1] 202 | 203 | # F0 "text" 50 204 | # F1 "text" 50 205 | # ... 206 | self.fields = [] 207 | while 1: 208 | parts = parser.parse_line() 209 | if not parts[0].startswith('F'): 210 | parser.back() 211 | break 212 | assert int(parts[0][1:]) == len(self.fields) 213 | assert len(parts) == 3 214 | self.fields.append((parts[1], int(parts[2]))) 215 | assert len(self.fields) >= 2 216 | 217 | parts = parser.parse_line() 218 | assert len(parts) == 1 219 | assert parts[0] == '$EndSheet' 220 | 221 | def format(self, outf): 222 | outf.write('$Sheet\n') 223 | # bug compatibility, add trailing space to S 224 | outf.write('S %u %u %u %u \n' % ( 225 | self.posx, self.posy, self.dimx, self.dimy)) 226 | outf.write('U %s\n' % self.uuid) 227 | for i, (text, n) in enumerate(self.fields): 228 | outf.write('F%u %s %s\n' % (i, _encode_string(text), n)) 229 | outf.write('$EndSheet\n') 230 | 231 | class SchCompField(Element): 232 | def __init__(self, parts): 233 | super(SchCompField, self).__init__() 234 | self.parse(parts) 235 | 236 | def parse(self, parts): 237 | assert len(parts) == 10 or len(parts) == 11 238 | self.num = int(parts[1]) 239 | self.text = parts[2] 240 | self.orientation = parts[3] 241 | self.x = int(parts[4]) 242 | self.y = int(parts[5]) 243 | self.size = int(parts[6]) 244 | self.flags = int(parts[7]) 245 | self.halign = parts[8] 246 | assert len(parts[9]) == 3 247 | self.valign = parts[9][0] 248 | self.italic = parts[9][1] 249 | self.bold = parts[9][2] 250 | if len(parts) > 10: 251 | self.name = parts[10] 252 | else: 253 | self.name = self.num 254 | 255 | def format(self, outf): 256 | if self.num < 4: 257 | # TODO check field names 258 | assert self.num == self.name 259 | extra = '' 260 | else: 261 | extra = ' %s' % _encode_string(self.name) 262 | outf.write('F %u %s %s %u %u %u %04u %s %s%s%s%s\n' % ( 263 | self.num, _encode_string(self.text), self.orientation, 264 | self.x, self.y, self.size, self.flags, 265 | self.halign, self.valign, self.italic, self.bold, 266 | extra)) 267 | 268 | class SchComp(Element): 269 | def __init__(self, parser): 270 | super(SchComp, self).__init__() 271 | self.parse(parser) 272 | self.kind = 'comp' 273 | 274 | def parse(self, parser): 275 | # $Comp 276 | parts = parser.parse_line() 277 | assert len(parts) == 1 278 | assert parts[0] == '$Comp' 279 | 280 | # L Library:Component_name REF123 281 | parts = parser.parse_line() 282 | assert len(parts) == 3 283 | assert parts[0] == 'L' 284 | self.name = parts[1] 285 | self.ref = parts[2] 286 | 287 | # U 1 1 DEADBEEF 288 | parts = parser.parse_line() 289 | assert len(parts) == 4 290 | assert parts[0] == 'U' 291 | self.uuid_1 = int(parts[1]) 292 | self.uuid_2 = int(parts[2]) 293 | self.uuid = parts[3] 294 | 295 | # P posx posy 296 | parts = parser.parse_line() 297 | assert len(parts) == 3 298 | assert parts[0] == 'P' 299 | self.posx = int(parts[1]) 300 | self.posy = int(parts[2]) 301 | 302 | # F 0 "REF" H 2456 8667 50 0000 C CNN 303 | # F 1 "USB_B_Micro" H 2456 8576 50 0000 C CNN 304 | # F 2 "mod:USB_Micro-B_Amphenol_10118193-0001LF_DIY" H 2550 8150 50 0001 C CNN 305 | # F 3 "~" H 2550 8150 50 0001 C CNN 306 | # F 4 "10118193-0001LF" H 2400 8200 50 0001 C CNN "MFP" 307 | # ... 308 | # 309 | # Note that F0..F3 are hardcoded, F4 and on have a user defined key at the end 310 | self.fields = OrderedDict() 311 | while 1: 312 | parts = parser.parse_line() 313 | if parts[0] != 'F': 314 | parser.back() 315 | break 316 | field = SchCompField(parts) 317 | assert field.num == len(self.fields) 318 | self.fields[field.name] = field 319 | assert len(self.fields) >= 4 320 | 321 | parts = parser.parse_line() 322 | assert len(parts) == 3 323 | self.a = (int(parts[0]), int(parts[1]), int(parts[2])) 324 | self.part = int(parts[0]) 325 | 326 | assert self.posx == self.a[1] 327 | assert self.posy == self.a[2] 328 | 329 | parts = parser.parse_line() 330 | assert len(parts) == 4 331 | self.orientation = ( int(parts[0]), int(parts[1]), 332 | int(parts[2]), int(parts[3]) ) 333 | 334 | parts = parser.parse_line() 335 | assert len(parts) == 1 336 | assert parts[0] == '$EndComp' 337 | 338 | def format(self, outf): 339 | outf.write('$Comp\n') 340 | outf.write('L %s %s\n' % (self.name, self.ref)) 341 | outf.write('U %u %u %s\n' % (self.uuid_1, self.uuid_2, self.uuid)) 342 | outf.write('P %u %u\n' % (self.posx, self.posy)) 343 | for field in self.fields.values(): 344 | field.format(outf) 345 | outf.write('\t%-4u %-4u %-4u\n' % self.a) 346 | # bug compatibility, the final %-4u can add whitespace at the end of the line 347 | outf.write('\t%-4u %-4u %-4u %-4u\n' % self.orientation) 348 | outf.write('$EndComp\n') 349 | 350 | class SchText(Element): 351 | def __init__(self, parser): 352 | super(SchText, self).__init__() 353 | self.kind = 'text' 354 | self.parse(parser) 355 | 356 | def parse(self, parser): 357 | parts = parser.parse_line() 358 | assert parts[0] == 'Text' 359 | self.sub = parts[1] 360 | self.x = int(parts[2]) 361 | self.y = int(parts[3]) 362 | self.orientation = int(parts[4]) 363 | self.size = int(parts[5]) 364 | 365 | if self.sub == 'GLabel': 366 | assert len(parts) == 9 367 | self.direction = parts[6] 368 | self.a = parts[7] 369 | self.b = parts[8] 370 | elif self.sub == 'Label' or self.sub == 'Notes': 371 | assert len(parts) == 8 372 | self.a = parts[6] 373 | self.b = parts[7] 374 | else: 375 | raise ValueError("Unknown text type \"%s\"" % self.sub) 376 | 377 | self.text = parser.readline() 378 | self.text = self.text.replace('\\\\', '\1') 379 | self.text = self.text.replace('\\n', '\n') 380 | self.text = self.text.replace('\1', '\\') 381 | 382 | def format(self, outf): 383 | if self.sub == 'GLabel': 384 | outf.write('Text %s %s %s %-4s %-4s %s %s %s\n' % ( 385 | self.sub, self.x, self.y, self.orientation, self.size, self.direction, self.a, self.b)) 386 | else: 387 | outf.write('Text %s %s %s %-4s %-4s %s %s\n' % ( 388 | self.sub, self.x, self.y, self.orientation, self.size, self.a, self.b)) 389 | outf.write('%s\n' % self.text) 390 | 391 | class SchWire(Element): 392 | def __init__(self, parser): 393 | super(SchWire, self).__init__() 394 | self.parse(parser) 395 | self.kind = 'wire' 396 | 397 | def parse(self, parser): 398 | parts = parser.parse_line() 399 | assert parts[0] == 'Wire' 400 | assert len(parts) == 3 401 | self.layer = parts[1] 402 | self.shape = parts[2] 403 | parts = parser.parse_line() 404 | assert len(parts) == 4 405 | self.x0 = int(parts[0]) 406 | self.y0 = int(parts[1]) 407 | self.x1 = int(parts[2]) 408 | self.y1 = int(parts[3]) 409 | 410 | def format(self, outf): 411 | outf.write('Wire %s %s\n' % (self.layer, self.shape)) 412 | outf.write('\t%u %u %u %u\n' % (self.x0, self.y0, self.x1, self.y1)) 413 | 414 | class SchConnection(Element): 415 | def __init__(self, parser): 416 | super(SchConnection, self).__init__() 417 | self.parse(parser) 418 | self.kind = 'conn' 419 | 420 | def parse(self, parser): 421 | parts = parser.parse_line() 422 | assert parts[0] == 'Connection' 423 | assert len(parts) == 4 424 | self.name = parts[1] 425 | self.x = int(parts[2]) 426 | self.y = int(parts[3]) 427 | 428 | def format(self, outf): 429 | outf.write('Connection %s %u %u\n' % (self.name, self.x, self.y)) 430 | 431 | class SchNoConn(Element): 432 | def __init__(self, parser): 433 | super(SchNoConn, self).__init__() 434 | self.parse(parser) 435 | self.kind = 'noconn' 436 | 437 | def parse(self, parser): 438 | parts = parser.parse_line() 439 | assert parts[0] == 'NoConn' 440 | assert len(parts) == 4 441 | self.name = parts[1] 442 | self.x = int(parts[2]) 443 | self.y = int(parts[3]) 444 | 445 | def format(self, outf): 446 | outf.write('NoConn %s %u %u\n' % (self.name, self.x, self.y)) 447 | 448 | class Sch(AttributeDict): 449 | def __init__(self, fn): 450 | assert fn.endswith('.sch') 451 | 452 | self.path = fn 453 | self.base, self.fn = os.path.split(fn) 454 | self.name = self.fn[:-4] 455 | 456 | f = open(fn) 457 | 458 | parser = Parser(f.readlines()) 459 | self.parse(parser) 460 | 461 | self.load_libs() 462 | 463 | self['conns'] = [] 464 | self['noconn'] = [] 465 | for child in self.children: 466 | if child.kind is None: 467 | continue 468 | try: 469 | a = self[child.kind] 470 | except KeyError: 471 | a = [] 472 | self[child.kind] = a 473 | a.append(child) 474 | 475 | def parse(self, parser): 476 | self.children = [] 477 | 478 | # EESchema Schematic File Version 4 479 | parts = parser.parse_line() 480 | assert parts[:4] == [ 'EESchema', 'Schematic', 'File', 'Version' ] 481 | self.version = int(parts[4]) 482 | assert self.version == 4 483 | 484 | # LIBS:project-cache foo bar boz 485 | 486 | self.lib_names = [] 487 | while 1: 488 | libs = self.parse_libs(parser) 489 | if not libs: 490 | break 491 | self.lib_names.append(libs) 492 | 493 | # EELAYER 26 0 494 | parts = parser.parse_line() 495 | assert parts[0] == 'EELAYER' 496 | self.eelayer = parts[1:] 497 | 498 | # EELAYER END 499 | parts = parser.parse_line() 500 | assert parts == [ 'EELAYER', 'END' ] 501 | 502 | self.children.append(SchDescr(parser)) 503 | 504 | while 1: 505 | parts = parser.parse_line() 506 | parser.back() 507 | if parts[0] == '$Sheet': 508 | self.children.append(SchSheet(parser)) 509 | elif parts[0] == '$Comp': 510 | self.children.append(SchComp(parser)) 511 | elif parts[0] == 'Text': 512 | self.children.append(SchText(parser)) 513 | elif parts[0] == 'Wire': 514 | self.children.append(SchWire(parser)) 515 | elif parts[0] == 'Connection': 516 | self.children.append(SchConnection(parser)) 517 | elif parts[0] == 'NoConn': 518 | self.children.append(SchNoConn(parser)) 519 | else: 520 | break 521 | 522 | parts = parser.parse_line() 523 | assert len(parts) == 1 524 | assert parts[0] == '$EndSCHEMATC' 525 | 526 | assert parser.eof() 527 | 528 | def parse_libs(self, parser): 529 | l = parser.readline() 530 | if l is None: 531 | return l 532 | if l.startswith('LIBS:'): 533 | return [ _.strip() for _ in l[5:].split(',') ] 534 | parser.back() 535 | return None 536 | 537 | def load_lib(self, fn, search = [ '.' ]): 538 | for base in search: 539 | path = os.path.join(base, fn) 540 | if os.path.exists(path): 541 | with open(path) as f: 542 | if VERBOSE: 543 | print("parsing library %s" % fn) 544 | lib = Lib(f) 545 | self.libs.append(lib) 546 | break 547 | else: 548 | if VERBOSE: 549 | print("%s: library not found" % fn) 550 | if VERBOSE: 551 | print() 552 | 553 | def load_libs(self, search = [ '.' ]): 554 | search = [ os.path.join(self.base, _) for _ in search ] 555 | 556 | # Make a unique set of library names 557 | names = set() 558 | for a in self.lib_names: 559 | names.update(a) 560 | 561 | # Remove the cache if it is in the list of names 562 | cache = self.name + '-cache' 563 | if cache in names: 564 | names.remove(cache) 565 | 566 | self.libs = [] 567 | for name in names: 568 | self.load_lib(name + '.lib', search) 569 | 570 | # Load the cache last so that it overwrites any other libraries 571 | self.load_lib(cache + '.lib', search) 572 | 573 | def format(self, outf): 574 | outf.write('EESchema Schematic File Version %u\n' % self.version) 575 | for libs in self.lib_names: 576 | outf.write('LIBS:%s\n' % ', '.join(libs)) 577 | outf.write('EELAYER %s\n' % ' '.join(self.eelayer)) 578 | outf.write('EELAYER END\n') 579 | 580 | for child in self.children: 581 | child.format(outf) 582 | 583 | outf.write('$EndSCHEMATC\n') 584 | 585 | class SymArc(Element): 586 | def __init__(self, parts): 587 | Element.__init__(self) 588 | assert parts[0] == 'A' 589 | assert len(parts) == 14 590 | self.x = int(parts[1]) 591 | self.y = int(parts[2]) 592 | self.r = int(parts[3]) 593 | self.start = int(parts[4]) 594 | self.end = int(parts[5]) 595 | self.part = int(parts[6]) 596 | self.unit = int(parts[7]) 597 | self.pen_width = int(parts[8]) 598 | assert parts[9].upper() in [ 'F', 'N' ] 599 | self.filled = parts[9].upper() == 'F' 600 | self.xstart = int(parts[10]) 601 | self.xend = int(parts[11]) 602 | self.ystart = int(parts[12]) 603 | self.yend = int(parts[13]) 604 | 605 | class SymCircle(Element): 606 | def __init__(self, parts): 607 | Element.__init__(self) 608 | assert parts[0] == 'C' 609 | assert len(parts) == 8 610 | self.x = int(parts[1]) 611 | self.y = int(parts[2]) 612 | self.r = int(parts[3]) 613 | self.part = int(parts[4]) 614 | self.unit = int(parts[5]) 615 | self.pen_width = int(parts[6]) 616 | assert parts[7].upper() in [ 'F', 'N' ] 617 | self.filled = parts[7].upper() == 'F' 618 | 619 | class SymPoly(Element): 620 | def __init__(self, parts): 621 | Element.__init__(self) 622 | assert parts[0] == 'P' 623 | count = int(parts[1]) 624 | self.part = int(parts[2]) 625 | self.unit = int(parts[3]) 626 | self.pen_width = int(parts[4]) 627 | self.vertices = [] 628 | idx = 5 629 | for i in range(count): 630 | self.vertices.append((int(parts[idx]), int(parts[idx+1]))) 631 | idx += 2 632 | assert parts[idx].upper() in [ 'F', 'N' ] 633 | self.filled = parts[idx].upper() == 'F' 634 | idx += 1 635 | assert idx == len(parts) 636 | 637 | class SymPin(Element): 638 | def __init__(self, parts): 639 | Element.__init__(self) 640 | assert parts[0] == 'X' 641 | assert len(parts) >= 12 and len(parts) <= 13 642 | self.name = parts[1] 643 | self.pin = parts[2] 644 | self.x = int(parts[3]) 645 | self.y = int(parts[4]) 646 | self.length = int(parts[5]) 647 | self.orientation = parts[6] 648 | self.sizenum = int(parts[7]) 649 | self.sizename = int(parts[8]) 650 | self.part = int(parts[9]) 651 | self.unit = int(parts[10]) 652 | self.kind = parts[11] 653 | if len(parts) > 12: 654 | self.shape = parts[12] 655 | else: 656 | self.shape = None 657 | 658 | class SymRect(Element): 659 | def __init__(self, parts): 660 | Element.__init__(self) 661 | assert parts[0] == 'S' 662 | assert len(parts) == 9 663 | self.x0 = int(parts[1]) 664 | self.y0 = int(parts[2]) 665 | self.x1 = int(parts[3]) 666 | self.y1 = int(parts[4]) 667 | self.part = int(parts[5]) 668 | self.unit = int(parts[6]) 669 | self.pen_width = int(parts[7]) 670 | assert parts[8].upper() in [ 'F', 'N' ] 671 | self.filled = parts[8].upper() == 'F' 672 | 673 | class SymText(Element): 674 | def __init__(self, parts): 675 | Element.__init__(self) 676 | assert parts[0] == 'T' 677 | assert len(parts) >= 12 and len(parts) <= 13 678 | self.angle = int(parts[1]) 679 | self.x = int(parts[2]) 680 | self.y = int(parts[3]) 681 | self.size = int(parts[4]) 682 | self.hidden = parts[5] 683 | self.part = int(parts[6]) 684 | self.unit = int(parts[7]) 685 | self.text = parts[8] 686 | self.italic = parts[9] 687 | self.bold = parts[10] 688 | self.halign = parts[11] 689 | self.valign = parts[11] 690 | 691 | class Sym(Element): 692 | def __init__(self, parser): 693 | super(Sym, self).__init__() 694 | self.parse(parser) 695 | self.kind = 'sym' 696 | 697 | def parse(self, parser): 698 | # DEF Connector_Generic_Conn_01x01 J 0 40 Y N 1 F N 699 | parts = parser.parse_line() 700 | assert parts[0] == 'DEF' 701 | self.name = parts[1] 702 | self.prefix = parts[2] 703 | assert int(parts[3]) == 0 704 | self.pin_name_offs = int(parts[4]) 705 | assert parts[5] in [ 'Y', 'N' ] 706 | self.pin_numbers_shown = parts[5] == 'Y' 707 | assert parts[6] in [ 'Y', 'N' ] 708 | self.pin_names_shown = parts[6] == 'Y' 709 | self.part_count = int(parts[7]) 710 | if len(parts) >= 8: 711 | assert parts[8] in [ 'F', 'L' ] 712 | self.locked = parts[8] == 'L' 713 | else: 714 | self.locked = 0 715 | if len(parts) >= 9: 716 | assert parts[9] in [ 'P', 'N' ] 717 | self.power = parts[9] == 'P' 718 | else: 719 | self.power = 0 720 | 721 | # F0 "J" 0 100 50 H V C CNN 722 | # F1 "Connector_Generic_Conn_01x01" 0 -100 50 H V C CNN 723 | # F2 "" 0 0 50 H I C CNN 724 | # F3 "" 0 0 50 H I C CNN 725 | # 726 | # Note that F0..F3 are hardcoded, F4 and on have a user defined key at the end 727 | self.fields = [] 728 | while 1: 729 | parts = parser.parse_line() 730 | if not parts[0].startswith('F'): 731 | break 732 | assert int(parts[0][1:]) == len(self.fields) 733 | assert len(parts) == 9 or len(parts) == 10 734 | a = [ parts[1], int(parts[2]), int(parts[3]), int(parts[4]), parts[5], parts[6], parts[7], parts[8] ] 735 | if len(parts) > 9: 736 | a.append(parts[9]) 737 | else: 738 | a.append(None) 739 | self.fields.append(a) 740 | assert len(self.fields) >= 4 741 | 742 | self.aliases = [] 743 | if parts[0] == 'ALIAS': 744 | assert len(parts) >= 2 745 | self.aliases.extend(parts[1:]) 746 | parts = parser.parse_line() 747 | 748 | self.fplist = [] 749 | if parts == [ '$FPLIST' ]: 750 | parts = parser.parse_line() 751 | while parts != [ '$ENDFPLIST' ]: 752 | self.fplist.append(' '.join(parts)) 753 | parts = parser.parse_line() 754 | parts = parser.parse_line() 755 | 756 | self.children = [] 757 | 758 | assert parts == [ 'DRAW' ] 759 | parts = parser.parse_line() 760 | while parts != [ 'ENDDRAW' ]: 761 | if parts[0] == 'A': 762 | self.children.append(SymArc(parts)) 763 | elif parts[0] == 'C': 764 | self.children.append(SymCircle(parts)) 765 | elif parts[0] == 'P': 766 | self.children.append(SymPoly(parts)) 767 | elif parts[0] == 'S': 768 | self.children.append(SymRect(parts)) 769 | elif parts[0] == 'T': 770 | self.children.append(SymText(parts)) 771 | elif parts[0] == 'X': 772 | self.children.append(SymPin(parts)) 773 | else: 774 | ValueError("Unknown symbol element \"%s\"" % parts[0]) 775 | 776 | parts = parser.parse_line() 777 | parts = parser.parse_line() 778 | 779 | assert parts == [ 'ENDDEF' ] 780 | 781 | def format(self, outf): 782 | outf.write('Connection %s %u %u\n' % (self.name, self.x, self.y)) 783 | 784 | class Lib(object): 785 | def __init__(self, f): 786 | parser = Parser(f.readlines()) 787 | self.parse(parser) 788 | 789 | def parse(self, parser): 790 | # EESchema-LIBRARY Version 2.4 791 | parts = parser.parse_line() 792 | assert parts[:2] == [ 'EESchema-LIBRARY','Version' ] 793 | self.version = parts[2:] 794 | 795 | l = parser.readline() 796 | assert l == '#encoding utf-8' 797 | 798 | self.syms = [] 799 | while True: 800 | parts = parser.parse_line() 801 | if parts is None: 802 | break 803 | 804 | if parts[0] == 'DEF': 805 | parser.back() 806 | sym = Sym(parser) 807 | self.syms.append(sym) 808 | 809 | assert parser.eof() 810 | 811 | self.map = {} 812 | for sym in self.syms: 813 | self.map[sym.name.upper()] = sym 814 | 815 | def get_sym(self, name): 816 | name = name.upper() 817 | sym = self.map.get(name) 818 | if sym: 819 | return sym 820 | name = name.replace(':', '_') 821 | sym = self.map.get(name) 822 | if sym: 823 | return sym 824 | return None 825 | -------------------------------------------------------------------------------- /kicad/spice_converter.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | VERBOSE = 0 5 | 6 | import os 7 | import re 8 | import numpy as np 9 | 10 | from . import schema 11 | 12 | from spice.circuit import Circuit 13 | from spice import unit 14 | 15 | supply_pat = r'(?P[+-]?)(?P[0-9]+)V(?P[0-9]*)$' 16 | supply_re = re.compile(supply_pat) 17 | 18 | class Net(object): 19 | def __init__(self, id): 20 | self.id = id 21 | self.coords = set() 22 | self.pins = [] 23 | 24 | def sch_to_circuit(sch): 25 | circuit = Circuit() 26 | 27 | d = {} 28 | 29 | id = 1 30 | for wire in sch.wire: 31 | c0 = (wire.x0, wire.y0) 32 | c1 = (wire.x1, wire.y1) 33 | 34 | net0 = d.get(c0) 35 | net1 = d.get(c1) 36 | 37 | if net0 and net1: 38 | if VERBOSE: 39 | print("merging net %s and net %s" % (net0.id, net1.id)) 40 | net = net0 41 | net.coords = net0.coords.union(net1.coords) 42 | 43 | elif net0: 44 | net = net0 45 | elif net1: 46 | net = net1 47 | else: 48 | net = Net(id) 49 | id += 1 50 | 51 | net.coords.add(c0) 52 | net.coords.add(c1) 53 | 54 | if VERBOSE: 55 | print(c0, c1, net.id) 56 | 57 | for c in net.coords: 58 | d[c] = net 59 | 60 | if VERBOSE: 61 | print() 62 | 63 | for text in sch.text: 64 | if text.sub != 'GLabel' and text.sub != 'Label': 65 | continue 66 | 67 | c = (text.x, text.y) 68 | net = d.get(c) 69 | 70 | if not net: 71 | net = Net(id) 72 | net.coords.add(c) 73 | id += 1 74 | d[c] = net 75 | 76 | if VERBOSE: 77 | print("label net %s as %s" % (net.id, text.text)) 78 | if not isinstance(net.id, int): 79 | raise ValueError("two labels for same net: %s and %s" % ( 80 | net.id, text.text)) 81 | 82 | net.id = text.text 83 | 84 | if VERBOSE: 85 | print() 86 | 87 | for comp in sch.comp: 88 | trans = np.reshape(comp.orientation, (2,2)).T 89 | pos = np.array((comp.posx, comp.posy)) 90 | 91 | for lib in sch.libs: 92 | sym = lib.get_sym(comp.name) 93 | if sym: 94 | break 95 | else: 96 | print("Symbol not found %s" % comp.name) 97 | continue 98 | 99 | nets = {} 100 | 101 | for draw in sym.children: 102 | if draw.part != 0: 103 | if comp.part != draw.part: 104 | continue 105 | 106 | if draw.__class__ != schema.SymPin: 107 | continue 108 | 109 | vert = np.array([ draw.x, draw.y ]) 110 | vert = np.matmul(vert, trans) + pos 111 | 112 | c = (vert[0], vert[1]) 113 | net = d.get(c) 114 | 115 | if not net: 116 | net = Net(id) 117 | net.coords.add(c) 118 | id += 1 119 | d[c] = net 120 | 121 | if VERBOSE: 122 | print(comp.ref, draw.name, draw.pin, c, net.id, net.pins) 123 | net.pins.append((comp.ref, draw.name, draw.pin)) 124 | 125 | nets[draw.pin] = net.id 126 | 127 | if 'Spice_Netlist_Enabled' in comp.fields: 128 | if comp.fields['Spice_Netlist_Enabled'].text == 'Y': 129 | if comp.fields['Spice_Primitive'].text: 130 | if 'Spice_Lib_File' in comp.fields and comp.fields['Spice_Lib_File'].text: 131 | fn = os.path.join(sch.base, comp.fields['Spice_Lib_File'].text) 132 | circuit.add_include(fn) 133 | 134 | seq_field = comp.fields.get('Spice_Node_Sequence') 135 | if seq_field: 136 | seq = seq_field.text.split() 137 | else: 138 | seq = [ str(_+1) for _ in range(len(nets)) ] 139 | 140 | nodes = [] 141 | for arg in seq: 142 | nodes.append(str(nets[str(arg)])) 143 | 144 | model = comp.fields['Spice_Model'].text 145 | 146 | ref = comp.ref 147 | if not ref.startswith(comp.fields['Spice_Primitive'].text): 148 | ref = comp.fields['Spice_Primitive'].text + ref 149 | 150 | if VERBOSE: 151 | print(ref, nodes, model) 152 | 153 | circuit.Device(ref, nodes, model) 154 | 155 | else: 156 | print("unknown spice model %s with ref %s" % (comp.fields['Spice_Primitive'].text, comp.ref)) 157 | 158 | elif comp.name in [ 'Device:R' ]: 159 | assert comp.ref.startswith('R') 160 | value = comp.fields[1].text 161 | if value.lower().endswith('ohm'): 162 | value = value[:-3] 163 | value = unit.parse_unit(value) 164 | circuit.R(comp.ref, nets['1'], nets['2'], value) 165 | 166 | elif comp.name in [ 'Device:C' ]: 167 | assert comp.ref.startswith('C') 168 | value = comp.fields[1].text 169 | if value.endswith('F'): 170 | value = value[:-1] 171 | value = unit.parse_unit(value) 172 | circuit.C(comp.ref, nets['1'], nets['2'], value) 173 | 174 | elif comp.name in [ 'Device:L' ]: 175 | assert comp.ref.startswith('L') 176 | if value.endswith('H'): 177 | value = value[:-1] 178 | value = unit.parse_unit(value) 179 | circuit.C(comp.ref, nets['1'], nets['2'], value) 180 | 181 | elif comp.name in [ 'power:GND' ]: 182 | assert comp.ref.startswith('#PWR') 183 | # circuit.R('R' + comp.ref[1:], nets['1'], 0, 1 * unit.p) 184 | circuit.V('V' + comp.ref[1:], nets['1'], 0, 0) 185 | 186 | elif comp.name.startswith('power:'): 187 | assert comp.ref.startswith('#PWR') 188 | 189 | match = supply_re.match(comp.fields[1].text) 190 | if match: 191 | v = int(match.group('int')) 192 | 193 | frac = match.group('frac') 194 | if frac: 195 | v += + 0.1**len(frac) * int(frac) 196 | 197 | if match.group('sign') == '-': 198 | v = -v 199 | 200 | circuit.V('V' + comp.ref[1:], nets['1'], 0, v) 201 | else: 202 | print("can't figure out supply voltage for %s with ref %s" % (comp.name, comp.ref)) 203 | 204 | else: 205 | print("unknown component %s with ref %s" % (comp.name, comp.ref)) 206 | 207 | if VERBOSE: 208 | print() 209 | 210 | return circuit 211 | -------------------------------------------------------------------------------- /models_source/diodes/LICENSE: -------------------------------------------------------------------------------- 1 | Spice models from Diodes Incorporated are covered by the following 2 | disclaimer: 3 | 4 | https://www.diodes.com/design/tools/spice-models/ 5 | 6 | Diodes Disclaimer 7 | 8 | DIODES INCORPORATED AND ITS AFFILIATED COMPANIES AND SUBSIDIARIES 9 | (COLLECTIVELY, "DIODES") PROVIDE THESE SPICE MODELS AND DATA 10 | (COLLECTIVELY, THE "SM DATA") "AS IS" AND WITHOUT ANY REPRESENTATIONS 11 | OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING ANY WARRANTY OF 12 | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ANY WARRANTY 13 | ARISING FROM COURSE OF DEALING OR COURSE OF PERFORMANCE, OR ANY 14 | WARRANTY THAT ACCESS TO OR OPERATION OF THE SM DATA WILL BE 15 | UNINTERRUPTED, OR THAT THE SM DATA OR ANY SIMULATION USING THE SM DATA 16 | WILL BE ERROR FREE. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO 17 | EVENT WILL DIODES BE LIABLE FOR ANY INDIRECT, SPECIAL, INCIDENTAL, 18 | PUNITIVE OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION WITH 19 | THE PRODUCTION OR USE OF SM DATA, HOWEVER CAUSED AND UNDER WHATEVER 20 | CAUSE OF ACTION OR THEORY OF LIABILITY BROUGHT (INCLUDING, WITHOUT 21 | LIMITATION, UNDER ANY CONTRACT, NEGLIGENCE OR OTHER TORT THEORY OF 22 | LIABILITY), EVEN IF DIODES HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 23 | DAMAGES, AND DIODES' TOTAL LIABILITY (WHETHER IN CONTRACT, TORT OR 24 | OTHERWISE) WITH REGARD TO THE SM DATA WILL NOT, IN THE AGGREGATE, 25 | EXCEED ANY SUMS PAID BY YOU TO DIODES FOR THE SM DATA. 26 | 27 | By accessing, reviewing and/or downloading the SM DATA, you 28 | unconditionally acknowledge and agree to the above "DIODES 29 | DISCLAIMER." -------------------------------------------------------------------------------- /models_source/diodes/diodes/BAV99.spice.diff: -------------------------------------------------------------------------------- 1 | Comment out stray line with "switching" 2 | 3 | --- models_source/diodes/diodes/BAV99.spice.txt 2018-08-29 21:40:32.379783776 +0200 4 | +++ models/diodes/diodes/BAV99.lib 2018-08-29 21:51:54.389499917 +0200 5 | @@ -1,4 +1,4 @@ 6 | *SRC=BAV99;DI_BAV99;Diodes;Si; 75.0V 0.300A 4.00ns Diodes Inc. 7 | -switching 8 | +* switching 9 | .MODEL DI_BAV99 D ( IS=261p RS=0.140 BV=75.0 IBV=2.50u 10 | + CJO=1.19p M=0.333 N=1.70 TT=5.76n ) 11 | 12 | -------------------------------------------------------------------------------- /models_source/diodes/diodes/BAV99.spice.txt: -------------------------------------------------------------------------------- 1 | *SRC=BAV99;DI_BAV99;Diodes;Si; 75.0V 0.300A 4.00ns Diodes Inc. 2 | switching 3 | .MODEL DI_BAV99 D ( IS=261p RS=0.140 BV=75.0 IBV=2.50u 4 | + CJO=1.19p M=0.333 N=1.70 TT=5.76n ) -------------------------------------------------------------------------------- /models_source/diodes/diodes/index.py: -------------------------------------------------------------------------------- 1 | # BAV99 SPICE Model 2 | # https://www.diodes.com/products/discrete/diodes-and-rectifiers/diodes/small-signal-switching-diodes/part/BAV99 3 | Model('BAV99', 4 | mod = Patch('BAV99.spice.txt', 'BAV99.spice.diff', 5 | '41628457630847fc81f1')) 6 | -------------------------------------------------------------------------------- /models_source/diodes/mosfets/DMG2301LK.spice.txt: -------------------------------------------------------------------------------- 1 | *---------- DMG2301LK Spice Model ---------- 2 | .SUBCKT DMG2301LK 10 20 30 3 | * TERMINALS: D G S 4 | M1 1 2 3 3 PMOS L = 1E-006 W = 1E-006 5 | RD 10 1 0.08416 6 | RS 30 3 0.001 7 | RG 20 2 40.9 8 | CGS 2 3 1.265E-010 9 | EGD 12 30 2 1 1 10 | VFB 14 30 0 11 | FFB 2 1 VFB 1 12 | CGD 13 14 1.85E-010 13 | R1 13 30 1 14 | D1 13 12 DLIM 15 | DDG 14 15 DCGD 16 | R2 12 15 1 17 | D2 30 15 DLIM 18 | DSD 10 3 DSUB 19 | .MODEL PMOS PMOS LEVEL = 3 U0 = 400 VMAX = 1E+006 ETA = 0.001 20 | + TOX = 6E-008 NSUB = 1E+016 KP = 6.629 KAPPA = 19.32 VTO = -0.6459 21 | .MODEL DCGD D CJO = 1.177E-010 VJ = 0.611 M = 0.6 22 | .MODEL DSUB D IS = 0.0001419 N = 4.041 RS = 7.253E-009 BV = 22 CJO = 2.853E-011 VJ = 0.7195 M = 0.6 23 | .MODEL DLIM D IS = 0.0001 24 | .ENDS 25 | *Diodes DMG2301LK Spice Model v1.0M Last Revised 2016/4/28 -------------------------------------------------------------------------------- /models_source/diodes/mosfets/DMN2005UFG.spice.txt: -------------------------------------------------------------------------------- 1 | *---------- DMN2005UFG Spice Model ---------- 2 | .SUBCKT DMN2005UFG 10 20 30 3 | * TERMINALS: D G S 4 | M1 1 2 3 3 NMOS L = 1E-006 W = 1E-006 5 | RD 10 1 0.001735 6 | RS 30 3 1E-006 7 | RG 20 2 0.73 8 | CGS 2 3 4.893E-009 9 | EGD 12 0 2 1 1 10 | VFB 14 0 0 11 | FFB 2 1 VFB 1 12 | CGD 13 14 8.203E-009 13 | R1 13 0 1 14 | D1 12 13 DLIM 15 | DDG 15 14 DCGD 16 | R2 12 15 1 17 | D2 15 0 DLIM 18 | DSD 3 10 DSUB 19 | .MODEL NMOS NMOS LEVEL = 3 VMAX = 8E+005 ETA = 0.001 VTO = 0.8495 20 | + TOX = 6E-008 NSUB = 1E+016 KP = 404.4 U0 = 400 KAPPA = 4.441E-010 21 | .MODEL DCGD D CJO = 3.312E-009 VJ = 0.1775 M = 0.4588 22 | .MODEL DSUB D IS = 7.261E-009 N = 1.052 RS = 0.006412 BV = 28 CJO = 5.538E-010 VJ = 0.3369 M = 0.6764 23 | .MODEL DLIM D IS = 0.0001 24 | .ENDS 25 | *Diodes DMN2005UFG Spice Model v1.0 Last Revised 2018/2/1 -------------------------------------------------------------------------------- /models_source/diodes/mosfets/DMN2230U.spice.txt: -------------------------------------------------------------------------------- 1 | *SRC=DMN2230U;DI_DMN2230U;MOSFETs N;Enh;20.0V 2.00A 0.110ohms Diodes Inc MOSFET 2 | .MODEL DI_DMN2230U NMOS( LEVEL=1 VTO=1.00 KP=10.4 GAMMA=1.24 3 | + PHI=.75 LAMBDA=127u RD=15.4m RS=15.4m 4 | + IS=1.00p PB=0.800 MJ=0.460 CBD=46.4p 5 | + CBS=55.6p CGSO=360n CGDO=300n CGBO=1.22u ) 6 | * -- Assumes default L=100U W=100U -- -------------------------------------------------------------------------------- /models_source/diodes/mosfets/DMP2078LCA3.spice.txt: -------------------------------------------------------------------------------- 1 | *---------- DMP2078LCA3 Spice Model ---------- 2 | .SUBCKT DMP2078LCA3 10 20 30 3 | * TERMINALS: D G S 4 | M1 1 2 3 3 PMOS L = 1E-006 W = 1E-006 5 | RD 10 1 0.03918 6 | RS 30 3 0.001 7 | RG 20 2 21.22 8 | CGS 2 3 1.462E-010 9 | EGD 12 30 2 1 1 10 | VFB 14 30 0 11 | FFB 2 1 VFB 1 12 | CGD 13 14 9.5E-011 13 | R1 13 30 1 14 | D1 13 12 DLIM 15 | DDG 14 15 DCGD 16 | R2 12 15 1 17 | D2 30 15 DLIM 18 | DSD 10 3 DSUB 19 | .MODEL PMOS PMOS LEVEL = 3 U0 = 400 VMAX = 1E+006 ETA = 0.001 20 | + TOX = 6E-008 NSUB = 1E+016 KP = 8.672 KAPPA = 19.32 VTO = -0.9423 21 | .MODEL DCGD D CJO = 3.289E-011 VJ = 0.8 M = 0.7232 22 | .MODEL DSUB D IS = 3.857E-010 N = 1.293 RS = 0.06577 BV = 21.5 CJO = 2E-010 VJ = 0.8 M = 0.6 TT = 3.8E-009 23 | .MODEL DLIM D IS = 0.0001 24 | .MODEL LEGD D IS = 5E-009 N = 1.089 RS = 0.004 BV = 14 25 | .ENDS 26 | *Diodes DMP2078LCA3 Spice Model v1.0M Last Revised 2017/9/27 -------------------------------------------------------------------------------- /models_source/diodes/mosfets/index.py: -------------------------------------------------------------------------------- 1 | # DMG2301LK 2 | # https://www.diodes.com/products/discrete/mosfets/mosfet-master-table/p-channel/p-channel-8v-to-29v/part/DMG2301LK#tab-details 3 | Model('DMG2301LK', mod = ('DMG2301LK.spice.txt', '5372b8f86b12cbc09236')) 4 | 5 | # DMN2005UFG 6 | # https://www.diodes.com/products/discrete/mosfets/mosfet-master-table/n-channel/n-channel-8v-to-29v/part/DMN2005UFG 7 | Model('DMN2005UFG', mod = ('DMN2005UFG.spice.txt', 'aaed76f4ad0241577523')) 8 | 9 | # DMN2230U 10 | # https://www.diodes.com/products/discrete/mosfets/mosfet-master-table/n-channel/n-channel-8v-to-29v/part/DMN2230U 11 | Model('DMN2230U', mod = ('DMN2230U.spice.txt', '11d3f8937dbead07d164')) 12 | 13 | # DMP2078LCA3 14 | # https://www.diodes.com/products/discrete/mosfets/mosfet-master-table/p-channel/p-channel-8v-to-29v/part/DMP2078LCA3 15 | Model('DMP2078LCA3', mod = ('DMP2078LCA3.spice.txt', '5cdb865d1bdbe0977cf9')) 16 | 17 | -------------------------------------------------------------------------------- /models_source/onsemi/bjt/50A02CH-SPICE-D.diff: -------------------------------------------------------------------------------- 1 | Some spice engines do not work with modelnames that start with a number. 2 | 3 | Comment out the .LIB statements 4 | 5 | --- models_source/onsemi/bjt/50A02CH-SPICE-D.txt 2013-08-20 08:38:08.000000000 +0200 6 | +++ models/onsemi/bjt/50A02CH.lib 2018-08-29 21:26:48.057054604 +0200 7 | @@ -1,9 +1,9 @@ 8 | ********************** 50A02CH SPICE PARAMETER ************************* 9 | -.LIB 50A02CH 10 | +* .LIB 50A02CH 11 | * DATE : 2010/05/07 12 | * Temp = 27 deg 13 | 14 | -.MODEL 50A02CH pnp ( IS = 50.00f BF = 240 15 | +.MODEL Q_50A02CH pnp ( IS = 50.00f BF = 240 16 | +NF = 1 VAF = 3 IKF = 50.00m 17 | +ISE = 1.000p NE = 2 BR = 32 18 | +NR = 1 VAR = 30 IKR = 130.0m 19 | @@ -17,7 +17,7 @@ 20 | +XCJC = 1 TR = 1.000n FC = 500.0m 21 | +KF = 0 AF = 1 ) 22 | * 23 | -.ENDL 50A02CH 24 | +* .ENDL 50A02CH 25 | 26 | * Information herein is for example only; 27 | * it is not guaranteed for volume production. 28 | -------------------------------------------------------------------------------- /models_source/onsemi/bjt/50A02CH-SPICE-D.txt: -------------------------------------------------------------------------------- 1 | ********************** 50A02CH SPICE PARAMETER ************************* 2 | .LIB 50A02CH 3 | * DATE : 2010/05/07 4 | * Temp = 27 deg 5 | 6 | .MODEL 50A02CH pnp ( IS = 50.00f BF = 240 7 | +NF = 1 VAF = 3 IKF = 50.00m 8 | +ISE = 1.000p NE = 2 BR = 32 9 | +NR = 1 VAR = 30 IKR = 130.0m 10 | +ISC = 231.0p NC = 2 RB = 4.25 11 | +IRB = 40.00m RBM = 228.0m RE = 85.50m 12 | +RC = 90.00m XTB = 1.6 EG = 1.11 13 | +XTI = 3 CJE = 32.50p VJE = 700.0m 14 | +MJE = 360.0m TF = 190p XTF = 2 15 | +VTF = 1.000K ITF = 250m PTF = 0 16 | +CJC = 13.00p VJC = 500.0m MJC = 345.0m 17 | +XCJC = 1 TR = 1.000n FC = 500.0m 18 | +KF = 0 AF = 1 ) 19 | * 20 | .ENDL 50A02CH 21 | 22 | * Information herein is for example only; 23 | * it is not guaranteed for volume production. 24 | 25 | * ON Semiconductor 26 | -------------------------------------------------------------------------------- /models_source/onsemi/bjt/50C02CH_SPICE-D.LIB: -------------------------------------------------------------------------------- 1 | ************************* 50C02CH SPICE PARAMETER **************************** 2 | *.LIB 50C02CH 3 | * DATE : 2013/02/25 4 | * Temp = 27 deg 5 | * 6 | .MODEL 50C02CH npn ( IS = 80.00f BF = 600 7 | +NF = 1 VAF = 13 IKF = 50.00m 8 | +ISE = 15.00p NE = 2 BR = 110 9 | +NR = 1 VAR = 66 IKR = 120.0m 10 | +ISC = 174.0p NC = 2 RB = 7 11 | +IRB = 20.0m RBM = 141.0m RE = 87.00m 12 | +RC = 178.0m XTB = 1.4 EG = 1.11 13 | +XTI = 3 CJE = 36.50p VJE = 680.0m 14 | +MJE = 300.0m TF = 320p XTF = 10 15 | +VTF = 10 ITF = 4 PTF = 0 16 | +CJC = 7.700p VJC = 500.0m MJC = 200.0m 17 | +XCJC = 1 TR = 1.000n FC = 500.0m 18 | +KF = 0 AF = 1 ) 19 | * 20 | *.ENDL 50C02CH 21 | * 22 | * Information herein is for example only; 23 | * it is not guaranteed for volume production. 24 | * 25 | * ON Semiconductor -------------------------------------------------------------------------------- /models_source/onsemi/bjt/50C02CH_SPICE-D.diff: -------------------------------------------------------------------------------- 1 | Some spice engines do not work with modelnames that start with a number 2 | 3 | --- models_source/onsemi/bjt/50C02CH_SPICE-D.LIB 2018-08-29 21:23:39.009017607 +0200 4 | +++ models/onsemi/bjt/50C02CH.lib 2018-08-29 21:31:48.578758105 +0200 5 | @@ -3,7 +3,7 @@ 6 | * DATE : 2013/02/25 7 | * Temp = 27 deg 8 | * 9 | -.MODEL 50C02CH npn ( IS = 80.00f BF = 600 10 | +.MODEL Q_50C02CH npn ( IS = 80.00f BF = 600 11 | +NF = 1 VAF = 13 IKF = 50.00m 12 | +ISE = 15.00p NE = 2 BR = 110 13 | +NR = 1 VAR = 66 IKR = 120.0m 14 | -------------------------------------------------------------------------------- /models_source/onsemi/bjt/index.py: -------------------------------------------------------------------------------- 1 | # 50A02CH-SPICE/D Rev 1, May 2016 2 | # http://www.onsemi.com/pub/Collateral/50A02CH-SPICE-D.ZIP 3 | Model('50A02CH', 4 | mod = Patch('50A02CH-SPICE-D.txt', '50A02CH-SPICE-D.diff', 5 | 'c06817e942c8427ec8cc')) 6 | 7 | # 50C02CH_SPICE/D Rev 1, May 2016 8 | # http://www.onsemi.com/pub/Collateral/50C02CH_SPICE-D.LIB 9 | Model('50C02CH', 10 | mod = Patch('50C02CH_SPICE-D.LIB', '50C02CH_SPICE-D.diff', 11 | '2ec3c89b94aada46a930')) 12 | -------------------------------------------------------------------------------- /models_source/ti/op_amp/LMH6624.MOD: -------------------------------------------------------------------------------- 1 | *////////////////////////////////////////////////////////////////////// 2 | * (C) National Semiconductor, Corporation. 3 | * Models developed and under copyright by: 4 | * National Semiconductor, Corporation. 5 | *///////////////////////////////////////////////////////////////////// 6 | * Legal Notice: 7 | * The model may be copied, and distributed without any modifications; 8 | * however, reselling or licensing the material is illegal. 9 | * We reserve the right to make changes to the model without prior notice. 10 | * Pspice Models are provided "AS IS, WITH NO WARRANTY OF ANY KIND" 11 | *//////////////////////////////////////////////////////////////////// 12 | * For more information, and our latest models, 13 | * please visit the models section of our website at 14 | * http://www.national.com/models/ 15 | *//////////////////////////////////////////////////////////////////// 16 | * BEGIN MODEL LMH6624 17 | * PINOUT ORDER +IN -IN +V -V OUT 18 | * PINOUT ORDER 1 2 3 4 5 19 | .SUBCKT LMH6624 1 2 3 4 5 20 | * BEGIN MODEL PROGRAMMING 21 | * R40 SETS SLEW FOR +- 6.0 VOLT OPERATION 22 | R40 39 31 164 23 | * R40 SETS SLEW FOR +- 2.5 VOLT OPERATION 24 | *R40 39 31 183 25 | * TO PROGRAM FOR OTHER TOTAL SUPPLY VOLTAGES, 26 | * PROPORTION THE VALUE OF R40 BETWEEN THE 27 | * VALUES ABOVE 28 | * END MODEL PROGRAMMING 29 | Q17 4 6 7 QOP 30 | Q21 3 8 7 QON 31 | D5 5 3 DD 32 | D6 4 5 DD 33 | D7 9 0 DIN 34 | D8 10 0 DIN 35 | I8 0 9 0.1E-3 36 | I9 0 10 0.1E-3 37 | E2 11 0 4 0 1 38 | E3 12 0 3 0 1 39 | D9 13 0 DVN 40 | D10 14 0 DVN 41 | I10 0 13 2E-3 42 | I11 0 14 2E-3 43 | E4 15 2 13 14 0.4 44 | G2 1 15 9 10 1.05E-4 45 | R22 4 3 11.67E3 46 | E5 16 0 12 0 1 47 | E6 17 0 11 0 1 48 | E7 18 0 19 0 1 49 | R30 16 20 1E5 50 | R31 17 21 1E5 51 | R32 18 22 1E5 52 | R33 0 20 10 53 | R34 0 21 10 54 | R35 0 22 10 55 | E10 23 1 22 0 0.5 56 | R36 24 19 1E3 57 | R37 19 25 1E3 58 | C6 16 20 100E-12 59 | C7 17 21 2E-12 60 | C8 18 22 0.7E-12 61 | E11 26 23 21 0 0.095 62 | E12 27 26 20 0 0.02 63 | Q22 11 28 8 QDP 64 | Q23 12 28 6 QDN 65 | I12 3 4 10.37E-3 66 | I13 12 8 0.6E-3 67 | I14 6 11 0.6E-3 68 | R38 0 29 10 69 | R39 0 28 10 70 | C9 29 0 36E-12 71 | C10 28 0 12E-12 72 | E15 30 31 32 0 1 73 | E16 31 33 32 0 1 74 | E17 34 0 31 0 1 75 | D11 35 12 DD 76 | D12 11 36 DD 77 | V11 33 36 1.397 78 | V12 35 30 1.417 79 | I15 0 37 1E-3 80 | D13 37 0 DD 81 | V13 32 37 -0.6551 82 | C11 31 0 8.5E-12 83 | D14 38 39 DD 84 | D15 39 40 DD 85 | R41 0 39 225E3 86 | C12 15 0 1.8E-12 87 | C13 27 0 1.8E-12 88 | R43 7 41 3.5 89 | G3 29 0 31 0 0.1 90 | G4 28 0 29 0 0.1 91 | L1 41 5 4E-9 92 | R45 41 5 100 93 | E20 38 34 32 0 1 94 | E21 40 34 32 0 -1 95 | C15 15 27 2E-12 96 | G5 39 0 42 43 -7.5E-3 97 | R49 44 45 0.1 98 | R50 44 46 0.1 99 | I16 12 47 2E-3 100 | R51 42 48 333 101 | R52 43 48 333 102 | V14 44 49 0.65 103 | V15 12 48 -0.2 104 | C17 42 43 0.2E-12 105 | D18 50 51 DIC 106 | D19 27 51 DIC 107 | E25 25 0 1 0 1 108 | E26 24 0 15 0 1 109 | C18 5 0 0.1E-12 110 | R58 31 30 1E9 111 | R59 33 31 1E9 112 | R60 2 15 1E9 113 | R61 1 23 1E9 114 | R62 23 26 1E9 115 | R63 26 27 1E9 116 | V16 15 50 0.04E-3 117 | R64 34 40 1E9 118 | R65 34 38 1E9 119 | Q28 42 50 45 QIN 120 | Q29 43 27 46 QIN 121 | Q30 49 47 11 QIN 122 | Q31 47 47 11 QIN 123 | D20 11 50 DIC 124 | D21 11 27 DIC 125 | V17 12 51 1.0 126 | RN1 32 0 1E9 127 | .MODEL DD D 128 | .MODEL DVN D KF=1E-14 129 | .MODEL DIN D KF=26E-14 130 | .MODEL DIC D RS=50 131 | .MODEL QDP PNP 132 | .MODEL QDN NPN 133 | .MODEL QON NPN VAF=150 BF=250 IKF=1 RE=1 RC=9 134 | .MODEL QOP PNP VAF=150 BF=250 IKF=1 RE=1 RC=9 135 | .MODEL QIN NPN VAF=150 BF=90 IKF=0.005 RE=1 RC=1 136 | .ENDS 137 | * END MODEL LMH6624 138 | -------------------------------------------------------------------------------- /models_source/ti/op_amp/LMH6624.txt: -------------------------------------------------------------------------------- 1 | LMH6624 SPICE MODEL PERFORMANCE 2 | 3 | THIS FILE BEST VIEWED WITH WINDOWS NOTEPAD. 4 | 5 | MODEL FEATURES INCLUDE OUTPUT SWING, OUTPUT CURRENT THRU 6 | THE SUPPLY RAILS, GAIN AND PHASE, SLEW RATE, SLEW RATE 7 | VARIATION WITH GAIN, BODE PLOT VARIATION WITH TEMPER- 8 | ATURE, HIGH CLOAD DRIVE TO 33 PF, COMMON MODE REJECTION, 9 | POWER SUPPLY REJECTION ON BOTH RAILS, INPUT VOLTAGE 10 | NOISE WITH 1/F, INPUT CURRENT NOISE WITH 1/F, OUPUT 11 | IMPEDANCE, INPUT CAPACITANCE, INPUT BIAS CURRENT, 12 | INPUT COMMON MODE RANGE, INPUT OFFSET, INPUT CLAMPS 13 | TO THE RAIL, OUTPUT CLAMPS TO THE RAIL, AND QUIESCENT 14 | SUPPLY CURRENT. 15 | 16 | MODEL TEMP RANGE IS -40 TO +125 DEG C. 17 | 18 | NOTE THAT MODEL IS FUNCTIONAL OVER THIS RANGE BUT NOT ALL 19 | PARAMETERS TRACK THOSE OF THE REAL PART. 20 | 21 | SPEC MACRO DATA 22 | MODEL SHEET 23 | 24 | AVOL @ DC 82 82 DB 25 | 26 | AVOL/PHSE @ 1 MHZ 61/-84 62/-80 DB/DEG 27 | 28 | AVOL/PHSE @ 10 MHZ 41/-92 42/-92 DB/DEG 29 | 30 | AVOL/PHSE @ 100 MHZ 21/-113 22/-115 DB/DEG 31 | 32 | AVOL/PHSE @ 200 MHZ 14/-135 13/-139 DB/DEG 33 | 34 | 35 | INPUT V NOISE 10 HZ 10.4 11.0 NV/RHZ 36 | INPUT V NOISE 1 KHZ 1.4 1.3 NV/RHZ 37 | INPUT V NOISE 100 KHZ 0.9 0.9 NV/RHZ 38 | 39 | INPUT I NOISE 10 HZ 62 60 PA/RHZ 40 | INPUT I NOISE 1 KHZ 6.5 6.7 PA/RHZ 41 | INPUT I NOISE 100 KHZ 2.1 2.1 PA/RHZ 42 | 43 | 44 | SLEW RATE @ V= +- 6 398 400 V/US 45 | AND AVCL = +10 46 | 47 | SLEW RATE @ V= +-2.5 360 360 V/US 48 | AND AVCL = +10 49 | 50 | SLEW RATE @ V= +- 6 347 350 V/US 51 | AND AVCL = +20 52 | 53 | SLEW RATE @ V= +-2.5 308 300 V/US 54 | AND AVCL = +20 55 | 56 | 57 | RF=500: 58 | 59 | BANDWIDTH @ AVCL= +10 209 200 MHZ 60 | PEAKING @ AVCL= +10 0.4 0.8 DB 61 | 62 | BANDWIDTH @ AVCL= +20 79 100 MHZ 63 | 64 | BANDWIDTH @ AVCL= +30 46 57 MHZ 65 | 66 | BANDWIDTH @ AVCL=+200 5.8 6 MHZ 67 | 68 | 69 | AVCL=+10: 70 | 71 | PEAKING @ RF = 511 0.4 0.4 DB 72 | 73 | PEAKING @ RF = 750 1.0 0.9 DB 74 | 75 | PEAKING @ RF = 1000 1.5 2.0 DB 76 | 77 | PEAKING @ RF = 1500 2.5 2.5 DB 78 | 79 | PEAKING @ RF = 2000 3.3 2.8 DB 80 | 81 | 82 | CLOAD: 83 | 84 | PEAKING @ CL= 0 PF 0.6 1.0 DB 85 | 86 | PEAKING @ CL= 15 PF 2.5 2.0 DB 87 | 88 | PEAKING @ CL= 33 PF 3.1 3.0 DB 89 | 90 | 91 | INPUT BIAS CURRENT 12.6 13 UA 92 | 93 | VOS 0.1 0.1 MV 94 | 95 | SWING AT RL=100 OHM +-4.9 +-4.9 V 96 | 97 | SWING AT IO=100 MA +-4.3 +-4.3 V 98 | 99 | IOUT MAX 140 150 MA 100 | 101 | IQ @ +- 6.0V 12.0 12.0 MA 102 | 103 | IQ @ +- 2.5V 11.4 11.4 MA 104 | 105 | CMRR , F ZERO 80,1 80,1 DB,MHZ 106 | 107 | PSRRP , F ZERO 92,30 94,30 DB,KHZ 108 | 109 | PSRRN , F ZERO 86,300 86,300 DB,KHZ 110 | -------------------------------------------------------------------------------- /models_source/ti/op_amp/LMH6702.MOD: -------------------------------------------------------------------------------- 1 | *////////////////////////////////////////////////////////////////////// 2 | * (C) National Semiconductor, Corporation. 3 | * Models developed and under copyright by: 4 | * National Semiconductor, Corporation. 5 | *///////////////////////////////////////////////////////////////////// 6 | * Legal Notice: 7 | * The model may be copied, and distributed without any modifications; 8 | * however, reselling or licensing the material is illegal. 9 | * We reserve the right to make changes to the model without prior notice. 10 | * Pspice Models are provided "AS IS, WITH NO WARRANTY OF ANY KIND" 11 | *//////////////////////////////////////////////////////////////////// 12 | * For more information, and our latest models, 13 | * please visit the models section of our website at 14 | * http://www.national.com/models/ 15 | *//////////////////////////////////////////////////////////////////// 16 | * BEGIN MODEL LMH6702 17 | * PINOUT ORDER +IN -IN +V -V OUT 18 | * PINOUT ORDER 3 4 5 2 1 19 | .SUBCKT LMH6702 3 4 5 2 1 20 | * 21 | ******* IMPORTANT NOTE ******* 22 | * RESISTOR R42 BELOW MUST BE VARIED DEPENDING ON 23 | * AMPLIFIER CONFIGURATION FOR ACCURATE BANDWIDTH. 24 | * IF THE AMPLIFIER IS USED IN A NON-INVERTING 25 | * CONFIGURATION R42 SHOULD BE 80 OHMS. IN AN 26 | * INVERTING CONFIGURATION R42 SHOULD BE 33 OHMS. 27 | * RESISTOR VALUE IS NOW SET FOR NON-INVERTING. 28 | ****************************** 29 | * 30 | R42 39 41 80 31 | * 32 | ****************************** 33 | R30 16 20 1E4 34 | R31 17 21 1E4 35 | R32 18 22 1E4 36 | R33 0 20 1 37 | R34 0 21 1 38 | R35 0 22 1 39 | E10 23 3 22 0 0.15 40 | C6 16 20 15E-12 41 | C7 17 21 15E-12 42 | C8 18 22 0.1E-12 43 | E11 24 23 21 0 4.3 44 | E12 25 24 20 0 3 45 | Q22 11 26 8 QDP 46 | Q23 12 26 6 QDN 47 | I12 5 2 11.74E-3 48 | I13 12 8 0.8E-3 49 | I14 6 11 0.8E-3 50 | R38 0 27 10 51 | R39 0 26 10 52 | C9 27 0 10E-12 53 | C10 26 0 4E-12 54 | Q17 2 6 7 QOP 55 | Q21 5 8 7 QON 56 | D5 1 5 DD 57 | D6 2 1 DD 58 | D7 9 0 DIP 59 | D8 10 0 DIP 60 | I8 0 9 0.1E-3 61 | I9 0 10 0.1E-3 62 | E2 11 0 2 0 1 63 | E3 12 0 5 0 1 64 | D9 13 0 DVN 65 | D10 14 0 DVN 66 | I10 0 13 0.1M 67 | I11 0 14 0.1M 68 | E4 15 4 13 14 0.8 69 | G2 3 0 9 10 1.45E-3 70 | R22 2 5 200E3 71 | E5 16 0 12 0 1 72 | E6 17 0 11 0 1 73 | E7 18 0 19 0 1 74 | E15 28 29 30 0 1 75 | E16 29 31 30 0 1 76 | E17 32 0 29 0 1 77 | D11 33 12 DD 78 | D12 11 34 DD 79 | V11 31 34 2 80 | V12 33 28 2 81 | I15 0 35 1M 82 | D13 35 0 DD 83 | V13 30 35 -0.71465 84 | C11 29 0 2.5E-12 85 | D14 36 37 DD 86 | D15 37 38 DD 87 | R40 37 29 92 88 | R41 0 37 2E5 89 | F1 37 0 V14 -2.6 90 | E18 39 0 40 0 0.998 91 | C12 15 0 0.4E-12 92 | C13 25 0 1.6E-12 93 | V14 41 42 0 94 | R43 7 43 1.5 95 | G3 27 0 29 0 0.1 96 | G4 26 0 27 0 0.1 97 | C14 7 0 2E-12 98 | L1 43 1 2N 99 | R45 43 1 100 100 | E20 36 32 30 0 1 101 | E21 38 32 30 0 -1 102 | I16 15 0 -8E-6 103 | I17 25 0 -6E-6 104 | V15 40 25 1E-3 105 | D16 44 0 DIN 106 | D17 45 0 DIN 107 | I18 0 44 0.1E-3 108 | I19 0 45 0.1E-3 109 | G5 4 0 44 45 9.7E-3 110 | E22 46 0 15 0 1 111 | E23 47 0 3 0 1 112 | R46 46 19 1E3 113 | R47 19 47 1E3 114 | R48 19 0 1E6 115 | R49 3 23 1E9 116 | R50 23 24 1E9 117 | R51 24 25 1E9 118 | R52 48 29 1E9 119 | R53 0 48 1E9 120 | R54 0 29 1E9 121 | R55 0 38 1E9 122 | R56 0 36 1E9 123 | R57 30 0 1E9 124 | L4 15 42 1N 125 | R63 15 42 100 126 | C16 15 25 0.1E-12 127 | V17 12 49 3.17 128 | V18 50 11 3.17 129 | J1 49 15 49 JI 130 | J2 49 25 49 JI 131 | J3 15 50 15 JI 132 | J4 25 50 25 JI 133 | RG1 40 0 1E9 134 | .MODEL QDP PNP 135 | .MODEL QDN NPN 136 | .MODEL DD D 137 | .MODEL JI NJF IS=1E-18 RD=100 RS=100 138 | .MODEL DC D IS=5.002E-16 139 | .MODEL DVN D KF=1.1E-15 140 | .MODEL DIP D KF=4E-15 141 | .MODEL DIN D KF=3.4E-15 142 | .MODEL QON NPN VAF=150 BF=150 IKF=0.7 RE=2 RC=1 143 | .MODEL QOP PNP VAF=150 BF=150 IKF=0.7 RE=2 RC=1 144 | .ENDS 145 | * END MODEL LMH6702 146 | -------------------------------------------------------------------------------- /models_source/ti/op_amp/LMH6702.txt: -------------------------------------------------------------------------------- 1 | LMH6702 SPICE MODEL PERFORMANCE 2 | 3 | MODEL FEATURES INCLUDE OUTPUT SWING, OUTPUT CURRENT THRU 4 | THE SUPPLY RAILS, GAIN AND PHASE, SLEW RATE, COMMON MODE 5 | REJECTION WITH FREQUENCY EFFECTS, POWER SUPPLY REJECTION 6 | ON BOTH RAILS WITH FREQUENCY EFFECTS, INPUT VOLTAGE NOISE 7 | WITH 1/F,INPUT CURRENT NOISE WITH 1/F ON THE INVERTING 8 | INPUT, INPUT CURRENT NOISE WITH 1/F ON THE NON-INVERTING 9 | INPUT, INPUT CAPACITANCE, INPUT BIAS CURRENT, OFFSET 10 | VOLTAGE, OUTPUT SWING, OUTPUT IMPEDANCE VS FREQUENCY, 11 | AND QUIESCENT CURRENT. 12 | 13 | MODEL TEMP RANGE IS -40 TO +85 DEG C. 14 | 15 | NOTE THAT MODEL IS FUNCTIONAL OVER THIS RANGE BUT NOT ALL 16 | PARAMETERS TRACK THOSE OF THE REAL PART. 17 | 18 | 19 | SPEC MACRO DATA 20 | MODEL SHEET 21 | 22 | 23 | -3DB BW @ AVCL= +1 794 700 MHZ 24 | 25 | PEAKING @ AVCL= +1 0.3 0.9 DB 26 | 27 | -3DB BW @ AVCL= +2 575 700 MHZ 28 | 29 | PEAKING @ AVCL= +2 0 0 DB 30 | 31 | -3DB BW @ AVCL= +4 346 330 MHZ 32 | 33 | -3DB BW @ AVCL= +10 151 145 MHZ 34 | 35 | 36 | -3DB BW @ AVCL= -1 831 880 MHZ 37 | 38 | PEAKING @ AVCL= -1 0.2 0 DB 39 | 40 | -3DB BW @ AVCL= -2 724 720 MHZ 41 | 42 | PEAKING @ AVCL= -2 0.02 0 DB 43 | 44 | -3DB BW @ AVCL= -4 575 570 MHZ 45 | 46 | -3DB BW @ AVCL= -10 316 380 MHZ 47 | 48 | 49 | CMRR @ 1KHZ -48 -48 DB 50 | 51 | CMRR @ 10MHZ -40 -42 DB 52 | 53 | CMRR @ 100MHZ -20 -20 DB 54 | 55 | 56 | PSRRP @ 1KHZ -64 -55 DB 57 | 58 | PSRRP @ 10MHZ -45 -44 DB 59 | 60 | PSRRP @ 100MHZ -25 -21 DB 61 | 62 | 63 | PSRRN @ 1KHZ -61 -52 DB 64 | 65 | PSRRN @ 10MHZ -42 -42 DB 66 | 67 | PSRRN @ 100MHZ -22 -21 DB 68 | 69 | 70 | 71 | INPUT VOLTAGE NOISE 9.9 9.5 NV/RHZ 72 | @ 100 HZ 73 | 74 | INPUT VOLTAGE NOISE 2 2 NV/RHZ 75 | @ 10 MHZ 76 | 77 | +INPUT CURR NOISE 34 35 PA/RHZ 78 | @ 100 HZ 79 | 80 | +INPUT CURR NOISE 3 3 PA/RHZ 81 | @ 10 MHZ 82 | 83 | -INPUT CURR NOISE 208 210 PA/RHZ 84 | @ 100 HZ 85 | 86 | 1INPUT CURR NOISE 20 19 PA/RHZ 87 | @ 10 MHZ 88 | 89 | 90 | INPUT BIAS CURRENT + -6 -6 UA 91 | 92 | INPUT BIAS CURRENT - -8 -8 UA 93 | 94 | VOS 1 1 MV 95 | 96 | SLEW RATE 3.08 3.10 V/NS 97 | 98 | INPUT COMMON MODE +-2.2 +-2.2 VOLTS 99 | VOLTAGE RANGE 100 | 101 | INPUT CLAMP DIODES YES YES 102 | 103 | OUTPUT CLAMP DIODES YES YES 104 | 105 | SWING AT RL=100 +-3.45 +-3.50 VOLT 106 | 107 | OUTPUT CURRENT MAX +-80 +-80 MA 108 | 109 | IQ 12.5 12.5 MA 110 | -------------------------------------------------------------------------------- /models_source/ti/op_amp/LMV981.MOD: -------------------------------------------------------------------------------- 1 | *Rev-B, March-2010 2 | *Modified notes 3 | * 4 | *////////////////////////////////////////////////////////////////////// 5 | * (C) National Semiconductor, Corporation. 6 | * Models developed and under copyright by: 7 | * National Semiconductor, Corporation. 8 | *///////////////////////////////////////////////////////////////////// 9 | * Legal Notice: 10 | * The model may be copied, and distributed without any modifications; 11 | * however, reselling or licensing the material is illegal. 12 | * We reserve the right to make changes to the model without prior notice. 13 | * Pspice Models are provided "AS IS, WITH NO WARRANTY OF ANY KIND" 14 | *//////////////////////////////////////////////////////////////////// 15 | * For more information, and our latest models, 16 | * please visit the models section of our website at 17 | * http://www.national.com/models/ 18 | *//////////////////////////////////////////////////////////////////// 19 | * BEGIN LMV981 MODEL 20 | * MODEL TEMPERATURE RANGE IS -40 C TO +125 C, NOT ALL PARAMETERS TRACK THOSE 21 | * OF THE REAL PART VS TEMPERATURE 22 | * FEATURES: 23 | * OPEN LOOP GAIN AND PHASE, INPUT BIAS CURRENT, INPUT CAPACITANCE 24 | * INPUT COMMON MODE VOLT RANGE, RAIL TO RAIL INPUT STAGE, WITH OFFSET TRANSITION 25 | * INPUT CLAMPS TO RAILS, CMRR WITH FREQUENCY EFFECTS, PSRR WITH FREQUENCY 26 | * EFFECTS, SLEW RATE, QUIESCENT CURRENT, RAIL TO RAIL OUTPUT STAGE, HIGH CLOAD 27 | * EFFECTS, CLASS AB BIAS IN OUTPUT STAGE, OUTPUT CURRENT THROUGH SUPPLIES 28 | * OUTPUT CURRENT LIMITING, OUTPUT CLAMPS TO RAILS, OUTPUT SWING VS OUTPUT CURRENT 29 | * SHUTDOWN, ENABLE TIME, QUIESCENT CURRENT DURING SHUTDOWN 30 | */////////////////////////////////////////////////////////////////////////// 31 | * 32 | * PINOUT ORDER +IN -IN +V -V OUT NSD 33 | * PINOUT ORDER 1 3 6 2 4 5 34 | .SUBCKT LMV981 1 3 6 2 4 5 35 | Q20 7 8 9 QLN 36 | R3 10 11 2 37 | R4 12 11 2 38 | R10 8 13 1E3 39 | R11 14 15 1E3 40 | R12 16 6 4 41 | R13 2 17 4 42 | R16 18 19 300 43 | R17 20 21 4 44 | R18 9 22 4 45 | D5 23 6 DD 46 | D6 2 23 DD 47 | D7 24 0 DIN 48 | D8 25 0 DIN 49 | I8 0 24 0.1E-3 50 | I9 0 25 0.1E-3 51 | E2 9 0 2 0 1 52 | E3 21 0 6 0 1 53 | D9 26 0 DVN 54 | D10 27 0 DVN 55 | I10 0 26 0.1E-3 56 | I11 0 27 0.1E-3 57 | E4 28 3 26 27 0.08 58 | G2 29 3 24 25 4E-5 59 | R22 2 6 100E6 60 | E5 30 0 21 0 1 61 | E6 31 0 9 0 1 62 | E7 32 0 33 0 1 63 | R30 30 34 1E5 64 | R31 31 35 1E5 65 | R32 32 36 1E5 66 | R33 0 34 10 67 | R34 0 35 10 68 | R35 0 36 10 69 | E10 37 1 36 0 0.3 70 | R36 38 33 1K 71 | R37 33 39 1K 72 | C6 30 34 1E-12 73 | C7 31 35 2E-12 74 | C8 32 36 200E-12 75 | E11 40 37 35 0 1.2 76 | E12 29 40 34 0 0.8 77 | E14 41 9 21 9 0.5 78 | D11 18 21 DD 79 | D12 9 18 DD 80 | M1 42 43 17 17 NOUT L=3U W=700U 81 | M2 44 45 16 16 POUT L=3U W=1400U 82 | M3 46 46 20 20 POUT L=3U W=1400U 83 | M4 47 48 10 10 PIN L=3U W=220U 84 | M5 49 50 12 12 PIN L=3U W=220U 85 | M8 51 51 22 22 NOUT L=3U W=700U 86 | R43 52 45 100 87 | R44 53 43 100 88 | G3 18 41 54 41 0.2E-3 89 | R45 41 18 60E6 90 | C12 19 23 33E-12 91 | R46 9 47 2E3 92 | R47 9 49 2E3 93 | C13 47 49 1E-12 94 | C14 29 0 3E-12 95 | C15 28 0 3E-12 96 | C16 23 0 0.5E-12 97 | D13 43 7 DD 98 | D14 55 45 DD 99 | Q15 55 15 21 QLP 100 | V18 29 56 1E-3 101 | M19 57 58 21 21 PIN L=6U W=500U 102 | E17 39 0 29 0 1 103 | E18 38 0 3 0 1 104 | M23 58 58 21 21 PIN L=6U W=500U 105 | V21 57 11 0 106 | R59 23 44 20 107 | R60 42 23 20 108 | J1 59 29 59 JNC 109 | J2 59 28 59 JNC 110 | J3 28 60 28 JNC 111 | J4 29 60 29 JNC 112 | C21 29 61 1E-12 113 | E20 62 41 49 47 1 114 | R62 62 54 1E4 115 | C23 54 41 5E-12 116 | G7 63 41 18 41 -1E-3 117 | G8 41 64 18 41 1E-3 118 | G9 41 65 51 9 1E-3 119 | G10 66 41 21 46 1E-3 120 | D17 66 63 DD 121 | D18 64 65 DD 122 | R66 63 66 100E6 123 | R67 65 64 100E6 124 | R68 66 21 1E3 125 | R69 9 65 1E3 126 | E23 21 52 21 66 1 127 | E24 53 9 65 9 1 128 | R70 64 41 1E6 129 | R71 65 41 1E6 130 | R72 41 66 1E6 131 | R73 41 63 1E6 132 | G11 6 2 67 0 -0.1E-3 133 | R75 40 29 1E9 134 | R76 37 40 1E9 135 | R77 1 37 1E9 136 | R78 3 28 1E9 137 | R79 41 54 1E9 138 | R81 52 21 1E9 139 | R82 9 53 1E9 140 | R83 33 0 1E9 141 | G14 58 9 67 0 35E-6 142 | G15 46 51 67 0 220E-6 143 | E48 68 18 67 0 30 144 | E49 69 41 67 0 -30 145 | V49 70 69 15 146 | V50 71 68 -15 147 | R127 68 0 1E12 148 | R128 69 0 1E12 149 | M41 41 71 18 72 PSW L=1.5U W=150U 150 | M42 18 70 41 73 NSW L=1.5U 151 | R129 72 0 1E12 152 | R130 73 0 1E12 153 | M43 74 5 9 9 NEN L=3U W=300U 154 | M44 75 76 9 9 NEN L=3U W=3000U 155 | R131 74 21 1E4 156 | R132 75 77 1E6 157 | V51 77 9 1 158 | M45 78 78 21 21 PEN L=6U W=60U 159 | M46 5 78 21 21 PEN L=6U W=60U 160 | I20 78 9 0.2E-6 161 | C26 5 0 1E-12 162 | E50 67 0 79 9 1 163 | V52 75 79 1.111E-6 164 | R133 9 79 1E12 165 | C32 21 74 15E-12 166 | C33 77 75 3F 167 | I21 6 2 0.2E-6 168 | L1 23 4 4E-9 169 | R150 23 4 400 170 | V78 21 59 0.05 171 | V79 60 9 0.05 172 | R155 46 21 1E8 173 | R156 9 51 1E8 174 | R157 17 43 1E8 175 | R158 16 45 1E8 176 | RG1 0 67 1E9 177 | R159 61 28 100 178 | R225 50 28 64 179 | R226 48 56 64 180 | I40 28 0 15E-9 181 | I47 29 0 15E-9 182 | M48 80 81 2 2 NIQS L=3U W=1000 183 | R297 80 6 8E6 184 | E94 81 2 67 0 2 185 | M49 82 74 9 9 NEN L=3U W=300U 186 | M50 76 82 9 9 NEN L=3U W=300U 187 | R298 82 77 1E4 188 | R299 76 77 1E4 189 | C35 77 82 535P 190 | M51 83 84 85 85 NIN L=3U W=220U 191 | M52 86 87 88 88 NIN L=3U W=220U 192 | R300 89 85 2 193 | R301 89 88 2 194 | R302 83 21 2E3 195 | R303 86 21 2E3 196 | C36 83 86 1E-12 197 | G36 18 41 90 41 0.2E-3 198 | R304 41 90 1E9 199 | C37 90 41 5E-12 200 | E97 91 41 86 83 1 201 | R305 91 90 1E4 202 | V115 92 56 0.25E-3 203 | R306 28 87 64 204 | R307 92 84 64 205 | M53 93 94 95 95 PIN L=6U W=500U 206 | R308 95 57 2E3 207 | V116 21 94 1.0 208 | M54 93 93 9 9 NIN L=3U W=500U 209 | M55 89 93 9 9 NIN L=3U W=500U 210 | E98 21 14 6 16 0.9 211 | E99 13 9 17 2 3 212 | .MODEL DVN D KF=8E-12 IS=1E-16 213 | .MODEL DD D 214 | .MODEL DIN D 215 | .MODEL QLN NPN 216 | .MODEL QLP PNP 217 | .MODEL JNC NJF 218 | .MODEL POUT PMOS KP=200U VTO=-0.7 219 | .MODEL NOUT NMOS KP=200U VTO=0.7 220 | .MODEL PIN PMOS KP=200U VTO=-0.7 221 | .MODEL NIN NMOS KP=200U VTO=0.7 222 | .MODEL NIQS NMOS KP=200U VTO=0.7 IS=1E-18 223 | .MODEL NEN NMOS KP=200U VTO=0.5 IS=1E-18 224 | .MODEL PEN PMOS KP=200U VTO=-0.7 IS=1E-18 225 | .MODEL PSW PMOS KP=200U VTO=-7.5 IS=1E-18 226 | .MODEL NSW NMOS KP=200U VTO=7.5 IS=1E-18 227 | .ENDS 228 | * END LMV981 MODEL 229 | -------------------------------------------------------------------------------- /models_source/ti/op_amp/LMV981.txt: -------------------------------------------------------------------------------- 1 | LMV981 SPICE MODEL PERFORMANCE 2 | 3 | MODEL FEATURES INCLUDE OPEN LOOP GAIN AND PHASE, INPUT 4 | VOLTAGE NOISE W 1/F, INPUT CURRENT NOISE, INPUT BIAS 5 | CURRENT, INPUT CAPACITANCE, INPUT COMMON MODE VOLT RANGE, 6 | RAIL TO RAIL INPUT STAGE WITH OFFSET TRANSITION, INPUT 7 | CLAMPS TO RAILS, CMRR WITH FREQUENCY EFFECTS, PSRR WITH 8 | FREQUENCY EFFECTS, SLEW RATE, QUIESCENT CURRENT, RAIL TO 9 | RAIL OUTPUT STAGE, HIGH CLOAD EFFECTS, CLASS AB BIAS IN 10 | OUTPUT STAGE, OUTPUT CURRENT THROUGH SUPPLIES, OUTPUT 11 | CURRENT LIMITING, OUTPUT CLAMPS TO RAILS, OUTPUT SWING 12 | VS OUTPUT CURRENT, SHUTDOWN, ENABLE TIME, AND QUIESCENT 13 | CURRENT DURING SHUTDOWN. 14 | 15 | MODEL TEMP RANGE IS -40 TO +125 DEG C. 16 | 17 | NOTE THAT THE MODEL IS FUNCTIONAL OVER THIS RANGE BUT NOT 18 | ALL PARAMETERS TRACK THOSE OF THE REAL PART. 19 | 20 | 21 | SPEC MACRO DATA 22 | MODEL SHEET 23 | 24 | 25 | SUPPLY VOLT RANGE 1.8 TO 5.5 1.8 TO 5.5 VOLTS 26 | 27 | INPUT COMMON MODE (V+)+0.2 (V+)+0.2 VOLTS 28 | VOLTAGE RANGE (V-)-0.2 (V-)-0.2 29 | 30 | INPUT CLAMP DIODES YES YES 31 | 32 | OUTPUT CLAMP DIODES YES YES 33 | 34 | INPUT VNSE @ 10 HZ 260 260 NV/RHZ 35 | INPUT VNSE @ 30 KHZ 20 17 NV/RHZ 36 | 37 | INPUT INSE 82 82 FA/RHZ 38 | 39 | AVOL @ RL=600 101 101 DB 40 | 41 | GAIN-BANDWIDTH 1.4 1.4 MHZ 42 | 43 | CMRR -84/2.5KHZ -84/2.5KHZ DB/ZERO 44 | 45 | PSRR+ -82/200HZ -82/200HZ DB/ZERO 46 | 47 | PSRR- -78/200HZ -78/200HZ DB/ZERO 48 | 49 | INPUT BIAS CURRENT 15 15 NA 50 | 51 | SLEW RATE 0.42 0.42 V/US 52 | 53 | VOS 1 1 MV 54 | 55 | VOS @ HIGH VCM 0.75 0.75 MV 56 | 57 | VOS TRANSITION (+V)-1.0 (+V)-1.0 V 58 | 59 | SWING AT RL=600 +0.12/-0.13 +0.15/-0.12 V 60 | 61 | SWING AT RL=2K +0.04/-0.05 +0.05/-0.04 V 62 | 63 | ISC +86/-71 +80/-65 MA 64 | 65 | IQ 0.13 0.13 MA 66 | 67 | IQ @ SHUTDOWN 0.25 0.25 UA 68 | 69 | SHUTDOWN THRESH 0.8 0.8 V 70 | REL TO -V 71 | 72 | SHUTDOWN RECOVERY 8.4 8.4 US 73 | TIME 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /models_source/ti/op_amp/OPA695_PSPICE_MODEL.diff: -------------------------------------------------------------------------------- 1 | Fix model so that it works with Xyce and ngspice 2 | 3 | Xyce gets confused when a node name in an expression contains + or -; 4 | rename + -> INP, - -> INN, V+ - VCC, V- -> VEE. 5 | 6 | ngspice treats $ as an inline comment; rename $N_foo to N_foo. 7 | 8 | ngspice has does not understand the switch model syntax used for 9 | OPA695_model_S1; hardcode the switch resistances. 10 | 11 | ngspice expects the PNP transistor area to be specified as area=value 12 | while other simulators expect only the number. Add an _AREA define 13 | which evaluates to area=. 14 | 15 | --- models_source/ti/op_amp/OPA695_PSPICE_MODEL.txt 2018-08-29 02:20:26.379136632 +0200 16 | +++ models/ti/op_amp/OPA695.lib 2018-08-29 04:11:29.479772707 +0200 17 | @@ -29,11 +29,17 @@ 18 | * input voltage range, input voltage offset and output voltage range. 19 | ******************************************************************************** 20 | 21 | -.SUBCKT OPA695 + - V+ V- Out DisA 22 | -X1 + - DisA Out V+ V- OPA695_model 23 | +.SUBCKT OPA695 INP INN VCC VEE Out DisA 24 | +X1 INP INN DisA Out VCC VEE OPA695_model 25 | .ENDS 26 | 27 | -.SUBCKT OPA695_model + - Dis OUT V+ V- 28 | +#ifdef NGSPICE 29 | +#define _AREA area= 30 | +#else 31 | +#define _AREA 32 | +#endif 33 | + 34 | +.SUBCKT OPA695_model INP INN Dis OUT VCC VEE 35 | 36 | .PARAM x1 = {1/8} 37 | .PARAM x2 = {x1*2} 38 | @@ -44,85 +50,90 @@ 39 | .PARAM x60 = {x1*60} 40 | 41 | C_C1 Vmid Dis 2p 42 | -X_S1 $N_0001 0 $N_0002 $N_0003 OPA695_model_S1 43 | +#ifdef NGSPICE 44 | +R_S1A N_0001 0 1e9 45 | +R_S1B N_0002 N_0003 0.001 46 | +#else 47 | +X_S1 N_0001 0 N_0002 N_0003 OPA695_model_S1 48 | +#endif 49 | R_R11 Vmid Dis 100MEG 50 | -R_R8 Vmid $N_0004 10k 51 | -Q_Q1 $N_0006 $N_0005 $N_0007 PNP8 {x1} 52 | -Q_Q4 $N_0008 $N_0008 $N_0005 NPN8 {x1} 53 | -Q_Q5 $N_0009 $N_0005 $N_0010 PNP8 {x2} 54 | -Q_Q12 $N_0011 $N_0005 $N_0012 PNP8 {x2} 55 | -Q_Q9 $N_0013 $N_0005 $N_0014 PNP8 {x2} 56 | -Q_Q7 $N_0015 $N_0015 $N_0016 NPN8 {x2} 57 | -Q_Q6 $N_0015 $N_0017 $N_0009 PNP8 {x16} 58 | -Q_Q14 $N_0011 $N_0017 $N_0018 NPN8 {x1} 59 | -Q_Q16 $N_0017 $N_0018 $N_0019 NPN8 {x1} 60 | -Q_Q15 $N_0018 $N_0018 $N_0020 NPN8 {x1} 61 | -Q_Q10 $N_0011 $N_0011 $N_0021 NPN8 {x16} 62 | -Q_Q8 $N_0013 $N_0015 $N_0022 NPN8 {x2} 63 | -D_D3 $N_0023 $N_0021 DX 1 64 | -D_D1 $N_0021 $N_0024 DX 1 65 | -D_D2 $N_0024 $N_0025 DX 1 66 | -Q_Q18 $N_0026 $N_0026 $N_0021 PNP8 {x16} 67 | -Q_Q17 $N_0026 $N_0015 $N_0027 NPN8 {x2} 68 | -R_R24 V- $N_0028 250 69 | -X_F1 $N_0002 $N_0029 $N_0006 V- OPA695_model_F1 70 | -Q_Q2 V- $N_0006 $N_0005 PNP8 {x1} 71 | -R_R18 V- $N_0015 50k 72 | -R_R20 V- $N_0022 500 73 | -R_R19 V- $N_0016 500 74 | -R_R21 V- $N_0019 2k 75 | -R_R22 V- $N_0020 2k 76 | -R_R23 V- $N_0027 500 77 | -D_D5 $N_0028 V- DX 1 78 | -Q_Q20 $N_0030 $N_0030 $N_0028 NPN8 {x3} 79 | -Q_Q19 $N_0030 $N_0026 $N_0025 PNP8 {x16} 80 | -Q_Q25 $N_0031 $N_0030 $N_0032 NPN8 {x12} 81 | -Q_Q24 $N_0034 $N_0033 $N_0035 PNP8 {x12} 82 | -R_R10 V+ V- 123.609k 83 | -E_E1 $N_0004 V- V+ V- 0.5 84 | -E_ABM21 $N_0001 0 VALUE { ( V(Dis) 85 | -+ / (V(V+) 86 | +R_R8 Vmid N_0004 10k 87 | +Q_Q1 N_0006 N_0005 N_0007 PNP8 _AREA{x1} 88 | +Q_Q4 N_0008 N_0008 N_0005 NPN8 _AREA{x1} 89 | +Q_Q5 N_0009 N_0005 N_0010 PNP8 _AREA{x2} 90 | +Q_Q12 N_0011 N_0005 N_0012 PNP8 _AREA{x2} 91 | +Q_Q9 N_0013 N_0005 N_0014 PNP8 _AREA{x2} 92 | +Q_Q7 N_0015 N_0015 N_0016 NPN8 _AREA{x2} 93 | +Q_Q6 N_0015 N_0017 N_0009 PNP8 _AREA{x16} 94 | +Q_Q14 N_0011 N_0017 N_0018 NPN8 _AREA{x1} 95 | +Q_Q16 N_0017 N_0018 N_0019 NPN8 _AREA{x1} 96 | +Q_Q15 N_0018 N_0018 N_0020 NPN8 _AREA{x1} 97 | +Q_Q10 N_0011 N_0011 N_0021 NPN8 _AREA{x16} 98 | +Q_Q8 N_0013 N_0015 N_0022 NPN8 _AREA{x2} 99 | +D_D3 N_0023 N_0021 DX 1 100 | +D_D1 N_0021 N_0024 DX 1 101 | +D_D2 N_0024 N_0025 DX 1 102 | +Q_Q18 N_0026 N_0026 N_0021 PNP8 _AREA{x16} 103 | +Q_Q17 N_0026 N_0015 N_0027 NPN8 _AREA{x2} 104 | +R_R24 VEE N_0028 250 105 | +X_F1 N_0002 N_0029 N_0006 VEE OPA695_model_F1 106 | +Q_Q2 VEE N_0006 N_0005 PNP8 _AREA{x1} 107 | +R_R18 VEE N_0015 50k 108 | +R_R20 VEE N_0022 500 109 | +R_R19 VEE N_0016 500 110 | +R_R21 VEE N_0019 2k 111 | +R_R22 VEE N_0020 2k 112 | +R_R23 VEE N_0027 500 113 | +D_D5 N_0028 VEE DX 1 114 | +Q_Q20 N_0030 N_0030 N_0028 NPN8 _AREA{x3} 115 | +Q_Q19 N_0030 N_0026 N_0025 PNP8 _AREA{x16} 116 | +Q_Q25 N_0031 N_0030 N_0032 NPN8 _AREA{x12} 117 | +Q_Q24 N_0034 N_0033 N_0035 PNP8 _AREA{x12} 118 | +R_R10 VCC VEE 123.609k 119 | +E_E1 N_0004 VEE VCC VEE 0.5 120 | +E_ABM21 N_0001 0 VALUE={ ( V(Dis) 121 | ++ / (V(VCC) 122 | + + 1e-6) ) * 5.0 } 123 | -R_R9 Dis V+ 41k 124 | -R_R12 $N_0008 V+ 8k 125 | -R_R14 $N_0010 V+ 500 126 | -R_R15 $N_0014 V+ 500 127 | -R_R16 $N_0012 V+ 500 128 | -R_R17 $N_0006 V+ 72k 129 | -R_R13 $N_0007 V+ 1987 130 | -Q_Q21 $N_0036 $N_0030 $N_0037 NPN8 {x5} 131 | -R_R7 $N_0029 Vmid 10k 132 | -R_R25 V- $N_0037 150 133 | -D_D7 V+ $N_0038 DX 1 134 | -R_R26 $N_0038 V+ 250 135 | -Q_Q22 $N_0033 $N_0033 $N_0038 PNP8 {x3} 136 | -R_R27 $N_0039 V+ 150 137 | -Q_Q23 $N_0036 $N_0033 $N_0039 PNP8 {x5} 138 | -D_D8 $N_0039 V+ DX 1 139 | -Q_Q13 $N_0017 $N_0006 $N_0013 PNP8 {x1} 140 | -Q_Q30 $N_0041 $N_0040 $N_0036 NPN8 {x1} 141 | -Q_Q31 $N_0042 $N_0040 $N_0036 PNP8 {x1} 142 | -V_V1 $N_0003 Vmid 2.04V 143 | -L_L1 + $N_0021 1.3nH 144 | -Q_Q11 $N_0033 $N_0011 $N_0025 NPN8 {x16} 145 | -D_D4 $N_0025 $N_0023 DX 1 146 | -L_L3 $N_0040 OUT 1.3nH 147 | -L_L2 $N_0025 $N_0043 1.3nH 148 | -C_C2 $N_0036 V+ 0.2p 149 | -R_R31 $N_0043 - 65 150 | -Q_Q32 $N_0044 $N_0044 $N_0041 PNP8 {x60} 151 | -Q_Q33 $N_0040 $N_0044 $N_0041 PNP8 {x60} 152 | -Q_Q28 $N_0045 $N_0045 $N_0042 NPN8 {x60} 153 | -Q_Q29 $N_0040 $N_0045 $N_0042 NPN8 {x60} 154 | -Q_Q35 $N_0045 $N_0031 $N_0040 PNP8 {x60} 155 | -Q_Q34 $N_0044 $N_0034 $N_0040 NPN8 {x60} 156 | -Q_Q27 $N_0042 $N_0036 $N_0034 PNP8 {x60} 157 | -Q_Q26 $N_0041 $N_0036 $N_0031 NPN8 {x60} 158 | -R_R28 $N_0035 V+ 62.5 159 | -D_D6 $N_0037 V- DX 1 160 | -R_R29 V- $N_0032 62.5 161 | -V_V3 V- $N_0042 0.2V 162 | -V_V2 $N_0041 V+ 0.2V 163 | +R_R9 Dis VCC 41k 164 | +R_R12 N_0008 VCC 8k 165 | +R_R14 N_0010 VCC 500 166 | +R_R15 N_0014 VCC 500 167 | +R_R16 N_0012 VCC 500 168 | +R_R17 N_0006 VCC 72k 169 | +R_R13 N_0007 VCC 1987 170 | +Q_Q21 N_0036 N_0030 N_0037 NPN8 _AREA{x5} 171 | +R_R7 N_0029 Vmid 10k 172 | +R_R25 VEE N_0037 150 173 | +D_D7 VCC N_0038 DX 1 174 | +R_R26 N_0038 VCC 250 175 | +Q_Q22 N_0033 N_0033 N_0038 PNP8 _AREA{x3} 176 | +R_R27 N_0039 VCC 150 177 | +Q_Q23 N_0036 N_0033 N_0039 PNP8 _AREA{x5} 178 | +D_D8 N_0039 VCC DX 1 179 | +Q_Q13 N_0017 N_0006 N_0013 PNP8 _AREA{x1} 180 | +Q_Q30 N_0041 N_0040 N_0036 NPN8 _AREA{x1} 181 | +Q_Q31 N_0042 N_0040 N_0036 PNP8 _AREA{x1} 182 | +V_V1 N_0003 Vmid 2.04V 183 | +L_L1 INP N_0021 1.3nH 184 | +Q_Q11 N_0033 N_0011 N_0025 NPN8 _AREA{x16} 185 | +D_D4 N_0025 N_0023 DX 1 186 | +L_L3 N_0040 OUT 1.3nH 187 | +L_L2 N_0025 N_0043 1.3nH 188 | +C_C2 N_0036 VCC 0.2p 189 | +R_R31 N_0043 INN 65 190 | +Q_Q32 N_0044 N_0044 N_0041 PNP8 _AREA{x60} 191 | +Q_Q33 N_0040 N_0044 N_0041 PNP8 _AREA{x60} 192 | +Q_Q28 N_0045 N_0045 N_0042 NPN8 _AREA{x60} 193 | +Q_Q29 N_0040 N_0045 N_0042 NPN8 _AREA{x60} 194 | +Q_Q35 N_0045 N_0031 N_0040 PNP8 _AREA{x60} 195 | +Q_Q34 N_0044 N_0034 N_0040 NPN8 _AREA{x60} 196 | +Q_Q27 N_0042 N_0036 N_0034 PNP8 _AREA{x60} 197 | +Q_Q26 N_0041 N_0036 N_0031 NPN8 _AREA{x60} 198 | +R_R28 N_0035 VCC 62.5 199 | +D_D6 N_0037 VEE DX 1 200 | +R_R29 VEE N_0032 62.5 201 | +V_V3 VEE N_0042 0.2V 202 | +V_V2 N_0041 VCC 0.2V 203 | 204 | .MODEL NPN8 NPN 205 | + IS = 7.604E-18 BF = 1.570E+02 NF = 1.000E+00 VAF= 7.871E+01 206 | @@ -166,3 +177,5 @@ 207 | F_F1 3 4 VF_F1 1 208 | VF_F1 1 2 0V 209 | .ends OPA695_model_F1 210 | + 211 | +#undef _AREA 212 | -------------------------------------------------------------------------------- /models_source/ti/op_amp/OPA695_PSPICE_MODEL.txt: -------------------------------------------------------------------------------- 1 | ******************************************************************************** 2 | * Disclaimer 3 | * 4 | * This model is designed as an aid for customers of Texas Instruments. 5 | * TI and its licensors and suppliers make no warranties, either expressed 6 | * or implied, with respect to this model, including the warranties of 7 | * merchantability or fitness for a particular purpose. The model is 8 | * provided solely on an "as is" basis. The entire risk as to its quality 9 | * and performance is with the customer. 10 | ******************************************************************************** 11 | * Copyright 12 | * 13 | * (C) Copyright 2009 Texas Instruments Incorporated. All rights reserved. 14 | ******************************************************************************** 15 | * Released by: Analog eLab Design Center, Texas Instruments Inc. 16 | * Part: OPA695 17 | * Date: 05/21/2009 18 | * Model Type: PSPICE 19 | * Simulator: PSpice 16.0.0.p001 20 | * Datasheet: SBOS293G 21 | ******************************************************************************** 22 | * Release Notes: 23 | * 1.0 Original Version 24 | * 2.0 Improving some of the DC performance 25 | * 2.1 Improving Slew Rate accuracy 26 | * This model provides good typical values for the following parameters: 27 | * small signal closed loop bandwidth for high gain(i.e G=8), input noise, 28 | * slew rate (in particular non-inverting configuration), current consumption, 29 | * input voltage range, input voltage offset and output voltage range. 30 | ******************************************************************************** 31 | 32 | .SUBCKT OPA695 + - V+ V- Out DisA 33 | X1 + - DisA Out V+ V- OPA695_model 34 | .ENDS 35 | 36 | .SUBCKT OPA695_model + - Dis OUT V+ V- 37 | 38 | .PARAM x1 = {1/8} 39 | .PARAM x2 = {x1*2} 40 | .PARAM x3 = {x1*3} 41 | .PARAM x5 = {x1*5} 42 | .PARAM x12 = {x1*12} 43 | .PARAM x16 = {x1*16} 44 | .PARAM x60 = {x1*60} 45 | 46 | C_C1 Vmid Dis 2p 47 | X_S1 $N_0001 0 $N_0002 $N_0003 OPA695_model_S1 48 | R_R11 Vmid Dis 100MEG 49 | R_R8 Vmid $N_0004 10k 50 | Q_Q1 $N_0006 $N_0005 $N_0007 PNP8 {x1} 51 | Q_Q4 $N_0008 $N_0008 $N_0005 NPN8 {x1} 52 | Q_Q5 $N_0009 $N_0005 $N_0010 PNP8 {x2} 53 | Q_Q12 $N_0011 $N_0005 $N_0012 PNP8 {x2} 54 | Q_Q9 $N_0013 $N_0005 $N_0014 PNP8 {x2} 55 | Q_Q7 $N_0015 $N_0015 $N_0016 NPN8 {x2} 56 | Q_Q6 $N_0015 $N_0017 $N_0009 PNP8 {x16} 57 | Q_Q14 $N_0011 $N_0017 $N_0018 NPN8 {x1} 58 | Q_Q16 $N_0017 $N_0018 $N_0019 NPN8 {x1} 59 | Q_Q15 $N_0018 $N_0018 $N_0020 NPN8 {x1} 60 | Q_Q10 $N_0011 $N_0011 $N_0021 NPN8 {x16} 61 | Q_Q8 $N_0013 $N_0015 $N_0022 NPN8 {x2} 62 | D_D3 $N_0023 $N_0021 DX 1 63 | D_D1 $N_0021 $N_0024 DX 1 64 | D_D2 $N_0024 $N_0025 DX 1 65 | Q_Q18 $N_0026 $N_0026 $N_0021 PNP8 {x16} 66 | Q_Q17 $N_0026 $N_0015 $N_0027 NPN8 {x2} 67 | R_R24 V- $N_0028 250 68 | X_F1 $N_0002 $N_0029 $N_0006 V- OPA695_model_F1 69 | Q_Q2 V- $N_0006 $N_0005 PNP8 {x1} 70 | R_R18 V- $N_0015 50k 71 | R_R20 V- $N_0022 500 72 | R_R19 V- $N_0016 500 73 | R_R21 V- $N_0019 2k 74 | R_R22 V- $N_0020 2k 75 | R_R23 V- $N_0027 500 76 | D_D5 $N_0028 V- DX 1 77 | Q_Q20 $N_0030 $N_0030 $N_0028 NPN8 {x3} 78 | Q_Q19 $N_0030 $N_0026 $N_0025 PNP8 {x16} 79 | Q_Q25 $N_0031 $N_0030 $N_0032 NPN8 {x12} 80 | Q_Q24 $N_0034 $N_0033 $N_0035 PNP8 {x12} 81 | R_R10 V+ V- 123.609k 82 | E_E1 $N_0004 V- V+ V- 0.5 83 | E_ABM21 $N_0001 0 VALUE { ( V(Dis) 84 | + / (V(V+) 85 | + + 1e-6) ) * 5.0 } 86 | R_R9 Dis V+ 41k 87 | R_R12 $N_0008 V+ 8k 88 | R_R14 $N_0010 V+ 500 89 | R_R15 $N_0014 V+ 500 90 | R_R16 $N_0012 V+ 500 91 | R_R17 $N_0006 V+ 72k 92 | R_R13 $N_0007 V+ 1987 93 | Q_Q21 $N_0036 $N_0030 $N_0037 NPN8 {x5} 94 | R_R7 $N_0029 Vmid 10k 95 | R_R25 V- $N_0037 150 96 | D_D7 V+ $N_0038 DX 1 97 | R_R26 $N_0038 V+ 250 98 | Q_Q22 $N_0033 $N_0033 $N_0038 PNP8 {x3} 99 | R_R27 $N_0039 V+ 150 100 | Q_Q23 $N_0036 $N_0033 $N_0039 PNP8 {x5} 101 | D_D8 $N_0039 V+ DX 1 102 | Q_Q13 $N_0017 $N_0006 $N_0013 PNP8 {x1} 103 | Q_Q30 $N_0041 $N_0040 $N_0036 NPN8 {x1} 104 | Q_Q31 $N_0042 $N_0040 $N_0036 PNP8 {x1} 105 | V_V1 $N_0003 Vmid 2.04V 106 | L_L1 + $N_0021 1.3nH 107 | Q_Q11 $N_0033 $N_0011 $N_0025 NPN8 {x16} 108 | D_D4 $N_0025 $N_0023 DX 1 109 | L_L3 $N_0040 OUT 1.3nH 110 | L_L2 $N_0025 $N_0043 1.3nH 111 | C_C2 $N_0036 V+ 0.2p 112 | R_R31 $N_0043 - 65 113 | Q_Q32 $N_0044 $N_0044 $N_0041 PNP8 {x60} 114 | Q_Q33 $N_0040 $N_0044 $N_0041 PNP8 {x60} 115 | Q_Q28 $N_0045 $N_0045 $N_0042 NPN8 {x60} 116 | Q_Q29 $N_0040 $N_0045 $N_0042 NPN8 {x60} 117 | Q_Q35 $N_0045 $N_0031 $N_0040 PNP8 {x60} 118 | Q_Q34 $N_0044 $N_0034 $N_0040 NPN8 {x60} 119 | Q_Q27 $N_0042 $N_0036 $N_0034 PNP8 {x60} 120 | Q_Q26 $N_0041 $N_0036 $N_0031 NPN8 {x60} 121 | R_R28 $N_0035 V+ 62.5 122 | D_D6 $N_0037 V- DX 1 123 | R_R29 V- $N_0032 62.5 124 | V_V3 V- $N_0042 0.2V 125 | V_V2 $N_0041 V+ 0.2V 126 | 127 | .MODEL NPN8 NPN 128 | + IS = 7.604E-18 BF = 1.570E+02 NF = 1.000E+00 VAF= 7.871E+01 129 | + IKF= 3.975E-02 ISE= 3.219E-14 NE = 2.000E+00 BR = 7.614E-01 130 | + NR = 1.000E+00 VAR= 1.452E+00 IKR= 8.172E-02 ISC= 7.618E-21 131 | + NC = 1.847E+00 RB = 1.060E+02 IRB= 0.000E+00 RBM= 2.400E+00 132 | + RE = 2.520E+00 RC = 1.270E+02 CJE= 1.120E-13 VJE= 7.591E-01 133 | + MJE= 5.406E-01 TF = 1.213E-11 XTF= 2.049E+00 VTF= 1.813E+00 134 | + ITF= 4.293E-02 PTF= 0.000E+00 CJC= 8.208E-15 VJC= 6.666E-01 135 | + MJC= 4.509E-01 XCJC=8.450E-02 TR = 4.000E-11 CJS= 1.160E-13 136 | + VJS= 5.286E-01 MJS= 4.389E-01 XTB= 1.022E+00 EG = 1.120E+00 137 | + XTI= 1.780E+00 KF = 3.500E-16 AF = 1.000E+00 FC = 8.273E-01 138 | 139 | .MODEL PNP8 PNP 140 | + IS = 7.999E-18 BF = 1.418E+02 NF = 1.000E+00 VAF= 4.158E+01 141 | + IKF= 1.085E-01 ISE= 2.233E-15 NE = 1.505E+00 BR = 3.252E+01 142 | + NR = 1.050E+00 VAR= 1.093E+00 IKR= 5.000E-05 ISC= 6.621E-16 143 | + NC = 1.150E+00 RB = 6.246E+01 IRB= 0.000E+00 RBM= 2.240E+00 144 | + RE = 2.537E+00 RC = 1.260E+02 CJE= 9.502E-14 VJE= 7.320E-01 145 | + MJE= 4.930E-01 TF = 1.303E-11 XTF= 3.500E+01 VTF= 3.259E+00 146 | + ITF= 2.639E-01 PTF= 0.000E+00 CJC= 1.080E-13 VJC= 7.743E-01 147 | + MJC= 5.000E-01 XCJC=8.504E-02 TR = 1.500E-10 CJS= 1.290E-13 148 | + VJS= 9.058E-01 MJS= 4.931E-01 XTB= 1.732E+00 EG = 1.120E+00 149 | + XTI= 2.000E+00 KF = 3.500E-16 AF = 1.000E+00 FC = 8.500E-01 150 | 151 | .MODEL DX D 152 | + IS=1.0000E-15 153 | 154 | .ENDS OPA695_model 155 | 156 | 157 | 158 | 159 | .subckt OPA695_model_S1 1 2 3 4 160 | S_S1 3 4 1 2 _S1 161 | RS_S1 1 2 1G 162 | .MODEL _S1 VSWITCH Roff=1e12 Ron=0.001 Voff=3.0 Von=4.5 163 | .ends OPA695_model_S1 164 | 165 | .subckt OPA695_model_F1 1 2 3 4 166 | F_F1 3 4 VF_F1 1 167 | VF_F1 1 2 0V 168 | .ends OPA695_model_F1 169 | -------------------------------------------------------------------------------- /models_source/ti/op_amp/index.py: -------------------------------------------------------------------------------- 1 | # LMH6624 PSPICE Model, 16 Jan 2012, http://www.ti.com/lit/zip/snom130 2 | Model('LMH6624', 3 | mod = ('LMH6624.MOD', '4aece1f9b563edfeba11'), 4 | doc = 'LMH6624.txt') 5 | 6 | # LMH6702 PSPICE Model, 16 Jan 2012, http://www.ti.com/lit/zip/snom144 7 | Model('LMH6702', 8 | mod = ('LMH6702.MOD', '6611a8ea4cdbdfe436a9'), 9 | doc = 'LMH6702.txt') 10 | 11 | # LMV981-N PSPICE Model, 16 Jan 2012, http://www.ti.com/lit/zip/snom030 12 | Model('LMV981', 13 | mod = ('LMV981.MOD', '4d1e935bdcab07c3a559'), 14 | doc = 'LMV981.txt') 15 | 16 | # OPAy695 PSpice Model (Rev. B), 26 may 2009, http://www.ti.com/lit/zip/sboc036 17 | Model('OPA695', 18 | mod = Patch('OPA695_PSPICE_MODEL.txt', 'OPA695_PSPICE_MODEL.diff', 19 | 'a0004433d0ffa8145e9f')) 20 | -------------------------------------------------------------------------------- /spice/__init__.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | -------------------------------------------------------------------------------- /spice/circuit.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | class Device(object): 5 | def __init__(self, ref, nodes, value, *args, **kwargs): 6 | self.ref = ref 7 | self.nodes = [ str(_) for _ in nodes ] 8 | self.value = value 9 | self.args = args 10 | self.kwargs = kwargs 11 | 12 | class Circuit(dict): 13 | def __init__(self): 14 | self.includes = set() 15 | 16 | def add_include(self, include): 17 | self.includes.add(include) 18 | 19 | def add_device(self, device): 20 | if '?' in device.ref: 21 | raise ValueError("Invalid ref %s" % device.ref) 22 | if device.ref in self: 23 | raise ValueError("Duplicate device with ref %s" % device.ref) 24 | self[device.ref] = device 25 | 26 | def R(self, ref, nodep, nodem, value): 27 | assert(ref.startswith('R')) 28 | self.add_device(Device(ref, [ nodep, nodem ], value)) 29 | 30 | def C(self, ref, nodep, nodem, value): 31 | assert(ref.startswith('C')) 32 | self.add_device(Device(ref, [ nodep, nodem ], value)) 33 | 34 | def L(self, ref, nodep, nodem, value): 35 | assert(ref.startswith('L')) 36 | self.add_device(Device(ref, [ nodep, nodem ], value)) 37 | 38 | def V(self, ref, nodep, nodem, value): 39 | assert(ref.startswith('V')) 40 | self.add_device(Device(ref, [ nodep, nodem ], value)) 41 | 42 | def I(self, ref, nodep, nodem, value): 43 | assert(ref.startswith('I')) 44 | self.add_device(Device(ref, [ nodep, nodem ], value)) 45 | 46 | def Device(self, ref, nodes, model): 47 | self.add_device(Device(ref, nodes, model)) 48 | -------------------------------------------------------------------------------- /spice/ltspice.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import os 5 | import numpy as np 6 | 7 | from .simulator import SimulatorBase, Dataset 8 | 9 | class LTspice(SimulatorBase): 10 | SIMULATOR = 'DISPLAY=:0 "%s/.wine/drive_c/Program Files/LTC/LTspiceXVII/XVIIx64.exe"' % os.environ['HOME'] 11 | ENCODING = 'utf_16_le' 12 | HEADER = '#define LTSPICE' 13 | 14 | def __init__(self): 15 | super(LTspice, self).__init__() 16 | 17 | def _create_files(self): 18 | return 'spice.cir', 'spice.raw' 19 | 20 | def _make_cmd(self, cir_path, raw_path): 21 | return '%s -b %s' % (self.SIMULATOR, cir_path) 22 | 23 | def _simulate_post(self, cir_path, raw_path, base): 24 | assert cir_path.endswith('.cir') 25 | log_path = cir_path[:-4] + '.log' 26 | with open(log_path, 'rb') as f: 27 | data = f.read() 28 | if data[1:2] == '\0': 29 | log = data.decode(self.encoding) 30 | else: 31 | log = data.decode('ascii') 32 | self.trace(log) 33 | 34 | def update_variable(self, dataset, var): 35 | name = var.name.upper() 36 | 37 | if name in [ 'GAIN', 'TIME' ]: 38 | pass 39 | elif var.idx == 0: 40 | name = 'SWEEP' 41 | elif name == 'V(ONOISE)': 42 | name = 'V(ONOISE_SPECTRUM)' 43 | elif name == 'INOISE': 44 | name = 'V(INOISE_SPECTRUM)' 45 | elif name.startswith('I('): 46 | pass 47 | elif not name.startswith('V('): 48 | name = 'V(%s)' % name 49 | 50 | var.name = name 51 | 52 | if 'complex' in dataset.flags: 53 | var.dt = np.complex128 54 | elif var.idx != 0: 55 | var.dt = np.float32 56 | else: 57 | var.dt = np.float64 58 | 59 | def dc(self, circuit, source, start, stop, step): 60 | args = [ '.dc', source, start, stop, step ] 61 | data = self._simulate_simple(circuit, *args) 62 | 63 | return data 64 | 65 | def tran(self, circuit, tstep, tstop, tstart=0, tmax=None, uic=False): 66 | args = [ '.tran', tstep, tstop, tstart ] 67 | if tmax is not None: 68 | args.append(tmax) 69 | if uic: 70 | args.append('uic') 71 | data = self._simulate_simple(circuit, *args) 72 | data['TIME'] = abs(data['TIME']) 73 | return data 74 | 75 | def noise(self, *args, **kwargs): 76 | data = super(LTspice, self).noise(*args, **kwargs) 77 | 78 | # Ngspice and Xyce return V^2/HZ while LTspice returns V/rtHz; 79 | # convert LTspice spectrums to same format as them 80 | for name in [ 'V(INOISE_SPECTRUM)', 'V(ONOISE_SPECTRUM)' ]: 81 | data[name] = data[name] ** 2 82 | return data 83 | 84 | Simulator = LTspice 85 | -------------------------------------------------------------------------------- /spice/models.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import sys 5 | import os 6 | import hashlib 7 | 8 | from StringIO import StringIO 9 | 10 | from . patch import PatchSet 11 | 12 | if sys.version_info.major < 3: 13 | STRING_TYPES = (str, unicode) 14 | else: 15 | STRING_TYPES = str 16 | 17 | _base_name = None 18 | _models = {} 19 | 20 | class Path(object): 21 | def __init__(self, url, hash = None, base = ''): 22 | i = url.find('://') 23 | if i != -1: 24 | scheme = url[:i] 25 | path = url[i+2:] 26 | else: 27 | scheme = None 28 | path = url.replace('\\', '/') 29 | 30 | if not path.startswith('/'): 31 | path = _base_name + '/' + path 32 | 33 | if 0: 34 | parts = path.split('/') 35 | for i in range(len(parts)-1, 0, -1): 36 | if parts[i].lower().endswith('.zip'): 37 | basefile = ZipPath('/'.join(parts[:i])) 38 | break 39 | 40 | self.scheme = scheme 41 | self.path = path 42 | self.hash = hash 43 | 44 | def load(self, base): 45 | path = os.path.join(base, self.path) 46 | text = normalize_text(open(path).read()) 47 | calc = calculate_hash(text) 48 | 49 | print('%s: %s' % (path, calc)) 50 | if self.hash and self.hash != calc: 51 | print("%s: hash mismatch, expected %s" % (path, self.hash)) 52 | 53 | return text 54 | 55 | def __repr__(self): 56 | return 'Path(%s, %s)' % (repr(self.path), self.hash) 57 | 58 | class Patch(Path): 59 | def __init__(self, url, patch, hash = None): 60 | super(Patch, self).__init__(url) 61 | self.patch = parse_spec(patch) 62 | self.patch_hash = hash.lower() 63 | 64 | def load(self, base): 65 | text = super(Patch, self).load(base) 66 | path = os.path.join(base, self.patch.path) 67 | patchset = PatchSet(open(path)) 68 | 69 | for i, p in enumerate(patchset.items): 70 | patchset.verify(i, 1, self.path, p, StringIO(text)) 71 | lines = patchset.patch_stream(StringIO(text), p.hunks) 72 | text = ''.join(lines) 73 | 74 | calc = calculate_hash(text) 75 | 76 | print('%s: %s' % (path, calc)) 77 | if self.patch_hash and self.patch_hash != calc: 78 | print("%s: patch hash mismatch, expected %s" % (path, self.patch_hash)) 79 | 80 | return text 81 | 82 | def __repr__(self): 83 | return 'Patch(%s, %s, %s)' % (repr(self.path), repr(self.patch), self.hash) 84 | 85 | class Model(object): 86 | def __init__(self, name, mod, doc = None, base = ''): 87 | if not name.startswith('/'): 88 | name = _base_name + name 89 | if not base: 90 | base = _base_name 91 | if not base.endswith('/'): 92 | base += '/' 93 | 94 | self.name = name 95 | self.base = base 96 | self.mod = parse_spec(mod) 97 | self.doc = parse_spec(doc) 98 | 99 | assert name not in _models 100 | _models[name] = self 101 | 102 | def __repr__(self): 103 | return "Model: %s" % (self.name) 104 | 105 | def normalize_text(text): 106 | text = '\n'.join([ _.rstrip() for _ in text.split('\n') ]) 107 | text = text.replace('\r', '') 108 | return text 109 | 110 | def calculate_hash(text): 111 | return hashlib.sha1(text).hexdigest().lower()[:20] 112 | 113 | def parse_spec(spec): 114 | if spec is None: 115 | return None 116 | elif isinstance(spec, Path): 117 | return spec 118 | elif isinstance(spec, tuple): 119 | assert len(spec) == 2 120 | return Path(spec[0], spec[1].lower()) 121 | else: 122 | return Path(spec) 123 | 124 | class LibraryManager(object): 125 | def __init__(self, source_path, download_path, output_path): 126 | self.source_path = source_path 127 | self.download_path = download_path 128 | self.output_path = output_path 129 | self.mod_ext = '.lib' 130 | self.doc_ext = '.txt' 131 | 132 | def resolve(self): 133 | for root, dirs, files in os.walk(self.source_path): 134 | for fn in files: 135 | if os.path.normcase(fn) == 'index.py': 136 | global _base_name 137 | _base_name = os.path.relpath(root, self.source_path) 138 | _base_name = _base_name.replace('\\', '/') 139 | _base_name = _base_name + '/' 140 | p = os.path.join(root, fn) 141 | print("Processing", p) 142 | l = {} 143 | execfile(p, globals(), l) 144 | if l: 145 | print(l) 146 | print() 147 | 148 | def process(self): 149 | for name, model in sorted(_models.items()): 150 | src_base = os.path.join(self.source_path) 151 | dst_base = os.path.join(self.output_path, model.name) 152 | 153 | dst_dir = dst_base.rsplit('/', 1)[0] 154 | if not os.path.isdir(dst_dir): 155 | os.makedirs(dst_dir) 156 | 157 | text = model.mod.load(src_base) 158 | dst_path = dst_base + self.mod_ext 159 | tmp_path = dst_path + '+' 160 | open(tmp_path, 'w').write(text) 161 | os.rename(tmp_path, dst_path) 162 | 163 | if model.doc: 164 | text = model.doc.load(src_base) 165 | dst_path = dst_base + self.doc_ext 166 | tmp_path = dst_path + '+' 167 | open(tmp_path, 'w').write(text) 168 | os.rename(tmp_path, dst_path) 169 | 170 | print() 171 | -------------------------------------------------------------------------------- /spice/ngspice.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | from .simulator import SimulatorBase 5 | 6 | import numpy as np 7 | 8 | class Ngspice(SimulatorBase): 9 | SIMULATOR = 'ngspice' 10 | HEADER = ''' 11 | #define NGSPICE 12 | .func if(a,b,c) 'ternary_fcn( a , b , c ) 13 | .func limit(x, y, z) {min(max(x, min(y, z)), max(z, y))} 14 | .param TEMP=27 15 | ''' 16 | def __init__(self): 17 | super(Ngspice, self).__init__() 18 | 19 | def update_variable(self, dataset, var): 20 | name = var.name.upper() 21 | if name in [ 'V(V-SWEEP)', 'V(I-SWEEP)', 'FREQUENCY' ]: 22 | assert var.idx == 0 23 | name = 'SWEEP' 24 | 25 | var.name = name 26 | 27 | if 'complex' in dataset.flags: 28 | var.dt = np.complex128 29 | else: 30 | var.dt = np.float64 31 | 32 | def noise(self, circuit, out, ref, variation, n, fstart, fstop, **kwargs): 33 | args = [ '.noise', out, ref, variation, n, fstart, fstop, 1 ] 34 | return self._simulate_simple(circuit, *args, secondary = True, **kwargs) 35 | 36 | Simulator = Ngspice 37 | -------------------------------------------------------------------------------- /spice/preprocessor.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | from ply.cpp import * 5 | 6 | class SpicePreprocessor(Preprocessor): 7 | def __init__(self): 8 | import ply.lex as lex 9 | super(SpicePreprocessor, self).__init__(lex.lex()) 10 | 11 | def parsegen(self,input,source=None): 12 | if source: 13 | input = '* included from "%s"\n\n' % source + input 14 | input += '\n' 15 | return super(SpicePreprocessor, self).parsegen(input,source=source) 16 | 17 | def __iter__(self): 18 | while True: 19 | tok = self.token() 20 | if not tok: 21 | break 22 | yield tok 23 | 24 | def output(self): 25 | line = [] 26 | lines = [] 27 | 28 | for tok in self: 29 | if tok.type == self.t_SPACE and '\n' in tok.value: 30 | line.append(tok.value) 31 | joined = ''.join(line) 32 | lines.append(joined) 33 | line = [] 34 | 35 | else: 36 | line.append(tok.value) 37 | 38 | lines.append(''.join(line)) 39 | 40 | return ''.join(lines) 41 | -------------------------------------------------------------------------------- /spice/rawfile.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | 3 | # Copyright (c) 2018 Christer Weinigel 4 | # 5 | # SPDX-License-Identifier: MIT 6 | # 7 | # Permission is hereby granted, free of charge, to any person 8 | # obtaining a copy of this software and associated documentation files 9 | # (the "Software"), to deal in the Software without restriction, 10 | # including without limitation the rights to use, copy, modify, merge, 11 | # publish, distribute, sublicense, and/or sell copies of the Software, 12 | # and to permit persons to whom the Software is furnished to do so, 13 | # subject to the following conditions: 14 | # 15 | # The above copyright notice and this permission notice shall be 16 | # included in all copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 22 | # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 23 | # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 24 | # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | # SOFTWARE. 26 | 27 | from __future__ import division, print_function, unicode_literals 28 | 29 | import numpy as np 30 | from collections import OrderedDict 31 | 32 | # Python 3 compatibility 33 | try: 34 | basestring 35 | except NameError: 36 | basestring = str 37 | 38 | class Variable(np.ndarray): 39 | def __new__(cls, *args, **kwargs): 40 | self = super(Variable, cls).__new__(cls, *args, **kwargs) 41 | 42 | self.unit = '' 43 | self.params = {} 44 | 45 | return self 46 | 47 | class Dataset(OrderedDict): 48 | def __init__(self): 49 | super(Dataset, self).__init__(self) 50 | 51 | self.headers = OrderedDict() 52 | self.variables = [] 53 | self.flavor = '' 54 | 55 | class Reader(object): 56 | """File like class with heuristics for encoding.""" 57 | 58 | def __init__(self, f, separator = '\n'): 59 | if isinstance(f, basestring): 60 | f = open(f, 'rb') 61 | 62 | self.f = f 63 | self.buf = b'' 64 | self.offset = 0 65 | 66 | self.encoding = None 67 | self.separator = separator 68 | 69 | def readline(self): 70 | """Read and decode a line. 71 | 72 | If this is the first time readline is called it tries to 73 | detect the encoding first.""" 74 | 75 | if not self.encoding: 76 | self.detect_encoding() 77 | 78 | while 1: 79 | i = self.buf.find(self.separator, self.offset) 80 | if i != -1: 81 | break 82 | 83 | if not self.fill(256): 84 | return None 85 | 86 | s = self.buf[self.offset:i].decode(self.encoding) 87 | 88 | self.offset = i + len(self.separator) 89 | 90 | return s 91 | 92 | def read(self, n): 93 | """Read raw bytes""" 94 | 95 | while len(self.buf) < self.offset + n: 96 | if not self.fill(n - len(self.buf) + self.offset): 97 | break 98 | 99 | data = self.buf[self.offset:self.offset + n] 100 | self.offset += n 101 | 102 | return data 103 | 104 | def fill(self, n): 105 | if self.offset: 106 | self.buf = self.buf[self.offset:] 107 | self.offset = 0 108 | 109 | data = self.f.read(n) 110 | if not data: 111 | return None 112 | 113 | if self.buf: 114 | self.buf += data 115 | else: 116 | self.buf = data 117 | 118 | return data 119 | 120 | def detect_encoding(self): 121 | self.fill(16) 122 | assert self.offset == 0 123 | 124 | if self.buf[0:2] == b'\xfe\xff': 125 | encoding = 'utf_16_be' 126 | self.offset += 2 127 | elif self.buf[0:1] == b'\0': 128 | encoding = 'utf_16_be' 129 | elif self.buf[0:2] == b'\xff\xfe': 130 | encoding = 'utf_16_le' 131 | self.offset += 2 132 | elif self.buf[1:2] == b'\0': 133 | encoding = 'utf_16_le' 134 | elif self.buf[:3] == b'\xef\xbb\xbf': 135 | encoding = 'utf_8' 136 | self.offset += 3 137 | else: 138 | encoding = 'utf_8' 139 | 140 | self.encoding = encoding 141 | self.separator = bytearray(self.separator, encoding) 142 | 143 | class RawFileReader(object): 144 | def load(self, f): 145 | a = [] 146 | 147 | self.reader = Reader(f) 148 | 149 | while True: 150 | d = self.load_dataset() 151 | if not d: 152 | break 153 | a.append(d) 154 | 155 | del self.reader 156 | 157 | return a 158 | 159 | def load_dataset(self): 160 | dataset = Dataset() 161 | 162 | while 1: 163 | k, v = self.load_header() 164 | 165 | if k is None: 166 | assert not dataset.headers 167 | return None 168 | 169 | kl = k.lower() 170 | 171 | if kl == 'variables': 172 | self.load_variables(dataset) 173 | continue 174 | 175 | if kl == 'binary': 176 | data = self.load_binary(dataset) 177 | break 178 | 179 | if kl == 'command': 180 | if 'ltspice' in v.lower().split(): 181 | assert not dataset.flavor 182 | dataset.flavor = 'ltspice' 183 | 184 | assert k not in dataset.headers 185 | dataset.headers[k] = v 186 | 187 | if kl == 'no. variables': 188 | dataset.nr_variables = int(v) 189 | elif kl == 'no. points': 190 | dataset.nr_points = int(v) 191 | elif kl == 'flags': 192 | dataset.flags = v.strip().split() 193 | 194 | for name, unit, params in dataset.variables: 195 | var = data[str(name)].view(Variable) 196 | var.unit = unit 197 | var.params = params 198 | dataset[name] = var 199 | 200 | return dataset 201 | 202 | def load_header(self): 203 | l = self.reader.readline() 204 | if l is None: 205 | return None, None 206 | i = l.find(':') 207 | return (l[:i], l[i+1:].strip()) 208 | 209 | def load_variables(self, dataset): 210 | for idx in range(dataset.nr_variables): 211 | parts = self.reader.readline().strip().split() 212 | assert int(parts[0]) == idx 213 | name = parts[1] 214 | unit = parts[2] 215 | params = {} 216 | for s in parts[3:]: 217 | i = s.find('=') 218 | params[s[:i]] = s[i+1:] 219 | 220 | dataset.variables.append((name, unit, params)) 221 | 222 | def load_binary(self, dataset): 223 | dtypes = self.make_dtypes(dataset) 224 | 225 | # Using str is a workaround for numpy 1.11 not understanding unicode 226 | dt = np.dtype([ (str(n), t) for n, t in dtypes ]) 227 | 228 | n = dataset.nr_points * dt.itemsize 229 | buf = self.reader.read(n) 230 | 231 | data = np.frombuffer(buf, dtype = dt, count = dataset.nr_points) 232 | 233 | return data 234 | 235 | def make_dtypes(self, dataset): 236 | dtypes = [] 237 | for name, unit, params in dataset.variables: 238 | if 'complex' in dataset.flags: 239 | # For complex data all variables are complex128 240 | dt = np.complex128 241 | else: 242 | # LTspice outputs all variables but first as float32 243 | if dtypes and dataset.flavor == 'ltspice': 244 | dt = np.float32 245 | else: 246 | dt = np.float64 247 | 248 | dtypes.append((name, dt)) 249 | 250 | return dtypes 251 | 252 | def load_rawfile(f): 253 | """Load datasets from a spice rawfile. 254 | 255 | This function has been tested with ngspice, xyce and ltspice. 256 | 257 | Returns an array of Datasets""" 258 | 259 | return RawFileReader().load(f) 260 | 261 | if __name__ == '__main__': 262 | import sys 263 | 264 | if not sys.argv[0]: 265 | sys.argv = [ '', 'spice.raw' ] 266 | 267 | for fn in sys.argv[1:]: 268 | print(fn) 269 | print() 270 | 271 | a = load_rawfile(fn) 272 | 273 | for d in a: 274 | for k, v in d.headers.items(): 275 | print(k, v) 276 | print() 277 | 278 | for name, a in d.items(): 279 | print(name, a.unit, a.params) 280 | print(a) 281 | print() 282 | -------------------------------------------------------------------------------- /spice/simulator.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import os 5 | import sys 6 | 7 | import numpy as np 8 | from subprocess import Popen, PIPE, STDOUT 9 | import tempfile 10 | import time 11 | import shutil 12 | from collections import OrderedDict 13 | 14 | from . import unit 15 | from . preprocessor import SpicePreprocessor 16 | 17 | class Dataset(dict): 18 | pass 19 | 20 | class Progress(object): 21 | def __init__(self): 22 | pass 23 | 24 | def start(self): 25 | pass 26 | 27 | def stop(self, status): 28 | pass 29 | 30 | def percent(self, percent): 31 | pass 32 | 33 | class Variable(object): 34 | def __init__(self, idx, name, unit, param): 35 | self.idx = idx 36 | self.name = name 37 | self.old_name = name 38 | self.unit = unit 39 | self.param = param 40 | 41 | class SimulatorBase(object): 42 | ENCODING = 'utf-8' 43 | SEPARATOR = '\n' 44 | BLOCKSIZE = 16 45 | BASE = '.' 46 | HEADER = '' 47 | 48 | def __init__(self): 49 | self.timing = 0 50 | self.verbose = 0 51 | self.progress = Progress() 52 | self.last_trace = '' 53 | self.preprocessor = SpicePreprocessor 54 | self.includes = [] 55 | 56 | def _dummy(self, *args, **kwargs): 57 | pass 58 | 59 | def trace(self, s): 60 | if s == self.last_trace: 61 | return 62 | 63 | self.last_trace = s 64 | 65 | if self.verbose >= 1: 66 | print(s) 67 | self.output.append(str(s)) 68 | 69 | def log(self): 70 | return '\n'.join(self.output) 71 | 72 | def fix_param(self, v): 73 | if isinstance(v, unit._Unit): 74 | prefix = v.prefix 75 | if prefix == 'M': 76 | prefix = 'MEG' 77 | return str(v.value / v.multiplier) + prefix 78 | 79 | return str(v) 80 | 81 | def device_to_spice(self, device): 82 | a = [] 83 | a.append(device.ref) 84 | for node in device.nodes: 85 | a.append(str(node)) 86 | a.append(self.fix_param(device.value)) 87 | for arg in device.args: 88 | a.append(self.fix_param(arg)) 89 | for k, v in device.kwargs: 90 | a.append('%s=%s' % (k, self.fix_param(v))) 91 | return ' '.join(a) 92 | 93 | def circuit_to_spice(self, circuit, base = '.'): 94 | a = [] 95 | 96 | for include in circuit.includes: 97 | a.append('#include "%s"' % os.path.join(base, include)) 98 | for device in circuit.values(): 99 | a.append(self.device_to_spice(device)) 100 | 101 | a.append('') 102 | 103 | return '\n'.join(a) 104 | 105 | def readline(self): 106 | while 1: 107 | i = self.buf.find(self.separator, self.offset) 108 | if i != -1: 109 | break 110 | 111 | data = self.f.read(self.BLOCKSIZE) 112 | if not data: 113 | return None 114 | 115 | # print("got %d bytes" % len(data)) 116 | 117 | if self.offset: 118 | self.buf = self.buf[self.offset:] 119 | self.offset = 0 120 | 121 | self.buf += data 122 | 123 | s = self.buf[self.offset:i].decode(self.ENCODING) 124 | 125 | self.offset = i + len(self.separator) 126 | 127 | return s 128 | 129 | def readheader(self): 130 | l = self.readline() 131 | if l is None: 132 | return None, None 133 | i = l.find(':') 134 | return (l[:i], l[i+1:].strip()) 135 | 136 | def read(self, n): 137 | while len(self.buf) < self.offset + n: 138 | data = self.f.read(max(self.BLOCKSIZE, n - len(self.buf) + self.offset)) 139 | if not data: 140 | break 141 | 142 | # print("got %d bytes" % len(data)) 143 | 144 | if self.offset: 145 | self.buf = self.buf[self.offset:] 146 | self.offset = 0 147 | 148 | self.buf += data 149 | 150 | data = self.buf[self.offset:self.offset + n] 151 | 152 | self.offset += n 153 | 154 | return data 155 | 156 | def _load_variables(self, dataset): 157 | dataset.variables = OrderedDict() 158 | 159 | for idx in range(dataset.nr_variables): 160 | parts = self.readline().strip().split() 161 | assert int(parts[0]) == idx 162 | name = parts[1] 163 | unit = parts[2] 164 | params = {} 165 | for s in parts[3:]: 166 | i = s.find('=') 167 | params[s[:i]] = s[i+1:] 168 | 169 | var = Variable(idx, name, unit, params) 170 | 171 | self.update_variable(dataset, var) 172 | 173 | dataset.variables[var.name] = var 174 | 175 | def _load_binary(self, dataset): 176 | # Doing str here is a workaround for numpy 1.11 not understanding unicode 177 | dt = np.dtype([ (str(var.name), var.dt) for var in dataset.variables.values() ]) 178 | 179 | n = dataset.nr_points * dt.itemsize 180 | buf = self.read(n) 181 | 182 | data = np.frombuffer(buf, dtype = dt, count = dataset.nr_points) 183 | 184 | for var in dataset.variables.values(): 185 | dataset[var.name] = data[str(var.name)] 186 | 187 | def _load(self, f): 188 | self.f = f 189 | 190 | self.buf = bytearray() 191 | self.offset = 0 192 | 193 | self.separator = bytearray(self.SEPARATOR, self.ENCODING) 194 | 195 | dataset = Dataset() 196 | dataset.headers = {} 197 | dataset.variables = None 198 | 199 | while 1: 200 | k, v = self.readheader() 201 | 202 | k = k.lower() 203 | 204 | if k == 'variables': 205 | self._load_variables(dataset) 206 | continue 207 | 208 | if k == 'binary': 209 | self._load_binary(dataset) 210 | break 211 | 212 | assert k not in dataset.headers 213 | dataset.headers[k] = v 214 | 215 | if k == 'no. variables': 216 | dataset.nr_variables = int(v) 217 | elif k == 'no. points': 218 | dataset.nr_points = int(v) 219 | elif k == 'flags': 220 | dataset.flags = v.strip().split() 221 | 222 | return dataset 223 | 224 | def _make_cmd(self, cir_path, raw_path): 225 | return '%s -b -r %s %s' % (self.SIMULATOR, raw_path, cir_path) 226 | 227 | def _write_circuit(self, fn, circuit, pre, post): 228 | title = "simulation" 229 | 230 | cir_s = self.circuit_to_spice(circuit, base = self.BASE) 231 | s = '\n'.join([ self.HEADER, pre, post, cir_s ]) 232 | if self.preprocessor: 233 | pp = self.preprocessor() 234 | for include in self.includes: 235 | pp.add_path(include) 236 | pp.parse(s) 237 | s = pp.output() 238 | 239 | with open(fn, 'w') as f: 240 | f.write('%s\n' % title) 241 | f.write('%s\n' % s) 242 | f.write('.end\n') 243 | f.close() 244 | 245 | def _simulate(self, circuit, pre, post, secondary = False, 246 | postprocess = None): 247 | self.progress.start() 248 | try: 249 | status = 1 250 | 251 | self.output = [] 252 | 253 | base = tempfile.mkdtemp(prefix = 'sim-', dir = '.') 254 | 255 | cir_path = os.path.join(base, 'spice.cir') 256 | raw_path = os.path.join(base, 'spice.raw') 257 | 258 | self._write_circuit(cir_path, circuit, pre, post) 259 | 260 | cmd = self._make_cmd(cir_path, raw_path) 261 | self.trace(cmd + '\n') 262 | 263 | t0 = time.time() 264 | p = Popen(cmd, shell = True, 265 | stdin = PIPE, stdout = PIPE, stderr = STDOUT, 266 | close_fds = True) 267 | while 1: 268 | buf = p.stdout.readline() 269 | if not buf: 270 | break 271 | self.trace(buf.decode('ascii').rstrip()) 272 | ec = p.wait() 273 | t1 = time.time() 274 | 275 | if self.timing: 276 | print("simulation took %.3f seconds" % (t1-t0)) 277 | 278 | if ec != 0: 279 | print("Simulation failed") 280 | print() 281 | if self.verbose < 1: 282 | print(self.log()) 283 | 284 | with open(raw_path, 'rb') as f: 285 | data = self._load(f) 286 | if secondary: 287 | data.secondary = self._load(f) 288 | assert len(self.read(1)) == 0 289 | 290 | if postprocess: 291 | postprocess(data, cir_path, raw_path, base) 292 | 293 | self._simulate_post(cir_path, raw_path, base) 294 | 295 | shutil.rmtree(base) 296 | 297 | status = 0 298 | 299 | return data 300 | 301 | finally: 302 | self.progress.stop(status) 303 | 304 | def _simulate_post(self, cir_path, raw_path, base): 305 | pass 306 | 307 | def _fixup_data(self, data): 308 | return data 309 | 310 | def _simulate_simple(self, circuit, *args, **kwargs): 311 | args = [ self.fix_param(_) for _ in args ] 312 | return self._simulate(circuit, '', ' '.join(args), **kwargs) 313 | 314 | def dc(self, circuit, source, start, stop, step): 315 | args = [ '.dc', source, start, stop, step ] 316 | return self._simulate_simple(circuit, *args) 317 | 318 | def ac(self, circuit, variation, n, fstart, fstop): 319 | args = [ '.ac', variation, n, fstart, fstop ] 320 | return self._simulate_simple(circuit, *args) 321 | 322 | def noise(self, circuit, out, ref, variation, n, fstart, fstop, **kwargs): 323 | args = [ '.noise', out, ref, variation, n, fstart, fstop ] 324 | return self._simulate_simple(circuit, *args, **kwargs) 325 | 326 | def tran(self, circuit, tstep, tstop, tstart=0, tmax=None, uic=False): 327 | args = [ '.tran', tstep, tstop, tstart ] 328 | if tmax is not None: 329 | args.append(tmax) 330 | if uic: 331 | args.append('uic') 332 | return self._simulate_simple(circuit, *args) 333 | -------------------------------------------------------------------------------- /spice/unit.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import numpy as np 5 | 6 | class _Unit(object): 7 | def __init__(self, multiplier, prefix, value = 1.0, precision = 6): 8 | assert isinstance(value, int) or isinstance(value, float) 9 | self.value = float(value) * multiplier 10 | self.multiplier = multiplier 11 | self.prefix = prefix 12 | self.precision = precision 13 | 14 | def __rmul__(self, other): 15 | o = self.__class__(self.multiplier, self.prefix) 16 | o.value = float(other) * self.value 17 | return o 18 | 19 | def __mul__(self, other): 20 | o = self.__class__(self.multiplier, self.prefix) 21 | o.value = self.value * float(other) 22 | return o 23 | 24 | def __add__(self, other): 25 | o = self.__class__(self.multiplier, self.prefix) 26 | o.value = self.value + float(other) 27 | return o 28 | 29 | def __radd__(self, other): 30 | o = self.__class__(self.multiplier, self.prefix) 31 | o.value = float(other) + self.value 32 | return o 33 | 34 | def __sub__(self, other): 35 | o = self.__class__(self.multiplier, self.prefix) 36 | o.value = self.value - float(other) 37 | return o 38 | 39 | def __rsub__(self, other): 40 | o = self.__class__(self.multiplier, self.prefix) 41 | o.value = float(other) - self.value 42 | return o 43 | 44 | def __div__(self, other): 45 | o = self.__class__(self.multiplier, self.prefix) 46 | o.value = self.value / float(other) 47 | return o 48 | 49 | def __truediv__(self, other): 50 | o = self.__class__(self.multiplier, self.prefix) 51 | o.value = self.value / float(other) 52 | return o 53 | 54 | def __neg__(self): 55 | o = self.__class__(self.multiplier, self.prefix) 56 | o.value = -self.value 57 | return o 58 | 59 | def __call__(self, value = 1): 60 | return self.__class__(self.multiplier, self.prefix, value) 61 | 62 | def __repr__(self): 63 | s = '%.*f' % (self.precision, self.value / self.multiplier) 64 | i = len(s) 65 | while s[i-1] == '0': 66 | i -= 1 67 | if s[i-1] == '.': 68 | i -= 1 69 | s = s[:i] 70 | s += self.prefix 71 | return s 72 | 73 | def __float__(self): 74 | return self.value 75 | 76 | def __int__(self): 77 | return int(self.value) 78 | 79 | T = _Unit(1E12, 'T') 80 | G = _Unit(1E9, 'G') 81 | M = _Unit(1E6, 'M') 82 | k = _Unit(1E3, 'k') 83 | m = _Unit(1E-3, 'm') 84 | u = _Unit(1E-6, 'u') 85 | n = _Unit(1E-9, 'n') 86 | p = _Unit(1E-12, 'p') 87 | f = _Unit(1E-15, 'f') 88 | 89 | _units = { _.prefix : _ for _ in [ T, G, M, k, m, u, n, p, f ] } 90 | 91 | def parse_unit(s): 92 | u = _units.get(s[-1:]) 93 | if u: 94 | return u(float(s[:-1])) 95 | return float(s) 96 | 97 | def dBa(v): 98 | """Convert value to decibel for amplitudes""" 99 | return 20 * np.log10(np.abs(v)) 100 | 101 | def dBp(v): 102 | """Convert value to decibel for power""" 103 | return 10 * np.log10(np.abs(v)) 104 | 105 | def dBm(v): 106 | """Convert value to decibel for power * 1000 107 | 108 | This is usually used to display dB referenced to 1 mW""" 109 | return 20 * np.log10(np.abs(v) * 1000.0) 110 | 111 | import unittest as _unittest 112 | 113 | class _Test(_unittest.TestCase): 114 | def test_Units(self): 115 | self.assertAlmostEqual(float(3*T), 3E12) 116 | self.assertAlmostEqual(float(3*G), 3E9) 117 | self.assertAlmostEqual(float(3*M), 3E6) 118 | self.assertAlmostEqual(float(3*k), 3E3) 119 | self.assertAlmostEqual(float(3*m), 3E-3) 120 | self.assertAlmostEqual(float(3*u), 3E-6) 121 | self.assertAlmostEqual(float(3*n), 3E-9) 122 | self.assertAlmostEqual(float(3*p), 3E-12) 123 | self.assertAlmostEqual(float(3*f), 3E-15) 124 | 125 | self.assertEqual(repr(3*T), '3T') 126 | self.assertEqual(repr(3*G), '3G') 127 | self.assertEqual(repr(3 * M), '3M') 128 | self.assertEqual(repr(3*k), '3k') 129 | self.assertEqual(repr(3*m), '3m') 130 | self.assertEqual(repr(3*u), '3u') 131 | self.assertEqual(repr(3*n), '3n') 132 | self.assertEqual(repr(3*p), '3p') 133 | self.assertEqual(repr(3*f), '3f') 134 | 135 | # Other ways of initializing a unit 136 | self.assertAlmostEqual(k.value, 1E3) 137 | self.assertAlmostEqual(float(k), 1E3) 138 | self.assertEqual(int(k), 1000) 139 | self.assertEqual(repr(k), '1k') 140 | 141 | # Math 142 | self.assertAlmostEqual(float(2 * (3*M)), 6E6) 143 | self.assertAlmostEqual(float((3*M) * 2), 6E6) 144 | 145 | self.assertAlmostEqual(float(5*M + 2*M), 7E6) 146 | self.assertAlmostEqual(float(5*M - 2*M), 3E6) 147 | 148 | self.assertAlmostEqual(float(5*M + 2E6), 7E6) 149 | self.assertAlmostEqual(float(5*M - 2E6), 3E6) 150 | 151 | self.assertAlmostEqual(float(5E6 + 2*M), 7E6) 152 | self.assertAlmostEqual(float(5E6 - 2*M), 3E6) 153 | 154 | self.assertAlmostEqual(float(5*M + 2E6), 7E6) 155 | self.assertAlmostEqual(float(5*M - 2E6), 3E6) 156 | 157 | self.assertAlmostEqual(float(5*M + 500E3), 5.5E6) 158 | self.assertAlmostEqual(float(5*M - 500E3), 4.5E6) 159 | 160 | self.assertAlmostEqual(float(5*M + 500*k), 5.5E6) 161 | self.assertAlmostEqual(float(5*M - 500*k), 4.5E6) 162 | 163 | self.assertEqual(repr(2 * (3*M)), '6M') 164 | self.assertEqual(repr((3*M) * 2), '6M') 165 | 166 | self.assertEqual(repr(5*M + 2*M), '7M') 167 | self.assertEqual(repr(5*M - 2*M), '3M') 168 | 169 | self.assertEqual(repr(5*M + 2E6), '7M') 170 | self.assertEqual(repr(5*M - 2E6), '3M') 171 | 172 | self.assertEqual(repr(5E6 + 2*M), '7M') 173 | self.assertEqual(repr(5E6 - 2*M), '3M') 174 | 175 | self.assertEqual(repr(5*M + 500*k), '5.5M') 176 | self.assertEqual(repr(5*M - 500*k), '4.5M') 177 | 178 | self.assertEqual(repr(500*k + 5*M), '5500k') 179 | 180 | if __name__ == '__main__': 181 | _unittest.main() 182 | -------------------------------------------------------------------------------- /spice/xyce.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import numpy as np 5 | 6 | from .simulator import SimulatorBase 7 | 8 | class Xyce(SimulatorBase): 9 | SIMULATOR = 'LD_LIBRARY_PATH=/usr/local/xyce/serial/lib /usr/local/xyce/serial/bin/Xyce' 10 | HEADER = '#define XYCE' 11 | 12 | def __init__(self): 13 | super(Xyce, self).__init__() 14 | 15 | def update_variable(self, dataset, var): 16 | name = var.name.upper() 17 | if name in [ 'SWEEP', 'TIME' ]: 18 | pass 19 | elif name in [ 'FREQUENCY' ]: 20 | name = 'SWEEP' 21 | elif name.endswith('#BRANCH'): 22 | name = 'I(%s)' % name[:-7] 23 | elif not name.startswith('V('): 24 | name = 'V(%s)' % name 25 | 26 | var.name = name 27 | 28 | if 'complex' in dataset.flags: 29 | var.dt = np.complex128 30 | else: 31 | var.dt = np.float64 32 | 33 | def _default_trace(self, s): 34 | if s.startswith('***** Percent complete'): 35 | percent = float(s.split()[-2]) 36 | self.progress.percent(percent) 37 | elif s.startswith('***** Current system time'): 38 | pass 39 | elif s.startswith('***** Estimated time to completion'): 40 | pass 41 | else: 42 | super(Xyce, self)._default_trace(s) 43 | 44 | def _merge_xyce(self, data, path): 45 | lines = [] 46 | for l in open(path): 47 | if l[:1].isspace(): 48 | lines[-1] += l 49 | else: 50 | lines.append(l) 51 | 52 | parts = lines[0].strip().split('\t') 53 | 54 | assert parts[0].strip() == 'TITLE="noise output"' 55 | assert parts[1].strip() == 'VARIABLES="frequency"' 56 | 57 | variables = [ None ] 58 | for i, s in enumerate(parts[2:]): 59 | s = s.strip() 60 | assert s.startswith('"') 61 | assert s.endswith('"') 62 | s = s[1:-1].strip() 63 | variables.append(s) 64 | 65 | assert lines[1].strip().split() == ['ZONE','F=POINT','T="Xyce','data"'] 66 | 67 | values = [] 68 | for l in lines[2:]: 69 | vs = np.fromiter(l.strip().split('\t'), dtype = float) 70 | values.append(vs) 71 | values = np.array(values).transpose() 72 | 73 | assert np.allclose(data['SWEEP'].imag, 0) 74 | data['SWEEP'] = abs(data['SWEEP']) 75 | 76 | assert np.allclose(data['SWEEP'], values[0]) 77 | 78 | for i in range(1, len(values)): 79 | name = 'V(%s)' % variables[i].upper() 80 | assert name not in data 81 | data[name] = values[i] 82 | 83 | def _noise_post(self, data, cir_path, raw_path, base): 84 | path = cir_path + '_noise.dat' 85 | self._merge_xyce(data, path) 86 | 87 | def noise(self, circuit, out, ref, variation, n, fstart, fstop, **kwargs): 88 | # Xyce doesn't include the noise spectrums in the raw file, 89 | # print the noise spectrums and add a postprocessing hook to 90 | # merge the print data with the raw data 91 | 92 | args = [ '.noise', out, ref, variation, n, fstart, fstop, 1 ] 93 | args = [ self.fix_param(_) for _ in args ] 94 | s = ' '.join(args) 95 | s += '\n' + '.PRINT NOISE' 96 | return self._simulate(circuit, '', s, 97 | postprocess = self._noise_post, **kwargs) 98 | 99 | Simulator = Xyce 100 | -------------------------------------------------------------------------------- /test-ltspice.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import sys 5 | 6 | from kicad import schema 7 | from kicad import spice_converter 8 | from spice.ltspice import Simulator 9 | 10 | def test(fn): 11 | from spice import unit 12 | 13 | sch = schema.Sch(fn) 14 | circuit = spice_converter.sch_to_circuit(sch) 15 | 16 | sim = Simulator() 17 | 18 | print(sim.circuit_to_spice(circuit)) 19 | 20 | data = sim.dc(circuit, 'v101', -2, 2, 1 * unit.m) 21 | 22 | print(data.keys()) 23 | 24 | print(data['SWEEP']) 25 | print(data['V(VOUT)']) 26 | 27 | if __name__ == '__main__': 28 | if not sys.argv[0]: 29 | sys.argv = [ '', 'examples/butterworth/butterworth.sch' ] 30 | test(sys.argv[1]) 31 | -------------------------------------------------------------------------------- /test-ngspice.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import sys 5 | 6 | from kicad import schema 7 | from kicad import spice_converter 8 | from spice.ngspice import Simulator 9 | 10 | def test(fn): 11 | from spice.unit import m 12 | 13 | sch = schema.Sch(fn) 14 | circuit = spice_converter.sch_to_circuit(sch) 15 | 16 | sim = Simulator() 17 | 18 | print(sim.circuit_to_spice(circuit)) 19 | 20 | data = sim.dc(circuit, 'V101', -2, 2, 1 * m) 21 | 22 | print(data['SWEEP']) 23 | print(data['V(VOUT)']) 24 | 25 | if __name__ == '__main__': 26 | if not sys.argv[0]: 27 | sys.argv = [ '', 'examples/butterworth/butterworth.sch' ] 28 | test(sys.argv[1]) 29 | -------------------------------------------------------------------------------- /test-preprocessor.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import os 5 | 6 | from spice.preprocessor import SpicePreprocessor 7 | 8 | if __name__ == "__main__": 9 | fn = 'examples/tia/spice.lib' 10 | models = 'models' 11 | 12 | pp = SpicePreprocessor() 13 | pp.add_path(models) 14 | pp.define('NGSPICE') 15 | pp.parse(open(fn).read()) 16 | 17 | print(pp.output()) 18 | -------------------------------------------------------------------------------- /test-render.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import sys 5 | 6 | import matplotlib.pyplot as plt 7 | import numpy as np 8 | 9 | from kicad import schema, matplotlib_renderer 10 | 11 | def test(fn): 12 | sch = schema.Sch(fn) 13 | 14 | fig, ax = plt.subplots(figsize = (8, 5.5)) 15 | 16 | # fig.subplots_adjust(left = 0.0, right = 1.0, top = 1.0, bottom = 0.0) 17 | matplotlib_renderer.render_to_ax(ax, sch) 18 | plt.show() 19 | 20 | fig.savefig('butterworth.png') 21 | fig.savefig('butterworth.svg') 22 | fig.savefig('butterworth.pdf') 23 | 24 | if __name__ == '__main__': 25 | if not sys.argv[0]: 26 | sys.argv = [ '', 'examples/butterworth/butterworth.sch' ] 27 | test(sys.argv[1]) 28 | -------------------------------------------------------------------------------- /test-schema.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import sys 5 | 6 | import kicad.schema 7 | 8 | def test(load_fn, save_fn): 9 | sch = kicad.schema.Sch(load_fn) 10 | print() 11 | 12 | with open(save_fn, 'w') as f: 13 | sch.format(f) 14 | 15 | if __name__ == '__main__': 16 | kicad.schema.VERBOSE = 1 17 | if not sys.argv[0]: 18 | sys.argv = [ '', 'examples/butterworth/butterworth.sch', 'out.sch' ] 19 | test(sys.argv[1], sys.argv[2]) 20 | -------------------------------------------------------------------------------- /test-xyce.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | import sys 5 | 6 | from kicad import schema 7 | from kicad import spice_converter 8 | from spice.xyce import Simulator 9 | 10 | def test(fn): 11 | from spice.unit import m 12 | 13 | sch = schema.Sch(fn) 14 | circuit = spice_converter.sch_to_circuit(sch) 15 | 16 | sim = Simulator() 17 | 18 | print(sim.circuit_to_spice(circuit)) 19 | 20 | data = sim.dc(circuit, 'v101', -2, 2, 1 * m) 21 | 22 | print(data['SWEEP']) 23 | print(data['V(VOUT)']) 24 | 25 | if __name__ == '__main__': 26 | if not sys.argv[0]: 27 | sys.argv = [ '', 'examples/butterworth/butterworth.sch' ] 28 | test(sys.argv[1]) 29 | -------------------------------------------------------------------------------- /update-models.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/python 2 | from __future__ import absolute_import, division, print_function, unicode_literals 3 | 4 | from spice.models import LibraryManager 5 | 6 | if __name__ == '__main__': 7 | manager = LibraryManager( 8 | 'models_source', 9 | 'models_download', 10 | 'models') 11 | manager.resolve() 12 | manager.process() 13 | --------------------------------------------------------------------------------