├── .gitignore ├── AUTHORS ├── LICENSE ├── MANIFEST.in ├── README.md ├── demo └── demo.py ├── gearbox ├── __init__.py ├── doc │ ├── Makefile │ ├── __init__.py │ ├── make.bat │ └── source │ │ ├── __init__.py │ │ ├── conf.py │ │ └── index.rst ├── export │ ├── __init__.py │ ├── export.py │ └── templates │ │ ├── abaqus_gear.template │ │ ├── abaqus_gear3D.template │ │ ├── abaqus_pair.template │ │ ├── abaqus_pair3D.template │ │ ├── ansys_gear.template │ │ ├── ansys_gear3D.template │ │ ├── ansys_pair.template │ │ ├── ansys_pair3D.template │ │ ├── comsol_gear.template │ │ ├── comsol_gear3D.template │ │ ├── comsol_pair.template │ │ └── comsol_pair3D.template ├── libs │ ├── __init__.py │ ├── gearprofile.py │ └── maths.py ├── optimization │ ├── __init__.py │ └── addendum.py ├── standards │ ├── __init__.py │ ├── agma.py │ └── iso.py └── transmission │ ├── __init__.py │ └── gears.py ├── setup.cfg └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | *.fuse* 3 | *.pyc 4 | dist 5 | python_gearbox* 6 | .vscode 7 | build 8 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | name: MSc. Eduardo Miguel Firvida Donestevez 2 | email: efirvida@gmail.com 3 | ocupation: Professor of the Mechanical Engineering Departament 4 | Universidad Central "Martha Abreu" de las Villas 5 | Santa Clara, Villa Clara, Cuba 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 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 -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include Makefile CHANGES LICENSE AUTHORS README 2 | exclude Makefile README.md 3 | recursive-include gearbox/doc/source *.rst 4 | recursive-include gearbox/export/templates * 5 | recursive-include demo * 6 | recursive-exclude gearbox *.pyc 7 | recursive-exclude demo/output *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | python-gearbox 2 | ============== 3 | Python library for design of spur and helical gears transmissions 4 | 5 | Install 6 | ------- 7 | the project is on *pypi* server for installation use: 8 | 9 | pip install python-gearbox 10 | 11 | for manual installation download the last release from: 12 | 13 | https://pypi.python.org/pypi/python-gearbox 14 | 15 | python setup.py install 16 | 17 | make shure you have installed all dependencies "jinja2, numpy and scipy" 18 | 19 | Features 20 | -------- 21 | - Gear stresses calculation using AGMA-2101 D04 and ISO-6336 standards 22 | - Optimization of the profile shift modification 23 | - Export 2D and 3D one tooth geometrical models, to *MATLAB/COMSOL* for spur and helical gears 24 | - Export 2D and 3D one tooth geometrical models, to *ABAQUS-CAE* only for spur gears 25 | - Export 2D and 3D one tooth geometrical models, to *ANSYS* only for spur gears 26 | 27 | Help and Documentation 28 | ---------------------- 29 | The documentation isn't ready yet, see the demo.py file for uses example 30 | 31 | Contribute 32 | ---------- 33 | if you want to contribute with the project contact with the author by e-mail 34 | e-mail: efirvida@gmail.com 35 | 36 | License 37 | ------- 38 | This project is licensed under the LGPL License - see the [LICENSE](LICENSE) file for details. 39 | 40 | 41 | For users 42 | --------- 43 | 44 | If you use Python-Gearbox for academic research, please use the following: 45 | 46 | **BibTeX:** 47 | ``` 48 | @misc{https://doi.org/10.5281/zenodo.3660527, 49 | doi = {10.5281/ZENODO.3660527}, 50 | url = {https://zenodo.org/record/3660527}, 51 | author = {Donéstevez, Eduardo Miguel Fírvida}, 52 | keywords = {gearbox, gear transmissions, gears, ISO-6336, AGMA-2101 D04, Gear stresses calculation}, 53 | language = {en}, 54 | title = {Python library for design of spur and helical gears transmissions}, 55 | publisher = {Zenodo}, 56 | year = {2020} 57 | } 58 | ``` 59 | 60 | **APA:** 61 | ``` 62 | Donéstevez, E. M. F. (2020). Python library for design of spur and helical gears transmissions (Version 1.0). Zenodo. https://doi.org/10.5281/ZENODO.3660527 63 | ``` 64 | 65 | **IEEE** 66 | ``` 67 | E. M. F. Donéstevez, “Python library for design of spur and helical gears transmissions.” Zenodo, 09-Feb-2020, doi: 10.5281/ZENODO.3660527. 68 | ``` 69 | -------------------------------------------------------------------------------- /demo/demo.py: -------------------------------------------------------------------------------- 1 | from gearbox.transmission.gears import * 2 | from gearbox.standards.iso import Pitting as isoPitting 3 | from gearbox.standards.iso import Bending as isoBending 4 | from gearbox.standards.agma import Pitting as agmaPitting 5 | from gearbox.standards.agma import Bending as agmaBending 6 | from gearbox.export.export import * 7 | from gearbox.optimization.addendum import * 8 | 9 | module = 2.5 # m 10 | helix_angle = 0.0 # beta 11 | pressure_angle = 20.0 # alpha 12 | 13 | lubricant = Lubricant( 14 | name='Kiruna', 15 | v40=160 16 | ) 17 | 18 | material = Material( 19 | name='AISI 2010', 20 | classification='NV(nitrocar)', 21 | sh_limit=1500., 22 | sf_limit=460., 23 | e=206000., 24 | poisson=0.3, 25 | density=7.83e-6, 26 | brinell=286.6667 27 | ) 28 | 29 | tool = Tool( 30 | ha_p=1, 31 | hf_p=1.25, 32 | rho_fp=0.38, 33 | x=0, 34 | rho_ao=0, 35 | delta_ao=0, 36 | nc=10. 37 | ) 38 | 39 | pinion = Gear( 40 | profile=tool, 41 | material=material, 42 | z=22., 43 | beta=helix_angle, 44 | alpha=pressure_angle, 45 | m=module, 46 | x=0.525, 47 | b=34.0, 48 | bs=34.0, 49 | sr=0.0, 50 | rz=3.67, 51 | precision_grade=6.0, 52 | shaft_diameter=35.0, 53 | schema=3.0, 54 | l=60.0, 55 | s=15.0, 56 | backlash=0.017, 57 | gear_crown=1, 58 | helix_modification=1, 59 | favorable_contact=True, 60 | gear_condition=1 61 | ) 62 | 63 | gear = Gear( 64 | profile=tool, 65 | material=material, 66 | z=40., 67 | m=module, 68 | beta=helix_angle, 69 | alpha=pressure_angle, 70 | x=-0.275, 71 | b=34.0, 72 | bs=34.0, 73 | sr=0.0, 74 | rz=3.67, 75 | precision_grade=6.0, 76 | shaft_diameter=50.0, 77 | schema=3.0, 78 | l=60.0, 79 | s=35.0, 80 | backlash=-0.017, 81 | gear_crown=1, 82 | helix_modification=1, 83 | favorable_contact=True, 84 | gear_condition=1 85 | ) 86 | 87 | pair = [pinion, gear] 88 | 89 | transmission = Transmission( 90 | gears=pair, 91 | lubricant=lubricant, 92 | rpm_in=1450.0, 93 | p=40.0, 94 | l=10000.0, 95 | gear_box_type=2, 96 | ka=1.3, 97 | sh_min=1, 98 | sf_min=1 99 | ) 100 | 101 | print ('========================================') 102 | print ('ISO Pitting') 103 | print (isoPitting(transmission=transmission).calculate()) 104 | print ('========================================') 105 | 106 | print ('========================================') 107 | print ('ISO Bending') 108 | print (isoBending(transmission=transmission).calculate) 109 | print ('========================================') 110 | 111 | print ('========================================') 112 | print ('AGMA Pitting') 113 | print (agmaPitting(transmission=transmission).calculate()) 114 | print ('========================================') 115 | 116 | print ('========================================') 117 | print ('AGMA Bending') 118 | print (agmaBending(transmission=transmission).calculate()) 119 | print ('========================================') 120 | 121 | print ('========================================') 122 | xoptim_bending = Optmization(transmission).bending() 123 | xoptim_pitting_iso = Optmization(transmission).pitting(standard='ISO') 124 | # xoptim_pitting_agma = Optmization(transmission).pitting(standard='AGMA') 125 | print ('Profile shift optimization') 126 | print ('x1=%s, x2=%s for minimum bending stress' % (xoptim_bending[0], xoptim_bending[1])) 127 | print ('x1=%s, x2=%s for minimum contact stress using ISO standard' % (xoptim_pitting_iso[0], xoptim_pitting_iso[1])) 128 | print ('========================================') 129 | 130 | 131 | 132 | 133 | output_folder = os.path.join(os.path.dirname(__file__), 'output') 134 | try: 135 | os.mkdir(output_folder) 136 | except: 137 | pass 138 | 139 | # =============================================== 140 | # EXPORT TO MATLAB/COMSOL SCRIPT 141 | # =============================================== 142 | # 2D model matlab-comsol export 143 | # for 2D export type='2D' is optional because '2D' is the default output 144 | comsol_transmission_model_name2d = 'transmission2d' 145 | comsol_pinion_model_name2d = 'pinion2d' 146 | comsol_wheel_model_name2d = 'wheel2d' 147 | ExportGear(pinion).matlab_comsol(model_name=comsol_pinion_model_name2d, output_folder=output_folder, type='2D') 148 | ExportGear(gear).matlab_comsol(model_name=comsol_wheel_model_name2d, output_folder=output_folder, type='2D') 149 | ExportPair(pair).matlab_comsol(model_name=comsol_transmission_model_name2d, output_folder=output_folder, type='2D') 150 | 151 | # 3D model matlab-comsol export 152 | comsol_transmission_model_name3d = 'transmission3d' 153 | comsol_pinion_model_name3d = 'pinion3d' 154 | comsol_wheel_model_name3d = 'wheel3d' 155 | ExportGear(pinion).matlab_comsol(model_name=comsol_pinion_model_name3d, output_folder=output_folder, type='3D') 156 | ExportGear(gear).matlab_comsol(model_name=comsol_wheel_model_name3d, output_folder=output_folder, type='3D') 157 | ExportPair(pair).matlab_comsol(model_name=comsol_transmission_model_name3d, output_folder=output_folder, type='3D') 158 | 159 | # =============================================== 160 | # EXPORT TO ABAQUS PYTHON 161 | # =============================================== 162 | # 2D model abaqus export 163 | # for 2D export type='2D' is optional because '2D' is the default output 164 | abaqus_transmission_model_name2d = 'transmission2d' 165 | abaqus_pinion_model_name2d = 'pinion2d' 166 | abaqus_wheel_model_name2d = 'wheel2d' 167 | ExportGear(pinion).abaqus(model_name=abaqus_pinion_model_name2d, output_folder=output_folder, type='2D') 168 | ExportGear(gear).abaqus(model_name=abaqus_wheel_model_name2d, output_folder=output_folder, type='2D') 169 | ExportPair(pair).abaqus(model_name=abaqus_transmission_model_name2d, output_folder=output_folder, type='2D') 170 | 171 | # 3D model abaqus export 172 | abaqus_transmission_model_name3d = 'transmission3d' 173 | abaqus_pinion_model_name3d = 'pinion3d' 174 | abaqus_wheel_model_name3d = 'wheel3d' 175 | ExportGear(pinion).abaqus(model_name=abaqus_pinion_model_name3d, output_folder=output_folder, type='3D') 176 | ExportGear(gear).abaqus(model_name=abaqus_wheel_model_name3d, output_folder=output_folder, type='3D') 177 | ExportPair(pair).abaqus(model_name=abaqus_transmission_model_name3d, output_folder=output_folder, type='3D') 178 | 179 | # =============================================== 180 | # EXPORT TO ANSYS/WOKRBENCH Script 181 | # =============================================== 182 | # 2D model abaqus export 183 | # for 2D export type='2D' is optional because '2D' is the default output 184 | ansys_transmission_model_name2d = 'transmission2d' 185 | ansys_pinion_model_name2d = 'pinion2d' 186 | ansys_wheel_model_name2d = 'wheel2d' 187 | ExportGear(pinion).ansys(model_name=ansys_pinion_model_name2d, output_folder=output_folder, type='2D') 188 | ExportGear(gear).ansys(model_name=ansys_wheel_model_name2d, output_folder=output_folder, type='2D') 189 | ExportPair(pair).ansys(model_name=ansys_transmission_model_name2d, output_folder=output_folder, type='2D') 190 | # 191 | # 3D model ansys export 192 | ansys_transmission_model_name3d = 'transmission3d' 193 | ansys_pinion_model_name3d = 'pinion3d' 194 | ansys_wheel_model_name3d = 'wheel3d' 195 | ExportGear(pinion).ansys(model_name=ansys_pinion_model_name3d, output_folder=output_folder, type='3D') 196 | ExportGear(gear).ansys(model_name=ansys_wheel_model_name3d, output_folder=output_folder, type='3D') 197 | ExportPair(pair).ansys(model_name=ansys_transmission_model_name3d, output_folder=output_folder, type='3D') 198 | -------------------------------------------------------------------------------- /gearbox/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'efirvida' 2 | -------------------------------------------------------------------------------- /gearbox/doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " applehelp to make an Apple Help Book" 34 | @echo " devhelp to make HTML files and a Devhelp project" 35 | @echo " epub to make an epub" 36 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 37 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 38 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 39 | @echo " text to make text files" 40 | @echo " man to make manual pages" 41 | @echo " texinfo to make Texinfo files" 42 | @echo " info to make Texinfo files and run them through makeinfo" 43 | @echo " gettext to make PO message catalogs" 44 | @echo " changes to make an overview of all changed/added/deprecated items" 45 | @echo " xml to make Docutils-native XML files" 46 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 47 | @echo " linkcheck to check all external links for integrity" 48 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 49 | @echo " coverage to run coverage check of the documentation (if enabled)" 50 | 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | html: 55 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 56 | @echo 57 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 58 | 59 | dirhtml: 60 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 61 | @echo 62 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 63 | 64 | singlehtml: 65 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 66 | @echo 67 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 68 | 69 | pickle: 70 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 71 | @echo 72 | @echo "Build finished; now you can process the pickle files." 73 | 74 | json: 75 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 76 | @echo 77 | @echo "Build finished; now you can process the JSON files." 78 | 79 | htmlhelp: 80 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 81 | @echo 82 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 83 | ".hhp project file in $(BUILDDIR)/htmlhelp." 84 | 85 | qthelp: 86 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 87 | @echo 88 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 89 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 90 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-gearbox.qhcp" 91 | @echo "To view the help file:" 92 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-gearbox.qhc" 93 | 94 | applehelp: 95 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 96 | @echo 97 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 98 | @echo "N.B. You won't be able to view it unless you put it in" \ 99 | "~/Library/Documentation/Help or install it in your application" \ 100 | "bundle." 101 | 102 | devhelp: 103 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 104 | @echo 105 | @echo "Build finished." 106 | @echo "To view the help file:" 107 | @echo "# mkdir -p $$HOME/.local/share/devhelp/python-gearbox" 108 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/python-gearbox" 109 | @echo "# devhelp" 110 | 111 | epub: 112 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 113 | @echo 114 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 115 | 116 | latex: 117 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 118 | @echo 119 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 120 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 121 | "(use \`make latexpdf' here to do that automatically)." 122 | 123 | latexpdf: 124 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 125 | @echo "Running LaTeX files through pdflatex..." 126 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 127 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 128 | 129 | latexpdfja: 130 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 131 | @echo "Running LaTeX files through platex and dvipdfmx..." 132 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 133 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 134 | 135 | text: 136 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 137 | @echo 138 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 139 | 140 | man: 141 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 142 | @echo 143 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 144 | 145 | texinfo: 146 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 147 | @echo 148 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 149 | @echo "Run \`make' in that directory to run these through makeinfo" \ 150 | "(use \`make info' here to do that automatically)." 151 | 152 | info: 153 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 154 | @echo "Running Texinfo files through makeinfo..." 155 | make -C $(BUILDDIR)/texinfo info 156 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 157 | 158 | gettext: 159 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 160 | @echo 161 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 162 | 163 | changes: 164 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 165 | @echo 166 | @echo "The overview file is in $(BUILDDIR)/changes." 167 | 168 | linkcheck: 169 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 170 | @echo 171 | @echo "Link check complete; look for any errors in the above output " \ 172 | "or in $(BUILDDIR)/linkcheck/output.txt." 173 | 174 | doctest: 175 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 176 | @echo "Testing of doctests in the sources finished, look at the " \ 177 | "results in $(BUILDDIR)/doctest/output.txt." 178 | 179 | coverage: 180 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 181 | @echo "Testing of coverage in the sources finished, look at the " \ 182 | "results in $(BUILDDIR)/coverage/python.txt." 183 | 184 | xml: 185 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 186 | @echo 187 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 188 | 189 | pseudoxml: 190 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 191 | @echo 192 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 193 | -------------------------------------------------------------------------------- /gearbox/doc/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'efirvida' 2 | -------------------------------------------------------------------------------- /gearbox/doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation test 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | set I18NSPHINXOPTS=%SPHINXOPTS% source 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | echo. coverage to run coverage check of the documentation if enabled 41 | goto end 42 | ) 43 | 44 | if "%1" == "clean" ( 45 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 46 | del /q /s %BUILDDIR%\* 47 | goto end 48 | ) 49 | 50 | 51 | REM Check if sphinx-build is available and fallback to Python version if any 52 | %SPHINXBUILD% 2> nul 53 | if errorlevel 9009 goto sphinx_python 54 | goto sphinx_ok 55 | 56 | :sphinx_python 57 | 58 | set SPHINXBUILD=python -m sphinx.__init__ 59 | %SPHINXBUILD% 2> nul 60 | if errorlevel 9009 ( 61 | echo. 62 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 63 | echo.installed, then set the SPHINXBUILD environment variable to point 64 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 65 | echo.may add the Sphinx directory to PATH. 66 | echo. 67 | echo.If you don't have Sphinx installed, grab it from 68 | echo.http://sphinx-doc.org/ 69 | exit /b 1 70 | ) 71 | 72 | :sphinx_ok 73 | 74 | 75 | if "%1" == "html" ( 76 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 80 | goto end 81 | ) 82 | 83 | if "%1" == "dirhtml" ( 84 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 88 | goto end 89 | ) 90 | 91 | if "%1" == "singlehtml" ( 92 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 93 | if errorlevel 1 exit /b 1 94 | echo. 95 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 96 | goto end 97 | ) 98 | 99 | if "%1" == "pickle" ( 100 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 101 | if errorlevel 1 exit /b 1 102 | echo. 103 | echo.Build finished; now you can process the pickle files. 104 | goto end 105 | ) 106 | 107 | if "%1" == "json" ( 108 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 109 | if errorlevel 1 exit /b 1 110 | echo. 111 | echo.Build finished; now you can process the JSON files. 112 | goto end 113 | ) 114 | 115 | if "%1" == "htmlhelp" ( 116 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 117 | if errorlevel 1 exit /b 1 118 | echo. 119 | echo.Build finished; now you can run HTML Help Workshop with the ^ 120 | .hhp project file in %BUILDDIR%/htmlhelp. 121 | goto end 122 | ) 123 | 124 | if "%1" == "qthelp" ( 125 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 129 | .qhcp project file in %BUILDDIR%/qthelp, like this: 130 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\python-gearbox.qhcp 131 | echo.To view the help file: 132 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\python-gearbox.ghc 133 | goto end 134 | ) 135 | 136 | if "%1" == "devhelp" ( 137 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. 141 | goto end 142 | ) 143 | 144 | if "%1" == "epub" ( 145 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 149 | goto end 150 | ) 151 | 152 | if "%1" == "latex" ( 153 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 157 | goto end 158 | ) 159 | 160 | if "%1" == "latexpdf" ( 161 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 162 | cd %BUILDDIR%/latex 163 | make all-pdf 164 | cd %~dp0 165 | echo. 166 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdfja" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf-ja 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "text" ( 181 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 182 | if errorlevel 1 exit /b 1 183 | echo. 184 | echo.Build finished. The text files are in %BUILDDIR%/text. 185 | goto end 186 | ) 187 | 188 | if "%1" == "man" ( 189 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 190 | if errorlevel 1 exit /b 1 191 | echo. 192 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 193 | goto end 194 | ) 195 | 196 | if "%1" == "texinfo" ( 197 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 198 | if errorlevel 1 exit /b 1 199 | echo. 200 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 201 | goto end 202 | ) 203 | 204 | if "%1" == "gettext" ( 205 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 206 | if errorlevel 1 exit /b 1 207 | echo. 208 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 209 | goto end 210 | ) 211 | 212 | if "%1" == "changes" ( 213 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 214 | if errorlevel 1 exit /b 1 215 | echo. 216 | echo.The overview file is in %BUILDDIR%/changes. 217 | goto end 218 | ) 219 | 220 | if "%1" == "linkcheck" ( 221 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 222 | if errorlevel 1 exit /b 1 223 | echo. 224 | echo.Link check complete; look for any errors in the above output ^ 225 | or in %BUILDDIR%/linkcheck/output.txt. 226 | goto end 227 | ) 228 | 229 | if "%1" == "doctest" ( 230 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 231 | if errorlevel 1 exit /b 1 232 | echo. 233 | echo.Testing of doctests in the sources finished, look at the ^ 234 | results in %BUILDDIR%/doctest/output.txt. 235 | goto end 236 | ) 237 | 238 | if "%1" == "coverage" ( 239 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 240 | if errorlevel 1 exit /b 1 241 | echo. 242 | echo.Testing of coverage in the sources finished, look at the ^ 243 | results in %BUILDDIR%/coverage/python.txt. 244 | goto end 245 | ) 246 | 247 | if "%1" == "xml" ( 248 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 249 | if errorlevel 1 exit /b 1 250 | echo. 251 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 252 | goto end 253 | ) 254 | 255 | if "%1" == "pseudoxml" ( 256 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 257 | if errorlevel 1 exit /b 1 258 | echo. 259 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 260 | goto end 261 | ) 262 | 263 | :end 264 | -------------------------------------------------------------------------------- /gearbox/doc/source/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'efirvida' 2 | -------------------------------------------------------------------------------- /gearbox/doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # python-gearbox documentation build configuration file, created by 4 | # sphinx-quickstart on Thu Apr 23 12:23:08 2015. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # sys.path.insert(0, os.path.abspath('.')) 19 | 20 | # -- General configuration ------------------------------------------------ 21 | 22 | # If your documentation needs a minimal Sphinx version, state it here. 23 | # needs_sphinx = '1.0' 24 | 25 | # Add any Sphinx extension module names here, as strings. They can be 26 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 27 | # ones. 28 | extensions = [ 29 | 'sphinx.ext.autodoc', 30 | 'sphinx.ext.doctest', 31 | 'sphinx.ext.intersphinx', 32 | 'sphinx.ext.todo', 33 | 'sphinx.ext.coverage', 34 | 'sphinx.ext.mathjax', 35 | 'sphinx.ext.ifconfig', 36 | 'sphinx.ext.viewcode', 37 | ] 38 | 39 | # Add any paths that contain templates here, relative to this directory. 40 | templates_path = ['_templates'] 41 | 42 | # The suffix(es) of source filenames. 43 | # You can specify multiple suffix as a list of string: 44 | # source_suffix = ['.rst', '.md'] 45 | source_suffix = '.rst' 46 | 47 | # The encoding of source files. 48 | # source_encoding = 'utf-8-sig' 49 | 50 | # The master toctree document. 51 | master_doc = 'index' 52 | 53 | # General information about the project. 54 | project = u'python-gearbox' 55 | copyright = u'2015, Eduardo M. Fírvida Donéstevez' 56 | author = u'Eduardo M. Fírvida Donéstevez' 57 | 58 | # The version info for the project you're documenting, acts as replacement for 59 | # |version| and |release|, also used in various other places throughout the 60 | # built documents. 61 | # 62 | # The short X.Y version. 63 | version = '0.1' 64 | # The full version, including alpha/beta/rc tags. 65 | release = '0.1' 66 | 67 | # The language for content autogenerated by Sphinx. Refer to documentation 68 | # for a list of supported languages. 69 | # 70 | # This is also used if you do content translation via gettext catalogs. 71 | # Usually you set "language" from the command line for these cases. 72 | language = None 73 | 74 | # There are two options for replacing |today|: either, you set today to some 75 | # non-false value, then it is used: 76 | # today = '' 77 | # Else, today_fmt is used as the format for a strftime call. 78 | # today_fmt = '%B %d, %Y' 79 | 80 | # List of patterns, relative to source directory, that match files and 81 | # directories to ignore when looking for source files. 82 | exclude_patterns = [] 83 | 84 | # The reST default role (used for this markup: `text`) to use for all 85 | # documents. 86 | # default_role = None 87 | 88 | # If true, '()' will be appended to :func: etc. cross-reference text. 89 | # add_function_parentheses = True 90 | 91 | # If true, the current module name will be prepended to all description 92 | # unit titles (such as .. function::). 93 | # add_module_names = True 94 | 95 | # If true, sectionauthor and moduleauthor directives will be shown in the 96 | # output. They are ignored by default. 97 | # show_authors = False 98 | 99 | # The name of the Pygments (syntax highlighting) style to use. 100 | pygments_style = 'sphinx' 101 | 102 | # A list of ignored prefixes for module index sorting. 103 | # modindex_common_prefix = [] 104 | 105 | # If true, keep warnings as "system message" paragraphs in the built documents. 106 | # keep_warnings = False 107 | 108 | # If true, `todo` and `todoList` produce output, else they produce nothing. 109 | todo_include_todos = True 110 | 111 | 112 | # -- Options for HTML output ---------------------------------------------- 113 | 114 | # The theme to use for HTML and HTML Help pages. See the documentation for 115 | # a list of builtin themes. 116 | html_theme = 'alabaster' 117 | 118 | # Theme options are theme-specific and customize the look and feel of a theme 119 | # further. For a list of options available for each theme, see the 120 | # documentation. 121 | # html_theme_options = {} 122 | 123 | # Add any paths that contain custom themes here, relative to this directory. 124 | # html_theme_path = [] 125 | 126 | # The name for this set of Sphinx documents. If None, it defaults to 127 | # " v documentation". 128 | # html_title = None 129 | 130 | # A shorter title for the navigation bar. Default is the same as html_title. 131 | # html_short_title = None 132 | 133 | # The name of an image file (relative to this directory) to place at the top 134 | # of the sidebar. 135 | # html_logo = None 136 | 137 | # The name of an image file (within the static path) to use as favicon of the 138 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 139 | # pixels large. 140 | # html_favicon = None 141 | 142 | # Add any paths that contain custom static files (such as style sheets) here, 143 | # relative to this directory. They are copied after the builtin static files, 144 | # so a file named "default.css" will overwrite the builtin "default.css". 145 | html_static_path = ['_static'] 146 | 147 | # Add any extra paths that contain custom files (such as robots.txt or 148 | # .htaccess) here, relative to this directory. These files are copied 149 | # directly to the root of the documentation. 150 | # html_extra_path = [] 151 | 152 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 153 | # using the given strftime format. 154 | # html_last_updated_fmt = '%b %d, %Y' 155 | 156 | # If true, SmartyPants will be used to convert quotes and dashes to 157 | # typographically correct entities. 158 | # html_use_smartypants = True 159 | 160 | # Custom sidebar templates, maps document names to template names. 161 | # html_sidebars = {} 162 | 163 | # Additional templates that should be rendered to pages, maps page names to 164 | # template names. 165 | # html_additional_pages = {} 166 | 167 | # If false, no module index is generated. 168 | # html_domain_indices = True 169 | 170 | # If false, no index is generated. 171 | # html_use_index = True 172 | 173 | # If true, the index is split into individual pages for each letter. 174 | # html_split_index = False 175 | 176 | # If true, links to the reST sources are added to the pages. 177 | # html_show_sourcelink = True 178 | 179 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 180 | # html_show_sphinx = True 181 | 182 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 183 | # html_show_copyright = True 184 | 185 | # If true, an OpenSearch description file will be output, and all pages will 186 | # contain a tag referring to it. The value of this option must be the 187 | # base URL from which the finished HTML is served. 188 | # html_use_opensearch = '' 189 | 190 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 191 | # html_file_suffix = None 192 | 193 | # Language to be used for generating the HTML full-text search index. 194 | # Sphinx supports the following languages: 195 | # 'da', 'de', 'en', 'es', 'fi', 'fr', 'hu', 'it', 'ja' 196 | # 'nl', 'no', 'pt', 'ro', 'ru', 'sv', 'tr' 197 | # html_search_language = 'en' 198 | 199 | # A dictionary with options for the search language support, empty by default. 200 | # Now only 'ja' uses this config value 201 | # html_search_options = {'type': 'default'} 202 | 203 | # The name of a javascript file (relative to the configuration directory) that 204 | # implements a search results scorer. If empty, the default will be used. 205 | # html_search_scorer = 'scorer.js' 206 | 207 | # Output file base name for HTML help builder. 208 | htmlhelp_basename = 'python-gearboxdoc' 209 | 210 | # -- Options for LaTeX output --------------------------------------------- 211 | 212 | latex_elements = { 213 | # The paper size ('letterpaper' or 'a4paper'). 214 | # 'papersize': 'letterpaper', 215 | 216 | # The font size ('10pt', '11pt' or '12pt'). 217 | # 'pointsize': '10pt', 218 | 219 | # Additional stuff for the LaTeX preamble. 220 | # 'preamble': '', 221 | 222 | # Latex figure (float) alignment 223 | # 'figure_align': 'htbp', 224 | } 225 | 226 | # Grouping the document tree into LaTeX files. List of tuples 227 | # (source start file, target name, title, 228 | # author, documentclass [howto, manual, or own class]). 229 | latex_documents = [ 230 | (master_doc, 'python-gearbox.tex', u'python-gearbox Documentation', 231 | u'Eduardo M. Fírvida Donéstevez', 'manual'), 232 | ] 233 | 234 | # The name of an image file (relative to this directory) to place at the top of 235 | # the title page. 236 | # latex_logo = None 237 | 238 | # For "manual" documents, if this is true, then toplevel headings are parts, 239 | # not chapters. 240 | # latex_use_parts = False 241 | 242 | # If true, show page references after internal links. 243 | # latex_show_pagerefs = False 244 | 245 | # If true, show URL addresses after external links. 246 | # latex_show_urls = False 247 | 248 | # Documents to append as an appendix to all manuals. 249 | # latex_appendices = [] 250 | 251 | # If false, no module index is generated. 252 | # latex_domain_indices = True 253 | 254 | 255 | # -- Options for manual page output --------------------------------------- 256 | 257 | # One entry per manual page. List of tuples 258 | # (source start file, name, description, authors, manual section). 259 | man_pages = [ 260 | (master_doc, 'python-gearbox', u'python-gearbox Documentation', 261 | [author], 1) 262 | ] 263 | 264 | # If true, show URL addresses after external links. 265 | # man_show_urls = False 266 | 267 | 268 | # -- Options for Texinfo output ------------------------------------------- 269 | 270 | # Grouping the document tree into Texinfo files. List of tuples 271 | # (source start file, target name, title, author, 272 | # dir menu entry, description, category) 273 | texinfo_documents = [ 274 | (master_doc, 'python-gearbox', u'python-gearbox Documentation', 275 | author, 'python-gearbox', 'One line description of project.', 276 | 'Miscellaneous'), 277 | ] 278 | 279 | # Documents to append as an appendix to all manuals. 280 | # texinfo_appendices = [] 281 | 282 | # If false, no module index is generated. 283 | # texinfo_domain_indices = True 284 | 285 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 286 | # texinfo_show_urls = 'footnote' 287 | 288 | # If true, do not generate a @detailmenu in the "Top" node's menu. 289 | # texinfo_no_detailmenu = False 290 | 291 | 292 | # -- Options for Epub output ---------------------------------------------- 293 | 294 | # Bibliographic Dublin Core info. 295 | epub_title = project 296 | epub_author = author 297 | epub_publisher = author 298 | epub_copyright = copyright 299 | 300 | # The basename for the epub file. It defaults to the project name. 301 | # epub_basename = project 302 | 303 | # The HTML theme for the epub output. Since the default themes are not optimized 304 | # for small screen space, using the same theme for HTML and epub output is 305 | # usually not wise. This defaults to 'epub', a theme designed to save visual 306 | # space. 307 | # epub_theme = 'epub' 308 | 309 | # The language of the text. It defaults to the language option 310 | # or 'en' if the language is not set. 311 | # epub_language = '' 312 | 313 | # The scheme of the identifier. Typical schemes are ISBN or URL. 314 | # epub_scheme = '' 315 | 316 | # The unique identifier of the text. This can be a ISBN number 317 | # or the project homepage. 318 | # epub_identifier = '' 319 | 320 | # A unique identification for the text. 321 | # epub_uid = '' 322 | 323 | # A tuple containing the cover image and cover page html template filenames. 324 | # epub_cover = () 325 | 326 | # A sequence of (type, uri, title) tuples for the guide element of content.opf. 327 | # epub_guide = () 328 | 329 | # HTML files that should be inserted before the pages created by sphinx. 330 | # The format is a list of tuples containing the path and title. 331 | # epub_pre_files = [] 332 | 333 | # HTML files shat should be inserted after the pages created by sphinx. 334 | # The format is a list of tuples containing the path and title. 335 | # epub_post_files = [] 336 | 337 | # A list of files that should not be packed into the epub file. 338 | epub_exclude_files = ['search.html'] 339 | 340 | # The depth of the table of contents in toc.ncx. 341 | # epub_tocdepth = 3 342 | 343 | # Allow duplicate toc entries. 344 | # epub_tocdup = True 345 | 346 | # Choose between 'default' and 'includehidden'. 347 | # epub_tocscope = 'default' 348 | 349 | # Fix unsupported image types using the Pillow. 350 | # epub_fix_images = False 351 | 352 | # Scale large images. 353 | # epub_max_image_width = 0 354 | 355 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 356 | # epub_show_urls = 'inline' 357 | 358 | # If false, no index is generated. 359 | # epub_use_index = True 360 | 361 | 362 | # Example configuration for intersphinx: refer to the Python standard library. 363 | intersphinx_mapping = {'https://docs.python.org/': None} 364 | -------------------------------------------------------------------------------- /gearbox/doc/source/index.rst: -------------------------------------------------------------------------------- 1 | .. python-gearbox documentation master file, created by 2 | sphinx-quickstart on Thu Apr 23 12:23:08 2015. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to python-gearbox's documentation! 7 | ========================================== 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | 15 | 16 | Indices and tables 17 | ================== 18 | 19 | * :ref:`genindex` 20 | * :ref:`modindex` 21 | * :ref:`search` 22 | 23 | -------------------------------------------------------------------------------- /gearbox/export/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'efirvida' 2 | -------------------------------------------------------------------------------- /gearbox/export/export.py: -------------------------------------------------------------------------------- 1 | # coding=utf-8 2 | import os 3 | from math import radians, tan, cos 4 | 5 | from jinja2 import Environment, FileSystemLoader 6 | 7 | import gearbox 8 | from gearbox.libs.gearprofile import GearExport 9 | from gearbox.libs.maths import rotate, involute, arcinvolute 10 | import platform 11 | 12 | OperatingSystem = platform.uname()[0] 13 | 14 | class ExportGear(object): 15 | """ 16 | 17 | :param gear: 18 | """ 19 | 20 | def __init__(self, gear): 21 | template_path = os.path.join(gearbox.__path__[0], 'export', 'templates') 22 | self.env = Environment(loader=FileSystemLoader(template_path)) 23 | 24 | self.gear = gear 25 | z = gear.z 26 | m = gear.m 27 | beta = gear.beta 28 | alpha = gear.alpha 29 | x = gear.x 30 | rho_f = gear.profile.rho_fp 31 | d_s = gear.shaft_diameter 32 | c = gear.profile.c 33 | b = gear.b 34 | 35 | gear_data = {'m_n': m, 'z': z, 'beta': beta, 'alpha_n': alpha, 'x': x, 'rho_f': rho_f, 'd_s': d_s, 'c': c, 36 | 'b': b} 37 | self.gear.export_data = GearExport(gear_data) 38 | 39 | def matlab_comsol(self, output_folder='', model_name='model', type='2D'): 40 | """ 41 | 42 | :param model_name: 43 | :param output_folder: 44 | :param type: 45 | """ 46 | 47 | if type is '2D': 48 | template = self.env.get_template('comsol_gear.template') 49 | elif type is '3D': 50 | template = self.env.get_template('comsol_gear3D.template') 51 | else: 52 | raise ValueError('type must be \'2D\' or \'3D\' default Value is \'2D\'') 53 | 54 | model_name = model_name.replace(' ', '_') 55 | if OperatingSystem=="Windows": 56 | output_folder = output_folder.replace('/', '\\') 57 | 58 | output_from_parsed_template = template.render(gear=self.gear.export_data.gear, model_name=model_name, 59 | model_path=output_folder) 60 | 61 | with open(output_folder + '/' + model_name + '.m', "w") as fh: 62 | fh.write(output_from_parsed_template) 63 | 64 | def abaqus(self, output_folder='', model_name='model', type='2D'): 65 | """ 66 | 67 | :param output_folder: 68 | :param model_name: 69 | :param type: 70 | :raise ValueError: 71 | """ 72 | 73 | if type is '2D': 74 | template = self.env.get_template('abaqus_gear.template') 75 | elif type is '3D': 76 | template = self.env.get_template('abaqus_gear3D.template') 77 | else: 78 | raise ValueError('type must be \'2D\' or \'3D\' default Value is \'2D\'') 79 | 80 | model_name = model_name.replace(' ', '_') 81 | if OperatingSystem=="Windows": 82 | output_folder = output_folder.replace('/', '\\') 83 | 84 | output_from_parsed_template = template.render(gear=self.gear.export_data.gear, model_name=model_name, 85 | model_path=output_folder) 86 | 87 | with open(output_folder + '/' + model_name + '.py', "w") as fh: 88 | fh.write(output_from_parsed_template) 89 | 90 | def ansys(self, output_folder='', model_name='model', type='2D'): 91 | """ 92 | 93 | :param output_folder: 94 | :param model_name: 95 | :param type: 96 | :raise ValueError: 97 | """ 98 | 99 | if type is '2D': 100 | template = self.env.get_template('ansys_gear.template') 101 | elif type is '3D': 102 | template = self.env.get_template('ansys_gear3D.template') 103 | else: 104 | raise ValueError('type must be \'2D\' or \'3D\' default Value is \'2D\'') 105 | 106 | model_name = model_name.replace(' ', '_') 107 | if OperatingSystem=="Windows": 108 | output_folder = output_folder.replace('/', '\\') 109 | 110 | final = [] 111 | for i in self.gear.export_data.gear.formcoords: 112 | final.append([-i[0], i[1]]) 113 | final.reverse() 114 | self.gear.export_data.gear.formcoords = self.gear.export_data.gear.formcoords + final 115 | 116 | self.gear.export_data.gear.shaftcoords[0] = [-self.gear.export_data.gear.shaftcoords[1][0], 117 | self.gear.export_data.gear.shaftcoords[1][1]] 118 | 119 | output_from_parsed_template = template.render(gear=self.gear.export_data.gear, model_name=model_name, 120 | model_path=output_folder) 121 | 122 | with open(output_folder + '/' + model_name + '.js', "w") as fh: 123 | fh.write(output_from_parsed_template) 124 | 125 | 126 | class ExportPair(object): 127 | """ 128 | 129 | :param pair: 130 | """ 131 | 132 | def __init__(self, pair): 133 | template_path = os.path.join(gearbox.__path__[0], 'export', 'templates') 134 | self.env = Environment(loader=FileSystemLoader(template_path)) 135 | 136 | self.pinion = ExportGear(pair[0]).gear.export_data.gear 137 | self.wheel = ExportGear(pair[1]).gear.export_data.gear 138 | 139 | shaft = [[0, (self.wheel.data['d_s'] / 2)], rotate([[0, self.wheel.data['d_s'] / 2]], 0.5 * ( 140 | (self.wheel.data['d_s'] / self.wheel.data['z']) * 360 / self.wheel.data['d_s']))[0]] 141 | 142 | coords = rotate(self.wheel.formcoords, 180) 143 | 144 | aw = self.__aw() 145 | 146 | self.wheel.shaftcoords = [[coord[0], coord[1] + aw] for coord in rotate(shaft, 180)] 147 | self.wheel.formcoords = [[coord[0], coord[1] + aw] for coord in coords] 148 | 149 | self.pinion.rotate_x = 0 150 | self.pinion.rotate_y = 0 151 | 152 | self.wheel.rotate_x = 0 153 | self.wheel.rotate_y = aw 154 | 155 | def matlab_comsol(self, output_folder='', model_name='model', type='2D'): 156 | """ 157 | 158 | :param output_folder: 159 | :param model_name: 160 | :param type: 161 | """ 162 | 163 | if type is '2D': 164 | template = self.env.get_template('comsol_pair.template') 165 | elif type is '3D': 166 | template = self.env.get_template('comsol_pair3D.template') 167 | else: 168 | raise ValueError('type must be \'2D\' or \'3D\' default Value is \'2D\'') 169 | 170 | pair = [self.pinion, self.wheel] 171 | 172 | model_name = model_name.replace(' ', '_') 173 | 174 | output_from_parsed_template = template.render(pair=pair, model_name=model_name, model_path=output_folder) 175 | 176 | with open(output_folder + '/' + model_name + '.m', "w") as fh: 177 | fh.write(output_from_parsed_template) 178 | 179 | def abaqus(self, output_folder='', model_name='model', type='2D'): 180 | """ 181 | 182 | :param output_folder: 183 | :param model_name: 184 | :param type: 185 | """ 186 | 187 | if type is '2D': 188 | template = self.env.get_template('abaqus_pair.template') 189 | elif type is '3D': 190 | template = self.env.get_template('abaqus_pair3D.template') 191 | else: 192 | raise ValueError('type must be \'2D\' or \'3D\' default Value is \'2D\'') 193 | 194 | pair = [self.pinion, self.wheel] 195 | 196 | model_name = model_name.replace(' ', '_') 197 | 198 | output_from_parsed_template = template.render(pair=pair, model_name=model_name, model_path=output_folder) 199 | 200 | with open(output_folder + '/' + model_name + '.py', "w") as fh: 201 | fh.write(output_from_parsed_template) 202 | 203 | def ansys(self, output_folder='', model_name='model', type='2D'): 204 | """ 205 | 206 | :param output_folder: 207 | :param model_name: 208 | :param type: 209 | """ 210 | if type is '2D': 211 | template = self.env.get_template('ansys_pair.template') 212 | elif type is '3D': 213 | template = self.env.get_template('ansys_pair3D.template') 214 | else: 215 | raise ValueError('type must be \'2D\' or \'3D\' default Value is \'2D\'') 216 | 217 | pinion = [] 218 | for i in self.pinion.formcoords: 219 | pinion.append([-i[0], i[1]]) 220 | pinion.reverse() 221 | self.pinion.formcoords = rotate(self.pinion.formcoords + pinion, self.pinion.rotate_ang) 222 | self.pinion.shaftcoords[0] = [-self.pinion.shaftcoords[1][0], self.pinion.shaftcoords[1][1]] 223 | self.pinion.shaftcoords = rotate(self.pinion.shaftcoords, self.pinion.rotate_ang) 224 | 225 | wheel = [] 226 | for i in self.wheel.formcoords: 227 | wheel.append([-i[0], i[1]]) 228 | wheel.reverse() 229 | self.wheel.formcoords = self.wheel.formcoords + wheel 230 | self.wheel.shaftcoords[0] = [-self.wheel.shaftcoords[1][0], self.wheel.shaftcoords[1][1]] 231 | 232 | self.wheel.formcoords = rotate(self.wheel.formcoords, self.wheel.rotate_ang, (0, self.__aw())) 233 | self.wheel.shaftcoords = rotate(self.wheel.shaftcoords, self.wheel.rotate_ang, (0, self.__aw())) 234 | 235 | pair = [self.pinion, self.wheel] 236 | model_name = model_name.replace(' ', '_') 237 | output_from_parsed_template = template.render(pair=pair, model_name=model_name, model_path=output_folder) 238 | 239 | with open(output_folder + '/' + model_name + '.js', "w") as fh: 240 | fh.write(output_from_parsed_template) 241 | 242 | def __aw(self): 243 | inv = involute(self.pinion.data['alpha_t']) + 2 * (self.pinion.data['x'] + self.wheel.data['x']) / ( 244 | self.pinion.data['z'] + self.wheel.data['z']) * tan( 245 | radians(self.pinion.data['alpha_n'])) 246 | alpha_wt = arcinvolute(inv) 247 | a = ((self.pinion.data['z'] + self.wheel.data['z']) * self.pinion.data['m_n']) / ( 248 | 2 * cos(radians(self.pinion.data['beta']))) 249 | aw = a * cos(radians(self.pinion.data['alpha_n'])) / cos(radians(alpha_wt)) 250 | return aw 251 | -------------------------------------------------------------------------------- /gearbox/export/templates/abaqus_gear.template: -------------------------------------------------------------------------------- 1 | from abaqus import * 2 | from abaqusConstants import * 3 | 4 | backwardCompatibility.setValues(includeDeprecated=True, reportDeprecated=False) 5 | 6 | myModel = mdb.Model(name='{{model_name}}') 7 | 8 | gear_formcoords = {{ gear.formcoords }} 9 | gear_shaftcoords = {{ gear.shaftcoords }} 10 | 11 | #GEAR 12 | myGearSketch = myModel.ConstrainedSketch(name='Gear sketch', sheetSize=400.0) 13 | gear_profile = myGearSketch.Spline(points=gear_formcoords) 14 | gear_tooth1 = myGearSketch.ConstructionLine(point1=gear_shaftcoords[0],point2=gear_formcoords[-1]) 15 | gear_tooth2 = myGearSketch.Line(point1=gear_shaftcoords[-1], point2=gear_formcoords[0]) 16 | gear_shaft = myGearSketch.ArcByCenterEnds(center=(0, 0), point1=gear_shaftcoords[0],point2=gear_shaftcoords[-1]) 17 | myGearSketch.copyMirror(mirrorLine=gear_tooth1, objectList=(gear_profile, gear_tooth2, gear_shaft,)) 18 | gear_tooth_part = myModel.Part(name='Gear', dimensionality=TWO_D_PLANAR, type=DEFORMABLE_BODY) 19 | gear_tooth_part.BaseShell(sketch=myGearSketch) 20 | -------------------------------------------------------------------------------- /gearbox/export/templates/abaqus_gear3D.template: -------------------------------------------------------------------------------- 1 | from abaqus import * 2 | from abaqusConstants import * 3 | 4 | backwardCompatibility.setValues(includeDeprecated=True, reportDeprecated=False) 5 | 6 | myModel = mdb.Model(name='{{model_name}}') 7 | 8 | gear_formcoords = {{ gear.formcoords }} 9 | gear_shaftcoords = {{ gear.shaftcoords }} 10 | 11 | #PINION 12 | myGearSketch = myModel.ConstrainedSketch(name='Gear sketch', sheetSize=400.0) 13 | gear_profile = myGearSketch.Spline(points=gear_formcoords) 14 | gear_tooth1 = myGearSketch.ConstructionLine(point1=gear_shaftcoords[0],point2=gear_formcoords[-1]) 15 | gear_tooth2 = myGearSketch.Line(point1=gear_shaftcoords[-1], point2=gear_formcoords[0]) 16 | gear_shaft = myGearSketch.ArcByCenterEnds(center=(0, 0), point1=gear_shaftcoords[0],point2=gear_shaftcoords[-1]) 17 | myGearSketch.rotate(centerPoint=(0, 0), angle={{ gear.rotate_ang }},objectList=(gear_profile, gear_tooth2, gear_tooth1, gear_shaft,)) 18 | myGearSketch.copyMirror(mirrorLine=gear_tooth1, objectList=(gear_profile, gear_tooth2, gear_shaft,)) 19 | gear_tooth_part = myModel.Part(name='Gear', dimensionality=THREE_D, type=DEFORMABLE_BODY) 20 | gear_tooth_part.BaseSolidExtrude(sketch=myGearSketch, depth={{ gear.data.b }}) 21 | -------------------------------------------------------------------------------- /gearbox/export/templates/abaqus_pair.template: -------------------------------------------------------------------------------- 1 | from abaqus import * 2 | from abaqusConstants import * 3 | import assembly 4 | 5 | 6 | backwardCompatibility.setValues(includeDeprecated=True, reportDeprecated=False) 7 | 8 | myModel = mdb.Model(name='{{model_name}}') 9 | 10 | pinion_formcoords = {{ pair[0].formcoords }} 11 | wheel_formcoords = {{ pair[1].formcoords }} 12 | pinion_shaftcoords = {{ pair[0].shaftcoords }} 13 | wheel_shaftcoords = {{ pair[1].shaftcoords }} 14 | 15 | 16 | #PINION 17 | myPinionSketch = myModel.ConstrainedSketch(name='Pinion sketch', sheetSize=400.0) 18 | pinion_profile = myPinionSketch.Spline(points=pinion_formcoords) 19 | pinion_tooth1 = myPinionSketch.ConstructionLine(point1=pinion_shaftcoords[0],point2=pinion_formcoords[-1]) 20 | pinion_tooth2 = myPinionSketch.Line(point1=pinion_shaftcoords[-1], point2=pinion_formcoords[0]) 21 | pinion_shaft = myPinionSketch.ArcByCenterEnds(center=({{ pair[0].rotate_x }}, {{ pair[0].rotate_y }}), point1=pinion_shaftcoords[0],point2=pinion_shaftcoords[-1]) 22 | myPinionSketch.rotate(centerPoint=({{ pair[0].rotate_x }}, {{ pair[0].rotate_y }},), angle={{ pair[0].rotate_ang }},objectList=(pinion_profile, pinion_tooth2, pinion_tooth1, pinion_shaft,)) 23 | myPinionSketch.copyMirror(mirrorLine=pinion_tooth1, objectList=(pinion_profile, pinion_tooth2, pinion_shaft,)) 24 | pinion_tooth_part = myModel.Part(name='Pinion', dimensionality=TWO_D_PLANAR, type=DEFORMABLE_BODY) 25 | pinion_tooth_part.BaseShell(sketch=myPinionSketch) 26 | 27 | 28 | #WHEEL 29 | myGearSketch = myModel.ConstrainedSketch(name='Gear sketch', sheetSize=400.0) 30 | gear_profile = myGearSketch.Spline(points=wheel_formcoords) 31 | gear_tooth1 = myGearSketch.ConstructionLine(point1=wheel_shaftcoords[0], point2=wheel_formcoords[-1]) 32 | gear_tooth2 = myGearSketch.Line(point1=wheel_shaftcoords[-1], point2=wheel_formcoords[0]) 33 | gear_shaft = myGearSketch.ArcByCenterEnds(center=({{ pair[1].rotate_x }}, {{ pair[1].rotate_y }}), point1=wheel_shaftcoords[0],point2=wheel_shaftcoords[-1]) 34 | myGearSketch.rotate(centerPoint=({{ pair[1].rotate_x }}, {{ pair[1].rotate_y }}), angle={{ pair[1].rotate_ang }},objectList=(gear_profile, gear_tooth2, gear_tooth1,gear_shaft)) 35 | myGearSketch.copyMirror(mirrorLine=gear_tooth1, objectList=(gear_profile, gear_tooth2, gear_shaft,)) 36 | gear_tooth_part = myModel.Part(name='Gear', dimensionality=TWO_D_PLANAR, type=DEFORMABLE_BODY) 37 | gear_tooth_part.BaseShell(sketch=myGearSketch) 38 | 39 | 40 | #ASSEMBLY 41 | a = myModel.rootAssembly 42 | p = myModel.parts['Gear'] 43 | a.Instance(name='Gear-1', part=p, dependent=OFF) 44 | p = mdb.models['transmition2d'].parts['Pinion'] 45 | a.Instance(name='Pinion-1', part=p, dependent=OFF) 46 | -------------------------------------------------------------------------------- /gearbox/export/templates/abaqus_pair3D.template: -------------------------------------------------------------------------------- 1 | from abaqus import * 2 | from abaqusConstants import * 3 | import assembly 4 | 5 | 6 | backwardCompatibility.setValues(includeDeprecated=True, reportDeprecated=False) 7 | 8 | myModel = mdb.Model(name='{{model_name}}') 9 | 10 | pinion_formcoords = {{ pair[0].formcoords }} 11 | wheel_formcoords = {{ pair[1].formcoords }} 12 | pinion_shaftcoords = {{ pair[0].shaftcoords }} 13 | wheel_shaftcoords = {{ pair[1].shaftcoords }} 14 | 15 | 16 | #PINION 17 | myPinionSketch = myModel.ConstrainedSketch(name='Pinion sketch', sheetSize=400.0) 18 | pinion_profile = myPinionSketch.Spline(points=pinion_formcoords) 19 | pinion_tooth1 = myPinionSketch.ConstructionLine(point1=pinion_shaftcoords[0],point2=pinion_formcoords[-1]) 20 | pinion_tooth2 = myPinionSketch.Line(point1=pinion_shaftcoords[-1], point2=pinion_formcoords[0]) 21 | pinion_shaft = myPinionSketch.ArcByCenterEnds(center=({{ pair[0].rotate_x }}, {{ pair[0].rotate_y }}), point1=pinion_shaftcoords[0],point2=pinion_shaftcoords[-1]) 22 | myPinionSketch.rotate(centerPoint=({{ pair[0].rotate_x }}, {{ pair[0].rotate_y }},), angle={{ pair[0].rotate_ang }},objectList=(pinion_profile, pinion_tooth2, pinion_tooth1, pinion_shaft,)) 23 | myPinionSketch.copyMirror(mirrorLine=pinion_tooth1, objectList=(pinion_profile, pinion_tooth2, pinion_shaft,)) 24 | pinion_tooth_part = myModel.Part(name='Pinion', dimensionality=THREE_D, type=DEFORMABLE_BODY) 25 | pinion_tooth_part.BaseSolidExtrude(sketch=myPinionSketch, depth={{ pair[0].data.b }}) 26 | 27 | #WHEEL 28 | myGearSketch = myModel.ConstrainedSketch(name='Gear sketch', sheetSize=400.0) 29 | gear_profile = myGearSketch.Spline(points=wheel_formcoords) 30 | gear_tooth1 = myGearSketch.ConstructionLine(point1=wheel_shaftcoords[0], point2=wheel_formcoords[-1]) 31 | gear_tooth2 = myGearSketch.Line(point1=wheel_shaftcoords[-1], point2=wheel_formcoords[0]) 32 | gear_shaft = myGearSketch.ArcByCenterEnds(center=({{ pair[1].rotate_x }}, {{ pair[1].rotate_y }}), point1=wheel_shaftcoords[0],point2=wheel_shaftcoords[-1]) 33 | myGearSketch.rotate(centerPoint=({{ pair[1].rotate_x }}, {{ pair[1].rotate_y }}), angle={{ pair[1].rotate_ang }},objectList=(gear_profile, gear_tooth2, gear_tooth1,gear_shaft)) 34 | myGearSketch.copyMirror(mirrorLine=gear_tooth1, objectList=(gear_profile, gear_tooth2, gear_shaft,)) 35 | gear_tooth_part = myModel.Part(name='Gear', dimensionality=THREE_D, type=DEFORMABLE_BODY) 36 | gear_tooth_part.BaseSolidExtrude(sketch=myGearSketch, depth={{ pair[1].data.b }}, draftAngle={{ pair[1].data.beta }}) 37 | 38 | #ASSEMBLY 39 | a = myModel.rootAssembly 40 | p = myModel.parts['Gear'] 41 | a.Instance(name='Gear-1', part=p, dependent=OFF) 42 | p = mdb.models['transmition2d'].parts['Pinion'] 43 | a.Instance(name='Pinion-1', part=p, dependent=OFF) 44 | -------------------------------------------------------------------------------- /gearbox/export/templates/ansys_gear.template: -------------------------------------------------------------------------------- 1 | //ag.gui.NewFile(); 2 | ag.m.ClearAllErrors(); 3 | //ag.m.NewSession (true); 4 | ag.gui.setUnits(ag.c.UnitMillimeter, ag.c.UnitDegree, ag.c.No); 5 | 6 | function planeSketchesOnly (p) 7 | { 8 | 9 | //Plane 10 | p.Plane = agb.GetActivePlane(); 11 | p.Origin = p.Plane.GetOrigin(); 12 | p.XAxis = p.Plane.GetXAxis(); 13 | p.YAxis = p.Plane.GetYAxis(); 14 | 15 | //Sketch 16 | p.Sk1 = p.Plane.NewSketch(); 17 | p.Sk1.Name = "Gear"; 18 | 19 | //Edges 20 | with (p.Sk1) 21 | { 22 | p.Sp1 = SplineBegin(); 23 | with(p.Sp1) 24 | { 25 | SplineFlexibility = agc.Yes; 26 | {% for coord in gear.formcoords -%} 27 | SplineXY({{ coord[0] }}, {{ coord[1] }}); 28 | {% endfor %} 29 | SplineFitPtEnd(); 30 | } 31 | p.Ln2 = Line({{gear.formcoords[0][0]}}, {{gear.formcoords[0][1]}}, {{gear.shaftcoords[1][0]}},{{gear.shaftcoords[1][1]}}); 32 | 33 | p.Ln3 = Line({{gear.shaftcoords[0][0]}}, {{ gear.shaftcoords[0][1] }}, {{gear.formcoords[-1][0]}}, {{gear.formcoords[-1][1]}}); 34 | p.Cr4 = ArcCtrEdge( 35 | 0, 0, 36 | {{gear.shaftcoords[0][0]}}, {{gear.shaftcoords[0][1]}}, 37 | {{gear.shaftcoords[-1][0]}}, {{gear.shaftcoords[-1][1]}}); 38 | } 39 | 40 | ag.selectedFeature = ag.gui.TreeviewFeature(p.Sk1.Name, 0); 41 | var SSk1=ag.gui.CreateSurfSk(); // IAnsFSurfSk 42 | SSk1.Name="GearSurf"; 43 | SSk1.Operation=ag.c.Frozen; 44 | SSk1.WithPlaneNormal=ag.c.Yes; 45 | 46 | //Dimensions and/or constraints 47 | with (p.Plane) 48 | { 49 | //Constraints 50 | } 51 | 52 | p.Plane.EvalDimCons(); //Final evaluate of all dimensions and constraints in plane 53 | 54 | return p; 55 | } //End Plane JScript function: planeSketchesOnly 56 | 57 | //Call Plane JScript function 58 | var ps1 = planeSketchesOnly (new Object()); 59 | 60 | //Finish 61 | agb.Regen(); //To insure model validity 62 | //End DM JScript 63 | -------------------------------------------------------------------------------- /gearbox/export/templates/ansys_gear3D.template: -------------------------------------------------------------------------------- 1 | function planeSketchesOnly (p) 2 | { 3 | 4 | //Plane 5 | p.Plane = agb.GetActivePlane(); 6 | p.Origin = p.Plane.GetOrigin(); 7 | p.XAxis = p.Plane.GetXAxis(); 8 | p.YAxis = p.Plane.GetYAxis(); 9 | 10 | //Sketch 11 | p.Sk1 = p.Plane.NewSketch(); 12 | p.Sk1.Name = "Gear"; 13 | 14 | //Edges 15 | with (p.Sk1) 16 | { 17 | p.Sp1 = SplineBegin(); 18 | with(p.Sp1) 19 | { 20 | SplineFlexibility = agc.Yes; 21 | {% for coord in gear.formcoords -%} 22 | SplineXY({{ coord[0] }}, {{ coord[1] }}); 23 | {% endfor %} 24 | SplineFitPtEnd(); 25 | } 26 | p.Ln2 = Line({{gear.formcoords[0][0]}}, {{gear.formcoords[0][1]}}, {{gear.shaftcoords[1][0]}},{{gear.shaftcoords[1][1]}}); 27 | 28 | p.Ln3 = Line({{gear.shaftcoords[0][0]}}, {{ gear.shaftcoords[0][1] }}, {{gear.formcoords[-1][0]}}, {{gear.formcoords[-1][1]}}); 29 | p.Cr4 = ArcCtrEdge( 30 | 0, 0, 31 | {{gear.shaftcoords[0][0]}}, {{gear.shaftcoords[0][1]}}, 32 | {{gear.shaftcoords[-1][0]}}, {{gear.shaftcoords[-1][1]}}); 33 | p.Ext11 = agb.Extrude(agc.Add, p.Sk1, agc.DirNormal, agc.ExtentFixe, {{ gear.data.b }}, agc.ExtentFixed, 0.0, agc.No, 0.0, 0.0); 34 | } 35 | 36 | //Dimensions and/or constraints 37 | with (p.Plane) 38 | { 39 | //Constraints 40 | } 41 | 42 | p.Plane.EvalDimCons(); //Final evaluate of all dimensions and constraints in plane 43 | 44 | return p; 45 | } //End Plane JScript function: planeSketchesOnly 46 | 47 | //Call Plane JScript function 48 | var ps1 = planeSketchesOnly (new Object()); 49 | 50 | //Finish 51 | agb.Regen(); //To insure model validity 52 | //End DM JScript 53 | -------------------------------------------------------------------------------- /gearbox/export/templates/ansys_pair.template: -------------------------------------------------------------------------------- 1 | //ag.gui.NewFile(); 2 | ag.m.ClearAllErrors(); 3 | //ag.m.NewSession (true); 4 | ag.gui.setUnits(ag.c.UnitMillimeter, ag.c.UnitDegree, ag.c.No); 5 | 6 | function planeSketchesOnly (p) 7 | { 8 | 9 | //Plane 10 | p.Plane = agb.GetActivePlane(); 11 | p.Origin = p.Plane.GetOrigin(); 12 | p.XAxis = p.Plane.GetXAxis(); 13 | p.YAxis = p.Plane.GetYAxis(); 14 | 15 | p.Sk1 = p.Plane.NewSketch(); 16 | p.Sk1.Name = "Pinion"; 17 | p.Sk2 = p.Plane.NewSketch(); 18 | p.Sk2.Name = "Wheel"; 19 | 20 | //Edges 21 | with (p.Sk1) 22 | { 23 | p.Sp1 = SplineBegin(); 24 | with(p.Sp1) 25 | { 26 | SplineFlexibility = agc.Yes; 27 | {% for coord in pair[0].formcoords -%} 28 | SplineXY({{ coord[0] }}, {{ coord[1] }}); 29 | {% endfor %} 30 | SplineFitPtEnd(); 31 | } 32 | p.Ln2 = Line({{pair[0].formcoords[0][0]}}, {{pair[0].formcoords[0][1]}}, {{pair[0].shaftcoords[1][0]}},{{pair[0].shaftcoords[1][1]}}); 33 | p.Ln3 = Line({{pair[0].shaftcoords[0][0]}}, {{ pair[0].shaftcoords[0][1] }}, {{pair[0].formcoords[-1][0]}}, {{pair[0].formcoords[-1][1]}}); 34 | p.Cr4 = ArcCtrEdge( 35 | 0, 0, 36 | {{pair[0].shaftcoords[0][0]}}, {{pair[0].shaftcoords[0][1]}}, 37 | {{pair[0].shaftcoords[-1][0]}}, {{pair[0].shaftcoords[-1][1]}}); 38 | } 39 | ag.selectedFeature = ag.gui.TreeviewFeature(p.Sk1.Name, 0); 40 | var SSk1=ag.gui.CreateSurfSk(); // IAnsFSurfSk 41 | SSk1.Name="PinionSurf"; 42 | SSk1.Operation=ag.c.Frozen; 43 | SSk1.WithPlaneNormal=ag.c.Yes; 44 | 45 | 46 | with (p.Sk2) 47 | { 48 | p.Sp1 = SplineBegin(); 49 | with(p.Sp1) 50 | { 51 | SplineFlexibility = agc.Yes; 52 | {% for coord in pair[1].formcoords -%} 53 | SplineXY({{ coord[0] }}, {{ coord[1] }}); 54 | {% endfor %} 55 | SplineFitPtEnd(); 56 | } 57 | p.Ln2 = Line({{pair[1].formcoords[0][0]}}, {{pair[1].formcoords[0][1]}}, {{pair[1].shaftcoords[1][0]}},{{pair[1].shaftcoords[1][1]}}); 58 | p.Ln3 = Line({{pair[1].shaftcoords[0][0]}}, {{ pair[1].shaftcoords[0][1] }}, {{pair[1].formcoords[-1][0]}}, {{pair[1].formcoords[-1][1]}}); 59 | p.Cr4 = ArcCtrEdge( 60 | {{ pair[1].rotate_x }}, {{ pair[1].rotate_y }}, 61 | {{ pair[1].shaftcoords[0][0] }}, {{ pair[1].shaftcoords[0][1] }}, 62 | {{ pair[1].shaftcoords[-1][0] }}, {{ pair[1].shaftcoords[-1][1] }}); 63 | } 64 | 65 | ag.selectedFeature = ag.gui.TreeviewFeature(p.Sk2.Name, 0); 66 | var SSk2=ag.gui.CreateSurfSk(); 67 | SSk2.Name="WheelSurf"; 68 | SSk2.Operation=ag.c.Frozen; 69 | SSk2.WithPlaneNormal=ag.c.Yes; 70 | 71 | //Dimensions and/or constraints 72 | with (p.Plane) 73 | { 74 | //Constraints 75 | } 76 | 77 | p.Plane.EvalDimCons(); //Final evaluate of all dimensions and constraints in plane 78 | 79 | return p; 80 | } //End Plane JScript function: planeSketchesOnly 81 | 82 | //Call Plane JScript function 83 | var ps1 = planeSketchesOnly (new Object()); 84 | 85 | //Finish 86 | agb.Regen(); //To insure model validity 87 | //End DM JScript 88 | -------------------------------------------------------------------------------- /gearbox/export/templates/ansys_pair3D.template: -------------------------------------------------------------------------------- 1 | //ag.gui.NewFile(); 2 | ag.m.ClearAllErrors(); 3 | //ag.m.NewSession (true); 4 | ag.gui.setUnits(ag.c.UnitMillimeter, ag.c.UnitDegree, ag.c.No); 5 | 6 | function planeSketchesOnly (p){ 7 | 8 | //Plane 9 | p.Plane = agb.GetActivePlane(); 10 | p.Origin = p.Plane.GetOrigin(); 11 | p.XAxis = p.Plane.GetXAxis(); 12 | p.YAxis = p.Plane.GetYAxis(); 13 | 14 | p.Sk1 = p.Plane.NewSketch(); 15 | p.Sk1.Name = "Pinion"; 16 | p.Sk2 = p.Plane.NewSketch(); 17 | p.Sk2.Name = "Wheel"; 18 | 19 | //Edges 20 | with (p.Sk1) 21 | { 22 | p.Sp1 = SplineBegin(); 23 | with(p.Sp1) 24 | { 25 | SplineFlexibility = agc.Yes; 26 | {% for coord in pair[0].formcoords -%} 27 | SplineXY({{ coord[0] }}, {{ coord[1] }}); 28 | {% endfor %} 29 | SplineFitPtEnd(); 30 | } 31 | p.Ln2 = Line({{pair[0].formcoords[0][0]}}, {{pair[0].formcoords[0][1]}}, {{pair[0].shaftcoords[1][0]}},{{pair[0].shaftcoords[1][1]}}); 32 | p.Ln3 = Line({{pair[0].shaftcoords[0][0]}}, {{ pair[0].shaftcoords[0][1] }}, {{pair[0].formcoords[-1][0]}}, {{pair[0].formcoords[-1][1]}}); 33 | p.Cr4 = ArcCtrEdge( 34 | 0, 0, 35 | {{pair[0].shaftcoords[0][0]}}, {{pair[0].shaftcoords[0][1]}}, 36 | {{pair[0].shaftcoords[-1][0]}}, {{pair[0].shaftcoords[-1][1]}}); 37 | p.Ext1 = agb.Extrude(agc.Add, p.Sk1, agc.DirNormal, agc.ExtentFixe, {{ pair[0].data.b }}, agc.ExtentFixed, 0.0, agc.No, 0.0, 0.0); 38 | } 39 | 40 | 41 | 42 | with (p.Sk2) 43 | { 44 | p.Sp1 = SplineBegin(); 45 | with(p.Sp1) 46 | { 47 | SplineFlexibility = agc.Yes; 48 | {% for coord in pair[1].formcoords -%} 49 | SplineXY({{ coord[0] }}, {{ coord[1] }}); 50 | {% endfor %} 51 | SplineFitPtEnd(); 52 | } 53 | p.Ln2 = Line({{pair[1].formcoords[0][0]}}, {{pair[1].formcoords[0][1]}}, {{pair[1].shaftcoords[1][0]}},{{pair[1].shaftcoords[1][1]}}); 54 | p.Ln3 = Line({{pair[1].shaftcoords[0][0]}}, {{ pair[1].shaftcoords[0][1] }}, {{pair[1].formcoords[-1][0]}}, {{pair[1].formcoords[-1][1]}}); 55 | p.Cr4 = ArcCtrEdge( 56 | {{ pair[1].rotate_x }}, {{ pair[1].rotate_y }}, 57 | {{ pair[1].shaftcoords[0][0] }}, {{ pair[1].shaftcoords[0][1] }}, 58 | {{ pair[1].shaftcoords[-1][0] }}, {{ pair[1].shaftcoords[-1][1] }}); 59 | p.Ext2 = agb.Extrude(agc.Add, p.Sk2, agc.DirNormal, agc.ExtentFixe, {{ pair[1].data.b }}, agc.ExtentFixed, {{ pair[1].data.b }}, agc.No, 0.0, 0.0); 60 | } 61 | 62 | return p; 63 | } 64 | //Call Plane JScript function 65 | var ps1 = planeSketchesOnly (new Object()); 66 | 67 | //Finish 68 | agb.Regen(); //To insure model validity 69 | //End DM JScript 70 | -------------------------------------------------------------------------------- /gearbox/export/templates/comsol_gear.template: -------------------------------------------------------------------------------- 1 | function out = {{model_name}} 2 | 3 | import com.comsol.model.* 4 | import com.comsol.model.util.* 5 | 6 | {{model_name}} = ModelUtil.create('{{ model_name }}'); 7 | 8 | {{model_name}}.modelPath('{{ model_path }}'); 9 | 10 | {{model_name}}.modelNode.create('comp1'); 11 | 12 | {{model_name}}.geom.create('geom1', 2); 13 | 14 | {{model_name}}.mesh.create('mesh1', 'geom1'); 15 | 16 | {{model_name}}.geom('geom1').lengthUnit('mm'); 17 | 18 | {{model_name}}.geom('geom1').feature.create('gear_thooth_profile', 'InterpolationCurve'); 19 | {{model_name}}.geom('geom1').feature('gear_thooth_profile').set('table', {{ '{' }} {% for coord in gear.formcoords -%}'{{ coord[0] }}' '{{ coord[1] }}';{%- endfor %}{{ '}' }}); 20 | {{model_name}}.geom('geom1').feature.create('gear_thooth_body', 'BezierPolygon'); 21 | {{model_name}}.geom('geom1').feature('gear_thooth_body').set('type', 'solid'); 22 | {{model_name}}.geom('geom1').feature('gear_thooth_body').set('p', {'{{gear.formcoords[0][0]}}' '{{gear.shaftcoords[1][0]}}' '{{ gear.shaftcoords[0][0] }}' '{{gear.formcoords[-1][0]}}'; '{{gear.formcoords[0][1]}}' '{{gear.shaftcoords[1][1]}}' '{{ gear.shaftcoords[0][1] }}' '{{gear.formcoords[-1][1]}}'}); 23 | {{model_name}}.geom('geom1').feature('gear_thooth_body').set('w', {'1' '1' '1' '1' '1' '1'}); 24 | {{model_name}}.geom('geom1').feature('gear_thooth_body').set('degree', [1 1 1]); 25 | {{model_name}}.geom('geom1').run('gear_thooth_body'); 26 | {{model_name}}.geom('geom1').feature('gear_thooth_body').set('type', 'open'); 27 | {{model_name}}.geom('geom1').feature.create('gear_tooth', 'ConvertToSolid'); 28 | {{model_name}}.geom('geom1').feature('gear_tooth').selection('input').set({'gear_thooth_body' 'gear_thooth_profile'}); 29 | {{model_name}}.geom('geom1').run('gear_tooth'); 30 | 31 | {{model_name}}.geom('geom1').create('gear_tooth_mirror', 'Mirror'); 32 | {{model_name}}.geom('geom1').feature('gear_tooth_mirror').set('keep', 'on'); 33 | {{model_name}}.geom('geom1').feature('gear_tooth_mirror').selection('input').set({'gear_tooth'}); 34 | {{model_name}}.geom('geom1').feature('gear_tooth_mirror').set('pos', {'0' '1'}); 35 | {{model_name}}.geom('geom1').runPre('fin'); 36 | {{model_name}}.geom('geom1').create('gear_tooth_union', 'Union'); 37 | {{model_name}}.geom('geom1').feature('gear_tooth_union').selection('input').set({'gear_tooth_mirror' 'gear_tooth'}); 38 | {{model_name}}.geom('geom1').run('gear_tooth_union'); 39 | 40 | %SHOW GEOMETRY 41 | mphgeom({{model_name}}); 42 | 43 | out = {{model_name}}; 44 | -------------------------------------------------------------------------------- /gearbox/export/templates/comsol_gear3D.template: -------------------------------------------------------------------------------- 1 | function out = {{model_name}} 2 | 3 | import com.comsol.model.* 4 | import com.comsol.model.util.* 5 | 6 | {{model_name}} = ModelUtil.create('{{ model_name }}'); 7 | 8 | {{model_name}}.modelPath('{{ model_path }}'); 9 | 10 | {{model_name}}.modelNode.create('comp1'); 11 | 12 | {{model_name}}.geom.create('geom1', 3); 13 | 14 | {{model_name}}.mesh.create('mesh1', 'geom1'); 15 | 16 | {{model_name}}.geom('geom1').lengthUnit('mm'); 17 | 18 | 19 | {{model_name}}.geom('geom1').feature.create('wp1', 'WorkPlane'); 20 | {{model_name}}.geom('geom1').feature('wp1').set('unite', true); 21 | {{model_name}}.geom('geom1').run('wp1'); 22 | 23 | {{model_name}}.geom('geom1').feature('wp1').geom.feature.create('gear_thooth_profile', 'InterpolationCurve'); 24 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_thooth_profile').set('table', {{ '{' }} {% for coord in gear.formcoords -%}'{{ coord[0] }}' '{{ coord[1] }}';{%- endfor %}{{ '}' }}); 25 | {{model_name}}.geom('geom1').feature('wp1').geom.feature.create('gear_thooth_body', 'BezierPolygon'); 26 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_thooth_body').set('type', 'solid'); 27 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_thooth_body').set('p', {'{{gear.formcoords[0][0]}}' '{{gear.shaftcoords[1][0]}}' '{{ gear.shaftcoords[0][0] }}' '{{gear.formcoords[-1][0]}}'; '{{gear.formcoords[0][1]}}' '{{gear.shaftcoords[1][1]}}' '{{ gear.shaftcoords[0][1] }}' '{{gear.formcoords[-1][1]}}'}); 28 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_thooth_body').set('w', {'1' '1' '1' '1' '1' '1'}); 29 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_thooth_body').set('degree', [1 1 1]); 30 | {{model_name}}.geom('geom1').feature('wp1').geom.run('gear_thooth_body'); 31 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_thooth_body').set('type', 'open'); 32 | {{model_name}}.geom('geom1').feature('wp1').geom.feature.create('gear_tooth', 'ConvertToSolid'); 33 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_tooth').selection('input').set({'gear_thooth_body' 'gear_thooth_profile'}); 34 | {{model_name}}.geom('geom1').feature('wp1').geom.run('gear_tooth'); 35 | {{model_name}}.geom('geom1').feature('wp1').geom.create('gear_tooth_mirror', 'Mirror'); 36 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_tooth_mirror').set('keep', 'on'); 37 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_tooth_mirror').selection('input').set({'gear_tooth'}); 38 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_tooth_mirror').set('pos', {'0' '1'}); 39 | {{model_name}}.geom('geom1').feature('wp1').geom.create('gear_tooth_union', 'Union'); 40 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('gear_tooth_union').selection('input').set({'gear_tooth_mirror' 'gear_tooth'}); 41 | {{model_name}}.geom('geom1').feature('wp1').geom.run('gear_tooth_union'); 42 | {{model_name}}.geom('geom1').feature.create('ext1', 'Extrude'); 43 | {{model_name}}.geom('geom1').feature('ext1').selection('input').set({'wp1'}); 44 | {{model_name}}.geom('geom1').feature('ext1').setIndex('distance', '{{ gear.data.b }}', 0); 45 | {{model_name}}.geom('geom1').feature('ext1').setIndex('twist', '{{ gear.data.beta }}', 0); 46 | 47 | %SHOW GEOMETRY 48 | mphgeom({{model_name}}); 49 | 50 | out = {{model_name}}; 51 | -------------------------------------------------------------------------------- /gearbox/export/templates/comsol_pair.template: -------------------------------------------------------------------------------- 1 | function out = {{model_name}} 2 | 3 | import com.comsol.model.* 4 | import com.comsol.model.util.* 5 | 6 | {{model_name}} = ModelUtil.create('{{ model_name }}'); 7 | 8 | {{model_name}}.modelPath('{{ model_path }}'); 9 | 10 | {{model_name}}.modelNode.create('comp1'); 11 | 12 | {{model_name}}.geom.create('geom1', 2); 13 | 14 | {{model_name}}.mesh.create('mesh1', 'geom1'); 15 | 16 | {{model_name}}.geom('geom1').lengthUnit('mm'); 17 | 18 | %PINION 19 | {{model_name}}.geom('geom1').feature.create('pinion_thooth_profile', 'InterpolationCurve'); 20 | {{model_name}}.geom('geom1').feature('pinion_thooth_profile').set('table', {{ '{' }} {% for coord in pair[0].formcoords -%}'{{ coord[0] }}' '{{ coord[1] }}';{%- endfor %}{{ '}' }}); 21 | {{model_name}}.geom('geom1').feature.create('pinion_thooth_body', 'BezierPolygon'); 22 | {{model_name}}.geom('geom1').feature('pinion_thooth_body').set('type', 'solid'); 23 | {{model_name}}.geom('geom1').feature('pinion_thooth_body').set('p', {'{{pair[0].formcoords[0][0]}}' '{{pair[0].shaftcoords[1][0]}}' '{{ pair[0].shaftcoords[0][0] }}' '{{pair[0].formcoords[-1][0]}}'; '{{pair[0].formcoords[0][1]}}' '{{pair[0].shaftcoords[1][1]}}' '{{ pair[0].shaftcoords[0][1] }}' '{{pair[0].formcoords[-1][1]}}'}); 24 | {{model_name}}.geom('geom1').feature('pinion_thooth_body').set('w', {'1' '1' '1' '1' '1' '1'}); 25 | {{model_name}}.geom('geom1').feature('pinion_thooth_body').set('degree', [1 1 1]); 26 | {{model_name}}.geom('geom1').run('pinion_thooth_body'); 27 | {{model_name}}.geom('geom1').feature('pinion_thooth_body').set('type', 'open'); 28 | {{model_name}}.geom('geom1').feature.create('pinion_tooth', 'ConvertToSolid'); 29 | {{model_name}}.geom('geom1').feature('pinion_tooth').selection('input').set({'pinion_thooth_body' 'pinion_thooth_profile'}); 30 | {{model_name}}.geom('geom1').run('pinion_tooth'); 31 | 32 | {{model_name}}.geom('geom1').create('pinion_tooth_mirror', 'Mirror'); 33 | {{model_name}}.geom('geom1').feature('pinion_tooth_mirror').set('keep', 'on'); 34 | {{model_name}}.geom('geom1').feature('pinion_tooth_mirror').selection('input').set({'pinion_tooth'}); 35 | {{model_name}}.geom('geom1').feature('pinion_tooth_mirror').set('pos', {'0' '1'}); 36 | {{model_name}}.geom('geom1').runPre('fin'); 37 | {{model_name}}.geom('geom1').create('pinion_tooth_union', 'Union'); 38 | {{model_name}}.geom('geom1').feature('pinion_tooth_union').selection('input').set({'pinion_tooth_mirror' 'pinion_tooth'}); 39 | {{model_name}}.geom('geom1').run('pinion_tooth_union'); 40 | {{model_name}}.geom('geom1').create('rotate_pinion', 'Rotate'); 41 | {{model_name}}.geom('geom1').feature('rotate_pinion').selection('input').set({'pinion_tooth_union'}); 42 | {{model_name}}.geom('geom1').feature('rotate_pinion').set('pos', {'{{ pair[0].rotate_x }}' '{{ pair[0].rotate_y }}'}); 43 | {{model_name}}.geom('geom1').feature('rotate_pinion').set('rot', '{{ pair[0].rotate_ang }}'); 44 | {{model_name}}.geom('geom1').run('rotate_pinion'); 45 | 46 | 47 | %GEAR 48 | {{model_name}}.geom('geom1').feature.create('wheel_thooth_profile', 'InterpolationCurve'); 49 | {{model_name}}.geom('geom1').feature('wheel_thooth_profile').set('table', {{ '{' }} {% for coord in pair[1].formcoords -%}'{{ coord[0] }}' '{{ coord[1] }}';{%- endfor %}{{ '}' }}); 50 | {{model_name}}.geom('geom1').feature.create('wheel_thooth_body', 'BezierPolygon'); 51 | {{model_name}}.geom('geom1').feature('wheel_thooth_body').set('type', 'solid'); 52 | {{model_name}}.geom('geom1').feature('wheel_thooth_body').set('p', {'{{pair[1].formcoords[0][0]}}' '{{pair[1].shaftcoords[1][0]}}' '{{ pair[1].shaftcoords[0][0] }}' '{{pair[1].formcoords[-1][0]}}'; '{{pair[1].formcoords[0][1]}}' '{{pair[1].shaftcoords[1][1]}}' '{{ pair[1].shaftcoords[0][1] }}' '{{pair[1].formcoords[-1][1]}}'}); 53 | {{model_name}}.geom('geom1').feature('wheel_thooth_body').set('w', {'1' '1' '1' '1' '1' '1'}); 54 | {{model_name}}.geom('geom1').feature('wheel_thooth_body').set('degree', [1 1 1]); 55 | {{model_name}}.geom('geom1').run('wheel_thooth_body'); 56 | {{model_name}}.geom('geom1').feature('wheel_thooth_body').set('type', 'open'); 57 | {{model_name}}.geom('geom1').feature.create('wheel_tooth', 'ConvertToSolid'); 58 | {{model_name}}.geom('geom1').feature('wheel_tooth').selection('input').set({'wheel_thooth_body' 'wheel_thooth_profile'}); 59 | {{model_name}}.geom('geom1').run('wheel_tooth'); 60 | 61 | {{model_name}}.geom('geom1').create('wheel_tooth_mirror', 'Mirror'); 62 | {{model_name}}.geom('geom1').feature('wheel_tooth_mirror').set('keep', 'on'); 63 | {{model_name}}.geom('geom1').feature('wheel_tooth_mirror').selection('input').set({'wheel_tooth'}); 64 | {{model_name}}.geom('geom1').feature('wheel_tooth_mirror').set('pos', {'0' '1'}); 65 | {{model_name}}.geom('geom1').runPre('fin'); 66 | {{model_name}}.geom('geom1').create('wheel_tooth_union', 'Union'); 67 | {{model_name}}.geom('geom1').feature('wheel_tooth_union').selection('input').set({'wheel_tooth_mirror' 'wheel_tooth'}); 68 | {{model_name}}.geom('geom1').run('wheel_tooth_union'); 69 | {{model_name}}.geom('geom1').create('rotate_wheel', 'Rotate'); 70 | {{model_name}}.geom('geom1').feature('rotate_wheel').selection('input').set({'wheel_tooth_union'}); 71 | {{model_name}}.geom('geom1').feature('rotate_wheel').set('pos', {'{{ pair[1].rotate_x }}' '{{ pair[1].rotate_y }}'}); 72 | {{model_name}}.geom('geom1').feature('rotate_wheel').set('rot', '{{ pair[1].rotate_ang }}'); 73 | {{model_name}}.geom('geom1').run('rotate_wheel'); 74 | 75 | 76 | %SHOW GEOMETRY 77 | mphgeom({{model_name}}); 78 | 79 | out = {{model_name}}; 80 | -------------------------------------------------------------------------------- /gearbox/export/templates/comsol_pair3D.template: -------------------------------------------------------------------------------- 1 | function out = {{model_name}} 2 | 3 | import com.comsol.model.* 4 | import com.comsol.model.util.* 5 | 6 | {{model_name}} = ModelUtil.create('{{ model_name }}'); 7 | 8 | {{model_name}}.modelPath('{{ model_path }}'); 9 | 10 | {{model_name}}.modelNode.create('comp1'); 11 | 12 | {{model_name}}.geom.create('geom1', 3); 13 | 14 | {{model_name}}.mesh.create('mesh1', 'geom1'); 15 | 16 | {{model_name}}.geom('geom1').lengthUnit('mm'); 17 | 18 | %PINION 19 | {{model_name}}.geom('geom1').feature.create('wp1', 'WorkPlane'); 20 | {{model_name}}.geom('geom1').feature('wp1').set('unite', true); 21 | {{model_name}}.geom('geom1').run('wp1'); 22 | {{model_name}}.geom('geom1').feature('wp1').geom.feature.create('pinion_thooth_profile', 'InterpolationCurve'); 23 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_thooth_profile').set('table', {{ '{' }} {% for coord in pair[0].formcoords -%}'{{ coord[0] }}' '{{ coord[1] }}';{%- endfor %}{{ '}' }}); 24 | {{model_name}}.geom('geom1').feature('wp1').geom.feature.create('pinion_thooth_body', 'BezierPolygon'); 25 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_thooth_body').set('type', 'solid'); 26 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_thooth_body').set('p', {'{{pair[0].formcoords[0][0]}}' '{{pair[0].shaftcoords[1][0]}}' '{{ pair[0].shaftcoords[0][0] }}' '{{pair[0].formcoords[-1][0]}}'; '{{pair[0].formcoords[0][1]}}' '{{pair[0].shaftcoords[1][1]}}' '{{ pair[0].shaftcoords[0][1] }}' '{{pair[0].formcoords[-1][1]}}'}); 27 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_thooth_body').set('w', {'1' '1' '1' '1' '1' '1'}); 28 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_thooth_body').set('degree', [1 1 1]); 29 | {{model_name}}.geom('geom1').feature('wp1').geom.run('pinion_thooth_body'); 30 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_thooth_body').set('type', 'open'); 31 | {{model_name}}.geom('geom1').feature('wp1').geom.feature.create('pinion_tooth', 'ConvertToSolid'); 32 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_tooth').selection('input').set({'pinion_thooth_body' 'pinion_thooth_profile'}); 33 | {{model_name}}.geom('geom1').feature('wp1').geom.run('pinion_tooth'); 34 | {{model_name}}.geom('geom1').feature('wp1').geom.create('pinion_tooth_mirror', 'Mirror'); 35 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_tooth_mirror').set('keep', 'on'); 36 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_tooth_mirror').selection('input').set({'pinion_tooth'}); 37 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_tooth_mirror').set('pos', {'0' '1'}); 38 | {{model_name}}.geom('geom1').feature('wp1').geom.create('pinion_tooth_union', 'Union'); 39 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('pinion_tooth_union').selection('input').set({'pinion_tooth_mirror' 'pinion_tooth'}); 40 | {{model_name}}.geom('geom1').feature('wp1').geom.run('pinion_tooth_union'); 41 | {{model_name}}.geom('geom1').feature('wp1').geom.create('rotate_pinion', 'Rotate'); 42 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('rotate_pinion').selection('input').set({'pinion_tooth_union'}); 43 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('rotate_pinion').set('pos', {'{{ pair[0].rotate_x }}' '{{ pair[0].rotate_y }}'}); 44 | {{model_name}}.geom('geom1').feature('wp1').geom.feature('rotate_pinion').set('rot', '{{ pair[0].rotate_ang }}'); 45 | {{model_name}}.geom('geom1').feature('wp1').geom.run('rotate_pinion'); 46 | 47 | {{model_name}}.geom('geom1').feature.create('ext1', 'Extrude'); 48 | {{model_name}}.geom('geom1').feature('ext1').selection('input').set({'wp1'}); 49 | {{model_name}}.geom('geom1').feature('ext1').setIndex('distance', '{{ pair[0].data.b }}', 0); 50 | {{model_name}}.geom('geom1').feature('ext1').setIndex('twist', '{{ pair[0].data.beta }}', 0); 51 | 52 | 53 | %WHEEL 54 | {{model_name}}.geom('geom1').feature.create('wp2', 'WorkPlane'); 55 | {{model_name}}.geom('geom1').feature('wp2').set('unite', true); 56 | {{model_name}}.geom('geom1').run('wp2'); 57 | {{model_name}}.geom('geom1').feature('wp2').geom.feature.create('wheel_thooth_profile', 'InterpolationCurve'); 58 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_thooth_profile').set('table', {{ '{' }} {% for coord in pair[1].formcoords -%}'{{ coord[0] }}' '{{ coord[1] }}';{%- endfor %}{{ '}' }}); 59 | {{model_name}}.geom('geom1').feature('wp2').geom.feature.create('wheel_thooth_body', 'BezierPolygon'); 60 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_thooth_body').set('type', 'solid'); 61 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_thooth_body').set('p', {'{{pair[1].formcoords[0][0]}}' '{{pair[1].shaftcoords[1][0]}}' '{{ pair[1].shaftcoords[0][0] }}' '{{pair[1].formcoords[-1][0]}}'; '{{pair[1].formcoords[0][1]}}' '{{pair[1].shaftcoords[1][1]}}' '{{ pair[1].shaftcoords[0][1] }}' '{{pair[1].formcoords[-1][1]}}'}); 62 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_thooth_body').set('w', {'1' '1' '1' '1' '1' '1'}); 63 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_thooth_body').set('degree', [1 1 1]); 64 | {{model_name}}.geom('geom1').feature('wp2').geom.run('wheel_thooth_body'); 65 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_thooth_body').set('type', 'open'); 66 | {{model_name}}.geom('geom1').feature('wp2').geom.feature.create('wheel_tooth', 'ConvertToSolid'); 67 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_tooth').selection('input').set({'wheel_thooth_body' 'wheel_thooth_profile'}); 68 | {{model_name}}.geom('geom1').feature('wp2').geom.run('wheel_tooth'); 69 | {{model_name}}.geom('geom1').feature('wp2').geom.create('wheel_tooth_mirror', 'Mirror'); 70 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_tooth_mirror').set('keep', 'on'); 71 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_tooth_mirror').selection('input').set({'wheel_tooth'}); 72 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_tooth_mirror').set('pos', {'0' '1'}); 73 | {{model_name}}.geom('geom1').feature('wp2').geom.create('wheel_tooth_union', 'Union'); 74 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('wheel_tooth_union').selection('input').set({'wheel_tooth_mirror' 'wheel_tooth'}); 75 | {{model_name}}.geom('geom1').feature('wp2').geom.run('wheel_tooth_union'); 76 | {{model_name}}.geom('geom1').feature('wp2').geom.create('rotate_wheel', 'Rotate'); 77 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('rotate_wheel').selection('input').set({'wheel_tooth_union'}); 78 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('rotate_wheel').set('pos', {'{{ pair[1].rotate_x }}' '{{ pair[1].rotate_y }}'}); 79 | {{model_name}}.geom('geom1').feature('wp2').geom.feature('rotate_wheel').set('rot', '{{ pair[1].rotate_ang }}'); 80 | {{model_name}}.geom('geom1').feature('wp2').geom.run('rotate_wheel'); 81 | {{model_name}}.geom('geom1').feature.create('ext2', 'Extrude'); 82 | {{model_name}}.geom('geom1').feature('ext2').selection('input').set({'wp2'}); 83 | {{model_name}}.geom('geom1').feature('ext2').setIndex('distance', '{{ pair[1].data.b }}', 0); 84 | {{model_name}}.geom('geom1').feature('ext2').setIndex('twist', '{{ pair[1].data.beta }}', 0); 85 | 86 | 87 | %SHOW GEOMETRY 88 | mphgeom({{model_name}}); 89 | 90 | out = {{model_name}}; 91 | -------------------------------------------------------------------------------- /gearbox/libs/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'efirvida' 2 | -------------------------------------------------------------------------------- /gearbox/libs/gearprofile.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is a modification of the pygear project (https://sourceforge.net/projects/pygear/) 3 | and is distribuited under the same license of his parent 4 | 5 | license: 6 | This code is published under the terms of the GNU General Public License v3 7 | http://www.gnu.org/licenses/gpl-3.0.html 8 | """ 9 | from copy import deepcopy 10 | from math import tan, radians, atan, pi, sin, cos, degrees, acos, asin, sqrt 11 | 12 | import numpy as np 13 | 14 | from gearbox.libs.maths import involute as inv 15 | from gearbox.libs.maths import rotate, CartesianCoordinatesToPolarCoordinates, sign 16 | 17 | 18 | class GearWheel(object): 19 | """ 20 | Parent Class for all gear wheels. 21 | """ 22 | 23 | # Attributes: settings for geometry construction 24 | points_flank = 100 # points along the involute from root form to tip form circle 25 | points_fillet = 50 # points on fillet from root to root form circle 26 | points_tip = 20 # points along tip circle (half tooth) 27 | points_root = 5 # points along root circle from center of gap to 28 | # beginning of fillet (half tooth) 29 | points_chamfer = 20 # points on tip chamfer 30 | points_ext = 100 # points on extension of involute beyond base circle (if applicable)(should be at least 8) 31 | points_width = 10 # resolution along width 32 | 33 | # Attributes: default settings for parameters 34 | _x_default = 0.0 # default value for addendum modification 35 | _alpha_n_default = 20.0 # default value for pressure angle (DIN 867) 36 | _beta_default = 0.0 # default value for helix angle (spur gear) 37 | _rho_f_default = 0.38 # default value for fillet radius (divided bei module)(DIN 867) 38 | _c_default = 0.25 # default value for tip clearance (divided bei module)(DIN 867) 39 | _k_default = 0.0 # default value for tip height modification 40 | _d_s_default = 0.0 # default value for shaft diameter (inner gear wheel diameter) 41 | _h_k_default = 0.0 # default value for radial value of tip chamfer 42 | _tol_default = 1e-6 # default tolerance for comparisons 43 | _A_s_default = 0.0 # default value for tooth thickness allowance (DIN 3967) 44 | 45 | # Attributes: gear data 46 | data = None # dictionary containing all gear parameters for macro-geometry 47 | modifications = None # dictionary containing all gear parameters for micro-geometry (flank profile modifications) 48 | formcoords = None # list of 2D-coordinates of points of half a tooth profile (TColgp_Array1OfPnt2d, pythonOCC) 49 | _formwire = None # wire of half a tooth profile (TopoDS_Wire, pythonOCC) 50 | 51 | def set_resolution(self, curvename, value): 52 | """ 53 | Set resolution for tooth form representation 54 | 55 | INPUT parameters: 56 | curvename : segment of tooth flank (string) 57 | one of the following: flank, fillet, tip, root, shaft, width 58 | value : new value for number of points to represent segment 59 | """ 60 | 61 | if curvename == 'flank': 62 | self.points_flank = value 63 | elif curvename == 'fillet': 64 | self.points_fillet = value 65 | elif curvename == 'tip': 66 | self.points_tip = value 67 | elif curvename == 'root': 68 | self.points_root = value 69 | elif curvename == 'shaft': 70 | self.points_shaft = value 71 | elif curvename == 'width': 72 | self.points_width = value 73 | 74 | def get_resolution(self, curvename): 75 | """ 76 | Get resolution for tooth form representation 77 | 78 | INPUT parameters: 79 | curvename : segment of tooth flank (string) 80 | one of the following: flank, fillet, tip, root, shaft, width 81 | 82 | OUTPUT: 83 | number of points used to represent requested segment 84 | """ 85 | 86 | if curvename == 'flank': 87 | return self.points_flank 88 | elif curvename == 'fillet': 89 | return self.points_fillet 90 | elif curvename == 'tip': 91 | return self.points_tip 92 | elif curvename == 'root': 93 | return self.points_root 94 | elif curvename == 'shaft': 95 | return self.points_shaft 96 | elif curvename == 'width': 97 | return self.points_width 98 | 99 | def _make_unique(self, coords): 100 | """ 101 | Remove redundant entries from coordinate array 102 | 103 | INPUT parameter: 104 | coords : list of 2d-coordinate points (TColgp_Array1OfPnt2d, pythonOCC) 105 | 106 | OUTPUT: 107 | unique_coords : list of unique coordinates (TColgp_Array1OfPnt2d, pythonOCC) 108 | """ 109 | 110 | # tolerance for comparisons 111 | index = None 112 | tol = self._tol_default * self.data.get('m_n') 113 | 114 | # upper and lower index of point-array 115 | upper_index = len(coords) 116 | lower_index = 0 117 | 118 | # remove redundant entries 119 | uniques = list() 120 | for index in range(lower_index, upper_index): 121 | unique = True 122 | for unique_point in uniques: 123 | if abs(coords[index][0] - unique_point[0]) < tol and abs(coords[index][1] - unique_point[1]) < tol: 124 | unique = False 125 | if unique: 126 | uniques.append([coords[index][0], coords[index][1]]) 127 | 128 | # copy list entries into coordinate array 129 | length_uniques = len(uniques) 130 | unique_coords = {} 131 | for index in range(lower_index, lower_index + length_uniques): 132 | if abs(uniques[index - 1][0]) > tol: 133 | unique_x = uniques[index - 1][0] 134 | else: 135 | unique_x = 0.0 136 | if abs(uniques[index - 1][1]) > tol: 137 | unique_y = uniques[index - 1][1] 138 | else: 139 | unique_y = 0.0 140 | if unique_x and unique_y: 141 | unique_coords.update({index: [unique_x, unique_y]}) 142 | 143 | unique_coords.update({index + 1: [0.0, self.data['d_a'] / 2]}) 144 | return unique_coords 145 | 146 | def __str__(self): 147 | """ 148 | Define string conversion of GearWheel objects 149 | 150 | INPUT parameter: 151 | - 152 | 153 | OUTPUT: 154 | string representation of class 155 | """ 156 | 157 | outstr = 'gear wheel data:\n' 158 | # output gear data 159 | for date in self.data: 160 | outstr += date.ljust(10) + ':\t' + str(self.data.get(date)) + '\n' 161 | 162 | # output modification data 163 | if self.modifications: 164 | outstr += '\nflank modifications:\n' 165 | for date in self.modifications: 166 | outstr += date.ljust(10) + ':\t' + str(self.modifications.get(date)) + '\n' 167 | 168 | # output tooth form coordinates 169 | if self.formcoords: 170 | # upper and lower index of point-array 171 | outstr += '\ntooth form coordinates:\n' 172 | for coord in self.formcoords: 173 | outstr += str(coord[0]) + '\t' + str(coord[1]) + '\n' 174 | 175 | return outstr 176 | 177 | def __init__(self, geardata, flankmods=None): 178 | """ 179 | Initialization of GearWheel-object 180 | Should be overwritten in derived classes 181 | 182 | INPUT parameter: 183 | geardata : data of gear wheel (dictionary) 184 | flankmods : data of flank modifications (dictionary) 185 | formcoords : list of 2d-coordinate points (list, list(len=2), numeric) 186 | """ 187 | 188 | self.points_shaft = None 189 | self.data = deepcopy(geardata) 190 | self.modifications = deepcopy(flankmods) 191 | 192 | def get_gear_data(self): 193 | """ 194 | Return data-attribute of class 195 | 196 | OUTPUT: 197 | data attribute of class (dictionary) 198 | """ 199 | 200 | return self.data 201 | 202 | def set_gear_data(self, geardata): 203 | """ 204 | Set data-attribute of class, overwrite current value 205 | 206 | INPUT parameter: 207 | geardata : dictionary, containing geometric data of gear 208 | for content, see method __init__ 209 | """ 210 | 211 | self.__init__(geardata, self.modifications) 212 | 213 | def update_gear_data(self, geardata): 214 | """ 215 | Set data-attribute of class, update current value 216 | 217 | INPUT parameter: 218 | geardata : dictionary, containing geometric data of gear 219 | for content, see method __init__ 220 | """ 221 | 222 | tempdata = self.data.copy() 223 | tempdata.update(geardata) 224 | self.__init__(geardata, self.modifications) 225 | 226 | def get_flank_modifications(self): 227 | """ 228 | Return modifications-attribute of class 229 | 230 | OUTPUT: 231 | data attribute of class (dictionary) 232 | """ 233 | 234 | return self.modifications 235 | 236 | def set_flank_modifications(self, flankmods): 237 | """ 238 | Set modifications-attribute of class, overwrite current value 239 | 240 | INPUT parameter: 241 | flankmods : dictionary, containing flank modification data of gear 242 | for content, see method __init__ 243 | """ 244 | 245 | self.__init__(self.data, flankmods) 246 | 247 | def update_flank_modifications(self, flankmods): 248 | """ 249 | Set modifications-attribute of class, update current value 250 | 251 | INPUT parameter: 252 | flankmods : dictionary, containing flank modification data of gear 253 | for content, see method __init__ 254 | """ 255 | 256 | tempmods = self.modifications.copy() 257 | tempmods.update(flankmods) 258 | self.__init__(self.data, tempmods) 259 | 260 | 261 | class CylindricalGearWheel(GearWheel): 262 | """ 263 | Class representing a spur wheel or a helical gear wheel. Applicable for external and internal gears. 264 | Derived from GearWheel-class 265 | """ 266 | 267 | def _tooth_thickness(self, d_y): 268 | """ 269 | Tooth thickness in transverse cross-section (chord-length) 270 | 271 | INPUT parameter: 272 | d_y : two times coordinate of tooth flank in radial direction 273 | (diameter of y-cylinder) 274 | 275 | OUTPUT: 276 | s_y : chord length of tooth thickness at d_y (numeric) 277 | d_yc : cutting point of diameter through tooth center and chord (numeric) 278 | """ 279 | 280 | # necessary due to numerical rounding errors 281 | if self.data.get('d') / d_y * cos(radians(self.data.get('alpha_t'))) > 1.0: 282 | alpha_yt = 0.0 283 | else: 284 | alpha_yt = degrees(acos(self.data.get('d') / d_y * cos(radians(self.data.get('alpha_t'))))) 285 | s_yt = d_y * ( 286 | (pi + 4 * self.data.get('x_E') * tan(radians(self.data.get('alpha_n')))) / 2 / self.data.get( 287 | 'z') + inv(self.data.get('alpha_t')) - inv(alpha_yt)) 288 | s_y = d_y * (sin(s_yt / d_y)) # tooth thickness (chord-length) 289 | d_yc = d_y * (cos(s_yt / d_y)) # diameter at center of tooth (cut with chord) 290 | 291 | return s_y, d_yc 292 | 293 | def _analyze_formcoords(self): 294 | # ONLY FOR EXTERNAL GEARS SO FAR !!! 295 | """ 296 | analyze tooth form coordinates in order to get necessary information for 297 | geometry generator. 298 | 299 | INPUT parameters: 300 | formcoords : 2D cartesian coordinates of points on the 301 | toothflank, describing a half tooth (TColgp_Array1OfPnt2d, pythonOCC) 302 | 303 | OUTPUT: 304 | suppdata : supplement data for geardata dictionary (dictionary) 305 | the dictionary contains at least the following keys: 306 | d_f : root circle diameter (numeric) 307 | d_a : tip diameter (numeric) 308 | d_ff : root form diameter (numeric) 309 | d_fa : tip form diameter (numeric) 310 | z : number of teeth (numeric, integer) 311 | """ 312 | 313 | # transform formcoords to NumPy-array 314 | point = None 315 | half_tooth = self.formcoords 316 | 317 | # convert to polar coordinates 318 | half_tooth_polar = np.zeros([np.size(half_tooth, 0) - 1, 2]) 319 | for index in range(0, np.size(half_tooth, 0) - 1): 320 | [r, phi] = CartesianCoordinatesToPolarCoordinates(half_tooth[index + 1, 0], half_tooth[index + 1, 1]) 321 | half_tooth_polar[index, 0] = r 322 | half_tooth_polar[index, 1] = phi 323 | d_f = 2 * min(half_tooth_polar[:, 0]) # minimum radius --> root circle 324 | d_a = 2 * max(half_tooth_polar[:, 0]) # maximum radius --> tip circle 325 | tau = 2 * (max(half_tooth_polar[:, 1]) - min(half_tooth_polar[:, 1])) # pitch angle [radians] 326 | z = int(round(2 * pi / tau)) # number of teeth from pitch angle 327 | 328 | # for finding form diameters, it is checked if the points are part of the flank involute 329 | # the limiting points of the flank involute define the form diameters 330 | if 'alpha_n' in self.data and 'alpha_t' in self.data and 'x_E' in self.data: 331 | tol = self._tol_default * self.data.get('m_n') # tolerance for comparisons 332 | point_on_flank = False 333 | first_limit_diameter = None 334 | second_limit_diameter = None 335 | for point in range(0, np.size(half_tooth_polar, 0)): 336 | [x, y] = self._tooth_thickness(2 * half_tooth_polar[point, 0]) 337 | if abs(x + 2 * half_tooth[point + 1, 0]) < tol and abs(y - 2 * half_tooth[point + 1, 1]) < tol: 338 | if not point_on_flank: 339 | first_limit_diameter = 2 * half_tooth_polar[point, 0] 340 | point_on_flank = True 341 | else: 342 | if point_on_flank: 343 | second_limit_diameter = 2 * half_tooth_polar[point, 0] 344 | point_on_flank = False 345 | if second_limit_diameter is None: 346 | second_limit_diameter = 2 * half_tooth_polar[point, 0] 347 | if first_limit_diameter == second_limit_diameter: 348 | raise ValueError('tooth form coordinate analysis failed') 349 | if first_limit_diameter > second_limit_diameter: 350 | d_fa = first_limit_diameter 351 | d_ff = second_limit_diameter 352 | else: 353 | d_fa = second_limit_diameter 354 | d_ff = first_limit_diameter 355 | if 'd_ff' in self.data: # use user-parameter if supplied 356 | d_ff = self.data.get('d_ff') 357 | if 'd_fa' in self.data: 358 | d_ff = self.data.get('d_fa') 359 | return {'d_f': d_f, 'd_a': d_a, 'd_ff': d_ff, 'd_fa': d_fa, 'z': z} 360 | 361 | else: 362 | return {'d_f': d_f, 'd_a': d_a, 'z': z} 363 | 364 | def __init__(self, geardata, flankmods=None, formcoords=None): 365 | """ 366 | Initialization of GearWheel-object. 367 | All parameters in accordance to DIN 3960 and DIN 3967. 368 | 369 | INPUT parameters: 370 | z : number of teeth (numeric, integer) 371 | m_n : normal module (numeric, positive) 372 | d : pitch diameter (numeric) 373 | two of the three parameters z, m_n, d, must be supplied 374 | b : tooth width (numeric, positive) 375 | d_f : root circle diameter (numeric) 376 | optional - calculated if not supplied 377 | d_a : tip diameter (numeric) 378 | optional - calculated if not supplied 379 | d_Ff : root form diameter (numeric) 380 | optional - will be estimated if not supplied 381 | d_Fa : tip form diameter (numeric) 382 | optional - set equal da if not supplied (no chamfer) 383 | rho_f : fillet radius (numeric) 384 | optional - set equal 0.38*mn if not supplied 385 | x : addendum modification factor (numeric) 386 | optional - set equal 0.0 if not supplied 387 | alpha_n : pressure angle (numeric, positive)[degrees] 388 | optional - set equal 20.0 if not supplied 389 | beta : helix angle (numeric)[degrees] 390 | optional - set equal 0.0 if not supplied 391 | a : addendum (numeric) 392 | optional - no estimation 393 | c : tip clearance (numeric, positive, 0.1...0.3*mn) 394 | optional - set equal 0.25*mn if not supplied 395 | alpha_wt : service pressure angle (numeric, positive)[degrees] 396 | optional - calculated from z_2 or d_w 397 | d_w : service pitch diameter (numeric) 398 | optional - calculated from alpha_wt or z_2 399 | h_k : radial size of tip chamfer (numeric) 400 | optional - set equal d_a-d_Fa or 0.0 if not supplied 401 | s_aK : remaining tooth thickness at tip, chord-length (numeric) 402 | optional - set equal s_a-2*h_k if not supplied 403 | z_2 : number of teeth of counter gear (numeric, integer) 404 | optional - calculated from alpha_wt or d_w 405 | d_s : shaft diameter, inner gear wheel diameter (numeric) 406 | optional - set equal 0.0 if not supplied 407 | A_s : tooth thickness allowance in normal cross-section (numeric, negative) 408 | optional - set equal 0.0 if not supplied 409 | 410 | All input parameters above are arranged in a dictionary. The keys are 411 | the names of the parameters as listed above. 412 | 413 | formcoords : 2D cartesian coordinates of points on the 414 | toothflank, describing a half tooth (TColgp_Array1OfPnt2d, pythonOCC) 415 | 416 | There are several possibilities for defining a complete gearwheel: 417 | 1) z, m_n, b, (beta), formcoords 418 | 2) z, m_n, b, (beta), d_f, d_a, d_Ff, d_Fa, rho_f 419 | 3) z, m_n, b, (beta), alpha_n, alpha_wt, x, a, rho_f 420 | 4) z, m_n, b, (beta), alpha_n, z_2, x, a, rho_f 421 | Some parameters can be left out, but the result might differ 422 | from your real gear. Missing parameters are estimated if 423 | possible. The helix angle beta doesn't have to be supplied 424 | for a spur gear. 425 | The constructor does not check for unit consistency. The user is 426 | responsible for supplying all values with consistent units. 427 | """ 428 | super(CylindricalGearWheel, self).__init__(geardata) 429 | self.data = deepcopy(geardata) 430 | self.modifications = deepcopy(flankmods) 431 | 432 | # form coordinates: value check (at least two points for defining a 433 | # tooth form (straight flanks) and two coordinates per point) 434 | if formcoords: 435 | self.data.update(self._analyze_formcoords()) 436 | 437 | # module: value check 438 | if 'm_n' in self.data and not self.data.get('m_n') >= 0: 439 | raise ValueError('module non-positive') 440 | 441 | if 'beta' not in self.data: 442 | self.data.update({'beta': self._beta_default}) 443 | self.data.update({'alpha_t': degrees( 444 | atan(tan(radians(self.data.get('alpha_n'))) / cos(radians(self.data.get('beta')))))}) 445 | self.data.update({'s_p': (pi * self.data['m_n'] / 2) + 2 * self.data['m_n'] * self.data['x'] * tan( 446 | radians(self.data['alpha_n']))}) 447 | if 'tau' in self.data and 'z' not in self.data: 448 | self.data.update({'z': int(2 * pi / self.data.get('tau'))}) 449 | if 'z' in self.data and 'm_n' in self.data: 450 | self.data.update( 451 | {'d': self.data.get('m_n') * self.data.get('z') / cos(radians(self.data.get('beta')))}) 452 | elif 'z' in self.data and 'd' in self.data: 453 | self.data.update( 454 | {'m_n': self.data.get('d') * cos(radians(self.data.get('beta'))) / self.data.get('z')}) 455 | elif 'm_n' in self.data and 'd' in self.data: 456 | self.data.update({ 457 | 'z': int(self.data.get('d') * cos(radians(self.data.get('beta'))) / self.data.get('m_n'))}) 458 | else: 459 | raise AttributeError('insufficient data supplied') 460 | 461 | if 'tau' not in self.data: 462 | self.data.update({'tau': degrees(2 * pi / self.data.get('z'))}) 463 | 464 | isexternal = sign(self.data.get('z')) 465 | if not sign(self.data.get('d')) == isexternal: 466 | raise ValueError('sign of pitch diameter') 467 | 468 | self.data.update({'m_t': self.data.get('m_n') / cos(radians(self.data.get('beta')))}) 469 | if 'alpha_n' in self.data: 470 | if self.data.get('alpha_n') < 0: 471 | raise ValueError('pitch angle non-positive') 472 | else: 473 | self.data.update({'alpha_n': self._alpha_n_default}) 474 | 475 | if 'x' not in self.data: 476 | self.data.update({'x': self._x_default}) 477 | 478 | if 'A_s' not in self.data: 479 | self.data.update({'A_s': self._A_s_default}) 480 | # tooth thickness allowance: value check 481 | else: 482 | if not self.data.get('A_s') <= 0: 483 | raise ValueError('tooth thickness allowance positive') 484 | 485 | self.data.update({'x_E': self.data.get('x') + self.data.get('A_s') / 2 / tan( 486 | radians(self.data.get('alpha_n'))) / self.data.get('m_n')}) 487 | if 'd_w' in self.data and 'alpha_wt' not in self.data: 488 | if not sign(self.data.get('d_w')) == isexternal: 489 | raise ValueError('sign of service pitch diameter') 490 | self.data.update({'alpha_wt': degrees(acos( 491 | self.data.get('d') / self.data.get('d_w') * cos(radians(self.data.get('alpha_t')))))}) 492 | 493 | if 'alpha_wt' in self.data and 'd_w' not in self.data: 494 | self.data.update({'d_w': self.data.get('d') * cos(radians(self.data.get('alpha_t'))) / cos( 495 | radians(self.data.get('alpha_wt')))}) 496 | 497 | self.data.update({'d_b': self.data.get('d') * cos(radians(self.data.get('alpha_t')))}) 498 | if formcoords: 499 | self.data.update(self._analyze_formcoords()) 500 | if not formcoords: 501 | # tip clearance: value check, set to default if not supplied 502 | if 'c' in self.data: 503 | if self.data.get('c') < 0.1 * self.data.get('m_n') or self.data.get('c') > 0.3 * self.data.get( 504 | 'm_n'): 505 | raise ValueError('tip clearance out of bounds') 506 | else: 507 | self.data.update({'c': self._c_default * self.data.get('m_n')}) 508 | 509 | # fillet radius: value check, set to default if not supplied 510 | if 'rho_f' not in self.data: 511 | self.data.update({'rho_f': self._rho_f_default * self.data.get('m_n')}) 512 | else: 513 | if self.data.get('rho_f') < 0: 514 | raise ValueError('fillet radius negative') 515 | 516 | # CAUTION: THE FOLLOWING SECTION OF CODE WILL BE REMOVED IN FUTURE RELEASES! 517 | # tool fillet radius: value check 518 | if 'rho_fP' in self.data: 519 | if self.data.get('rho_fP') < 0: 520 | raise ValueError('tool fillet radius negative') 521 | if not self.data.get('beta') == 0: 522 | raise ValueError('fillet trochoid cannot be generated for helical gears') 523 | # END OF CODE SECTION TO BE REMOVED 524 | 525 | # calculate tip height modification factor if possible (else set to default) 526 | # various attempts are made 527 | if 'a' in self.data and 'k' not in self.data: 528 | self.data.update( 529 | {'a_d': self.data.get('m_t') * (self.data.get('z') + self.data.get('z_2')) / 2}) 530 | self.data.update({'k': (self.data.get('a') - self.data.get('a_d')) / self.data.get('m_n') - ( 531 | self.data.get('x') + self.data.get('x_2'))}) 532 | else: 533 | self.data.update({'k': self._k_default}) 534 | 535 | # root circle diameter: value check, calculate if not supplied 536 | if 'd_f' in self.data: 537 | if 'd_f' in self.data > 'd' in self.data: 538 | raise ValueError('root circle diameter greater than pitch diameter') 539 | if not sign(self.data.get('d_f')) == isexternal: 540 | raise ValueError('sign of root circle diameter') 541 | else: 542 | self.data.update({ 543 | 'd_f': self.data.get('d') + 2 * self.data.get('x_E') * self.data.get('m_n') - 2 * ( 544 | self.data.get('m_n') + self.data.get('c'))}) 545 | 546 | # tip diameter: value check, calculate if not supplied 547 | if 'd_a' in self.data: 548 | # if self.data.get('d_a') s_a: 574 | raise ValueError('remaining tip tooth thickness greater than tooth thickness') 575 | 576 | if 'd_Ff' in self.data: 577 | if self.data.get('d_Ff') > self.data.get('d'): 578 | raise ValueError('root form diameter greater than pitch diameter') 579 | if self.data.get('d_Ff') < self.data.get('d_f'): 580 | raise ValueError('root form diameter less than root circle diameter') 581 | if not sign(self.data.get('d_Ff')) == isexternal: 582 | raise ValueError('sign of root form diameter') 583 | 584 | # tip form diameter: value check 585 | if 'd_Fa' in self.data: 586 | if self.data.get('d_Fa') < self.data.get('d'): 587 | raise ValueError('tip form diameter less than pitch diameter') 588 | if self.data.get('d_Fa') > self.data.get('d_a'): 589 | raise ValueError('tip form diameter greater than tip diameter') 590 | if not sign(self.data.get('d_Fa')) == isexternal: 591 | raise ValueError('sign of tip form diameter') 592 | else: 593 | self.data.update({'d_Fa': self.data.get('d_a') - 2 * self.data.get('h_k')}) 594 | 595 | if 'd_s' not in self.data: 596 | self.data.update({'d_s': self._d_s_default}) 597 | if abs(self.data.get('d_s')) > self._tol_default: 598 | if not sign(self.data.get('d_s')) == isexternal: 599 | raise ValueError('sign of shaft diameter') 600 | if not self.data.get('d_s') < self.data.get('d_f'): 601 | raise ValueError('shaft diameter greater than root circle diameter') 602 | 603 | if not self.formcoords: 604 | self._make_form_coords() 605 | else: 606 | self.formcoords = self._make_unique(self.formcoords) 607 | 608 | def _make_form_coords(self): 609 | """ 610 | Tooth form coordinates in transverse cross-section (half tooth and half gap) 611 | points returned in 2D-cartesian coordinates, origin on wheel axis 612 | old form coordinates (if existend) will be replaced! 613 | This method should be used only if no user-supplied form coordinates are 614 | present. 615 | 616 | INPUT parameter: 617 | - 618 | """ 619 | 620 | # module imports 621 | from scipy.optimize import fsolve 622 | from numpy.linalg import norm 623 | from numpy import insert 624 | 625 | # tolerance for comparisons 626 | tol = self._tol_default * self.data.get('m_n') 627 | 628 | # delete old form coordinates if existend 629 | if self.formcoords: 630 | del self.formcoords 631 | if self._formwire: 632 | del self._formwire 633 | 634 | # indicator whether gear is external (number of teeth positive) or internal 635 | isexternal = sign(self.data.get('z')) 636 | inv_extension = False 637 | 638 | # indices for adressing parts of tooth form 639 | lower_index = 0 640 | start_rootcirc_index = lower_index + 1 # one entry reserved for origin 641 | end_rootcirc_index = start_rootcirc_index + self.points_root - 1 642 | start_fillet_index = end_rootcirc_index 643 | end_fillet_index = start_fillet_index + self.points_fillet - 1 644 | start_involute_index = end_fillet_index + 1 # can differ from end of fillet 645 | end_involute_index = start_involute_index + self.points_flank - 1 646 | start_chamfer_index = end_involute_index + 1 647 | end_chamfer_index = start_chamfer_index + self.points_chamfer - 1 648 | start_tipcirc_index = end_chamfer_index + 1 # differs from end of involute if chamfer present 649 | end_tipcirc_index = start_tipcirc_index + self.points_tip - 1 650 | upper_index = end_tipcirc_index 651 | 652 | # determine boundary of half tooth segment on root circle 653 | rootcirc_start_point = self.data.get('d_f') / 2 * np.array( 654 | [-sin(radians(self.data.get('tau') / 2)), cos(radians(self.data.get('tau') / 2))]) 655 | 656 | # determine how the root shape is defined and calculate significant points 657 | # root shape is circular in transverse cross-section 658 | if isexternal > 0: # for external gears 659 | if 'd_Ff' not in self.data: 660 | # root circle is tangent to involute 661 | if (self.data.get('d_f') ** 2 + 4 * self.data.get('rho_f') * self.data.get( 662 | 'd_f') >= self.data.get('d_b') ** 2): 663 | self.data.update({'d_Ff': isexternal * sqrt((sqrt( 664 | (self.data.get('d_f') + 2 * self.data.get('rho_f')) ** 2 - self.data.get( 665 | 'd_b') ** 2) - 2 * self.data.get('rho_f')) ** 2 + self.data.get('d_b') ** 2)}) 666 | s_yt, d_yc = self._tooth_thickness(self.data.get('d_Ff')) 667 | fil_end_point = np.array([-s_yt / 2, d_yc / 2]) 668 | # no tangency possible: undercut 669 | elif self.data.get('d_f') + 4 * self.data.get('rho_f') >= self.data.get('d_b'): 670 | self.data.update({'d_Ff': self.data.get('d_b')}) 671 | s_yt, d_yc = self._tooth_thickness(self.data.get('d_b')) 672 | fil_end_point = np.array([-s_yt / 2, d_yc / 2]) # end of involute at base circle 673 | print( 'Warning: undercutting occurs!') 674 | else: 675 | self.data.update({'d_Ff': self.data.get('d_b')}) 676 | d_tangent = sqrt(self.data.get('d_f') ** 2 + 4 * self.data.get('rho_f') * self.data.get( 677 | 'd_f')) # diameter around gear center on that tangency point of fillet curve is located 678 | s_yt, d_yc = self._tooth_thickness(self.data.get('d_b')) 679 | nu = atan(s_yt / d_yc) 680 | fil_end_point = np.array([-d_tangent / 2 * sin(nu), d_tangent / 2 * cos( 681 | nu)]) # tangential extension of involute beyond base circle 682 | print ('Warning: involute had to be extended below base cicle to achieve root fillet tangency!') 683 | inv_extension = True 684 | else: 685 | # if root form circle diameter is supplied, it is forced strictly if possible 686 | if (self.data.get('d_Ff') - self.data.get('d_f')) / 2 > 2 * self.data.get( 687 | 'rho_f'): # check if root fillet circle fits beetween root form circle and root circle 688 | raise ValueError('root fillet radius too small: root shape cannot be determined') 689 | s_yt, d_yc = self._tooth_thickness(self.data.get('d_Ff')) 690 | if abs(self.data.get('d_Ff')) >= abs(self.data.get('d_b')): # fillet ends at root form circle 691 | fil_end_point = np.array([-s_yt / 2, d_yc / 2]) 692 | else: # base circle diameter greater than root form diameter: tangential extension of involute 693 | nu = atan(s_yt / d_yc) 694 | fil_end_point = np.array( 695 | [-self.data.get('d_Ff') * sin(nu), self.data.get('d_Ff') * cos(nu)]) 696 | print ('Warning: involute had to be extended below base cicle to enforce root form circle diameter!') 697 | inv_extension = True 698 | 699 | else: # for internal gears 700 | if 'd_Ff' not in self.data: 701 | # root circle is tangent to involute 702 | t_b = sqrt( 703 | (self.data.get('d_f') / 2 + self.data.get('rho_f')) ** 2 - (self.data.get('d_b') / 2) ** 2) 704 | self.data.update( 705 | {'d_Ff': -2 * sqrt((t_b + self.data.get('rho_f')) ** 2 + (self.data.get('d_b') / 2) ** 2)}) 706 | else: 707 | # if root form circle diameter is supplied, it is forced strictly if possible 708 | if (self.data.get('d_Ff') - self.data.get('d_f')) / 2 > 2 * self.data.get( 709 | 'rho_f'): # check if root fillet circle fits beetween root form circle and root circle 710 | raise ValueError('root fillet radius too small: root shape cannot be determined') 711 | s_yt, d_yc = self._tooth_thickness(self.data.get('d_Ff')) 712 | fil_end_point = np.array([-s_yt / 2, d_yc / 2]) 713 | 714 | # find center of root fillet circle by cutting circle around fillet end point with radius rho_f 715 | # with circle around center of gear wheel with radius d_f/2+rho_f 716 | def root_circle_center_func(phi): 717 | return fil_end_point + self.data.get('rho_f') * np.array([sin(phi[0]), cos(phi[0])]) - (self.data.get( 718 | 'd_f') / 2 + self.data.get('rho_f')) * np.array([sin(phi[1]), cos(phi[1])]) 719 | 720 | phi_fil_center = fsolve(root_circle_center_func, [-pi / 2, 0.0]) 721 | fil_center_point = (self.data.get('d_f') / 2 + self.data.get('rho_f')) * np.array( 722 | [sin(phi_fil_center[1]), cos(phi_fil_center[1])]) 723 | 724 | # boundary point of root fillet and root circle 725 | fil_start_point = fil_center_point * self.data.get('d_f') / ( 726 | self.data.get('d_f') + 2 * self.data.get('rho_f')) 727 | 728 | # if boundary point and fillet center are outside half tooth segment the shape of the root fillet 729 | # cannot be determined (root fillet curve is not continously differentiable and d_f is not matched) 730 | if abs(atan(fil_start_point[0] / fil_start_point[1])) > abs(radians(self.data.get('tau') / 2)): 731 | raise ValueError('root fillet radius too large: root shape cannot be determined') 732 | 733 | # determine boundary points of involute 734 | s_yt, d_yc = self._tooth_thickness(self.data.get('d_Ff')) 735 | inv_start_point = np.array([-s_yt / 2, d_yc / 2]) # involute starts at root form circle 736 | s_yt, d_yc = self._tooth_thickness(self.data.get('d_Fa')) 737 | inv_end_point = np.array([-s_yt / 2, d_yc / 2]) # involute ends at tip form circle 738 | 739 | # determine boundary points of tip circle 740 | nu = self.data.get('s_aK') / self.data.get('d_a') 741 | tipcirc_start_point = np.array([-self.data.get('d_a') / 2 * sin(nu), self.data.get('d_a') / 2 * cos( 742 | nu)]) # tip circle starts at end of tip chamfer 743 | tipcirc_end_point = np.array([0.0, self.data.get('d_a') / 2]) # tip circle ends at symmetry line 744 | 745 | # create array for tooth form coordinates 746 | formcoord_array = np.zeros([upper_index, 2]) 747 | 748 | # compute points on root circle 749 | phi_start = -asin(2 * rootcirc_start_point[0] / self.data.get('d_f')) # starting angle of root circle 750 | if abs(phi_start - acos(2 * rootcirc_start_point[1] / self.data.get( 751 | 'd_f'))) > tol: # computation is not unique 752 | phi_start = pi - phi_start 753 | phi_end = -asin(2 * fil_start_point[0] / self.data.get('d_f')) # end angle of root circle 754 | if abs(phi_end - acos(2 * fil_start_point[1] / self.data.get('d_f'))) > tol: # computation is not unique 755 | phi_end = pi - phi_end 756 | if abs(phi_start - phi_end) > tol: # check if a root circle curve exists 757 | delta_phi = (phi_end - phi_start) / (self.points_root - 1) 758 | n = 0 759 | for index in range(start_rootcirc_index, end_rootcirc_index): 760 | formcoord_array[index] = self.data.get('d_f') / 2 * np.array( 761 | [-sin(phi_start + n * delta_phi), isexternal * cos(phi_start + n * delta_phi)]) 762 | n += 1 763 | 764 | # compute points on root fillet 765 | print ('Warning: circular root fillet in transverse cross-section assumed!') 766 | phi_start = asin( 767 | (fil_start_point[0] - fil_center_point[0]) / self.data.get('rho_f')) # starting angle of root fillet 768 | if abs(phi_start - acos(-(fil_start_point[1] - fil_center_point[1]) / self.data.get( 769 | 'rho_f'))) > tol: # computation is not unique 770 | phi_start = pi - phi_start 771 | phi_end = asin( 772 | (fil_end_point[0] - fil_center_point[0]) / self.data.get('rho_f')) # end angle of root fillet 773 | if abs(phi_end - acos(-(fil_end_point[1] - fil_center_point[1]) / self.data.get( 774 | 'rho_f'))) > tol: # computation is not unique 775 | phi_end = pi - phi_end 776 | if abs(phi_start - phi_end) > tol: # check if a root fillet curve exists 777 | delta_phi = (phi_end - phi_start) / (self.points_fillet - 1) 778 | n = 0 779 | for index in range(start_fillet_index, end_fillet_index + 1): 780 | formcoord_array[index] = fil_center_point + self.data.get('rho_f') * np.array( 781 | [sin(phi_start + n * delta_phi), -isexternal * cos(phi_start + n * delta_phi)]) 782 | n += 1 783 | if (inv_start_point - fil_end_point).any(): # check if a root fillet circle connects directly to flank 784 | print ('involute was extended') # placeholder for future 785 | 786 | # compute points on flank 787 | d_start = isexternal * norm(inv_start_point, 2) * 2 # start diameter of involute flank (root form diameter) 788 | d_end = isexternal * norm(inv_end_point, 2) * 2 # end diameter of involute flank (tip form diameter) 789 | delta_d = (d_end - d_start) / (self.points_flank - 1) 790 | n = 0 791 | for index in range(start_involute_index, end_involute_index + 1): 792 | s_yt, d_yc = self._tooth_thickness(d_start + n * delta_d) 793 | formcoord_array[index] = np.array([-s_yt / 2, d_yc / 2]) 794 | n += 1 795 | 796 | # compute points on tip chamfer 797 | if 'h_k' in self.data and (self.data.get('h_k') > 0): 798 | print ('Warning: straight tip chamfer assumed!') 799 | delta_k = 1 / (self.points_chamfer - 1) 800 | n = 0 801 | for index in range(end_involute_index, end_chamfer_index): 802 | formcoord_array[index] = inv_end_point + (tipcirc_start_point - inv_end_point) * n * delta_k 803 | n += 1 804 | 805 | # compute points on tip circle 806 | phi_start = -asin(2 * tipcirc_start_point[0] / self.data.get('d_a')) # starting angle of tip circle 807 | if abs(phi_start - acos(2 * tipcirc_start_point[1] / self.data.get( 808 | 'd_a'))) > tol: # computation is not unique 809 | phi_start = pi - phi_start 810 | phi_end = -asin(2 * tipcirc_end_point[0] / self.data.get('d_a')) # end angle of tip circle 811 | if abs(phi_end - acos(2 * tipcirc_end_point[1] / self.data.get( 812 | 'd_a'))) > tol: # computation is not unique 813 | phi_end = pi - phi_end 814 | if isexternal < 0: 815 | phi_end = phi_end + pi 816 | if abs(phi_start - phi_end) > tol: # check if a tip circle curve exists 817 | delta_phi = (phi_end - phi_start) / (self.points_tip - 1) 818 | n = 1 819 | for index in range(end_chamfer_index + 1, end_tipcirc_index): 820 | formcoord_array[index] = self.data.get('d_a') / 2 * np.array( 821 | [-sin(phi_start + n * delta_phi), isexternal * cos(phi_start + n * delta_phi)]) 822 | n += 1 823 | 824 | # compute points on tangential extension of involute below base circle 825 | if inv_extension: 826 | delta_k = 1 / (self.points_ext - 1) 827 | for n in range(1, self.points_ext - 1): 828 | formcoord_array = insert(formcoord_array, start_involute_index, 829 | inv_start_point + (fil_end_point - inv_start_point) * n * delta_k, axis=0) 830 | 831 | self.formcoords = self._make_unique(formcoord_array) 832 | 833 | 834 | class GearExport(object): 835 | def __init__(self, pairdata): 836 | """ 837 | Initialization of GearPair-object 838 | Should be overwritten in derived classes 839 | 840 | :rtype : object 841 | INPUT parameters: 842 | pairdata : data of gear wheel pair (dictionary) 843 | Pinion : pinion (GearWheel-instance) 844 | Gear : gear (GearWheel-instance) 845 | """ 846 | 847 | self.data = deepcopy(pairdata) 848 | gear = {'z': self.data['z'], 'x': self.data['x'], 'alpha_n': self.data['alpha_n'], 'beta': self.data['beta'], 849 | 'm_n': self.data['m_n'], 'rho_f': self.data['rho_f'], 'd_s': self.data['d_s'], 'c': self.data['c'], 850 | 'b': self.data['b']} 851 | 852 | self.gear = self.__set_gear(gear) 853 | 854 | @staticmethod 855 | def __set_gear(geardata): 856 | """ 857 | Set pinion attribute 858 | 859 | :rtype : object 860 | INPUT parameter: 861 | gear : pinion ((Gear Pair data)) 862 | """ 863 | 864 | gear = CylindricalGearWheel(geardata) 865 | pd_s = gear.data['d'] * pi 866 | ang = gear.data['s_p'] * 360 / pd_s 867 | shaft = [[0, gear.data['d_s'] / 2], rotate([[0, gear.data['d_s'] / 2]], 0.5 * ( 868 | (gear.data['d_s'] / gear.data['z']) * 360 / gear.data['d_s']))[0]] 869 | gear.shaftcoords = shaft 870 | gear.formcoords = list(gear.formcoords.values()) 871 | gear.rotate_ang = -ang / 2 872 | 873 | return gear -------------------------------------------------------------------------------- /gearbox/libs/maths.py: -------------------------------------------------------------------------------- 1 | from math import tan, radians, degrees, pi, sqrt, cos, sin, atan 2 | 3 | 4 | def involute(angle): 5 | """ 6 | 7 | :param angle: 8 | :return: 9 | """ 10 | return tan(radians(angle)) - radians(angle) 11 | 12 | 13 | def arcinvolute(inv): 14 | """ 15 | 16 | :param inv: 17 | :return: 18 | """ 19 | anglezero = 0 20 | angleone = pi / 2 21 | invdiff = inv 22 | anglecal = 0 23 | while abs(invdiff) > 1e-5: 24 | anglecal = (anglezero + angleone) / 2 25 | invdiff = tan(anglecal) - anglecal - inv 26 | if invdiff > 0: 27 | angleone = anglecal 28 | else: 29 | anglezero = anglecal 30 | return degrees(anglecal) 31 | 32 | 33 | def sign(number): 34 | """ 35 | Sign of a number 36 | 37 | :param number: 38 | INPUT parameter: 39 | number : number that's sign is to be calculated (numeric) 40 | 41 | OUTPUT: 42 | value of sign(number) (-1, 0, 1) 43 | """ 44 | 45 | if number > 0.0: 46 | return 1 47 | elif number < 0.0: 48 | return -1 49 | else: 50 | return 0 51 | 52 | 53 | def CartesianCoordinatesToPolarCoordinates(x, y): 54 | """ 55 | convert a tuple that represents a vector in cartesian coordinates to polar coordinates. 56 | The zero angle of the polar representation corresponds to x-direction of cartesian representation. 57 | 58 | INPUT parameters: 59 | x: x-value of vector in cartesian coordinates (numeric) 60 | y: y-value of vector in cartesian coordinates (numeric) 61 | 62 | OUTPUT: 63 | r: radial coordinate of vector in polar coordinates (numeric) 64 | phi: anglular coordinate of vector in polar coordinates (numeric)[radians] 65 | """ 66 | 67 | r = sqrt(x ** 2 + y ** 2) 68 | if x > 0.0: # arctangent is not unique 69 | phi = atan(y / x) 70 | elif x < 0.0: 71 | phi = atan(y / x) + pi * sign(y) 72 | else: # absolute value of x/y is infinity 73 | if y > 0.0: 74 | phi = pi / 2 75 | elif y < 0.0: 76 | phi = -pi / 2 77 | else: 78 | phi = 0.0 # this is arbitrary 79 | 80 | return [r, phi] 81 | 82 | 83 | def PolarCoordinatesToCartesianCoordinates(r, phi): 84 | """ 85 | convert a tuple that represents a vector in polar coordinates to cartesian coordinates. 86 | The zero angle of the polar representation corresponds to x-direction of cartesian representation. 87 | 88 | INPUT parameters: 89 | r: radial coordinate of vector in polar coordinates (numeric) 90 | phi: anglular coordinate of vector in polar coordinates (numeric)[radians] 91 | 92 | OUTPUT: 93 | x: x-value of vector in cartesian coordinates (numeric) 94 | y: y-value of vector in cartesian coordinates (numeric) 95 | """ 96 | 97 | x = r * cos(phi) 98 | y = r * sin(phi) 99 | 100 | return [x, y] 101 | 102 | 103 | def rotate(coords, angle, center=(0, 0,)): 104 | """ 105 | p'x = cos(angle) * (px-ox) - sin(angle) * (py-oy) + ox 106 | p'y = sin(angle) * (px-ox) + cos(angle) * (py-oy) + oy 107 | 108 | :param coords: 109 | :param angle: 110 | :param center: 111 | :return: 112 | """ 113 | rotated = [[cos(radians(angle)) * (coord[0] - center[0]) - sin(radians(angle)) * (coord[1] - center[1]) + center[0], 114 | sin(radians(angle)) * (coord[0] - center[0]) + cos(radians(angle)) * (coord[1] - center[1]) + center[1]] 115 | for coord in coords] 116 | 117 | return rotated -------------------------------------------------------------------------------- /gearbox/optimization/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'efirvida' 2 | -------------------------------------------------------------------------------- /gearbox/optimization/addendum.py: -------------------------------------------------------------------------------- 1 | from math import radians, pi, tan, cos, acos, degrees 2 | 3 | from gearbox.libs.maths import involute 4 | from gearbox.transmission.gears import Transmission 5 | 6 | 7 | class Optmization(object): 8 | def __init__(self, transmission): 9 | self.transmission = transmission 10 | 11 | def pitting(self, standard='ISO'): 12 | sh1 = 1 13 | sh2 = -1 14 | xsum = self.transmission.xsum 15 | xmin1 = self.transmission.gear_one.xmin 16 | xmin2 = self.transmission.gear_two.xmin 17 | xm = self.maxaddendum() 18 | xmin = max([xmin1, xmin2]) 19 | # xmax = min([xm[0], xm[1]]) 20 | xmax = min([xm[0], xm[1]]) if min([xm[0], xm[1]]) < xmin else max([xm[0], xm[1]]) 21 | 22 | if standard is 'ISO': 23 | from gearbox.standards.iso import Pitting 24 | elif standard is 'AGMA': 25 | from gearbox.standards.agma import Pitting 26 | 27 | while abs(sh1 - sh2) >= 1e-10: 28 | self.transmission.gear_one.x = xmin 29 | self.transmission.gear_two.x = xsum - xmin 30 | self.transmission = Transmission(transmission=self.transmission) 31 | sh1 = Pitting(self.transmission).calculate()['sigmaH'] 32 | 33 | self.transmission.gear_one.x = xmax 34 | self.transmission.gear_two.x = xsum - xmax 35 | self.transmission = Transmission(transmission=self.transmission) 36 | sh2 = Pitting(self.transmission).calculate()['sigmaH'] 37 | 38 | if sh1 > sh2: 39 | xmin = (xmax + xmin) / 2 40 | else: 41 | xmax = (xmax + xmin) / 2 42 | 43 | return [xmin, xsum - xmin] 44 | 45 | def bending(self): 46 | return self.maxaddendum() 47 | 48 | 49 | def maxaddendum(self): 50 | sa1 = 0.3 51 | sa2 = 0.3 52 | b = 0.20 * self.transmission.m 53 | x1 = 0 54 | xmax = 3 55 | 56 | xmin1 = self.transmission.gear_one.xmin 57 | xmin2 = self.transmission.gear_two.xmin 58 | xmin = max([xmin1, xmin2]) 59 | xsum = self.transmission.xsum 60 | 61 | while abs(sa1 - b) >= 1e-10 and abs(sa2 - b) >= 1e-10: 62 | x1 = (xmax + xmin) / 2 63 | x2 = - x1 + xsum 64 | dy = xsum + 0.5 * ( 65 | self.transmission.gear_one.z + self.transmission.gear_two.z) - self.transmission.aw / self.transmission.m 66 | 67 | da1 = self.transmission.m * (self.transmission.gear_one.z / cos(radians( 68 | self.transmission.gear_one.beta)) + 2 * self.transmission.gear_one.profile.ha_p + 2 * x1 - 2 * dy) 69 | da2 = self.transmission.m * (self.transmission.gear_two.z / cos(radians( 70 | self.transmission.gear_one.beta)) + 2 * self.transmission.gear_one.profile.ha_p + 2 * x2 - 2 * dy) 71 | 72 | # da1 = self.transmission.gear_one.da 73 | # da2 = self.transmission.gear_two.da 74 | 75 | sp1 = self.transmission.m * (pi / 2 + 2 * x1 * tan(radians(self.transmission.alpha))) 76 | sp2 = self.transmission.m * (pi / 2 + 2 * x2 * tan(radians(self.transmission.alpha))) 77 | 78 | d1 = self.transmission.gear_one.d 79 | d2 = self.transmission.gear_two.d 80 | 81 | db1 = self.transmission.gear_one.db 82 | db2 = self.transmission.gear_two.db 83 | 84 | alfae1 = acos(db1 / da1) 85 | alfae2 = acos(db2 / da2) 86 | 87 | sa1 = da1 * (sp1 / d1 + involute(self.transmission.alpha) - involute(degrees(alfae1))) 88 | sa2 = da2 * (sp2 / d2 + involute(self.transmission.alpha) - involute(degrees(alfae2))) 89 | 90 | if min([sa1, sa2]) - b > 0: 91 | xmin = x1 92 | else: 93 | xmax = x1 94 | 95 | if x2 < xmin2: 96 | x1 = abs(xmin2) 97 | 98 | self.transmission.gear_one.x = x1 99 | self.transmission.gear_two.x = x2 100 | self.transmission = Transmission(transmission=self.transmission) 101 | 102 | if self.transmission.epsilon_alpha <= 1.2: 103 | break 104 | 105 | # print(self.transmission.epsilon_alpha) 106 | # print(sa1) 107 | # print(sa2) 108 | return [x1, xsum - x1] 109 | -------------------------------------------------------------------------------- /gearbox/standards/__init__.py: -------------------------------------------------------------------------------- 1 | __author__ = 'efirvida' 2 | -------------------------------------------------------------------------------- /gearbox/standards/agma.py: -------------------------------------------------------------------------------- 1 | from math import pi, sqrt, log, ceil, sin, radians, degrees, asin, cos, atan, tan, acos 2 | 3 | from numpy import interp, max 4 | 5 | from gearbox.libs.maths import arcinvolute 6 | 7 | 8 | # pitting from AGMA-2101 D04 9 | class Pitting(object): 10 | """ 11 | 12 | :param transmission: 13 | """ 14 | 15 | def __init__(self, transmission): 16 | self.transmission = transmission 17 | 18 | def calculate(self): 19 | pair = self.transmission 20 | d = pair.gear_one.d 21 | b = pair.gear_two.bs 22 | 23 | cp = self.__ElasticCoefficient__(pair) 24 | ft = pair.ft 25 | ka = pair.ka 26 | ks = __sizefactor__(pair) 27 | kh = __loaddistribution__(pair) 28 | cf = 1 29 | 30 | kv = __dynamicfactor__(pair) 31 | I = __geometryfactor__(pair)['I'] 32 | 33 | # Ko = OverloadFactor(pair) 34 | sigmah = cp * sqrt( 35 | ft * ka * kv * ks * (kh / (d * b)) * cf / I) 36 | return { 37 | 'sigmaH': sigmah, 38 | 'cp': cp, 39 | 'Wt': ft, 40 | 'ka': ka, 41 | 'kv': kv, 42 | 'ks': ks, 43 | 'kh': kh, 44 | 'cf': cf, 45 | 'I': I 46 | } 47 | 48 | @staticmethod 49 | def __ElasticCoefficient__(pair): 50 | eone = pair.gear_one.material.e 51 | etwo = pair.gear_two.material.e 52 | pone = pair.gear_one.material.poisson 53 | ptwo = pair.gear_two.material.poisson 54 | 55 | if eone == etwo: 56 | return sqrt(eone / (2 * pi * (1 - pone ** 2))) 57 | else: 58 | return sqrt(1 / (pi * (((1 - pone) / eone) + (1 - ptwo) / etwo))) 59 | 60 | 61 | # Bending from AGMA-2101 D04 62 | class Bending(object): 63 | """ 64 | 65 | :param transmission: 66 | """ 67 | 68 | def __init__(self, transmission): 69 | self.transmission = transmission 70 | 71 | def calculate(self): 72 | pair = self.transmission 73 | ft = pair.ft 74 | ka = pair.ka 75 | 76 | b = pair.gear_one.bs 77 | mt = pair.gear_one.m / cos(radians(pair.gear_one.beta)) 78 | 79 | kv = __dynamicfactor__(pair) 80 | ks = __sizefactor__(pair) 81 | J = __geometryfactor__(pair)['J'] 82 | kh = __loaddistribution__(pair) 83 | kb = __rimthicknessfactor__(pair) 84 | 85 | sigmafone = ft * ka * kv * ks * (1. / (b * mt)) * (kh * kb / J[0]) 86 | sigmaftwo = ft * ka * kv * ks * (1. / (b * mt)) * (kh * kb / J[1]) 87 | 88 | return { 89 | 'sigmafone': sigmafone, 90 | 'sigmaftwo': sigmaftwo, 91 | 'Wt': ft, 92 | 'ka': ka, 93 | 'kv': kv, 94 | 'JOne': J[0], 95 | 'JTwo': J[1] 96 | } 97 | 98 | 99 | # influence Factors from AGMA AGMA-2101 D04 100 | def __geometryfactor__(pair): 101 | n1 = pair.gear_one.z 102 | n2 = pair.gear_two.z 103 | nc1 = pair.gear_one.profile.nc 104 | nc2 = pair.gear_two.profile.nc 105 | 106 | mn = pair.gear_one.m 107 | fi_n = radians(pair.gear_one.alpha) 108 | psi = radians(pair.gear_one.beta) 109 | f = pair.gear_one.b / mn 110 | 111 | x1 = pair.gear_one.x 112 | x2 = pair.gear_two.x 113 | xo1 = pair.gear_one.profile.x 114 | xo2 = pair.gear_two.profile.x 115 | hao1 = pair.gear_one.profile.ha_p 116 | hao2 = pair.gear_two.profile.ha_p 117 | rho_ao1 = pair.gear_one.profile.rho_ao 118 | rho_ao2 = pair.gear_two.profile.rho_ao 119 | delta_ao1 = pair.gear_one.profile.delta_ao 120 | delta_ao2 = pair.gear_two.profile.delta_ao 121 | delta_sn1 = pair.gear_one.backlash 122 | delta_sn2 = pair.gear_two.backlash 123 | ro1 = (pair.gear_one.da / 2) / mn 124 | ro2 = (pair.gear_two.da / 2) / mn 125 | mg = pair.u_real 126 | r1 = n1 / (2 * cos(psi)) 127 | r2 = r1 * mg 128 | cr = r1 + r2 129 | fi = atan(tan(fi_n) / cos(psi)) 130 | rb1 = r1 * cos(fi) 131 | rb2 = rb1 * mg 132 | 133 | if n1 > 0: 134 | fi_r = acos((rb2 + rb1) / cr) 135 | else: 136 | fi_r = acos((rb2 - rb1) / cr) 137 | 138 | pb = 2 * pi * rb1 / n1 139 | pn = pi * cos(fi_n) 140 | psi_b = acos(pn / pb) 141 | 142 | c6 = cr * sin(fi_r) 143 | if n1 > 0: 144 | c1 = (c6 - sqrt(ro2 ** 2 - rb2 ** 2)) 145 | # C3 = c6 / (mg + 1) 146 | else: 147 | c1 = -1 * (c6 - sqrt(ro2 ** 2 - rb2 ** 2)) 148 | # C3 = c6 / (mg - 1) 149 | 150 | c4 = c1 + pb 151 | c5 = sqrt(ro1 ** 2. - rb1 ** 2.) 152 | c2 = c5 - pb 153 | 154 | z = c5 - c1 155 | mp = z / pb 156 | 157 | nr = mp % 1 158 | if not psi: 159 | mf = 0 160 | mn = 1 161 | lmin = f 162 | else: 163 | px = pi / sin(psi) 164 | mf = f / px 165 | if mf > 1: 166 | na = mf % 1 167 | if 1 - nr < na: 168 | lmin = (mp * f - (1. - na) * (1. - nr) * px) / cos(psi_b) 169 | else: 170 | lmin = (mp * f - na * nr * px) / cos(psi_b) 171 | mn = f / lmin 172 | else: 173 | mn = 1 174 | psi_r = atan(tan(psi_b) / cos(fi_r)) 175 | fi_nr = asin(cos(psi_b) * sin(fi_r)) 176 | 177 | # I FACTOR# 178 | if n1 > 0: 179 | d = 2 * cr / (mg + 1.) 180 | rm1 = 0.5 * (ro1 + (cr - ro2)) 181 | else: 182 | d = 2 * cr / (mg - 1.) 183 | rm1 = 0.5 * (ro1 + (cr - ro2)) 184 | 185 | if mf <= 1: 186 | rho_1 = c2 187 | rho_m1 = sqrt(rm1 ** 2 - rb1 ** 2) 188 | if n1 > 0: 189 | rho_2 = c6 - rho_1 190 | rho_m2 = c6 - rho_m1 191 | else: 192 | rho_2 = c6 + rho_1 193 | rho_m2 = c6 + rho_m1 194 | c_psi = sqrt(1 - mf * (1 - rho_m1 * rho_m2 * z / (rho_1 * rho_2 * pn))) 195 | else: 196 | rho_1 = sqrt(rm1 ** 2. - rb1 ** 2.) 197 | if n1 > 0: 198 | rho_2 = c6 - rho_1 199 | else: 200 | rho_2 = c6 + rho_1 201 | c_psi = 1 202 | 203 | if n1 > 0: 204 | I = (cos(fi_r) * c_psi ** 2.) / ((1. / rho_1 + 1. / rho_2) * d * mn) 205 | else: 206 | I = (cos(fi_r) * c_psi ** 2.) / ((1. / rho_1 - 1. / rho_2) * d * mn) 207 | # I FACTOR # 208 | 209 | def _j(n1, mg, ro1, r1, r2, rb1, c4, x, delta_sn, nc, hao, xo, rho_ao, delta_ao): 210 | # J FACTOR # 211 | if psi != 0: 212 | n = n1 / cos(psi) ** 3. 213 | rn = n / 2 214 | rnb = rn * cos(fi_n) 215 | if mf <= 1: 216 | rn2 = rn * mg 217 | rnb2 = rnb * mg 218 | rna2 = rn2 + ro2 - r2 219 | cn6 = (rnb2 + rnb) * tan(fi_nr) 220 | cn1 = cn6 - sqrt(rna2 ** 2 - rnb2 ** 2) 221 | cn4 = cn1 + pn 222 | tan_fi_nw = cn4 / rnb 223 | else: 224 | rna = rn + ro1 - r1 225 | tan_fi_nw = sqrt(((rna / rnb) ** 2.) - 1.) 226 | else: 227 | n = n1 228 | rn = r1 229 | rnb = rb1 230 | tan_fi_nw = c4 / rnb 231 | 232 | xg = x - delta_sn / (2 * tan(fi_n)) 233 | sn = pi / 2 + 2 * xg * tan(fi_n) 234 | inv_fi_n = tan(fi_n) - fi_n 235 | fi_nl = tan_fi_nw - tan(fi_n) + fi_n - sn / n 236 | rnl = rnb / cos(fi_nl) 237 | no = nc / cos(psi) ** 3. 238 | rno = no / 2 239 | rnbo = rno * cos(fi_n) 240 | r_s_no = rno + hao + xo - rho_ao 241 | fi_ns = acos(rnbo / r_s_no) 242 | inv_fi_ns = tan(fi_ns) - fi_ns 243 | sno = pi / 2 + 2 * xo * tan(fi_n) 244 | inv_fi_npo = tan(fi_n) - fi_n + sno / no 245 | lambda_ns_2 = inv_fi_npo - inv_fi_ns + ((delta_ao - rho_ao) / rnbo) 246 | inv_fi_n_2 = inv_fi_n + ((2 * (xg + xo) * tan(fi_n)) / (n + no)) 247 | fi_n_2 = radians(arcinvolute(inv_fi_n_2)) 248 | 249 | rn_2 = rn * cos(fi_n) / cos(fi_n_2) 250 | rno_2 = rno * cos(fi_n) / cos(fi_n_2) 251 | alpha_n = pi / 4 252 | hf = 0. 253 | xi_nf = 0. 254 | while 1: 255 | mi_no = acos(rno_2 * cos(alpha_n) / r_s_no) - alpha_n 256 | ks = rno_2 * sin(alpha_n) - r_s_no * sin(alpha_n + mi_no) 257 | kf = ks - rho_ao 258 | sigma_n = no / n * (mi_no - lambda_ns_2 + pi / no) 259 | beta_n = alpha_n - sigma_n 260 | xi_nf = rn_2 * sin(sigma_n) + kf * cos(beta_n) 261 | eta_nf = rn_2 * cos(sigma_n) + kf * sin(beta_n) 262 | hf = rnl - eta_nf 263 | y = 2 * hf * tan(beta_n) - xi_nf 264 | y_ = (2 * hf / cos(beta_n) ** 2) - kf * sin(beta_n) + no / n * ( 265 | (rno_2 * sin(alpha_n) / (r_s_no * sin(alpha_n + mi_no))) - 1) * ( 266 | 2 * xi_nf * tan(beta_n) - eta_nf - 2 * hf / ( 267 | cos(beta_n) ** 2)) - rno_2 * ( 268 | cos(alpha_n) - sin(alpha_n) / tan(alpha_n + mi_no)) * ((1 + sin(beta_n) ** 2.) / cos(beta_n)) 269 | alpha_n1 = alpha_n - y / y_ 270 | 271 | if y <= 1e-6: 272 | break 273 | else: 274 | alpha_n = alpha_n1 275 | 276 | rho_f = rho_ao + ((rno_2 - r_s_no) ** 2) / ((rn_2 * rno_2 / (rn_2 + rno_2)) - (rno_2 - r_s_no)) 277 | omega = degrees(atan(tan(psi) * sin(fi_n))) 278 | sf = 2. * xi_nf 279 | h = 0.331 - 0.436 * fi_n 280 | l = 0.324 - 0.492 * fi_n 281 | m = 0.261 - 0.545 * fi_n 282 | kf = h + ((sf / rho_f) ** l) * ((sf / hf) ** m) 283 | 284 | if mf > 1: 285 | ch = 1. / (1. - sqrt((omega / 100.) * (1. - omega / 100.))) 286 | k_psi = cos(psi_r) * cos(psi) 287 | else: 288 | ch = 1. 289 | k_psi = 1. 290 | 291 | y = k_psi / ((cos(fi_nl) / cos(fi_nr)) * ((6. * hf / ((sf ** 2.) * ch)) - tan(fi_nl) / sf)) 292 | 293 | return y * c_psi / (kf * mn) 294 | 295 | j1 = _j(n1, mg, ro1, r1, r2, rb1, c4, x1, delta_sn1, nc1, hao1, xo1, rho_ao1, delta_ao1) 296 | j2 = _j(n2, 1. / mg, ro2, r2, r1, rb2, c6 - c2, x2, delta_sn2, nc2, hao2, xo2, rho_ao2, delta_ao2) 297 | 298 | return { 299 | 'I': I, 300 | 'J': [j1, j2] 301 | } 302 | 303 | 304 | # FIXME 305 | def __dynamicfactor__(pair): 306 | fpt = pair.gear_one.f_pt 307 | dt1 = pair.gear_one.da - 2 * pair.gear_one.m 308 | dt2 = pair.gear_two.da - 2 * pair.gear_two.m 309 | m = pair.gear_one.m 310 | 311 | if 5 < dt1 <= 400: 312 | # av1 = (log(abs(fpt)) - log(0.3 * m + 0.003 * dt1 + 5.2))/0.3466 + 5 313 | av1 = (log(abs(fpt)) - log(0.3 * m + 0.12 * sqrt(dt1) + 4)) / 0.3466 + 5 314 | else: 315 | av1 = (log(abs(fpt)) - log(0.3 * m + 0.12 * sqrt(dt1) + 4)) / 0.3466 + 5 316 | 317 | if 5 < dt2 <= 400: 318 | # av2 = (log(abs(fpt)) - log(0.3 * m + 0.003 * dt2 + 5.2))/0.3466 + 5 319 | av2 = (log(abs(fpt)) - log(0.3 * m + 0.12 * sqrt(dt2) + 4)) / 0.3466 + 5 320 | else: 321 | av2 = (log(abs(fpt)) - log(0.3 * m + 0.12 * sqrt(dt2) + 4)) / 0.3466 + 5 322 | 323 | av = ceil(max([av1, av2])) 324 | b = 0.25 * (av - 5.0) ** (2. / 3) 325 | c = 50 + 56 * (1 - b) 326 | vt = pi * pair.rpm_in * pair.gear_one.d / 60000 327 | 328 | return (c / (c + sqrt(196.85 * vt))) ** (-b) 329 | 330 | 331 | def __sizefactor__(pair): 332 | a = [5, 6, 8, 12, 20] 333 | b = [1, 1.05, 1.15, 1.25, 1.40] 334 | 335 | if pair.gear_one.m < 5: 336 | ks = 1 337 | elif pair.gear_one.m > 20: 338 | ks = 1.40 339 | else: 340 | ks = interp(pair.gear_one.m, a, b) 341 | 342 | return ks 343 | 344 | 345 | def __loaddistribution__(pair): 346 | cmc = [1, 0.8] 347 | ce = [0.8, 1] 348 | 349 | if pair.gear_one.bs <= 25: 350 | cpf = -0.025 + pair.gear_one.bs / (10 * pair.gear_one.d) 351 | elif 25 < pair.gear_one.bs <= 432: 352 | cpf = (pair.gear_one.bs / ( 353 | 10 * pair.gear_one.d)) - 0.0375 + 0.000492 * pair.gear_one.bs 354 | else: 355 | cpf = (pair.gear_one.bs / ( 356 | 10 * pair.gear_one.d)) - 0.1109 + 0.000815 * pair.gear_one.bs - 0.000000353 * pair.gear_one.bs ** 2 357 | 358 | if pair.gear_one.s / pair.gear_one.l < 0.175: 359 | cpm = 1 360 | else: 361 | cpm = 1.1 362 | 363 | a = [2.47e-1, 1.27e-1, 0.675e-1, 0.380e-1] 364 | b = [0.657e-3, 0.622e-3, 0.504e-3, 0.402e-3] 365 | c = [-1.186e-7, -1.69e-7, -1.44e-7, -1.27e-7] 366 | 367 | cma = a[pair.gear_box_type - 1] + (b[pair.gear_box_type - 1] * pair.gear_one.bs) + (c[ 368 | pair.gear_box_type - 1] * pair.gear_one.bs) ** 2 369 | 370 | return 1. + cmc[pair.gear_one.gear_crown - 1] * (cpf * cpm + cma * ce[pair.gear_one.gear_condition - 1]) 371 | 372 | 373 | def __rimthicknessfactor__(pair): 374 | ht = pair.gear_one.h 375 | 376 | if pair.gear_one.sr == 0: 377 | tr = pair.gear_one.df - pair.gear_one.shaft_diameter 378 | else: 379 | tr = pair.gear_one.sr 380 | 381 | mb = tr / ht 382 | 383 | if mb >= 1.2: 384 | kb = 1. 385 | else: 386 | kb = 1.6 * log(2.242 / mb) 387 | 388 | return kb -------------------------------------------------------------------------------- /gearbox/standards/iso.py: -------------------------------------------------------------------------------- 1 | from math import log, exp, acos 2 | 3 | from numpy import interp, log10 4 | 5 | from gearbox.transmission.gears import * 6 | 7 | 8 | def __c__(pair): 9 | x = [0, 0.04723, 0.15551, 0.25791, -0.00635, -0.11654, -0.00193, -0.24188, 0.00529, 0.00182] 10 | qp = x[1] + (x[2] / pair.gear_one.zn) + (x[3] / pair.gear_two.zn) + (x[4] * pair.gear_one.x) + ( 11 | x[5] * pair.gear_one.x / pair.gear_one.zn) + (x[6] * pair.gear_two.x) + ( 12 | x[7] * pair.gear_two.x / pair.gear_two.zn) + (x[8] * pair.gear_one.x ** 2) + (x[9] * pair.gear_two.x ** 2) 13 | 14 | beq = pair.gear_one.bs / pair.gear_one.b 15 | if beq < 0.2: 16 | beq = 0.2 17 | elif beq > 1.2: 18 | beq = 1.2 19 | 20 | if pair.gear_one.sr is None: 21 | srm = 1 22 | else: 23 | srm = pair.gear_one.sr / pair.gear_one.m 24 | 25 | if srm < 1: 26 | srm = 1 27 | 28 | cth = 1 / qp 29 | 30 | cm = 0.8 31 | cr = 1 + (log(beq) / (5 * exp(srm / (5 * pair.gear_one.m)))) 32 | cb = 0.975 33 | cp = cth * cm * cr * cb * cos(radians(pair.gear_one.beta)) 34 | cgammaalpha = cp * (0.75 * pair.epsilon_alpha + 0.25) 35 | if pair.epsilon_alpha < 1.2: 36 | cgammaalpha *= 0.9 37 | 38 | cgammabeta = 0.85 * cgammaalpha 39 | 40 | return cgammaalpha, cgammabeta, cp 41 | 42 | 43 | def __yb__(gear, pair, fbx): 44 | material = gear.material.classification 45 | sigmahlimit = gear.material.sh_limit 46 | v = pair.v 47 | yb = 0 48 | 49 | if material == 'V' or material == 'St' or material == 'GGG(perl)' or material == 'GTS': 50 | yb = (320. / sigmahlimit) * fbx 51 | if 5 < v <= 10 and yb > 25600. / sigmahlimit: 52 | yb = 25600. / sigmahlimit 53 | elif v > 10 and yb > 12800. / sigmahlimit: 54 | yb = 12800. / sigmahlimit 55 | 56 | elif material == 'GG' or material == 'GGG(ferr)': 57 | yb = 0.55 * fbx 58 | if 5 < v <= 10 and yb > 45: 59 | yb = 45 60 | elif v > 10 and yb > 22: 61 | yb = 22 62 | 63 | elif material == 'Eh' or material == 'IF' or material == 'NT' or material == 'NV(nitr)' or material == 'NV(nitrocar)': 64 | yb = 0.15 * fbx 65 | 66 | return yb 67 | 68 | 69 | def __ya__(material, sigmahlimit, v, fpbone, fpbtwo): 70 | ya = 0 71 | if fpbone > fpbtwo: 72 | fpb = fpbone 73 | else: 74 | fpb = fpbtwo 75 | 76 | if material == 'V' or material == 'St' or material == 'GGG(perl)' or material == 'GTS': 77 | ya = 160 / (sigmahlimit * fpb) 78 | if 5 < v <= 10 and ya > 12800 / sigmahlimit: 79 | ya = 12800 / sigmahlimit 80 | elif 10 < v and ya > 6400 / sigmahlimit: 81 | ya = 6400 / sigmahlimit 82 | 83 | elif material == 'GG' or material == 'GGG(ferr)': 84 | ya = 0.275 * fpb 85 | if 5 < v <= 10 and ya > 12800 / sigmahlimit: 86 | ya = 22 87 | elif 10 < v and ya > 6400 / sigmahlimit: 88 | ya = 11 89 | 90 | elif material == 'Eh' or material == 'IF' or material == 'NT' or material == 'NV(nitr)' or material == 'NV(nitrocar)': 91 | ya = 0.075 * fpb 92 | if ya > 3: 93 | ya = 3 94 | 95 | return ya 96 | 97 | 98 | def __kv__(pair): 99 | fmt = pair.fmt 100 | sr_one = pair.gear_one.sr 101 | sr_two = pair.gear_one.sr 102 | epsilon_gama = pair.epsilon_gama 103 | # sh_limit_1 = pair.gear_one.sigmaHLimit 104 | # sh_limit_2 = pair.gear_two.sigmaHLimit 105 | rho_one = pair.gear_one.material.density 106 | rho_two = pair.gear_two.material.density 107 | da_one = pair.gear_one.da 108 | da_two = pair.gear_two.da 109 | df_one = pair.gear_one.df 110 | df_two = pair.gear_two.df 111 | db_one = pair.gear_one.db 112 | rpm_one = pair.rpm_in 113 | f_f_alpha_one = pair.gear_one.f_f_alpha 114 | f_f_alpha_two = pair.gear_two.f_f_alpha 115 | material_one = pair.gear_one.material 116 | material_two = pair.gear_two.material 117 | v = pair.v 118 | precision_grade = pair.gear_one.precision_grade 119 | u = pair.u_real 120 | z_one = pair.gear_one.z 121 | 122 | c_gamma_alpha, c_gamma_beta, cp = __c__(pair) 123 | di_one = 0.0 if sr_one is None else df_one - 2 * sr_one 124 | di_two = 0.0 if sr_two is None else df_two - 2 * sr_two 125 | dm_one = (da_one + df_one) / 2 126 | dm_two = (da_two + df_two) / 2 127 | q_one = di_one / dm_one 128 | q_two = di_two / dm_two 129 | 130 | cv1 = 0 131 | cv2 = 0 132 | cv3 = 0 133 | cv4 = 0 134 | cv5 = 0 135 | cv6 = 0 136 | cv7 = 0 137 | kv = 0 138 | 139 | if sr_one == 0: 140 | a_one = 1 141 | else: 142 | a_one = 1 / (1 - q_one ** 4) 143 | 144 | if sr_two == 0: 145 | a_two = 1 146 | else: 147 | a_two = 1 / (1 - q_two ** 4) 148 | 149 | m_red = (pi / 8) * ((dm_one / db_one) ** 2) * ( 150 | dm_one ** 2 / ((1 / (a_one * rho_one)) + (1 / (a_two * rho_two * u ** 2)))) 151 | 152 | ne_one = (30000 / (pi * z_one)) * sqrt(c_gamma_alpha / m_red) 153 | 154 | n = rpm_one / ne_one # this is the resonance ratio 155 | 156 | if fmt == 100: 157 | ns = 0.5 + 0.35 * sqrt(fmt / 100) 158 | else: 159 | ns = 0.85 160 | 161 | if 1 < epsilon_gama <= 2: 162 | cv1 = 0.32 163 | cv2 = 0.34 164 | cv3 = 0.23 165 | cv4 = 0.9 166 | cv5 = 0.47 167 | cv6 = 0.47 168 | elif epsilon_gama > 2: 169 | cv1 = 0.32 170 | cv2 = 0.57 / (epsilon_gama - 0.3) 171 | cv3 = 0.096 / (epsilon_gama - 1.56) 172 | cv4 = (0.57 - 0.05 * epsilon_gama) / (epsilon_gama - 1.44) 173 | cv5 = 0.47 174 | cv6 = 0.12 / (epsilon_gama - 1.74) 175 | 176 | if 1 < epsilon_gama <= 1.5: 177 | cv7 = 0.75 178 | elif 1.5 < epsilon_gama <= 2.5: 179 | cv7 = 0.125 * sin(pi * (epsilon_gama - 2)) + 0.875 180 | elif epsilon_gama > 2.5: 181 | cv7 = 1 182 | 183 | cay_one = 1. / 8 * (((pair.gear_one.material.sh_limit / 97.) - 18.45) ** 2) + 1.5 184 | cay_two = 1. / 8 * (((pair.gear_two.material.sh_limit / 97.) - 18.45) ** 2) + 1.5 185 | cay = 0.5 * (cay_one + cay_two) 186 | ya_one = __ya__(material_one, pair.gear_one.material.sh_limit, v, f_f_alpha_one, f_f_alpha_two) 187 | ya_two = __ya__(material_two, pair.gear_two.material.sh_limit, v, f_f_alpha_one, f_f_alpha_two) 188 | ya = 0.5 * (ya_two + ya_one) 189 | 190 | # FIXME 191 | if f_f_alpha_one > f_f_alpha_two: 192 | f_f_alpha = f_f_alpha_one 193 | fpb = f_f_alpha_one 194 | else: 195 | f_f_alpha = f_f_alpha_two 196 | fpb = f_f_alpha_two 197 | 198 | fpbeff = fpb - ya 199 | ffaeff = f_f_alpha - ya 200 | bp = cp * fpbeff / fmt 201 | bf = cp * ffaeff / fmt 202 | # FIXME 203 | 204 | if precision_grade >= 6: 205 | bk = 1 206 | else: 207 | bk = abs(1 - (cp * cay / fmt)) 208 | 209 | if n <= ns: 210 | k = cv1 * bp + cv2 * bf + cv3 * bk 211 | kv = n * k + 1 212 | elif ns < n <= 1.15: 213 | kv = cv1 * bp + cv2 * bf + cv4 * bk + 1 214 | elif n >= 1.5: 215 | kv = cv5 * bp + cv6 * bf + cv7 216 | elif 1.15 < n < 1.5: 217 | kv = (cv5 * bp + cv6 * bf + cv7) + (((cv1 * bp + cv2 * bf + cv4 * bk + 1) - ( 218 | cv5 * bp + cv6 * bf + cv7)) / 0.35) * (1.5 - n) 219 | 220 | return kv 221 | 222 | 223 | def __khb__(pair): 224 | fmt = pair.fmt 225 | b = pair.gear_one.b 226 | helixmodiffication = pair.gear_one.helix_modification 227 | d = pair.gear_one.d 228 | shaftdiameter = pair.gear_one.shaft_diameter 229 | schema = pair.gear_one.schema 230 | l = pair.gear_one.l 231 | s = pair.gear_one.s 232 | fhbone = pair.gear_one.f_h_beta 233 | fhbtwo = pair.gear_two.f_h_beta 234 | fhbeta5one = pair.gear_one.f_h_beta5 235 | fhbeta5two = pair.gear_two.f_h_beta5 236 | fav = pair.gear_one.favorable_contact 237 | kp = 0 238 | b1 = 0 239 | b2 = 0 240 | 241 | kv = __kv__(pair) 242 | cgammabeta = __c__(pair)[1] 243 | 244 | if kv * fmt < 100: 245 | fm_b = 100 246 | else: 247 | fm_b = kv * fmt 248 | 249 | if helixmodiffication == 1: 250 | b1 = 1. 251 | b2 = 1. 252 | if helixmodiffication == 2: 253 | b1 = 1. 254 | b2 = 0.5 255 | if helixmodiffication == 3: 256 | b1 = 0.1 257 | b2 = 1. 258 | if helixmodiffication == 4: 259 | b1 = 0.1 260 | b2 = 0.5 261 | if helixmodiffication == 5: 262 | b1 = 0.7 263 | b2 = 0.7 264 | 265 | stiff = d / shaftdiameter 266 | 267 | if stiff < 1.15: 268 | if schema == 1: 269 | kp = 0.8 270 | if schema == 2: 271 | kp = -0.8 272 | if schema == 3: 273 | kp = 1.33 274 | if schema == 4: 275 | kp = -0.6 276 | if schema == 5: 277 | kp = -1 278 | else: 279 | if schema == 1: 280 | kp = 0.48 281 | if schema == 2: 282 | kp = -0.48 283 | if schema == 3: 284 | kp = 1.33 285 | if schema == 4: 286 | kp = -0.36 287 | if schema == 5: 288 | kp = -0.6 289 | 290 | factemp = (stiff ** 4) * ((l * s) / (d ** 2)) 291 | fsh = fm_b * 0.023 * (abs(1 + kp * factemp - 0.3) + 0.3) * ((b / d) ** 2) 292 | fma = sqrt(fhbone ** 2 + fhbtwo ** 2) 293 | 294 | if fhbeta5one > fhbeta5two: 295 | fhb5 = fhbeta5one 296 | else: 297 | fhb5 = fhbeta5two 298 | 299 | if fav == 1: 300 | fbx = abs(1.33 * b1 * fsh - fhb5) 301 | else: 302 | fbx = 1.33 * b1 * fsh + b2 * fma 303 | 304 | ybone = __yb__(pair.gear_one, pair, fbx) 305 | ybtwo = __yb__(pair.gear_two, pair, fbx) 306 | yb = round(0.5 * (ybone + ybtwo), 1) 307 | fby = fbx - yb 308 | 309 | if fby * cgammabeta / (2 * fm_b) >= 1: 310 | khb = sqrt((2. * fby * cgammabeta) / fm_b) 311 | else: 312 | khb = 1 + (fby * cgammabeta) / (2 * fm_b) 313 | 314 | return khb 315 | 316 | 317 | def __kfb__(pair): 318 | khb = __khb__(pair) 319 | bhone = pair.gear_one.b / pair.gear_one.h 320 | bhtwo = pair.gear_two.b / pair.gear_two.h 321 | 322 | if bhone < bhtwo: 323 | bh = bhone 324 | else: 325 | bh = bhtwo 326 | if bh < 3: 327 | bh = 3 328 | 329 | nf = (bh ** 2) / (1 + bh + (bh ** 2)) 330 | 331 | return khb ** nf 332 | 333 | 334 | def __var__(pair): 335 | ffalphaone = pair.gear_one.f_f_alpha 336 | ffalphatwo = pair.gear_two.f_f_alpha 337 | materialone = pair.gear_one.material 338 | materialtwo = pair.gear_two.material 339 | v = pair.v 340 | 341 | if ffalphaone > ffalphatwo: 342 | fpb = ffalphaone 343 | else: 344 | fpb = ffalphatwo 345 | 346 | khb = __khb__(pair) 347 | kv = __kv__(pair) 348 | cgammaalpha = __c__(pair)[0] 349 | fmt = pair.fmt 350 | 351 | yaone = __ya__(materialone, pair.gear_one.material.sh_limit, v, ffalphaone, ffalphatwo) 352 | yatwo = __ya__(materialtwo, pair.gear_two.material.sh_limit, v, ffalphaone, ffalphatwo) 353 | ya = 0.5 * (yatwo + yaone) 354 | 355 | if kv * fmt < 100: 356 | fm_b = 100 357 | else: 358 | fm_b = kv * fmt 359 | 360 | fthb = fm_b * khb 361 | 362 | return (cgammaalpha * (fpb - ya)) / fthb 363 | 364 | 365 | def __kha__(pair): 366 | epsilonalpha = pair.epsilon_alpha 367 | epsilongama = pair.epsilon_gama 368 | epsilonbeta = pair.epsilon_beta 369 | 370 | var = __var__(pair) 371 | 372 | if epsilonbeta is 0: 373 | zepsilon = sqrt((4 - epsilonalpha) / 3) 374 | elif 1 > epsilonbeta > 0: 375 | zepsilon = sqrt(((4 - epsilonalpha) / 3) * (1 - epsilonbeta) + (epsilonbeta / epsilonalpha)) 376 | else: 377 | zepsilon = sqrt(1 / epsilonalpha) 378 | 379 | if epsilongama <= 2: 380 | kha = (epsilongama / 2) * (0.9 + 0.4 * var) 381 | if kha > epsilongama / (epsilonalpha * zepsilon ** 2): 382 | kha = epsilongama / (epsilonalpha * zepsilon ** 2) 383 | elif kha < 1: 384 | kha = 1 385 | else: 386 | kha = 0.9 + 0.4 * var * sqrt(2 * (epsilongama - 1) / epsilongama) 387 | if kha > epsilongama / (epsilonalpha * zepsilon ** 2): 388 | kha = epsilongama / (epsilonalpha * zepsilon ** 2) 389 | elif kha < 1: 390 | kha = 1 391 | 392 | return kha 393 | 394 | 395 | def __kfa__(pair): 396 | epsilonalpha = pair.epsilon_alpha 397 | epsilongama = pair.epsilon_gama 398 | 399 | var = __var__(pair) 400 | 401 | if epsilongama <= 2: 402 | kfa = (epsilongama / 2) * (0.9 + 0.4 * var) 403 | if kfa > epsilongama / (0.25 * epsilonalpha + 0.75): 404 | kfa = epsilongama / (0.25 * epsilonalpha + 0.75) 405 | elif kfa < 1: 406 | kfa = 1 407 | else: 408 | kfa = 0.9 + 0.4 * var * sqrt(2 * (epsilongama - 1) / epsilongama) 409 | if kfa > epsilongama / (0.25 * epsilonalpha + 0.75): 410 | kfa = epsilongama / (0.25 * epsilonalpha + 0.75) 411 | elif kfa < 1: 412 | kfa = 1 413 | 414 | return kfa 415 | 416 | 417 | class Pitting(object): 418 | """ 419 | 420 | :param transmission: 421 | """ 422 | 423 | def __init__(self, transmission): 424 | self.transmission = transmission 425 | 426 | def calculate(self): 427 | """ 428 | 429 | 430 | :return: 431 | """ 432 | pair = self.transmission 433 | u = pair.u_real 434 | 435 | """ 436 | 437 | :param pair: 438 | :return: 439 | """ 440 | zh = self.__zh(pair) 441 | zb, zd = self.__zb(pair) 442 | ze = self.__ze(pair) 443 | z_epsilon = self.__z_epsilon(pair) 444 | z_beta = 1 / sqrt(cos(radians(pair.gear_one.beta))) 445 | znt_one = self.__znt(pair.gear_one.material.classification, pair.rpm_in) 446 | znt_two = self.__znt(pair.gear_two.material.classification, pair.rpm_out) 447 | zl = self.__zl(pair) 448 | zv = self.__zv(pair) 449 | zr = self.__zr(pair) 450 | zw_one, zw_two = self.__zw(pair) 451 | zx = 1 452 | 453 | kv = __kv__(pair) 454 | khb = __khb__(pair) 455 | kha = __kha__(pair) 456 | 457 | sigmah0 = zh * ze * z_epsilon * z_beta * sqrt((pair.ft * (u + 1)) / (pair.gear_one.d * pair.gear_one.b * u)) 458 | sigmahone = zb * sigmah0 * sqrt(pair.ka * kv * khb * kha) 459 | sigmahtwo = zd * sigmah0 * sqrt(pair.ka * kv * khb * kha) 460 | 461 | sigmahpone = pair.gear_one.material.sh_limit * znt_one * zl * zv * zr * zw_one * zx / pair.sh_min 462 | sigmahptwo = pair.gear_two.material.sh_limit * znt_two * zl * zv * zr * zw_two * zx / pair.sh_min 463 | 464 | shone = znt_one * zl * zv * zr * zw_one * zx / sigmahone 465 | shtwo = znt_two * zl * zv * zr * zw_two * zx / sigmahtwo 466 | 467 | return { 468 | 'sigmaH': sigmahone, 469 | 'sigmaHTwo': sigmahtwo, 470 | 'sigmaHPOne': sigmahpone, 471 | 'sigmaHPTwo': sigmahptwo, 472 | 'zh': zh, 473 | 'zb': zb, 474 | 'zd': zd, 475 | 'ze': ze, 476 | 'z_epsilon': z_epsilon, 477 | 'z_beta': z_beta, 478 | 'znt_one': znt_one, 479 | 'znt_two': znt_two, 480 | 'zl': zl, 481 | 'zv': zv, 482 | 'zr': zr, 483 | 'zw_one': zw_one, 484 | 'zw_two': zw_two, 485 | 'zx': zx, 486 | 'kv': kv, 487 | 'khb': khb, 488 | 'kha': kha 489 | } 490 | 491 | @staticmethod 492 | def __zh(pair): 493 | beta_b = radians(pair.gear_one.beta_b) 494 | alpha_wt = radians(pair.alpha_wt) 495 | alpha_t = radians(pair.gear_one.alpha_t) 496 | return sqrt((2. * cos(beta_b) * cos(alpha_wt)) / (cos(alpha_t) ** 2. * sin(alpha_wt))) 497 | 498 | @staticmethod 499 | def __zb(pair): 500 | da_one = pair.gear_one.da 501 | db_one = pair.gear_one.db 502 | z_one = pair.gear_one.z 503 | beta = pair.gear_one.beta 504 | da_two = pair.gear_two.da 505 | db_two = pair.gear_two.db 506 | z_two = pair.gear_two.z 507 | alpha_wt = radians(pair.alpha_wt) 508 | epsilon_alpha = pair.epsilon_alpha 509 | epsilon_beta = pair.epsilon_beta 510 | zb = 0 511 | zd = 0 512 | 513 | m1 = tan(alpha_wt) / sqrt((sqrt((da_one ** 2 / db_one ** 2) - 1) - (2 * pi) / z_one) * ( 514 | sqrt((da_two ** 2 / db_two ** 2) - 1) - (epsilon_alpha - 1) * (2 * pi) / z_two)) 515 | m2 = tan(alpha_wt) / sqrt((sqrt((da_two ** 2 / db_two ** 2) - 1) - (2 * pi) / z_two) * ( 516 | sqrt((da_one ** 2 / db_one ** 2) - 1) - (epsilon_alpha - 1) * (2 * pi) / z_one)) 517 | 518 | if beta is 0: 519 | if epsilon_alpha > 1: 520 | if m1 <= 1: 521 | zb = 1 522 | else: 523 | zb = m1 524 | if m2 <= 1: 525 | zd = 1 526 | else: 527 | zd = m2 528 | if (z_one / z_two) > 1.5: 529 | zd = 1 530 | else: 531 | if epsilon_alpha > 1 and epsilon_beta >= 1: 532 | zb = 1 533 | zd = zb 534 | elif epsilon_alpha > 1 > epsilon_beta: 535 | if m1 - epsilon_beta * (m1 - 1) < 1: 536 | zb = 1 537 | else: 538 | zb = m1 - epsilon_beta * (m1 - 1) 539 | if m2 - epsilon_beta * (m2 - 1) < 1: 540 | zd = 1 541 | else: 542 | zd = m2 - epsilon_beta * (m2 - 1) 543 | 544 | return zb, zd 545 | 546 | @staticmethod 547 | def __ze(pair): 548 | e_one = pair.gear_one.material.e 549 | e_two = pair.gear_two.material.e 550 | poisson_one = pair.gear_one.material.poisson 551 | poisson_two = pair.gear_two.material.poisson 552 | 553 | if e_one == e_two: 554 | return sqrt(e_one / (2 * pi * (1 - poisson_one ** 2))) 555 | else: 556 | return sqrt(1 / (pi * (((1 - poisson_one) / e_one) + (1 - poisson_two) / e_two))) 557 | 558 | @staticmethod 559 | def __z_epsilon(pair): 560 | epsilon_alpha = pair.epsilon_alpha 561 | epsilon_beta = pair.epsilon_beta 562 | 563 | if epsilon_beta is 0: 564 | return sqrt((4 - epsilon_alpha) / 3) 565 | elif 1 > epsilon_beta > 0: 566 | return sqrt(((4 - epsilon_alpha) / 3) * (1 - epsilon_beta) + (epsilon_beta / epsilon_alpha)) 567 | else: 568 | return sqrt(1 / epsilon_alpha) 569 | 570 | def __znt(self, material, rpm): 571 | 572 | nl = self.transmission.l * 60 * rpm 573 | 574 | if material == 'NV(nitrocar)': 575 | y = [1.1, 1.1, 1, 0.85] 576 | x = [1e4, 1e5, 2e6, 1e10] 577 | elif material == 'GG' or material == 'GGG(ferr)' or material == 'NT' or material == 'NV(nitr)': 578 | y = [1.3, 1.3, 1, 0.85] 579 | x = [1e4, 1e5, 2e6, 1e10] 580 | else: 581 | y = [1.6, 1.6, 1, 0.85] 582 | x = [1e4, 1e5, 5e7, 1e10] 583 | 584 | return 10**interp(log10(nl), log10(x), log10(y)) 585 | 586 | @staticmethod 587 | def __r_red(pair): 588 | db_one = pair.gear_one.db 589 | db_two = pair.gear_two.db 590 | alpha_wt = radians(pair.alpha_wt) 591 | r1 = 0.5 * db_one * tan(alpha_wt) 592 | r2 = 0.5 * db_two * tan(alpha_wt) 593 | 594 | return (r1 * r2) / (r1 + r2) 595 | 596 | @staticmethod 597 | def __czl(pair): 598 | sh_limit_1 = pair.gear_one.material.sh_limit 599 | sh_limit_2 = pair.gear_two.material.sh_limit 600 | if sh_limit_1 < sh_limit_2: 601 | sh_min = sh_limit_1 602 | else: 603 | sh_min = sh_limit_2 604 | 605 | if 850 <= sh_min <= 1200: 606 | czl = (sh_min / 437.5) + 0.6357 607 | elif 850 > sh_min: 608 | czl = 0.83 609 | else: 610 | czl = 0.91 611 | return czl 612 | 613 | def __zl(self, pair): 614 | czl = self.__czl(pair) 615 | v40 = self.transmission.v40 616 | return czl + 4.0 * (1.0 - czl) / (1.2 + 134.0 / v40) ** 2 617 | 618 | def __zv(self, pair): 619 | v = pair.v 620 | czv = self.__czl(pair) + 0.02 621 | return czv + (2 * (1 - czv) / sqrt(0.8 + 32 / v)) 622 | 623 | def __zr(self, pair): 624 | rz_one = pair.gear_one.rz 625 | rz_two = pair.gear_two.rz 626 | sh_limit_1 = pair.gear_one.material.sh_limit 627 | sh_limit_2 = pair.gear_one.material.sh_limit 628 | czr = 0 629 | 630 | if sh_limit_1 < sh_limit_2: 631 | sh_min = sh_limit_1 632 | else: 633 | sh_min = sh_limit_2 634 | 635 | rz = (rz_one + rz_two) / 2. 636 | 637 | rz10 = rz * ((10.0 / self.__r_red(pair)) ** (1. / 3.)) 638 | 639 | if 850 <= sh_min <= 1200: 640 | czr = 0.32 - 0.0002 * sh_min 641 | if 850 > sh_min: 642 | czr = 0.15 643 | if 1200 < sh_min: 644 | czr = 0.08 645 | 646 | return (3.0 / rz10) ** czr 647 | 648 | def __zw(self, pair): 649 | rz_one = pair.gear_one.rz 650 | rz_two = pair.gear_two.rz 651 | hb_1 = pair.gear_one.material.brinell 652 | hb_2 = pair.gear_two.material.brinell 653 | v40 = self.transmission.v40 654 | v = pair.v 655 | 656 | rzh = ((rz_one * (10 / self.__r_red(pair)) ** 0.33) * (rz_one / rz_two) ** 0.66) / ((v40 * v / 1500) ** 0.33) 657 | 658 | if rzh > 16: 659 | rzh = 16 660 | if rzh < 3: 661 | rzh = 3 662 | 663 | if hb_1 < 130: 664 | zw_1 = 1.2 * (3 / rzh) ** 0.15 665 | elif hb_1 > 470: 666 | zw_1 = (3 / rzh) ** 0.15 667 | else: 668 | zw_1 = (1.2 - (hb_1 - 130) / 1700) * (3 / rzh) ** 0.15 669 | 670 | if hb_2 < 130: 671 | zw_2 = 1.2 * (3 / rzh) ** 0.15 672 | elif hb_2 > 470: 673 | zw_2 = (3 / rzh) ** 0.15 674 | else: 675 | zw_2 = (1.2 - (hb_2 - 130) / 1700) * (3 / rzh) ** 0.15 676 | 677 | return zw_1, zw_2 678 | 679 | 680 | # iso 6336-3 681 | class Bending(object): 682 | """ 683 | 684 | :param transmission: 685 | """ 686 | 687 | def __init__(self, transmission): 688 | self.transmission = transmission 689 | 690 | @property 691 | def calculate(self): 692 | """ 693 | 694 | 695 | :return: 696 | """ 697 | pair = self.transmission 698 | # ka = pair.ka 699 | sfmin = pair.sf_min 700 | gear_one = pair.gear_one 701 | gear_two = pair.gear_two 702 | pair.gear_one.b = gear_one.b 703 | btwo = gear_two.b 704 | m = gear_one.m 705 | sigmaflimitone = gear_one.material.sf_limit 706 | sigmaflimittwo = gear_two.material.sf_limit 707 | 708 | yst = self.__yst() 709 | yxone = self.__yx(gear_one) 710 | yxtwo = self.__yx(gear_two) 711 | yfone, yftwo = self.__yf(pair) 712 | ysone, ystwo = self.__ys(pair) 713 | ybeta = self.__ybeta(pair) 714 | ybone = self.__yb(gear_one) 715 | ybtwo = self.__yb(gear_two) 716 | 717 | ydeltaone, ydeltatwo = self.__ydelta(pair) 718 | ydt = self.__ydt(pair) 719 | yntone, ynttwo = self.__ynt(pair) 720 | yrelone = self.__yrel(gear_one) 721 | yreltwo = self.__yrel(gear_two) 722 | 723 | kv = __kv__(pair) 724 | kfa = __kfa__(pair) 725 | kfb = __kfb__(pair) 726 | 727 | sigmaf0one = pair.ft / (pair.gear_one.b * m) * yfone * ysone * ybeta * ybone * ydt 728 | sigmaf0two = pair.ft / (btwo * m) * yftwo * ystwo * ybeta * ybtwo * ydt 729 | 730 | sigmafone = sigmaf0one * pair.ka * kv * kfb * kfa 731 | sigmaftwo = sigmaf0two * pair.ka * kv * kfb * kfa 732 | 733 | sigmafpone = sigmaflimitone * yst * yntone * ydeltaone * yrelone * yxone / sfmin 734 | sigmafptwo = sigmaflimittwo * yst * ynttwo * ydeltatwo * yreltwo * yxtwo / sfmin 735 | 736 | sfone = sigmaflimitone * ysone * yntone * ydeltaone * yrelone / sigmafone 737 | sftwo = sigmaflimittwo * ystwo * ynttwo * ydeltatwo * yreltwo / sigmaftwo 738 | 739 | return { 740 | 'sigmafone': sigmafone, 741 | 'sigmaftwo': sigmaftwo, 742 | 'sigmafpone': sigmafpone, 743 | 'sigmafptwo': sigmafptwo, 744 | 'yst': yst, 745 | 'yxone': yxone, 746 | 'yxtwo': yxtwo, 747 | 'yfone': yfone, 748 | 'yftwo': yftwo, 749 | 'ysone': ysone, 750 | 'ystwo': ystwo, 751 | 'ybeta': ybeta, 752 | 'ybone': ybone, 753 | 'ybtwo': ybtwo, 754 | 'ydeltaone': ydeltaone, 755 | 'ydeltatwo': ydeltatwo, 756 | 'ydt': ydt, 757 | 'yntone': yntone, 758 | 'ynttwo': ynttwo, 759 | 'yrelone': yrelone, 760 | 'yreltwo': yreltwo, 761 | 'kv': kv, 762 | 'kfa': kfa, 763 | 'kfb': kfb 764 | } 765 | 766 | @staticmethod 767 | def __yrel(gear): 768 | rz = gear.rz 769 | material = gear.material.classification 770 | if rz < 1: 771 | if material == 'V' or material == 'GGG(perl)' or material == 'Eh' or material == 'IF' or material == 'GTS': 772 | return 1.12 773 | elif material == 'St': 774 | return 1.07 775 | elif material == 'GG' or material == 'GGG(ferr)' or material == 'NT' or material == 'NV(nitrocar)' or material == 'NV(nitr)': 776 | return 1.025 777 | else: 778 | if material == 'V' or material == 'GGG(perl)' or material == 'Eh' or material == 'IF' or material == 'GTS': 779 | return 1.674 - 0.529 * (rz + 1) ** 0.1 780 | elif material == 'St': 781 | return 5.306 - 4.203 * (rz + 1) ** 0.01 782 | elif material == 'GG' or material == 'GGG(ferr)' or material == 'NT' or material == 'NV(nitrocar)' or material == 'NV(nitr)': 783 | return 4.299 - 3.259 * (rz + 1) ** 0.0058 784 | 785 | @staticmethod 786 | def __ynt(pair): 787 | """ 788 | 789 | :rtype : object 790 | """ 791 | materialone = pair.gear_one.material.classification 792 | materialtwo = pair.gear_two.material.classification 793 | rpmone = pair.rpm_in 794 | rpmtwo = pair.rpm_out 795 | l = pair.l 796 | y = 0 797 | 798 | nlone = l * 60 * rpmone 799 | nltwo = l * 60 * rpmtwo 800 | 801 | result = [] 802 | 803 | for material, nl in [materialone, nlone], [materialtwo, nltwo]: 804 | 805 | if material == 'V' or material == 'GGG(perl)' or material == 'GTS' or material == 'St': 806 | y = [2.5, 2.5, 1, 0.85] 807 | x = [1e2, 1e4, 3e6, 1e10] 808 | 809 | elif material == 'Eh' or material == 'IF': 810 | y = [2.5, 2.5, 1, 0.85] 811 | x = [1e2, 1e3, 3e6, 1e10] 812 | 813 | elif material == 'GG' or material == 'GGG(ferr)' or material == 'NT' or material == 'NV(nitr)': 814 | y = [1.6, 1.6, 1, 0.85] 815 | x = [1e2, 1e3, 3e6, 1e10] 816 | 817 | elif material == 'NV(nitrocar)': 818 | y = [1.1, 1.1, 1, 0.85] 819 | x = [1e2, 1e3, 3e6, 1e10] 820 | 821 | result.append(10**interp(log10(nl), log10(x), log10(y))) 822 | 823 | return result 824 | 825 | def __ydelta(self, pair): 826 | gear_one = pair.gear_one 827 | gear_two = pair.gear_two 828 | 829 | alphafenone, alphafentwo, sfnone, sfntwo, rhofone, rhoftwo, hfeone, hfetwo = self.__aux(pair) 830 | rhoone = self.__rho(gear_one) 831 | rhotwo = self.__rho(gear_two) 832 | 833 | qsone = sfnone / (2 * rhofone) 834 | qstwo = sfntwo / (2 * rhoftwo) 835 | xpone = (1 / 5.) * (1 + 2 * qsone) 836 | xptwo = (1 / 5.) * (1 + 2 * qstwo) 837 | xt = (1 / 5.) * (1 + 2 * 2.5) 838 | 839 | ydeltaone = (1 + sqrt(rhoone * xpone)) / (1 + sqrt(rhoone * xt)) 840 | ydeltatwo = (1 + sqrt(rhotwo * xptwo)) / (1 + sqrt(rhotwo * xt)) 841 | 842 | return ydeltaone, ydeltatwo 843 | 844 | @staticmethod 845 | def __rho(gear): 846 | sigmaflimit = gear.material.sf_limit 847 | material = gear.material.classification 848 | rho = 0 849 | 850 | if material == 'GG' or material == 'GGG(ferr)': 851 | if sigmaflimit <= 150: 852 | rho = 0.3124 853 | elif sigmaflimit >= 300: 854 | rho = 0.3095 855 | else: 856 | rho = interp(sigmaflimit, [150, 300], [0.3124, 0.3095]) 857 | 858 | elif material == 'GGG(perl)' or material == 'V' or material == 'GTS': 859 | if sigmaflimit <= 500: 860 | rho = 0.0281 861 | elif sigmaflimit >= 1000: 862 | rho = 0.0014 863 | else: 864 | rho = interp(sigmaflimit, [500, 600, 800, 1000], [0.0281, 0.0194, 0.0064, 0.0014]) 865 | 866 | elif material == 'NT' or material == 'NV(nitrocar)' or material == 'NV(nitr)': 867 | rho = 0.1005 868 | 869 | elif material == 'St': 870 | if sigmaflimit <= 300: 871 | rho = 0.0833 872 | elif sigmaflimit >= 400: 873 | rho = 0.0445 874 | else: 875 | rho = interp(sigmaflimit, [300, 400], [0.0833, 0.445]) 876 | 877 | elif material == 'Eh' or material == 'IF': 878 | rho = 0.003 879 | 880 | return rho 881 | 882 | @staticmethod 883 | def __ydt(pair): 884 | epsilonalpha = pair.epsilon_alpha 885 | betab = radians(pair.gear_one.beta_b) 886 | gprecision = pair.gear_one.precision_grade 887 | epsilonalphan = epsilonalpha / (cos(betab) ** 2) 888 | 889 | if epsilonalphan <= 2.05 or epsilonalphan > 2.05 and gprecision > 4: 890 | return 1 891 | elif 2.05 < epsilonalphan <= 2.5 and gprecision <= 4: 892 | return -0.666 * epsilonalphan + 2.366 893 | elif epsilonalphan > 2.5 and gprecision <= 4: 894 | return 0.9 895 | 896 | @staticmethod 897 | def __yb(gear): 898 | sr = gear.sr 899 | h = gear.h 900 | 901 | if sr is None: 902 | srh = 1.21 903 | else: 904 | srh = sr / h 905 | 906 | if srh >= 1.2: 907 | return 1 908 | elif 0.5 < srh < 1.2: 909 | return 1.6 * log(2.242 * 1 / srh) 910 | else: 911 | raise Exception('External gears require: sr/ht > 0.5') 912 | 913 | 914 | @staticmethod 915 | def __ybeta(pair): 916 | epsilonbeta = pair.epsilon_beta 917 | beta = pair.gear_one.beta 918 | 919 | if epsilonbeta > 1: 920 | eb = 1 921 | else: 922 | eb = epsilonbeta 923 | 924 | if beta > 30: 925 | be = 30 926 | else: 927 | be = beta 928 | 929 | return 1 - eb * (be / 120) 930 | 931 | def __ys(self, pair): 932 | alphafenone, alphafentwo, sfnone, sfntwo, rhofone, rhoftwo, hfeone, hfetwo = self.__aux(pair) 933 | lone = sfnone / hfeone 934 | ltwo = sfntwo / hfetwo 935 | qsone = sfnone / (2 * rhofone) 936 | qstwo = sfntwo / (2 * rhoftwo) 937 | ysone = (1.2 + 0.13 * lone) * (qsone ** (1 / (1.21 + (2.3 / lone)))) 938 | ystwo = (1.2 + 0.13 * ltwo) * (qstwo ** (1 / (1.21 + (2.3 / ltwo)))) 939 | 940 | return ysone, ystwo 941 | 942 | @staticmethod 943 | def __aux(pair): 944 | m = pair.gear_one.m 945 | epsilonalpha = pair.epsilon_alpha 946 | znone = pair.gear_one.zn 947 | zntwo = pair.gear_two.zn 948 | ztwo = pair.gear_two.z 949 | xone = pair.gear_one.x 950 | xtwo = pair.gear_two.x 951 | zone = pair.gear_one.z 952 | beta = radians(pair.gear_one.beta) 953 | betab = radians(pair.gear_one.beta_b) 954 | alpha = radians(pair.gear_one.alpha) 955 | hfp = pair.gear_one.profile.hf_p * m 956 | hap = pair.gear_one.profile.ha_p 957 | rhofp = pair.gear_one.profile.rho_fp * m 958 | thetaone = 0 959 | thetatwo = 0 960 | 961 | e = ((pi / 4) * m) - hfp * tan(alpha) - (1 - sin(alpha)) * (rhofp / cos(alpha)) 962 | gone = (rhofp / m) - (hfp / m) + xone 963 | gtwo = (rhofp / m) - (hfp / m) + xtwo 964 | hone = (2 / znone) * ((pi / 2) - (e / m)) - (pi / 3) 965 | htwo = (2 / zntwo) * ((pi / 2) - (e / m)) - (pi / 3) 966 | 967 | thetatone = pi / 6 968 | thetattwo = pi / 6 969 | for i in range(1, 10): 970 | thetaone = ((2 * gone) / znone) * tan(thetatone) - hone 971 | thetatwo = ((2 * gtwo) / zntwo) * tan(thetattwo) - htwo 972 | thetatone = thetaone 973 | thetattwo = thetatwo 974 | 975 | pair.gear_one.d = m * zone / cos(beta) 976 | dtwo = m * ztwo / cos(beta) 977 | daone = m * (zone / cos(beta) + 2. * (hap + xone)) 978 | datwo = m * (ztwo / cos(beta) + 2. * (hap + xtwo)) 979 | 980 | epsilonalphan = epsilonalpha / (cos(betab) ** 2) 981 | dnone = pair.gear_one.d / (cos(betab) ** 2) 982 | dntwo = dtwo / (cos(betab) ** 2) 983 | dbnone = dnone * cos(alpha) 984 | dbntwo = dntwo * cos(alpha) 985 | danone = dnone + daone - pair.gear_one.d 986 | dantwo = dntwo + datwo - dtwo 987 | denone = 2. * sqrt((sqrt((danone / 2.) ** 2 - (dbnone / 2.) ** 2) - ( 988 | (pi * pair.gear_one.d * cos(beta) * cos(alpha)) / zone) * (epsilonalphan - 1)) ** 2 + (dbnone / 2) ** 2) 989 | dentwo = 2. * sqrt((sqrt((dantwo / 2.) ** 2 - (dbntwo / 2.) ** 2) - ( 990 | (pi * dtwo * cos(beta) * cos(alpha)) / ztwo) * (epsilonalphan - 1)) ** 2 + (dbntwo / 2) ** 2) 991 | alphaenone = acos(dbnone / denone) 992 | alphaentwo = acos(dbntwo / dentwo) 993 | gamaeone = ((0.5 * pi + 2. * tan(alpha) * xone) / znone) + degrees(involute(alpha)) - degrees(involute( 994 | alphaenone)) 995 | gamaetwo = ((0.5 * pi + 2. * tan(alpha) * xtwo) / zntwo) + degrees(involute(alpha)) - degrees(involute( 996 | alphaentwo)) 997 | 998 | alphafenone = alphaenone - gamaeone 999 | alphafentwo = alphaentwo - gamaetwo 1000 | 1001 | sfnone = m * (znone * sin((pi / 3) - thetaone) + sqrt(3) * ((gone / cos(thetaone)) - (rhofp / m))) 1002 | sfntwo = m * (zntwo * sin((pi / 3) - thetatwo) + sqrt(3) * ((gtwo / cos(thetatwo)) - (rhofp / m))) 1003 | 1004 | rhofone = m * ( 1005 | rhofp / m + ((2 * gone ** 2) / (cos(thetaone) * (znone * cos(thetaone) ** 2 - 2 * gone)))) 1006 | rhoftwo = m * ( 1007 | rhofp / m + ((2 * gtwo ** 2) / (cos(thetatwo) * (zntwo * cos(thetatwo) ** 2 - 2 * gtwo)))) 1008 | 1009 | hfeone = 0.5 * m * ( 1010 | (cos(gamaeone) - sin(gamaeone) * tan(alphafenone)) * denone / m - znone * cos(pi / 3 - thetaone) - ( 1011 | gone / cos(thetaone) - rhofp / m)) 1012 | hfetwo = 0.5 * m * ( 1013 | (cos(gamaetwo) - sin(gamaetwo) * tan(alphafentwo)) * dentwo / m - zntwo * cos(pi / 3 - thetatwo) - ( 1014 | gtwo / cos(thetatwo) - rhofp / m)) 1015 | 1016 | return alphafenone, alphafentwo, sfnone, sfntwo, rhofone, rhoftwo, hfeone, hfetwo 1017 | 1018 | def __yf(self, pair): 1019 | alpha = radians(pair.gear_one.alpha) 1020 | alphafenone, alphafentwo, sfnone, sfntwo, rhofone, rhoftwo, hfeone, hfetwo = self.__aux(pair) 1021 | m = pair.gear_one.m 1022 | 1023 | yfone = ((6 * hfeone / m) * cos(alphafenone)) / (((sfnone / m) ** 2) * cos(alpha)) 1024 | yftwo = ((6 * hfetwo / m) * cos(alphafentwo)) / (((sfntwo / m) ** 2) * cos(alpha)) 1025 | 1026 | return yfone, yftwo 1027 | 1028 | @staticmethod 1029 | def __yx(gear): 1030 | material = gear.material.classification 1031 | m = gear.m 1032 | x = 0 1033 | y = 0 1034 | 1035 | if material == 'St' or material == 'V' or material == 'GGG(perl)' or material == 'GTS': 1036 | y = [1, 1, 0.85, 0.85] 1037 | x = [0, 5, 30, 60] 1038 | elif material == 'GG' or material == 'GGG(ferr)': 1039 | y = [1, 1, 0.85, 0.7, 0.7] 1040 | x = [0, 5, 15, 25, 60] 1041 | elif material == 'NV(nitrocar)' or material == 'NT' or material == 'NV(nitr)' or material == 'Eh' or material == 'IF': 1042 | y = [1, 1, 0.95, 0.9, 0.85, 0.8, 0.8] 1043 | x = [0, 5, 10, 15, 20, 25, 60] 1044 | 1045 | return interp(m, x, y) 1046 | 1047 | @staticmethod 1048 | def __yst(): 1049 | return 2 1050 | -------------------------------------------------------------------------------- /gearbox/transmission/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/efirvida/python-gearbox/2a41b4d56720ffc33e272bc2c8a8c09bd97252fe/gearbox/transmission/__init__.py -------------------------------------------------------------------------------- /gearbox/transmission/gears.py: -------------------------------------------------------------------------------- 1 | from math import pi, atan, tan, radians, cos, sin, degrees, sqrt, floor, ceil 2 | 3 | from gearbox.libs.maths import involute, arcinvolute 4 | 5 | 6 | class Tool(object): 7 | """ 8 | 9 | :param ha_p: 10 | :param hf_p: 11 | :param rho_fp: 12 | :param x: 13 | :param rho_ao: 14 | :param delta_ao: 15 | :param nc: 16 | """ 17 | 18 | def __init__(self, ha_p, hf_p, rho_fp, x, rho_ao, delta_ao, nc, c=0.25): 19 | self.ha_p = ha_p 20 | self.hf_p = hf_p 21 | self.rho_fp = rho_fp 22 | self.c = c 23 | self.nc = nc 24 | self.x = x 25 | self.rho_ao = rho_ao 26 | self.delta_ao = delta_ao 27 | 28 | 29 | class Material(object): 30 | """ 31 | 32 | :param sh_limit: 33 | :param sf_limit: 34 | :param brinell: 35 | :param classification: 36 | :param name: 37 | :param e: 38 | :param poisson: 39 | :param density: 40 | """ 41 | 42 | def __init__(self, sh_limit, sf_limit, brinell, classification, name='', e=206000., poisson=0.3, density=7.83e-6): 43 | self.sh_limit = sh_limit 44 | self.sf_limit = sf_limit 45 | self.classification = classification 46 | self.name = name 47 | self.e = e 48 | self.poisson = poisson 49 | self.density = density 50 | self.brinell = brinell 51 | 52 | 53 | class Lubricant(object): 54 | """ 55 | 56 | :param v40: 57 | :param name: 58 | """ 59 | 60 | def __init__(self, v40, name=''): 61 | self.name = name 62 | self.v40 = v40 63 | 64 | 65 | class Gear(object): 66 | """ 67 | 68 | :param profile: 69 | :param material: 70 | :param z: 71 | :param beta: 72 | :param b: 73 | :param bs: 74 | :param alpha: 75 | :param m: 76 | :param x: 77 | :param sr: 78 | :param rz: 79 | :param precision_grade: 80 | :param shaft_diameter: 81 | :param schema: 82 | :param l: 83 | :param s: 84 | :param backlash: 85 | :param gear_crown: 86 | :param gear_condition: 87 | :param helix_modification: 88 | :param favorable_contact: 89 | """ 90 | 91 | def __init__(self, **kw): 92 | if 'gear' in kw: 93 | self.profile = kw['gear'].profile 94 | self.material = kw['gear'].material 95 | self.z = kw['gear'].z 96 | self.beta = kw['gear'].beta 97 | self.alpha = kw['gear'].alpha 98 | self.m = kw['gear'].m 99 | self.x = kw['gear'].x 100 | self.b = kw['gear'].b 101 | self.bs = kw['gear'].bs 102 | self.sr = kw['gear'].sr 103 | self.rz = kw['gear'].rz 104 | self.precision_grade = kw['gear'].precision_grade 105 | self.shaft_diameter = kw['gear'].shaft_diameter 106 | self.schema = kw['gear'].schema 107 | self.l = kw['gear'].l 108 | self.s = kw['gear'].s 109 | self.backlash = kw['gear'].backlash 110 | 111 | self.gear_crown = kw['gear'].gear_crown 112 | self.helix_modification = kw['gear'].helix_modification 113 | 114 | if kw['gear'].favorable_contact: 115 | self.favorable_contact = 1 116 | else: 117 | self.favorable_contact = 0 118 | 119 | self.gear_condition = kw['gear'].gear_condition 120 | 121 | else: 122 | self.profile = kw['profile'] 123 | self.material = kw['material'] 124 | self.z = kw['z'] 125 | self.beta = kw['beta'] 126 | self.alpha = kw['alpha'] 127 | self.m = kw['m'] 128 | self.x = kw['x'] 129 | self.b = kw['b'] 130 | self.bs = kw['bs'] 131 | self.sr = kw['sr'] 132 | self.rz = kw['rz'] 133 | self.precision_grade = kw['precision_grade'] 134 | self.shaft_diameter = kw['shaft_diameter'] 135 | self.schema = kw['schema'] 136 | self.l = kw['l'] 137 | self.s = kw['s'] 138 | self.backlash = kw['backlash'] 139 | 140 | self.gear_crown = kw['gear_crown'] 141 | self.helix_modification = kw['helix_modification'] 142 | 143 | if kw['favorable_contact']: 144 | self.favorable_contact = 1 145 | else: 146 | self.favorable_contact = 0 147 | 148 | self.gear_condition = kw['gear_condition'] 149 | 150 | self.xmin = (1 - sqrt(self.z * sin(radians(self.alpha)))) / 2 151 | self.alpha_t = degrees(atan(tan(radians(self.alpha)) / cos(radians(self.beta)))) 152 | self.d = self.m * self.z / cos(radians(self.beta)) 153 | self.da = self.m * (self.z / cos(radians(self.beta)) + 2 * (self.profile.ha_p + self.x)) 154 | self.df = self.d - 2 * self.m * (self.profile.ha_p + self.profile.c - self.x) 155 | self.db = self.d * cos(radians(self.alpha_t)) 156 | self.addendum = self.m * (self.profile.ha_p + self.x) 157 | self.dedendum = self.m * (self.profile.hf_p - self.x) 158 | self.h = self.dedendum + self.addendum 159 | self.rho_f = self.profile.rho_fp * self.m 160 | self.mt = self.m / cos(radians(self.beta)) 161 | self.p_b = self.m * cos(radians(self.alpha)) * pi 162 | self.p_n = pi * cos(radians(self.alpha)) 163 | 164 | # FIXME self.sn = ((pi/2) + 2 * 0 *self.m*self.x*tan(self.Alpha)) 165 | self.beta_b = degrees(atan(self.db * tan(radians(self.beta)) / self.d)) 166 | 167 | self.zn = self.z / (cos(radians(self.beta)) * cos(radians(self.beta_b)) ** 2) 168 | 169 | mc = self.__interval_calc([0, 0.5, 2.0, 3.5, 6.0, 25, 40, 70], self.m) 170 | dc = self.__interval_calc([0, 5, 20, 50, 125, 280, 560, 1000, 1600, 2500, 4000, 6000, 8000, 10000], self.d) 171 | bc = self.__interval_calc([0, 4, 10, 20, 40, 80, 160, 250, 400, 650, 1000], self.b) 172 | 173 | f_pt = 0.3 * (mc + 0.4 * sqrt(dc)) + 4. 174 | f_p = 0.3 * mc + 1.25 * sqrt(dc) + 7. 175 | f_a = 3.2 * sqrt(mc) + 0.22 * sqrt(dc) + 0.27 176 | f_beta = 0.1 * sqrt(dc) + 0.63 * sqrt(bc) + 4.2 177 | f_f_alpha = 2.5 * sqrt(mc) + 0.17 * sqrt(dc) + 0.5 178 | f_h_alpha = 2 * sqrt(mc) + 0.14 * sqrt(dc) + 0.5 179 | f_h_beta = 0.07 * sqrt(dc) + 0.45 * sqrt(bc) + 3. 180 | 181 | self.f_pt = self.__q(f_pt, self.precision_grade) 182 | self.f_p = self.__q(f_p, self.precision_grade) 183 | self.f_alpha = self.__q(f_a, self.precision_grade) 184 | self.f_beta = self.__q(f_beta, self.precision_grade) 185 | self.f_f_alpha = self.__q(f_f_alpha, self.precision_grade) 186 | self.f_h_alpha = self.__q(f_h_alpha, self.precision_grade) 187 | self.f_h_beta = self.__q(f_h_beta, self.precision_grade) 188 | self.f_f_beta = self.__q(f_h_beta, self.precision_grade) 189 | self.f_h_beta5 = self.__q(f_h_beta, 5) 190 | 191 | @staticmethod 192 | def __interval_calc(intervals, attr): 193 | for i in range(1, intervals.__len__()): 194 | if intervals[i - 1] <= attr < intervals[i]: 195 | return sqrt(intervals[i] * intervals[i - 1]) 196 | 197 | @staticmethod 198 | def __q(x, qiso): 199 | x *= 2 ** (0.5 * (qiso - 5)) 200 | if x >= 10: 201 | x = round(x) 202 | elif 5 <= x < 10: 203 | if x % 1 <= 0.25 or (0.5 <= x % 1 % 1 <= 0.75): 204 | x = floor(x * 2) * 0.5 205 | else: 206 | x = ceil(x * 2) * 0.5 207 | else: 208 | x = round(x, 1) 209 | return x 210 | 211 | 212 | class Transmission(object): 213 | """ 214 | :param lubricant: 215 | :param rpm_in: the rotation speed of the first gear 216 | :param gear_box_type: used for AGMA calculation 217 | :param p: the transmitted power in kW 218 | :param l: the design life in hours 219 | :param gears: tuple of Gear objects 220 | :param ka: the application factor 221 | :param sf_min: the minimum safety factor for tooth bending 222 | :param sh_min: the minumum safety factor for flank pitting 223 | """ 224 | 225 | def __init__(self, **kw): 226 | 227 | if 'transmission' in kw: 228 | gear_one = Gear(gear=kw['transmission'].gear_one) 229 | gear_two = Gear(gear=kw['transmission'].gear_two) 230 | gears = [gear_one, gear_two] 231 | self.rpm_in = kw['transmission'].rpm_in 232 | self.rpm_out = gear_one.z/gear_two.z*self.rpm_in 233 | self.ka = kw['transmission'].ka 234 | self.sh_min = kw['transmission'].sh_min 235 | self.sf_min = kw['transmission'].sf_min 236 | 237 | self.v40 = kw['transmission'].v40 238 | self.gear_box_type = kw['transmission'].gear_box_type 239 | 240 | self.u = kw['transmission'].rpm_out / kw['transmission'].rpm_in 241 | self.p = kw['transmission'].p 242 | self.l = kw['transmission'].l 243 | else: 244 | gears = kw['gears'] 245 | self.rpm_in = kw['rpm_in'] 246 | self.rpm_out = gears[0].z/gears[1].z*self.rpm_in 247 | self.ka = kw['ka'] 248 | self.sh_min = kw['sh_min'] 249 | self.sf_min = kw['sf_min'] 250 | 251 | self.v40 = kw['lubricant'].v40 252 | self.gear_box_type = kw['gear_box_type'] 253 | 254 | self.u = self.rpm_out / self.rpm_in 255 | self.p = kw['p'] 256 | self.l = kw['l'] 257 | self.pair = self.__calculate(gears[0], gears[1], self.rpm_in, self.rpm_out) 258 | 259 | def __calculate(self, gear_one, gear_two, rpm_in, rpm_out): 260 | if gear_one.m is not gear_two.m: 261 | raise Exception("the modulus of the two gears most be equal") 262 | else: 263 | self.m = gear_one.m 264 | 265 | if gear_one.alpha is not gear_two.alpha: 266 | raise Exception("the pressure angle of the two gears most be equal") 267 | else: 268 | self.alpha = gear_one.alpha 269 | self.alpha_t = gear_one.alpha_t 270 | 271 | self.u_real = gear_two.z / gear_one.z 272 | self.u = rpm_in / rpm_out 273 | self.u_error = abs(1 - (self.u_real / self.u)) * 100 274 | inv = involute(gear_one.alpha_t) + 2 * (gear_one.x + gear_two.x) / (gear_one.z + gear_two.z) * tan( 275 | radians(gear_one.alpha)) 276 | self.alpha_wt = arcinvolute(inv) 277 | self.a = ((gear_one.z + gear_two.z) * gear_one.m) / (2 * cos(radians(gear_one.beta))) 278 | self.aw = self.a * cos(radians(gear_one.alpha)) / cos(radians(self.alpha_wt)) 279 | self.epsilon_alpha = (0.5 * ( 280 | sqrt(gear_one.da ** 2 - gear_one.db ** 2) + sqrt(gear_two.da ** 2 - gear_two.db ** 2)) - self.a * sin( 281 | radians(self.alpha_wt))) / ( 282 | pi * gear_one.m * cos(radians(gear_one.alpha_t)) / (cos(radians(gear_one.beta)))) 283 | self.epsilon_beta = gear_one.b * sin(radians(gear_one.beta)) / (gear_one.m * pi) 284 | self.epsilon_gama = self.epsilon_alpha + self.epsilon_beta 285 | self.v = rpm_in * gear_one.d * pi / 60000 286 | self.ft = 1000. * self.p * 60000 / (pi * gear_one.d * rpm_in) 287 | if self.ka * self.ft / gear_one.b < 100: 288 | self.fmt = 100 289 | else: 290 | self.fmt = self.ka * self.ft / gear_one.b 291 | 292 | # self.xsum = ((gear_one.z + gear_two.z) * (involute(radians(self.alpha_wt))-involute(radians(self.alpha_t))))/(2*tan(radians(self.alpha))) 293 | self.xsum = gear_one.x + gear_two.x 294 | self.gear_one = gear_one 295 | self.gear_two = gear_two 296 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [build_sphinx] 2 | source-dir = gearbox/doc 3 | build-dir = gearbox/_build 4 | 5 | [upload_sphinx] 6 | upload-dir = gearbox/doc/_build/html 7 | 8 | [egg_info] 9 | tag_build = .dev 10 | tag_svn_revision = 0 11 | 12 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | version = '0.1.2.a' 4 | 5 | setup( 6 | name='python-gearbox', 7 | version=version, 8 | author='Eduardo M. Firvida Donestevez', 9 | packages=find_packages(), 10 | include_package_data=True, 11 | author_email='efirvida@gmail.com', 12 | description='Python library for gear transmission design', 13 | install_requires=['numpy>=1.8.0', 'scipy>=0.10.0', 'jinja2>=2.7.0'], 14 | url='https://github.com/efirvida/python-gearbox', 15 | download_url='https://github.com/efirvida/python-gearbox/archive/master.zip', 16 | keywords=['gearbox', 'gear', 'agma', 'iso', 'gear transmission', 'engineering'], 17 | platforms='any', 18 | license='MIT', 19 | zip_safe=False, 20 | classifiers=['Intended Audience :: Developers', 21 | 'Intended Audience :: Manufacturing', 22 | 'Intended Audience :: Science/Research', 23 | 'Natural Language :: English', 24 | 'Programming Language :: Python', 25 | 'Programming Language :: Python :: 2.7', 26 | 'Topic :: Scientific/Engineering', 27 | 'Topic :: Scientific/Engineering :: Human Machine Interfaces', 28 | 'Topic :: Software Development', 29 | 'Topic :: Software Development :: Libraries', 30 | ] 31 | ) --------------------------------------------------------------------------------