├── .gitignore ├── LICENSE ├── README.md ├── config ├── grid_coords.yaml ├── grid_coords_dipole.yaml ├── grid_coords_dipole_valid.yaml ├── grid_coords_gabor_rand.yaml ├── grid_coords_gabor_small.yaml ├── grid_coords_squares.yaml ├── grid_coords_squares_utah.yaml ├── grid_coords_valid.yaml ├── grid_coords_valid_2.yaml ├── grid_coords_valid_3.yaml └── params.yaml ├── dynaphos ├── __init__.py ├── cortex_models.py ├── image_processing.py ├── plotting.py ├── simulator.py └── utils.py ├── examples ├── __init__.py ├── demo_simulator.ipynb ├── demo_webcam.py ├── example_video.mp4 ├── example_video_gaze_contingent_object_grabbing.mp4 ├── example_video_gaze_contingent_walking.mp4 ├── eye_tracked_i1344739819_subject_hp.mp4 ├── eye_tracked_i1344739819_subject_hp_orig.mp4 └── readme.md ├── pyproject.toml ├── requirements.txt ├── setup.py └── test ├── __init__.py ├── benchmark.pkl ├── benchmark.png ├── benchmark.py ├── data ├── Fernandez_2021_fig6A.csv ├── activation.npy ├── coordinates_dipole.npz ├── coordinates_monopole.npz ├── coordinates_wedge-dipole.npz ├── donders.png ├── fernandez_activation_fit.npy ├── fernandez_brightness_fit.npy ├── output.npy ├── phosphene_map.npy ├── phosphenes_donders.npy ├── results_dynamics.pkl ├── sigma.npy ├── stimulus.npy ├── trace.npy ├── valid_electrodes.npy └── z_full_view.npy └── test_all.py /.gitignore: -------------------------------------------------------------------------------- 1 | .ipynb_checkpoints 2 | __pycache__ 3 | 4 | clips/ 5 | **[Aa]rchived 6 | .idea/ 7 | 8 | /dist/ 9 | /dynaphos.egg-info/ 10 | *.mp4 11 | *.avi 12 | /scratch/ 13 | *.pickle 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # About the project 2 | A fully differentiable and biologically plausible simulation of cortical prosthetic vision, which can be used for end-to-end optimization. 3 | 4 | ## Installation 5 | `pip install dynaphos` 6 | 7 | ## Getting Started 8 | - Download the default configuration file (config/params.yaml) from [our repository](https://github.com/neuralcodinglab/dynaphos/) and adjust according to needs. 9 | - Run the `test` suite. 10 | - See the `examples` directory for simple use cases. 11 | 12 | ## Citation 13 | van der Grinten, M., van Steveninck, J. D. R., Lozano, A., Pijnacker, L., Rueckauer, B., Roelfsema, P., Marcel van Gerven, Richard van Wezel, Umut Güçlü & Güçlütürk, Y. (2024). Towards biologically plausible phosphene simulation for the differentiable optimization of visual cortical prostheses. eLife, 13, e85812. [https://doi.org/10.7554/eLife.85812](https://doi.org/10.7554/eLife.85812). 14 | 15 | ## Experiments 16 | For the end-to-end optimization experiments in our publication see [this repository](https://github.com/neuralcodinglab/viseon/tree/dynaphos-paper). The code for the experiments described in our publication (using this simulator) can be found in [this repository](https://github.com/neuralcodinglab/dynaphos-experiments). All other code that was used in our publication can be made available on request. 17 | 18 | ## Contact 19 | Feel free to submit an issue, we're happy to help. 20 | -------------------------------------------------------------------------------- /config/grid_coords_gabor_rand.yaml: -------------------------------------------------------------------------------- 1 | x: [ 6.41 , 14.791, 7.007, 22.26 , 8.291, 14.558, 11.211, 6.375, 2 | 6.542, 6.305, 8.344, 6.866, 14.643, 23.202, 11.439, 8.952, 3 | 6.318, 7.669, 7.42 , 7.331, 9.939, 7.542, 11.093, 6.951, 4 | 14.417, 11.031, 13.24 , 17.014, 9.033, 14.756, 7.671, 20.991, 5 | 9.628, 14.41 , 12.996, 10.432, 22.556, 10.996, 18.598, 18.658, 6 | 21.492, 6.868, 12.74 , 8.871, 13.954, 15.865, 19.115, 19.461, 7 | 10.761, 16.771] 8 | y: [ 8.152, 13.758, 18.18 , 8.972, 21.359, 6.433, 22.803, 11.561, 9 | 17.659, 6.464, 7.881, 13.841, 17.692, 15.068, 9.701, 10.122, 10 | 9.534, 6.591, 15.323, 12.834, 23.457, 7.257, 14.056, 9.216, 11 | 10.548, 19.329, 11.045, 15.187, 20.45 , 22.486, 21.444, 21.898, 12 | 11.422, 18.84 , 8.94 , 16.333, 16.636, 7.699, 10.073, 14.845, 13 | 23.055, 15.687, 16.141, 12.807, 11.27 , 8.267, 6.681, 13.075, 14 | 10.66 , 6.627] 15 | theta: [1.68 , 3.13 , 1.491, 2.564, 1.357, 2.502, 1.871, 2.785, 1.291, 16 | 1.898, 1.979, 1.311, 0.453, 0.294, 0.052, 2.744, 0.743, 0.664, 17 | 2.312, 1.005, 1.59 , 0.511, 3.015, 2.675, 2.714, 1.278, 2.395, 18 | 0.452, 0.027, 0.063, 1.843, 1.431, 1.627, 0.023, 1.328, 2.256, 19 | 1.391, 2.3 , 0.732, 2.555, 1.849, 0.662, 0.744, 1.973, 2.607, 20 | 1.306, 0.811, 2.724, 2.103, 1.408] -------------------------------------------------------------------------------- /config/grid_coords_gabor_small.yaml: -------------------------------------------------------------------------------- 1 | x: [15,15,15, 12,12,12, 18,18,18] 2 | y: [3, 0, -3, 3, 0, -3, 3, 0, -3] 3 | theta: [0, 1.57079633,0, 1.57079633, 0, 1.57079633, 1.57079633, 0, 1.57079633] -------------------------------------------------------------------------------- /config/grid_coords_squares.yaml: -------------------------------------------------------------------------------- 1 | x: 2 | - 35.0 3 | - 35.55555555555556 4 | - 36.111111111111114 5 | - 36.666666666666664 6 | - 37.22222222222222 7 | - 37.77777777777778 8 | - 38.333333333333336 9 | - 38.888888888888886 10 | - 39.44444444444444 11 | - 40.0 12 | - 35.0 13 | - 35.55555555555556 14 | - 36.111111111111114 15 | - 36.666666666666664 16 | - 37.22222222222222 17 | - 37.77777777777778 18 | - 38.333333333333336 19 | - 38.888888888888886 20 | - 39.44444444444444 21 | - 40.0 22 | - 35.0 23 | - 35.55555555555556 24 | - 36.111111111111114 25 | - 36.666666666666664 26 | - 37.22222222222222 27 | - 37.77777777777778 28 | - 38.333333333333336 29 | - 38.888888888888886 30 | - 39.44444444444444 31 | - 40.0 32 | - 35.0 33 | - 35.55555555555556 34 | - 36.111111111111114 35 | - 36.666666666666664 36 | - 37.22222222222222 37 | - 37.77777777777778 38 | - 38.333333333333336 39 | - 38.888888888888886 40 | - 39.44444444444444 41 | - 40.0 42 | - 35.0 43 | - 35.55555555555556 44 | - 36.111111111111114 45 | - 36.666666666666664 46 | - 37.22222222222222 47 | - 37.77777777777778 48 | - 38.333333333333336 49 | - 38.888888888888886 50 | - 39.44444444444444 51 | - 40.0 52 | - 35.0 53 | - 35.55555555555556 54 | - 36.111111111111114 55 | - 36.666666666666664 56 | - 37.22222222222222 57 | - 37.77777777777778 58 | - 38.333333333333336 59 | - 38.888888888888886 60 | - 39.44444444444444 61 | - 40.0 62 | - 35.0 63 | - 35.55555555555556 64 | - 36.111111111111114 65 | - 36.666666666666664 66 | - 37.22222222222222 67 | - 37.77777777777778 68 | - 38.333333333333336 69 | - 38.888888888888886 70 | - 39.44444444444444 71 | - 40.0 72 | - 35.0 73 | - 35.55555555555556 74 | - 36.111111111111114 75 | - 36.666666666666664 76 | - 37.22222222222222 77 | - 37.77777777777778 78 | - 38.333333333333336 79 | - 38.888888888888886 80 | - 39.44444444444444 81 | - 40.0 82 | - 35.0 83 | - 35.55555555555556 84 | - 36.111111111111114 85 | - 36.666666666666664 86 | - 37.22222222222222 87 | - 37.77777777777778 88 | - 38.333333333333336 89 | - 38.888888888888886 90 | - 39.44444444444444 91 | - 40.0 92 | - 35.0 93 | - 35.55555555555556 94 | - 36.111111111111114 95 | - 36.666666666666664 96 | - 37.22222222222222 97 | - 37.77777777777778 98 | - 38.333333333333336 99 | - 38.888888888888886 100 | - 39.44444444444444 101 | - 40.0 102 | - 2.0 103 | - 2.5555555555555554 104 | - 3.111111111111111 105 | - 3.666666666666667 106 | - 4.222222222222222 107 | - 4.777777777777778 108 | - 5.333333333333334 109 | - 5.888888888888889 110 | - 6.444444444444445 111 | - 7.0 112 | - 2.0 113 | - 2.5555555555555554 114 | - 3.111111111111111 115 | - 3.666666666666667 116 | - 4.222222222222222 117 | - 4.777777777777778 118 | - 5.333333333333334 119 | - 5.888888888888889 120 | - 6.444444444444445 121 | - 7.0 122 | - 2.0 123 | - 2.5555555555555554 124 | - 3.111111111111111 125 | - 3.666666666666667 126 | - 4.222222222222222 127 | - 4.777777777777778 128 | - 5.333333333333334 129 | - 5.888888888888889 130 | - 6.444444444444445 131 | - 7.0 132 | - 2.0 133 | - 2.5555555555555554 134 | - 3.111111111111111 135 | - 3.666666666666667 136 | - 4.222222222222222 137 | - 4.777777777777778 138 | - 5.333333333333334 139 | - 5.888888888888889 140 | - 6.444444444444445 141 | - 7.0 142 | - 2.0 143 | - 2.5555555555555554 144 | - 3.111111111111111 145 | - 3.666666666666667 146 | - 4.222222222222222 147 | - 4.777777777777778 148 | - 5.333333333333334 149 | - 5.888888888888889 150 | - 6.444444444444445 151 | - 7.0 152 | - 2.0 153 | - 2.5555555555555554 154 | - 3.111111111111111 155 | - 3.666666666666667 156 | - 4.222222222222222 157 | - 4.777777777777778 158 | - 5.333333333333334 159 | - 5.888888888888889 160 | - 6.444444444444445 161 | - 7.0 162 | - 2.0 163 | - 2.5555555555555554 164 | - 3.111111111111111 165 | - 3.666666666666667 166 | - 4.222222222222222 167 | - 4.777777777777778 168 | - 5.333333333333334 169 | - 5.888888888888889 170 | - 6.444444444444445 171 | - 7.0 172 | - 2.0 173 | - 2.5555555555555554 174 | - 3.111111111111111 175 | - 3.666666666666667 176 | - 4.222222222222222 177 | - 4.777777777777778 178 | - 5.333333333333334 179 | - 5.888888888888889 180 | - 6.444444444444445 181 | - 7.0 182 | - 2.0 183 | - 2.5555555555555554 184 | - 3.111111111111111 185 | - 3.666666666666667 186 | - 4.222222222222222 187 | - 4.777777777777778 188 | - 5.333333333333334 189 | - 5.888888888888889 190 | - 6.444444444444445 191 | - 7.0 192 | - 2.0 193 | - 2.5555555555555554 194 | - 3.111111111111111 195 | - 3.666666666666667 196 | - 4.222222222222222 197 | - 4.777777777777778 198 | - 5.333333333333334 199 | - 5.888888888888889 200 | - 6.444444444444445 201 | - 7.0 202 | - 20.0 203 | - 20.555555555555557 204 | - 21.11111111111111 205 | - 21.666666666666668 206 | - 22.22222222222222 207 | - 22.77777777777778 208 | - 23.333333333333332 209 | - 23.88888888888889 210 | - 24.444444444444443 211 | - 25.0 212 | - 20.0 213 | - 20.555555555555557 214 | - 21.11111111111111 215 | - 21.666666666666668 216 | - 22.22222222222222 217 | - 22.77777777777778 218 | - 23.333333333333332 219 | - 23.88888888888889 220 | - 24.444444444444443 221 | - 25.0 222 | - 20.0 223 | - 20.555555555555557 224 | - 21.11111111111111 225 | - 21.666666666666668 226 | - 22.22222222222222 227 | - 22.77777777777778 228 | - 23.333333333333332 229 | - 23.88888888888889 230 | - 24.444444444444443 231 | - 25.0 232 | - 20.0 233 | - 20.555555555555557 234 | - 21.11111111111111 235 | - 21.666666666666668 236 | - 22.22222222222222 237 | - 22.77777777777778 238 | - 23.333333333333332 239 | - 23.88888888888889 240 | - 24.444444444444443 241 | - 25.0 242 | - 20.0 243 | - 20.555555555555557 244 | - 21.11111111111111 245 | - 21.666666666666668 246 | - 22.22222222222222 247 | - 22.77777777777778 248 | - 23.333333333333332 249 | - 23.88888888888889 250 | - 24.444444444444443 251 | - 25.0 252 | - 20.0 253 | - 20.555555555555557 254 | - 21.11111111111111 255 | - 21.666666666666668 256 | - 22.22222222222222 257 | - 22.77777777777778 258 | - 23.333333333333332 259 | - 23.88888888888889 260 | - 24.444444444444443 261 | - 25.0 262 | - 20.0 263 | - 20.555555555555557 264 | - 21.11111111111111 265 | - 21.666666666666668 266 | - 22.22222222222222 267 | - 22.77777777777778 268 | - 23.333333333333332 269 | - 23.88888888888889 270 | - 24.444444444444443 271 | - 25.0 272 | - 20.0 273 | - 20.555555555555557 274 | - 21.11111111111111 275 | - 21.666666666666668 276 | - 22.22222222222222 277 | - 22.77777777777778 278 | - 23.333333333333332 279 | - 23.88888888888889 280 | - 24.444444444444443 281 | - 25.0 282 | - 20.0 283 | - 20.555555555555557 284 | - 21.11111111111111 285 | - 21.666666666666668 286 | - 22.22222222222222 287 | - 22.77777777777778 288 | - 23.333333333333332 289 | - 23.88888888888889 290 | - 24.444444444444443 291 | - 25.0 292 | - 20.0 293 | - 20.555555555555557 294 | - 21.11111111111111 295 | - 21.666666666666668 296 | - 22.22222222222222 297 | - 22.77777777777778 298 | - 23.333333333333332 299 | - 23.88888888888889 300 | - 24.444444444444443 301 | - 25.0 302 | - 20.0 303 | - 20.555555555555557 304 | - 21.11111111111111 305 | - 21.666666666666668 306 | - 22.22222222222222 307 | - 22.77777777777778 308 | - 23.333333333333332 309 | - 23.88888888888889 310 | - 24.444444444444443 311 | - 25.0 312 | - 20.0 313 | - 20.555555555555557 314 | - 21.11111111111111 315 | - 21.666666666666668 316 | - 22.22222222222222 317 | - 22.77777777777778 318 | - 23.333333333333332 319 | - 23.88888888888889 320 | - 24.444444444444443 321 | - 25.0 322 | - 20.0 323 | - 20.555555555555557 324 | - 21.11111111111111 325 | - 21.666666666666668 326 | - 22.22222222222222 327 | - 22.77777777777778 328 | - 23.333333333333332 329 | - 23.88888888888889 330 | - 24.444444444444443 331 | - 25.0 332 | - 20.0 333 | - 20.555555555555557 334 | - 21.11111111111111 335 | - 21.666666666666668 336 | - 22.22222222222222 337 | - 22.77777777777778 338 | - 23.333333333333332 339 | - 23.88888888888889 340 | - 24.444444444444443 341 | - 25.0 342 | - 20.0 343 | - 20.555555555555557 344 | - 21.11111111111111 345 | - 21.666666666666668 346 | - 22.22222222222222 347 | - 22.77777777777778 348 | - 23.333333333333332 349 | - 23.88888888888889 350 | - 24.444444444444443 351 | - 25.0 352 | - 20.0 353 | - 20.555555555555557 354 | - 21.11111111111111 355 | - 21.666666666666668 356 | - 22.22222222222222 357 | - 22.77777777777778 358 | - 23.333333333333332 359 | - 23.88888888888889 360 | - 24.444444444444443 361 | - 25.0 362 | - 20.0 363 | - 20.555555555555557 364 | - 21.11111111111111 365 | - 21.666666666666668 366 | - 22.22222222222222 367 | - 22.77777777777778 368 | - 23.333333333333332 369 | - 23.88888888888889 370 | - 24.444444444444443 371 | - 25.0 372 | - 20.0 373 | - 20.555555555555557 374 | - 21.11111111111111 375 | - 21.666666666666668 376 | - 22.22222222222222 377 | - 22.77777777777778 378 | - 23.333333333333332 379 | - 23.88888888888889 380 | - 24.444444444444443 381 | - 25.0 382 | - 20.0 383 | - 20.555555555555557 384 | - 21.11111111111111 385 | - 21.666666666666668 386 | - 22.22222222222222 387 | - 22.77777777777778 388 | - 23.333333333333332 389 | - 23.88888888888889 390 | - 24.444444444444443 391 | - 25.0 392 | - 20.0 393 | - 20.555555555555557 394 | - 21.11111111111111 395 | - 21.666666666666668 396 | - 22.22222222222222 397 | - 22.77777777777778 398 | - 23.333333333333332 399 | - 23.88888888888889 400 | - 24.444444444444443 401 | - 25.0 402 | y: 403 | - 1.0 404 | - 1.0 405 | - 1.0 406 | - 1.0 407 | - 1.0 408 | - 1.0 409 | - 1.0 410 | - 1.0 411 | - 1.0 412 | - 1.0 413 | - 1.5555555555555556 414 | - 1.5555555555555556 415 | - 1.5555555555555556 416 | - 1.5555555555555556 417 | - 1.5555555555555556 418 | - 1.5555555555555556 419 | - 1.5555555555555556 420 | - 1.5555555555555556 421 | - 1.5555555555555556 422 | - 1.5555555555555556 423 | - 2.111111111111111 424 | - 2.111111111111111 425 | - 2.111111111111111 426 | - 2.111111111111111 427 | - 2.111111111111111 428 | - 2.111111111111111 429 | - 2.111111111111111 430 | - 2.111111111111111 431 | - 2.111111111111111 432 | - 2.111111111111111 433 | - 2.666666666666667 434 | - 2.666666666666667 435 | - 2.666666666666667 436 | - 2.666666666666667 437 | - 2.666666666666667 438 | - 2.666666666666667 439 | - 2.666666666666667 440 | - 2.666666666666667 441 | - 2.666666666666667 442 | - 2.666666666666667 443 | - 3.2222222222222223 444 | - 3.2222222222222223 445 | - 3.2222222222222223 446 | - 3.2222222222222223 447 | - 3.2222222222222223 448 | - 3.2222222222222223 449 | - 3.2222222222222223 450 | - 3.2222222222222223 451 | - 3.2222222222222223 452 | - 3.2222222222222223 453 | - 3.7777777777777777 454 | - 3.7777777777777777 455 | - 3.7777777777777777 456 | - 3.7777777777777777 457 | - 3.7777777777777777 458 | - 3.7777777777777777 459 | - 3.7777777777777777 460 | - 3.7777777777777777 461 | - 3.7777777777777777 462 | - 3.7777777777777777 463 | - 4.333333333333334 464 | - 4.333333333333334 465 | - 4.333333333333334 466 | - 4.333333333333334 467 | - 4.333333333333334 468 | - 4.333333333333334 469 | - 4.333333333333334 470 | - 4.333333333333334 471 | - 4.333333333333334 472 | - 4.333333333333334 473 | - 4.888888888888889 474 | - 4.888888888888889 475 | - 4.888888888888889 476 | - 4.888888888888889 477 | - 4.888888888888889 478 | - 4.888888888888889 479 | - 4.888888888888889 480 | - 4.888888888888889 481 | - 4.888888888888889 482 | - 4.888888888888889 483 | - 5.444444444444445 484 | - 5.444444444444445 485 | - 5.444444444444445 486 | - 5.444444444444445 487 | - 5.444444444444445 488 | - 5.444444444444445 489 | - 5.444444444444445 490 | - 5.444444444444445 491 | - 5.444444444444445 492 | - 5.444444444444445 493 | - 6.0 494 | - 6.0 495 | - 6.0 496 | - 6.0 497 | - 6.0 498 | - 6.0 499 | - 6.0 500 | - 6.0 501 | - 6.0 502 | - 6.0 503 | - 1.0 504 | - 1.0 505 | - 1.0 506 | - 1.0 507 | - 1.0 508 | - 1.0 509 | - 1.0 510 | - 1.0 511 | - 1.0 512 | - 1.0 513 | - 1.5555555555555556 514 | - 1.5555555555555556 515 | - 1.5555555555555556 516 | - 1.5555555555555556 517 | - 1.5555555555555556 518 | - 1.5555555555555556 519 | - 1.5555555555555556 520 | - 1.5555555555555556 521 | - 1.5555555555555556 522 | - 1.5555555555555556 523 | - 2.111111111111111 524 | - 2.111111111111111 525 | - 2.111111111111111 526 | - 2.111111111111111 527 | - 2.111111111111111 528 | - 2.111111111111111 529 | - 2.111111111111111 530 | - 2.111111111111111 531 | - 2.111111111111111 532 | - 2.111111111111111 533 | - 2.666666666666667 534 | - 2.666666666666667 535 | - 2.666666666666667 536 | - 2.666666666666667 537 | - 2.666666666666667 538 | - 2.666666666666667 539 | - 2.666666666666667 540 | - 2.666666666666667 541 | - 2.666666666666667 542 | - 2.666666666666667 543 | - 3.2222222222222223 544 | - 3.2222222222222223 545 | - 3.2222222222222223 546 | - 3.2222222222222223 547 | - 3.2222222222222223 548 | - 3.2222222222222223 549 | - 3.2222222222222223 550 | - 3.2222222222222223 551 | - 3.2222222222222223 552 | - 3.2222222222222223 553 | - 3.7777777777777777 554 | - 3.7777777777777777 555 | - 3.7777777777777777 556 | - 3.7777777777777777 557 | - 3.7777777777777777 558 | - 3.7777777777777777 559 | - 3.7777777777777777 560 | - 3.7777777777777777 561 | - 3.7777777777777777 562 | - 3.7777777777777777 563 | - 4.333333333333334 564 | - 4.333333333333334 565 | - 4.333333333333334 566 | - 4.333333333333334 567 | - 4.333333333333334 568 | - 4.333333333333334 569 | - 4.333333333333334 570 | - 4.333333333333334 571 | - 4.333333333333334 572 | - 4.333333333333334 573 | - 4.888888888888889 574 | - 4.888888888888889 575 | - 4.888888888888889 576 | - 4.888888888888889 577 | - 4.888888888888889 578 | - 4.888888888888889 579 | - 4.888888888888889 580 | - 4.888888888888889 581 | - 4.888888888888889 582 | - 4.888888888888889 583 | - 5.444444444444445 584 | - 5.444444444444445 585 | - 5.444444444444445 586 | - 5.444444444444445 587 | - 5.444444444444445 588 | - 5.444444444444445 589 | - 5.444444444444445 590 | - 5.444444444444445 591 | - 5.444444444444445 592 | - 5.444444444444445 593 | - 6.0 594 | - 6.0 595 | - 6.0 596 | - 6.0 597 | - 6.0 598 | - 6.0 599 | - 6.0 600 | - 6.0 601 | - 6.0 602 | - 6.0 603 | - 10.0 604 | - 10.0 605 | - 10.0 606 | - 10.0 607 | - 10.0 608 | - 10.0 609 | - 10.0 610 | - 10.0 611 | - 10.0 612 | - 10.0 613 | - 10.555555555555555 614 | - 10.555555555555555 615 | - 10.555555555555555 616 | - 10.555555555555555 617 | - 10.555555555555555 618 | - 10.555555555555555 619 | - 10.555555555555555 620 | - 10.555555555555555 621 | - 10.555555555555555 622 | - 10.555555555555555 623 | - 11.11111111111111 624 | - 11.11111111111111 625 | - 11.11111111111111 626 | - 11.11111111111111 627 | - 11.11111111111111 628 | - 11.11111111111111 629 | - 11.11111111111111 630 | - 11.11111111111111 631 | - 11.11111111111111 632 | - 11.11111111111111 633 | - 11.666666666666666 634 | - 11.666666666666666 635 | - 11.666666666666666 636 | - 11.666666666666666 637 | - 11.666666666666666 638 | - 11.666666666666666 639 | - 11.666666666666666 640 | - 11.666666666666666 641 | - 11.666666666666666 642 | - 11.666666666666666 643 | - 12.222222222222221 644 | - 12.222222222222221 645 | - 12.222222222222221 646 | - 12.222222222222221 647 | - 12.222222222222221 648 | - 12.222222222222221 649 | - 12.222222222222221 650 | - 12.222222222222221 651 | - 12.222222222222221 652 | - 12.222222222222221 653 | - 12.777777777777779 654 | - 12.777777777777779 655 | - 12.777777777777779 656 | - 12.777777777777779 657 | - 12.777777777777779 658 | - 12.777777777777779 659 | - 12.777777777777779 660 | - 12.777777777777779 661 | - 12.777777777777779 662 | - 12.777777777777779 663 | - 13.333333333333334 664 | - 13.333333333333334 665 | - 13.333333333333334 666 | - 13.333333333333334 667 | - 13.333333333333334 668 | - 13.333333333333334 669 | - 13.333333333333334 670 | - 13.333333333333334 671 | - 13.333333333333334 672 | - 13.333333333333334 673 | - 13.88888888888889 674 | - 13.88888888888889 675 | - 13.88888888888889 676 | - 13.88888888888889 677 | - 13.88888888888889 678 | - 13.88888888888889 679 | - 13.88888888888889 680 | - 13.88888888888889 681 | - 13.88888888888889 682 | - 13.88888888888889 683 | - 14.444444444444445 684 | - 14.444444444444445 685 | - 14.444444444444445 686 | - 14.444444444444445 687 | - 14.444444444444445 688 | - 14.444444444444445 689 | - 14.444444444444445 690 | - 14.444444444444445 691 | - 14.444444444444445 692 | - 14.444444444444445 693 | - 15.0 694 | - 15.0 695 | - 15.0 696 | - 15.0 697 | - 15.0 698 | - 15.0 699 | - 15.0 700 | - 15.0 701 | - 15.0 702 | - 15.0 703 | - -10.0 704 | - -10.0 705 | - -10.0 706 | - -10.0 707 | - -10.0 708 | - -10.0 709 | - -10.0 710 | - -10.0 711 | - -10.0 712 | - -10.0 713 | - -10.555555555555555 714 | - -10.555555555555555 715 | - -10.555555555555555 716 | - -10.555555555555555 717 | - -10.555555555555555 718 | - -10.555555555555555 719 | - -10.555555555555555 720 | - -10.555555555555555 721 | - -10.555555555555555 722 | - -10.555555555555555 723 | - -11.11111111111111 724 | - -11.11111111111111 725 | - -11.11111111111111 726 | - -11.11111111111111 727 | - -11.11111111111111 728 | - -11.11111111111111 729 | - -11.11111111111111 730 | - -11.11111111111111 731 | - -11.11111111111111 732 | - -11.11111111111111 733 | - -11.666666666666666 734 | - -11.666666666666666 735 | - -11.666666666666666 736 | - -11.666666666666666 737 | - -11.666666666666666 738 | - -11.666666666666666 739 | - -11.666666666666666 740 | - -11.666666666666666 741 | - -11.666666666666666 742 | - -11.666666666666666 743 | - -12.222222222222221 744 | - -12.222222222222221 745 | - -12.222222222222221 746 | - -12.222222222222221 747 | - -12.222222222222221 748 | - -12.222222222222221 749 | - -12.222222222222221 750 | - -12.222222222222221 751 | - -12.222222222222221 752 | - -12.222222222222221 753 | - -12.777777777777779 754 | - -12.777777777777779 755 | - -12.777777777777779 756 | - -12.777777777777779 757 | - -12.777777777777779 758 | - -12.777777777777779 759 | - -12.777777777777779 760 | - -12.777777777777779 761 | - -12.777777777777779 762 | - -12.777777777777779 763 | - -13.333333333333334 764 | - -13.333333333333334 765 | - -13.333333333333334 766 | - -13.333333333333334 767 | - -13.333333333333334 768 | - -13.333333333333334 769 | - -13.333333333333334 770 | - -13.333333333333334 771 | - -13.333333333333334 772 | - -13.333333333333334 773 | - -13.88888888888889 774 | - -13.88888888888889 775 | - -13.88888888888889 776 | - -13.88888888888889 777 | - -13.88888888888889 778 | - -13.88888888888889 779 | - -13.88888888888889 780 | - -13.88888888888889 781 | - -13.88888888888889 782 | - -13.88888888888889 783 | - -14.444444444444445 784 | - -14.444444444444445 785 | - -14.444444444444445 786 | - -14.444444444444445 787 | - -14.444444444444445 788 | - -14.444444444444445 789 | - -14.444444444444445 790 | - -14.444444444444445 791 | - -14.444444444444445 792 | - -14.444444444444445 793 | - -15.0 794 | - -15.0 795 | - -15.0 796 | - -15.0 797 | - -15.0 798 | - -15.0 799 | - -15.0 800 | - -15.0 801 | - -15.0 802 | - -15.0 803 | -------------------------------------------------------------------------------- /config/grid_coords_squares_utah.yaml: -------------------------------------------------------------------------------- 1 | x: 2 | - 30.0 3 | - 30.0 4 | - 30.0 5 | - 30.0 6 | - 30.0 7 | - 30.0 8 | - 30.0 9 | - 30.0 10 | - 30.0 11 | - 30.0 12 | - 30.4 13 | - 30.4 14 | - 30.4 15 | - 30.4 16 | - 30.4 17 | - 30.4 18 | - 30.4 19 | - 30.4 20 | - 30.4 21 | - 30.4 22 | - 30.8 23 | - 30.8 24 | - 30.8 25 | - 30.8 26 | - 30.8 27 | - 30.8 28 | - 30.8 29 | - 30.8 30 | - 30.8 31 | - 30.8 32 | - 31.2 33 | - 31.2 34 | - 31.2 35 | - 31.2 36 | - 31.2 37 | - 31.2 38 | - 31.2 39 | - 31.2 40 | - 31.2 41 | - 31.2 42 | - 31.6 43 | - 31.6 44 | - 31.6 45 | - 31.6 46 | - 31.6 47 | - 31.6 48 | - 31.6 49 | - 31.6 50 | - 31.6 51 | - 31.6 52 | - 32.0 53 | - 32.0 54 | - 32.0 55 | - 32.0 56 | - 32.0 57 | - 32.0 58 | - 32.0 59 | - 32.0 60 | - 32.0 61 | - 32.0 62 | - 32.4 63 | - 32.4 64 | - 32.4 65 | - 32.4 66 | - 32.4 67 | - 32.4 68 | - 32.4 69 | - 32.4 70 | - 32.4 71 | - 32.4 72 | - 32.8 73 | - 32.8 74 | - 32.8 75 | - 32.8 76 | - 32.8 77 | - 32.8 78 | - 32.8 79 | - 32.8 80 | - 32.8 81 | - 32.8 82 | - 33.2 83 | - 33.2 84 | - 33.2 85 | - 33.2 86 | - 33.2 87 | - 33.2 88 | - 33.2 89 | - 33.2 90 | - 33.2 91 | - 33.2 92 | - 33.6 93 | - 33.6 94 | - 33.6 95 | - 33.6 96 | - 33.6 97 | - 33.6 98 | - 33.6 99 | - 33.6 100 | - 33.6 101 | - 33.6 102 | - 37.0 103 | - 37.0 104 | - 37.0 105 | - 37.0 106 | - 37.0 107 | - 37.0 108 | - 37.0 109 | - 37.0 110 | - 37.0 111 | - 37.0 112 | - 37.4 113 | - 37.4 114 | - 37.4 115 | - 37.4 116 | - 37.4 117 | - 37.4 118 | - 37.4 119 | - 37.4 120 | - 37.4 121 | - 37.4 122 | - 37.8 123 | - 37.8 124 | - 37.8 125 | - 37.8 126 | - 37.8 127 | - 37.8 128 | - 37.8 129 | - 37.8 130 | - 37.8 131 | - 37.8 132 | - 38.2 133 | - 38.2 134 | - 38.2 135 | - 38.2 136 | - 38.2 137 | - 38.2 138 | - 38.2 139 | - 38.2 140 | - 38.2 141 | - 38.2 142 | - 38.6 143 | - 38.6 144 | - 38.6 145 | - 38.6 146 | - 38.6 147 | - 38.6 148 | - 38.6 149 | - 38.6 150 | - 38.6 151 | - 38.6 152 | - 39.0 153 | - 39.0 154 | - 39.0 155 | - 39.0 156 | - 39.0 157 | - 39.0 158 | - 39.0 159 | - 39.0 160 | - 39.0 161 | - 39.0 162 | - 39.4 163 | - 39.4 164 | - 39.4 165 | - 39.4 166 | - 39.4 167 | - 39.4 168 | - 39.4 169 | - 39.4 170 | - 39.4 171 | - 39.4 172 | - 39.8 173 | - 39.8 174 | - 39.8 175 | - 39.8 176 | - 39.8 177 | - 39.8 178 | - 39.8 179 | - 39.8 180 | - 39.8 181 | - 39.8 182 | - 40.2 183 | - 40.2 184 | - 40.2 185 | - 40.2 186 | - 40.2 187 | - 40.2 188 | - 40.2 189 | - 40.2 190 | - 40.2 191 | - 40.2 192 | - 40.6 193 | - 40.6 194 | - 40.6 195 | - 40.6 196 | - 40.6 197 | - 40.6 198 | - 40.6 199 | - 40.6 200 | - 40.6 201 | - 40.6 202 | - 20.0 203 | - 20.0 204 | - 20.0 205 | - 20.0 206 | - 20.0 207 | - 20.0 208 | - 20.0 209 | - 20.0 210 | - 20.0 211 | - 20.0 212 | - 20.4 213 | - 20.4 214 | - 20.4 215 | - 20.4 216 | - 20.4 217 | - 20.4 218 | - 20.4 219 | - 20.4 220 | - 20.4 221 | - 20.4 222 | - 20.8 223 | - 20.8 224 | - 20.8 225 | - 20.8 226 | - 20.8 227 | - 20.8 228 | - 20.8 229 | - 20.8 230 | - 20.8 231 | - 20.8 232 | - 21.2 233 | - 21.2 234 | - 21.2 235 | - 21.2 236 | - 21.2 237 | - 21.2 238 | - 21.2 239 | - 21.2 240 | - 21.2 241 | - 21.2 242 | - 21.6 243 | - 21.6 244 | - 21.6 245 | - 21.6 246 | - 21.6 247 | - 21.6 248 | - 21.6 249 | - 21.6 250 | - 21.6 251 | - 21.6 252 | - 22.0 253 | - 22.0 254 | - 22.0 255 | - 22.0 256 | - 22.0 257 | - 22.0 258 | - 22.0 259 | - 22.0 260 | - 22.0 261 | - 22.0 262 | - 22.4 263 | - 22.4 264 | - 22.4 265 | - 22.4 266 | - 22.4 267 | - 22.4 268 | - 22.4 269 | - 22.4 270 | - 22.4 271 | - 22.4 272 | - 22.8 273 | - 22.8 274 | - 22.8 275 | - 22.8 276 | - 22.8 277 | - 22.8 278 | - 22.8 279 | - 22.8 280 | - 22.8 281 | - 22.8 282 | - 23.2 283 | - 23.2 284 | - 23.2 285 | - 23.2 286 | - 23.2 287 | - 23.2 288 | - 23.2 289 | - 23.2 290 | - 23.2 291 | - 23.2 292 | - 23.6 293 | - 23.6 294 | - 23.6 295 | - 23.6 296 | - 23.6 297 | - 23.6 298 | - 23.6 299 | - 23.6 300 | - 23.6 301 | - 23.6 302 | - 20.0 303 | - 20.0 304 | - 20.0 305 | - 20.0 306 | - 20.0 307 | - 20.0 308 | - 20.0 309 | - 20.0 310 | - 20.0 311 | - 20.0 312 | - 20.4 313 | - 20.4 314 | - 20.4 315 | - 20.4 316 | - 20.4 317 | - 20.4 318 | - 20.4 319 | - 20.4 320 | - 20.4 321 | - 20.4 322 | - 20.8 323 | - 20.8 324 | - 20.8 325 | - 20.8 326 | - 20.8 327 | - 20.8 328 | - 20.8 329 | - 20.8 330 | - 20.8 331 | - 20.8 332 | - 21.2 333 | - 21.2 334 | - 21.2 335 | - 21.2 336 | - 21.2 337 | - 21.2 338 | - 21.2 339 | - 21.2 340 | - 21.2 341 | - 21.2 342 | - 21.6 343 | - 21.6 344 | - 21.6 345 | - 21.6 346 | - 21.6 347 | - 21.6 348 | - 21.6 349 | - 21.6 350 | - 21.6 351 | - 21.6 352 | - 22.0 353 | - 22.0 354 | - 22.0 355 | - 22.0 356 | - 22.0 357 | - 22.0 358 | - 22.0 359 | - 22.0 360 | - 22.0 361 | - 22.0 362 | - 22.4 363 | - 22.4 364 | - 22.4 365 | - 22.4 366 | - 22.4 367 | - 22.4 368 | - 22.4 369 | - 22.4 370 | - 22.4 371 | - 22.4 372 | - 22.8 373 | - 22.8 374 | - 22.8 375 | - 22.8 376 | - 22.8 377 | - 22.8 378 | - 22.8 379 | - 22.8 380 | - 22.8 381 | - 22.8 382 | - 23.2 383 | - 23.2 384 | - 23.2 385 | - 23.2 386 | - 23.2 387 | - 23.2 388 | - 23.2 389 | - 23.2 390 | - 23.2 391 | - 23.2 392 | - 23.6 393 | - 23.6 394 | - 23.6 395 | - 23.6 396 | - 23.6 397 | - 23.6 398 | - 23.6 399 | - 23.6 400 | - 23.6 401 | - 23.6 402 | y: 403 | - 1.0 404 | - 1.4 405 | - 1.8 406 | - 2.2 407 | - 2.6 408 | - 3.0 409 | - 3.4000000000000004 410 | - 3.8000000000000003 411 | - 4.2 412 | - 4.6 413 | - 1.0 414 | - 1.4 415 | - 1.8 416 | - 2.2 417 | - 2.6 418 | - 3.0 419 | - 3.4000000000000004 420 | - 3.8000000000000003 421 | - 4.2 422 | - 4.6 423 | - 1.0 424 | - 1.4 425 | - 1.8 426 | - 2.2 427 | - 2.6 428 | - 3.0 429 | - 3.4000000000000004 430 | - 3.8000000000000003 431 | - 4.2 432 | - 4.6 433 | - 1.0 434 | - 1.4 435 | - 1.8 436 | - 2.2 437 | - 2.6 438 | - 3.0 439 | - 3.4000000000000004 440 | - 3.8000000000000003 441 | - 4.2 442 | - 4.6 443 | - 1.0 444 | - 1.4 445 | - 1.8 446 | - 2.2 447 | - 2.6 448 | - 3.0 449 | - 3.4000000000000004 450 | - 3.8000000000000003 451 | - 4.2 452 | - 4.6 453 | - 1.0 454 | - 1.4 455 | - 1.8 456 | - 2.2 457 | - 2.6 458 | - 3.0 459 | - 3.4000000000000004 460 | - 3.8000000000000003 461 | - 4.2 462 | - 4.6 463 | - 1.0 464 | - 1.4 465 | - 1.8 466 | - 2.2 467 | - 2.6 468 | - 3.0 469 | - 3.4000000000000004 470 | - 3.8000000000000003 471 | - 4.2 472 | - 4.6 473 | - 1.0 474 | - 1.4 475 | - 1.8 476 | - 2.2 477 | - 2.6 478 | - 3.0 479 | - 3.4000000000000004 480 | - 3.8000000000000003 481 | - 4.2 482 | - 4.6 483 | - 1.0 484 | - 1.4 485 | - 1.8 486 | - 2.2 487 | - 2.6 488 | - 3.0 489 | - 3.4000000000000004 490 | - 3.8000000000000003 491 | - 4.2 492 | - 4.6 493 | - 1.0 494 | - 1.4 495 | - 1.8 496 | - 2.2 497 | - 2.6 498 | - 3.0 499 | - 3.4000000000000004 500 | - 3.8000000000000003 501 | - 4.2 502 | - 4.6 503 | - -9.0 504 | - -8.6 505 | - -8.2 506 | - -7.8 507 | - -7.4 508 | - -7.0 509 | - -6.6 510 | - -6.199999999999999 511 | - -5.8 512 | - -5.4 513 | - -9.0 514 | - -8.6 515 | - -8.2 516 | - -7.8 517 | - -7.4 518 | - -7.0 519 | - -6.6 520 | - -6.199999999999999 521 | - -5.8 522 | - -5.4 523 | - -9.0 524 | - -8.6 525 | - -8.2 526 | - -7.8 527 | - -7.4 528 | - -7.0 529 | - -6.6 530 | - -6.199999999999999 531 | - -5.8 532 | - -5.4 533 | - -9.0 534 | - -8.6 535 | - -8.2 536 | - -7.8 537 | - -7.4 538 | - -7.0 539 | - -6.6 540 | - -6.199999999999999 541 | - -5.8 542 | - -5.4 543 | - -9.0 544 | - -8.6 545 | - -8.2 546 | - -7.8 547 | - -7.4 548 | - -7.0 549 | - -6.6 550 | - -6.199999999999999 551 | - -5.8 552 | - -5.4 553 | - -9.0 554 | - -8.6 555 | - -8.2 556 | - -7.8 557 | - -7.4 558 | - -7.0 559 | - -6.6 560 | - -6.199999999999999 561 | - -5.8 562 | - -5.4 563 | - -9.0 564 | - -8.6 565 | - -8.2 566 | - -7.8 567 | - -7.4 568 | - -7.0 569 | - -6.6 570 | - -6.199999999999999 571 | - -5.8 572 | - -5.4 573 | - -9.0 574 | - -8.6 575 | - -8.2 576 | - -7.8 577 | - -7.4 578 | - -7.0 579 | - -6.6 580 | - -6.199999999999999 581 | - -5.8 582 | - -5.4 583 | - -9.0 584 | - -8.6 585 | - -8.2 586 | - -7.8 587 | - -7.4 588 | - -7.0 589 | - -6.6 590 | - -6.199999999999999 591 | - -5.8 592 | - -5.4 593 | - -9.0 594 | - -8.6 595 | - -8.2 596 | - -7.8 597 | - -7.4 598 | - -7.0 599 | - -6.6 600 | - -6.199999999999999 601 | - -5.8 602 | - -5.4 603 | - 10.0 604 | - 10.4 605 | - 10.8 606 | - 11.2 607 | - 11.6 608 | - 12.0 609 | - 12.4 610 | - 12.8 611 | - 13.2 612 | - 13.6 613 | - 10.0 614 | - 10.4 615 | - 10.8 616 | - 11.2 617 | - 11.6 618 | - 12.0 619 | - 12.4 620 | - 12.8 621 | - 13.2 622 | - 13.6 623 | - 10.0 624 | - 10.4 625 | - 10.8 626 | - 11.2 627 | - 11.6 628 | - 12.0 629 | - 12.4 630 | - 12.8 631 | - 13.2 632 | - 13.6 633 | - 10.0 634 | - 10.4 635 | - 10.8 636 | - 11.2 637 | - 11.6 638 | - 12.0 639 | - 12.4 640 | - 12.8 641 | - 13.2 642 | - 13.6 643 | - 10.0 644 | - 10.4 645 | - 10.8 646 | - 11.2 647 | - 11.6 648 | - 12.0 649 | - 12.4 650 | - 12.8 651 | - 13.2 652 | - 13.6 653 | - 10.0 654 | - 10.4 655 | - 10.8 656 | - 11.2 657 | - 11.6 658 | - 12.0 659 | - 12.4 660 | - 12.8 661 | - 13.2 662 | - 13.6 663 | - 10.0 664 | - 10.4 665 | - 10.8 666 | - 11.2 667 | - 11.6 668 | - 12.0 669 | - 12.4 670 | - 12.8 671 | - 13.2 672 | - 13.6 673 | - 10.0 674 | - 10.4 675 | - 10.8 676 | - 11.2 677 | - 11.6 678 | - 12.0 679 | - 12.4 680 | - 12.8 681 | - 13.2 682 | - 13.6 683 | - 10.0 684 | - 10.4 685 | - 10.8 686 | - 11.2 687 | - 11.6 688 | - 12.0 689 | - 12.4 690 | - 12.8 691 | - 13.2 692 | - 13.6 693 | - 10.0 694 | - 10.4 695 | - 10.8 696 | - 11.2 697 | - 11.6 698 | - 12.0 699 | - 12.4 700 | - 12.8 701 | - 13.2 702 | - 13.6 703 | - -10.0 704 | - -9.6 705 | - -9.2 706 | - -8.8 707 | - -8.4 708 | - -8.0 709 | - -7.6 710 | - -7.199999999999999 711 | - -6.8 712 | - -6.4 713 | - -10.0 714 | - -9.6 715 | - -9.2 716 | - -8.8 717 | - -8.4 718 | - -8.0 719 | - -7.6 720 | - -7.199999999999999 721 | - -6.8 722 | - -6.4 723 | - -10.0 724 | - -9.6 725 | - -9.2 726 | - -8.8 727 | - -8.4 728 | - -8.0 729 | - -7.6 730 | - -7.199999999999999 731 | - -6.8 732 | - -6.4 733 | - -10.0 734 | - -9.6 735 | - -9.2 736 | - -8.8 737 | - -8.4 738 | - -8.0 739 | - -7.6 740 | - -7.199999999999999 741 | - -6.8 742 | - -6.4 743 | - -10.0 744 | - -9.6 745 | - -9.2 746 | - -8.8 747 | - -8.4 748 | - -8.0 749 | - -7.6 750 | - -7.199999999999999 751 | - -6.8 752 | - -6.4 753 | - -10.0 754 | - -9.6 755 | - -9.2 756 | - -8.8 757 | - -8.4 758 | - -8.0 759 | - -7.6 760 | - -7.199999999999999 761 | - -6.8 762 | - -6.4 763 | - -10.0 764 | - -9.6 765 | - -9.2 766 | - -8.8 767 | - -8.4 768 | - -8.0 769 | - -7.6 770 | - -7.199999999999999 771 | - -6.8 772 | - -6.4 773 | - -10.0 774 | - -9.6 775 | - -9.2 776 | - -8.8 777 | - -8.4 778 | - -8.0 779 | - -7.6 780 | - -7.199999999999999 781 | - -6.8 782 | - -6.4 783 | - -10.0 784 | - -9.6 785 | - -9.2 786 | - -8.8 787 | - -8.4 788 | - -8.0 789 | - -7.6 790 | - -7.199999999999999 791 | - -6.8 792 | - -6.4 793 | - -10.0 794 | - -9.6 795 | - -9.2 796 | - -8.8 797 | - -8.4 798 | - -8.0 799 | - -7.6 800 | - -7.199999999999999 801 | - -6.8 802 | - -6.4 803 | -------------------------------------------------------------------------------- /config/grid_coords_valid.yaml: -------------------------------------------------------------------------------- 1 | x: 2 | - 24.34782608695652 3 | - 26.08695652173913 4 | - 27.82608695652174 5 | - 29.565217391304348 6 | - 31.304347826086957 7 | - 33.04347826086956 8 | - 34.78260869565217 9 | - 36.52173913043478 10 | - 38.26086956521739 11 | - 40.0 12 | - 19.130434782608695 13 | - 20.869565217391305 14 | - 22.608695652173914 15 | - 24.34782608695652 16 | - 26.08695652173913 17 | - 27.82608695652174 18 | - 29.565217391304348 19 | - 31.304347826086957 20 | - 33.04347826086956 21 | - 34.78260869565217 22 | - 36.52173913043478 23 | - 38.26086956521739 24 | - 40.0 25 | - 13.91304347826087 26 | - 15.652173913043478 27 | - 17.391304347826086 28 | - 19.130434782608695 29 | - 20.869565217391305 30 | - 22.608695652173914 31 | - 24.34782608695652 32 | - 26.08695652173913 33 | - 27.82608695652174 34 | - 29.565217391304348 35 | - 31.304347826086957 36 | - 33.04347826086956 37 | - 34.78260869565217 38 | - 36.52173913043478 39 | - 38.26086956521739 40 | - 40.0 41 | - 12.17391304347826 42 | - 13.91304347826087 43 | - 15.652173913043478 44 | - 17.391304347826086 45 | - 19.130434782608695 46 | - 20.869565217391305 47 | - 22.608695652173914 48 | - 24.34782608695652 49 | - 26.08695652173913 50 | - 27.82608695652174 51 | - 29.565217391304348 52 | - 31.304347826086957 53 | - 33.04347826086956 54 | - 34.78260869565217 55 | - 36.52173913043478 56 | - 38.26086956521739 57 | - 40.0 58 | - 8.695652173913043 59 | - 10.434782608695652 60 | - 12.17391304347826 61 | - 13.91304347826087 62 | - 15.652173913043478 63 | - 17.391304347826086 64 | - 19.130434782608695 65 | - 20.869565217391305 66 | - 22.608695652173914 67 | - 24.34782608695652 68 | - 26.08695652173913 69 | - 27.82608695652174 70 | - 29.565217391304348 71 | - 31.304347826086957 72 | - 33.04347826086956 73 | - 34.78260869565217 74 | - 36.52173913043478 75 | - 38.26086956521739 76 | - 40.0 77 | - 6.956521739130435 78 | - 8.695652173913043 79 | - 10.434782608695652 80 | - 12.17391304347826 81 | - 13.91304347826087 82 | - 15.652173913043478 83 | - 17.391304347826086 84 | - 19.130434782608695 85 | - 20.869565217391305 86 | - 22.608695652173914 87 | - 24.34782608695652 88 | - 26.08695652173913 89 | - 27.82608695652174 90 | - 29.565217391304348 91 | - 31.304347826086957 92 | - 33.04347826086956 93 | - 34.78260869565217 94 | - 36.52173913043478 95 | - 38.26086956521739 96 | - 40.0 97 | - 5.217391304347826 98 | - 6.956521739130435 99 | - 8.695652173913043 100 | - 10.434782608695652 101 | - 12.17391304347826 102 | - 13.91304347826087 103 | - 15.652173913043478 104 | - 17.391304347826086 105 | - 19.130434782608695 106 | - 20.869565217391305 107 | - 22.608695652173914 108 | - 24.34782608695652 109 | - 26.08695652173913 110 | - 27.82608695652174 111 | - 29.565217391304348 112 | - 31.304347826086957 113 | - 33.04347826086956 114 | - 34.78260869565217 115 | - 36.52173913043478 116 | - 38.26086956521739 117 | - 40.0 118 | - 5.217391304347826 119 | - 6.956521739130435 120 | - 8.695652173913043 121 | - 10.434782608695652 122 | - 12.17391304347826 123 | - 13.91304347826087 124 | - 15.652173913043478 125 | - 17.391304347826086 126 | - 19.130434782608695 127 | - 20.869565217391305 128 | - 22.608695652173914 129 | - 24.34782608695652 130 | - 26.08695652173913 131 | - 27.82608695652174 132 | - 29.565217391304348 133 | - 31.304347826086957 134 | - 33.04347826086956 135 | - 34.78260869565217 136 | - 36.52173913043478 137 | - 38.26086956521739 138 | - 40.0 139 | - 3.4782608695652173 140 | - 5.217391304347826 141 | - 6.956521739130435 142 | - 8.695652173913043 143 | - 10.434782608695652 144 | - 12.17391304347826 145 | - 13.91304347826087 146 | - 15.652173913043478 147 | - 17.391304347826086 148 | - 19.130434782608695 149 | - 20.869565217391305 150 | - 22.608695652173914 151 | - 24.34782608695652 152 | - 26.08695652173913 153 | - 27.82608695652174 154 | - 29.565217391304348 155 | - 31.304347826086957 156 | - 33.04347826086956 157 | - 34.78260869565217 158 | - 36.52173913043478 159 | - 38.26086956521739 160 | - 40.0 161 | - 3.4782608695652173 162 | - 5.217391304347826 163 | - 6.956521739130435 164 | - 8.695652173913043 165 | - 10.434782608695652 166 | - 12.17391304347826 167 | - 13.91304347826087 168 | - 15.652173913043478 169 | - 17.391304347826086 170 | - 19.130434782608695 171 | - 20.869565217391305 172 | - 22.608695652173914 173 | - 24.34782608695652 174 | - 26.08695652173913 175 | - 27.82608695652174 176 | - 29.565217391304348 177 | - 31.304347826086957 178 | - 33.04347826086956 179 | - 34.78260869565217 180 | - 36.52173913043478 181 | - 38.26086956521739 182 | - 40.0 183 | - 1.7391304347826086 184 | - 3.4782608695652173 185 | - 5.217391304347826 186 | - 6.956521739130435 187 | - 8.695652173913043 188 | - 10.434782608695652 189 | - 12.17391304347826 190 | - 13.91304347826087 191 | - 15.652173913043478 192 | - 17.391304347826086 193 | - 19.130434782608695 194 | - 20.869565217391305 195 | - 22.608695652173914 196 | - 24.34782608695652 197 | - 26.08695652173913 198 | - 27.82608695652174 199 | - 29.565217391304348 200 | - 31.304347826086957 201 | - 33.04347826086956 202 | - 34.78260869565217 203 | - 36.52173913043478 204 | - 38.26086956521739 205 | - 40.0 206 | - 1.7391304347826086 207 | - 3.4782608695652173 208 | - 5.217391304347826 209 | - 6.956521739130435 210 | - 8.695652173913043 211 | - 10.434782608695652 212 | - 12.17391304347826 213 | - 13.91304347826087 214 | - 15.652173913043478 215 | - 17.391304347826086 216 | - 19.130434782608695 217 | - 20.869565217391305 218 | - 22.608695652173914 219 | - 24.34782608695652 220 | - 26.08695652173913 221 | - 27.82608695652174 222 | - 29.565217391304348 223 | - 31.304347826086957 224 | - 33.04347826086956 225 | - 34.78260869565217 226 | - 36.52173913043478 227 | - 38.26086956521739 228 | - 40.0 229 | - 1.7391304347826086 230 | - 3.4782608695652173 231 | - 5.217391304347826 232 | - 6.956521739130435 233 | - 8.695652173913043 234 | - 10.434782608695652 235 | - 12.17391304347826 236 | - 13.91304347826087 237 | - 15.652173913043478 238 | - 17.391304347826086 239 | - 19.130434782608695 240 | - 20.869565217391305 241 | - 22.608695652173914 242 | - 24.34782608695652 243 | - 26.08695652173913 244 | - 27.82608695652174 245 | - 29.565217391304348 246 | - 31.304347826086957 247 | - 33.04347826086956 248 | - 34.78260869565217 249 | - 36.52173913043478 250 | - 38.26086956521739 251 | - 40.0 252 | - 1.7391304347826086 253 | - 3.4782608695652173 254 | - 5.217391304347826 255 | - 6.956521739130435 256 | - 8.695652173913043 257 | - 10.434782608695652 258 | - 12.17391304347826 259 | - 13.91304347826087 260 | - 15.652173913043478 261 | - 17.391304347826086 262 | - 19.130434782608695 263 | - 20.869565217391305 264 | - 22.608695652173914 265 | - 24.34782608695652 266 | - 26.08695652173913 267 | - 27.82608695652174 268 | - 29.565217391304348 269 | - 31.304347826086957 270 | - 33.04347826086956 271 | - 34.78260869565217 272 | - 36.52173913043478 273 | - 38.26086956521739 274 | - 40.0 275 | - 1.7391304347826086 276 | - 3.4782608695652173 277 | - 5.217391304347826 278 | - 6.956521739130435 279 | - 8.695652173913043 280 | - 10.434782608695652 281 | - 12.17391304347826 282 | - 13.91304347826087 283 | - 15.652173913043478 284 | - 17.391304347826086 285 | - 19.130434782608695 286 | - 20.869565217391305 287 | - 22.608695652173914 288 | - 24.34782608695652 289 | - 26.08695652173913 290 | - 27.82608695652174 291 | - 29.565217391304348 292 | - 31.304347826086957 293 | - 33.04347826086956 294 | - 34.78260869565217 295 | - 36.52173913043478 296 | - 38.26086956521739 297 | - 40.0 298 | - 1.7391304347826086 299 | - 3.4782608695652173 300 | - 5.217391304347826 301 | - 6.956521739130435 302 | - 8.695652173913043 303 | - 10.434782608695652 304 | - 12.17391304347826 305 | - 13.91304347826087 306 | - 15.652173913043478 307 | - 17.391304347826086 308 | - 19.130434782608695 309 | - 20.869565217391305 310 | - 22.608695652173914 311 | - 24.34782608695652 312 | - 26.08695652173913 313 | - 27.82608695652174 314 | - 29.565217391304348 315 | - 31.304347826086957 316 | - 33.04347826086956 317 | - 34.78260869565217 318 | - 36.52173913043478 319 | - 38.26086956521739 320 | - 40.0 321 | - 1.7391304347826086 322 | - 3.4782608695652173 323 | - 5.217391304347826 324 | - 6.956521739130435 325 | - 8.695652173913043 326 | - 10.434782608695652 327 | - 12.17391304347826 328 | - 13.91304347826087 329 | - 15.652173913043478 330 | - 17.391304347826086 331 | - 19.130434782608695 332 | - 20.869565217391305 333 | - 22.608695652173914 334 | - 24.34782608695652 335 | - 26.08695652173913 336 | - 27.82608695652174 337 | - 29.565217391304348 338 | - 31.304347826086957 339 | - 33.04347826086956 340 | - 34.78260869565217 341 | - 36.52173913043478 342 | - 38.26086956521739 343 | - 40.0 344 | - 1.7391304347826086 345 | - 3.4782608695652173 346 | - 5.217391304347826 347 | - 6.956521739130435 348 | - 8.695652173913043 349 | - 10.434782608695652 350 | - 12.17391304347826 351 | - 13.91304347826087 352 | - 15.652173913043478 353 | - 17.391304347826086 354 | - 19.130434782608695 355 | - 20.869565217391305 356 | - 22.608695652173914 357 | - 24.34782608695652 358 | - 26.08695652173913 359 | - 27.82608695652174 360 | - 29.565217391304348 361 | - 31.304347826086957 362 | - 33.04347826086956 363 | - 34.78260869565217 364 | - 36.52173913043478 365 | - 38.26086956521739 366 | - 40.0 367 | - 1.7391304347826086 368 | - 3.4782608695652173 369 | - 5.217391304347826 370 | - 6.956521739130435 371 | - 8.695652173913043 372 | - 10.434782608695652 373 | - 12.17391304347826 374 | - 13.91304347826087 375 | - 15.652173913043478 376 | - 17.391304347826086 377 | - 19.130434782608695 378 | - 20.869565217391305 379 | - 22.608695652173914 380 | - 24.34782608695652 381 | - 26.08695652173913 382 | - 27.82608695652174 383 | - 29.565217391304348 384 | - 31.304347826086957 385 | - 33.04347826086956 386 | - 34.78260869565217 387 | - 36.52173913043478 388 | - 38.26086956521739 389 | - 40.0 390 | - 1.7391304347826086 391 | - 3.4782608695652173 392 | - 5.217391304347826 393 | - 6.956521739130435 394 | - 8.695652173913043 395 | - 10.434782608695652 396 | - 12.17391304347826 397 | - 13.91304347826087 398 | - 15.652173913043478 399 | - 17.391304347826086 400 | - 19.130434782608695 401 | - 20.869565217391305 402 | - 22.608695652173914 403 | - 24.34782608695652 404 | - 26.08695652173913 405 | - 27.82608695652174 406 | - 29.565217391304348 407 | - 31.304347826086957 408 | - 33.04347826086956 409 | - 34.78260869565217 410 | - 36.52173913043478 411 | - 38.26086956521739 412 | - 40.0 413 | - 3.4782608695652173 414 | - 5.217391304347826 415 | - 6.956521739130435 416 | - 8.695652173913043 417 | - 10.434782608695652 418 | - 12.17391304347826 419 | - 13.91304347826087 420 | - 15.652173913043478 421 | - 17.391304347826086 422 | - 19.130434782608695 423 | - 20.869565217391305 424 | - 22.608695652173914 425 | - 24.34782608695652 426 | - 26.08695652173913 427 | - 27.82608695652174 428 | - 29.565217391304348 429 | - 31.304347826086957 430 | - 33.04347826086956 431 | - 34.78260869565217 432 | - 36.52173913043478 433 | - 38.26086956521739 434 | - 40.0 435 | - 3.4782608695652173 436 | - 5.217391304347826 437 | - 6.956521739130435 438 | - 8.695652173913043 439 | - 10.434782608695652 440 | - 12.17391304347826 441 | - 13.91304347826087 442 | - 15.652173913043478 443 | - 17.391304347826086 444 | - 19.130434782608695 445 | - 20.869565217391305 446 | - 22.608695652173914 447 | - 24.34782608695652 448 | - 26.08695652173913 449 | - 27.82608695652174 450 | - 29.565217391304348 451 | - 31.304347826086957 452 | - 33.04347826086956 453 | - 34.78260869565217 454 | - 36.52173913043478 455 | - 38.26086956521739 456 | - 40.0 457 | - 5.217391304347826 458 | - 6.956521739130435 459 | - 8.695652173913043 460 | - 10.434782608695652 461 | - 12.17391304347826 462 | - 13.91304347826087 463 | - 15.652173913043478 464 | - 17.391304347826086 465 | - 19.130434782608695 466 | - 20.869565217391305 467 | - 22.608695652173914 468 | - 24.34782608695652 469 | - 26.08695652173913 470 | - 27.82608695652174 471 | - 29.565217391304348 472 | - 31.304347826086957 473 | - 33.04347826086956 474 | - 34.78260869565217 475 | - 36.52173913043478 476 | - 38.26086956521739 477 | - 40.0 478 | - 5.217391304347826 479 | - 6.956521739130435 480 | - 8.695652173913043 481 | - 10.434782608695652 482 | - 12.17391304347826 483 | - 13.91304347826087 484 | - 15.652173913043478 485 | - 17.391304347826086 486 | - 19.130434782608695 487 | - 20.869565217391305 488 | - 22.608695652173914 489 | - 24.34782608695652 490 | - 26.08695652173913 491 | - 27.82608695652174 492 | - 29.565217391304348 493 | - 31.304347826086957 494 | - 33.04347826086956 495 | - 34.78260869565217 496 | - 36.52173913043478 497 | - 38.26086956521739 498 | - 40.0 499 | - 6.956521739130435 500 | - 8.695652173913043 501 | - 10.434782608695652 502 | - 12.17391304347826 503 | - 13.91304347826087 504 | - 15.652173913043478 505 | - 17.391304347826086 506 | - 19.130434782608695 507 | - 20.869565217391305 508 | - 22.608695652173914 509 | - 24.34782608695652 510 | - 26.08695652173913 511 | - 27.82608695652174 512 | - 29.565217391304348 513 | - 31.304347826086957 514 | - 33.04347826086956 515 | - 34.78260869565217 516 | - 36.52173913043478 517 | - 38.26086956521739 518 | - 40.0 519 | - 8.695652173913043 520 | - 10.434782608695652 521 | - 12.17391304347826 522 | - 13.91304347826087 523 | - 15.652173913043478 524 | - 17.391304347826086 525 | - 19.130434782608695 526 | - 20.869565217391305 527 | - 22.608695652173914 528 | - 24.34782608695652 529 | - 26.08695652173913 530 | - 27.82608695652174 531 | - 29.565217391304348 532 | - 31.304347826086957 533 | - 33.04347826086956 534 | - 34.78260869565217 535 | - 36.52173913043478 536 | - 38.26086956521739 537 | - 40.0 538 | - 12.17391304347826 539 | - 13.91304347826087 540 | - 15.652173913043478 541 | - 17.391304347826086 542 | - 19.130434782608695 543 | - 20.869565217391305 544 | - 22.608695652173914 545 | - 24.34782608695652 546 | - 26.08695652173913 547 | - 27.82608695652174 548 | - 29.565217391304348 549 | - 31.304347826086957 550 | - 33.04347826086956 551 | - 34.78260869565217 552 | - 36.52173913043478 553 | - 38.26086956521739 554 | - 40.0 555 | - 13.91304347826087 556 | - 15.652173913043478 557 | - 17.391304347826086 558 | - 19.130434782608695 559 | - 20.869565217391305 560 | - 22.608695652173914 561 | - 24.34782608695652 562 | - 26.08695652173913 563 | - 27.82608695652174 564 | - 29.565217391304348 565 | - 31.304347826086957 566 | - 33.04347826086956 567 | - 34.78260869565217 568 | - 36.52173913043478 569 | - 38.26086956521739 570 | - 40.0 571 | - 19.130434782608695 572 | - 20.869565217391305 573 | - 22.608695652173914 574 | - 24.34782608695652 575 | - 26.08695652173913 576 | - 27.82608695652174 577 | - 29.565217391304348 578 | - 31.304347826086957 579 | - 33.04347826086956 580 | - 34.78260869565217 581 | - 36.52173913043478 582 | - 38.26086956521739 583 | - 40.0 584 | - 24.34782608695652 585 | - 26.08695652173913 586 | - 27.82608695652174 587 | - 29.565217391304348 588 | - 31.304347826086957 589 | - 33.04347826086956 590 | - 34.78260869565217 591 | - 36.52173913043478 592 | - 38.26086956521739 593 | - 40.0 594 | y: 595 | - -19.902161680671945 596 | - -19.902161680671945 597 | - -19.902161680671945 598 | - -19.902161680671945 599 | - -19.902161680671945 600 | - -19.902161680671945 601 | - -19.902161680671945 602 | - -19.902161680671945 603 | - -19.902161680671945 604 | - -19.902161680671945 605 | - -18.529598806142843 606 | - -18.529598806142843 607 | - -18.529598806142843 608 | - -18.529598806142843 609 | - -18.529598806142843 610 | - -18.529598806142843 611 | - -18.529598806142843 612 | - -18.529598806142843 613 | - -18.529598806142843 614 | - -18.529598806142843 615 | - -18.529598806142843 616 | - -18.529598806142843 617 | - -18.529598806142843 618 | - -17.157035931613745 619 | - -17.157035931613745 620 | - -17.157035931613745 621 | - -17.157035931613745 622 | - -17.157035931613745 623 | - -17.157035931613745 624 | - -17.157035931613745 625 | - -17.157035931613745 626 | - -17.157035931613745 627 | - -17.157035931613745 628 | - -17.157035931613745 629 | - -17.157035931613745 630 | - -17.157035931613745 631 | - -17.157035931613745 632 | - -17.157035931613745 633 | - -17.157035931613745 634 | - -15.784473057084645 635 | - -15.784473057084645 636 | - -15.784473057084645 637 | - -15.784473057084645 638 | - -15.784473057084645 639 | - -15.784473057084645 640 | - -15.784473057084645 641 | - -15.784473057084645 642 | - -15.784473057084645 643 | - -15.784473057084645 644 | - -15.784473057084645 645 | - -15.784473057084645 646 | - -15.784473057084645 647 | - -15.784473057084645 648 | - -15.784473057084645 649 | - -15.784473057084645 650 | - -15.784473057084645 651 | - -14.411910182555545 652 | - -14.411910182555545 653 | - -14.411910182555545 654 | - -14.411910182555545 655 | - -14.411910182555545 656 | - -14.411910182555545 657 | - -14.411910182555545 658 | - -14.411910182555545 659 | - -14.411910182555545 660 | - -14.411910182555545 661 | - -14.411910182555545 662 | - -14.411910182555545 663 | - -14.411910182555545 664 | - -14.411910182555545 665 | - -14.411910182555545 666 | - -14.411910182555545 667 | - -14.411910182555545 668 | - -14.411910182555545 669 | - -14.411910182555545 670 | - -13.039347308026446 671 | - -13.039347308026446 672 | - -13.039347308026446 673 | - -13.039347308026446 674 | - -13.039347308026446 675 | - -13.039347308026446 676 | - -13.039347308026446 677 | - -13.039347308026446 678 | - -13.039347308026446 679 | - -13.039347308026446 680 | - -13.039347308026446 681 | - -13.039347308026446 682 | - -13.039347308026446 683 | - -13.039347308026446 684 | - -13.039347308026446 685 | - -13.039347308026446 686 | - -13.039347308026446 687 | - -13.039347308026446 688 | - -13.039347308026446 689 | - -13.039347308026446 690 | - -11.666784433497346 691 | - -11.666784433497346 692 | - -11.666784433497346 693 | - -11.666784433497346 694 | - -11.666784433497346 695 | - -11.666784433497346 696 | - -11.666784433497346 697 | - -11.666784433497346 698 | - -11.666784433497346 699 | - -11.666784433497346 700 | - -11.666784433497346 701 | - -11.666784433497346 702 | - -11.666784433497346 703 | - -11.666784433497346 704 | - -11.666784433497346 705 | - -11.666784433497346 706 | - -11.666784433497346 707 | - -11.666784433497346 708 | - -11.666784433497346 709 | - -11.666784433497346 710 | - -11.666784433497346 711 | - -10.294221558968246 712 | - -10.294221558968246 713 | - -10.294221558968246 714 | - -10.294221558968246 715 | - -10.294221558968246 716 | - -10.294221558968246 717 | - -10.294221558968246 718 | - -10.294221558968246 719 | - -10.294221558968246 720 | - -10.294221558968246 721 | - -10.294221558968246 722 | - -10.294221558968246 723 | - -10.294221558968246 724 | - -10.294221558968246 725 | - -10.294221558968246 726 | - -10.294221558968246 727 | - -10.294221558968246 728 | - -10.294221558968246 729 | - -10.294221558968246 730 | - -10.294221558968246 731 | - -10.294221558968246 732 | - -8.921658684439146 733 | - -8.921658684439146 734 | - -8.921658684439146 735 | - -8.921658684439146 736 | - -8.921658684439146 737 | - -8.921658684439146 738 | - -8.921658684439146 739 | - -8.921658684439146 740 | - -8.921658684439146 741 | - -8.921658684439146 742 | - -8.921658684439146 743 | - -8.921658684439146 744 | - -8.921658684439146 745 | - -8.921658684439146 746 | - -8.921658684439146 747 | - -8.921658684439146 748 | - -8.921658684439146 749 | - -8.921658684439146 750 | - -8.921658684439146 751 | - -8.921658684439146 752 | - -8.921658684439146 753 | - -8.921658684439146 754 | - -7.549095809910046 755 | - -7.549095809910046 756 | - -7.549095809910046 757 | - -7.549095809910046 758 | - -7.549095809910046 759 | - -7.549095809910046 760 | - -7.549095809910046 761 | - -7.549095809910046 762 | - -7.549095809910046 763 | - -7.549095809910046 764 | - -7.549095809910046 765 | - -7.549095809910046 766 | - -7.549095809910046 767 | - -7.549095809910046 768 | - -7.549095809910046 769 | - -7.549095809910046 770 | - -7.549095809910046 771 | - -7.549095809910046 772 | - -7.549095809910046 773 | - -7.549095809910046 774 | - -7.549095809910046 775 | - -7.549095809910046 776 | - -6.176532935380948 777 | - -6.176532935380948 778 | - -6.176532935380948 779 | - -6.176532935380948 780 | - -6.176532935380948 781 | - -6.176532935380948 782 | - -6.176532935380948 783 | - -6.176532935380948 784 | - -6.176532935380948 785 | - -6.176532935380948 786 | - -6.176532935380948 787 | - -6.176532935380948 788 | - -6.176532935380948 789 | - -6.176532935380948 790 | - -6.176532935380948 791 | - -6.176532935380948 792 | - -6.176532935380948 793 | - -6.176532935380948 794 | - -6.176532935380948 795 | - -6.176532935380948 796 | - -6.176532935380948 797 | - -6.176532935380948 798 | - -6.176532935380948 799 | - -4.803970060851849 800 | - -4.803970060851849 801 | - -4.803970060851849 802 | - -4.803970060851849 803 | - -4.803970060851849 804 | - -4.803970060851849 805 | - -4.803970060851849 806 | - -4.803970060851849 807 | - -4.803970060851849 808 | - -4.803970060851849 809 | - -4.803970060851849 810 | - -4.803970060851849 811 | - -4.803970060851849 812 | - -4.803970060851849 813 | - -4.803970060851849 814 | - -4.803970060851849 815 | - -4.803970060851849 816 | - -4.803970060851849 817 | - -4.803970060851849 818 | - -4.803970060851849 819 | - -4.803970060851849 820 | - -4.803970060851849 821 | - -4.803970060851849 822 | - -3.4314071863227475 823 | - -3.4314071863227475 824 | - -3.4314071863227475 825 | - -3.4314071863227475 826 | - -3.4314071863227475 827 | - -3.4314071863227475 828 | - -3.4314071863227475 829 | - -3.4314071863227475 830 | - -3.4314071863227475 831 | - -3.4314071863227475 832 | - -3.4314071863227475 833 | - -3.4314071863227475 834 | - -3.4314071863227475 835 | - -3.4314071863227475 836 | - -3.4314071863227475 837 | - -3.4314071863227475 838 | - -3.4314071863227475 839 | - -3.4314071863227475 840 | - -3.4314071863227475 841 | - -3.4314071863227475 842 | - -3.4314071863227475 843 | - -3.4314071863227475 844 | - -3.4314071863227475 845 | - -2.0588443117936492 846 | - -2.0588443117936492 847 | - -2.0588443117936492 848 | - -2.0588443117936492 849 | - -2.0588443117936492 850 | - -2.0588443117936492 851 | - -2.0588443117936492 852 | - -2.0588443117936492 853 | - -2.0588443117936492 854 | - -2.0588443117936492 855 | - -2.0588443117936492 856 | - -2.0588443117936492 857 | - -2.0588443117936492 858 | - -2.0588443117936492 859 | - -2.0588443117936492 860 | - -2.0588443117936492 861 | - -2.0588443117936492 862 | - -2.0588443117936492 863 | - -2.0588443117936492 864 | - -2.0588443117936492 865 | - -2.0588443117936492 866 | - -2.0588443117936492 867 | - -2.0588443117936492 868 | - -0.6862814372645474 869 | - -0.6862814372645474 870 | - -0.6862814372645474 871 | - -0.6862814372645474 872 | - -0.6862814372645474 873 | - -0.6862814372645474 874 | - -0.6862814372645474 875 | - -0.6862814372645474 876 | - -0.6862814372645474 877 | - -0.6862814372645474 878 | - -0.6862814372645474 879 | - -0.6862814372645474 880 | - -0.6862814372645474 881 | - -0.6862814372645474 882 | - -0.6862814372645474 883 | - -0.6862814372645474 884 | - -0.6862814372645474 885 | - -0.6862814372645474 886 | - -0.6862814372645474 887 | - -0.6862814372645474 888 | - -0.6862814372645474 889 | - -0.6862814372645474 890 | - -0.6862814372645474 891 | - 0.6862814372645509 892 | - 0.6862814372645509 893 | - 0.6862814372645509 894 | - 0.6862814372645509 895 | - 0.6862814372645509 896 | - 0.6862814372645509 897 | - 0.6862814372645509 898 | - 0.6862814372645509 899 | - 0.6862814372645509 900 | - 0.6862814372645509 901 | - 0.6862814372645509 902 | - 0.6862814372645509 903 | - 0.6862814372645509 904 | - 0.6862814372645509 905 | - 0.6862814372645509 906 | - 0.6862814372645509 907 | - 0.6862814372645509 908 | - 0.6862814372645509 909 | - 0.6862814372645509 910 | - 0.6862814372645509 911 | - 0.6862814372645509 912 | - 0.6862814372645509 913 | - 0.6862814372645509 914 | - 2.0588443117936492 915 | - 2.0588443117936492 916 | - 2.0588443117936492 917 | - 2.0588443117936492 918 | - 2.0588443117936492 919 | - 2.0588443117936492 920 | - 2.0588443117936492 921 | - 2.0588443117936492 922 | - 2.0588443117936492 923 | - 2.0588443117936492 924 | - 2.0588443117936492 925 | - 2.0588443117936492 926 | - 2.0588443117936492 927 | - 2.0588443117936492 928 | - 2.0588443117936492 929 | - 2.0588443117936492 930 | - 2.0588443117936492 931 | - 2.0588443117936492 932 | - 2.0588443117936492 933 | - 2.0588443117936492 934 | - 2.0588443117936492 935 | - 2.0588443117936492 936 | - 2.0588443117936492 937 | - 3.431407186322751 938 | - 3.431407186322751 939 | - 3.431407186322751 940 | - 3.431407186322751 941 | - 3.431407186322751 942 | - 3.431407186322751 943 | - 3.431407186322751 944 | - 3.431407186322751 945 | - 3.431407186322751 946 | - 3.431407186322751 947 | - 3.431407186322751 948 | - 3.431407186322751 949 | - 3.431407186322751 950 | - 3.431407186322751 951 | - 3.431407186322751 952 | - 3.431407186322751 953 | - 3.431407186322751 954 | - 3.431407186322751 955 | - 3.431407186322751 956 | - 3.431407186322751 957 | - 3.431407186322751 958 | - 3.431407186322751 959 | - 3.431407186322751 960 | - 4.803970060851849 961 | - 4.803970060851849 962 | - 4.803970060851849 963 | - 4.803970060851849 964 | - 4.803970060851849 965 | - 4.803970060851849 966 | - 4.803970060851849 967 | - 4.803970060851849 968 | - 4.803970060851849 969 | - 4.803970060851849 970 | - 4.803970060851849 971 | - 4.803970060851849 972 | - 4.803970060851849 973 | - 4.803970060851849 974 | - 4.803970060851849 975 | - 4.803970060851849 976 | - 4.803970060851849 977 | - 4.803970060851849 978 | - 4.803970060851849 979 | - 4.803970060851849 980 | - 4.803970060851849 981 | - 4.803970060851849 982 | - 4.803970060851849 983 | - 6.176532935380951 984 | - 6.176532935380951 985 | - 6.176532935380951 986 | - 6.176532935380951 987 | - 6.176532935380951 988 | - 6.176532935380951 989 | - 6.176532935380951 990 | - 6.176532935380951 991 | - 6.176532935380951 992 | - 6.176532935380951 993 | - 6.176532935380951 994 | - 6.176532935380951 995 | - 6.176532935380951 996 | - 6.176532935380951 997 | - 6.176532935380951 998 | - 6.176532935380951 999 | - 6.176532935380951 1000 | - 6.176532935380951 1001 | - 6.176532935380951 1002 | - 6.176532935380951 1003 | - 6.176532935380951 1004 | - 6.176532935380951 1005 | - 6.176532935380951 1006 | - 7.54909580991005 1007 | - 7.54909580991005 1008 | - 7.54909580991005 1009 | - 7.54909580991005 1010 | - 7.54909580991005 1011 | - 7.54909580991005 1012 | - 7.54909580991005 1013 | - 7.54909580991005 1014 | - 7.54909580991005 1015 | - 7.54909580991005 1016 | - 7.54909580991005 1017 | - 7.54909580991005 1018 | - 7.54909580991005 1019 | - 7.54909580991005 1020 | - 7.54909580991005 1021 | - 7.54909580991005 1022 | - 7.54909580991005 1023 | - 7.54909580991005 1024 | - 7.54909580991005 1025 | - 7.54909580991005 1026 | - 7.54909580991005 1027 | - 7.54909580991005 1028 | - 8.921658684439148 1029 | - 8.921658684439148 1030 | - 8.921658684439148 1031 | - 8.921658684439148 1032 | - 8.921658684439148 1033 | - 8.921658684439148 1034 | - 8.921658684439148 1035 | - 8.921658684439148 1036 | - 8.921658684439148 1037 | - 8.921658684439148 1038 | - 8.921658684439148 1039 | - 8.921658684439148 1040 | - 8.921658684439148 1041 | - 8.921658684439148 1042 | - 8.921658684439148 1043 | - 8.921658684439148 1044 | - 8.921658684439148 1045 | - 8.921658684439148 1046 | - 8.921658684439148 1047 | - 8.921658684439148 1048 | - 8.921658684439148 1049 | - 8.921658684439148 1050 | - 10.29422155896825 1051 | - 10.29422155896825 1052 | - 10.29422155896825 1053 | - 10.29422155896825 1054 | - 10.29422155896825 1055 | - 10.29422155896825 1056 | - 10.29422155896825 1057 | - 10.29422155896825 1058 | - 10.29422155896825 1059 | - 10.29422155896825 1060 | - 10.29422155896825 1061 | - 10.29422155896825 1062 | - 10.29422155896825 1063 | - 10.29422155896825 1064 | - 10.29422155896825 1065 | - 10.29422155896825 1066 | - 10.29422155896825 1067 | - 10.29422155896825 1068 | - 10.29422155896825 1069 | - 10.29422155896825 1070 | - 10.29422155896825 1071 | - 11.666784433497345 1072 | - 11.666784433497345 1073 | - 11.666784433497345 1074 | - 11.666784433497345 1075 | - 11.666784433497345 1076 | - 11.666784433497345 1077 | - 11.666784433497345 1078 | - 11.666784433497345 1079 | - 11.666784433497345 1080 | - 11.666784433497345 1081 | - 11.666784433497345 1082 | - 11.666784433497345 1083 | - 11.666784433497345 1084 | - 11.666784433497345 1085 | - 11.666784433497345 1086 | - 11.666784433497345 1087 | - 11.666784433497345 1088 | - 11.666784433497345 1089 | - 11.666784433497345 1090 | - 11.666784433497345 1091 | - 11.666784433497345 1092 | - 13.039347308026446 1093 | - 13.039347308026446 1094 | - 13.039347308026446 1095 | - 13.039347308026446 1096 | - 13.039347308026446 1097 | - 13.039347308026446 1098 | - 13.039347308026446 1099 | - 13.039347308026446 1100 | - 13.039347308026446 1101 | - 13.039347308026446 1102 | - 13.039347308026446 1103 | - 13.039347308026446 1104 | - 13.039347308026446 1105 | - 13.039347308026446 1106 | - 13.039347308026446 1107 | - 13.039347308026446 1108 | - 13.039347308026446 1109 | - 13.039347308026446 1110 | - 13.039347308026446 1111 | - 13.039347308026446 1112 | - 14.411910182555548 1113 | - 14.411910182555548 1114 | - 14.411910182555548 1115 | - 14.411910182555548 1116 | - 14.411910182555548 1117 | - 14.411910182555548 1118 | - 14.411910182555548 1119 | - 14.411910182555548 1120 | - 14.411910182555548 1121 | - 14.411910182555548 1122 | - 14.411910182555548 1123 | - 14.411910182555548 1124 | - 14.411910182555548 1125 | - 14.411910182555548 1126 | - 14.411910182555548 1127 | - 14.411910182555548 1128 | - 14.411910182555548 1129 | - 14.411910182555548 1130 | - 14.411910182555548 1131 | - 15.78447305708465 1132 | - 15.78447305708465 1133 | - 15.78447305708465 1134 | - 15.78447305708465 1135 | - 15.78447305708465 1136 | - 15.78447305708465 1137 | - 15.78447305708465 1138 | - 15.78447305708465 1139 | - 15.78447305708465 1140 | - 15.78447305708465 1141 | - 15.78447305708465 1142 | - 15.78447305708465 1143 | - 15.78447305708465 1144 | - 15.78447305708465 1145 | - 15.78447305708465 1146 | - 15.78447305708465 1147 | - 15.78447305708465 1148 | - 17.157035931613745 1149 | - 17.157035931613745 1150 | - 17.157035931613745 1151 | - 17.157035931613745 1152 | - 17.157035931613745 1153 | - 17.157035931613745 1154 | - 17.157035931613745 1155 | - 17.157035931613745 1156 | - 17.157035931613745 1157 | - 17.157035931613745 1158 | - 17.157035931613745 1159 | - 17.157035931613745 1160 | - 17.157035931613745 1161 | - 17.157035931613745 1162 | - 17.157035931613745 1163 | - 17.157035931613745 1164 | - 18.529598806142847 1165 | - 18.529598806142847 1166 | - 18.529598806142847 1167 | - 18.529598806142847 1168 | - 18.529598806142847 1169 | - 18.529598806142847 1170 | - 18.529598806142847 1171 | - 18.529598806142847 1172 | - 18.529598806142847 1173 | - 18.529598806142847 1174 | - 18.529598806142847 1175 | - 18.529598806142847 1176 | - 18.529598806142847 1177 | - 19.90216168067195 1178 | - 19.90216168067195 1179 | - 19.90216168067195 1180 | - 19.90216168067195 1181 | - 19.90216168067195 1182 | - 19.90216168067195 1183 | - 19.90216168067195 1184 | - 19.90216168067195 1185 | - 19.90216168067195 1186 | - 19.90216168067195 1187 | -------------------------------------------------------------------------------- /config/grid_coords_valid_2.yaml: -------------------------------------------------------------------------------- 1 | x: 2 | - 36.52173913043478 3 | - 27.82608695652174 4 | - 19.130434782608695 5 | - 40.0 6 | - 12.17391304347826 7 | - 40.0 8 | - 36.52173913043478 9 | - 31.304347826086957 10 | - 33.04347826086956 11 | - 10.434782608695652 12 | - 24.34782608695652 13 | - 33.04347826086956 14 | - 10.434782608695652 15 | - 10.434782608695652 16 | - 8.695652173913043 17 | - 6.956521739130435 18 | - 3.4782608695652173 19 | - 38.26086956521739 20 | - 5.217391304347826 21 | - 5.217391304347826 22 | - 1.7391304347826086 23 | - 38.26086956521739 24 | - 27.82608695652174 25 | - 40.0 26 | - 12.17391304347826 27 | - 40.0 28 | - 3.4782608695652173 29 | - 27.82608695652174 30 | - 40.0 31 | - 36.52173913043478 32 | - 29.565217391304348 33 | - 38.26086956521739 34 | - 38.26086956521739 35 | - 8.695652173913043 36 | - 33.04347826086956 37 | - 40.0 38 | - 15.652173913043478 39 | - 27.82608695652174 40 | - 20.869565217391305 41 | - 31.304347826086957 42 | - 10.434782608695652 43 | - 38.26086956521739 44 | - 36.52173913043478 45 | - 24.34782608695652 46 | - 17.391304347826086 47 | - 29.565217391304348 48 | - 24.34782608695652 49 | - 27.82608695652174 50 | - 34.78260869565217 51 | - 3.4782608695652173 52 | - 15.652173913043478 53 | - 29.565217391304348 54 | - 10.434782608695652 55 | - 31.304347826086957 56 | - 33.04347826086956 57 | - 26.08695652173913 58 | - 38.26086956521739 59 | - 15.652173913043478 60 | - 26.08695652173913 61 | - 20.869565217391305 62 | - 31.304347826086957 63 | - 1.7391304347826086 64 | - 17.391304347826086 65 | - 5.217391304347826 66 | - 19.130434782608695 67 | - 10.434782608695652 68 | - 20.869565217391305 69 | - 36.52173913043478 70 | - 26.08695652173913 71 | - 40.0 72 | - 22.608695652173914 73 | - 26.08695652173913 74 | - 10.434782608695652 75 | - 33.04347826086956 76 | - 31.304347826086957 77 | - 31.304347826086957 78 | - 31.304347826086957 79 | - 33.04347826086956 80 | - 27.82608695652174 81 | - 3.4782608695652173 82 | - 8.695652173913043 83 | - 19.130434782608695 84 | - 36.52173913043478 85 | - 24.34782608695652 86 | - 1.7391304347826086 87 | - 5.217391304347826 88 | - 17.391304347826086 89 | - 38.26086956521739 90 | - 31.304347826086957 91 | - 6.956521739130435 92 | - 20.869565217391305 93 | - 13.91304347826087 94 | - 36.52173913043478 95 | - 19.130434782608695 96 | - 26.08695652173913 97 | - 29.565217391304348 98 | - 31.304347826086957 99 | - 19.130434782608695 100 | - 27.82608695652174 101 | - 34.78260869565217 102 | - 12.17391304347826 103 | - 34.78260869565217 104 | - 10.434782608695652 105 | - 10.434782608695652 106 | - 27.82608695652174 107 | - 20.869565217391305 108 | - 31.304347826086957 109 | - 10.434782608695652 110 | - 38.26086956521739 111 | - 19.130434782608695 112 | - 29.565217391304348 113 | - 5.217391304347826 114 | - 22.608695652173914 115 | - 26.08695652173913 116 | - 5.217391304347826 117 | - 34.78260869565217 118 | - 13.91304347826087 119 | - 20.869565217391305 120 | - 29.565217391304348 121 | - 33.04347826086956 122 | - 8.695652173913043 123 | - 29.565217391304348 124 | - 36.52173913043478 125 | - 10.434782608695652 126 | - 27.82608695652174 127 | - 40.0 128 | - 26.08695652173913 129 | - 20.869565217391305 130 | - 34.78260869565217 131 | - 31.304347826086957 132 | - 15.652173913043478 133 | - 12.17391304347826 134 | - 20.869565217391305 135 | - 8.695652173913043 136 | - 24.34782608695652 137 | - 29.565217391304348 138 | - 34.78260869565217 139 | - 17.391304347826086 140 | - 34.78260869565217 141 | - 26.08695652173913 142 | - 10.434782608695652 143 | - 15.652173913043478 144 | - 34.78260869565217 145 | - 17.391304347826086 146 | - 6.956521739130435 147 | - 36.52173913043478 148 | - 31.304347826086957 149 | - 36.52173913043478 150 | - 6.956521739130435 151 | - 24.34782608695652 152 | - 17.391304347826086 153 | - 22.608695652173914 154 | - 12.17391304347826 155 | - 36.52173913043478 156 | - 40.0 157 | - 5.217391304347826 158 | - 8.695652173913043 159 | - 34.78260869565217 160 | - 31.304347826086957 161 | - 8.695652173913043 162 | - 27.82608695652174 163 | - 29.565217391304348 164 | - 34.78260869565217 165 | - 27.82608695652174 166 | - 5.217391304347826 167 | - 29.565217391304348 168 | - 26.08695652173913 169 | - 22.608695652173914 170 | - 38.26086956521739 171 | - 24.34782608695652 172 | - 20.869565217391305 173 | - 38.26086956521739 174 | - 36.52173913043478 175 | - 38.26086956521739 176 | - 33.04347826086956 177 | - 24.34782608695652 178 | - 22.608695652173914 179 | - 17.391304347826086 180 | - 13.91304347826087 181 | - 36.52173913043478 182 | - 38.26086956521739 183 | - 19.130434782608695 184 | - 19.130434782608695 185 | - 17.391304347826086 186 | - 19.130434782608695 187 | - 26.08695652173913 188 | - 10.434782608695652 189 | - 40.0 190 | - 38.26086956521739 191 | - 19.130434782608695 192 | - 24.34782608695652 193 | - 34.78260869565217 194 | - 33.04347826086956 195 | - 13.91304347826087 196 | - 19.130434782608695 197 | - 36.52173913043478 198 | - 12.17391304347826 199 | - 1.7391304347826086 200 | - 26.08695652173913 201 | - 5.217391304347826 202 | - 38.26086956521739 203 | - 26.08695652173913 204 | - 20.869565217391305 205 | - 36.52173913043478 206 | - 10.434782608695652 207 | - 38.26086956521739 208 | - 3.4782608695652173 209 | - 29.565217391304348 210 | - 34.78260869565217 211 | - 15.652173913043478 212 | - 17.391304347826086 213 | - 12.17391304347826 214 | - 8.695652173913043 215 | - 13.91304347826087 216 | - 38.26086956521739 217 | - 22.608695652173914 218 | - 6.956521739130435 219 | - 15.652173913043478 220 | - 12.17391304347826 221 | - 36.52173913043478 222 | - 24.34782608695652 223 | - 27.82608695652174 224 | - 13.91304347826087 225 | - 17.391304347826086 226 | - 31.304347826086957 227 | - 34.78260869565217 228 | - 6.956521739130435 229 | - 15.652173913043478 230 | - 31.304347826086957 231 | - 40.0 232 | - 17.391304347826086 233 | - 15.652173913043478 234 | - 12.17391304347826 235 | - 22.608695652173914 236 | - 27.82608695652174 237 | - 17.391304347826086 238 | - 19.130434782608695 239 | - 22.608695652173914 240 | - 33.04347826086956 241 | - 17.391304347826086 242 | - 29.565217391304348 243 | - 13.91304347826087 244 | - 17.391304347826086 245 | - 15.652173913043478 246 | - 1.7391304347826086 247 | - 10.434782608695652 248 | - 40.0 249 | - 17.391304347826086 250 | - 34.78260869565217 251 | - 26.08695652173913 252 | - 34.78260869565217 253 | - 31.304347826086957 254 | - 13.91304347826087 255 | - 3.4782608695652173 256 | - 24.34782608695652 257 | - 34.78260869565217 258 | - 34.78260869565217 259 | - 40.0 260 | - 36.52173913043478 261 | - 17.391304347826086 262 | - 24.34782608695652 263 | - 13.91304347826087 264 | - 6.956521739130435 265 | - 26.08695652173913 266 | - 33.04347826086956 267 | - 15.652173913043478 268 | - 1.7391304347826086 269 | - 27.82608695652174 270 | - 38.26086956521739 271 | - 22.608695652173914 272 | - 12.17391304347826 273 | - 19.130434782608695 274 | - 22.608695652173914 275 | - 33.04347826086956 276 | - 31.304347826086957 277 | - 20.869565217391305 278 | - 36.52173913043478 279 | - 34.78260869565217 280 | - 6.956521739130435 281 | - 33.04347826086956 282 | - 22.608695652173914 283 | - 29.565217391304348 284 | - 3.4782608695652173 285 | - 17.391304347826086 286 | - 12.17391304347826 287 | - 5.217391304347826 288 | - 26.08695652173913 289 | - 33.04347826086956 290 | - 26.08695652173913 291 | - 17.391304347826086 292 | - 31.304347826086957 293 | - 33.04347826086956 294 | - 27.82608695652174 295 | - 33.04347826086956 296 | - 19.130434782608695 297 | - 31.304347826086957 298 | - 12.17391304347826 299 | - 22.608695652173914 300 | - 26.08695652173913 301 | - 6.956521739130435 302 | - 1.7391304347826086 303 | - 40.0 304 | - 26.08695652173913 305 | - 34.78260869565217 306 | - 34.78260869565217 307 | - 40.0 308 | - 27.82608695652174 309 | - 22.608695652173914 310 | - 34.78260869565217 311 | - 6.956521739130435 312 | - 12.17391304347826 313 | - 6.956521739130435 314 | - 13.91304347826087 315 | - 29.565217391304348 316 | - 40.0 317 | - 13.91304347826087 318 | - 40.0 319 | - 36.52173913043478 320 | - 27.82608695652174 321 | - 12.17391304347826 322 | - 19.130434782608695 323 | - 36.52173913043478 324 | - 20.869565217391305 325 | - 26.08695652173913 326 | - 10.434782608695652 327 | - 22.608695652173914 328 | - 22.608695652173914 329 | - 22.608695652173914 330 | - 3.4782608695652173 331 | - 8.695652173913043 332 | - 20.869565217391305 333 | - 40.0 334 | - 34.78260869565217 335 | - 3.4782608695652173 336 | - 36.52173913043478 337 | - 24.34782608695652 338 | - 6.956521739130435 339 | - 13.91304347826087 340 | - 20.869565217391305 341 | - 17.391304347826086 342 | - 22.608695652173914 343 | - 10.434782608695652 344 | - 6.956521739130435 345 | - 29.565217391304348 346 | - 34.78260869565217 347 | - 24.34782608695652 348 | - 19.130434782608695 349 | - 29.565217391304348 350 | - 19.130434782608695 351 | - 8.695652173913043 352 | - 13.91304347826087 353 | - 31.304347826086957 354 | - 3.4782608695652173 355 | - 38.26086956521739 356 | - 40.0 357 | - 38.26086956521739 358 | - 27.82608695652174 359 | - 5.217391304347826 360 | - 20.869565217391305 361 | - 31.304347826086957 362 | - 13.91304347826087 363 | - 19.130434782608695 364 | - 19.130434782608695 365 | - 36.52173913043478 366 | - 40.0 367 | - 13.91304347826087 368 | - 12.17391304347826 369 | - 8.695652173913043 370 | - 31.304347826086957 371 | - 22.608695652173914 372 | - 20.869565217391305 373 | - 34.78260869565217 374 | - 24.34782608695652 375 | - 15.652173913043478 376 | - 17.391304347826086 377 | - 38.26086956521739 378 | - 24.34782608695652 379 | - 5.217391304347826 380 | - 27.82608695652174 381 | - 29.565217391304348 382 | - 13.91304347826087 383 | - 22.608695652173914 384 | - 12.17391304347826 385 | - 38.26086956521739 386 | - 20.869565217391305 387 | - 38.26086956521739 388 | - 20.869565217391305 389 | - 31.304347826086957 390 | - 15.652173913043478 391 | - 3.4782608695652173 392 | - 17.391304347826086 393 | - 15.652173913043478 394 | - 38.26086956521739 395 | - 10.434782608695652 396 | - 33.04347826086956 397 | - 26.08695652173913 398 | - 22.608695652173914 399 | - 36.52173913043478 400 | - 31.304347826086957 401 | - 31.304347826086957 402 | - 10.434782608695652 403 | - 26.08695652173913 404 | - 24.34782608695652 405 | - 15.652173913043478 406 | - 13.91304347826087 407 | - 31.304347826086957 408 | - 33.04347826086956 409 | - 17.391304347826086 410 | - 29.565217391304348 411 | - 19.130434782608695 412 | - 26.08695652173913 413 | - 26.08695652173913 414 | - 20.869565217391305 415 | - 33.04347826086956 416 | - 33.04347826086956 417 | - 26.08695652173913 418 | - 38.26086956521739 419 | - 40.0 420 | - 29.565217391304348 421 | - 22.608695652173914 422 | - 31.304347826086957 423 | - 22.608695652173914 424 | - 19.130434782608695 425 | - 33.04347826086956 426 | - 22.608695652173914 427 | - 24.34782608695652 428 | - 24.34782608695652 429 | - 38.26086956521739 430 | - 29.565217391304348 431 | - 40.0 432 | - 12.17391304347826 433 | - 27.82608695652174 434 | - 17.391304347826086 435 | - 36.52173913043478 436 | - 15.652173913043478 437 | - 24.34782608695652 438 | - 6.956521739130435 439 | - 15.652173913043478 440 | - 13.91304347826087 441 | - 26.08695652173913 442 | - 12.17391304347826 443 | - 29.565217391304348 444 | - 10.434782608695652 445 | - 38.26086956521739 446 | - 33.04347826086956 447 | - 33.04347826086956 448 | - 34.78260869565217 449 | - 12.17391304347826 450 | - 29.565217391304348 451 | - 29.565217391304348 452 | - 20.869565217391305 453 | - 20.869565217391305 454 | - 13.91304347826087 455 | - 17.391304347826086 456 | - 8.695652173913043 457 | - 17.391304347826086 458 | - 27.82608695652174 459 | - 31.304347826086957 460 | - 8.695652173913043 461 | - 12.17391304347826 462 | - 22.608695652173914 463 | - 40.0 464 | - 10.434782608695652 465 | - 15.652173913043478 466 | - 27.82608695652174 467 | - 34.78260869565217 468 | - 27.82608695652174 469 | - 34.78260869565217 470 | - 22.608695652173914 471 | - 17.391304347826086 472 | - 24.34782608695652 473 | - 33.04347826086956 474 | - 19.130434782608695 475 | - 8.695652173913043 476 | - 22.608695652173914 477 | - 12.17391304347826 478 | - 33.04347826086956 479 | - 24.34782608695652 480 | - 8.695652173913043 481 | - 12.17391304347826 482 | - 33.04347826086956 483 | - 8.695652173913043 484 | - 19.130434782608695 485 | - 34.78260869565217 486 | - 13.91304347826087 487 | - 19.130434782608695 488 | - 29.565217391304348 489 | - 20.869565217391305 490 | - 33.04347826086956 491 | - 3.4782608695652173 492 | - 15.652173913043478 493 | - 22.608695652173914 494 | - 1.7391304347826086 495 | - 5.217391304347826 496 | - 38.26086956521739 497 | - 20.869565217391305 498 | - 1.7391304347826086 499 | - 31.304347826086957 500 | - 6.956521739130435 501 | - 19.130434782608695 502 | - 36.52173913043478 503 | - 6.956521739130435 504 | - 10.434782608695652 505 | - 13.91304347826087 506 | - 40.0 507 | - 5.217391304347826 508 | - 33.04347826086956 509 | - 31.304347826086957 510 | - 5.217391304347826 511 | - 38.26086956521739 512 | - 24.34782608695652 513 | - 3.4782608695652173 514 | - 22.608695652173914 515 | - 10.434782608695652 516 | - 36.52173913043478 517 | - 34.78260869565217 518 | - 31.304347826086957 519 | - 24.34782608695652 520 | - 6.956521739130435 521 | - 29.565217391304348 522 | - 24.34782608695652 523 | - 17.391304347826086 524 | - 15.652173913043478 525 | - 40.0 526 | - 24.34782608695652 527 | - 19.130434782608695 528 | - 19.130434782608695 529 | - 40.0 530 | - 29.565217391304348 531 | - 24.34782608695652 532 | - 33.04347826086956 533 | - 27.82608695652174 534 | - 36.52173913043478 535 | - 33.04347826086956 536 | - 31.304347826086957 537 | - 15.652173913043478 538 | - 15.652173913043478 539 | - 13.91304347826087 540 | - 12.17391304347826 541 | - 29.565217391304348 542 | - 40.0 543 | - 38.26086956521739 544 | - 36.52173913043478 545 | - 1.7391304347826086 546 | - 29.565217391304348 547 | - 3.4782608695652173 548 | - 38.26086956521739 549 | - 6.956521739130435 550 | - 36.52173913043478 551 | - 10.434782608695652 552 | - 8.695652173913043 553 | - 5.217391304347826 554 | - 5.217391304347826 555 | - 22.608695652173914 556 | - 15.652173913043478 557 | - 8.695652173913043 558 | - 33.04347826086956 559 | - 26.08695652173913 560 | - 36.52173913043478 561 | - 26.08695652173913 562 | - 27.82608695652174 563 | - 24.34782608695652 564 | - 5.217391304347826 565 | - 38.26086956521739 566 | - 20.869565217391305 567 | - 38.26086956521739 568 | - 34.78260869565217 569 | - 40.0 570 | - 17.391304347826086 571 | - 27.82608695652174 572 | - 13.91304347826087 573 | - 33.04347826086956 574 | - 34.78260869565217 575 | - 6.956521739130435 576 | - 27.82608695652174 577 | - 26.08695652173913 578 | - 6.956521739130435 579 | - 40.0 580 | - 13.91304347826087 581 | - 8.695652173913043 582 | - 40.0 583 | - 36.52173913043478 584 | - 36.52173913043478 585 | - 29.565217391304348 586 | - 19.130434782608695 587 | - 26.08695652173913 588 | - 8.695652173913043 589 | - 20.869565217391305 590 | - 15.652173913043478 591 | - 15.652173913043478 592 | - 20.869565217391305 593 | - 13.91304347826087 594 | - 40.0 595 | - 8.695652173913043 596 | - 26.08695652173913 597 | - 27.82608695652174 598 | - 13.91304347826087 599 | - 20.869565217391305 600 | - 24.34782608695652 601 | - 15.652173913043478 602 | - 40.0 603 | - 27.82608695652174 604 | - 20.869565217391305 605 | - 22.608695652173914 606 | - 34.78260869565217 607 | - 24.34782608695652 608 | - 8.695652173913043 609 | - 29.565217391304348 610 | - 12.17391304347826 611 | - 27.82608695652174 612 | y: 613 | - -12.800506834585123 614 | - 10.105663290461937 615 | - 11.453085062523531 616 | - -4.715976202215572 617 | - 11.453085062523531 618 | - -0.673710886030797 619 | - -8.758241518400347 620 | - -3.3685544301539814 621 | - -15.495350378708308 622 | - -0.673710886030797 623 | - -4.715976202215572 624 | - 15.495350378708306 625 | - 14.147928606646719 626 | - -3.3685544301539814 627 | - 4.715976202215572 628 | - -12.800506834585123 629 | - -4.715976202215572 630 | - 2.0211326580923874 631 | - 11.453085062523531 632 | - -2.0211326580923874 633 | - 2.0211326580923874 634 | - -3.3685544301539814 635 | - -16.8427721507699 636 | - -8.758241518400347 637 | - 7.410819746338756 638 | - 7.410819746338756 639 | - 6.063397974277162 640 | - -18.19019392283149 641 | - -7.410819746338756 642 | - -11.453085062523531 643 | - 19.53761569489308 644 | - 14.147928606646719 645 | - 15.495350378708306 646 | - -10.10566329046194 647 | - -3.3685544301539814 648 | - 3.3685544301539814 649 | - 10.105663290461937 650 | - 4.715976202215572 651 | - -16.8427721507699 652 | - 20.885037466954675 653 | - -4.715976202215572 654 | - -10.10566329046194 655 | - -0.673710886030797 656 | - 16.8427721507699 657 | - 15.495350378708306 658 | - 11.453085062523531 659 | - -10.10566329046194 660 | - -7.410819746338756 661 | - -16.8427721507699 662 | - 0.673710886030797 663 | - -12.800506834585123 664 | - -12.800506834585123 665 | - 3.3685544301539814 666 | - -19.537615694893084 667 | - 8.75824151840035 668 | - 0.673710886030797 669 | - -18.19019392283149 670 | - 0.673710886030797 671 | - -7.410819746338756 672 | - 11.453085062523531 673 | - 15.495350378708306 674 | - -4.715976202215572 675 | - 10.105663290461937 676 | - 0.673710886030797 677 | - -12.800506834585123 678 | - -15.495350378708308 679 | - -4.715976202215572 680 | - -20.885037466954675 681 | - 10.105663290461937 682 | - -2.0211326580923874 683 | - 3.3685544301539814 684 | - -18.19019392283149 685 | - -6.063397974277162 686 | - 11.453085062523531 687 | - -8.758241518400347 688 | - -0.673710886030797 689 | - 10.105663290461937 690 | - -7.410819746338756 691 | - 3.3685544301539814 692 | - -3.3685544301539814 693 | - 0.673710886030797 694 | - -2.0211326580923874 695 | - -3.3685544301539814 696 | - 15.495350378708306 697 | - -2.0211326580923874 698 | - 3.3685544301539814 699 | - -10.10566329046194 700 | - -11.453085062523531 701 | - -16.8427721507699 702 | - 3.3685544301539814 703 | - 7.410819746338756 704 | - -2.0211326580923874 705 | - 3.3685544301539814 706 | - 4.715976202215572 707 | - -0.673710886030797 708 | - -4.715976202215572 709 | - 19.53761569489308 710 | - 6.063397974277162 711 | - -15.495350378708308 712 | - 10.105663290461937 713 | - -14.147928606646715 714 | - -7.410819746338756 715 | - 15.495350378708306 716 | - -2.0211326580923874 717 | - -19.537615694893084 718 | - 0.673710886030797 719 | - 3.3685544301539814 720 | - -10.10566329046194 721 | - -0.673710886030797 722 | - 7.410819746338756 723 | - 10.105663290461937 724 | - 10.105663290461937 725 | - 11.453085062523531 726 | - -6.063397974277162 727 | - -3.3685544301539814 728 | - -4.715976202215572 729 | - 2.0211326580923874 730 | - 18.190193922831494 731 | - -15.495350378708308 732 | - -18.19019392283149 733 | - -3.3685544301539814 734 | - 2.0211326580923874 735 | - 4.715976202215572 736 | - -11.453085062523531 737 | - 15.495350378708306 738 | - -10.10566329046194 739 | - -12.800506834585123 740 | - -18.19019392283149 741 | - -18.19019392283149 742 | - -14.147928606646715 743 | - 7.410819746338756 744 | - -11.453085062523531 745 | - -3.3685544301539814 746 | - -6.063397974277162 747 | - 6.063397974277162 748 | - 16.8427721507699 749 | - -8.758241518400347 750 | - 7.410819746338756 751 | - -12.800506834585123 752 | - 19.53761569489308 753 | - 6.063397974277162 754 | - -8.758241518400347 755 | - 2.0211326580923874 756 | - 3.3685544301539814 757 | - 8.75824151840035 758 | - -7.410819746338756 759 | - 7.410819746338756 760 | - 14.147928606646719 761 | - -7.410819746338756 762 | - -8.758241518400347 763 | - -14.147928606646715 764 | - -19.537615694893084 765 | - 4.715976202215572 766 | - 2.0211326580923874 767 | - 19.53761569489308 768 | - -4.715976202215572 769 | - -11.453085062523531 770 | - -14.147928606646715 771 | - 0.673710886030797 772 | - -0.673710886030797 773 | - 7.410819746338756 774 | - -6.063397974277162 775 | - -6.063397974277162 776 | - -12.800506834585123 777 | - -6.063397974277162 778 | - -11.453085062523531 779 | - 8.75824151840035 780 | - -12.800506834585123 781 | - -16.8427721507699 782 | - 18.190193922831494 783 | - 10.105663290461937 784 | - 3.3685544301539814 785 | - -14.147928606646715 786 | - 4.715976202215572 787 | - 6.063397974277162 788 | - -3.3685544301539814 789 | - 18.190193922831494 790 | - -16.8427721507699 791 | - -10.10566329046194 792 | - -15.495350378708308 793 | - 19.53761569489308 794 | - -3.3685544301539814 795 | - 16.8427721507699 796 | - -2.0211326580923874 797 | - 3.3685544301539814 798 | - -10.10566329046194 799 | - 2.0211326580923874 800 | - -18.19019392283149 801 | - -6.063397974277162 802 | - -15.495350378708308 803 | - -11.453085062523531 804 | - 18.190193922831494 805 | - 7.410819746338756 806 | - -15.495350378708308 807 | - 12.800506834585125 808 | - 10.105663290461937 809 | - -6.063397974277162 810 | - 4.715976202215572 811 | - -2.0211326580923874 812 | - 4.715976202215572 813 | - 11.453085062523531 814 | - -3.3685544301539814 815 | - -6.063397974277162 816 | - -6.063397974277162 817 | - 11.453085062523531 818 | - -8.758241518400347 819 | - -0.673710886030797 820 | - -10.10566329046194 821 | - -0.673710886030797 822 | - 8.75824151840035 823 | - 8.75824151840035 824 | - -15.495350378708308 825 | - 3.3685544301539814 826 | - 4.715976202215572 827 | - 16.8427721507699 828 | - 4.715976202215572 829 | - -3.3685544301539814 830 | - -6.063397974277162 831 | - 15.495350378708306 832 | - 12.800506834585125 833 | - -0.673710886030797 834 | - 8.75824151840035 835 | - -12.800506834585123 836 | - -3.3685544301539814 837 | - 16.8427721507699 838 | - 6.063397974277162 839 | - -8.758241518400347 840 | - -14.147928606646715 841 | - 11.453085062523531 842 | - -12.800506834585123 843 | - 11.453085062523531 844 | - 11.453085062523531 845 | - 3.3685544301539814 846 | - 6.063397974277162 847 | - 11.453085062523531 848 | - -8.758241518400347 849 | - 0.673710886030797 850 | - -8.758241518400347 851 | - 10.105663290461937 852 | - 4.715976202215572 853 | - 6.063397974277162 854 | - 8.75824151840035 855 | - -11.453085062523531 856 | - 2.0211326580923874 857 | - 0.673710886030797 858 | - -8.758241518400347 859 | - 15.495350378708306 860 | - 14.147928606646719 861 | - 16.8427721507699 862 | - -15.495350378708308 863 | - -19.537615694893084 864 | - -7.410819746338756 865 | - 16.8427721507699 866 | - -6.063397974277162 867 | - 10.105663290461937 868 | - 8.75824151840035 869 | - 7.410819746338756 870 | - 14.147928606646719 871 | - -19.537615694893084 872 | - 0.673710886030797 873 | - -18.19019392283149 874 | - 14.147928606646719 875 | - 2.0211326580923874 876 | - -19.537615694893084 877 | - 20.885037466954675 878 | - 15.495350378708306 879 | - -6.063397974277162 880 | - -14.147928606646715 881 | - 12.800506834585125 882 | - -14.147928606646715 883 | - 2.0211326580923874 884 | - 2.0211326580923874 885 | - 19.53761569489308 886 | - 4.715976202215572 887 | - 6.063397974277162 888 | - 2.0211326580923874 889 | - 6.063397974277162 890 | - 4.715976202215572 891 | - 6.063397974277162 892 | - 16.8427721507699 893 | - -10.10566329046194 894 | - 14.147928606646719 895 | - 4.715976202215572 896 | - -12.800506834585123 897 | - -7.410819746338756 898 | - 7.410819746338756 899 | - 15.495350378708306 900 | - 12.800506834585125 901 | - 4.715976202215572 902 | - -4.715976202215572 903 | - -10.10566329046194 904 | - -16.8427721507699 905 | - -2.0211326580923874 906 | - -2.0211326580923874 907 | - -7.410819746338756 908 | - 2.0211326580923874 909 | - -0.673710886030797 910 | - 0.673710886030797 911 | - 11.453085062523531 912 | - -10.10566329046194 913 | - 6.063397974277162 914 | - -19.537615694893084 915 | - -14.147928606646715 916 | - -2.0211326580923874 917 | - 14.147928606646719 918 | - 20.885037466954675 919 | - 18.190193922831494 920 | - 8.75824151840035 921 | - 0.673710886030797 922 | - 10.105663290461937 923 | - -10.10566329046194 924 | - 0.673710886030797 925 | - -6.063397974277162 926 | - -14.147928606646715 927 | - 6.063397974277162 928 | - 0.673710886030797 929 | - -20.885037466954675 930 | - 7.410819746338756 931 | - 6.063397974277162 932 | - 12.800506834585125 933 | - -16.8427721507699 934 | - -4.715976202215572 935 | - 8.75824151840035 936 | - 18.190193922831494 937 | - -12.800506834585123 938 | - 16.8427721507699 939 | - 7.410819746338756 940 | - 10.105663290461937 941 | - 8.75824151840035 942 | - -4.715976202215572 943 | - -2.0211326580923874 944 | - 2.0211326580923874 945 | - -15.495350378708308 946 | - 3.3685544301539814 947 | - 16.8427721507699 948 | - 11.453085062523531 949 | - -11.453085062523531 950 | - -8.758241518400347 951 | - -10.10566329046194 952 | - -7.410819746338756 953 | - -6.063397974277162 954 | - 8.75824151840035 955 | - -6.063397974277162 956 | - -3.3685544301539814 957 | - 11.453085062523531 958 | - 4.715976202215572 959 | - -0.673710886030797 960 | - -18.19019392283149 961 | - 10.105663290461937 962 | - 7.410819746338756 963 | - -16.8427721507699 964 | - 18.190193922831494 965 | - -7.410819746338756 966 | - 0.673710886030797 967 | - -15.495350378708308 968 | - -14.147928606646715 969 | - -4.715976202215572 970 | - -0.673710886030797 971 | - -15.495350378708308 972 | - -20.885037466954675 973 | - 12.800506834585125 974 | - -10.10566329046194 975 | - 18.190193922831494 976 | - 20.885037466954675 977 | - 12.800506834585125 978 | - -14.147928606646715 979 | - -3.3685544301539814 980 | - 12.800506834585125 981 | - -15.495350378708308 982 | - 15.495350378708306 983 | - -14.147928606646715 984 | - 15.495350378708306 985 | - -6.063397974277162 986 | - 6.063397974277162 987 | - 2.0211326580923874 988 | - 7.410819746338756 989 | - -19.537615694893084 990 | - 2.0211326580923874 991 | - -0.673710886030797 992 | - 18.190193922831494 993 | - -7.410819746338756 994 | - -15.495350378708308 995 | - -12.800506834585123 996 | - -4.715976202215572 997 | - 6.063397974277162 998 | - -2.0211326580923874 999 | - 4.715976202215572 1000 | - 12.800506834585125 1001 | - -10.10566329046194 1002 | - -8.758241518400347 1003 | - -15.495350378708308 1004 | - -7.410819746338756 1005 | - -15.495350378708308 1006 | - -14.147928606646715 1007 | - 3.3685544301539814 1008 | - 3.3685544301539814 1009 | - -0.673710886030797 1010 | - 0.673710886030797 1011 | - -18.19019392283149 1012 | - 4.715976202215572 1013 | - 12.800506834585125 1014 | - 14.147928606646719 1015 | - 14.147928606646719 1016 | - -11.453085062523531 1017 | - -4.715976202215572 1018 | - -12.800506834585123 1019 | - -6.063397974277162 1020 | - -18.19019392283149 1021 | - -8.758241518400347 1022 | - -11.453085062523531 1023 | - 16.8427721507699 1024 | - -16.8427721507699 1025 | - 16.8427721507699 1026 | - 19.53761569489308 1027 | - 18.190193922831494 1028 | - 12.800506834585125 1029 | - 10.105663290461937 1030 | - 8.75824151840035 1031 | - -0.673710886030797 1032 | - 2.0211326580923874 1033 | - 8.75824151840035 1034 | - -16.8427721507699 1035 | - -6.063397974277162 1036 | - 2.0211326580923874 1037 | - -7.410819746338756 1038 | - 8.75824151840035 1039 | - -12.800506834585123 1040 | - 8.75824151840035 1041 | - 15.495350378708306 1042 | - 16.8427721507699 1043 | - 0.673710886030797 1044 | - 12.800506834585125 1045 | - -0.673710886030797 1046 | - 18.190193922831494 1047 | - 14.147928606646719 1048 | - 2.0211326580923874 1049 | - -0.673710886030797 1050 | - -4.715976202215572 1051 | - -3.3685544301539814 1052 | - 6.063397974277162 1053 | - 14.147928606646719 1054 | - 8.75824151840035 1055 | - 10.105663290461937 1056 | - 20.885037466954675 1057 | - -20.885037466954675 1058 | - -19.537615694893084 1059 | - 3.3685544301539814 1060 | - 6.063397974277162 1061 | - 0.673710886030797 1062 | - -2.0211326580923874 1063 | - -12.800506834585123 1064 | - -0.673710886030797 1065 | - 10.105663290461937 1066 | - 6.063397974277162 1067 | - 14.147928606646719 1068 | - 16.8427721507699 1069 | - -8.758241518400347 1070 | - -11.453085062523531 1071 | - -12.800506834585123 1072 | - 8.75824151840035 1073 | - -2.0211326580923874 1074 | - 0.673710886030797 1075 | - 0.673710886030797 1076 | - -15.495350378708308 1077 | - 19.53761569489308 1078 | - -3.3685544301539814 1079 | - 0.673710886030797 1080 | - 20.885037466954675 1081 | - -4.715976202215572 1082 | - 18.190193922831494 1083 | - 12.800506834585125 1084 | - -14.147928606646715 1085 | - 14.147928606646719 1086 | - -7.410819746338756 1087 | - -18.19019392283149 1088 | - -8.758241518400347 1089 | - -12.800506834585123 1090 | - -2.0211326580923874 1091 | - -14.147928606646715 1092 | - 10.105663290461937 1093 | - -0.673710886030797 1094 | - 8.75824151840035 1095 | - -14.147928606646715 1096 | - -20.885037466954675 1097 | - 7.410819746338756 1098 | - 8.75824151840035 1099 | - 7.410819746338756 1100 | - 15.495350378708306 1101 | - 14.147928606646719 1102 | - -2.0211326580923874 1103 | - 4.715976202215572 1104 | - 12.800506834585125 1105 | - 3.3685544301539814 1106 | - -8.758241518400347 1107 | - 18.190193922831494 1108 | - -8.758241518400347 1109 | - -3.3685544301539814 1110 | - 14.147928606646719 1111 | - -4.715976202215572 1112 | - -18.19019392283149 1113 | - -10.10566329046194 1114 | - -2.0211326580923874 1115 | - 4.715976202215572 1116 | - 6.063397974277162 1117 | - 10.105663290461937 1118 | - -11.453085062523531 1119 | - -11.453085062523531 1120 | - -4.715976202215572 1121 | - -10.10566329046194 1122 | - -7.410819746338756 1123 | - -7.410819746338756 1124 | - 7.410819746338756 1125 | - -3.3685544301539814 1126 | - 7.410819746338756 1127 | - -2.0211326580923874 1128 | - -11.453085062523531 1129 | - -6.063397974277162 1130 | - -16.8427721507699 1131 | - 11.453085062523531 1132 | - 3.3685544301539814 1133 | - 7.410819746338756 1134 | - 12.800506834585125 1135 | - 12.800506834585125 1136 | - -11.453085062523531 1137 | - -14.147928606646715 1138 | - -4.715976202215572 1139 | - -8.758241518400347 1140 | - 4.715976202215572 1141 | - 12.800506834585125 1142 | - 3.3685544301539814 1143 | - -4.715976202215572 1144 | - 14.147928606646719 1145 | - 19.53761569489308 1146 | - -8.758241518400347 1147 | - -2.0211326580923874 1148 | - 16.8427721507699 1149 | - -16.8427721507699 1150 | - 11.453085062523531 1151 | - -2.0211326580923874 1152 | - -19.537615694893084 1153 | - -16.8427721507699 1154 | - -12.800506834585123 1155 | - -16.8427721507699 1156 | - -0.673710886030797 1157 | - 4.715976202215572 1158 | - 2.0211326580923874 1159 | - 6.063397974277162 1160 | - 4.715976202215572 1161 | - -18.19019392283149 1162 | - -7.410819746338756 1163 | - 6.063397974277162 1164 | - 8.75824151840035 1165 | - -7.410819746338756 1166 | - 14.147928606646719 1167 | - -2.0211326580923874 1168 | - -2.0211326580923874 1169 | - 0.673710886030797 1170 | - 2.0211326580923874 1171 | - 15.495350378708306 1172 | - 7.410819746338756 1173 | - -6.063397974277162 1174 | - 19.53761569489308 1175 | - 6.063397974277162 1176 | - -20.885037466954675 1177 | - 3.3685544301539814 1178 | - -19.537615694893084 1179 | - 19.53761569489308 1180 | - 11.453085062523531 1181 | - -6.063397974277162 1182 | - -11.453085062523531 1183 | - 3.3685544301539814 1184 | - -10.10566329046194 1185 | - 12.800506834585125 1186 | - 12.800506834585125 1187 | - -10.10566329046194 1188 | - -8.758241518400347 1189 | - 7.410819746338756 1190 | - -6.063397974277162 1191 | - -0.673710886030797 1192 | - 2.0211326580923874 1193 | - 18.190193922831494 1194 | - 11.453085062523531 1195 | - 8.75824151840035 1196 | - -7.410819746338756 1197 | - 15.495350378708306 1198 | - -4.715976202215572 1199 | - 10.105663290461937 1200 | - -7.410819746338756 1201 | - -0.673710886030797 1202 | - -3.3685544301539814 1203 | - 12.800506834585125 1204 | - 15.495350378708306 1205 | - -3.3685544301539814 1206 | - 11.453085062523531 1207 | - -11.453085062523531 1208 | - 16.8427721507699 1209 | - -11.453085062523531 1210 | - -11.453085062523531 1211 | - -15.495350378708308 1212 | - 3.3685544301539814 1213 | - -14.147928606646715 1214 | - -3.3685544301539814 1215 | - 14.147928606646719 1216 | - -11.453085062523531 1217 | - -10.10566329046194 1218 | - 0.673710886030797 1219 | - -8.758241518400347 1220 | - -16.8427721507699 1221 | - -4.715976202215572 1222 | - 2.0211326580923874 1223 | -------------------------------------------------------------------------------- /config/params.yaml: -------------------------------------------------------------------------------- 1 | # run settings 2 | run: 3 | resolution: [256,256] #[width,height] in pixels 4 | view_angle: 16 #in degrees, horizontal view angle 5 | origin: [0,0] 6 | min_angle: 0.001 #in degrees, minimal eccentricity 7 | fps: 35 8 | gpu: 0 #if using cuda, enter gpu nr here (e.g. 0) 9 | print_stats: False #print simulator values for sanity check 10 | seed: 42 11 | dtype: float32 12 | use_gaussian_lut: False # Whether to approximate Gaussian activation with a 13 | # look-up table. 14 | batch_size: 0 # Set to zero when simulator is not used for computational optimization 15 | 16 | # display specs to accurately diplay sizes in dva 17 | display: 18 | screen_resolution: [1920,1080] #width & height in pixels 19 | #screen_size: [294,166] #width & height in mm 20 | screen_diagonal: 13.3 #inches 21 | dist_to_screen: 600 # eyes to screen in mm 22 | 23 | # for sampling from images/video 24 | sampling: 25 | sampling_method: receptive_fields #receptive_fields or center 26 | RF_size: 0.5 # millimeters of cortical surface (when sampling receptive fields) 27 | stimulus_scale: 1.e-4 # Only used when the sample_stimulus method is called with 'rescale=True'. The default behaviour 28 | # is no scaling (i.e., the stim amplitude equals the intensity of the sampled image). 29 | 30 | # settings for electrode coords to visual field coords 31 | cortex_model: 32 | model: dipole 33 | k: 17.3 34 | a: 0.75 35 | b: 120 36 | alpha: 0.95 37 | dropout_rate: 0.2 38 | noise_scale: 0.4 39 | 40 | # habituation and other temporal dynamics 41 | temporal_dynamics: 42 | trace_increase_rate: 13.95528162 # how much the trace increases when there is input, per second 43 | activation_decay_per_second: 0.00012340980408667956 # The decay of tissue activation per second 44 | trace_decay_per_second: 0.99949191 # The decay of the memory trace, per second 45 | 46 | # current strength effect on size (Bosking et al., 2017), 47 | size: 48 | size_equation: sqrt #which equation to use for current->size computations. sqrt or sigmoid 49 | MD: 0.7 # predicted maximum diameter of activated cortex in mm 50 | I_half: 40 # mu-A 51 | slope_size: 0.08 # slope of size saturation curve in mm/mu-A 52 | current_spread: 675.e-6 #A/mm2 53 | radius_to_sigma: 0.5 #circle to gaussian factor, sigma = r/2 54 | 55 | # sigmoid on activation 56 | brightness_saturation: 57 | cps_half: 1.057631326853325e-07 # calibrated on fig. 6A Fernández et al., (2021) 58 | slope_brightness: 19152642.500946816 # calibrated on fig. 6A/B Fernández et al., (2021) 59 | 60 | # Stimulation threshold 61 | thresholding: 62 | use_threshold: True 63 | rheobase: 23.9e-6 # The minimal current (Ampere) for infinite stimulation duration. Is used as the constant leak current. 64 | activation_threshold: 9.141886000943878e-08 # Threshold of tissue activation for the perception of phosphenes 65 | activation_threshold_sd: 6.715877869833961e-08 # Standard deviation of the tissue activation threshold (for random initialization) 66 | 67 | # Pulse width (pw), frequency (freq) default values, in case they aren't specified in the input 68 | default_stim: 69 | relative_stim_duration: 1 # range: [0-1]. stim_duration = rel_stim_dur * frame_duration 70 | pw_default: 170.e-6 #Seconds 71 | freq_default: 300 #Hertz 72 | 73 | # Gabor filters 74 | gabor: 75 | gabor_filtering: False 76 | gamma: 1.5 77 | -------------------------------------------------------------------------------- /dynaphos/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/dynaphos/__init__.py -------------------------------------------------------------------------------- /dynaphos/cortex_models.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import torch 3 | from typing import Optional, Tuple, Callable, Union 4 | 5 | import numpy as np 6 | 7 | from dynaphos.utils import (Map, cartesian_to_complex, polar_to_complex, 8 | complex_to_polar) 9 | 10 | 11 | def get_visual_field_coordinates_from_cortex( 12 | params: dict, coordinates_cortex: Optional[Map] = None, 13 | rng: Optional[np.random.Generator] = None) -> Map: 14 | """Map electrode locations from cortex to visual field. 15 | 16 | :param params: Parameters for visuotopic model. 17 | :param coordinates_cortex: Locations of electrodes on a cortex map. 18 | :param rng: Numpy random number generator. 19 | :return: Location of electrodes / phosphenes in the visual field. 20 | """ 21 | if coordinates_cortex is None: 22 | coordinates_cortex = get_cortex_coordinates_grid(params, 32, 32, 23 | x_max=40) 24 | 25 | x, y = coordinates_cortex.cartesian 26 | x, y = add_noise(x, y, params['noise_scale'], rng) 27 | x, y = add_dropout(x, y, params['dropout_rate'], rng) 28 | 29 | cortex_to_visual_field = get_mapping_from_cortex_to_visual_field(params) 30 | z = cortex_to_visual_field(cartesian_to_complex(x, y)) 31 | z = remove_out_of_view(z) 32 | 33 | return Map(z=z).flip(hor=True, vert=True) # Flip x and y-coordinates to account for upside-down orientation of visual 34 | 35 | 36 | def get_visual_field_coordinates_from_cortex_full( 37 | params: dict, coordinates_cortex: Optional[Map] = None, 38 | rng: Optional[np.random.Generator] = None) -> Map: 39 | """Initialize phosphene locations in the full field of view. 40 | 41 | :param params: dictionary with the several parameters in subdictionaries. 42 | :param coordinates_cortex: Visuotopic map of with electrode locations on 43 | cortex. 44 | If None, default coordinates will be used. 45 | :param rng: Numpy random number generator. 46 | :return: Phosphene locations. 47 | """ 48 | args = (params, coordinates_cortex, rng) 49 | r_left, phi_left = get_visual_field_coordinates_from_cortex(*args).polar 50 | r_right, phi_right = get_visual_field_coordinates_from_cortex(*args).polar 51 | r = np.concatenate([r_left, r_right]) 52 | phi = np.concatenate([phi_left, np.pi - phi_right]) 53 | return Map(r=r, phi=phi) 54 | 55 | 56 | def get_visual_field_coordinates_probabilistically( 57 | params: dict, n_phosphenes: int, 58 | rng: Optional[np.random.Generator] = None) -> Map: 59 | """Generate a number of phosphene locations probabilistically. 60 | 61 | :param params: Model parameters. 62 | :param n_phosphenes: Number of phosphenes. 63 | :param rng: Numpy random number generator. 64 | :return: Polar coordinates of n_phosphenes phosphenes. 65 | """ 66 | if rng is None: 67 | rng = np.random.default_rng() 68 | 69 | max_r = params['run']['view_angle'] / 2 70 | min_r = params['run']['min_angle'] 71 | 72 | valid_ecc = np.linspace(min_r, max_r, 1000) 73 | weights = get_cortical_magnification(valid_ecc, params['cortex_model']) 74 | 75 | probs = weights / np.sum(weights) 76 | r = rng.choice(valid_ecc, size=n_phosphenes, replace=True, p=probs) 77 | phi = 2 * np.pi * rng.random(n_phosphenes) 78 | 79 | return Map(r=r, phi=phi) 80 | 81 | 82 | def get_visual_field_coordinates_grid() -> Map: 83 | ecc_range = np.arange(0, 90, 1) 84 | ang_range = np.linspace(-np.pi / 2, np.pi / 2, 10) 85 | r, phi = np.meshgrid(ecc_range, ang_range) 86 | return Map(r=r.ravel(), phi=phi.ravel()) 87 | 88 | 89 | def get_cortex_coordinates_grid(params: dict, n_electrodes_x: int, 90 | n_electrodes_y: int, 91 | x_max: Optional[int] = None) -> Map: 92 | coordinates = get_cortex_coordinates_default(params) 93 | x, y = coordinates.cartesian 94 | x_min, x_max = np.min(x), x_max or np.max(x) 95 | y_min, y_max = np.min(y), np.max(y) 96 | xrange = np.linspace(x_min, x_max, n_electrodes_x) 97 | yrange = np.linspace(y_min, y_max, n_electrodes_y) 98 | x, y = np.meshgrid(xrange, yrange) 99 | 100 | return Map(x.ravel(), y.ravel()) 101 | 102 | 103 | def get_cortex_coordinates_default(params: dict) -> Map: 104 | """Generate cortical map. 105 | 106 | :return: Cortical coordinates. 107 | """ 108 | coordinates_visual_field = get_visual_field_coordinates_grid() 109 | visual_field_to_cortex = get_mapping_from_visual_field_to_cortex(params) 110 | z = visual_field_to_cortex(coordinates_visual_field.complex) 111 | return Map(z=z) 112 | 113 | 114 | def get_mapping_from_visual_field_to_cortex(params: dict) -> Callable: 115 | mapping_model = params['model'] 116 | a = params['a'] 117 | b = params['b'] 118 | k = params['k'] 119 | alpha = params['alpha'] 120 | if mapping_model == 'monopole': 121 | def f(z): return k * np.log(1 + z / a) 122 | elif mapping_model == 'dipole': 123 | def f(z): return k * np.log(b * (z + a) / (a * (z + b))) 124 | elif mapping_model == 'wedge-dipole': 125 | def wedge(r, phi): return polar_to_complex(r, alpha * phi) 126 | def dipole(z): return k * np.log(b * (z + a) / (a * (z + b))) 127 | def f(z): return dipole(wedge(*complex_to_polar(z))) 128 | else: 129 | raise NotImplementedError 130 | return f 131 | 132 | 133 | def get_mapping_from_cortex_to_visual_field(params: dict) -> Callable: 134 | mapping_model = params['model'] 135 | a = params['a'] 136 | b = params['b'] 137 | k = params['k'] 138 | alpha = params['alpha'] 139 | if mapping_model == 'monopole': 140 | def f(w): return a * np.exp(w / k) - a 141 | elif mapping_model == 'dipole': 142 | def f(w): 143 | e = np.exp(w / k) 144 | return a * b * (e - 1) / (b - a * e) 145 | elif mapping_model == 'wedge-dipole': 146 | def wedge_inverse(z): 147 | r, phi = complex_to_polar(z) 148 | return polar_to_complex(r, phi / alpha) 149 | 150 | def dipole_inverse(w): 151 | e = np.exp(w / k) 152 | return a * b * (e - 1) / (b - a * e) 153 | 154 | def f(w): return wedge_inverse(dipole_inverse(w)) 155 | else: 156 | raise NotImplementedError 157 | return f 158 | 159 | 160 | def get_cortical_magnification( 161 | r: Union[np.ndarray, torch.Tensor], 162 | params: dict) -> Union[np.ndarray, torch.Tensor]: 163 | mapping_model = params['model'] 164 | a = params['a'] 165 | b = params['b'] 166 | k = params['k'] 167 | if mapping_model == 'monopole': 168 | return k / (r + a) 169 | if mapping_model in ['dipole', 'wedge-dipole']: 170 | return k * (1 / (r + a) - 1 / (r + b)) 171 | raise NotImplementedError 172 | 173 | 174 | def remove_out_of_view(z: np.ndarray) -> np.ndarray: 175 | r, phi = complex_to_polar(z) 176 | 177 | z = z[(r >= 0) & (r <= 90) & (phi > -np.pi / 2) & (phi < np.pi / 2)] 178 | 179 | logging.info(f"Removed {len(r) - len(z)} of {len(r)} phosphene locations.") 180 | 181 | return z 182 | 183 | 184 | def add_noise(x: np.ndarray, y: np.ndarray, noise_scale: Optional[float] = 0., 185 | rng: Optional[np.random.Generator] = None) -> Tuple[np.ndarray, 186 | np.ndarray]: 187 | if rng is None: 188 | rng = np.random.default_rng() 189 | 190 | noise = rng.normal(scale=noise_scale, size=(2, len(x))) 191 | 192 | return x + noise[0], y + noise[1] 193 | 194 | 195 | def add_dropout(x: np.ndarray, y: np.ndarray, 196 | dropout_rate: Optional[float] = 0., 197 | rng: Optional[np.random.Generator] = None 198 | ) -> Tuple[np.ndarray, np.ndarray]: 199 | if rng is None: 200 | rng = np.random.default_rng() 201 | 202 | n = len(x) 203 | active = rng.choice(np.arange(n), int(n * (1 - dropout_rate)), 204 | replace=False) 205 | 206 | return x[active], y[active] 207 | -------------------------------------------------------------------------------- /dynaphos/image_processing.py: -------------------------------------------------------------------------------- 1 | import torch 2 | from typing import Optional, Union 3 | 4 | import cv2 5 | import numpy as np 6 | 7 | 8 | def canny_processor(frame: np.ndarray, threshold_low: float, 9 | threshold_high: float) -> np.ndarray: 10 | return cv2.Canny(frame, threshold_low, threshold_high) 11 | 12 | 13 | def sobel_processor(frame: np.ndarray) -> np.ndarray: 14 | kwargs = dict(ksize=3, scale=1, delta=0, borderType=cv2.BORDER_DEFAULT) 15 | grad_x = cv2.Sobel(frame, cv2.CV_16S, 1, 0, **kwargs) 16 | grad_y = cv2.Sobel(frame, cv2.CV_16S, 0, 1, **kwargs) 17 | xy = np.stack([grad_x, grad_y]) 18 | grad = np.linalg.norm(xy, axis=0) 19 | return grad 20 | 21 | 22 | def to_n_dim(image: Union[np.ndarray, torch.Tensor], n: Optional[int] = 3 23 | ) -> Union[np.ndarray, torch.Tensor]: 24 | while image.ndim < n: 25 | if isinstance(image, torch.Tensor): 26 | image = torch.unsqueeze(image, 0) 27 | else: 28 | image = np.expand_dims(image, 0) 29 | return image 30 | 31 | 32 | def scale_image(image: Union[np.ndarray, torch.Tensor], 33 | f: Optional[float] = None, use_max: Optional[bool] = False 34 | ) -> Union[np.ndarray, torch.Tensor]: 35 | if use_max: 36 | m = np.max if isinstance(image, np.ndarray) else torch.max 37 | image = image / m(image) 38 | if f is not None: 39 | image = image * f 40 | return image 41 | -------------------------------------------------------------------------------- /dynaphos/plotting.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from matplotlib import pyplot as plt 4 | 5 | from dynaphos.cortex_models import get_cortex_coordinates_default, get_cortex_coordinates_grid 6 | 7 | 8 | def plot_coordinates(params: dict, n_electrodes_x: int, n_electrodes_y: int, 9 | x_max: Optional[int] = None): 10 | coordinates_cortex = get_cortex_coordinates_default(params) 11 | grid_cortex = get_cortex_coordinates_grid(params, n_electrodes_x, 12 | n_electrodes_y, x_max) 13 | plt.scatter(*coordinates_cortex.cartesian, c='r') 14 | plt.scatter(*grid_cortex.cartesian) 15 | plt.xlabel('Cortical distance (mm)') 16 | plt.ylabel('Cortical distance (mm)') 17 | plt.show() 18 | -------------------------------------------------------------------------------- /dynaphos/simulator.py: -------------------------------------------------------------------------------- 1 | import math 2 | from typing import Optional, Tuple, Union 3 | 4 | import logging 5 | import numpy as np 6 | import torch 7 | import warnings 8 | 9 | from dynaphos.cortex_models import get_cortical_magnification 10 | from dynaphos.image_processing import scale_image, to_n_dim 11 | from dynaphos.utils import (to_tensor, get_data_kwargs, get_truncated_normal, 12 | get_deg2pix_coeff, set_deterministic, 13 | print_stats, sigmoid, to_numpy, Map) 14 | 15 | class State: 16 | def __init__(self, params: dict, shape: Tuple[int, ...], 17 | verbose: Optional[bool] = False): 18 | self.params = params 19 | self.shape = shape 20 | self.verbose = verbose 21 | self.state = None 22 | self.data_kwargs = get_data_kwargs(self.params) 23 | 24 | self.reset() 25 | 26 | def reset(self): 27 | self.state = torch.zeros(self.shape, **self.data_kwargs) 28 | 29 | def get(self) -> torch.Tensor: 30 | return self.state 31 | 32 | def update(self, x: torch.Tensor): 33 | raise NotImplementedError 34 | 35 | def to_tensor(self, x: np.ndarray) -> torch.Tensor: 36 | return to_tensor(x, **self.data_kwargs) 37 | 38 | 39 | class Activation(State): 40 | def __init__(self, params: dict, shape: Tuple[int, ...], 41 | verbose: Optional[bool] = False): 42 | super().__init__(params, shape, verbose) 43 | 44 | self.fps = self.to_tensor(self.params['run']['fps']) 45 | # By default, the stimulus lasts as long as a frame. Can be adjusted: 46 | self.rel_stim_duration = self.to_tensor( 47 | self.params['default_stim']['relative_stim_duration']) 48 | # Convert decay-per-second to exponential decay constant. 49 | self.decay_rate = -torch.log(self.to_tensor( 50 | self.params['temporal_dynamics']['activation_decay_per_second'])) 51 | self.num_steps = int(torch.ceil(self.decay_rate / self.fps)) 52 | 53 | def update(self, x: torch.Tensor): 54 | """Update activation with leaky integrator. 55 | 56 | :param x: Effective stimulation current. 57 | """ 58 | 59 | # If decay rate > frame rate, perform extra simulation steps for 60 | # numerical stability. 61 | for _ in range(self.num_steps): 62 | # eq: \Delta A = (-\gamma * A + I) * \Delta t 63 | self.state = self.state.detach() + ( 64 | (-self.state.detach() * self.decay_rate + x * self.rel_stim_duration) / 65 | self.fps / self.num_steps) 66 | 67 | print_stats('activation', self.state, self.verbose) 68 | 69 | class ActivationThreshold(State): 70 | def __init__(self, params: dict, shape: Tuple[int, ...], 71 | rng: np.random.Generator, verbose: Optional[bool] = False): 72 | super().__init__(params, shape, verbose) 73 | self.rng = rng 74 | self._mu = self.params['thresholding']['activation_threshold'] 75 | self._sd = self.params['thresholding']['activation_threshold_sd'] 76 | self.reinitialize() 77 | 78 | def reinitialize(self, activation_thresholds: Optional[np.ndarray] = None): 79 | """Set or re-initialize the activation thresholds for each electrode. Default: sample from truncated random 80 | normal distribution.""" 81 | if self.params['thresholding']['use_threshold']: 82 | if activation_thresholds is None: 83 | activation_thresholds = self.rng.standard_normal(self.shape) * self._sd + self._mu 84 | self.state = self.to_tensor(activation_thresholds).clip(0, None) 85 | else: 86 | self.state = torch.zeros(self.shape, **self.data_kwargs) 87 | 88 | class Trace(State): 89 | def __init__(self, params: dict, shape: Tuple[int, ...], 90 | verbose: Optional[bool] = False): 91 | super().__init__(params, shape, verbose) 92 | 93 | fps = self.params['run']['fps'] 94 | 95 | # By default, the stimulus lasts as long as a frame. Can be adjusted: 96 | rel_stim_duration = \ 97 | self.params['default_stim']['relative_stim_duration'] 98 | 99 | # Convert decay-per-second to exponential decay constant. 100 | decay_rate = -math.log( 101 | self.params['temporal_dynamics']['trace_decay_per_second']) 102 | 103 | # Scaling of the trace increment. 104 | scale = self.params['temporal_dynamics']['trace_increase_rate'] 105 | 106 | # If decay rate > frame rate, perform extra simulation steps for 107 | # numerical stability. 108 | self.num_steps = math.ceil(decay_rate / fps) 109 | 110 | self._a = self.to_tensor(-decay_rate / fps / self.num_steps) 111 | self._b = self.to_tensor(rel_stim_duration * scale / fps / 112 | self.num_steps) 113 | 114 | def update(self, x: torch.Tensor): 115 | """Update memory trace using a leaky integrator. 116 | 117 | :param x: Effective stimulation current. 118 | """ 119 | for _ in range(self.num_steps): 120 | self.state = self.state.detach() + self._a * self.state.detach() + self._b * x 121 | 122 | print_stats('trace', self.state, self.verbose) 123 | 124 | 125 | class Brightness(State): 126 | def __init__(self, params: dict, shape: Tuple[int, ...], verbose: Optional[bool] = False): 127 | super().__init__(params, shape, verbose) 128 | self.slope = self.to_tensor( 129 | self.params['brightness_saturation']['slope_brightness']) 130 | self.cps_half = self.to_tensor( 131 | self.params['brightness_saturation']['cps_half']) 132 | 133 | def update(self, x: torch.Tensor): 134 | """Saturate activation values.""" 135 | 136 | self.state = sigmoid(self.slope * (x - self.cps_half)) 137 | print_stats('sigmoided activation', self.state, self.verbose) 138 | 139 | 140 | class Sigma(State): 141 | def __init__(self, params: dict, shape: Tuple[int, ...], 142 | magnification: torch.Tensor, verbose: Optional[bool] = False): 143 | super().__init__(params, shape, verbose) 144 | 145 | p = self.params['size'] 146 | if p['size_equation'] == 'sqrt': # Tehovnik 2007 147 | def f(x): 148 | return torch.sqrt(torch.div(x, p['current_spread'])) 149 | elif p['size_equation'] == 'sigmoid': # Bosking et al., 2017 150 | def f(x): 151 | return 0.5 * p['MD'] * sigmoid(p['slope_size'] * 152 | (x - p['I_half'])) 153 | else: 154 | raise ValueError("Size equation should be 'sqrt' or 'sigmoid'.") 155 | self.f = f 156 | self.scale = p['radius_to_sigma'] / magnification 157 | def update(self, x: torch.Tensor): 158 | """Compute the effect of the input current on phosphene size.""" 159 | 160 | # Current spread to sigma in pixels. 161 | self.state = torch.mul(self.f(x), self.scale) 162 | 163 | print_stats('Sigma (in degrees)', self.state, self.verbose) 164 | 165 | 166 | class GaussianSimulator: 167 | def __init__(self, params: dict, coordinates: Map, 168 | rng: Optional[np.random.Generator] = None, 169 | theta: Optional[np.ndarray] = None): 170 | """initialize a simulator with provided parameters settings, 171 | given phosphene locations in polar coordinates 172 | 173 | :param params: dict of dicts with all setting parameters. 174 | :param coordinates: Eccentricities and angles of phosphenes. 175 | :param theta: Orientations for gabor filtering (if 'gabor_filtering' set to True) 176 | :param rng: Numpy random number generator. 177 | """ 178 | 179 | self.params = params 180 | self.data_kwargs = get_data_kwargs(self.params) 181 | 182 | rng = np.random.default_rng() if rng is None else rng 183 | set_deterministic(self.params['run']['seed']) 184 | 185 | self.deg2pix_coeff = get_deg2pix_coeff(self.params['run']) 186 | 187 | self.phosphene_maps = \ 188 | self.generate_phosphene_maps(coordinates, theta=theta) 189 | 190 | batch_size = self.params['run']['batch_size'] 191 | if batch_size != 0: 192 | self.shape = (batch_size, self.num_phosphenes, 1, 1) 193 | self._electrode_dimension = 1 194 | else: 195 | self.shape = (self.num_phosphenes, 1, 1) 196 | self._electrode_dimension = 0 197 | 198 | r, phi = coordinates.polar 199 | r = torch.reshape(self.to_tensor(r), self.shape[-3:]) 200 | self.magnification = get_cortical_magnification( 201 | r, self.params['cortex_model']) 202 | 203 | verbose = self.params['run']['print_stats'] 204 | self.activation = Activation(params, self.shape, verbose=verbose) 205 | self.trace = Trace(params, self.shape) 206 | self.sigma = Sigma(params, self.shape, self.magnification) 207 | self.brightness = Brightness(params, self.shape) 208 | self.threshold = ActivationThreshold(params, self.shape, rng) 209 | self.effective_charge_per_second = None 210 | 211 | # Pre-allocate some helper variables. 212 | self._sampling_mask = None 213 | self._phosphene_centers = None 214 | params_sampling = self.params['sampling'] 215 | self._sampling_method = params_sampling['sampling_method'] 216 | self._sqrt_pi_inv = 1 / torch.sqrt(self.to_tensor(torch.pi)) 217 | self._pulse_width = (self.params['default_stim']['pw_default'] * 218 | torch.ones(self.shape, **self.data_kwargs)) 219 | self._frequency = (self.params['default_stim']['freq_default'] * 220 | torch.ones(self.shape, **self.data_kwargs)) 221 | 222 | self._zero = self.to_tensor(0) 223 | self._inf = self.to_tensor(torch.inf) 224 | 225 | self.reset() 226 | 227 | @property 228 | def num_phosphenes(self): 229 | return len(self.phosphene_maps) 230 | 231 | def to_tensor(self, x: Union[int, float, np.ndarray]) -> torch.Tensor: 232 | return to_tensor(x, **self.data_kwargs) 233 | 234 | def reset(self): 235 | """Reset Memory of previous timestep.""" 236 | self.activation.reset() 237 | self.trace.reset() 238 | self.sigma.reset() 239 | 240 | def gabor_rotation(self, x, y, theta=None) -> torch.Tensor: 241 | """Rotation of ellipsis.""" 242 | num_phosphenes = len(x) 243 | if theta is None: 244 | theta = torch.mul(2 * math.pi, torch.rand((num_phosphenes, 1, 1), **self.data_kwargs)) # Random rotation 245 | else: 246 | theta = torch.reshape(self.to_tensor(theta), (-1, 1, 1)) 247 | y_rotated = -x * torch.sin(theta) + y * torch.cos(theta) 248 | x_rotated = x * torch.cos(theta) + y * torch.sin(theta) 249 | gamma = self.params['gabor']['gamma'] 250 | phosphene_maps = torch.sqrt(x_rotated ** 2 + y_rotated ** 2 * gamma ** 2) 251 | return phosphene_maps 252 | 253 | def generate_phosphene_maps(self, coordinates: Map, 254 | remove_invalid: Optional[bool] = True, 255 | theta: Optional[np.ndarray] = None, 256 | ) -> torch.Tensor: 257 | """Generate phosphene maps (for each phosphene distance to each pixel). 258 | 259 | :param coordinates: Coordinates of phosphenes. 260 | :param remove_invalid: Whether to remove phosphenes out of view. 261 | :param theta: Orientations for gabor filtering (if 'gabor_filtering' set to True) 262 | :return: an (n_phosphenes x resolution[0] x resolution[1]) array 263 | describing distances from phosphene locations 264 | """ 265 | 266 | # Phosphene coordinates 267 | x_coords, y_coords = coordinates.cartesian 268 | x_coords = torch.reshape(self.to_tensor(x_coords), (-1, 1, 1)) 269 | y_coords = torch.reshape(self.to_tensor(y_coords), (-1, 1, 1)) 270 | 271 | # x,y limits of the simulation 272 | res_x, res_y = self.params['run']['resolution'] 273 | x_org, y_org = self.params['run']['origin'] 274 | hemi_fov = self.params['run']['view_angle'] / 2 275 | x_min, x_max = x_org - hemi_fov, x_org + hemi_fov 276 | y_min, y_max = y_org - hemi_fov, y_org + hemi_fov 277 | 278 | if remove_invalid: 279 | # Check if phosphene locations are inside of view angle. 280 | valid = ( 281 | torch.ge(x_coords, x_min) & torch.less(x_coords, x_max) & 282 | torch.ge(y_coords, y_min) & torch.less(y_coords, y_max)).ravel() 283 | num_total = len(x_coords) 284 | num_valid = torch.sum(valid) 285 | logging.debug(f"{num_total - num_valid} of {num_total} phosphenes " 286 | f"are outside of view and will be removed.") 287 | x_coords = x_coords[valid] 288 | y_coords = y_coords[valid] 289 | coordinates.use_subset(to_numpy(valid)) 290 | 291 | # Get distance maps to phosphene centres (in degrees of visual angle). 292 | device = self.data_kwargs['device'] 293 | num_phosphenes = len(x_coords) 294 | 295 | x_range = torch.linspace(x_min, x_max, res_x, device=device) 296 | y_range = torch.linspace(y_min, y_max, res_y, device=device) 297 | 298 | grid = torch.meshgrid(x_range, y_range, indexing='xy') 299 | grid_x = torch.tile(grid[0], (num_phosphenes, 1, 1)) 300 | grid_y = torch.tile(grid[1], (num_phosphenes, 1, 1)) 301 | x = grid_x - x_coords 302 | y = grid_y - y_coords 303 | 304 | if self.params['gabor']['gabor_filtering']: 305 | phosphene_maps = self.gabor_rotation(x, y, theta) 306 | else: 307 | phosphene_maps = torch.sqrt(x ** 2 + y ** 2) 308 | 309 | return phosphene_maps 310 | 311 | def update(self, amplitude: torch.Tensor, 312 | pulse_width: Optional[torch.Tensor] = None, 313 | frequency: Optional[torch.Tensor] = None): 314 | """Update phosphene states (brightness, size, tissue activation) as 315 | function of the electrical stimulation input and the previous state. 316 | 317 | :param amplitude: Stimulation amplitudes for each electrode. 318 | :param pulse_width: Stimulation pulse widths for each electrode. 319 | :param frequency: Stimulation frequencies for each electrode. 320 | """ 321 | 322 | if pulse_width is None: 323 | pulse_width = self._pulse_width 324 | if frequency is None: 325 | frequency = self._frequency 326 | 327 | charge_per_s = self.get_current(amplitude.view(self.shape), 328 | frequency.view(self.shape), 329 | pulse_width.view(self.shape)) 330 | 331 | self.activation.update(charge_per_s) 332 | 333 | self.trace.update(charge_per_s) 334 | 335 | self.sigma.update(amplitude.view(self.shape)) 336 | 337 | self.brightness.update(self.activation.get()) 338 | 339 | def get_current(self, amplitude: torch.Tensor, frequency: torch.Tensor, 340 | pulse_width: torch.Tensor) -> torch.Tensor: 341 | """Caclulate effective current (charge per second) from the square wave 342 | pulse. Cannot be negative. 343 | 344 | :param amplitude: Stimulation amplitudes for each electrode. 345 | :param pulse_width: Stimulation pulse widths for each electrode. 346 | :param frequency: Stimulation frequencies for each electrode. 347 | """ 348 | 349 | leak_current = \ 350 | self.trace.get() + self.params['thresholding']['rheobase'] 351 | charge_per_s = torch.relu((amplitude - leak_current) * 352 | pulse_width * frequency) 353 | self.effective_charge_per_second = charge_per_s 354 | 355 | print_stats('charge per second', charge_per_s) 356 | 357 | return charge_per_s 358 | 359 | def gaussian_activation(self) -> torch.Tensor: 360 | """Generate gaussian activation maps, based on sigmas and phosphene 361 | mapping. 362 | 363 | :return: Stack of Gaussian-shaped phosphene images 364 | (n_phosphenes, resolution_y, resolution_x) 365 | """ 366 | 367 | # Calculate normalized Gaussian (peak has value 1). 368 | sigma = self.sigma.get().clamp(1e-22, None) # TODO: clamping redundant? Default division by zero gives inf. 369 | exp = torch.exp(-0.5 * (self.phosphene_maps / sigma) ** 2) 370 | return exp 371 | 372 | def get_state(self): 373 | state = { 374 | 'brightness': self.brightness.get(), 375 | 'sigma': self.sigma.get(), 376 | 'activation': self.activation.get(), 377 | 'trace': self.trace.get(), 378 | 'threshold': self.threshold.get(), 379 | 'effective_charge_per_second': 380 | self.effective_charge_per_second} 381 | return state 382 | 383 | def __call__(self, amplitude: torch.Tensor, 384 | pulse_width: Optional[torch.Tensor] = None, 385 | frequency: Optional[torch.Tensor] = None) -> torch.Tensor: 386 | """Generate simulated phosphene representation based on the 387 | electrical stimulation parameters and the previous state. 388 | 389 | :param amplitude: Stimulation amplitudes for each electrode. 390 | :param pulse_width: Stimulation pulse widths for each electrode. 391 | :param frequency: Stimulation frequencies for each electrode. 392 | 393 | :return: image with simulated phosphene representation 394 | """ 395 | 396 | # Update phosphene state. 397 | self.update(amplitude, pulse_width, frequency) 398 | 399 | # Generate phosphene map. 400 | activation = self.gaussian_activation() 401 | 402 | # Thresholding: Set phosphene intensity to zero if tissue activation is lower than threshold. 403 | supra_threshold = torch.greater(self.activation.get(), self.threshold.get()) 404 | intensity = torch.where(supra_threshold, self.brightness.get(), self._zero) 405 | 406 | # Return phosphene image. 407 | return torch.sum(intensity * activation, dim=self._electrode_dimension).clamp(0, 1) 408 | 409 | @property 410 | def phosphene_centers(self): 411 | """Indices (flat indexing) of the phosphene centers""" 412 | if self._phosphene_centers is None: 413 | self._phosphene_centers = self.phosphene_maps.flatten(start_dim=1).argmin(dim=-1) 414 | return self._phosphene_centers 415 | 416 | def sample_centers(self, x: torch.Tensor) -> torch.Tensor: 417 | """Extracts the value of the activation mask at the center pixel of each phosphene""" 418 | # instead of multiplying with sampling mask, values are retrieved using the indices of the center pixels 419 | return x.flatten(-2)[..., self.phosphene_centers] 420 | 421 | def sample_receptive_fields(self, x: torch.Tensor) -> torch.Tensor: 422 | """Extracts the maximum value of activation mask x within the 'receptive field' of each phosphene""" 423 | return torch.amax(self.sampling_mask * x, dim=(-2,-1)) 424 | 425 | @property 426 | def sampling_mask(self): 427 | """Boolean mask (tensor) that defines which pixels are inside the receptive field / center of each phosphene""" 428 | if self._sampling_mask is None: 429 | params = self.params['sampling'] 430 | if self._sampling_method == 'receptive_fields': 431 | self._sampling_mask = torch.less(self.phosphene_maps, params['RF_size'] / self.magnification) 432 | elif self._sampling_method == 'center': 433 | # Sampling mask is not used anymore in 'center' mode (pixels are directly retrieved using indexing), 434 | # but still implemented here for backwards compatibility 435 | p_map = self.phosphene_maps 436 | flat_idx = torch.arange(p_map.shape[0], device=p_map.device) * p_map.shape[-2] * p_map.shape[-1] 437 | self._sampling_mask = torch.zeros_like(p_map) 438 | self._sampling_mask.flatten()[self.phosphene_centers + flat_idx] = 1 439 | else: 440 | raise NotImplementedError 441 | return self._sampling_mask 442 | 443 | def sample_stimulus(self, activation_mask: Union[np.ndarray, torch.Tensor], rescale=False, 444 | ) -> torch.Tensor: 445 | """Obtain a stimulation vector from an activation mask image that indicates the regional stimulation intensity. 446 | 447 | param activation_mask: Image (or batch of images: N, 1, H, W). The pixel intensities indicate the 448 | stimulation amplitude for each visual region. 449 | 450 | param rescale: If False (default), the pixel intensities indicate the stimulation amplitude in Amperes. 451 | If True, the input pixels (in range [0, 1] or [0, 255]) are mapped to stimulation amplitudes 452 | using the default stimulus scale parameter specified in the params configuration file. 453 | 454 | return: Stimulation tensor with the stimulation amplitudes for each phosphene. """ 455 | 456 | if isinstance(activation_mask, np.ndarray): 457 | dtype = activation_mask.dtype 458 | activation_mask = self.to_tensor(activation_mask) 459 | if (dtype == np.dtype('uint8')) or (activation_mask.max() > 1): 460 | activation_mask = scale_image(activation_mask, 1 / 255) 461 | if self._sampling_method == 'receptive_fields': 462 | electrode_activation = self.sample_receptive_fields(activation_mask) 463 | elif self._sampling_method == 'center': 464 | electrode_activation = self.sample_centers(activation_mask) # electrode activations between 0 and 1 465 | else: 466 | raise NotImplementedError 467 | if rescale: 468 | electrode_activation = torch.mul(electrode_activation, self.params['sampling']['stimulus_scale']) 469 | elif electrode_activation.max() >= 1e-3: 470 | warnings.warn("High values detected! Activation mask not longer rescaled as default behaviour. Please set " 471 | "rescale=True to map pixels in range [0, 1] or [0, 255] to the default stimulus scale.", 472 | category=DeprecationWarning, stacklevel=2) 473 | return electrode_activation 474 | -------------------------------------------------------------------------------- /dynaphos/utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import numpy as np 3 | import torch 4 | import yaml 5 | from matplotlib import pyplot as plt 6 | from scipy.stats import truncnorm 7 | from typing import Optional, Tuple, Union, Iterable 8 | 9 | 10 | def get_deg2pix_coeff(run_params: dict) -> float: 11 | view_angle = run_params['view_angle'] 12 | resolution = run_params['resolution'] 13 | deg2pix = resolution[0] / view_angle 14 | logging.debug(f"Displaying {view_angle} degrees of vision in a resolution " 15 | f"of {resolution}.") 16 | logging.debug(f"One degree is equivalent to {deg2pix} pixels.") 17 | return deg2pix 18 | 19 | 20 | def calculate_dpi(params: dict) -> float: 21 | w_pixels = params['display']['screen_resolution'][0] 22 | h_pixels = params['display']['screen_resolution'][1] 23 | diagonal = params['display']['screen_diagonal'] 24 | w_inches = (diagonal ** 2 / (1 + h_pixels ** 2 / w_pixels ** 2)) ** 0.5 25 | dpi = round(w_pixels / w_inches) 26 | return dpi 27 | 28 | 29 | def display_real_size(params: dict, image: np.ndarray): 30 | mm_per_degree = \ 31 | params['display']['dist_to_screen'] * np.tan(2 * np.pi / 360) 32 | view_angle = params['run']['view_angle'] 33 | resolution = params['run']['resolution'] 34 | aspect_ratio = resolution[0] / resolution[1] 35 | 36 | mm = 0.1 / 2.54 37 | fig_width = mm_per_degree * view_angle * mm 38 | fig_height = mm_per_degree * (view_angle / aspect_ratio) * mm 39 | dpi = calculate_dpi(params) 40 | logging.debug(f"Display sizes: {fig_width}, {fig_height} | dpi: {dpi}") 41 | 42 | fig = plt.figure(figsize=(fig_width, fig_height), dpi=dpi) 43 | ax = fig.add_axes([0, 0, 1, 1]) 44 | 45 | # Hide spines, ticks, etc. 46 | ax.axis('off') 47 | 48 | # Display the image. 49 | ax.imshow(image, cmap='gray', vmin=0, vmax=255, origin='lower') 50 | plt.show() 51 | 52 | 53 | def load_coordinates_from_yaml(path: str, n_coordinates: Optional[int] = None, 54 | rng: Optional[np.random.Generator] = None 55 | ) -> Tuple[np.ndarray, np.ndarray]: 56 | with open(path, 'r') as f: 57 | coordinates = yaml.load(f, Loader=yaml.FullLoader) 58 | x = np.array(coordinates['x']) 59 | y = np.array(coordinates['y']) 60 | 61 | if n_coordinates: 62 | if rng is None: 63 | rng = np.random.default_rng() 64 | sample = rng.choice(len(x), n_coordinates) 65 | x = x[sample] 66 | y = y[sample] 67 | 68 | return x, y 69 | 70 | 71 | def load_params(path: str) -> dict: 72 | with open(path, 'r') as f: 73 | params = yaml.load(f, Loader=yaml.FullLoader) 74 | return params 75 | 76 | 77 | def to_tensor(x: Union[int, float, np.ndarray], **data_kwargs) -> torch.Tensor: 78 | return torch.tensor(x, **data_kwargs) 79 | 80 | 81 | def to_numpy(x: torch.Tensor) -> np.ndarray: 82 | return x.cpu().numpy() 83 | 84 | 85 | def get_data_kwargs(params: dict) -> dict: 86 | dtype = getattr(torch, params['run']['dtype']) 87 | gpu = params['run']['gpu'] 88 | device = 'cpu' if not torch.cuda.device_count() or gpu is None \ 89 | else f'cuda:{gpu}' 90 | return dict(device=device, dtype=dtype) 91 | 92 | 93 | def cartesian_to_complex(x: np.ndarray, y: np.ndarray) -> np.ndarray: 94 | return x + 1j * y 95 | 96 | 97 | def polar_to_complex(r: np.ndarray, phi: np.ndarray) -> np.ndarray: 98 | return r * np.exp(1j * phi) 99 | 100 | 101 | def complex_to_cartesian(z: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: 102 | return np.real(z), np.imag(z) 103 | 104 | 105 | def complex_to_polar(z: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: 106 | return np.abs(z), np.angle(z) 107 | 108 | 109 | def cartesian_to_polar(x: np.ndarray, y: np.ndarray 110 | ) -> Tuple[np.ndarray, np.ndarray]: 111 | r = np.sqrt(x * x + y * y) 112 | phi = np.arctan2(y, x) 113 | return r, phi 114 | 115 | 116 | def get_truncated_normal(size: Union[int, Iterable], mean: float, sd: float, 117 | low: Optional[float] = 0., 118 | upp: Optional[float] = 1e-4) -> np.ndarray: 119 | return truncnorm.rvs( 120 | (low - mean) / sd, (upp - mean) / sd, loc=mean, scale=sd, size=size) 121 | 122 | 123 | def set_deterministic(seed): 124 | torch.manual_seed(seed) 125 | torch.cuda.manual_seed(seed) 126 | torch.cuda.manual_seed_all(seed) 127 | torch.backends.cudnn.benchmark = False 128 | torch.backends.cudnn.deterministic = True 129 | torch.use_deterministic_algorithms(True) 130 | np.random.seed(seed) 131 | 132 | 133 | class Map: 134 | def __init__(self, 135 | x: Optional[np.ndarray] = None, 136 | y: Optional[np.ndarray] = None, 137 | z: Optional[np.ndarray] = None, 138 | r: Optional[np.ndarray] = None, 139 | phi: Optional[np.ndarray] = None): 140 | assert ((x is not None and y is not None) ^ (z is not None) ^ 141 | (r is not None and phi is not None)), "Invalid arguments." 142 | 143 | self._x = x 144 | self._y = y 145 | self._z = z 146 | self._r = r 147 | self._phi = phi 148 | 149 | if self._x is not None and self._y is not None: 150 | self._z = cartesian_to_complex(self._x, self._y) 151 | self._r, self._phi = complex_to_polar(self._z) 152 | elif self._z is not None: 153 | self._x, self._y = complex_to_cartesian(self._z) 154 | self._r, self._phi = complex_to_polar(self._z) 155 | elif self._r is not None and self._phi is not None: 156 | self._z = polar_to_complex(self._r, self._phi) 157 | self._x, self._y = complex_to_cartesian(self._z) 158 | 159 | def __len__(self): 160 | if self._x is None: 161 | return 0 162 | return len(self._x) 163 | 164 | @property 165 | def polar(self): 166 | return self._r, self._phi 167 | 168 | @property 169 | def cartesian(self): 170 | return self._x, self._y 171 | 172 | @property 173 | def complex(self): 174 | return self._z 175 | 176 | def use_subset(self, indexes: np.ndarray): 177 | self._x = self._x[indexes] 178 | self._y = self._y[indexes] 179 | self._z = self._z[indexes] 180 | self._r = self._r[indexes] 181 | self._phi = self._phi[indexes] 182 | 183 | def flip(self, hor=False, vert=False): 184 | z = np.array(self._z) # copy 185 | if hor: 186 | z.real *= -1 187 | if vert: 188 | z.imag *= -1 189 | return Map(z=z) 190 | 191 | 192 | 193 | def sigmoid(x: torch.Tensor) -> torch.Tensor: 194 | """Sigmoid for brightness saturation and thresholding psychometric curves. 195 | """ 196 | return torch.div(1, 1 + torch.exp(-x)) 197 | 198 | 199 | def print_stats(stat_name: str, stat: torch.Tensor, verbose=False): 200 | if verbose: 201 | msg = f"""{stat_name}: 202 | size: {stat.size()} 203 | min: {stat.min():.2E} 204 | max: {stat.max():.2E} 205 | mean: {stat.mean():.2E} 206 | std: {stat.std():.2E}""" 207 | logging.debug(msg) 208 | -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/__init__.py -------------------------------------------------------------------------------- /examples/demo_webcam.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | 4 | import cv2 5 | import numpy as np 6 | 7 | from dynaphos.image_processing import sobel_processor, canny_processor 8 | from dynaphos.simulator import GaussianSimulator 9 | from dynaphos.utils import load_params, load_coordinates_from_yaml, Map 10 | from dynaphos.cortex_models import \ 11 | get_visual_field_coordinates_from_cortex_full 12 | 13 | FILTER = 'canny' # choose canny or sobel 14 | THRESHOLD_HIGH = 200 # the high threshold for the canny edge detection 15 | 16 | def main(params: dict, in_video: int): 17 | params['thresholding']['use_threshold'] = False 18 | coordinates_cortex = load_coordinates_from_yaml( 19 | '../config/grid_coords_dipole_valid.yaml', n_coordinates=100) 20 | coordinates_cortex = Map(*coordinates_cortex) 21 | coordinates_visual_field = get_visual_field_coordinates_from_cortex_full( 22 | params['cortex_model'], coordinates_cortex) 23 | simulator = GaussianSimulator(params, coordinates_visual_field) 24 | resolution = params['run']['resolution'] 25 | fps = params['run']['fps'] 26 | 27 | prev = 0 28 | cap = cv2.VideoCapture(in_video) 29 | ret, frame = cap.read() 30 | while ret: 31 | 32 | # Capture the video frame by frame 33 | ret, frame = cap.read() 34 | 35 | time_elapsed = time.time() - prev 36 | if time_elapsed > 1 / fps: 37 | prev = time.time() 38 | 39 | # Create Canny edge detection mask 40 | frame = cv2.resize(frame, resolution) 41 | frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 42 | frame = cv2.GaussianBlur(frame, (3, 3), 0) 43 | 44 | method = FILTER 45 | if method == 'sobel': 46 | processed_img = sobel_processor(frame) 47 | elif method == 'canny': 48 | processed_img = canny_processor(frame, THRESHOLD_HIGH//2, THRESHOLD_HIGH) 49 | elif method == 'none': 50 | processed_img = frame 51 | else: 52 | raise ValueError(f"{method} is not a valid filter keyword.") 53 | 54 | # Generate phosphenes 55 | stim_pattern = simulator.sample_stimulus(processed_img, rescale=True) 56 | phosphenes = simulator(stim_pattern) 57 | phosphenes = phosphenes.cpu().numpy() * 255 58 | 59 | # Concatenate results 60 | cat = np.concatenate([frame, processed_img, phosphenes], 61 | axis=1).astype('uint8') 62 | 63 | # Display the resulting frame 64 | cv2.imshow('Simulator', cat) 65 | 66 | # the 'q' button is set as the quit button 67 | if cv2.waitKey(1) & 0xFF == ord('q'): 68 | break 69 | 70 | cap.release() 71 | # Destroy all the windows 72 | cv2.destroyAllWindows() 73 | 74 | 75 | if __name__ == '__main__': 76 | _params = load_params('../config/params.yaml') 77 | _in_video = 0 # use 0 for webcam, or string with video path 78 | main(_params, _in_video) 79 | sys.exit() 80 | -------------------------------------------------------------------------------- /examples/example_video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/example_video.mp4 -------------------------------------------------------------------------------- /examples/example_video_gaze_contingent_object_grabbing.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/example_video_gaze_contingent_object_grabbing.mp4 -------------------------------------------------------------------------------- /examples/example_video_gaze_contingent_walking.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/example_video_gaze_contingent_walking.mp4 -------------------------------------------------------------------------------- /examples/eye_tracked_i1344739819_subject_hp.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/eye_tracked_i1344739819_subject_hp.mp4 -------------------------------------------------------------------------------- /examples/eye_tracked_i1344739819_subject_hp_orig.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/examples/eye_tracked_i1344739819_subject_hp_orig.mp4 -------------------------------------------------------------------------------- /examples/readme.md: -------------------------------------------------------------------------------- 1 | # Example videos 2 | 3 | ### Semantic segmentation example 4 | 5 | ![example_video.mp4](example_video.mp4) 6 | 7 | Left: video and the semantic segmentation labels (from the [KITTI dataset](https://www.cvlibs.net/datasets/kitti/)). 8 | Middle: preprocessed image that was used to sample the electrode activations. 9 | Right: output of the dynaphos phosphene simulator. 10 | 11 | ### Example videos gaze-contingent processing 12 | 13 | ![example_video_gaze_contingent_object_grabbing.mp4](example_video_gaze_contingent_object_grabbing.mp4) 14 | 15 | ![example_video_gaze_contingent_walking.mp4](example_video_gaze_contingent_walking.mp4) 16 | 17 | Left: input video. The red circle indicates the gaze-direction of the wearer of the camera. 18 | Middle: the input video after processing with sobel edge detection (which was used to sample the electrode activations). The electrode activations are created by sampling the gaze-contingent patches (indicated by the circle). 19 | Right: output of the dynaphos phosphene simulator. The simulated phosphes are rendered contingent with the gaze direction. 20 | 21 | **Acknowledgement:** Videos and gaze data are obtained by and used here with permission from Ashkan Nejad and Eva Postuma, Laboratory of Experimental Ophthalmology, University Medical Center Groningen. 22 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=61.0"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "dynaphos" 7 | version = "0.1.3" 8 | authors = [ 9 | { name="Maureen van der Grinten", email="maureen.vandergrinten@ru.nl" }, 10 | { name="Jaap de Ruyter", email="jaap.deruyter@donders.ru.nl" }, 11 | { name="Bodo Rueckauer", email="bodo.rueckauer@donders.ru.nl" }, 12 | ] 13 | description = "Fully differentiable and biologically plausible simulation of prosthetic vision." 14 | readme = "README.md" 15 | requires-python = ">=3.7" 16 | classifiers = [ 17 | "Programming Language :: Python :: 3", 18 | "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", 19 | "Operating System :: OS Independent", 20 | ] 21 | 22 | [project.urls] 23 | "Homepage" = "https://github.com/neuralcodinglab/dynaphos.git" 24 | 25 | [tool.setuptools] 26 | packages = ["dynaphos"] 27 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==4.3.0 2 | argon2-cffi==23.1.0 3 | argon2-cffi-bindings==21.2.0 4 | arrow==1.3.0 5 | asttokens==2.4.1 6 | async-lru==2.0.4 7 | attrs==23.2.0 8 | Babel==2.14.0 9 | beautifulsoup4==4.12.3 10 | bleach==6.1.0 11 | certifi==2024.2.2 12 | cffi==1.16.0 13 | charset-normalizer==3.3.2 14 | colorama==0.4.6 15 | comm==0.2.1 16 | contourpy==1.2.0 17 | cycler==0.12.1 18 | debugpy==1.8.1 19 | decorator==5.1.1 20 | defusedxml==0.7.1 21 | executing==2.0.1 22 | fastjsonschema==2.19.1 23 | filelock==3.13.1 24 | fonttools==4.49.0 25 | fqdn==1.5.1 26 | fsspec==2024.2.0 27 | h11==0.14.0 28 | httpcore==1.0.4 29 | httpx==0.27.0 30 | idna==3.6 31 | iniconfig==2.0.0 32 | ipykernel==6.29.3 33 | ipython==8.22.2 34 | ipywidgets==8.1.2 35 | isoduration==20.11.0 36 | jedi==0.19.1 37 | Jinja2==3.1.3 38 | json5==0.9.20 39 | jsonpointer==2.4 40 | jsonschema==4.21.1 41 | jsonschema-specifications==2023.12.1 42 | jupyter==1.0.0 43 | jupyter-console==6.6.3 44 | jupyter-events==0.9.0 45 | jupyter-lsp==2.2.3 46 | jupyter_client==8.6.0 47 | jupyter_core==5.7.1 48 | jupyter_server==2.13.0 49 | jupyter_server_terminals==0.5.2 50 | jupyterlab==4.1.3 51 | jupyterlab_pygments==0.3.0 52 | jupyterlab_server==2.25.3 53 | jupyterlab_widgets==3.0.10 54 | kiwisolver==1.4.5 55 | MarkupSafe==2.1.5 56 | matplotlib==3.8.3 57 | matplotlib-inline==0.1.6 58 | mistune==3.0.2 59 | mpmath==1.3.0 60 | nbclient==0.9.0 61 | nbconvert==7.16.2 62 | nbformat==5.9.2 63 | nest-asyncio==1.6.0 64 | networkx==3.2.1 65 | notebook==7.1.1 66 | notebook_shim==0.2.4 67 | numpy==1.26.4 68 | opencv-contrib-python==4.9.0.80 69 | opencv-python==4.9.0.80 70 | overrides==7.7.0 71 | packaging==23.2 72 | pandas==2.2.1 73 | pandocfilters==1.5.1 74 | parso==0.8.3 75 | pillow==10.2.0 76 | platformdirs==4.2.0 77 | pluggy==1.4.0 78 | prometheus_client==0.20.0 79 | prompt-toolkit==3.0.43 80 | psutil==5.9.8 81 | pure-eval==0.2.2 82 | pycparser==2.21 83 | Pygments==2.17.2 84 | pyparsing==3.1.1 85 | pytest==8.0.2 86 | python-dateutil==2.9.0 87 | python-json-logger==2.0.7 88 | pytz==2024.1 89 | pywin32==306 90 | pywinpty==2.0.13 91 | PyYAML==6.0.1 92 | pyzmq==25.1.2 93 | qtconsole==5.5.1 94 | QtPy==2.4.1 95 | referencing==0.33.0 96 | requests==2.31.0 97 | rfc3339-validator==0.1.4 98 | rfc3986-validator==0.1.1 99 | rpds-py==0.18.0 100 | scipy==1.12.0 101 | Send2Trash==1.8.2 102 | six==1.16.0 103 | sniffio==1.3.1 104 | soupsieve==2.5 105 | stack-data==0.6.3 106 | sympy==1.12 107 | terminado==0.18.0 108 | tinycss2==1.2.1 109 | torch==2.2.1 110 | tornado==6.4 111 | traitlets==5.14.1 112 | types-python-dateutil==2.8.19.20240106 113 | typing_extensions==4.10.0 114 | tzdata==2024.1 115 | uri-template==1.3.0 116 | urllib3==2.2.1 117 | wcwidth==0.2.13 118 | webcolors==1.13 119 | webencodings==0.5.1 120 | websocket-client==1.7.0 121 | widgetsnbextension==4.0.10 122 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | if __name__ == "__main__": 4 | setuptools.setup() -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/__init__.py -------------------------------------------------------------------------------- /test/benchmark.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/benchmark.pkl -------------------------------------------------------------------------------- /test/benchmark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/benchmark.png -------------------------------------------------------------------------------- /test/benchmark.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | import pandas as pd 4 | import timeit 5 | import numpy as np 6 | import torch 7 | import matplotlib.pyplot as plt 8 | import seaborn as sns 9 | import tqdm 10 | 11 | from dynaphos.simulator import GaussianSimulator 12 | from dynaphos.utils import load_params, load_coordinates_from_yaml, Map, \ 13 | get_data_kwargs 14 | from dynaphos.cortex_models import \ 15 | get_visual_field_coordinates_from_cortex_full 16 | 17 | 18 | def get_random(resolution, num_phosphenes, num_frames=1000): 19 | params = load_params('../config/params.yaml') 20 | data_kwargs = get_data_kwargs(params) 21 | rng = np.random.default_rng(seed=params['run']['seed']) 22 | params['run']['resolution'] = list(resolution) 23 | shape = [num_frames] + params['run']['resolution'] 24 | coordinates_cortex = load_coordinates_from_yaml( 25 | '../config/grid_coords_dipole_valid.yaml', num_phosphenes, rng) 26 | coordinates_cortex = Map(*coordinates_cortex) 27 | coordinates_visual_field = get_visual_field_coordinates_from_cortex_full( 28 | params['cortex_model'], coordinates_cortex, rng) 29 | simulator = GaussianSimulator(params, coordinates_visual_field, rng) 30 | frames = torch.mul(torch.rand(shape, **data_kwargs), 100e-6) # range [0, 100µA] 31 | 32 | stim_sequence = [] 33 | for frame in frames: 34 | stim_sequence.append(simulator.sample_stimulus(frame)) 35 | return simulator, stim_sequence 36 | 37 | def run_simulation(simulator, stim_sequence): 38 | for stimulus in stim_sequence: 39 | simulator(stimulus) 40 | 41 | 42 | def run_single(n=5): 43 | simulator, stim_sequence = get_random([256, 256], 100, 1000) 44 | timer = timeit.Timer(lambda: run_simulation(simulator, stim_sequence)) 45 | result = timer.timeit(n) 46 | print(result / n) 47 | 48 | 49 | def run_sweep(): 50 | num_frames = 1000 51 | num_repetitions = 5 52 | num_phosphenes = [] 53 | resolutions = [] 54 | fps = [] 55 | for _ in tqdm.tqdm(range(num_repetitions), 'Repetition', leave=False): 56 | for m in tqdm.tqdm([128, 256, 512, 1024], 'Phosphenes', leave=False): 57 | for k in tqdm.tqdm([64, 128, 256, 512], 'Resolution', leave=False): 58 | simulator, stim_sequence = get_random([k, k], m, num_frames) 59 | timer = timeit.Timer(lambda: run_simulation(simulator, stim_sequence)) 60 | t = timer.timeit(1) 61 | num_phosphenes.append(m) 62 | resolutions.append(k) 63 | fps.append(num_frames / t) 64 | data = pd.DataFrame(dict(num_phosphenes=num_phosphenes, 65 | resolution=resolutions, fps=fps)) 66 | summary = data.groupby(['resolution', 'num_phosphenes']).mean() 67 | print(summary) 68 | pd.to_pickle(data, 'benchmark.pkl') 69 | sns.relplot(data=data, x='num_phosphenes', y='fps', hue='resolution', 70 | style='resolution', kind='line', markers=True) 71 | plt.savefig('benchmark.png') 72 | 73 | 74 | if __name__ == '__main__': 75 | run_sweep() 76 | # run_single() 77 | 78 | sys.exit() 79 | -------------------------------------------------------------------------------- /test/data/Fernandez_2021_fig6A.csv: -------------------------------------------------------------------------------- 1 | amplitude,brightness,description 2 | 0.00001,0.04, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" 3 | 0.00002,0.08, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" 4 | 0.00003,0.2, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" 5 | 0.00004,0.36, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" 6 | 0.00005,0.48, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" 7 | 0.00006,0.8, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" 8 | 0.00007,0.8, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" 9 | 0.00008,0.8, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" 10 | 0.00009,1.0, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" 11 | 0.00010,0.92, "these data are obtained from visual inspection of (Fernandez et al. 2021; Figure 6A) see https://doi.org/10.1172%2FJCI151331" -------------------------------------------------------------------------------- /test/data/activation.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/activation.npy -------------------------------------------------------------------------------- /test/data/coordinates_dipole.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/coordinates_dipole.npz -------------------------------------------------------------------------------- /test/data/coordinates_monopole.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/coordinates_monopole.npz -------------------------------------------------------------------------------- /test/data/coordinates_wedge-dipole.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/coordinates_wedge-dipole.npz -------------------------------------------------------------------------------- /test/data/donders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/donders.png -------------------------------------------------------------------------------- /test/data/fernandez_activation_fit.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/fernandez_activation_fit.npy -------------------------------------------------------------------------------- /test/data/fernandez_brightness_fit.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/fernandez_brightness_fit.npy -------------------------------------------------------------------------------- /test/data/output.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/output.npy -------------------------------------------------------------------------------- /test/data/phosphene_map.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/phosphene_map.npy -------------------------------------------------------------------------------- /test/data/phosphenes_donders.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/phosphenes_donders.npy -------------------------------------------------------------------------------- /test/data/results_dynamics.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/results_dynamics.pkl -------------------------------------------------------------------------------- /test/data/sigma.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/sigma.npy -------------------------------------------------------------------------------- /test/data/stimulus.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/stimulus.npy -------------------------------------------------------------------------------- /test/data/trace.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/trace.npy -------------------------------------------------------------------------------- /test/data/valid_electrodes.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/valid_electrodes.npy -------------------------------------------------------------------------------- /test/data/z_full_view.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neuralcodinglab/dynaphos/f3e10224f8233e6a58772d8ce7bdd8943975826a/test/data/z_full_view.npy -------------------------------------------------------------------------------- /test/test_all.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import pytest 3 | import torch 4 | import numpy as np 5 | import pandas as pd 6 | 7 | from dynaphos.simulator import GaussianSimulator 8 | from dynaphos.cortex_models import ( 9 | get_visual_field_coordinates_from_cortex, remove_out_of_view, 10 | get_visual_field_coordinates_grid, get_mapping_from_cortex_to_visual_field, 11 | get_cortex_coordinates_default, get_cortex_coordinates_grid, 12 | get_visual_field_coordinates_from_cortex_full, 13 | get_visual_field_coordinates_probabilistically) 14 | from dynaphos.utils import (to_tensor, to_numpy, get_data_kwargs, load_params, 15 | load_coordinates_from_yaml, Map) 16 | 17 | 18 | PARAMS_PATH = '../config/params.yaml' 19 | MAPPING_MODELS = ['monopole', 'dipole', 'wedge-dipole'] 20 | 21 | 22 | @pytest.fixture 23 | def params(): 24 | return load_params(PARAMS_PATH) 25 | 26 | 27 | @pytest.fixture 28 | def rng(params): 29 | return np.random.default_rng(seed=params['run']['seed']) 30 | 31 | 32 | @pytest.fixture 33 | def simulator(params, rng): 34 | params['sampling']['sampling_method'] = 'center' 35 | return get_simulator(params, rng) 36 | 37 | 38 | def get_simulator(params, rng): 39 | coordinates_cortex = load_coordinates_from_yaml( 40 | '../config/grid_coords_dipole_valid.yaml', n_coordinates=100, rng=rng) 41 | coordinates_cortex = Map(*coordinates_cortex) 42 | coordinates_visual_field = get_visual_field_coordinates_from_cortex_full( 43 | params['cortex_model'], coordinates_cortex, rng) 44 | return GaussianSimulator(params, coordinates_visual_field, rng) 45 | 46 | 47 | @pytest.fixture 48 | def stimulus(params): 49 | stimulus = np.load('data/stimulus.npy') 50 | data_kwargs = get_data_kwargs(params) 51 | return to_tensor(stimulus, **data_kwargs) 52 | 53 | class TestInit: 54 | def test_init_probabilistically(self, params, rng): 55 | r_expected = [4.18866466, 1.41023323, 5.35768769, 3.33191491, 56 | 0.18516116, 7.47153754, 4.03653153, 4.3407978, 57 | 0.26523123, 1.47428929] 58 | phi_expected = [2.3297927, 5.82303616, 4.04552386, 5.16956368, 59 | 2.78605358, 1.427783, 3.48455899, 0.40097565, 60 | 5.20016002, 3.96886447] 61 | coordinates_cortex = get_visual_field_coordinates_probabilistically( 62 | params, len(r_expected), rng) 63 | r, phi = coordinates_cortex.polar 64 | assert np.isclose(r, r_expected).all() 65 | assert np.isclose(phi, phi_expected).all() 66 | 67 | 68 | class TestCorticalModels: 69 | def test_init_covering_electrode_grid(self, params): 70 | x_expected = [0., 26.27987687, 52.55975374, 78.83963061, 0., 71 | 26.27987687, 52.55975374, 78.83963061, 0., 26.27987687, 72 | 52.55975374, 78.83963061, 0., 26.27987687, 52.55975374, 73 | 78.83963061] 74 | y_expected = [-24.44135778, -24.44135778, -24.44135778, -24.44135778, 75 | -8.14711926, -8.14711926, -8.14711926, -8.14711926, 76 | 8.14711926, 8.14711926, 8.14711926, 8.14711926, 77 | 24.44135778, 24.44135778, 24.44135778, 24.44135778] 78 | coordinates_cortex = get_cortex_coordinates_grid( 79 | params['cortex_model'], 4, 4) 80 | x, y = coordinates_cortex.cartesian 81 | assert np.isclose(x, x_expected).all() 82 | assert np.isclose(y, y_expected).all() 83 | 84 | def test_get_phosphene_map_from_electrodes(self, params, rng): 85 | p = params['cortex_model'] 86 | r_expected = [17.3140795, 17.0009518] 87 | phi_expected = [-2.56560138, 2.61408701] 88 | coordinates_cortex = get_cortex_coordinates_grid(p, 4, 4) 89 | coordinates_visual_field = get_visual_field_coordinates_from_cortex( 90 | p, coordinates_cortex, rng) 91 | r, phi = coordinates_visual_field.polar 92 | assert np.isclose(r, r_expected).all() 93 | assert np.isclose(phi, phi_expected).all() 94 | 95 | def test_init_full_view(self): 96 | visual_field = get_visual_field_coordinates_grid() 97 | z_expected = np.load('data/z_full_view.npy') 98 | assert np.isclose(visual_field.complex, z_expected).all() 99 | 100 | @pytest.mark.parametrize('mapping_model', MAPPING_MODELS) 101 | def test_generate_cortical_map(self, params, mapping_model): 102 | p = params['cortex_model'] 103 | p['model'] = mapping_model 104 | cortex_map = get_cortex_coordinates_default(p) 105 | x, y = cortex_map.cartesian 106 | coordinates = np.load(f'data/coordinates_{mapping_model}.npz') 107 | assert np.isclose(x, coordinates['x']).all() 108 | assert np.isclose(y, coordinates['y']).all() 109 | 110 | @pytest.mark.parametrize('mapping_model', MAPPING_MODELS) 111 | def test_generate_phosphene_map(self, params, mapping_model): 112 | p = params['cortex_model'] 113 | p['model'] = mapping_model 114 | cortex_map = get_cortex_coordinates_default(p) 115 | cortex_to_visual_field = get_mapping_from_cortex_to_visual_field(p) 116 | z = cortex_to_visual_field(cortex_map.complex) 117 | z_expected = get_visual_field_coordinates_grid().complex 118 | assert np.isclose(z, z_expected, atol=1e-8).all() 119 | 120 | def test_filter_invalid_electrodes(self): 121 | coordinates_visual_field = get_visual_field_coordinates_grid() 122 | z_all = coordinates_visual_field.complex 123 | z = remove_out_of_view(z_all) 124 | valid_electrodes = np.load('data/valid_electrodes.npy') 125 | assert np.array_equal(z, z_all[valid_electrodes]) 126 | 127 | 128 | class TestSimulator: 129 | def test_generate_phosphene_maps(self, simulator): 130 | phosphene_maps = to_numpy(simulator.phosphene_maps) 131 | phosphene_maps_expected = np.load('data/phosphene_map.npy') 132 | assert np.isclose(phosphene_maps, phosphene_maps_expected, atol=1e-8).all() 133 | 134 | def test_update(self, simulator, stimulus): 135 | simulator.update(stimulus) 136 | sigma = to_numpy(simulator.sigma.get()) 137 | trace = to_numpy(simulator.trace.get()) 138 | sigma_expected = np.load('data/sigma.npy') 139 | trace_expected = np.load('data/trace.npy') 140 | assert np.isclose(sigma, sigma_expected, atol=1e-8).all() 141 | assert np.isclose(trace, trace_expected, atol=1e-8).all() 142 | 143 | def test_gaussian_activation(self, simulator, stimulus): 144 | simulator.update(stimulus) 145 | activation = to_numpy(simulator.gaussian_activation()) 146 | activation_expected = np.load('data/activation.npy') 147 | assert np.isclose(activation, activation_expected, atol=1e-8).all() 148 | 149 | def test_call(self, simulator, stimulus): 150 | phosphenes = to_numpy(simulator(stimulus)) 151 | phosphenes_expected = np.load('data/output.npy') 152 | assert np.isclose(phosphenes, phosphenes_expected, atol=1e-8).all() 153 | 154 | 155 | class TestFunctional: 156 | def test_sampling(self, params, rng): 157 | simulator = get_simulator(params, rng) 158 | shape = params['run']['resolution'] 159 | image = rng.random(shape) * 1e-4 160 | stimulus = simulator.sample_stimulus(image) 161 | stimulus_expected = np.load('data/stimulus.npy') 162 | assert np.isclose(stimulus, stimulus_expected, atol=1e-8).all() 163 | 164 | def test_image(self, params, rng): 165 | params['thresholding']['use_threshold'] = False 166 | shape = params['run']['resolution'] 167 | frame = cv2.imread('data/donders.png') 168 | frame = cv2.resize(frame, shape) 169 | frame = frame[::-1] 170 | frame = 255 - cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) 171 | frame = cv2.GaussianBlur(frame, (3, 3), 0) 172 | frame = frame.clip(0, 1) * 255 173 | simulator = get_simulator(params, rng) 174 | stimulus = simulator.sample_stimulus(frame, rescale=True) 175 | phosphenes = to_numpy(simulator(stimulus)) 176 | phosphenes_expected = np.load('data/phosphenes_donders.npy') 177 | assert np.isclose(phosphenes, phosphenes_expected, atol=1e-8).all() 178 | 179 | def test_brightness(self, params, rng): 180 | fps = 500 181 | stimulus_sequence = np.concatenate([np.ones(83), np.zeros(417)]) 182 | data = pd.read_csv('data/Fernandez_2021_fig6A.csv') 183 | 184 | params['cortex_model']['dropout_rate'] = 0 185 | params['default_stim']['pw_default'] = 170e-6 186 | params['default_stim']['freq_default'] = 300 187 | params['run']['fps'] = fps 188 | params['thresholding']['use_threshold'] = False 189 | coordinates_cortex = Map(np.array([35.]), np.array([10.])) 190 | coordinates_visual_field = get_visual_field_coordinates_from_cortex( 191 | params['cortex_model'], coordinates_cortex, rng) 192 | simulator = GaussianSimulator(params, coordinates_visual_field, rng) 193 | 194 | n_phosphenes = len(coordinates_visual_field) 195 | data_kwargs = get_data_kwargs(params) 196 | electrodes = torch.ones(n_phosphenes, **data_kwargs) 197 | results = [] 198 | for stim_condition, amplitude in enumerate(data.amplitude): 199 | simulator.reset() 200 | states = [] 201 | for i, stim in enumerate(stimulus_sequence): 202 | simulator.update(electrodes * stim * amplitude) 203 | state = {key: val.item() for key, val in simulator.get_state().items()} # state as numpy 204 | states.append(state) 205 | states[-1]['amplitude'] = stim * amplitude 206 | states[-1]['stim_condition'] = stim_condition 207 | states[-1]['time'] = i / fps 208 | 209 | results.append(pd.DataFrame(states)) 210 | results = pd.concat(results, ignore_index=True) 211 | 212 | # Find the peaks in activation and brightness for each stim_condition 213 | brightness = [] 214 | activation = [] 215 | for i in results.stim_condition.unique(): 216 | brightness.append( 217 | results.loc[results.stim_condition == i, 'brightness'].max()) 218 | activation.append( 219 | results.loc[results.stim_condition == i, 'activation'].max()) 220 | activation = np.array(activation) 221 | brightness = np.array(brightness) 222 | activation_expected = np.load('data/fernandez_activation_fit.npy') 223 | brightness_expected = np.load('data/fernandez_brightness_fit.npy') 224 | assert np.isclose(activation, activation_expected).all() 225 | assert np.isclose(brightness, brightness_expected).all() 226 | 227 | def test_dynamics(self, params, rng): 228 | stimulus_amplitude = 90e-6 229 | 230 | # Stimulation sequences for 1200 seconds 231 | fps = 256 232 | total_duration = 200 # seconds 233 | train_duration = 0.125 # seconds 234 | stim_moments = np.concatenate( 235 | [np.linspace(0, 200, 50, endpoint=False), # Fast part 236 | np.linspace(200, 1200, 6, endpoint=True)]) # Slow part 237 | 238 | num_frames = int(fps * train_duration) 239 | stim_sequences = np.zeros(int(fps * total_duration)) 240 | for t in stim_moments: 241 | idx = int(t * fps) 242 | stim_sequences[idx:idx + num_frames] = stimulus_amplitude 243 | 244 | params['cortex_model']['dropout_rate'] = 0 245 | params['default_stim']['pw_default'] = 100e-6 246 | params['default_stim']['freq_default'] = 200 247 | params['run']['fps'] = fps 248 | params['thresholding']['use_threshold'] = False 249 | coordinates_cortex = Map(np.array([35.]), np.array([10.])) 250 | coordinates_visual_field = get_visual_field_coordinates_from_cortex( 251 | params['cortex_model'], coordinates_cortex, rng) 252 | simulator = GaussianSimulator(params, coordinates_visual_field, rng) 253 | 254 | data_kwargs = get_data_kwargs(params) 255 | states = [] 256 | for i, stimulus in enumerate(to_tensor(stim_sequences, **data_kwargs)): 257 | simulator.update(stimulus) 258 | state = {key: val.item() for key, val in simulator.get_state().items()} # state as numpy 259 | states.append(state) 260 | 261 | results = pd.DataFrame(states) 262 | results['stimulation'] = stim_sequences 263 | results['fps'] = fps 264 | results['time'] = results.index.copy() / fps 265 | results_expected = pd.read_pickle('data/results_dynamics.pkl') 266 | assert np.isclose(results.to_numpy(), 267 | results_expected.to_numpy()).all() 268 | --------------------------------------------------------------------------------